1195 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1195 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /****************************************************************************
 | |
| 
 | |
| Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
 | |
| 
 | |
| This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
 | |
| be copied by any method or incorporated into another program without
 | |
| the express written consent of Aerospace C.Power. This Information or any portion
 | |
| thereof remains the property of Aerospace C.Power. The Information contained herein
 | |
| is believed to be accurate and Aerospace C.Power assumes no responsibility or
 | |
| liability for its use in any way and conveys no license or title under
 | |
| any patent or copyright and makes no representation or warranty that this
 | |
| Information is free from patent or copyright infringement.
 | |
| 
 | |
| ****************************************************************************/
 | |
| /* os_ship header files */
 | |
| #include "os_task_api.h"
 | |
| #include "os_event_api.h"
 | |
| #include "os_timer_api.h"
 | |
| #include "os_utils_api.h"
 | |
| #include "os_lock_api.h"
 | |
| 
 | |
| /* iot common header files */
 | |
| #include "iot_io_api.h"
 | |
| #include "iot_module_api.h"
 | |
| #include "iot_errno_api.h"
 | |
| #include "iot_task_api.h"
 | |
| #include "iot_pkt_api.h"
 | |
| #include "iot_ipc_api.h"
 | |
| #include "iot_sg_ext_api.h"
 | |
| #include "iot_board_api.h"
 | |
| #include "iot_oem_api.h"
 | |
| #include "iot_plc_api.h"
 | |
| #include "iot_mem_pool_api.h"
 | |
| 
 | |
| #include "iot_grapp.h"
 | |
| #include "iot_proto_common.h"
 | |
| #include "iot_proto_ge.h"
 | |
| #include "iot_modbus_task.h"
 | |
| #include "iot_modbus_ext.h"
 | |
| 
 | |
| #if IOT_GE_MODBUS_TASK_ENABLE
 | |
| 
 | |
| #if (IOT_PSRAM_ENABLE)
 | |
| #define IOT_MODBUS_TASK_UART_BUF_SIZE       (2048)
 | |
| #else
 | |
| #define IOT_MODBUS_TASK_UART_BUF_SIZE       (256 + 64)
 | |
| #endif
 | |
| /* define ge FE A0 cmd max data len */
 | |
| #define IOT_GE_FE_A0_DATA_LEN_MAX           (GE_FRM_PLD_MAX_LEN - IOT_MAC_ADDR_LEN)
 | |
| /* print data buff in hex formate. */
 | |
| #define IOT_MODBUS_TASK_DATA_DUMP           (1)
 | |
| /* modbus bradcast addr is 0 */
 | |
| #define IOT_MODBUS_BROADCAST_ADDR           (0x0)
 | |
| /* modbus default slaver address */
 | |
| #define IOT_MODBUS_DEFAULT_SLAVER_ADDR      (0xff)
 | |
| 
 | |
| 
 | |
| #if PLC_SUPPORT_CCO_ROLE // master REQUEST
 | |
| const iot_mb_data_check_t mb_check[] = {
 | |
|     {0x02, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x01, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x05, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x0F, 1 + 6 + 2, 1, 0x06}, // 1 + 6 + n + 2
 | |
|     {0x04, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x03, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x06, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x10, 1 + 6 + 2, 1, 0x06}, // 1 + 6 + n + 2
 | |
|     {0x17, 1 + 10 + 2,1, 0x0A}, // 1 + 10 + n + 2
 | |
|     {0x16, 1 + 7 + 2, 0, 0xFF}, // 1 + 7 + 2
 | |
| };
 | |
| #else // slave RESPONSE
 | |
| const iot_mb_data_check_t mb_check[] = {
 | |
|     {0x02, 1 + 2 + 2, 1, 0x02}, // 1 + 2 + n + 2
 | |
|     {0x01, 1 + 2 + 2, 1, 0x02}, // 1 + 2 + n + 2
 | |
|     {0x05, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x0F, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x04, 1 + 2 + 2, 1, 0x02}, // 1 + 2 + n + 2
 | |
|     {0x03, 1 + 2 + 2, 1, 0x02}, // 1 + 2 + n + 2
 | |
|     {0x06, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x10, 1 + 5 + 2, 0, 0xff}, // 1 + 5 + 2
 | |
|     {0x17, 1 + 2 + 2, 1, 0x02}, // 1 + 2 + n + 2
 | |
|     {0x16, 1 + 7 + 2, 0, 0xff}, // 1 + 7 + 2
 | |
| };
 | |
| #endif
 | |
| const uint8_t max_func_code_num = sizeof(mb_check) / sizeof(mb_check[0]);
 | |
| 
 | |
| /** modbus_task message */
 | |
| typedef struct _iot_mb_task_msg {
 | |
|     /* iot task message */
 | |
|     iot_task_msg_t  task_msg;
 | |
|     /* pointer to message data */
 | |
|     void            *data;
 | |
|     /* another data field */
 | |
|     uint32_t        data2;
 | |
| } iot_mb_task_msg_t;
 | |
| 
 | |
| iot_mb_task_t mb_task;
 | |
| 
 | |
| #if IOT_MODBUS_RT_TABLE_SUPPORT
 | |
| 
 | |
| /* route entry max nums */
 | |
| #define IOT_MODBUS_MAC_RT_ENTRY_MAX          (32)
 | |
| /* route entry timeout, unit is second. */
 | |
| #define IOT_MODBUS_MAC_RT_ENTRY_TTL          (60)
 | |
| /* route entry update interval, unit is second. */
 | |
| #define IOT_MODBUS_MAC_RT_UPDATE_INTERVAL    (20)
 | |
| 
 | |
| /** iot mac address hash table entry */
 | |
| typedef struct _iot_modbus_addr_rout_entry {
 | |
|     struct _iot_modbus_addr_rout_entry *next;
 | |
|     /* modbus device id */
 | |
|     uint8_t             slaver_addr;
 | |
|     /** mac address of the entry */
 | |
|     uint8_t             addr[IOT_MAC_ADDR_LEN];
 | |
|     /* ttl of the route item. unit is s */
 | |
|     int                 ent_ttl;
 | |
| } iot_modbus_addr_rout_entry_t;
 | |
| 
 | |
| /* iot mac address hash table */
 | |
| typedef struct _iot_modbus_addr_rout_table {
 | |
|     /* number of entries supported */
 | |
|     uint16_t                entry_cnt;
 | |
|     /* size of each entry */
 | |
|     uint16_t                entry_size;
 | |
|     /* entry point for each entry item */
 | |
|     iot_modbus_addr_rout_entry_t   *rout_ent;
 | |
|     /* entry pool */
 | |
|     iot_mem_pool_t          *entry_p;
 | |
| } iot_modbus_addr_rout_table_t;
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_rt_update_timer_exe() - timer timeout callback function.
 | |
|  * @timer_id : timer id with that timer who causes this api-call.
 | |
|  * @arg : param past to this callback api.
 | |
|  */
 | |
| static void iot_mb_task_rt_update_timer_exe(timer_id_t timer_id, void * arg)
 | |
