Select Git revision
throttle_drv.c
-
Anders Blomdell authoredAnders Blomdell authored
throttle_drv.c 14.03 KiB
#include "throttle_drv.h"
#include "ethernet_drv.h"
#include <errno.h>
#include "display.h"
#include "stdlib.h"
#include <string.h>
#include <time.h>
// #include <arpa/inet.h>
#define THROTTLENET_PROTO 0x544e
#define THR_DST_ADR_POS 0
#define THR_SRC_ADR_POS (THR_DST_ADR_POS + sizeof(((thr_header_t*)0)->dst_adr)) //6
#define THR_ETH_TYP_POS (THR_SRC_ADR_POS + sizeof(((thr_header_t*)0)->src_adr)) //12
#define THR_CHN_ID_POS (THR_ETH_TYP_POS + sizeof(((thr_header_t*)0)->eth_type)) //14
#define THR_FRAG_NUM_POS (THR_CHN_ID_POS + sizeof(((thr_header_t*)0)->chn_id)) //15
#define THR_FRAG_TOT_NUM_POS (THR_FRAG_NUM_POS + sizeof(((thr_header_t*)0)->frag_num)) //17
#define THR_FRAG_LEN_POS (THR_FRAG_TOT_NUM_POS + sizeof(((thr_header_t*)0)->frag_num_tot)) //19
#define THR_PAYLOAD_POS (THR_FRAG_LEN_POS + sizeof(((thr_header_t*)0)->frag_len)) //21
#define THR_MSG_HEADER_LEN THR_PAYLOAD_POS
#define THR_MSG_DST_ADR(thr_msg) (struct ether_addr*)(&thr_msg[THR_DST_ADR_POS])
#define THR_MSG_SRC_ADR(thr_msg) (struct ether_addr*)(&thr_msg[THR_SRC_ADR_POS])
#define THR_MSG_ETH_TYP(thr_msg) *(unsigned short*)(&thr_msg[THR_ETH_TYP_POS])
#define THR_MSG_CHN_ID(thr_msg) *(unsigned char*)(&thr_msg[THR_CHN_ID_POS])
#define THR_MSG_FRAG_NUM(thr_msg) *(unsigned short*)(&thr_msg[THR_FRAG_NUM_POS])
#define THR_MSG_FRAG_TOT_NUM(thr_msg) *(unsigned short*)(&thr_msg[THR_FRAG_TOT_NUM_POS])
#define THR_MSG_FRAG_LEN(thr_msg) *(unsigned short*)(&thr_msg[THR_FRAG_LEN_POS])
#define THR_MSG_PAYLOAD(thr_msg) (unsigned char*)(&thr_msg[THR_PAYLOAD_POS])
/* local type for the Throttle Channel structure */
struct thr_chn_t
{
struct ether_addr dst_adr; /* destination MAC address */
unsigned char id; /* Channel id */
unsigned short frag_size; /* Fragment size */
unsigned short freq; /* Message transmission frequency */
thr_msg_handler_t funct; /* Callback function invoked at the reception */
unsigned short msg_length;
unsigned char* p_msg;
struct ether_addr last_sender_adr;/* src MAC address of last message */
};
/* Type for the Throttle message */
typedef struct
{
struct ether_addr dst_adr; /* destination MAC address */
struct ether_addr src_adr; /* source MAC address */
unsigned short eth_type; /* ethernet packet type */
unsigned char chn_id; /* channel identification */
unsigned short frag_num; /* fragment number */
unsigned short frag_num_tot; /* total fragment number */
unsigned short frag_len; /* fragment length */
}thr_header_t;
/* Local functions */
static int thr_msg_check(const unsigned char* thr_msg, unsigned short chn_id, unsigned short length);
static struct eth_int_t* eth_int = NULL;
/**
* @fn int thr_init(const char* eth_int_name)
*
* @brief Initializes the Throttle Net Driver, enabling the Ethernet Raw communication for the eth_int_name interface.
*
* @param [in] eth_int_name: ethernet interface name (e.g. "eth0","eth1")
*
* @retval int: 0 on success; -1 on error and errno is set appropriately
*
*******************************************************************************/
int thr_init(const char* eth_int_name)
{
int ret = 0;
if (NULL == eth_int_name)
{
ret = -1;
errno = EINVAL;
DISPLAY_ERR("Input parameter NULL");
}
else
{
eth_int = eth_open(eth_int_name); /* open the Ethernet socket */
if (NULL == eth_int)
{
ret = -1;
}
}
return(ret);
}
/**
* @fn struct thr_chn_t* thr_open_chn(const char* dst_adr, unsigned char chn_id, unsigned char frag_size, unsigned short freq, const thr_msg_handler_t funct);
*
* @brief Open a logic channel
*
* @param [in] dst_adr: destination MAC address;
* @param [in] chn_id: identification of the channel;
* @param [in] frag_size: fragment size;
* @param [in] freq: frequency of trasmission for each fragment;
* @param [in] msg_handler: callback invoked when a message is completely received;
*
* @retval struct thr_chn_t*: pointer to the Channel structure. NULL on error and errno is set appropriately.
*
*******************************************************************************/
struct thr_chn_t* thr_open_chn(const struct ether_addr* dst_adr, unsigned char chn_id, unsigned char frag_size, unsigned short freq, const thr_msg_handler_t funct)
{
struct thr_chn_t* tmp_chn = NULL; /* pointer to Channel structure */
/* TO-DO: check if a similar channel has already been created */
/* Input parameters not valid ? */
if ((NULL == dst_adr) || (0 == frag_size))
{
errno = EINVAL;
DISPLAY_ERR("Input parameter(s) NULL");
}
else
{
/* allocate memory for the Channel structure */
tmp_chn = (struct thr_chn_t*)malloc(sizeof(struct thr_chn_t));
if (NULL == tmp_chn)
{
DISPLAY_ERR("Error allocating memory!");
}
else
{
/* Update the Channel structure */
memcpy(&tmp_chn->dst_adr, dst_adr, sizeof(tmp_chn->dst_adr));
tmp_chn->id = chn_id;
tmp_chn->frag_size = frag_size;
tmp_chn->freq = freq;
tmp_chn->funct = funct;
}
#ifdef DEBUG
printf("thr_open_chn: callback = %x\n", tmp_chn->funct);
#endif
}
return(tmp_chn);
}
void thr_close_chn(struct thr_chn_t* c){
free(c);
}
/**
* @fn int thr_send(const struct thr_chn_t* thr_chn, const char* data, unsigned int length)
*
* @brief Sends a Throttle message. A channel must be opened first.
*
* @param [in] thr_chn: pointer to the Throttle channel descriptor;
* @param [in] data: data buffer to be sent;
* @param [in] length: length of the data buffer;
*
* @retval int: number of byte sent, on success. -1 on error and errno is set appropriately.
*
*******************************************************************************/
int thr_send(const struct thr_chn_t* thr_chn, const char* data, unsigned int length)
{
unsigned char* thr_msg;
unsigned char i;
int ret = 0;
/* Check the input parameters */
if ((NULL == thr_chn) || (NULL == data) || (0 == length))
{
ret = -1;
errno = EINVAL;
DISPLAY_ERR("Input parameter(s) NULL");
}
else
{
if (0 == thr_chn->frag_size)
{
ret = -1;
errno = ERANGE;
DISPLAY_ERR("Division by zero");
}
else
{
/* allocate memory for the Throttle Message */
thr_msg = (unsigned char*)malloc(THR_MSG_HEADER_LEN + thr_chn->frag_size);
if (NULL == thr_msg)
{
ret = -1;
DISPLAY_ERR("Error allocating memory!");
}
else
{
/* Compose the Ethernet Frame to be sent */
memcpy(THR_MSG_DST_ADR(thr_msg), &thr_chn->dst_adr, sizeof(thr_chn->dst_adr)); /* Destiantion MAC Address */
eth_getMACadr(eth_int, THR_MSG_SRC_ADR(thr_msg)); /* Source MAC Address */
THR_MSG_ETH_TYP(thr_msg) = htons(THROTTLENET_PROTO); /* Ethernet Packet Type */
THR_MSG_CHN_ID(thr_msg) = thr_chn->id; /* Channel identification */
THR_MSG_FRAG_TOT_NUM(thr_msg) = ((length - 1) / thr_chn->frag_size) + 1; /* Total number of fragment */
struct timespec thr_time;
thr_time.tv_sec = thr_chn->freq / 1000;
thr_time.tv_nsec = (thr_chn->freq % 1000) * 1000000;
/* Message is splitted into fragments and they are sent */
for (i = 1; i <= THR_MSG_FRAG_TOT_NUM(thr_msg); i++)
{
THR_MSG_FRAG_NUM(thr_msg) = i; /* fragment number */
/* update the fragment length */
if (length >= thr_chn->frag_size)
{
THR_MSG_FRAG_LEN(thr_msg) = thr_chn->frag_size;
length -= thr_chn->frag_size;
}
else
{
THR_MSG_FRAG_LEN(thr_msg) = length;
}
memcpy ((void*)THR_MSG_PAYLOAD(thr_msg), (void*)data, THR_MSG_FRAG_LEN(thr_msg)); /* update the payload */
ret = eth_send(eth_int, &thr_msg[0], (THR_MSG_HEADER_LEN + THR_MSG_FRAG_LEN(thr_msg))); /* send the message */
if (-1 == ret) /*Error during the Ethernet trasmission ? */
{
DISPLAY_ERR("Error during Throttle msg trasmission!");
break;
}
else
{
data += THR_MSG_FRAG_LEN(thr_msg);
nanosleep(&thr_time, NULL);
}
}
/*deallocate the memory */
free(thr_msg);
thr_msg = NULL;
}
}
}
return(ret);
}
int thr_receive(struct thr_chn_t* thr_chn, unsigned char* data, void* param)
{
unsigned char* thr_msg = NULL;
unsigned char* p_data = NULL;
unsigned short frag_index = 1;
short byte_rec = 0;
unsigned char msg_received = 0;
int ret;
if ((NULL == thr_chn) || (NULL == data) || (NULL == thr_chn->funct) || (NULL == param))
{
ret = -1;
errno = EINVAL;
DISPLAY_ERR("Input parameter(s) NULL");
}
else
{
/* allocate memory for the Throttle Message */
thr_msg = (unsigned char*)malloc(THR_MSG_HEADER_LEN + thr_chn->frag_size);
if (NULL == thr_msg)
{
ret = -1;
DISPLAY_ERR("Error allocating memory!");
}
else
{
p_data = data;
do
{
byte_rec = eth_receive(eth_int, thr_msg, (THR_MSG_HEADER_LEN + thr_chn->frag_size)); /* receive the Ethernet Raw packet */
if (-1 == byte_rec)
{
/* discard the message */
DISPLAY_ERR("Error during Throttle msg reception: Fragment discarded.");
}
else
{
/* check if the Ethernet Raw message is correct (Ethernet protocol, Channel ID, length) */
ret = thr_msg_check(thr_msg, thr_chn->id, byte_rec);
if (ret < 0)
{
//printf("Throttle msg mismatch: Fragment discarded.\n");
}
else
{
#ifdef DEBUG
printf("thr_receive: Message Index %d on %d. Actual Index %d\n", THR_MSG_FRAG_NUM(thr_msg), THR_MSG_FRAG_TOT_NUM(thr_msg), frag_index);
#endif
if (frag_index == THR_MSG_FRAG_NUM(thr_msg)) /* The fragment is the one expected ? */
{
/* Rebuild the original data linking the payloads of each fragment */
memcpy((void*)p_data, (void*)THR_MSG_PAYLOAD(thr_msg), THR_MSG_FRAG_LEN(thr_msg));
p_data += THR_MSG_FRAG_LEN(thr_msg); /* update the pointer to the buffer */
frag_index++; /* update the fragment index */
ret = p_data - data; /* update the number of received byte */
if (frag_index > THR_MSG_FRAG_TOT_NUM(thr_msg))
{
msg_received = 1;
}
}
else
{
printf("thr_receive: Fragment mismatch: Fragment discarded.\n");
frag_index = 1;
p_data = data;
}
}
}
}while (msg_received != 1);
thr_chn->p_msg = (unsigned char*)malloc(ret);
if (NULL == thr_chn->p_msg)
{
ret = -1;
DISPLAY_ERR("Error allocating memory!");
}
else
{
#ifdef DEBUG
printf("thr_receive: Number of byte receive %d\n",ret);
#endif
thr_chn->msg_length = ret;
memcpy(thr_chn->p_msg, data, ret); /* copy the msg into the thr structure */
memcpy(&thr_chn->last_sender_adr, THR_MSG_SRC_ADR(thr_msg), 6); /* ... and the address of the sender */
#ifdef DEBUG
printf("thr_receive: calling %x\n", thr_chn->funct);
#endif
(thr_chn->funct)(param);
free(thr_chn->p_msg);
thr_chn->p_msg = NULL;
}
/* deallocate memory for the Throttle Message */
free(thr_msg);
thr_msg = NULL;
p_data = NULL;
}
}
return(ret);
}
static int thr_msg_check(const unsigned char* thr_msg, unsigned short chn_id, unsigned short length)
{
int ret = 0;
if (length > THR_MSG_HEADER_LEN) /* Ethernet Raw Packet contains a valid Payload ? */
{
if (THROTTLENET_PROTO == ntohs(THR_MSG_ETH_TYP(thr_msg))) /* Is Ethernet Type THROTTLENET Protocol ? */
{
if (THR_MSG_CHN_ID(thr_msg) == chn_id) /* Is Channel identification correct ? */
{
/* throttle message is correct */
}
else
{
ret = -1;
}
}
else
{
/* discard the message */
ret = -2;
}
}
else
{
/* discard the message */
ret = -3;
}
return(ret);
}
int thr_read(struct thr_chn_t* thr_chn, unsigned char* data, int length)
{
int ret = 0;
if ((NULL == thr_chn) || (NULL == data))
{
ret = -1;
errno = EINVAL;
DISPLAY_ERR("Input parameter(s) NULL");
}
else
{
if (length > thr_chn->msg_length)
{
length = thr_chn->msg_length;
#ifdef DEBUG
printf("thr_read: truncating length to %d\n", length);
#endif
}
#ifdef DEBUG
printf("thr_read: calling memcpy(%x, %x, %d\n", data, thr_chn->p_msg, length);
#endif
memcpy(data, thr_chn->p_msg, length); /* copy the msg into the thr structure */
ret = length;
thr_chn->msg_length = 0;
}
return(ret);
}
struct ether_addr* get_sender_addr(struct thr_chn_t* ch) {
return &ch->last_sender_adr;
}
unsigned char get_channel(struct thr_chn_t* ch) {
return ch->id;
}