/* ------------------------------------------------------------------------
 *
 * common.h
 *
 * Short description: 
 *                    
 *
 * ------------------------------------------------------------------------
 *
 * Copyright (c) 2017, Ericsson Canada
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * Neither the name of Ericsson Canada nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Jon Maloy, 2017
 *
 * ------------------------------------------------------------------------
 */

#ifndef __BUS_TEST_H_
#define __BUS_TEST_H_

#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/tipc.h>
#include <tipcc.h>

#define COMMAND_GROUP      1111
#define TRAFFIC_GROUP      2222

/* Member ids can be used in both groups
*/
#define TRANSMITTER_ID     0
#define RECEIVER_ID1       1
#define RECEIVER_ID2       2
#define COMMANDER_ID       100
#define SCALER_ID          101
#define LISTENER_ID        1000

/* Commands
 */
#define NONE                0
#define CREATE_WORKER       1
#define UNICAST_TEST        2
#define ANYCAST_TEST        3
#define MULTICAST_TEST      4
#define BROADCAST_TEST      5
#define UC_AFT_BC_SEQ_TEST  6
#define BC_AFT_UC_SEQ_TEST  7
#define MULTIPOINT_TEST     8
#define JOIN                9
#define LEAVE               10

/* Results
 */
#define OK                0
#define BAD_SRC_ADDR      1
#define BAD_LENGTH        2
#define BAD_TYPE          3
#define BAD_SEQNO         4
#define NOT_RECEIVED      5
#define NOT_SENT          6
#define NO_RESPONSE       7

/* Traffic message types
*/
#define UNICAST         1
#define ANYCAST         2
#define MULTICAST       3
#define BROADCAST       4

struct command_hdr {
	uint32_t cmd;
	uint32_t memberid; /* For CREATE, JOIN and LEAVE commands */
	uint32_t msg_len;
	uint32_t stats_intv;
	uint8_t events;
	uint8_t loopback;
};

struct traffic_hdr {
	uint32_t type;
	uint32_t seqno;
	uint8_t check_length;
	uint8_t check_seqno;
};

struct report_hdr {
	uint32_t error;
	uint32_t snt_uc;
	uint32_t snt_ac;
	uint32_t snt_mc;
	uint32_t snt_bc;
	uint32_t rcv_uc;
	uint32_t rcv_ac;
	uint32_t rcv_mc;
	uint32_t rcv_bc;
	uint32_t rcv_first;
	uint32_t rcv_last;
	char mbrstr[64];
};

void scaler_main(uint32_t node);
void worker_main(uint32_t member, bool stats, uint32_t node);

extern int vlevel;

#define dbg1(fmt, arg...) do { if (vlevel >= 1) printf(fmt, ##arg); } while (0)
#define dbg2(fmt, arg...) do { if (vlevel >= 2) printf(fmt, ##arg); } while (0)
#define dbg3(fmt, arg...) do { if (vlevel >= 3) printf(fmt, ##arg); } while (0)
#define die(fmt, arg...) do { printf("%s(): "fmt, __func__, ##arg); perror(0); exit(1);} while(0)

static const char *cmdstr(int test)
{
	switch(test) {
	case CREATE_WORKER:
		return "Create Worker";
	case UNICAST_TEST:
		return "Unicast Test";
	case ANYCAST_TEST:
		return "Anycast Test";
	case MULTICAST_TEST:
		return "Multicast Test";
	case BROADCAST_TEST:
		return "Broadcast Test";
	case UC_AFT_BC_SEQ_TEST:
		return "Unicast after Broadcast Sequence Test";
	case BC_AFT_UC_SEQ_TEST:
		return "Broadcast after Unicast Sequence Test";
	case MULTIPOINT_TEST:
		return "Flow Control Multipoint-to-Point Test";
	case JOIN:
		return "Join";
	case LEAVE:
		return "Leave";
	default:
		return "Unknown Test Type";
	}
}

static const char *errstr(int err)
{
	switch(err) {
	case OK:
		return "OK";
	case BAD_SRC_ADDR:
		return "Bad Source Addr";
	case BAD_LENGTH:
		return "Bad Msg Length";
	case BAD_TYPE:
		return "Bad Msg Type";
	case BAD_SEQNO:
		return "Bad Sequence Number";
	case NOT_RECEIVED:
		return "Failed to Receive";
	case NOT_SENT:
		return "Failed to Send";
	default:
		return "Unknown Error";
	}
}

#endif