| {
 | |
|     (void)arg;
 | |
|     if (timer_id == mb_task.uart_timer) {
 | |
|         iot_mb_task_msg_post(IOT_MODBUS_TASK_MT_TIMER,
 | |
|             IOT_MODBUS_TASK_MSG_ID_TMR_RT_UPDATE_TIMEOUT, NULL);
 | |
|         os_reset_timer(timer_id);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_alloc_entry() - Alloc a rout entry from the mem pool.
 | |
|  */
 | |
| static iot_modbus_addr_rout_entry_t *iot_modbus_addr_rout_alloc_entry(
 | |
|     iot_modbus_addr_rout_table_t *table)
 | |
| {
 | |
|     return iot_mem_pool_alloc(table->entry_p);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_table_free_entry() - Free a rout entry of the mem pool.
 | |
|  */
 | |
| static void iot_modbus_addr_rout_table_free_entry(
 | |
|     iot_modbus_addr_rout_table_t *table, iot_modbus_addr_rout_entry_t *entry)
 | |
| {
 | |
|     iot_mem_pool_free(table->entry_p, entry);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_table_create() - Create a rout table.
 | |
|  */
 | |
| static iot_modbus_addr_rout_table_h iot_modbus_addr_rout_table_create(
 | |
|     module_id_t module, uint16_t entry_cnt, uint16_t entry_size)
 | |
| {
 | |
|     uint32_t ret;
 | |
|     iot_modbus_addr_rout_table_t *table = NULL;
 | |
| 
 | |
|     table = os_mem_malloc(module, sizeof(*table));
 | |
|     if (table == NULL) {
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     ret = iot_mem_pool_new(module, entry_cnt,
 | |
|         entry_size, &table->entry_p, 1);
 | |
|     if (ret)
 | |
|         goto err_table;
 | |
| 
 | |
|     table->entry_cnt = entry_cnt;
 | |
|     table->entry_size = entry_size;
 | |
|     goto out;
 | |
| 
 | |
| err_table:
 | |
|     os_mem_free(table);
 | |
|     table = NULL;
 | |
| out:
 | |
|     return table;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_table_clean() - Clean the modbus rout table.
 | |
|  */
 | |
| void iot_modbus_addr_rout_table_clean(iot_modbus_addr_rout_table_h handle)
 | |
| {
 | |
|     iot_modbus_addr_rout_table_t *table = handle;
 | |
|     iot_modbus_addr_rout_entry_t *entry = table->rout_ent;
 | |
|     iot_modbus_addr_rout_entry_t *tmp = NULL;
 | |
| 
 | |
|     while (entry) {
 | |
|         tmp = entry;
 | |
|         iot_mem_pool_free(table->entry_p, tmp);
 | |
|         entry = entry->next;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_table_find() - Find the rout entry by device id.
 | |
|  */
 | |
| static iot_modbus_addr_rout_entry_t *iot_modbus_addr_rout_table_find(
 | |
|     iot_modbus_addr_rout_table_h handle, uint8_t slave_addr)
 | |
| {
 | |
|     iot_modbus_addr_rout_table_t *table = handle;
 | |
|     iot_modbus_addr_rout_entry_t *entry = NULL;
 | |
| 
 | |
|     entry = table->rout_ent;
 | |
|     while (entry) {
 | |
|         if (entry->slaver_addr == slave_addr) {
 | |
|             break;
 | |
|         }
 | |
|         entry = entry->next;
 | |
|     }
 | |
| 
 | |
|     return entry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_addr_rout_table_find_replaced() - Find the smallest ttl
 | |
|  *                                   entry and return to replace it.
 | |
|  */
 | |
| static iot_modbus_addr_rout_entry_t *iot_modbus_addr_rout_table_find_replaced(
 | |
|     iot_modbus_addr_rout_table_h handle)
 | |
| {
 | |
|     iot_modbus_addr_rout_table_t *table = handle;
 | |
|     iot_modbus_addr_rout_entry_t *entry , *tmp;
 | |
| 
 | |
|     entry = table->rout_ent;
 | |
| 
 | |
|     if (entry == NULL) {
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     tmp = entry->next;
 | |
| 
 | |
|     while (tmp) {
 | |
|         if (entry->ent_ttl > tmp->ent_ttl) {
 | |
|             entry = tmp;
 | |
|         }
 | |
|         tmp = tmp->next;
 | |
|     }
 | |
| 
 | |
| out:
 | |
|     return entry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_add_addr_rt() - Add the MAC address and the corresponding
 | |
|  *                                   device id to the routing table .
 | |
|  */
 | |
| static uint8_t iot_modbus_add_addr_rt(iot_modbus_addr_rout_table_h rt_table,
 | |
|     uint8_t *dst_addr, uint8_t slave_addr)
 | |
| {
 | |
|     iot_modbus_addr_rout_entry_t *entry;
 | |
|     iot_modbus_addr_rout_table_t *table = rt_table;
 | |
| 
 | |
|     entry = (iot_modbus_addr_rout_entry_t *)iot_modbus_addr_rout_table_find(
 | |
|         rt_table, slave_addr);
 | |
| 
 | |
|     if (entry) {
 | |
|         entry->ent_ttl = IOT_MODBUS_MAC_RT_ENTRY_TTL;
 | |
|         if(!iot_mac_addr_cmp(dst_addr, entry->addr)) {
 | |
|                 iot_mac_addr_cpy(entry->addr, dst_addr);
 | |
|             }
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     /* entry not exist, try to add it */
 | |
|     entry = (iot_modbus_addr_rout_entry_t *)iot_modbus_addr_rout_alloc_entry(
 | |
|         rt_table);
 | |
|     if (entry == NULL) {
 | |
|         /* force get the entry that it's ttl is the smallest */
 | |
|         entry = iot_modbus_addr_rout_table_find_replaced(rt_table);
 | |
|         if (entry == NULL) {
 | |
|         } else {
 | |
|             entry->slaver_addr = slave_addr;
 | |
|             iot_mac_addr_cpy(entry->addr, dst_addr);
 | |
|             entry->ent_ttl = IOT_MODBUS_MAC_RT_ENTRY_TTL;
 | |
|         }
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     entry->slaver_addr = slave_addr;
 | |
|     iot_mac_addr_cpy(entry->addr, dst_addr);
 | |
|     entry->ent_ttl = IOT_MODBUS_MAC_RT_ENTRY_TTL;
 | |
| 
 | |
|     entry->next = table->rout_ent;
 | |
|     table->rout_ent = entry;
 | |
| 
 | |
|     iot_printf("[%s][info] update rt table successfully!\n", __FUNCTION__);
 | |
| 
 | |
| out:
 | |
| 
 | |
|     return ERR_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_update_addr_rt() - Update route table every 20 seconds .
 | |
|  */
 | |
| static void iot_modbus_update_addr_rt(iot_modbus_addr_rout_table_h rt_table)
 | |
| {
 | |
|     iot_modbus_addr_rout_table_t *table = (iot_modbus_addr_rout_table_t *)rt_table;
 | |
|     iot_modbus_addr_rout_entry_t *tmp, *entry = table->rout_ent;
 | |
| 
 | |
|     if (entry == NULL) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     tmp = entry->next;
 | |
| 
 | |
|     while(tmp) {
 | |
|         if (tmp->ent_ttl <= 0) {
 | |
|             entry->next = tmp->next;
 | |
|             iot_modbus_addr_rout_table_free_entry(table, tmp);
 | |
|             tmp = entry->next;
 | |
|         } else {
 | |
|             tmp->ent_ttl -= IOT_MODBUS_MAC_RT_UPDATE_INTERVAL;
 | |
|             entry = entry->next;
 | |
|             tmp = entry->next;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     entry = table->rout_ent;
 | |
| 
 | |
|     if (entry) {
 | |
|         if (entry->ent_ttl <= 0) {
 | |
|             table->rout_ent = entry->next;
 | |
|             iot_modbus_addr_rout_table_free_entry(table, entry);
 | |
|         } else {
 | |
|             entry->ent_ttl -= IOT_MODBUS_MAC_RT_UPDATE_INTERVAL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_modbus_get_addr_rt() - Get the MAC address by looking up the
 | |
|  *                                   routing table with the device id.
 | |
|  */
 | |
| static uint8_t iot_modbus_get_addr_rt(iot_modbus_addr_rout_table_h rt_table,
 | |
|     uint8_t slave_addr, uint8_t *dst_addr)
 | |
| {
 | |
|     iot_modbus_addr_rout_entry_t *entry;
 | |
| 
 | |
|     if (dst_addr == NULL) {
 | |
|         return ERR_FAIL;
 | |
|     }
 | |
| 
 | |
|     entry = (iot_modbus_addr_rout_entry_t *)iot_modbus_addr_rout_table_find(
 | |
|         rt_table, slave_addr);
 | |
| 
 | |
|     if (entry) {
 | |
|         iot_mac_addr_cpy(dst_addr, entry->addr);
 | |
|     } else {
 | |
|         return ERR_FAIL;
 | |
|     }
 | |
| 
 | |
|     iot_printf("[%s][info] get rt entry successfully!\n", __FUNCTION__);
 | |
| 
 | |
|     return ERR_OK;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| static uint8_t iot_mb_task_get_slaver_addr(uint8_t *modbus_data)
 | |
| {
 | |
|     return modbus_data[0];
 | |
| }
 | |
| 
 | |
| void iot_mb_task_data_dump(uint8_t * buf, uint32_t len, uint32_t line)
 | |
| {
 | |
| #if IOT_MODBUS_TASK_DATA_DUMP
 | |
|     uint32_t i;
 | |
| 
 | |
|     iot_cus_printf("[mb_task]DUMP(%03d)@line:%d", len, line);
 | |
|     for (i = 0; i < len; i++) {
 | |
|         iot_cus_printf(" %02X", buf[i]);
 | |
|     }
 | |
|     iot_cus_printf("\n");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_msg_post_to_uart() - send data to uart port.
 | |
|  * @param p_pkt_frame: pointer of pkt frame data buffer.
 | |
|  * @return ERR_OK
 | |
|  */
 | |
| uint32_t iot_mb_task_msg_post_to_uart(iot_uart_h uart_h, iot_pkt_t *p_pkt_frame)
 | |
| {
 | |
|     uint32_t ret;
 | |
| 
 | |
|     ret = iot_uart_send(uart_h, p_pkt_frame, NULL);
 | |
| 
 | |
|     return (ERR_OK == ret) ? ERR_OK : ERR_FAIL;
 | |
| }
 | |
| 
 | |
| static uint32_t iot_mb_task_msg_msg_from_ge(iot_pkt_t *p_pkt_frame)
 | |
| {
 | |
|     ge_frame_data_send_set_subfn160_t *p_subfn160;
 | |
|     ge_fn160_appdata_mb_t *p_fn160_appdata; /* modbus proto in ge fn160 */
 | |
|     uint32_t fn160_applen;                  /* fn160 append data len */
 | |
|     iot_pkt_t *p_mb_pkt;        /* pkt for task message post to uart */
 | |
|     uint32_t mb_len;            /* current ge modbus frame length */
 | |
|     static uint8_t frame_idx_count; /* check current frame index order */
 | |
|     uint8_t slaver_addr = 0;
 | |
|     uint8_t src_mac[IOT_MAC_ADDR_LEN] = {0};
 | |
| 
 | |
|     if (p_pkt_frame == NULL) {
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     iot_cus_printf("[mb_task]frame receive from GE.\n");
 | |
|     iot_mb_task_data_dump(iot_pkt_data(p_pkt_frame),
 | |
|         iot_pkt_data_len(p_pkt_frame), __LINE__);
 | |
| 
 | |
|     p_subfn160 = (ge_frame_data_send_set_subfn160_t*)iot_pkt_data(p_pkt_frame);
 | |
|     if (p_subfn160->hdr.hdr.fn == PROTO_GE_PLC_SET_CMD
 | |
|         && p_subfn160->hdr.subfn == PROTO_GE_DATA_CMD) {
 | |
|         /* subfn160 appdata */
 | |
|         p_fn160_appdata = (ge_fn160_appdata_mb_t *)p_subfn160->data;
 | |
|         fn160_applen = p_subfn160->hdr.hdr.data_len - IOT_MAC_ADDR_LEN;
 | |
|         if (p_fn160_appdata->type == IOT_FN160_TYPE_MODBUS) {
 | |
|             iot_mac_addr_cpy(src_mac, p_fn160_appdata->src_mac);
 | |
| #if PLC_SUPPORT_STA_ROLE
 | |
|             /* save cco mac addr */
 | |
|             iot_mac_addr_cpy(mb_task.dest_cco_mac, p_fn160_appdata->src_mac);
 | |
| #endif
 | |
|             /* first frame need reset ge buff len and frame index check count */
 | |
|             if (p_fn160_appdata->frame_idx == 0) {
 | |
|                 mb_task.ge_mb_len = 0;
 | |
|                 frame_idx_count = 0;
 | |
|             }
 | |
|             /* Is the current frame index order correct?  */
 | |
|             if  (frame_idx_count != p_fn160_appdata->frame_idx) {
 | |
|                 iot_cus_printf("[mb_task][err] ge frame index error\n");
 | |
|                 frame_idx_count = 0;
 | |
|                 iot_pkt_free(p_pkt_frame);
 | |
|                 return ERR_FAIL;
 | |
|             } else {
 | |
|                 frame_idx_count++;
 | |
|             }
 | |
|             /* remove other append data, get modbus data length */
 | |
|             mb_len = fn160_applen - sizeof(ge_fn160_appdata_mb_t);
 | |
|             /* remain ge buffer size >= current modbus frame size. */
 | |
|             if (mb_len <= sizeof(mb_task.ge_mb_buf) - mb_task.ge_mb_len) {
 | |
|                 /* copy current modbus data to ge buff offset index */
 | |
|                 os_mem_cpy(mb_task.ge_mb_buf + mb_task.ge_mb_len ,
 | |
|                     p_fn160_appdata->data, mb_len);
 | |
|                 mb_task.ge_mb_len += mb_len;
 | |
|             } else {
 | |
|                 iot_cus_printf("[mb_task][warning] ge modbus data overflow, dropped!!!\n");
 | |
|             }
 | |
|             iot_pkt_free(p_pkt_frame);
 | |
| 
 | |
|             /* last modbus frame, malloc pkt, then send modbus pkt to uart. */
 | |
|             if (p_fn160_appdata->frame_idx == p_fn160_appdata->frame_total - 1) {
 | |
| 
 | |
|                 if (mb_task.ge_mb_len) {
 | |
|                     p_mb_pkt = iot_pkt_alloc(mb_task.ge_mb_len, IOT_MODBUS_TASK_ID);
 | |
|                     if (NULL == p_mb_pkt) {
 | |
|                         iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|                         IOT_ASSERT(0);
 | |
|                         return ERR_FAIL;
 | |
|                     }
 | |
| 
 | |
|                     os_mem_cpy(iot_pkt_put(p_mb_pkt, mb_task.ge_mb_len),
 | |
|                         mb_task.ge_mb_buf, mb_task.ge_mb_len);
 | |
| 
 | |
|                     slaver_addr = iot_mb_task_get_slaver_addr(mb_task.ge_mb_buf);
 | |
| #if IOT_MODBUS_RT_TABLE_SUPPORT
 | |
|                     if (slaver_addr != IOT_MODBUS_BROADCAST_ADDR) {
 | |
|                         /* add rt entry */
 | |
|                         iot_modbus_add_addr_rt(mb_task.rt_table, src_mac, slaver_addr);
 | |
|                     }
 | |
| #endif
 | |
| 
 | |
|                     if ((slaver_addr == mb_task.slave_addr) ||
 | |
|                         (IOT_MODBUS_BROADCAST_ADDR == slaver_addr)) {
 | |
|                         iot_mb_ext_cmd_handler(mb_task.ge_mb_buf, mb_task.ge_mb_len,
 | |
|                             MODBUS_CMD_FROM_PLC);
 | |
|                     }
 | |
| 
 | |
|                     mb_task.ge_mb_len = 0;
 | |
|                     frame_idx_count = 0;
 | |
| 
 | |
|                     if ((slaver_addr != mb_task.slave_addr) ||
 | |
|                         (IOT_MODBUS_BROADCAST_ADDR == slaver_addr)) {
 | |
|                         iot_mb_task_msg_post_to_uart(mb_task.uart_h, p_mb_pkt);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             goto out;
 | |
|         }
 | |
|         goto ge2uart;
 | |
|     }
 | |
| 
 | |
|     if (ERR_OK == iot_mb_ext_handle_resp_from_ge(p_pkt_frame)) {
 | |
|         iot_pkt_free(p_pkt_frame);
 | |
|         goto out;
 | |
|     }
 | |
| ge2uart:
 | |
|     iot_mb_task_msg_post_to_uart(mb_task.uart_h, p_pkt_frame);
 | |
| out:
 | |
|     return ERR_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_post_uart_cmd() - recveived command from uart, send to
 | |
|  *                                       common proto
 | |
|  * @param data: command data.
 | |
|  * @param len : command data length.
 | |
|  * @return    : ERR_OK   - send successfully.
 | |
|  *              ERR_FAIL - send failed.
 | |
|  */
 | |
| uint8_t iot_mb_task_post_uart_cmd(uint8_t * data, uint16_t len, uint32_t param)
 | |
| {
 | |
|     (void)param;
 | |
|     iot_pkt_t* send_pkt;
 | |
| 
 | |
|     iot_cus_printf("[%s][info] data:%p, len:%d\n", __FUNCTION__, data, len);
 | |
| 
 | |
|     send_pkt = iot_pkt_alloc(len, IOT_MODBUS_TASK_ID);
 | |
|     if (send_pkt) {
 | |
|         /* copy data from buf to data packet */
 | |
|         os_mem_cpy(iot_pkt_put(send_pkt, len), data, len);
 | |
| 
 | |
|         /* alloc message to insert proto task msg queue */
 | |
|         iot_mb_task_msg_post(IOT_MODBUS_TASK_MT_UART,
 | |
|               IOT_MODBUS_TASK_MSG_ID_CMD_HANDLE, send_pkt);
 | |
|         return ERR_OK;
 | |
|     } else {
 | |
|         iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|         IOT_ASSERT(0);
 | |
|         return ERR_FAIL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Compute the MODBUS RTU CRC. */
 | |
| uint16_t iot_modbus_rtu_crc16(uint8_t *buf, uint32_t len)
 | |
| {
 | |
|     uint16_t crc = 0xFFFF;
 | |
| 
 | |
|     for (uint32_t pos = 0; pos < len; pos++) {
 | |
|         crc ^= (uint16_t)buf[pos];        /* XOR byte into least sig. byte of crc */
 | |
|         for (uint8_t i = 8; i != 0; i--) {/* Loop over each bit */
 | |
|             if ((crc & 0x0001) != 0) {    /* If the LSB is set */
 | |
|                 crc >>= 1;                /* Shift right and XOR 0xA001 */
 | |
|                 crc ^= 0xA001;
 | |
|             } else {                      /* Else LSB is not set */
 | |
|                 crc >>= 1;                /* Just shift right */
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /* Note, this number has low and high bytes swapped,
 | |
|     so use it accordingly (or swap bytes) */
 | |
|     return crc;
 | |
| }
 | |
| 
 | |
| iot_pkt_t *iot_modbus_fn160_appdata_pack(uint8_t *mb_data, uint32_t mb_len,
 | |
|     uint32_t curr_idx, uint32_t total_idx)
 | |
| {
 | |
|     ge_frame_data_send_set_subfn160_t *p_subfn160;
 | |
|     ge_fn160_appdata_mb_t *p_fn160_appdata;
 | |
|     uint32_t appdata_len = sizeof(ge_fn160_appdata_mb_t) + mb_len;
 | |
|     /* subfn160 header + appdata + crc16(2 bytes) + proto end frame(1 bytes) */
 | |
|     uint32_t alloc_len = sizeof(ge_frame_data_send_set_subfn160_t) + appdata_len
 | |
|         + 2 + 1;
 | |
|     uint16_t crc16;
 | |
|     iot_pkt_t* p_ge_pkt;
 | |
| 
 | |
|     p_ge_pkt = iot_pkt_alloc(alloc_len, IOT_MODBUS_TASK_ID);
 | |
|     if (NULL == p_ge_pkt) {
 | |
|         iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|         IOT_ASSERT(0);
 | |
|         return NULL;
 | |
|     }
 | |
|     p_subfn160 = (ge_frame_data_send_set_subfn160_t*)iot_pkt_put(p_ge_pkt, alloc_len);
 | |
|     /* fix header */
 | |
|     p_subfn160->hdr.hdr.preamble = GE_FRM_PREAMBLE_CODE;
 | |
|     p_subfn160->hdr.hdr.fn = PROTO_GE_PLC_SET_CMD;
 | |
|     p_subfn160->hdr.hdr.data_len = appdata_len + IOT_MAC_ADDR_LEN;
 | |
|     p_subfn160->hdr.subfn = PROTO_GE_DATA_CMD;
 | |
|     /* resv 2 bytes */
 | |
|     p_subfn160->force_tx_connless = 0;
 | |
|     p_subfn160->force_noaggr = 1;
 | |
|     p_subfn160->recv_connless = 0;
 | |
|     p_subfn160->data_type = 0;
 | |
|     /* payload */
 | |
| #if PLC_SUPPORT_STA_ROLE
 | |
|     iot_mac_addr_cpy(p_subfn160->dest_mac, mb_task.dest_cco_mac);
 | |
| #endif
 | |
| #if IOT_MODBUS_RT_TABLE_SUPPORT
 | |
|     uint8_t dest_mac[IOT_MAC_ADDR_LEN];
 | |
|     uint8_t slave_addr = iot_mb_task_get_slaver_addr(mb_data);
 | |
|     if (ERR_OK != iot_modbus_get_addr_rt(mb_task.rt_table, slave_addr, dest_mac)) {
 | |
|         os_mem_set(p_subfn160->dest_mac, 0xff, IOT_MAC_ADDR_LEN);
 | |
|     } else {
 | |
|         iot_mac_addr_cpy(p_subfn160->dest_mac, dest_mac);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     /* subfn160 appdata */
 | |
|     p_fn160_appdata = (ge_fn160_appdata_mb_t *)p_subfn160->data;
 | |
|     p_fn160_appdata->type = IOT_FN160_TYPE_MODBUS; /* modbus proto */
 | |
|     iot_mac_addr_cpy(p_fn160_appdata->src_mac, mb_task.local_mac);
 | |
|     p_fn160_appdata->frame_idx = curr_idx;
 | |
|     p_fn160_appdata->frame_total = total_idx;
 | |
|     /* modbus raw data */
 | |
|     os_mem_cpy(p_fn160_appdata->data, mb_data, mb_len);
 | |
| 
 | |
|     crc16 = ge_frm_checksum_calc((uint8_t *)p_subfn160, alloc_len - 3);
 | |
|     *((uint8_t*)p_subfn160 + alloc_len - 3) = crc16 & 0xff;
 | |
|     *((uint8_t*)p_subfn160 + alloc_len - 2) = (crc16 >> 8) & 0xff;
 | |
|     *((uint8_t*)p_subfn160 + alloc_len - 1) = GE_FRM_TAIL_CODE;
 | |
| 
 | |
|     return p_ge_pkt;
 | |
| }
 | |
| 
 | |
| static uint8_t iot_modbus_data_check(uint8_t *p_buffer, uint32_t buffer_len)
 | |
| {
 | |
|     iot_pkt_t *p_pkt;
 | |
|     uint32_t buf_index;
 | |
|     uint32_t buf_offset;
 | |
|     uint32_t buf_len;
 | |
|     uint32_t curr_idx;
 | |
|     uint32_t total_idx;
 | |
|     uint32_t lookup_fc_idx; //look up func code index
 | |
|     uint32_t mb_total_len;
 | |
|     uint16_t crc16;
 | |
|     uint8_t have_modbus_frame = 0, slaver_addr = 0;
 | |
| 
 | |
|     for (buf_index = 0; (buffer_len >= 5) && (buf_index <= buffer_len - 5); ) {
 | |
|         uint8_t *p_buf_index = p_buffer + buf_index;
 | |
|         iot_cus_printf("index=%d\r\n", buf_index);
 | |
|         /* lookup function code index */
 | |
|         for (lookup_fc_idx = 0; lookup_fc_idx < max_func_code_num; lookup_fc_idx++) {
 | |
|             if (mb_check[lookup_fc_idx].func_code == p_buf_index[1] ||
 | |
|                 (mb_check[lookup_fc_idx].func_code | 0x80) == p_buf_index[1]) {
 | |
|                 iot_cus_printf("func_code=%d\r\n", p_buf_index[1]);
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         /* can not find valid func code */
 | |
|         if (lookup_fc_idx == max_func_code_num) {
 | |
|             buf_index++;
 | |
|             continue;
 | |
|         }
 | |
|         /* from func code get modbus total len, then checkout modbus crc16 */
 | |
|         if ((p_buf_index[1] & 0x80) == 0) { /* normal function code */
 | |
|             mb_total_len = mb_check[lookup_fc_idx].min_len +
 | |
|                 (mb_check[lookup_fc_idx].not_fix_len ?
 | |
|                     p_buf_index[mb_check[lookup_fc_idx].byte_count_idx] : 0);
 | |
|         } else { /* error function code */
 | |
|             mb_total_len = 5;
 | |
|         }
 | |
|         iot_cus_printf("mb_total_len=%d, buffer_len-index=%d\r\n",
 | |
|             mb_total_len,  (buffer_len - buf_index));
 | |
|         /* modbus lenth <= remain buffer lenth. */
 | |
|         if (mb_total_len > buffer_len - buf_index) {
 | |
|             buf_index++;
 | |
|             continue;
 | |
|         }
 | |
|         /* check modbus crc */
 | |
|         crc16 = iot_modbus_rtu_crc16(p_buf_index, mb_total_len - 2);
 | |
|         if (crc16 !=
 | |
|             (((uint16_t)p_buf_index[mb_total_len-1]<<8) | p_buf_index[mb_total_len-2])) {
 | |
|             buf_index++;
 | |
|             continue;
 | |
|         }
 | |
|         iot_cus_printf("uart----------------------modbus\r\n");
 | |
| 
 | |
|         slaver_addr = iot_mb_task_get_slaver_addr(p_buf_index);
 | |
| 
 | |
|         if ((slaver_addr != mb_task.slave_addr) ||
 | |
|             (IOT_MODBUS_BROADCAST_ADDR == slaver_addr)) {
 | |
|             total_idx = (mb_total_len /
 | |
|                 (IOT_GE_FE_A0_DATA_LEN_MAX - sizeof(ge_fn160_appdata_mb_t))) + 1;
 | |
|             /* front frame */
 | |
|             for (curr_idx = 0; curr_idx < total_idx - 1; curr_idx++) {
 | |
|                 buf_offset = (IOT_GE_FE_A0_DATA_LEN_MAX -
 | |
|                     sizeof(ge_fn160_appdata_mb_t)) * curr_idx;
 | |
|                 buf_len = IOT_GE_FE_A0_DATA_LEN_MAX - sizeof(ge_fn160_appdata_mb_t);
 | |
|                 p_pkt = iot_modbus_fn160_appdata_pack(p_buf_index + buf_offset,
 | |
|                     buf_len, curr_idx, total_idx);
 | |
|                 if (NULL == p_pkt) {
 | |
|                     iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|                     IOT_ASSERT(0);
 | |
|                     return -1;
 | |
|                 }
 | |
|                 iot_mb_task_data_dump(iot_pkt_data(p_pkt), iot_pkt_data_len(p_pkt), __LINE__);
 | |
|                 /* parser ge command and post to task */
 | |
|                 iot_proto_data_parse_and_post(iot_pkt_data(p_pkt),
 | |
|                     iot_pkt_data_len(p_pkt), iot_mb_task_post_uart_cmd, 0);
 | |
|                 iot_pkt_free(p_pkt);
 | |
|             }
 | |
|             /* last frame */
 | |
|             buf_offset = (IOT_GE_FE_A0_DATA_LEN_MAX -
 | |
|                 sizeof(ge_fn160_appdata_mb_t)) * curr_idx;
 | |
|             buf_len = mb_total_len % (IOT_GE_FE_A0_DATA_LEN_MAX -
 | |
|                 sizeof(ge_fn160_appdata_mb_t));
 | |
|             p_pkt = iot_modbus_fn160_appdata_pack(p_buf_index + buf_offset, buf_len,
 | |
|                 curr_idx, total_idx);
 | |
|             if (NULL == p_pkt) {
 | |
|                 iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|                 IOT_ASSERT(0);
 | |
|                 return -1;
 | |
|             }
 | |
|             iot_mb_task_data_dump(iot_pkt_data(p_pkt), iot_pkt_data_len(p_pkt), __LINE__);
 | |
|             /* parser ge command and post to task */
 | |
|             iot_proto_data_parse_and_post(iot_pkt_data(p_pkt), iot_pkt_data_len(p_pkt),
 | |
|                 iot_mb_task_post_uart_cmd, 0);
 | |
|             iot_pkt_free(p_pkt);
 | |
|         }
 | |
| 
 | |
|         if ((slaver_addr == mb_task.slave_addr) ||
 | |
|             (IOT_MODBUS_BROADCAST_ADDR == slaver_addr)) {
 | |
|             iot_mb_ext_cmd_handler(p_buf_index, mb_total_len, MODBUS_CMD_FROM_UART);
 | |
|         }
 | |
| 
 | |
|         buf_index += mb_total_len;
 | |
|         have_modbus_frame = 1;
 | |
|     }
 | |
|     return have_modbus_frame;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_uart_msg_process() - process the data from uart.
 | |
|  * @param p_modbus_msg: message received from uart. msg->data will be
 | |
|  *   freed by this handle but msg will not.
 | |
|  */
 | |
| static void iot_mb_task_uart_msg_process(iot_mb_task_msg_t *msg)
 | |
| {
 | |
|     iot_pkt_t * p_pkt = (iot_pkt_t*)msg->data;
 | |
| 
 | |
|     switch (msg->task_msg.id) {
 | |
|         case IOT_MODBUS_TASK_MSG_ID_CMD_HANDLE:
 | |
|         {
 | |
|             /* trans to GE command */
 | |
|             iot_cus_task_message_to_ge(iot_pkt_data(p_pkt),
 | |
|                 iot_pkt_data_len(p_pkt));
 | |
|             iot_pkt_free(p_pkt);
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|         {
 | |
|             iot_cus_printf("[mb_task]unknown uart message id #%d.\n",
 | |
|                 msg->task_msg.id);
 | |
|             IOT_ASSERT(0);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_timer_msg_process() - process data from local timer.
 | |
|  * @msg : message.
 | |
|  */
 | |
| static void iot_mb_task_timer_msg_process(iot_mb_task_msg_t *msg)
 | |
| {
 | |
|     switch (msg->task_msg.id) {
 | |
|         case IOT_MODBUS_TASK_MSG_ID_TMR_GE_START_MONITOR:
 | |
|         {
 | |
|             if (iot_grapp_init_success()) {
 | |
|                 iot_grapp_reg_fn_receive_from_ge(HOST_PORT_CUSTOM_TASK,
 | |
|                     iot_mb_task_msg_msg_from_ge);
 | |
|                 iot_grapp_set_uart_config(mb_task.uart_h);
 | |
|                 os_stop_timer(mb_task.ge_start_timer);
 | |
|                 /* update local mac addr. */
 | |
|                 iot_mac_addr_cpy(mb_task.local_mac, prototask_contxt.local_dev.mac);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|         case IOT_MODBUS_TASK_MSG_ID_TMR_UART_MB_TIMEOUT:
 | |
|         {
 | |
|             if (mb_task.uart_mb_len > 0) {
 | |
|                 /* if not have modbus frame, then send data use ge proto. */
 | |
|                 if (iot_modbus_data_check(mb_task.uart_mb_buf,
 | |
|                     mb_task.uart_mb_len) == 0) {
 | |
|                     iot_cus_printf("uart----------------------ge\r\n");
 | |
|                     /* parser ge command and post to task */
 | |
|                     iot_proto_data_parse_and_post(mb_task.uart_mb_buf,
 | |
|                         mb_task.uart_mb_len, iot_mb_task_post_uart_cmd, 0);
 | |
|                 }
 | |
|                 mb_task.uart_mb_len = 0;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| #if IOT_MODBUS_RT_TABLE_SUPPORT
 | |
|         case IOT_MODBUS_TASK_MSG_ID_TMR_RT_UPDATE_TIMEOUT:
 | |
|         {
 | |
|             iot_modbus_update_addr_rt(mb_task.rt_table);
 | |
|             break;
 | |
|         }
 | |
| #endif
 | |
|         case IOT_MODBUS_MSG_ID_TMR_MB_EXT_RESP_TIMEOUT:
 | |
|         {
 | |
|             iot_mb_ext_resp_cmd_timeout_or_failed();
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|         {
 | |
|             iot_cus_printf("[mb_task]unknown timer message id #%d.\n",
 | |
|                 msg->task_msg.id);
 | |
|             IOT_ASSERT(0);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_internal_msg_process() - process the data from modbus-task.
 | |
|  * @param msg: message received from modbus-task. msg->data
 | |
|  *   will be freed by this handle but msg will not.
 | |
|  */
 | |
| static void iot_mb_task_internal_msg_process(iot_mb_task_msg_t *msg)
 | |
| {
 | |
|     iot_pkt_t * p_pkt = (iot_pkt_t*)msg->data;
 | |
|     uint8_t *p_data = NULL;
 | |
|     uint32_t data_len = 0;
 | |
| 
 | |
|     switch (msg->task_msg.id) {
 | |
|         case IOT_MODBUS_TASK_MSG_ID_CMD_HANDLE:
 | |
|         {
 | |
|             p_data = iot_pkt_data(p_pkt);
 | |
|             data_len = iot_pkt_data_len(p_pkt);
 | |
|             iot_cus_printf("uart buf index=%d\n", mb_task.uart_mb_len);
 | |
|             /* save all uart data to uart recv buff, if timer timeout, task begin to
 | |
|             checkout modbus frame. */
 | |
|             if (data_len <= sizeof(mb_task.uart_mb_buf) - mb_task.uart_mb_len) {
 | |
|                 /* copy data to uart recv buffer. */
 | |
|                 os_mem_cpy(mb_task.uart_mb_buf + mb_task.uart_mb_len, p_data, data_len);
 | |
|                 mb_task.uart_mb_len += data_len;
 | |
|             } else {
 | |
|                 iot_cus_printf("[mb_task][warning] uart modbus data overflow, dropped!!!\n");
 | |
|             }
 | |
|             iot_pkt_free(p_pkt);
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|         {
 | |
|             IOT_ASSERT(0);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_msg_exe_func() - messages handle function.
 | |
|  * @param task_h: handle of task.
 | |
|  * @param p_msg: message that will be processed.
 | |
|  */
 | |
| static void iot_mb_task_msg_exe_func(iot_task_h task_h, iot_task_msg_t *p_msg)
 | |
| {
 | |
|     iot_mb_task_msg_t *p_mb_msg = (iot_mb_task_msg_t *)p_msg;
 | |
| 
 | |
|     switch (p_mb_msg->task_msg.type)
 | |
|     {
 | |
|         case IOT_MODBUS_TASK_MT_UART:
 | |
|         {
 | |
|             iot_mb_task_uart_msg_process(p_mb_msg);
 | |
|             break;
 | |
|         }
 | |
|         case IOT_MODBUS_TASK_MT_TIMER:
 | |
|         {
 | |
|             iot_mb_task_timer_msg_process(p_mb_msg);
 | |
|             break;
 | |
|         }
 | |
|         case IOT_MODBUS_TASK_MT_INTERNAL:
 | |
|         {
 | |
|             iot_mb_task_internal_msg_process(p_mb_msg);
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|         {
 | |
|             if (NULL != p_mb_msg->data) {
 | |
|                 iot_pkt_free(p_mb_msg->data);
 | |
|             }
 | |
|             IOT_ASSERT(0);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     iot_task_free_msg(task_h, p_msg);
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_msg_cancel_func() - pull back messages that sent to this
 | |
|  *   task.
 | |
|  * @param task_h: handle of task.
 | |
|  * @param p_msg: message that will be pull back.
 | |
|  */
 | |
| static void iot_mb_task_msg_cancel_func(iot_task_h task_h, iot_task_msg_t *p_msg)
 | |
| {
 | |
|     iot_mb_task_msg_t *p_mb_msg = (iot_mb_task_msg_t *)p_msg;
 | |
| 
 | |
|     switch(p_mb_msg->task_msg.type)
 | |
|     {
 | |
|         case IOT_MODBUS_TASK_MT_UART:
 | |
|         case IOT_MODBUS_TASK_MT_TIMER:
 | |
|         case IOT_MODBUS_TASK_MT_INTERNAL:
 | |
|         {
 | |
|             iot_pkt_free(p_mb_msg->data);
 | |
|         }
 | |
|         default:
 | |
|         {
 | |
|             IOT_ASSERT(0);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     iot_task_free_msg(task_h, p_msg);
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_uart_receive_func() - Uart driver callback function
 | |
|  *   when data received.
 | |
|  * @param buffer: pointer of data buffer.
 | |
|  * @param buffer_len: length of data received.
 | |
|  * @param is_full_frame: tell if this is a whole frame in this buffer.
 | |
|  * @param invalid_data_len: length of invalid data received. we ignore this.
 | |
|  */
 | |
| static void iot_mb_task_uart_receive_func(uint8_t* p_buffer, uint32_t buffer_len,
 | |
|     bool_t is_full_frame, uint32_t invalid_data_len)
 | |
| {
 | |
|     iot_pkt_t *p_pkt;
 | |
| 
 | |
|     iot_cus_printf("[mb_task] uart received, len:%d \n", buffer_len);
 | |
|     iot_mb_task_data_dump(p_buffer, buffer_len, __LINE__);
 | |
| 
 | |
|     /* timer to montor uart recv data timeout. */
 | |
|     if (0 == os_is_timer_active(mb_task.uart_timer)) {
 | |
|         iot_cus_printf("start timer\n");
 | |
|        os_start_timer(mb_task.uart_timer, IOT_MODBUS_TASK_UART_MB_TIMER_PERIOD);
 | |
|     } else {
 | |
|         iot_cus_printf("reset timer\n");
 | |
|         os_reset_timer(mb_task.uart_timer);
 | |
|     }
 | |
|     p_pkt = iot_pkt_alloc(buffer_len, IOT_MODBUS_TASK_ID);
 | |
|     if (p_pkt) {
 | |
|         /* copy data from buf to data packet */
 | |
|         os_mem_cpy(iot_pkt_put(p_pkt, buffer_len), p_buffer, buffer_len);
 | |
|         /* alloc message to insert proto task msg queue */
 | |
|         iot_mb_task_msg_post(IOT_MODBUS_TASK_MT_INTERNAL,
 | |
|               IOT_MODBUS_TASK_MSG_ID_CMD_HANDLE, p_pkt);
 | |
|     } else {
 | |
|         iot_cus_printf("[mb_task][err]no mem@line %d\n", __LINE__);
 | |
|         IOT_ASSERT(0);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| void iot_mb_task_msg_post(uint16_t msg_type, uint16_t msg_id, iot_pkt_t *data)
 | |
| {
 | |
|     iot_task_msg_t *msg;
 | |
|     iot_mb_task_msg_t *task_msg;
 | |
| 
 | |
|     msg = iot_task_alloc_msg_with_reserved(mb_task.task, 0);
 | |
|     if (NULL == msg) {
 | |
|         if (NULL != data) {
 | |
|             iot_pkt_free(data);
 | |
|         }
 | |
|         IOT_ASSERT(0);
 | |
|         return;
 | |
|     }
 | |
|     task_msg = (iot_mb_task_msg_t*)msg;
 | |
|     task_msg->task_msg.type = msg_type;
 | |
|     task_msg->task_msg.id = msg_id;
 | |
|     task_msg->data = data;
 | |
|     task_msg->data2 = 0;
 | |
|     iot_task_queue_msg(mb_task.task, &task_msg->task_msg, 0);
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_ge_start_timer_exe() - timer timeout callback function.
 | |
|  * @timer_id : timer id with that timer who causes this api-call.
 | |
|  * @arg : param past to this callback api.
 | |
|  */
 | |
| static void iot_mb_task_ge_start_timer_exe(timer_id_t timer_id, void * arg)
 | |
| {
 | |
|     (void)arg;
 | |
|     if (timer_id == mb_task.ge_start_timer) {
 | |
|         iot_mb_task_msg_post(IOT_MODBUS_TASK_MT_TIMER,
 | |
|             IOT_MODBUS_TASK_MSG_ID_TMR_GE_START_MONITOR, NULL);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_uart_mb_timer_exe() - timer timeout callback function.
 | |
|  * @timer_id : timer id with that timer who causes this api-call.
 | |
|  * @arg : param past to this callback api.
 | |
|  */
 | |
| static void iot_mb_task_uart_mb_timer_exe(timer_id_t timer_id, void * arg)
 | |
| {
 | |
|     (void)arg;
 | |
|     if (timer_id == mb_task.uart_timer) {
 | |
|         iot_mb_task_msg_post(IOT_MODBUS_TASK_MT_TIMER,
 | |
|             IOT_MODBUS_TASK_MSG_ID_TMR_UART_MB_TIMEOUT, NULL);
 | |
|         os_stop_timer(timer_id);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_ext_resp_timer_exe() - timer timeout callback function.
 | |
|  * @timer_id : timer id with that timer who causes this api-call.
 | |
|  * @arg : param past to this callback api.
 | |
|  */
 | |
| void iot_mb_ext_resp_timer_exe(timer_id_t timer_id, void * arg)
 | |
| {
 | |
|     (void)arg;
 | |
|     if (timer_id == mb_task.mb_ext_resp_timer) {
 | |
|         iot_mb_ext_resp_cmd_timeout_or_failed();
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_deinit() - Uninitialize modbus task.
 | |
|  */
 | |
| static void iot_mb_task_deinit(void)
 | |
| {
 | |
|     iot_cus_printf("[mb_task]mb_task deinit!\n");
 | |
|     if (NULL != mb_task.uart_h) {
 | |
|         iot_uart_close(mb_task.uart_h);
 | |
|     }
 | |
|     if (NULL != mb_task.task) {
 | |
|         iot_task_delete(mb_task.task);
 | |
|         mb_task.task = NULL;
 | |
|     }
 | |
|     if (0 != mb_task.ge_start_timer) {
 | |
|         os_delete_timer(mb_task.ge_start_timer);
 | |
|         mb_task.ge_start_timer = 0;
 | |
|     }
 | |
|     if (0 != mb_task.uart_timer) {
 | |
|         os_delete_timer(mb_task.uart_timer);
 | |
|         mb_task.uart_timer = 0;
 | |
|     }
 | |
| 
 | |
|     os_mem_set(&mb_task, 0x0, sizeof(iot_mb_task_t));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @brief iot_mb_task_init() - Initialize modbus task.
 | |
|  */
 | |
| static uint32_t iot_mb_task_init(void)
 | |
| {
 | |
|     uint32_t ret = ERR_OK;
 | |
|     iot_task_config_t task_cfg;
 | |
|     uint8_t uart_port;
 | |
| 
 | |
|     iot_cus_printf("[mb_task]mb_task init!\n");
 | |
| 
 | |
|     /* task configration. */
 | |
|     os_mem_set(&task_cfg, 0x0, sizeof(task_cfg));
 | |
|     task_cfg.stack_size = IOT_MODBUS_TASK_TASK_STACK_SIZE;
 | |
|     task_cfg.task_prio = IOT_MODBUS_TASK_PROTO_TASK_PRIO;
 | |
|     task_cfg.msg_size = sizeof(iot_mb_task_msg_t);
 | |
|     task_cfg.msg_cnt = IOT_MODBUS_TASK_TASK_POOL_SIZE;
 | |
|     task_cfg.queue_cnt = 1;
 | |
|     task_cfg.queue_cfg[0].quota = 0;
 | |
|     task_cfg.task_event_func = NULL;
 | |
|     task_cfg.msg_exe_func = iot_mb_task_msg_exe_func;
 | |
|     task_cfg.msg_cancel_func = iot_mb_task_msg_cancel_func;
 | |
| 
 | |
|     os_mem_set(&mb_task, 0, sizeof(iot_mb_task_t));
 | |
| 
 | |
|     /* default value of slave address is 0xff. */
 | |
|     mb_task.slave_addr = IOT_MODBUS_DEFAULT_SLAVER_ADDR;
 | |
| 
 | |
|     /* IIC:0x3D0A0108(61.10.1.8) */
 | |
|     iot_cus_printf("[mb_task]hardware ver:%08x\n", iot_board_hw_version_hex());
 | |
|     uart_port = iot_board_get_uart(UART_RS485_PORT);
 | |
|     if (uart_port >= iot_uart_get_max_port_num()) {
 | |
|         iot_cus_printf("[mb_task]open 485 port err, try to open meter port\n");
 | |
|         uart_port = iot_board_get_uart(UART_METER_PORT);
 | |
|         /* if need to set meter port as rs485,
 | |
|          * use function iot_uart_enable_rs485 after iot_uart_open success.
 | |
|          * iot_uart_enable_rs485(mb_task.uart_h,
 | |
|          *     iot_board_get_gpio(GPIO_RS485_TXE))
 | |
|          */
 | |
|     }
 | |
|     mb_task.uart_h = iot_uart_open(uart_port,
 | |
|         iot_mb_task_uart_receive_func, IOT_MODBUS_TASK_UART_BUF_SIZE, NULL);
 | |
|     if (NULL == mb_task.uart_h) {
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
| 
 | |
|     mb_task.task = iot_task_create(IOT_MODBUS_TASK_ID, &task_cfg);
 | |
|     if (NULL == mb_task.task) {
 | |
|         iot_cus_printf("[mb_task]create task failed.\n");
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
| 
 | |
|     /* ge start monitor timer. */
 | |
|     mb_task.ge_start_timer = os_create_timer(IOT_MODBUS_TASK_ID, true,
 | |
|         iot_mb_task_ge_start_timer_exe, NULL);
 | |
|     if (0 == mb_task.ge_start_timer) {
 | |
|         iot_cus_printf("[mb_task]create ge start timer failed.\n");
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
|     os_start_timer(mb_task.ge_start_timer, IOT_MODBUS_TASK_GE_START_TIMER_PERIOD);
 | |
| 
 | |
|     /* uart mmodbus recv monitor timer. */
 | |
|     mb_task.uart_timer = os_create_timer(IOT_MODBUS_TASK_ID, true,
 | |
|         iot_mb_task_uart_mb_timer_exe, NULL);
 | |
|     if (0 == mb_task.uart_timer) {
 | |
|         iot_cus_printf("[mb_task]create uart modbus timer failed.\n");
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
| 
 | |
|     /* modbus ext resp timer. */
 | |
|     mb_task.mb_ext_resp_timer = os_create_timer(IOT_MODBUS_TASK_ID, true,
 | |
|         iot_mb_ext_resp_timer_exe, NULL);
 | |
|     if (0 == mb_task.mb_ext_resp_timer) {
 | |
|         iot_cus_printf("[mb_task]create mb_ext resp timer failed.\n");
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
| 
 | |
| #if IOT_MODBUS_RT_TABLE_SUPPORT
 | |
| 
 | |
|     mb_task.rt_table = iot_modbus_addr_rout_table_create(IOT_MODBUS_TASK_ID,
 | |
|             IOT_MODBUS_MAC_RT_ENTRY_MAX, sizeof(iot_modbus_addr_rout_entry_t));
 | |
| 
 | |
|     /* rout table update timer. */
 | |
|     mb_task.rt_update_timer = os_create_timer(IOT_MODBUS_TASK_ID, true,
 | |
|         iot_mb_task_rt_update_timer_exe, mb_task.rt_table);
 | |
|     if (0 == mb_task.rt_update_timer) {
 | |
|         iot_cus_printf("[%s][err]create route talbe update timer failed.\n", __FUNCTION__);
 | |
|         ret = ERR_FAIL;
 | |
|         goto init_err_handle;
 | |
|     }
 | |
|     os_start_timer(mb_task.rt_update_timer, IOT_MODBUS_TASK_RT_TIMER_PERIOD);
 | |
| 
 | |
| #endif
 | |
| 
 | |
|     iot_cus_printf("[mb_task]task create successfully.\n");
 | |
| 
 | |
|     goto out;
 | |
| 
 | |
| init_err_handle:
 | |
|     iot_mb_task_deinit();
 | |
| 
 | |
| out:
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| uint32_t app_modbus_task_entry(void)
 | |
| {
 | |
|     uint32_t ret = ERR_PENDING;
 | |
| 
 | |
|     if (ERR_OK == iot_mb_task_init()) {
 | |
|         ret = ERR_OK;
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| #endif /* IOT_GE_EXT_TASK_ENABLE */
 |