Files
kunlun/app/iot_ge_modbus_app/iot_modbus_task.c
2024-09-28 14:24:04 +08:00

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