/* * Licensed under the GNU General Public License version 2 with exceptions. See * LICENSE file in the project root for full license information */ /** \file * \brief * Ethernet over EtherCAT (EoE) module. */ #include #include #include "esc.h" #include "esc_eoe.h" #if defined(EC_BIG_ENDIAN) #define EOE_HTONS(x) (x) #define EOE_NTOHS(x) (x) #define EOE_HTONL(x) (x) #define EOE_NTOHL(x) (x) #else #define EOE_HTONS(x) ((((x) & 0x00ffUL) << 8) | (((x) & 0xff00UL) >> 8)) #define EOE_NTOHS(x) EOE_HTONS(x) #define EOE_HTONL(x) ((((x) & 0x000000ffUL) << 24) | \ (((x) & 0x0000ff00UL) << 8) | \ (((x) & 0x00ff0000UL) >> 8) | \ (((x) & 0xff000000UL) >> 24)) #define EOE_NTOHL(x) EOE_HTONL(x) #endif /* #if defined(EC_BIG_ENDIAN) */ #define EOE_MAKEU32(a,b,c,d) (((uint32_t)((a) & 0xff) << 24) | \ ((uint32_t)((b) & 0xff) << 16) | \ ((uint32_t)((c) & 0xff) << 8) | \ (uint32_t)((d) & 0xff)) /** Get one byte from the 4-byte address */ #define eoe_ip4_addr1(ipaddr) (((const uint8_t*)(&(ipaddr)->addr))[0]) #define eoe_ip4_addr2(ipaddr) (((const uint8_t*)(&(ipaddr)->addr))[1]) #define eoe_ip4_addr3(ipaddr) (((const uint8_t*)(&(ipaddr)->addr))[2]) #define eoe_ip4_addr4(ipaddr) (((const uint8_t*)(&(ipaddr)->addr))[3]) /** Set an IP address given by the four byte-parts */ #define EOE_IP4_ADDR_TO_U32(ipaddr,a,b,c,d) \ (ipaddr)->addr = EOE_HTONL(EOE_MAKEU32(a,b,c,d)) /** Header frame info 1 */ #define EOE_HDR_FRAME_TYPE_OFFSET 0 #define EOE_HDR_FRAME_TYPE (0xF << 0) #define EOE_HDR_FRAME_TYPE_SET(x) (((x) & 0xF) << 0) #define EOE_HDR_FRAME_TYPE_GET(x) (((x) >> 0) & 0xF) #define EOE_HDR_FRAME_PORT_OFFSET 4 #define EOE_HDR_FRAME_PORT (0xF << 4) #define EOE_HDR_FRAME_PORT_SET(x) (((x) & 0xF) << 4) #define EOE_HDR_FRAME_PORT_GET(x) (((x) >> 4) & 0xF) #define EOE_HDR_LAST_FRAGMENT_OFFSET 8 #define EOE_HDR_LAST_FRAGMENT (0x1 << 8) #define EOE_HDR_LAST_FRAGMENT_SET(x) (((x) & 0x1) << 8) #define EOE_HDR_LAST_FRAGMENT_GET(x) (((x) >> 8) & 0x1) #define EOE_HDR_TIME_APPEND_OFFSET 9 #define EOE_HDR_TIME_APPEND (0x1 << 9) #define EOE_HDR_TIME_APPEND_SET(x) (((x) & 0x1) << 9) #define EOE_HDR_TIME_APPEND_GET(x) (((x) >> 9) & 0x1) #define EOE_HDR_TIME_REQUEST_OFFSET 10 #define EOE_HDR_TIME_REQUEST (0x1 << 10) #define EOE_HDR_TIME_REQUEST_SET(x) (((x) & 0x1) << 10) #define EOE_HDR_TIME_REQUEST_GET(x) (((x) >> 10) & 0x1) /** Header frame info 2 */ #define EOE_HDR_FRAG_NO_OFFSET 0 #define EOE_HDR_FRAG_NO (0x3F << 0) #define EOE_HDR_FRAG_NO_SET(x) (((x) & 0x3F) << 0) #define EOE_HDR_FRAG_NO_GET(x) (((x) >> 0) & 0x3F) #define EOE_HDR_FRAME_OFFSET_OFFSET 6 #define EOE_HDR_FRAME_OFFSET (0x3F << 6) #define EOE_HDR_FRAME_OFFSET_SET(x) (((x) & 0x3F) << 6) #define EOE_HDR_FRAME_OFFSET_GET(x) (((x) >> 6) & 0x3F) #define EOE_HDR_FRAME_NO_OFFSET 12 #define EOE_HDR_FRAME_NO (0xF << 12) #define EOE_HDR_FRAME_NO_SET(x) (((x) & 0xF) << 12) #define EOE_HDR_FRAME_NO_GET(x) (((x) >> 12) & 0xF) /** EOE param */ #define EOE_PARAM_OFFSET 4 #define EOE_PARAM_MAC_INCLUDE (0x1 << 0) #define EOE_PARAM_IP_INCLUDE (0x1 << 1) #define EOE_PARAM_SUBNET_IP_INCLUDE (0x1 << 2) #define EOE_PARAM_DEFAULT_GATEWAY_INCLUDE (0x1 << 3) #define EOE_PARAM_DNS_IP_INCLUDE (0x1 << 4) #define EOE_PARAM_DNS_NAME_INCLUDE (0x1 << 5) /** EoE frame types */ #define EOE_FRAG_DATA 0 #define EOE_INIT_RESP_TIMESTAMP 1 #define EOE_INIT_REQ 2 /* Spec SET IP REQ */ #define EOE_INIT_RESP 3 /* Spec SET IP RESP */ #define EOE_SET_ADDR_FILTER_REQ 4 #define EOE_SET_ADDR_FILTER_RESP 5 #define EOE_GET_IP_PARAM_REQ 6 #define EOE_GET_IP_PARAM_RESP 7 #define EOE_GET_ADDR_FILTER_REQ 8 #define EOE_GET_ADDR_FILTER_RESP 9 /** Define number of ports available.(Only one is supported currently */ #define EOE_NUMBER_OF_PORTS 1 #define EOE_PORT_INDEX(x) ((x > 0) ? (x - 1) : 0) /** DNS length according to ETG 1000.6 */ #define EOE_DNS_NAME_LENGTH 32 /** Ethernet address length not including VLAN */ #define EOE_ETHADDR_LENGTH 6 /** IPv4 address length */ #define EOE_IP4_LENGTH sizeof(uint32_t) /** EOE ip4 address in network order */ struct eoe_ip4_addr { uint32_t addr; }; typedef struct eoe_ip4_addr eoe_ip4_addr_t; /** EOE ethernet address */ CC_PACKED_BEGIN typedef struct CC_PACKED eoe_ethaddr { uint8_t addr[EOE_ETHADDR_LENGTH]; } eoe_ethaddr_t; CC_PACKED_END typedef struct { /** Pointer to current RX buffer to fill */ eoe_pbuf_t rxebuf; /** Pointer to current TX buff to Send */ eoe_pbuf_t txebuf; /** Current RX fragment number */ uint8_t rxfragmentno; /** Complete RX frame size of current frame */ uint16_t rxframesize; /** Current RX data offset in frame */ uint16_t rxframeoffset; /** Current RX frame number */ uint16_t rxframeno; /** Current TX fragment number */ uint8_t txfragmentno; /** Complete TX frame size of current frame */ uint16_t txframesize; /** Current TX data offset in frame */ uint16_t txframeoffset; } _EOEvar; /** EoE IP request structure */ typedef struct eoe_param { uint8_t mac_set:1; uint8_t ip_set:1; uint8_t subnet_set:1; uint8_t default_gateway_set:1; uint8_t dns_ip_set:1; uint8_t dns_name_set:1; eoe_ethaddr_t mac; eoe_ip4_addr_t ip; eoe_ip4_addr_t subnet; eoe_ip4_addr_t default_gateway; eoe_ip4_addr_t dns_ip; char dns_name[EOE_DNS_NAME_LENGTH]; } eoe_param_t; /** Main EoE status data array. Structure gets filled with current information * variables during EoE receive and send operations. */ static _EOEvar EOEvar; /** Main FoE configuration pointer data array. Structure is allocated and filled * by the application defining what preferences it requires. */ static eoe_cfg_t * eoe_cfg; /** Local EoE variable holding cached IP information values. * To be set or read from the user application, eg. TCP/IP stack. */ static eoe_param_t nic_ports[EOE_NUMBER_OF_PORTS]; /** Local init/reset functions on frame receive init */ static void EOE_init_rx (); /** Local init/reset functions on frame send completion */ static void EOE_init_tx (); /** EoE utility function to convert uint32 to eoe ip bytes. * @param[in] ip = ip in uint32 * @param[out] byte_ip = eoe ip 4th octet, 3ed octet, 2nd octet, 1st octet */ static void EOE_ip_uint32_to_byte (eoe_ip4_addr_t * ip, uint8_t * byte_ip) { byte_ip[3] = eoe_ip4_addr1(ip); /* 1st octet */ byte_ip[2] = eoe_ip4_addr2(ip); /* 2nd octet */ byte_ip[1] = eoe_ip4_addr3(ip); /* 3ed octet */ byte_ip[0] = eoe_ip4_addr4(ip); /* 4th octet */ } /** EoE utility function to convert eoe ip bytes to uint32. * @param[in] byte_ip = eoe ip 4th octet, 3ed octet, 2nd octet, 1st octet * @param[out] ip = ip in uint32 */ static void EOE_ip_byte_to_uint32 (uint8_t * byte_ip, eoe_ip4_addr_t * ip) { EOE_IP4_ADDR_TO_U32(ip, byte_ip[3], /* 1st octet */ byte_ip[2], /* 2nd octet */ byte_ip[1], /* 3ed octet */ byte_ip[0]) ;/* 4th octet */ } /** Get EoE cached MAC address * * @param[in] port = get MAC for port * @param[out] mac = variable to store mac in, should fit EOE_ETHADDR_LENGTH * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_mac(uint8_t port, uint8_t mac[]) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].mac_set) { memcpy(mac, nic_ports[port_ix].mac.addr, sizeof(nic_ports[port_ix].mac)); nic_ports[port_ix].mac_set = 1; ret = 0; } } return ret; } /** Set EoE cached MAC address * * @param[in] port = get MAC for port * @param[in] mac = mac address to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_mac(uint8_t port, uint8_t mac[]) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); memcpy(nic_ports[port_ix].mac.addr, mac, sizeof(nic_ports[port_ix].mac)); ret = 0; } return ret; } /** Get EoE cached ip address * * @param[in] port = get ip address for port * @param[out] ip = variable to store ip in * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_ip(uint8_t port, uint32_t * ip) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].ip_set) { *ip = EOE_NTOHL(nic_ports[port_ix].ip.addr); ret = 0; } } return ret; } /** Set EoE cached ip address * * @param[in] port = get ip for port * @param[in] ip = ip address to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_ip(uint8_t port, uint32_t ip) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); nic_ports[port_ix].ip.addr = EOE_HTONL(ip); nic_ports[port_ix].ip_set = 1; ret = 0; } return ret; } /** Get EoE cached subnet ip address * * @param[in] port = get ip address for port * @param[out] subnet = variable to store ip in * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_subnet(uint8_t port, uint32_t * subnet) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].subnet_set) { *subnet = EOE_NTOHL(nic_ports[port_ix].subnet.addr); ret = 0; } } return ret; } /** Set EoE cached subnet ip address * * @param[in] port = get ip for port * @param[in] subnet = ip address to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_subnet(uint8_t port, uint32_t subnet) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); nic_ports[port_ix].subnet.addr = EOE_HTONL(subnet); nic_ports[port_ix].subnet_set = 1; ret = 0; } return ret; } /** Get EoE cached default gateway ip address * * @param[in] port = get ip address for port * @param[out] default_gateway = variable to store ip in * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_gateway(uint8_t port, uint32_t * default_gateway) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].default_gateway_set) { *default_gateway = EOE_NTOHL(nic_ports[port_ix].default_gateway.addr); ret = 0; } } return ret; } /** Set EoE cached default gateway ip address * * @param[in] port = get ip for port * @param[in] default_gateway = ip address to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_gateway(uint8_t port, uint32_t default_gateway) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); nic_ports[port_ix].default_gateway.addr = EOE_HTONL(default_gateway); nic_ports[port_ix].default_gateway_set = 1; ret = 0; } return ret; } /** Get EoE cached dns ip address * * @param[in] port = get ip address for port * @param[out] dns_ip = variable to store ip in * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_dns_ip(uint8_t port, uint32_t * dns_ip) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].dns_ip_set) { *dns_ip = EOE_NTOHL(nic_ports[port_ix].dns_ip.addr); ret = 0; } } return ret; } /** Set EoE cached dns ip address * * @param[in] port = get ip for port * @param[in] dns_ip = ip address to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_dns_ip(uint8_t port, uint32_t dns_ip) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); nic_ports[port_ix].dns_ip.addr = EOE_HTONL(dns_ip); nic_ports[port_ix].dns_ip_set = 1; ret = 0; } return ret; } /** Get EoE cached dns name * * @param[in] port = get dns name for port * @param[out] dns_name = variable to store dns name in * @return 0= if we succeed, -1 if not set */ int EOE_ecat_get_dns_name(uint8_t port, char * dns_name) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].dns_name_set) { memcpy(dns_name, nic_ports[port_ix].dns_name, sizeof(nic_ports[port_ix].dns_name)); ret = 0; } } return ret; } /** Set EoE cached dns name * * @param[in] port = get dns name for port * @param[in] dns_name = dns name to store * @return 0= if we succeed, else -1. */ int EOE_ecat_set_dns_name(uint8_t port, char * dns_name) { int ret = -1; int port_ix; if(port < EOE_NUMBER_OF_PORTS) { port_ix = EOE_PORT_INDEX(port); memcpy(nic_ports[port_ix].dns_name, dns_name, sizeof(nic_ports[port_ix].dns_name)); nic_ports[port_ix].dns_name_set = 1; ret = 0; } return ret; } /** Function for sending an simple EOE response frame. * * @param[in] frametype1 = frame type of response * @param[in] result = result code */ static void EOE_no_data_response (uint16_t frameinfo1, uint16_t result) { _EOE *eoembx; uint8_t mbxhandle; /* Send back a response packet. */ mbxhandle = ESC_claimbuffer (); if (mbxhandle) { eoembx = (_EOE *) &MBX[mbxhandle * ESC_MBXSIZE]; eoembx->mbxheader.length = htoes (ESC_EOEHSIZE); eoembx->mbxheader.mbxtype = MBXEOE; eoembx->eoeheader.frameinfo1 = htoes(frameinfo1); eoembx->eoeheader.result = htoes(result); MBXcontrol[mbxhandle].state = MBXstate_outreq; } } /** EoE get IP param request handler. Will send a get IP param response. */ static void EOE_get_ip (void) { _EOE *req_eoembx; _EOE *eoembx; uint8_t mbxhandle; uint16_t frameinfo1; uint8_t port; uint8_t flags; uint8_t data_offset; int port_ix; req_eoembx = (_EOE *) &MBX[0]; frameinfo1 = etohs(req_eoembx->eoeheader.frameinfo1); port = EOE_HDR_FRAME_PORT_GET(frameinfo1); data_offset = EOE_PARAM_OFFSET; flags = 0; if(port > EOE_NUMBER_OF_PORTS) { DPRINT("Invalid port\n"); /* Return error response on given port */ EOE_no_data_response((EOE_HDR_FRAME_PORT_SET(port) | EOE_INIT_RESP | EOE_HDR_LAST_FRAGMENT), EOE_RESULT_UNSPECIFIED_ERROR); return; } /* Refresh settings if needed */ if(eoe_cfg->load_eth_settings != NULL) { (void)eoe_cfg->load_eth_settings(); } /* Send back an response packet. */ mbxhandle = ESC_claimbuffer (); if (mbxhandle) { eoembx = (_EOE *) &MBX[mbxhandle * ESC_MBXSIZE]; eoembx->mbxheader.mbxtype = MBXEOE; MBXcontrol[mbxhandle].state = MBXstate_outreq; eoembx->eoeheader.frameinfo1 = htoes(EOE_HDR_FRAME_TYPE_SET(EOE_GET_IP_PARAM_RESP) | EOE_HDR_FRAME_PORT_SET(port) | EOE_HDR_LAST_FRAGMENT); eoembx->eoeheader.frameinfo2 = 0; /* include mac in get ip request */ port_ix = EOE_PORT_INDEX(port); if(nic_ports[port_ix].mac_set) { flags |= EOE_PARAM_MAC_INCLUDE; memcpy(&eoembx->data[data_offset] , nic_ports[port_ix].mac.addr, EOE_ETHADDR_LENGTH); /* Add size of mac address */ data_offset += EOE_ETHADDR_LENGTH; } /* include ip in get ip request */ if(nic_ports[port_ix].ip_set) { flags |= EOE_PARAM_IP_INCLUDE; EOE_ip_uint32_to_byte(&nic_ports[port_ix].ip, &eoembx->data[data_offset]); /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* include subnet in get ip request */ if(nic_ports[port_ix].subnet_set) { flags |= EOE_PARAM_SUBNET_IP_INCLUDE; EOE_ip_uint32_to_byte(&nic_ports[port_ix].subnet, &eoembx->data[data_offset]); /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* include default gateway in get ip request */ if(nic_ports[port_ix].default_gateway_set) { flags |= EOE_PARAM_DEFAULT_GATEWAY_INCLUDE; EOE_ip_uint32_to_byte(&nic_ports[port_ix].default_gateway, &eoembx->data[data_offset]); /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* include dns ip in get ip request */ if(nic_ports[port_ix].dns_ip_set) { flags |= EOE_PARAM_DNS_IP_INCLUDE; EOE_ip_uint32_to_byte(&nic_ports[port_ix].dns_ip, &eoembx->data[data_offset]); /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* include dns name in get ip request */ if(nic_ports[port_ix].dns_name_set) { /* TwinCAT include EOE_DNS_NAME_LENGTH chars even if name is shorter */ flags |= EOE_PARAM_DNS_NAME_INCLUDE; memcpy(&eoembx->data[data_offset], nic_ports[port_ix].dns_name, EOE_DNS_NAME_LENGTH); /* Add size of dns name length */ data_offset += EOE_DNS_NAME_LENGTH; } eoembx->data[0] = flags; eoembx->mbxheader.length = htoes (ESC_EOEHSIZE + data_offset); } } /** EoE set IP param request handler. Will send a set IP param response. */ static void EOE_set_ip (void) { _EOE *eoembx; uint16_t eoedatasize; uint16_t frameinfo1; uint8_t port; uint8_t flags; uint8_t data_offset; uint16_t result; int port_ix; eoembx = (_EOE *) &MBX[0]; eoedatasize = etohs(eoembx->mbxheader.length) - ESC_EOEHSIZE; frameinfo1 = etohs(eoembx->eoeheader.frameinfo1); port = EOE_HDR_FRAME_PORT_GET(frameinfo1); flags = eoembx->data[0]; data_offset = EOE_PARAM_OFFSET; if(port > EOE_NUMBER_OF_PORTS) { DPRINT("Invalid port\n"); /* Return error response on given port */ EOE_no_data_response((EOE_HDR_FRAME_PORT_SET(port) | EOE_INIT_RESP | EOE_HDR_LAST_FRAGMENT), EOE_RESULT_UNSPECIFIED_ERROR); return; } /* mac included in set ip request? */ port_ix = EOE_PORT_INDEX(port); if(flags & EOE_PARAM_MAC_INCLUDE) { memcpy(&nic_ports[port_ix].mac.addr, &eoembx->data[data_offset], EOE_ETHADDR_LENGTH); nic_ports[port_ix].mac_set = 1; /* Add size of mac address */ data_offset += EOE_ETHADDR_LENGTH; } /* ip included in set ip request? */ if(flags & EOE_PARAM_IP_INCLUDE) { EOE_ip_byte_to_uint32(&eoembx->data[data_offset], &nic_ports[port_ix].ip); nic_ports[port_ix].ip_set = 1; /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* subnet included in set ip request? */ if(flags & EOE_PARAM_SUBNET_IP_INCLUDE) { EOE_ip_byte_to_uint32(&eoembx->data[data_offset], &nic_ports[port_ix].subnet); nic_ports[port_ix].subnet_set = 1; /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* default gateway included in set ip request? */ if(flags & EOE_PARAM_DEFAULT_GATEWAY_INCLUDE) { EOE_ip_byte_to_uint32(&eoembx->data[data_offset], &nic_ports[port_ix].default_gateway); nic_ports[port_ix].default_gateway_set = 1; /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* dns ip included in set ip request? */ if(flags & EOE_PARAM_DNS_IP_INCLUDE) { EOE_ip_byte_to_uint32(&eoembx->data[data_offset], &nic_ports[port_ix].dns_ip); nic_ports[port_ix].dns_ip_set = 1; /* Add size of uint32 IP address */ data_offset += EOE_IP4_LENGTH; } /* dns name included in set ip request? */ if(flags & EOE_PARAM_DNS_NAME_INCLUDE) { uint16_t dns_len = MIN((eoedatasize - data_offset), EOE_DNS_NAME_LENGTH); memcpy(nic_ports[port_ix].dns_name, &eoembx->data[data_offset], dns_len); nic_ports[port_ix].dns_name_set = 1; data_offset += dns_len; /* expected 1- EOE_DNS_NAME_LENGTH; */ } if(data_offset > eoedatasize) { result = MBXERR_SIZETOOSHORT; } else { /* Application specific store settings function. From there * you typically set the IP for the TCP/IP stack */ if(eoe_cfg->store_ethernet_settings != NULL) { result = eoe_cfg->store_ethernet_settings(); } else { result = EOE_RESULT_NO_IP_SUPPORT; } } EOE_no_data_response((EOE_HDR_FRAME_PORT_SET(port) | EOE_INIT_RESP | EOE_HDR_LAST_FRAGMENT), result); } /** EoE receive fragment handler. */ static void EOE_receive_fragment (void) { _EOE *eoembx; eoembx = (_EOE *) &MBX[0]; uint16_t eoedatasize = etohs(eoembx->mbxheader.length) - ESC_EOEHSIZE; uint16_t frameinfo1 = etohs(eoembx->eoeheader.frameinfo1); uint16_t frameinfo2 = etohs(eoembx->eoeheader.frameinfo2); /* Capture error case */ if(EOEvar.rxfragmentno != EOE_HDR_FRAG_NO_GET(frameinfo2)) { DPRINT("Unexpected fragment number %d, expected: %d\n", EOE_HDR_FRAG_NO_GET(frameinfo2), EOEvar.rxfragmentno); /* Clean up existing saved data */ if(EOEvar.rxfragmentno != 0) { EOE_init_rx(); } /* Skip fragment if not start of new frame */ if(EOE_HDR_FRAG_NO_GET(frameinfo2) > 0) { return; } } /* Start of new frame at fragment 0 */ if(EOEvar.rxfragmentno == 0) { EOEvar.rxframesize = (EOE_HDR_FRAME_OFFSET_GET(frameinfo2) << 5); if(EOEvar.rxebuf.payload != NULL) { EOEvar.rxebuf.len = EOEvar.rxframesize; EOEvar.rxframeoffset = 0; EOEvar.rxframeno = EOE_HDR_FRAME_NO_GET(frameinfo2); } } /* In frame fragment received */ else { uint16_t offset = (EOE_HDR_FRAME_OFFSET_GET(frameinfo2) << 5); /* Validate received fragment */ if(EOEvar.rxframeno != EOE_HDR_FRAME_NO_GET(frameinfo2)) { DPRINT("Unexpected frame number %d, expected: %d\n", EOE_HDR_FRAME_NO_GET(frameinfo2), EOEvar.rxframeno); EOE_init_rx (); return; } else if(EOEvar.rxframeoffset != offset) { DPRINT("Unexpected frame offset %d, expected: %d\n", offset, EOEvar.rxframeoffset); EOE_init_rx (); return; } } /* Check so allocated buffer is sufficient */ if ((EOEvar.rxframeoffset + eoedatasize) <= EOEvar.rxframesize) { memcpy((uint8_t *)(EOEvar.rxebuf.payload + EOEvar.rxframeoffset), eoembx->data, eoedatasize); EOEvar.rxframeoffset += eoedatasize; EOEvar.rxfragmentno++; } else { DPRINT("Size of data exceed available buffer size\n"); EOE_init_rx (); return; } if(EOE_HDR_LAST_FRAGMENT_GET(frameinfo1)) { /* Remove time stamp, TODO support for time stamp? */ if(EOE_HDR_TIME_APPEND_GET(frameinfo1)) { EOEvar.rxframeoffset -= 4; } EOEvar.rxebuf.len = EOEvar.rxframeoffset; eoe_cfg->handle_recv_buffer(EOE_HDR_FRAME_PORT_GET(frameinfo1), &EOEvar.rxebuf); /* Pass ownership of buf to receive function */ EOEvar.rxebuf.payload = NULL; EOE_init_rx (); } } /** EoE send fragment handler. */ static void EOE_send_fragment () { _EOE *eoembx; uint8_t mbxhandle; int len; int len_to_send; uint16_t frameinfo1; uint16_t frameinfo2; static uint8_t frameno = 0; /* Do we have a current transfer on-going */ if(EOEvar.txebuf.payload == NULL) { /* Fetch a buffer if available */ len = eoe_cfg->fetch_send_buffer(0, &EOEvar.txebuf); if(len > 0) { EOEvar.txframesize = len; } else { return; } } /* Process the frame if we can get a free mailbox */ mbxhandle = ESC_claimbuffer (); if (mbxhandle) { len_to_send = EOEvar.txframesize - EOEvar.txframeoffset; if((len_to_send + ESC_EOEHSIZE + ESC_MBXHSIZE) > ESC_MBXSIZE) { /* Adjust to len in whole 32 octet blocks to fit specification*/ len_to_send = (((ESC_MBXSIZE - ESC_EOEHSIZE - ESC_MBXHSIZE) >> 5) << 5); } /* TODO: port handling? */ if(len_to_send == (EOEvar.txframesize - EOEvar.txframeoffset)) { frameinfo1 = EOE_HDR_LAST_FRAGMENT_SET(1); } else { frameinfo1 = 0; } /* Set fragment number */ frameinfo2 = EOE_HDR_FRAG_NO_SET(EOEvar.txfragmentno); /* Set complete size for fragment 0 or offset for in frame fragments */ if(EOEvar.txfragmentno > 0) { frameinfo2 |= (EOE_HDR_FRAME_OFFSET_SET((EOEvar.txframeoffset >> 5))); } else { frameinfo2 |= (EOE_HDR_FRAME_OFFSET_SET(((EOEvar.txframesize + 31) >> 5))); frameno++; } /* Set frame number */ frameinfo2 = frameinfo2 | EOE_HDR_FRAME_NO_SET(frameno); eoembx = (_EOE *) &MBX[mbxhandle * ESC_MBXSIZE]; eoembx->mbxheader.length = htoes (len_to_send + ESC_EOEHSIZE); eoembx->mbxheader.mbxtype = MBXEOE; eoembx->eoeheader.frameinfo1 = htoes(frameinfo1); eoembx->eoeheader.frameinfo2 = htoes(frameinfo2); /* Copy data to mailbox */ memcpy(eoembx->data, &EOEvar.txebuf.payload[EOEvar.txframeoffset], len_to_send); MBXcontrol[mbxhandle].state = MBXstate_outreq; /* Did we complete the frame? */ if(len_to_send == (EOEvar.txframesize - EOEvar.txframeoffset)) { EOE_init_tx (); } else { EOEvar.txframeoffset += len_to_send; EOEvar.txfragmentno += 1; } if(eoe_cfg->fragment_sent_event != NULL) { eoe_cfg->fragment_sent_event(); } } } /** Initialize by clearing all current status variables and fetch new buffer. */ static void EOE_init_rx () { /* Reset RX transfer status variables */ EOEvar.rxfragmentno = 0; EOEvar.rxframesize = 0; EOEvar.rxframeoffset = 0; EOEvar.rxframeno = 0; /* Fetch buffer */ if(EOEvar.rxebuf.payload == NULL) { if(eoe_cfg->get_buffer != NULL) { /* TODO: verify size VS buffer size */ eoe_cfg->get_buffer(&EOEvar.rxebuf); } } } /** Initialize by clearing all current status variables and release old buffer. */ static void EOE_init_tx () { /* Reset TX transfer status variables */ EOEvar.txfragmentno = 0; EOEvar.txframesize = 0; EOEvar.txframeoffset = 0; /* Release what seems as an abandoned buffer */ if((EOEvar.txebuf.payload != NULL)) { if(eoe_cfg->free_buffer != NULL) { eoe_cfg->free_buffer(&EOEvar.txebuf); EOEvar.txebuf.pbuf = NULL; EOEvar.txebuf.payload = NULL; EOEvar.txebuf.len = 0; } } } /** Initialize by clearing all current status variables. */ void EOE_init () { DPRINT("EOE_init\n"); EOE_init_tx (); EOE_init_rx (); } /** Function copying the application configuration variable * to the EoE module local pointer variable. * * @param[in] cfg = Pointer to by the Application static declared * configuration variable holding application specific details. */ void EOE_config (eoe_cfg_t * cfg) { eoe_cfg = cfg; } /** Main EoE receive function checking the status on current mailbox buffers * carrying data, distributing the mailboxes to appropriate EOE functions * depending on requested frametype. */ void ESC_eoeprocess (void) { _MBXh *mbh; _EOE *eoembx; uint16_t frameinfo1; if (ESCvar.MBXrun == 0) { return; } if (!ESCvar.xoe && (MBXcontrol[0].state == MBXstate_inclaim)) { mbh = (_MBXh *) &MBX[0]; if (mbh->mbxtype == MBXEOE) { ESCvar.xoe = MBXEOE; } } if (ESCvar.xoe == MBXEOE) { eoembx = (_EOE *) &MBX[0]; /* Verify the size of the file data. */ if (etohs (eoembx->mbxheader.length) < ESC_EOEHSIZE) { EOE_no_data_response ( EOE_INIT_RESP | EOE_HDR_LAST_FRAGMENT, MBXERR_SIZETOOSHORT); } else { frameinfo1 = etohs(eoembx->eoeheader.frameinfo1); switch (EOE_HDR_FRAME_TYPE_GET(frameinfo1)) { case EOE_FRAG_DATA: { EOE_receive_fragment (); break; } case EOE_INIT_REQ: { EOE_set_ip (); break; } case EOE_GET_IP_PARAM_REQ: { EOE_get_ip (); break; } case EOE_INIT_RESP_TIMESTAMP: case EOE_INIT_RESP: case EOE_SET_ADDR_FILTER_REQ: case EOE_SET_ADDR_FILTER_RESP: case EOE_GET_IP_PARAM_RESP: case EOE_GET_ADDR_FILTER_REQ: case EOE_GET_ADDR_FILTER_RESP: default: { DPRINT("EOE_RESULT_UNSUPPORTED_TYPE\n"); EOE_no_data_response ((EOE_HDR_FRAME_PORT & frameinfo1) | (EOE_HDR_FRAME_TYPE & frameinfo1) | EOE_HDR_LAST_FRAGMENT, EOE_RESULT_UNSUPPORTED_FRAME_TYPE); break; } } } MBXcontrol[0].state = MBXstate_idle; ESCvar.xoe = 0; } } /** EoE function to send a fragment. * NOTE: Not thread safe, should be called from the SOES task sequential * with other mailbox functions. Add support for threading by adding * a thread safe application fetch function, example a mailbox with buffers * to send, posted by TCP/IP stack and fetched by SOES task. */ void ESC_eoeprocess_tx (void) { if (ESCvar.MBXrun == 0) { return; } EOE_send_fragment (); }