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 */
 |