diff --git a/APP_Framework/Applications/framework_init.c b/APP_Framework/Applications/framework_init.c index b34c32131..a22b351d6 100644 --- a/APP_Framework/Applications/framework_init.c +++ b/APP_Framework/Applications/framework_init.c @@ -21,6 +21,7 @@ extern int AdapterNbiotInit(void); extern int AdapterBlueToothInit(void); extern int AdapterWifiInit(void); extern int AdapterEthernetInit(void); +extern int AdapterEthercatInit(void); extern int AdapterZigbeeInit(void); extern int AdapterLoraInit(void); @@ -142,6 +143,9 @@ static struct InitDesc connection_desc[] = #ifdef CONNECTION_ADAPTER_ETHERNET { "ethernet adapter", AdapterEthernetInit}, #endif +#ifdef CONNECTION_ADAPTER_ETHERCAT + { "ethercat adapter", AdapterEthercatInit}, +#endif #ifdef CONNECTION_ADAPTER_LORA { "lora adapter", AdapterLoraInit}, #endif diff --git a/APP_Framework/Framework/connection/Kconfig b/APP_Framework/Framework/connection/Kconfig index 43094d28f..ea22c5fb2 100644 --- a/APP_Framework/Framework/connection/Kconfig +++ b/APP_Framework/Framework/connection/Kconfig @@ -62,6 +62,12 @@ if SUPPORT_CONNECTION_FRAMEWORK default n if CONNECTION_ADAPTER_ETHERNET source "$APP_DIR/Framework/connection/ethernet/Kconfig" + config CONNECTION_ADAPTER_ETHERCAT + bool "Using ethercat on ethernet adapter device" + default n + if CONNECTION_ADAPTER_ETHERCAT + source "$APP_DIR/Framework/connection/ethercat/Kconfig" + endif endif menuconfig CONNECTION_ADAPTER_BLUETOOTH diff --git a/APP_Framework/Framework/connection/ethercat/Kconfig b/APP_Framework/Framework/connection/ethercat/Kconfig new file mode 100644 index 000000000..0193e6a80 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/Kconfig @@ -0,0 +1,10 @@ +config ADAPTER_HFA21_ETHERCAT + depends on ADAPTER_HFA21_ETHERNET # ADAPTER_HFA21_WIFI + help + Ethercat is dependant on Ethernet. Please enable hfa21 ethernet first. And this is a software-defined experiment module, without supports on ECS and on-the-fly. + bool "Using ethercat on ethernet adapter device HFA21" + default n + +if ADAPTER_HFA21_ETHERCAT + source "$APP_DIR/Framework/connection/ethercat/hfa21_ethercat/Kconfig" +endif diff --git a/APP_Framework/Framework/connection/ethercat/Makefile b/APP_Framework/Framework/connection/ethercat/Makefile new file mode 100644 index 000000000..4dc242928 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/Makefile @@ -0,0 +1,7 @@ +SRC_FILES := adapter_ethercat.c + +ifeq ($(CONFIG_ADAPTER_HFA21_ETHERCAT),y) + SRC_DIR += hfa21_ethercat +endif + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/connection/ethercat/adapter_ethercat.c b/APP_Framework/Framework/connection/ethercat/adapter_ethercat.c new file mode 100644 index 000000000..640151505 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/adapter_ethercat.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file adapter_ethercat.c + * @brief Implement the connection ethercat adapter function, reuse the ethernet implementations + * @version 1.1 + * @author AIIT XUOS Lab + * @date 2021.10.15 + */ + +#include +#include + +#ifdef ADAPTER_HFA21_ETHERCAT +extern AdapterProductInfoType Hfa21EthercatAttach(struct Adapter *adapter); +#endif + +#define ADAPTER_ETHERCAT_NAME "ethercat" + +/** + * @description: clear the datagram in ethercat frame, do not free the frame itself, since it may be a memory space on stack + * @param frame - ethercat frame pointer + */ +void EcatClear(EcatFramePtr frame) +{ + EcatDatagramPtr datagram = frame->datagram; + while (datagram) + { + EcatDatagramPtr temp = datagram->next; + PrivFree(datagram->data); + PrivFree(datagram); + datagram = temp; + } + memset(frame, 0, sizeof(EcatFrame)); + frame->header.length = 2; // 2 bytes for the ethercat header + frame->header.res = 1; + frame->header.type = 0b1001; +} + +/** + * @description: receive data from adapter + * @param frame - ethercat frame pointer + * @param address - ethercat address + * @param data - data to be carried inside frame + * @param data_len - length of provided `data` + * @return success: 0, else return error code. + */ +int EcatAppend(EcatFramePtr frame, EcatAddress address, uint8_t *data, uint16_t data_len) +{ + EcatDatagramPtr datagram = frame->datagram; + if (!datagram) + { + datagram = PrivMalloc(sizeof(EcatDatagram)); + if (!datagram) + { + printf("EcatAppend malloc error\n"); + return -1; + } + memset(datagram, 0, sizeof(EcatDatagram)); + frame->datagram = datagram; + } + else + { + while (datagram->next) + { + datagram = datagram->next; + } + datagram->header.m = 1; // indcate the datagram is not the last one + datagram->next = PrivMalloc(sizeof(EcatDatagram)); + if (!datagram->next) + { + printf("EcatAppend malloc error\n"); + return -1; + } + memset(datagram->next, 0, sizeof(EcatDatagram)); + datagram = datagram->next; + } + datagram->header.address = address; + datagram->header.length = data_len; + datagram->data = data; + datagram->work_counter++; + frame->header.length += sizeof(datagram->header) + data_len + sizeof(datagram->work_counter); + printf("EcatAppend change length to %d\n", frame->header.length); + return 0; +} + +/** + * @description: find datagram for self and update its content + * @param frame - ethercat frame pointer + * @param address - ethercat address + * @param data - data to be carried inside frame + * @param data_len - length of provided `data` + * @return success: 0, else return error code. + */ +int EcatUpdate(EcatFramePtr frame, uint8_t *data, uint16_t data_len) +{ + EcatDatagramPtr datagram = frame->datagram; + if (!datagram) + { + printf("EcatUpdate error: null datagram.\n"); + return -1; + } + while (datagram) + { + if (datagram->self) + { + datagram->header.length = data_len; + frame->header.length -= strlen(datagram->data); + datagram->data = data; + frame->header.length += data_len; + datagram->work_counter++; + return 0; + } + else + { + datagram = datagram->next; + } + } + printf("EcatUpdate error: cannot find datagram for node itself.\n"); + return -2; +} + +static int AdapterEthercatRegister(struct Adapter *adapter) +{ + int ret = 0; + + strncpy(adapter->name, ADAPTER_ETHERCAT_NAME, NAME_NUM_MAX); + + adapter->net_protocol = IP_PROTOCOL; + adapter->adapter_status = UNREGISTERED; + + ret = AdapterDeviceRegister(adapter); + if (ret < 0) + { + printf("AdapterEthercat register error\n"); + return -1; + } + + return ret; +} + +int AdapterEthercatInit(void) +{ + int ret = 0; + + struct Adapter *adapter = PrivMalloc(sizeof(struct Adapter)); + if (!adapter) + { + printf("AdapterEthercatInit malloc error\n"); + PrivFree(adapter); + return -1; + } + + memset(adapter, 0, sizeof(struct Adapter)); + + ret = AdapterEthercatRegister(adapter); + if (ret < 0) + { + printf("AdapterEthercatInit register ethercat adapter error\n"); + PrivFree(adapter); + return -1; + } + +#ifdef ADAPTER_HFA21_ETHERCAT + AdapterProductInfoType product_info = Hfa21EthercatAttach(adapter); + if (!product_info) + { + printf("AdapterEthercatInit hfa21 attach error\n"); + PrivFree(adapter); + return -1; + } + + adapter->product_info_flag = 1; + adapter->info = product_info; + adapter->done = product_info->model_done; + +#endif + + return ret; +} + +/******************ethercat TEST*********************/ +extern int Hfa21EthercatSlaveTest(struct Adapter *adapter); +extern int Hfa21EthercatMasterTest(struct Adapter *adapter); + +int AdapterEthercatTest(void) +{ + struct Adapter *adapter = AdapterDeviceFindByName(ADAPTER_ETHERCAT_NAME); + +#ifdef ADAPTER_HFA21_ETHERCAT +#ifdef AS_ETHERCAT_SLAVE_ROLE + Hfa21EthercatSlaveTest(adapter); +#else // AS_ETHERCAT_MASTER_ROLE + Hfa21EthercatMasterTest(adapter); +#endif +#endif + + return 0; +} +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_PARAM_NUM(0) | SHELL_CMD_DISABLE_RETURN, AdapterEthercatTest, AdapterEthercatTest, show adapter ethercat information); diff --git a/APP_Framework/Framework/connection/ethercat/ethercat.h b/APP_Framework/Framework/connection/ethercat/ethercat.h new file mode 100644 index 000000000..77b655955 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/ethercat.h @@ -0,0 +1,103 @@ +#ifndef ETHERCAT_H +#define ETHERCAT_H + +#include + +#define BIG_ENDIAN_PACK __attribute__((packed, scalar_storage_order("big-endian"))) +#define LITTLE_ENDIAN_PACK __attribute__((packed, scalar_storage_order("little-endian"))) +#define ETHERCAT_PORT "34980" // 0x88A4 +#define MAX_FRAME_LEN 1500 +#define MIN_FRAME_LEN 14 + +typedef union BIG_ENDIAN_PACK +{ + struct BIG_ENDIAN_PACK + { + uint16_t length : 11; + uint16_t res : 1; + uint16_t type : 4; + }; + uint16_t header; +} EcatHeader, *EcatHeaderPtr; + +#define ECAT_HEADER_LENGTH 2 + +typedef union BIG_ENDIAN_PACK +{ + struct BIG_ENDIAN_PACK + { + uint16_t position; + uint16_t pos_offset; + }; // Position Addressing + struct BIG_ENDIAN_PACK + { + uint16_t address; + uint16_t addr_offset; + }; // Node Addressing + uint32_t logical; +} EcatAddress, *EcatAddressPtr; + +#define ECAT_ADDRESS_LENGTH 4 + +typedef struct +{ + uint8_t cmd; + uint8_t idx; + EcatAddress address; + union BIG_ENDIAN_PACK + { + struct BIG_ENDIAN_PACK + { + uint16_t length : 11; + uint16_t r : 3; + uint16_t c : 1; + uint16_t m : 1; // followed by more datagrams or not + }; + uint16_t suffix; // for easy parse + }; + uint16_t irq : 16; +} EcatDataHeader, *EcatDataHeaderPtr; + +#define ECAT_DATA_HEADER_LENGTH 10 + +typedef struct +{ + // frame data + EcatDataHeader header; // 10 bytes + uint8_t *data; // 0-1486 bytes + uint16_t work_counter; // 2bytes + // utilities + uint8_t self; // indicating this datagram is mine + void *next; // EcatDatagramPtr +} EcatDatagram, *EcatDatagramPtr; + +typedef struct +{ + EcatHeader header; // 2 bytes + EcatDatagramPtr datagram; // 12-1470 bytes +} EcatFrame, *EcatFramePtr; + +extern EcatFrame ecat_data; + +void EcatClear(EcatFramePtr frame); +int EcatAppend(EcatFramePtr frame, EcatAddress address, uint8_t *data, uint16_t data_len); +int EcatUpdate(EcatFramePtr frame, uint8_t *data, uint16_t data_len); + +#define READ8(buffer, offset) (((uint8_t *)buffer)[offset++]) +#define READ16(buffer, offset) ((uint16_t)((uint8_t *)buffer)[offset++] << 8 | (uint16_t)((uint8_t *)buffer)[offset++]) +#define READ32(buffer, offset) (uint32_t)((uint8_t *)buffer)[offset++] << 24 | \ + (uint32_t)((uint8_t *)buffer)[offset++] << 16 | \ + (uint32_t)((uint8_t *)buffer)[offset++] << 8 | \ + (uint32_t)((uint8_t *)buffer)[offset++] + +#define WRITE8(buffer, offset, value) ((uint8_t *)buffer)[offset++] = (uint8_t)(value & 0xFF); +#define WRITE16(buffer, offset, value) \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value >> 8 & 0xFF); \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value & 0xFF); +#define WRITE32(buffer, offset, value) \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value >> 24 & 0xFF); \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value >> 16 & 0xFF); \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value >> 8 & 0xFF); \ + ((uint8_t *)buffer)[offset++] = (uint8_t)(value & 0xFF); + +#endif \ No newline at end of file diff --git a/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Kconfig b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Kconfig new file mode 100644 index 000000000..fa56d3b52 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Kconfig @@ -0,0 +1,41 @@ +config ADAPTER_ETHERCAT_HFA21 + string "HFA21 EtherCAT adapter name" + default "hfa21_ethercat" + +config ADAPTER_ETHERCAT_HFA21_ROLE + choice + prompt "EtherCAT adapter select net role type " + default AS_ETHERCAT_SLAVE_ROLE + + config AS_ETHERCAT_MASTER_ROLE + bool "config as a master" + + config AS_ETHERCAT_SLAVE_ROLE + bool "config as a slave" + endchoice + + +config ADAPTER_ETHERCAT_HFA21_NETMASK + string "Current EtherCAT adapter netmask" + default "255.255.255.0" + + +config ADAPTER_ETHERCAT_HFA21_GATEWAY + string "Current EtherCAT adapter gateway" + default "10.10.100.254" + +config ADAPTER_ETHERCAT_HFA21_IP_SELF + string "Current EtherCAT adapter IP" + default "10.10.100.254" + +config ADAPTER_ETHERCAT_ADDRESS_SELF + string "Current EtherCAT address" + default 0x12345678 + +config ADAPTER_ETHERCAT_HFA21_IP_FROM + string "Receive Packet from IP" + default "10.10.100.50" + +config ADAPTER_ETHERCAT_HFA21_IP_TO + string "Send Packet to IP" + default "10.10.100.50" diff --git a/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Makefile b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Makefile new file mode 100644 index 000000000..b9178f04e --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := hfa21_ethercat.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/hfa21_ethercat.c b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/hfa21_ethercat.c new file mode 100644 index 000000000..820f391c2 --- /dev/null +++ b/APP_Framework/Framework/connection/ethercat/hfa21_ethercat/hfa21_ethercat.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file hfa21_ethercat.c + * @brief Implement the connection ethercat adapter function, using HFA21 device + * @version 1.1 + * @author AIIT XUOS Lab + * @date 2021.10.15 + */ + +#include +#include +#include + +// With HFA21, we use transparant transmission mode, +// therefore, only the TCP/UDP datagrams are considered, +// here EtherCAT is in fact an application layer protocol. + +#define ADAPTER_ETHERNET_NAME "ethernet" //"wifi" +EcatFrame ecat_data; +static struct Adapter *ethernet; +uint32_t self_address; + +/** + * @description: Open HFA21 ethernet uart function for ethercat + * @param adapter - ethercat device pointer + * @return success: 0, failure: -1 + */ +static int Hfa21EthercatOpen(struct Adapter *adapter) +{ + ethernet = AdapterDeviceFindByName(ADAPTER_ETHERNET_NAME); + AdapterDeviceOpen(ethernet); + ADAPTER_DEBUG("Hfa21Ethercat open done\n"); + + return 0; +} + +/** + * @description: disconnnect ethercat from internet + * @param adapter - ethercat device pointer + * @return success: 0 + */ +static int Hfa21EthercatSetDown(struct Adapter *adapter) +{ + if (ethernet) + { + AdapterDeviceClose(ethernet); + ethernet = NULL; + } + return 0; +} + +/** + * @description: Close HFA21 ethercat and uart function + * @param adapter - ethercat device pointer + * @return success: 0 + */ +static int Hfa21EthercatClose(struct Adapter *adapter) +{ + return Hfa21EthercatSetDown(adapter); +} + +static int Hfa21EthercatBuildAndSend(struct Adapter *adapter) +{ + int result = 0; + // fill the frame according to the ecat_data + uint16_t frame_len = sizeof(EcatHeader); + EcatDatagramPtr cur_data = ecat_data.datagram; + while (cur_data) + { + frame_len += sizeof(EcatDataHeader); + frame_len += cur_data->header.length; + frame_len += sizeof(cur_data->work_counter); + cur_data = (EcatDatagramPtr)cur_data->next; + } + if (frame_len > MAX_FRAME_LEN) + { + ADAPTER_DEBUG("frame_len is too long\n"); + result = -2; + goto __exit; + } + if (frame_len < MIN_FRAME_LEN) + { + ADAPTER_DEBUG("frame_len is too short\n"); + result = -2; + goto __exit; + } + uint8_t *frame = PrivMalloc(sizeof(uint8_t) * frame_len); + if (frame == NULL) + { + ADAPTER_DEBUG("Hfa21EthercatBuildAndSend: malloc failed\n"); + result = -1; + goto __exit; + } + + size_t idx = 0; + WRITE16(frame, idx, ecat_data.header.header); + cur_data = ecat_data.datagram; + while (cur_data) + { + WRITE8(frame, idx, cur_data->header.cmd); + WRITE8(frame, idx, cur_data->header.idx); + WRITE32(frame, idx, cur_data->header.address.logical); + WRITE16(frame, idx, cur_data->header.suffix); + WRITE16(frame, idx, cur_data->header.irq); + memcpy(frame + idx, cur_data->data, cur_data->header.length); + idx += cur_data->header.length; + WRITE16(frame, idx, cur_data->work_counter); + cur_data = (EcatDatagramPtr)cur_data->next; + } + // send the frame + if (ethernet && ethernet->agent) + { + result = EntmSend(ethernet->agent, (const char *)frame, frame_len); + if (result == 0) + { + result = frame_len; + } + } + else + { + printf("Hfa21Ethercat Send can not find agent!\n"); + result = -1; + goto __exit; + } + +__exit: + return result; +} + +/** + * @description: send data to adapter + * @param adapter - ethercat device pointer + * @param data - data buffer, when it is NULL, it means to build frame according to `ecat_data`, + * otherwise, it means to replace datagram in `ecat_data` and make up a frame. Slave can use + * this function to update its data. Master have to construct frame according to `ecat_data` and + * pass NULL data to this function. + * @param data - data length + * @return success: sent frame len + */ +static int Hfa21EthercatSend(struct Adapter *adapter, const void *data, size_t len) +{ + if (data == NULL || len == 0) + { + return Hfa21EthercatBuildAndSend(adapter); + } + EcatDatagramPtr cur_data = ecat_data.datagram; + size_t cur_len = 0; + while (cur_data) + { + if (cur_data->self) + { + PrivFree(cur_data->data); + cur_data->data = PrivMalloc(sizeof(uint8_t) * len); + memcpy(cur_data->data, data, len); + cur_data->header.length = len; + break; + } + cur_data = (EcatDatagramPtr)cur_data->next; + } + + return Hfa21EthercatBuildAndSend(adapter); +} + +/** + * @description: receive data from adapter + * @param adapter - ethercat device pointer + * @param data_buffer - data buffer, the whole received frame + * @param buffer_len - whole frame length, set it to maximum 1500 if you don't know the length + * @return success: data length, the data can be visited via variable `ecat_data` + */ +static int Hfa21EthercatReceive(struct Adapter *adapter, void *data_buffer, size_t buffer_len) +{ + // in fact, the length of data must be less than buffer_len + int result = 0; + if (ethernet && ethernet->agent) + { + // + result = EntmRecv(ethernet->agent, data_buffer, buffer_len, 40000); + } + else + { + printf("Hfa21Ethercat::Receive can not find agent!\n"); + result = -1; + goto __exit; + } + // parse header + size_t data_len = 0; + size_t idx = 0; + ecat_data.header.header = READ16(data_buffer, idx); + buffer_len -= ECAT_HEADER_LENGTH; + if (ecat_data.header.length > buffer_len) + { + printf("buffer size is less than the frame length!\n"); + result = -2; + } + if (ecat_data.header.length <= ECAT_DATA_HEADER_LENGTH) + { + // the first datagram header is too short + printf("Datagram is empty!\n"); + result = -3; + goto __exit; + } + + // parse datagrams + ecat_data.datagram = (EcatDatagramPtr)PrivMalloc(sizeof(EcatDatagram)); + EcatDatagramPtr cur_data = ecat_data.datagram; + do + { + // parse datagram header + cur_data->header.cmd = READ8(data_buffer, idx); + cur_data->header.idx = READ8(data_buffer, idx); + cur_data->header.address.logical = READ32(data_buffer, idx); + if (cur_data->header.address.logical == self_address) + { + cur_data->self = 1; // this datagram is mine + } + else + { + cur_data->self = 0; + } + cur_data->header.suffix = READ16(data_buffer, idx); + cur_data->header.irq = READ16(data_buffer, idx); + if (idx + cur_data->header.length + sizeof(cur_data->work_counter) > buffer_len) + { + printf("buffer size is less than the frame length!\n"); + result = -2; + goto __exit; + } + // parse datagram data + if (cur_data->data) + { + PrivFree(cur_data->data); + } + cur_data->data = PrivMalloc(sizeof(char) * cur_data->header.length); + memcpy(cur_data->data, data_buffer + idx, cur_data->header.length); + idx += cur_data->header.length; + memcpy(data_buffer + data_len, cur_data->data, cur_data->header.length); + data_len += cur_data->header.length; + cur_data->work_counter = READ16(data_buffer, idx); + // check header flag `more` for next datagram, move to next datagram if exists + if (cur_data->header.m == 1 && buffer_len >= idx + ECAT_DATA_HEADER_LENGTH) + { + if (!cur_data->next) + { + cur_data->next = PrivMalloc(sizeof(EcatDatagram)); + } + cur_data = (EcatDatagramPtr)cur_data->next; + } + else + { + cur_data = cur_data->next; + while (cur_data) + { + EcatDatagramPtr temp = (EcatDatagramPtr)cur_data->next; + PrivFree(cur_data->data); + PrivFree(cur_data); + cur_data = temp; + } + break; + } + } while (1); + result = data_len; +__exit: + return result; +} + +/** + * @description: connnect Ethercat to internet + * @param adapter - Ethercat device pointer + * @return success: 0 + */ +static int Hfa21EthercatSetUp(struct Adapter *adapter) +{ + if (ethernet) + { + return AdapterDeviceSetUp(ethernet); + } + return -1; +} + +/** + * @description: set ethercat ip/gateway/netmask address(in sta mode) working at WANN mode + * @param adapter - ethercat device pointer + * @param ip - ip address + * @param gateway - gateway address + * @param netmask - netmask address + * @return success: 0, failure: -ENOMEMORY or -1 + */ +static int Hfa21EthercatSetAddr(struct Adapter *adapter, const char *ip, const char *gateway, const char *netmask) +{ + if (ethernet) + { + return AdapterDeviceSetAddr(ethernet, + ip == NULL ? ADAPTER_ETHERCAT_HFA21_IP_SELF : ip, + gateway == NULL ? ADAPTER_ETHERCAT_HFA21_GATEWAY : gateway, + netmask == NULL ? ADAPTER_ETHERCAT_HFA21_NETMASK : netmask); + } + return -1; +} + +/** + * @description: ethercat ping function + * @param adapter - ethercat device pointer + * @param destination - domain name or ip address + * @return success: 0, failure: -1 + */ +static int Hfa21EthercatPing(struct Adapter *adapter, const char *destination) +{ + if (ethernet) + { + return AdapterDevicePing(ethernet, destination); + } + return -1; +} + +/** + * @description: ethercat connect function + * @param adapter - ethercat device pointer + * @param net_role - net role, CLIENT or SERVER + * @param ip - ip address + * @param port - port num + * @param ip_type - ip type, IPV4 or IPV6 + * @return success: 0, failure: -1 + */ +static int Hfa21EthercatConnect(struct Adapter *adapter, enum NetRoleType net_role, const char *ip, const char *port, enum IpType ip_type) +{ + + if (ethernet) + { + return AdapterDeviceConnect(ethernet, net_role, ip, + port == NULL ? ETHERCAT_PORT : port, ip_type); + } + return -1; +} + +static int Hfa21EthercatIoctl(struct Adapter *adapter, int cmd, void *args) +{ + if (ethernet) + { + return AdapterDeviceControl(ethernet, cmd, args); + } + return -1; +} + +static const struct IpProtocolDone hfa21_ethercat_done = + { + .open = Hfa21EthercatOpen, + .close = Hfa21EthercatClose, + .ioctl = Hfa21EthercatIoctl, + .setup = Hfa21EthercatSetUp, + .setdown = Hfa21EthercatSetDown, + .setaddr = Hfa21EthercatSetAddr, + .setdns = NULL, + .setdhcp = NULL, + .ping = Hfa21EthercatPing, + .netstat = NULL, + .connect = Hfa21EthercatConnect, + .send = Hfa21EthercatSend, + .recv = Hfa21EthercatReceive, + .disconnect = NULL, +}; + +/** + * @description: Register ethercat device hfa21 + * @return success: product_info, failure: NULL + */ +AdapterProductInfoType Hfa21EthercatAttach(struct Adapter *adapter) +{ + struct AdapterProductInfo *product_info = PrivMalloc(sizeof(struct AdapterProductInfo)); + if (!product_info) + { + printf("Hfa21EthercatAttach Attach malloc product_info error\n"); + PrivFree(product_info); + return NULL; + } + strcpy(product_info->model_name, ADAPTER_ETHERCAT_HFA21); + product_info->model_done = (void *)&hfa21_ethercat_done; + printf("str address during init: %s\n", ADAPTER_ETHERCAT_ADDRESS_SELF); + self_address = strtoul(ADAPTER_ETHERCAT_ADDRESS_SELF, NULL, 16); + printf("self address during init: %x\n", self_address); + return product_info; +} + +/** + * @description: Test case for slave ethercat device for hfa21 + * @return success: 0, failure: -1 + */ +int Hfa21EthercatSlaveTest(struct Adapter *adapter) +{ + int baud_rate = BAUD_RATE_57600; + char ethercat_recv_msg[128] = {0}; + int i, len = 0; + AdapterDeviceOpen(adapter); + AdapterDeviceControl(adapter, OPE_INT, &baud_rate); + AdapterDeviceSetUp(adapter); + // AdapterDeviceSetAddr(adapter, NULL, NULL, NULL); + + enum IpType ip_type = IPV4; + + printf("ready to test data transfer\n"); + + // for slave nodes, receive first, change the contents and then send it to next node + len = 1500; + for (i = 0; i < 10; i++) + { + // wait for neighbor node to send data + const char *ip_from = ADAPTER_ETHERCAT_HFA21_IP_FROM; + AdapterDeviceConnect(adapter, SERVER, ip_from, NULL, ip_type); + PrivTaskDelay(200); + AdapterDeviceRecv(adapter, ethercat_recv_msg, 1500); + printf("AdapterEthercatTest recv %s\n", ethercat_recv_msg); + memset(ethercat_recv_msg, 0, 128); + PrivTaskDelay(1000); + // send processed data to next node + const char *ip_to = ADAPTER_ETHERCAT_HFA21_IP_TO; + AdapterDeviceConnect(adapter, CLIENT, ip_to, NULL, ip_type); + PrivTaskDelay(200); + printf("AdapterEthercatTest send\n"); + AdapterDeviceSend(adapter, NULL, len); + PrivTaskDelay(1000); + } +} + +/** + * @description: Test case for master ethercat device for hfa21 + * @return success: 0, failure: -1 + */ +int Hfa21EthercatMasterTest(struct Adapter *adapter) +{ + int baud_rate = BAUD_RATE_57600; + char ethercat_recv_msg[128] = {0}; + int i, len = 0; + AdapterDeviceOpen(adapter); + AdapterDeviceControl(adapter, OPE_INT, &baud_rate); + AdapterDeviceSetUp(adapter); + // AdapterDeviceSetAddr(adapter, NULL, NULL, NULL); + // printf("setup addr\n"); + + enum IpType ip_type = IPV4; + // for master, manually build ethercat frame + EcatClear(&ecat_data); + printf("start build first block\n"); + EcatAddress slave1; + slave1.logical = 0x01020304; + char data1[] = "cats"; + EcatAppend(&ecat_data, slave1, data1, sizeof(data1)); + printf("start build second block\n"); + EcatAddress slave2; + slave2.logical = 0x20304050; + char data2[] = "dog"; + EcatAppend(&ecat_data, slave2, data2, sizeof(data2)); + + printf("ready to test data transfer\n"); + + len = 1500; + for (i = 0; i < 10; i++) + { + // send a frame to a slave node + const char *ip_to = ADAPTER_ETHERCAT_HFA21_IP_TO; + AdapterDeviceConnect(adapter, CLIENT, ip_to, NULL, ip_type); + PrivTaskDelay(200); + printf("[AdapterEthercatTest send]\n"); + AdapterDeviceSend(adapter, NULL, len); + PrivTaskDelay(1000); + // wait for slaves' responses + const char *ip_from = ADAPTER_ETHERCAT_HFA21_IP_FROM; + AdapterDeviceConnect(adapter, SERVER, ip_from, NULL, ip_type); + PrivTaskDelay(200); + AdapterDeviceRecv(adapter, ethercat_recv_msg, 1500); + printf("[AdapterEthercatTest recv] %s\n", ethercat_recv_msg); + memset(ethercat_recv_msg, 0, 128); + PrivTaskDelay(1000); + } +} \ No newline at end of file diff --git a/APP_Framework/Framework/connection/ethernet/adapter_ethernet.c b/APP_Framework/Framework/connection/ethernet/adapter_ethernet.c index 00a8dbf9b..654166ac7 100644 --- a/APP_Framework/Framework/connection/ethernet/adapter_ethernet.c +++ b/APP_Framework/Framework/connection/ethernet/adapter_ethernet.c @@ -101,7 +101,7 @@ int AdapterEthernetTest(void) const char *ip = "10.10.100.50"; const char *port = "12345"; - enum NetRoleType net_role = SERVER;//CLIENT + enum NetRoleType net_role = CLIENT;//SERVER enum IpType ip_type = IPV4; AdapterDeviceConnect(adapter, net_role, ip, port, ip_type); diff --git a/Ubiquitous/XiZi/path_kernel.mk b/Ubiquitous/XiZi/path_kernel.mk index 854a74407..e8911bd8b 100755 --- a/Ubiquitous/XiZi/path_kernel.mk +++ b/Ubiquitous/XiZi/path_kernel.mk @@ -258,6 +258,10 @@ KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/connection # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/connection/zigbee # endif +ifeq ($(CONFIG_ADAPTER_HFA21_ETHERCAT), y) +KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/connection/ethercat # +endif + ifeq ($(CONFIG_SUPPORT_KNOWING_FRAMEWORK), y) KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/knowing # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/knowing/tensorflow-lite/tensorflow-lite-for-mcu/source #