Skip to content
Snippets Groups Projects
Select Git revision
  • labcomm2014
  • labcomm2006
  • master default
  • python_sig_hash
  • typedefs
  • anders.blomdell
  • typeref
  • pragma
  • compiler-refactoring
  • labcomm2013
  • v2014.6
  • v2015.0
  • v2014.5
  • v2014.4
  • v2006.0
  • v2014.3
  • v2014.2
  • v2014.1
  • v2014.0
  • v2013.0
20 results

throttle_drv.c

Blame
  • 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;
    }