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

1726 lines
52 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
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_timer_api.h"
#include "os_utils_api.h"
#include "iot_app_api.h"
#include "iot_io_api.h"
#include "iot_task_api.h"
#include "iot_proto_ge.h"
#include "iot_board_api.h"
#include "iot_proto_cctt.h"
#include "iot_plc_msg_cco_api.h"
#include "iot_gpio_api.h"
#if PLC_SUPPORT_CCO_ROLE
/* iot concentrator module, version 3.0 */
#ifndef HW_VERSION_IOT_CCTT_V3_0
#define HW_VERSION_IOT_CCTT_V3_0 0x720A0100 //114.10.01.00
#endif
/* iot concentrator module, version 3.5 */
#ifndef HW_VERSION_IOT_CCTT_V3_5
#define HW_VERSION_IOT_CCTT_V3_5 0x760A0100 //118.10.01.00
#endif
#define PLC_NW_OPEN (0xAA)
#define PLC_NW_CLOSE (0x55)
/* timeout period if rs485 device has no response */
#define RS485_DEV_RESP_TO_MS (2000)
/* timeout period to judge rs485 data receive done */
#define RS485_DEV_IDLE_TO_MS (20)
/* fn of reporting sta join/leave state */
#define RPT_STA_STATE_FN (0x07)
/* event to report sta joined */
#define EVENT_RPT_STA_JOINED (0x01)
/* for cco */
static cctt_context_t g_cctt_context = {0};
/* local rs485 manager object */
static cctt_local_rs485_t g_local_rs485 = {0};
/**
* @brief cctt_resp_cmd_ack() - dl645 query err、set cmd ack
* @param ctrl: read or write cmd
* @param err: error number,see DL645_ERR_XXX
* @return: 0 success, others false
*/
static uint8_t cctt_resp_cmd_ack(uint8_t ctrl, uint8_t err)
{
uint8_t *send_cmd;
uint8_t data_len = DL645_PARSE_FRM_MIN_LEN;
iot_pkt_t *pkt = NULL;
iot_cus_printf("cctt resp ack:%lu\n", err);
if (err > 0) {
data_len += 1;
}
pkt = iot_pkt_alloc(data_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
return 1;
}
send_cmd = iot_pkt_put(pkt, data_len);
iot_proto_645_build_resp_msg((proto_645_header_t *)send_cmd, NULL, 0,
err, ctrl);
iot_proto_send_to_mainboard(pkt);
return 0;
}
/* set whitelist */
uint8_t iot_cctt_set_whitelist(uint8_t *data, uint8_t len, uint8_t action)
{
uint8_t i;
int32_t mac_in_dev, mac_in_dev_tmp;
proto_dev_t wlist;
cctt_set_whitelist_t *cmd = (cctt_set_whitelist_t*)data;
uint8_t reason = DL645_ERR_OTHER_ERROR;
if (sizeof(cctt_set_whitelist_t) + cmd->cnt * IOT_MAC_ADDR_LEN != len ||
cmd->cnt == 0) {
/* length or count err */
reason = DL645_ERR_OTHER_ERROR;
} else if ((action == GE_PROTO_ACTION_ADD) ||
(action == GE_PROTO_ACTION_DEL)) {
iot_cus_printf("cctt_set_whitelist act:%d seq:%d cnt:%d\n", action,
cmd->seq, cmd->cnt);
for (i = 0; i < cmd->cnt; i++) {
iot_mac_addr_reverse(cmd->mac[i]);
mac_in_dev = iot_proto_check_mac_exists(cmd->mac[i],
prototask_contxt.dev_lst.dev,
prototask_contxt.dev_lst.valid_dev_cnt);
mac_in_dev_tmp = iot_proto_check_mac_exists(cmd->mac[i],
prototask_contxt.dev_lst.dev_tmp,
prototask_contxt.dev_lst.valid_dev_tmp_cnt);
if (((action == GE_PROTO_ACTION_ADD) && (mac_in_dev < 0) &&
(mac_in_dev_tmp < 0)) || ((action == GE_PROTO_ACTION_DEL) &&
(mac_in_dev>= 0) && (mac_in_dev_tmp < 0))) {
/* mac is not in dev_tmp and dev,which will be added if need,
or is in dev and not in dev_tmp, which will be deleted if need */
os_mem_set(&wlist, 0x00, sizeof(wlist));
iot_mac_addr_cpy(wlist.mac, cmd->mac[i]);
iot_proto_add_wl_to_tmp(&wlist);
}
}
if (cmd->seq == 0) {
if (action == GE_PROTO_ACTION_ADD) {
iot_proto_add_wl_tmp2formal();
} else {
iot_proto_del_wl_from_formal();
}
iot_proto_whitelist_add_remove(action, NULL, false);
iot_proto_wl_save2flash();
iot_proto_whitelist_state_init();
}
reason = DL645_ERR_OK;
}
iot_cus_printf("cctt_set_whitelist end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
/* reboot cco */
uint8_t iot_cctt_reboot_cco(uint8_t *data, uint8_t len)
{
(void)data;
uint8_t reason = DL645_ERR_OTHER_ERROR;
if (len != sizeof(cctt_reboot_cco_t)) {
reason = DL645_ERR_PARAMETER_ERROR;
} else {
os_start_timer(prototask_contxt.reboot_tmr,
PROTO_TIMER_REBOOT_DELAY_INTVL);
reason = DL645_ERR_OK;
}
iot_cus_printf("cctt reboot cco end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
static void iot_cctt_build_reboot_sta_frame(uint8_t *ge_data, uint8_t *dst_mac)
{
ge_frame_reboot_sta_set_subfn18_t *data_frm;
data_frm = (ge_frame_reboot_sta_set_subfn18_t *)ge_data;
data_frm->hdr.hdr.preamble = GE_FRM_PREAMBLE_CODE;
data_frm->hdr.hdr.data_len = sizeof(ge_frame_reboot_sta_set_subfn18_t) -
GE_FRM_MIN_LEN;
data_frm->hdr.hdr.fn = PROTO_GE_PLC_SET_CMD;
data_frm->hdr.subfn = PROTO_REBOOT_STA_CMD;
data_frm->nid = prototask_contxt.local_dev.nid;
data_frm->reboot_type = REBOOT_NORMAL;
data_frm->seq = 0;
iot_mac_addr_cpy(data_frm->src_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_cpy(data_frm->dst_mac, dst_mac);
data_frm->tail.check_sum =
ge_frm_checksum_calc(ge_data, data_frm->hdr.hdr.data_len +
GE_FRM_CHECK_SUM_FIELD_POS);;
data_frm->tail.tail = GE_FRM_TAIL_CODE;
}
static void iot_reboot_sta(uint8_t *dst_mac)
{
iot_pkt_t *pkt;
uint8_t *cmd_data;
protpkt_tx_info_t txinfo = { 0 };
iot_cus_printf("reboot sta:%02X%02X%02X%02X%02X%02X\n",
dst_mac[0], dst_mac[1], dst_mac[2],
dst_mac[3], dst_mac[4], dst_mac[5]);
pkt = iot_pkt_alloc(sizeof(ge_frame_reboot_sta_set_subfn18_t),
IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
return;
}
cmd_data = iot_pkt_put(pkt, sizeof(ge_frame_reboot_sta_set_subfn18_t));
iot_cctt_build_reboot_sta_frame(cmd_data, dst_mac);
iot_proto_fill_txinfo(&txinfo, false, PLCTXRX_UNICAST,
PROTO_UNICAST_RETRY_DEFAULT_CNT, PROTO_UNICAST_RETRY_DEFAULT_INTVL, 1,
prototask_contxt.local_dev.mac, dst_mac);
iot_proto_remote_cmd_send_to_plctxrx(cmd_data,
sizeof(ge_frame_reboot_sta_set_subfn18_t), &txinfo);
}
/* reboot sta */
uint8_t iot_cctt_reboot_sta(uint8_t *cmd, uint8_t len)
{
uint8_t reason = DL645_ERR_OTHER_ERROR;
cctt_reboot_sta_t *reboot_cmd;
if (len != sizeof(cctt_reboot_sta_t)) {
goto out;
}
// TODO: check dst mac is in whitelist
reboot_cmd = (cctt_reboot_sta_t*)cmd;
iot_mac_addr_reverse(reboot_cmd->mac);
iot_reboot_sta(reboot_cmd->mac);
reason = DL645_ERR_OK;
out:
iot_cus_printf("cctt reboot sta end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
/* set whitelist state */
uint8_t iot_cctt_set_wl_state(uint8_t *data, uint8_t len)
{
uint8_t reason = DL645_ERR_PARAMETER_ERROR;
cctt_set_wl_state_t *set_cmd;
if (len != sizeof(cctt_set_wl_state_t)) {
goto out;
}
set_cmd = (cctt_set_wl_state_t*)data;
if (set_cmd->state == 0) {
iot_proto_whitelist_en_disable(GE_PROTO_WL_DISABLE, false);
} else if (set_cmd->state == 1) {
iot_proto_whitelist_en_disable(GE_PROTO_WL_ENABLE, false);
} else {
/* error state */
goto out;
}
reason = DL645_ERR_OK;
out:
iot_cus_printf("cctt set wl state end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
/* clear whitelist */
uint8_t iot_cctt_clear_whitelist(uint8_t *data, uint8_t len)
{
(void)data;
uint8_t reason;
if (sizeof(cctt_clear_whitelist_t) != len) {
/* cmd length error */
reason = DL645_ERR_PARAMETER_ERROR;
} else {
if (prototask_contxt.dev_lst.valid_dev_cnt > 0) {
prototask_contxt.dev_lst.valid_dev_cnt = 0;
os_mem_set(prototask_contxt.dev_lst.dev, 0,
sizeof(proto_dev_t) * STA_DEV_MAX);
iot_proto_wl_save2flash();
iot_proto_whitelist_remove_all(false);
}
reason = DL645_ERR_OK;
}
iot_cus_printf("cctt clear whitelist end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
/* check address in whitelist */
uint8_t iot_cctt_check_whitelist_mac(uint8_t *data, uint8_t len)
{
uint16_t i;
uint8_t reason = DL645_ERR_NO_REQ_DATA;
cctt_check_whitelist_mac_t *cmd;
if (sizeof(cctt_check_whitelist_mac_t) != len) {
/* cmd length error */
reason = DL645_ERR_PARAMETER_ERROR;
} else {
cmd = (cctt_check_whitelist_mac_t*)data;
iot_mac_addr_reverse(cmd->mac);
if (prototask_contxt.dev_lst.valid_dev_cnt > 0) {
for (i = 0; i < STA_DEV_MAX; i++) {
if (iot_mac_addr_cmp(cmd->mac,
prototask_contxt.dev_lst.dev[i].mac)) {
reason = DL645_ERR_OK;
break;
}
}
}
}
iot_cus_printf("cctt check whitelist mac cco end\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return (reason != DL645_ERR_OK);
}
/* resp whitelist */
static void cco_resp_whitelist_to_cctt(uint16_t start, uint8_t resp_cnt)
{
uint8_t flow = 0;
uint8_t *send_cmd;
uint16_t out_len;
uint8_t ctrl, i;
uint8_t *tmp_mac;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
proto_645_header_t *hdr;
iot_pkt_t *pkt;
out_len = DL645_PARSE_FRM_MIN_LEN + IOT_MAC_ADDR_LEN * resp_cnt;
if (g_cctt_context.q_wl_seq) {
ctrl = PROTO_645_2007_FN_READ_DATA_C;
out_len += sizeof(cctt_resp_whitelist_withseq_t) + sizeof(uint8_t);
} else {
ctrl = PROTO_645_2007_FN_READ_DATA;
out_len += sizeof(cctt_resp_whitelist_t);
}
if ((g_cctt_context.q_wl_cnt == 0xFFFF &&
(start + resp_cnt < prototask_contxt.dev_lst.valid_dev_cnt)) ||
(g_cctt_context.q_wl_cnt != 0xFFFF &&
(start + resp_cnt < g_cctt_context.q_wl_cnt))) {
g_cctt_context.q_wl_pos += resp_cnt;
flow = 1;
}
iot_cus_printf("cco_resp_whitelist_to_cctt start:%d cnt:%d "
"ctrl:0x%02X seq:%d flow:%d out_len:%d\n", start, resp_cnt, ctrl,
g_cctt_context.q_wl_seq, flow, out_len);
pkt = iot_pkt_alloc(out_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
return ;
}
send_cmd = iot_pkt_put(pkt, out_len);
hdr = (proto_645_header_t*)send_cmd;
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
iot_proto_645_header_init(hdr, dst_mac, ctrl, PROTO_645_DIR_SLAVE,
PROTO_645_2007_ERR_OK, flow);
if (g_cctt_context.q_wl_seq == 0) {
hdr->len = sizeof(cctt_resp_whitelist_t);
((cctt_resp_whitelist_t*)(hdr->data))->total_cnt =
prototask_contxt.dev_lst.valid_dev_cnt;
tmp_mac = hdr->data + sizeof(cctt_resp_whitelist_t);
} else {
hdr->len = sizeof(cctt_resp_whitelist_withseq_t);
tmp_mac = hdr->data + sizeof(cctt_resp_whitelist_withseq_t);
}
proto_645_2007_di_to_byte(DL645_07_DI_QUERY_WHITELIST, hdr->data);
hdr->len += IOT_MAC_ADDR_LEN * resp_cnt;
for (i = 0; i < resp_cnt; i++) {
iot_mac_addr_cpy(tmp_mac + i * IOT_MAC_ADDR_LEN,
prototask_contxt.dev_lst.dev[start + i - 1].mac);
iot_mac_addr_reverse(tmp_mac + i * IOT_MAC_ADDR_LEN);
}
if (g_cctt_context.q_wl_seq) {
*(hdr->data + hdr->len) = g_cctt_context.q_wl_seq;
hdr->len += 1;
}
if (flow == 0) {
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
}
iot_proto_645_ext_add33_handle(hdr->data, hdr->len);
iot_proto_645_tail_init(hdr);
iot_proto_send_to_mainboard(pkt);
}
/* read whitelist */
uint8_t iot_cctt_read_whitelist(uint8_t *data, uint8_t len)
{
uint8_t ctrl;
uint8_t read_cnt;
cctt_query_whitelist_t *read_cmd;
read_cnt = (DL645_FRM_DATA_MAX_LEN - DL645_PARSE_FRM_MIN_LEN -
sizeof(cctt_resp_whitelist_t)) / IOT_MAC_ADDR_LEN;
if (len == sizeof(cctt_query_whitelist_t)) {
ctrl = PROTO_645_2007_FN_READ_DATA;
read_cmd = (cctt_query_whitelist_t*)data;
iot_cus_printf("cctt_read_whitelist start:%d cnt:%d q_cnt:%d total:%d\n",
read_cmd->start, read_cnt, read_cmd->cnt,
prototask_contxt.dev_lst.valid_dev_cnt);
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
g_cctt_context.q_wl_cnt = read_cmd->cnt;
if (read_cmd->start > 0) {
g_cctt_context.q_wl_pos = read_cmd->start;
if (g_cctt_context.q_wl_pos + read_cnt - 1 >
prototask_contxt.dev_lst.valid_dev_cnt) {
read_cnt = prototask_contxt.dev_lst.valid_dev_cnt -
g_cctt_context.q_wl_pos + 1;
}
} else {
goto err;
}
} else {
ctrl = PROTO_645_2007_FN_READ_DATA_C;
/* check query topo for next frame */
if (g_cctt_context.q_wl_seq + 1 == data[DL645_DI_LEN] &&
g_cctt_context.q_wl_pos > 0) {
g_cctt_context.q_wl_seq = data[DL645_DI_LEN];
/* q_topo_cnt will be change after topo resp */
} else {
goto err;
}
iot_cus_printf("cctt_read_whitelist start:%d seq:%d cnt:%d total:%d\n",
g_cctt_context.q_wl_pos, g_cctt_context.q_wl_seq,
g_cctt_context.q_wl_cnt, prototask_contxt.dev_lst.valid_dev_cnt);
if (g_cctt_context.q_wl_pos > prototask_contxt.dev_lst.valid_dev_cnt) {
read_cnt = 0;
} else if (g_cctt_context.q_wl_pos + read_cnt - 1 >
prototask_contxt.dev_lst.valid_dev_cnt) {
read_cnt = prototask_contxt.dev_lst.valid_dev_cnt -
g_cctt_context.q_wl_pos + 1;
}
}
if (read_cnt > g_cctt_context.q_wl_cnt) {
read_cnt = g_cctt_context.q_wl_cnt;
}
cco_resp_whitelist_to_cctt(g_cctt_context.q_wl_pos, read_cnt);
return 0;
err:
/* read cmd error */
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
iot_cus_printf("cctt read whitelist err\n");
cctt_resp_cmd_ack(ctrl, DL645_ERR_PARAMETER_ERROR);
return 1;
}
/**
* @brief: report sta join or leave event
*
* @param p_mac: mac address of sta device
* @param evt : event of sta device, 1=join, 2=leave
* @return : 0 if success, 1 when failed
*/
uint8_t iot_cctt_report_sta_event(uint8_t *p_mac, uint8_t evt)
{
uint8_t *send_cmd;
uint16_t out_len;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
iot_pkt_t *pkt;
proto_645_header_t *hdr;
cctt_rpt_sta_evt_t *rpt;
out_len = DL645_PARSE_FRM_MIN_LEN + sizeof(cctt_rpt_sta_evt_t);
pkt = iot_pkt_alloc(out_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
return 1;
}
send_cmd = iot_pkt_put(pkt, out_len);
hdr = (proto_645_header_t*)send_cmd;
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
iot_proto_645_header_init(hdr, dst_mac, RPT_STA_STATE_FN, 0,
PROTO_645_2007_ERR_OK, 0);
hdr->len = sizeof(cctt_rpt_sta_evt_t);
rpt = (cctt_rpt_sta_evt_t *)hdr->data;
rpt->event = evt;
iot_mac_addr_cpy(rpt->mac, p_mac);
iot_mac_addr_reverse(rpt->mac);
iot_proto_645_tail_init(hdr);
iot_proto_send_to_mainboard(pkt);
return 0;
}
uint8_t iot_cctt_report_sta_online(plctxrx_cmd_topov2_t *resp_node,
uint16_t total_cnt, uint16_t cur_cnt)
{
uint8_t i = 0;
if (iot_mac_addr_cmp(resp_node[0].mac, prototask_contxt.local_dev.mac)){
/* skip cco device report */
i++;
}
for (; i < cur_cnt; i++) {
iot_cus_printf("sta %02X:%02X:%02X:%02X:%02X:%02X report online\n",
resp_node[i].mac[0], resp_node[i].mac[1], resp_node[i].mac[2],
resp_node[i].mac[3], resp_node[i].mac[4], resp_node[i].mac[5]);
iot_cctt_report_sta_event(resp_node[i].mac, EVENT_RPT_STA_JOINED);
}
if (total_cnt == cur_cnt) {
iot_cus_printf("topo report online done, total = %u\n", total_cnt);
g_cctt_context.q_topo_rpt_online = 0;
}
return 0;
}
/* report topo info as DL645 frame */
uint8_t iot_cctt_report_topo(plctxrx_cmd_topov2_t *resp_node,
uint16_t total_cnt, uint16_t cur_cnt, uint8_t flow)
{
uint8_t ctrl, i;
uint8_t resp_cnt;
uint8_t *send_cmd;
uint16_t out_len;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
iot_pkt_t *pkt;
node_t *node;
proto_645_header_t *hdr;
resp_cnt = cur_cnt;
out_len = DL645_PARSE_FRM_MIN_LEN + sizeof(node_t) * resp_cnt;
if (g_cctt_context.q_topo_seq) {
ctrl = PROTO_645_2007_FN_READ_DATA_C;
out_len += DL645_DI_LEN + 1;
} else {
ctrl = PROTO_645_2007_FN_READ_DATA;
out_len += sizeof(cctt_resp_topo_t) ;
}
iot_cus_printf("topo_resp cnt:%d ctrl:0x%02X seq:%d flow:%d out_len:%d\n",
resp_cnt, ctrl, g_cctt_context.q_topo_seq, flow, out_len);
pkt = iot_pkt_alloc(out_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
cctt_resp_cmd_ack(ctrl, DL645_ERR_OTHER_ERROR);
return 1;
}
send_cmd = iot_pkt_put(pkt, out_len);
hdr = (proto_645_header_t*)send_cmd;
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
iot_proto_645_header_init(hdr, dst_mac, ctrl, PROTO_645_DIR_SLAVE,
PROTO_645_2007_ERR_OK, flow);
proto_645_2007_di_to_byte(DL645_07_DI_QUERY_TOPO, hdr->data);
if (g_cctt_context.q_topo_seq) {
hdr->len = DL645_DI_LEN;
node = (node_t*)(hdr->data + DL645_DI_LEN);
} else {
hdr->len = sizeof(cctt_resp_topo_t);
((cctt_resp_topo_t*)(hdr->data))->total_cnt = total_cnt;
((cctt_resp_topo_t*)(hdr->data))->q_ver = 0;
node = ((cctt_resp_topo_t*)(hdr->data))->node;
}
hdr->len += sizeof(node_t) * resp_cnt;
for (i = 0; i < resp_cnt; i++) {
node->level = resp_node[i].level;
iot_mac_addr_cpy(node->mac, resp_node[i].mac);
iot_mac_addr_reverse(node->mac);
node++;
}
if (g_cctt_context.q_topo_seq) {
*(hdr->data + hdr->len) = g_cctt_context.q_topo_seq;
hdr->len += 1;
}
/* check end */
if (flow == 0) {
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
}
iot_proto_645_ext_add33_handle(hdr->data, hdr->len);
iot_proto_645_tail_init(hdr);
iot_proto_send_to_mainboard(pkt);
return 0;
}
/* response topo info */
uint8_t iot_cco_resp_topo_to_cctt(plctxrx_cmd_topov2_t *resp_node,
uint16_t total_cnt, uint16_t cur_cnt, uint8_t flow)
{
if (g_cctt_context.q_topo_rpt_online) {
/* request to report sta online by iot_cctt_req_online_sta_report */
return iot_cctt_report_sta_online(resp_node, total_cnt, cur_cnt);
} else {
return iot_cctt_report_topo(resp_node, total_cnt, cur_cnt, flow);
}
}
/**
* @brief: send cmd to txrx to request topo info
*
* @param start: start of topo to request
* @param count: number of topo to request
* @param seq : frame sequence
* @return 0 if success, 1 when failed
*/
uint8_t iot_cctt_req_txrx_topo(uint16_t start, uint16_t count, uint8_t seq)
{
uint8_t txrx_cmd_len;
iot_pkt_t *pkt;
plctxrx_cmd_arg_t *cmd;
plctxrx_cmd_query_topo_t *topo_cmd;
proto_cmd_hdl_state_t *sm = iot_proto_cmd_handle_state_get();
iot_cus_printf("cctt_query_topo seq=%d pos:%d cnt:%d\n",
g_cctt_context.q_topo_seq, g_cctt_context.q_topo_pos, count);
txrx_cmd_len = sizeof(plctxrx_cmd_arg_t) + sizeof(plctxrx_cmd_query_topo_t);
/* send txrx cmd */
pkt = iot_pkt_alloc(txrx_cmd_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]cctt pkt alloc fail\n");
goto err;
}
cmd = (plctxrx_cmd_arg_t*)iot_pkt_put(pkt, txrx_cmd_len);
cmd->cid.cid = PLCTXRX_CID_TOPO;
cmd->cid.opcode = PLCTXRX_OP_QUERY;
cmd->need_ack = true;
cmd->prio = 0;
cmd->dlen = sizeof(plctxrx_cmd_query_topo_t);
topo_cmd = (plctxrx_cmd_query_topo_t*)cmd->arg;
topo_cmd->ver = IOT_PLC_CCO_TOPO_REQ_DATA_VER_V2;
topo_cmd->start = start;
topo_cmd->cnt = count;
sm->state = PROTO_CMD_DL645_WAIT_TOPO_INFO_RESP;
sm->dir = CMD_LOCAL_UP_LINK;
sm->seq = seq;
iot_proto_cmd_send_to_plctxrx(pkt);
return 0;
err:
return 1;
}
/**
* @brief: request online sta device report online to server
*
* @param none
* @return 0 if success, 1 when failed
*/
uint8_t iot_cctt_req_online_sta_report(void)
{
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
g_cctt_context.q_topo_type = 0;
g_cctt_context.q_topo_pos = 1;
g_cctt_context.q_topo_cnt = 0xFFFF;
g_cctt_context.q_topo_rpt_online = 1;
return iot_cctt_req_txrx_topo(1, 0xFFFF, 0);
}
/* query topo, only send cmd to query topo */
uint8_t iot_cctt_query_topo(uint8_t *data, uint8_t len)
{
uint8_t ctrl;
uint8_t err_num;
uint8_t query_cnt;
cctt_query_topo_t *query_cmd;
query_cnt = (DL645_FRM_DATA_MAX_LEN - DL645_PARSE_FRM_MIN_LEN -
sizeof(cctt_resp_topo_t)) / sizeof(node_t);
if (len == sizeof(cctt_query_topo_t) ) {
ctrl = PROTO_645_2007_FN_READ_DATA;
query_cmd = (cctt_query_topo_t*)data;
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
if (query_cmd->start > 0) {
g_cctt_context.q_topo_type = query_cmd->q_ver;
g_cctt_context.q_topo_pos = query_cmd->start;
g_cctt_context.q_topo_cnt = query_cmd->cnt;
} else {
err_num = DL645_ERR_PARAMETER_ERROR;
goto err;
}
} else {
ctrl = PROTO_645_2007_FN_READ_DATA_C;
/* check query topo for next frame */
if (g_cctt_context.q_topo_seq + 1 == data[DL645_DI_LEN] &&
g_cctt_context.q_topo_pos > 0) {
g_cctt_context.q_topo_seq = data[DL645_DI_LEN];
/* q_topo_cnt will be change after topo resp */
} else {
err_num = DL645_ERR_PARAMETER_ERROR;
goto err;
}
}
if (query_cnt > g_cctt_context.q_topo_cnt) {
query_cnt = g_cctt_context.q_topo_cnt;
}
if (g_cctt_context.q_topo_rpt_online) {
iot_cus_printf("cctt query topo, and reporting online, wait...\n");
err_num = DL645_ERR_OTHER_ERROR;
goto err;
}
if (0 != iot_cctt_req_txrx_topo(g_cctt_context.q_topo_pos,
query_cnt, g_cctt_context.q_topo_seq)) {
err_num = DL645_ERR_OTHER_ERROR;
goto err;
}
return 0;
err:
iot_cus_printf("cctt query topo end\n");
cctt_resp_cmd_ack(ctrl, err_num);
return 1;
}
void iot_cctt_set_plc_nw(uint8_t *data, uint8_t len)
{
uint8_t reason = DL645_ERR_OK;
cctt_set_plc_net_t *nw_handle = (cctt_set_plc_net_t *)data;
if (nw_handle->action == 0) {
iot_plc_stop_nw_fmt(greeapp->app_handle);
g_cctt_context.plc_nw_state = PLC_NW_CLOSE;
} else {
iot_plc_start_nw_fmt(greeapp->app_handle, 1);
g_cctt_context.plc_nw_state = PLC_NW_OPEN;
}
iot_cus_printf("ccct set nw :%d\n", nw_handle->action);
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
}
void iot_cctt_get_plc_nw(void)
{
uint8_t *send_cmd;
uint8_t datalen = DL645_DI_LEN + sizeof(uint8_t);
uint8_t out_len = DL645_PARSE_FRM_MIN_LEN + datalen;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
iot_pkt_t *pkt;
proto_645_header_t *hdr;
pkt = iot_pkt_alloc(out_len, IOT_GREE_APP_MID);
if (pkt == NULL) {
iot_cus_printf("[err]read plc nw fail\n");
return ;
}
send_cmd = iot_pkt_put(pkt, out_len);
hdr = (proto_645_header_t*)send_cmd;
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
hdr->len = datalen;
iot_proto_645_header_init(hdr, dst_mac, PROTO_645_2007_FN_READ_DATA,
PROTO_645_DIR_SLAVE, PROTO_645_2007_ERR_OK, 0);
proto_645_2007_di_to_byte(DL645_07_DI_HANDLE_PLC_NW, hdr->data);
hdr->data[DL645_DI_LEN] = g_cctt_context.plc_nw_state;
iot_cus_printf("ccct read nw :0x%x\n", g_cctt_context.plc_nw_state);
iot_proto_645_ext_add33_handle(hdr->data, datalen);
iot_proto_645_tail_init(hdr);
iot_proto_send_to_mainboard(pkt);
}
static void iot_cctt_add_pco(uint8_t *mac)
{
uint8_t i;
iot_cus_printf("add pco mac:%02X%02X%02X%02X%02X%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
if (iot_mac_addr_cmp(mac, prototask_contxt.local_dev.mac)) {
/* pco is cco, not add */
return;
}
for (i = 0; i < IOT_CCTT_CACHE_PCO_CNT; i++) {
if (!iot_mac_addr_valid(g_cctt_context.pco_list[i])) {
/* store pco in blank */
iot_mac_addr_cpy(g_cctt_context.pco_list[i], mac);
g_cctt_context.pco_cnt++;
break;
}
if (iot_mac_addr_cmp(mac, g_cctt_context.pco_list[i])) {
/* check pco have stored */
break;
}
}
return;
}
void iot_cctt_reboot_mac_list_pco(uint8_t *data, uint8_t len)
{
uint8_t i;
uint16_t j;
uint8_t reason = DL645_ERR_OK;
cctt_reboot_mac_list_pco_t *cmd = (cctt_reboot_mac_list_pco_t *)data;
if (sizeof(cctt_reboot_mac_list_pco_t) + cmd->cnt * IOT_MAC_ADDR_LEN != len
|| cmd->cnt == 0) {
reason = DL645_ERR_PARAMETER_ERROR;
goto out;
}
/* find pco */
for (i = 0; i < cmd->cnt; i++) {
if (!iot_mac_addr_valid(cmd->mac[i])) {
continue;
}
iot_mac_addr_reverse(cmd->mac[i]);
for (j = 0; j < STA_DEV_MAX; j++) {
if (!iot_mac_addr_valid(prototask_contxt.dev_lst.dev[j].mac)) {
continue;
}
if (iot_mac_addr_cmp(cmd->mac[i],
prototask_contxt.dev_lst.dev[j].mac)) {
iot_cus_printf("find mac:%02x%02x%02x%02x%02x%02x role=%d\n",
cmd->mac[i][0], cmd->mac[i][1], cmd->mac[i][2],
cmd->mac[i][3], cmd->mac[i][4], cmd->mac[i][5],
prototask_contxt.dev_lst.dev[j].dev_role);
if (prototask_contxt.dev_lst.dev[j].dev_role ==
IOT_PLC_DEV_ROLE_STA) {
/* only add sta's pco, not add pco's pco */
iot_cctt_add_pco(prototask_contxt.dev_lst.dev_pco[j]);
}
break;
}
}
}
iot_cus_printf("[cctt]find pco cnt=%d\n", g_cctt_context.pco_cnt);
/* reboot pco */
if (cmd->seq == 0 && g_cctt_context.pco_cnt > 0) {
for (i = 0; i < g_cctt_context.pco_cnt; i++) {
iot_reboot_sta(g_cctt_context.pco_list[i]);
os_delay(50);
}
/* reset param */
g_cctt_context.pco_cnt = 0;
os_mem_set(g_cctt_context.pco_list, 0,
IOT_CCTT_CACHE_PCO_CNT * IOT_MAC_ADDR_LEN);
}
out:
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
return;
}
#if IOT_APP_SELECTION == IOT_APP_DEF_22_GE_MICRO_CCTT
void iot_cctt_init_rs485_led_pin(void)
{
switch (iot_board_hw_version_hex()) {
case HW_VERSION_IOT_CCTT_V3_0: /* micro cctt 3.0 hardware */
g_local_rs485.rs485_led_pin = 0xFF;
break;
case HW_VERSION_IOT_CCTT_V3_5: /* micro cctt 3.5 hardware */
default:
g_local_rs485.rs485_led_pin = 54;
break;
}
if (g_local_rs485.rs485_led_pin != 0xFF) {
iot_gpio_open_as_output(g_local_rs485.rs485_led_pin);
iot_gpio_value_set(g_local_rs485.rs485_led_pin, 1);
}
iot_cus_printf("g_local_rs485.rs485_led_pin=%u\n",
g_local_rs485.rs485_led_pin);
}
#else
void iot_cctt_init_rs485_led_pin(void)
{
g_local_rs485.rs485_led_pin = 0xFF;
}
#endif
void iot_cctt_rs485_led_blink(void)
{
if (g_local_rs485.rs485_led_pin != 0xFF) {
iot_gpio_value_set(g_local_rs485.rs485_led_pin, 0);
os_delay(1);
iot_gpio_value_set(g_local_rs485.rs485_led_pin, 1);
}
}
void iot_cctt_delaytime(uint8_t *data, uint8_t len)
{
uint8_t err_num = DL645_ERR_OK;
uint16_t pkt_len;
iot_pkt_t *data_pkt;
proto_645_header_t *header = (proto_645_header_t *)data;
cctt_delaytime_t *data_info = (cctt_delaytime_t *)header->data;
ge_frame_delay_time_subfn166_t *ge_frame = NULL;
uint16_t rsv_data_len = data_info->time_info.datalen;
pkt_len = sizeof(ge_frame_delay_time_subfn166_t) +
data_info->time_info.datalen + sizeof(ge_frm_tail_t);
if (pkt_len > DL645_FRM_DATA_MAX_LEN) {
err_num = DL645_ERR_PARAMETER_ERROR;
goto err;
}
data_pkt = iot_pkt_alloc(pkt_len, IOT_GREE_APP_MID);
if (data_pkt == NULL) {
iot_cus_printf("%s alloc pkt err\n", __FUNCTION__);
err_num = DL645_ERR_OTHER_ERROR;
goto err;
}
/* pack a ge delaytime frame */
ge_frame = (ge_frame_delay_time_subfn166_t *)iot_pkt_put(data_pkt, pkt_len);
ge_frm_tail_t *tail_data = (ge_frm_tail_t *)(iot_pkt_data(data_pkt) +
sizeof(ge_frame_delay_time_subfn166_t) + rsv_data_len);
os_mem_set((uint8_t *)ge_frame, 0, pkt_len);
g_cctt_context.q_delaytime_seq++;
ge_frame->seq = g_cctt_context.q_delaytime_seq;
ge_frame->resv = DL645_07_RESV0_RESV;
iot_mac_addr_cpy(ge_frame->dest_mac, header->addr);
iot_mac_addr_reverse(ge_frame->dest_mac);
data_info->time_info.level = iot_plctxrx_get_node_level(ge_frame->dest_mac);
if (data_info->time_info.level == -1) {
iot_cus_printf("%s query level failed\n", __FUNCTION__);
}
os_mem_cpy((uint8_t *)&ge_frame->tm_test,(uint8_t *)&data_info->time_info,
sizeof(ge_delay_tm_test_t));
iot_delay_timer_get(&ge_frame->tm_test.mcu_tx_time, CCO_TX_TIME, 0);
EXT_FN_TWO_PART_FRM_PREPARE(ge_frame, tail_data, rsv_data_len,
PROTO_GE_PLC_SET_CMD, PROTO_GE_DELAY_TM_CMD);
tail_data->check_sum = ge_frm_checksum_calc((uint8_t *)ge_frame,
pkt_len - sizeof(ge_frm_tail_t));
iot_proto_delay_time_send(data_pkt, prototask_contxt.local_dev.mac,
ge_frame->dest_mac);
return;
err:
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, err_num);
return;
}
/**
* @brief: set parameter of rs485 interface
*
* @param baudrate: baudrate of rs485
* @param parity : parity of rs485
* @param databits: data bit number of rs485
* @param stopbits: stopbits of rs485
* @return ERR_OK if success, ERR_FAIL otherwise
*/
uint8_t iot_cctt_set_rs485_config_impl(uint32_t baudrate, uint8_t parity,
uint8_t databits, uint8_t stopbits)
{
ge_app_pib_info_t *p_flash = &prototask_contxt.flashinfo;
uint32_t baud_val[] = PROTO_GE_UART_BAUD_VALUE;
if (NULL == g_local_rs485.handler) {
return ERR_FAIL;
}
if (!iot_proto_uart_param_check(baudrate, parity, databits, stopbits)) {
iot_cus_printf("%s: invalid rs485 param:%u,%u,%u,%u\n",
__FUNCTION__, baudrate, parity, databits, stopbits);
return ERR_FAIL;
}
if ((baud_val[p_flash->public.pub.baudidx] != baudrate) ||
(p_flash->public.pub.parity != parity) ||
(p_flash->public.pub.data != databits) ||
(p_flash->public.pub.stop != stopbits)) {
iot_cus_printf("%s: rs485 param:%u,%u,%u,%u changed, save it\n",
__FUNCTION__, baudrate, parity, databits, stopbits);
p_flash->public.pub.baudidx = uart_baud_find_index(baudrate);
p_flash->public.pub.parity = parity;
p_flash->public.pub.data = databits;
p_flash->public.pub.stop = stopbits;
iot_proto_flashsave(p_flash);
}
iot_uart_set_config(g_local_rs485.handler,
baudrate, parity, databits, stopbits);
iot_cus_printf("%s: success to set rs485 param: %u,%u,%u,%u\n",
__FUNCTION__, baudrate, parity, databits, stopbits);
return ERR_OK;
}
/**
* @brief: callback function to receive rs485 data
*
* @param buffer : pointer buffer of storing rs485 data
* @param len : received data length
* @param is_full_frame: unused
* @param invalid_data_len: unused
* @return none
*/
static void iot_cctt_rs485_recv_callback(uint8_t *buffer, uint32_t len,
bool_t is_full_frame, uint32_t invalid_data_len)
{
uint8_t *p_dst = g_local_rs485.cache;
uint32_t total_len;
os_acquire_mutex(g_local_rs485.cache_mutex);
total_len = g_local_rs485.cache_len + len;
if (total_len <= IOT_CCTT_RS485_CACHE_SIZE) {
p_dst += g_local_rs485.cache_len;
os_mem_cpy(p_dst, buffer, len);
g_local_rs485.cache_len += len;
g_local_rs485.recv_ts = os_boot_time64();
} else {
iot_cus_printf("%s: rs485 cache overflow\n", __FUNCTION__);
}
os_release_mutex(g_local_rs485.cache_mutex);
}
/**
* @brief: init rs485 interface
*
* @param none
* @return ERR_OK if success, ERR_FAIL otherwise
*/
uint8_t iot_cctt_init_rs485_intf(void)
{
uint8_t uart_port = iot_board_get_uart(UART_RS485_PORT);
int32_t rs485_txe = iot_board_get_gpio(GPIO_RS485_TXE);
ge_app_pib_info_t *p_flash = &prototask_contxt.flashinfo;
uint32_t baud_val[] = PROTO_GE_UART_BAUD_VALUE;
uint8_t ret = ERR_OK;
if (true == g_local_rs485.ready) {
goto out;
}
iot_cctt_init_rs485_led_pin();
/* open rs485 uart interface */
g_local_rs485.handler = iot_uart_open(uart_port,
iot_cctt_rs485_recv_callback, 256, NULL);
if (NULL == g_local_rs485.handler) {
iot_cus_printf("%s: open rs485 uart failed!\n", __FUNCTION__);
ret = ERR_FAIL;
goto out;
}
/* set rs485 mode and rs485 txe pin */
iot_cus_printf("rs485_txe pin = %u\n", rs485_txe);
iot_uart_enable_rs485(g_local_rs485.handler, rs485_txe);
/* create mutex to protect rs485 receive cache */
g_local_rs485.cache_mutex = os_create_mutex(IOT_GREE_APP_MID);
IOT_ASSERT(NULL != g_local_rs485.cache_mutex);
if (false == iot_proto_uart_param_check(
baud_val[p_flash->public.pub.baudidx], p_flash->public.pub.parity,
p_flash->public.pub.data, p_flash->public.pub.stop)) {
p_flash->public.pub.baudidx = 2; // default baudrate = 2400
p_flash->public.pub.parity = IOT_UART_PARITY_EVEN;
p_flash->public.pub.data = IOT_UART_DLEN_8_BITS;
p_flash->public.pub.stop = IOT_UART_STOP_1_BITS;
}
iot_cctt_set_rs485_config_impl(baud_val[p_flash->public.pub.baudidx],
p_flash->public.pub.parity, p_flash->public.pub.data,
p_flash->public.pub.stop);
g_local_rs485.ready = true;
out:
return ret;
}
/**
* @brief: set configuration of rs485 interface by dl645 protocol
*
* @param data: dl645 request data
* @param len : length of dl645 request data
* @return none
*/
void iot_cctt_set_rs485_config(uint8_t *data, uint8_t len)
{
cctt_set_rs485_cfg_t *rs485_cfg = (cctt_set_rs485_cfg_t*)data;
uint8_t reason = DL645_ERR_PARAMETER_ERROR;
if ((false == g_local_rs485.ready) &&
(ERR_OK != iot_cctt_init_rs485_intf())) {
iot_cus_printf("can not set rs485 config, rs485 not ready!\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
/* protocol compatibility conversion */
if (2 == rs485_cfg->stopbits) {
rs485_cfg->stopbits = IOT_UART_STOP_2_BITS;
}
if (ERR_OK == iot_cctt_set_rs485_config_impl(rs485_cfg->baudrate,
rs485_cfg->parity, rs485_cfg->databits, rs485_cfg->stopbits)) {
reason = DL645_ERR_OK;
}
cctt_resp_cmd_ack(PROTO_645_2007_FN_WRITE_DATA, reason);
}
/**
* @brief: readout configuration of rs485 interface by dl645 protocol
*
* @param data: dl645 request data
* @param len : length of dl645 request data
* @return none
*/
void iot_cctt_read_rs485_config(uint8_t *data, uint8_t len)
{
iot_pkt_t *p_pkt;
proto_645_header_t *p_hdr;
cctt_read_rs485_cfg_t *p_rs485_cfg;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
uint32_t pkt_len = DL645_PARSE_FRM_MIN_LEN + sizeof(cctt_read_rs485_cfg_t);
uint32_t baud_val[] = PROTO_GE_UART_BAUD_VALUE;
ge_app_pib_info_t *p_flash = &prototask_contxt.flashinfo;
if ((false == g_local_rs485.ready) &&
(ERR_OK != iot_cctt_init_rs485_intf())) {
iot_cus_printf("can not read rs485 config, rs485 not ready!\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
p_pkt = iot_pkt_alloc(pkt_len, IOT_GREE_APP_MID);
if (NULL == p_pkt) {
iot_cus_printf("%s: memory runout!\n", __FUNCTION__);
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
p_hdr = (proto_645_header_t *)iot_pkt_put(p_pkt, pkt_len);
p_rs485_cfg = (cctt_read_rs485_cfg_t *)p_hdr->data;
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
iot_proto_645_header_init(p_hdr, dst_mac, PROTO_645_2007_FN_READ_DATA,
PROTO_645_DIR_SLAVE, PROTO_645_2007_ERR_OK, 0);
p_hdr->len = sizeof(cctt_read_rs485_cfg_t);
proto_645_2007_di_to_byte(DL645_07_DI_RS485_CONFIG,
(uint8_t*)&p_rs485_cfg->di);
p_rs485_cfg->baudrate = baud_val[p_flash->public.pub.baudidx];
p_rs485_cfg->parity = p_flash->public.pub.parity;
p_rs485_cfg->databits = p_flash->public.pub.data;
p_rs485_cfg->stopbits = p_flash->public.pub.stop;
/* protocol compatibility conversion */
if (IOT_UART_STOP_2_BITS == p_rs485_cfg->stopbits) {
p_rs485_cfg->stopbits = 2;
}
iot_proto_645_ext_add33_handle(p_hdr->data, p_hdr->len);
iot_proto_645_tail_init(p_hdr);
iot_proto_send_to_mainboard(p_pkt);
}
/**
* @brief: send data to rs485 interface
*
* @param buff : data buffer to send
* @param buff_len: length of buff
* @return none
*/
static void iot_cctt_rs485_send(uint8_t *buff, uint32_t buff_len)
{
iot_pkt_t *pkt;
uint8_t *data;
if (NULL == g_local_rs485.handler) {
iot_cus_printf("%s: rs485 handler null!\n", __FUNCTION__);
return;
}
pkt = iot_pkt_alloc(buff_len, IOT_GREE_APP_MID);
if (NULL == pkt) {
iot_cus_printf("%s rs485 send fail, pkt alloc fail!\n", __FUNCTION__);
return;
}
data = iot_pkt_put(pkt, buff_len);
os_mem_cpy(data, buff, buff_len);
iot_uart_send(g_local_rs485.handler, pkt, NULL);
}
/**
* @brief: dump bin data to log
*
* @param desc : description of bin data
* @param p_data: data to dump
* @param len : length of p_data
* @return none
*/
static void iot_cctt_bin_dump(char *desc, uint8_t *p_data, uint32_t len)
{
iot_cus_printf("%s:", desc);
while (len > 0) {
iot_cus_printf("%02X ", *p_data);
p_data++;
len--;
}
iot_cus_printf("\n");
}
/**
* @brief: wait data reply from rs485 interface
*
* @param p_buff : buffer used to store received reply
* @param len : length of p_buff
* @return length of received data
*/
static uint32_t iot_cctt_wait_rs485_reply(uint8_t *p_buff, uint32_t len)
{
uint64_t time_end = RS485_DEV_RESP_TO_MS + os_boot_time64();
uint64_t time_idle;
uint32_t ret = 0;
while (os_boot_time64() < time_end) {
os_acquire_mutex(g_local_rs485.cache_mutex);
time_idle = os_boot_time64() - g_local_rs485.recv_ts;
if ((g_local_rs485.cache_len > 0) &&
(time_idle >= RS485_DEV_IDLE_TO_MS)) {
if (g_local_rs485.cache_len < len) {
len = g_local_rs485.cache_len;
}
os_mem_cpy(p_buff, g_local_rs485.cache, len);
ret = g_local_rs485.cache_len;
}
os_release_mutex(g_local_rs485.cache_mutex);
if (ret > 0) {
iot_cus_printf("iot_cctt_wait_rs485_reply ret = %u\n", ret);
break;
} else {
os_delay(10);
}
}
return ret;
}
/**
* @brief: report specified data with specified di with DL645 protocol
*
* @param di : di of dl645 protocol
* @param data : data to send
* @param len : length of data
* @return none
*/
static void iot_cctt_report_local_data(uint32_t di, uint8_t *data, uint8_t len)
{
iot_pkt_t *p_pkt;
uint32_t pkt_len;
proto_645_header_t *p_hdr;
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
pkt_len = DL645_PARSE_FRM_MIN_LEN + DL645_DI_LEN + len;
p_pkt = iot_pkt_alloc(pkt_len, IOT_GREE_APP_MID);
if (NULL == p_pkt) {
iot_cus_printf("%s: can not alloc modbus reply frame!\n", __FUNCTION__);
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
p_hdr = (proto_645_header_t*)iot_pkt_put(p_pkt, pkt_len);
iot_mac_addr_cpy(dst_mac, prototask_contxt.local_dev.mac);
iot_mac_addr_reverse(dst_mac);
iot_proto_645_header_init(p_hdr, dst_mac, PROTO_645_2007_FN_READ_DATA,
PROTO_645_DIR_SLAVE, PROTO_645_2007_ERR_OK, 0);
p_hdr->len = DL645_DI_LEN + len;
proto_645_2007_di_to_byte(di, p_hdr->data);
os_mem_cpy(p_hdr->data + DL645_DI_LEN, data, len);
iot_proto_645_ext_add33_handle(p_hdr->data, p_hdr->len);
iot_proto_645_tail_init(p_hdr);
iot_proto_send_to_mainboard(p_pkt);
}
/**
* @brief: check whether the specified data is a complete dl645 frame
*
* @param p_data: data to check
* @param len : length of data
* @param p_frm_offset: pointer to store 645 frame offset in p_data
* @param p_frm_length: pointer to store 645 frame length in p_data
* @return ERR_OK if check pass, ERR_FAIL otherwise
*/
uint8_t proto_645_format_check(uint8_t *p_data, uint16_t len,
uint8_t *p_frm_offset, uint8_t *p_frm_lenth)
{
proto_645_header_t * hdr_645 = (proto_645_header_t*)p_data;
proto_645_tailer_t * tail_645 = NULL;
uint8_t frm_offset = 0;
uint8_t err_code = 0;
uint8_t ret = ERR_OK;
if ((NULL == p_data) || (len == 0) ||
(NULL == p_frm_offset) || (NULL == p_frm_lenth)) {
err_code = 9;
goto out;
}
/* skip preamble code before dl645 frame */
frm_offset = 0;
while ((frm_offset < len) && (p_data[frm_offset] != PROTO_645_START_CHAR)) {
frm_offset++;
}
len -= frm_offset;
p_data += frm_offset;
hdr_645 = (proto_645_header_t*)p_data;
if ((len == 0) || (p_data[0] != PROTO_645_START_CHAR)) {
err_code = 1;
goto out;
}
if (len <= PROTO_645_SECOND_HEAD_POS ||
p_data[PROTO_645_SECOND_HEAD_POS] != PROTO_645_START_CHAR) {
err_code = 2;
goto out;
}
if (len < sizeof(proto_645_header_t)) {
err_code = 3;
goto out;
}
if (hdr_645->start_char_2 != PROTO_645_START_CHAR) {
err_code = 4;
goto out;
}
if (len < hdr_645->len + sizeof(proto_645_header_t) +
sizeof(proto_645_tailer_t)) {
err_code = 5;
goto out;
}
tail_645 = (proto_645_tailer_t*)(p_data + sizeof(proto_645_header_t) +
hdr_645->len);
if (tail_645->end_char != PROTO_645_END_CHAR) {
err_code = 6;
goto out;
}
if (tail_645->cs != iot_proto_645_calc_cs(hdr_645)) {
err_code = 7;
goto out;
}
*p_frm_offset = frm_offset;
*p_frm_lenth = sizeof(proto_645_header_t) + hdr_645->len +
sizeof(proto_645_tailer_t);
out:
if (err_code > 0) {
ret = ERR_FAIL;
iot_cus_printf("%s: error_code=%d\n", __FUNCTION__, err_code);
}
return ret;
}
/**
* @brief: transparent transmit dl645 frame to rs485, reply dl645 response
*
* @param data : data to transparent transmit to rs485
* @param len : length of data
* @return none
*/
void iot_cctt_rs485_trans_dl645(uint8_t *data, uint8_t len)
{
static uint8_t recv_buff[256];
uint32_t recv_len;
uint8_t frm_offset = 0, frm_length = 0;
if ((NULL == data) || (len < DL645_DI_LEN)) {
return;
}
if ((false == g_local_rs485.ready) &&
(ERR_OK != iot_cctt_init_rs485_intf())) {
iot_cus_printf("can not trans dl645, rs485 not ready!\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
data += DL645_DI_LEN;
len -= DL645_DI_LEN;
os_acquire_mutex(g_local_rs485.cache_mutex);
g_local_rs485.cache_len = 0;
os_release_mutex(g_local_rs485.cache_mutex);
iot_cctt_rs485_led_blink();
iot_cctt_bin_dump("dl645 to rs485", data, len);
iot_cctt_rs485_send(data, len);
recv_len = iot_cctt_wait_rs485_reply(recv_buff, sizeof(recv_buff));
if (recv_len > 0) {
iot_cctt_bin_dump("rs485 reply", recv_buff, recv_len);
}
if (ERR_OK != proto_645_format_check(
recv_buff, recv_len, &frm_offset, &frm_length)) {
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_NO_REQ_DATA);
return;
}
iot_cctt_rs485_led_blink();
iot_cctt_report_local_data(DL645_07_DI_TRANS_DL645,
recv_buff + frm_offset, frm_length);
}
/**
 * @brief check the validity of modbus frame.
 * @param data: point to the data
 * @param len:  the number of input data
 * @return: ERR_OK --> success; ERR_FAIL --> failed.
 */
static uint8_t iot_cctt_modbus_frame_check(uint8_t *data, uint32_t len)
{
uint8_t i;
uint32_t pos;
uint16_t crc = 0xFFFF;
for (pos = 0; pos < len; pos++) {
/* XOR byte into least sig. byte of crc */
crc ^= (uint16_t)data[pos];
/* Loop over each bit */
for (i = 8; i != 0; i--) {
/* If the LSB is set */
if ((crc & 0x0001) != 0) {
/* Shift right and XOR 0xA001 */
crc >>= 1;
/* Else LSB is not set */
crc ^= 0xA001;
} else {
/* Just shift right */
crc >>= 1;
}
}
}
/* Note, this number has low and high bytes swapped,
so use it accordingly (or swap bytes) */
return (0x0 == crc) ? ERR_OK : ERR_FAIL;
}
/**
* @brief: transparent transmit modbus frame to rs485, reply modbus response
*
* @param data : data to transparent transmit to rs485
* @param len : length of data
* @return none
*/
void iot_cctt_rs485_trans_modbus(uint8_t *data, uint8_t len)
{
static uint8_t recv_buff[256];
uint32_t recv_len;
if ((NULL == data) || (len < DL645_DI_LEN)) {
return;
}
if ((false == g_local_rs485.ready) &&
(ERR_OK != iot_cctt_init_rs485_intf())) {
iot_cus_printf("can not trans modbus, rs485 not ready!\n");
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_OTHER_ERROR);
return;
}
data += DL645_DI_LEN;
len -= DL645_DI_LEN;
os_acquire_mutex(g_local_rs485.cache_mutex);
g_local_rs485.cache_len = 0;
os_release_mutex(g_local_rs485.cache_mutex);
iot_cctt_rs485_led_blink();
iot_cctt_bin_dump("modbus to rs485", data, len);
iot_cctt_rs485_send(data, len);
recv_len = iot_cctt_wait_rs485_reply(recv_buff, sizeof(recv_buff));
if (0 != recv_len) {
iot_cctt_bin_dump("rs485 reply", recv_buff, recv_len);
} else {
iot_cus_printf("%s: rs485 device no reply!\n", __FUNCTION__);
}
if(ERR_OK != iot_cctt_modbus_frame_check(recv_buff, recv_len)) {
cctt_resp_cmd_ack(PROTO_645_2007_FN_READ_DATA, DL645_ERR_NO_REQ_DATA);
return;
}
iot_cctt_rs485_led_blink();
iot_cctt_report_local_data(DL645_07_DI_TRANS_MODBUS, recv_buff, recv_len);
}
static void cctt_read_data_cmd_handle(proto_645_header_t *header)
{
uint32_t di;
iot_pkt_t *p_pkt;
uint16_t msg_id = 0xff;
uint16_t pkt_len;
proto_645_2007_byte_to_di(header->data, di);
iot_cus_printf("cctt_read_data_cmd_handle di:%08X\n", di);
switch (di) {
case DL645_07_DI_QUERY_WHITELIST:
{
msg_id = CCTT_QUERY_WHITELIST;
break;
}
case DL645_07_DI_QUERY_TOPO:
{
msg_id = CCTT_QUERY_TOPO;
break;
}
case DL645_07_DI_RS485_CONFIG:
{
msg_id = CCTT_READ_RS485_CONFIG;
break;
}
case DL645_07_DI_TRANS_DL645:
{
msg_id = CCTT_RS485_TRANS_DL645;
break;
}
case DL645_07_DI_TRANS_MODBUS:
{
msg_id = CCTT_RS485_TRANS_MODBUS;
break;
}
case DL645_07_DI_HANDLE_PLC_NW:
{
msg_id = CCTT_READ_PLC_NW;
break;
}
case DL645_07_DI_DELAYTIME:
{
msg_id = CCTT_DELAYTIME;
break;
}
default:
break;
}
if (msg_id != 0xFF) {
if (msg_id == CCTT_DELAYTIME) {
/* need post dst_mac */
pkt_len = header->len + sizeof(header);
} else {
pkt_len = header->len;
}
p_pkt = iot_pkt_alloc(header->len , IOT_GREE_APP_MID);
if (!p_pkt) {
iot_cus_printf("[dl645][err]No Mem!\n");
return;
}
if (msg_id == CCTT_DELAYTIME) {
os_mem_cpy(iot_pkt_put(p_pkt, pkt_len), (uint8_t *)header, pkt_len);
} else {
os_mem_cpy(iot_pkt_put(p_pkt, pkt_len), header->data, pkt_len);
}
iot_proto_task_post_msg(PROTO_CCTT_MSG, msg_id, p_pkt,
0, IOT_PROTO_TASK_QUEUE_LP);
}
}
static void cctt_write_data_cmd_handle(proto_645_header_t *header)
{
uint32_t di;
iot_pkt_t *p_pkt;
uint16_t msg_id = 0xff;
proto_645_2007_byte_to_di(header->data, di);
iot_cus_printf("cctt_write_data_cmd_handle di:%08X\n", di);
switch (di) {
case DL645_07_DI_ADD_WHITELISET:
{
msg_id = CCTT_ADD_WHITELIST;
break;
}
case DL645_07_DI_DEL_WHITELISET:
{
msg_id = CCTT_DEL_WHITELIST;
break;
}
case DL645_07_DI_REBOOT_CCTT:
case DL645_07_DI_REBOOT_CCO:
{
msg_id = CCTT_REBOOT_CCO;
break;
}
case DL645_07_DI_REBOOT_STA:
{
msg_id = CCTT_REBOOT_STA;
break;
}
case DL645_07_DI_WL_STATE:
{
msg_id = CCTT_SET_WL_STATE;
break;
}
case DL645_07_DI_CLEAR_WL:
{
msg_id = CCTT_CLR_WHITELIST;
break;
}
case DL645_07_DI_CHECK_WL_ADDR:
{
msg_id = CCTT_CHECK_WL_MAC;
break;
}
case DL645_07_DI_HANDLE_PLC_NW:
{
msg_id = CCTT_SET_PLC_NW;
break;
}
case DL645_07_DI_REBOOT_MAC_LIST_PCO:
{
msg_id = CCTT_REBOOT_MAC_LIST_PCO;
break;
}
case DL645_07_DI_RS485_CONFIG:
{
msg_id = CCTT_SET_RS485_CONFIG;
break;
}
default:
break;
}
if (msg_id != 0xFF) {
p_pkt = iot_pkt_alloc(header->len, IOT_GREE_APP_MID);
if (!p_pkt) {
iot_cus_printf("[dl645][err]No Mem!\n");
return;
}
os_mem_cpy(iot_pkt_put(p_pkt, header->len), header->data, header->len);
iot_proto_task_post_msg(PROTO_CCTT_MSG, msg_id, p_pkt,
0, IOT_PROTO_TASK_QUEUE_LP);
}
}
/**
* @brief iot_cctt_handle_local_dl645_cmd() - handle the local cmd
* data is del 0x33
* @param pkt: point to the dl645 pkt data
*/
uint8_t iot_cctt_handle_local_dl645_cmd(iot_pkt_t *pkt)
{
proto_645_header_t *header = (proto_645_header_t*)iot_pkt_data(pkt);
switch (header->control.fn) {
case PROTO_645_2007_FN_READ_DATA:
case PROTO_645_2007_FN_READ_DATA_C:
{
cctt_read_data_cmd_handle(header);
break;
}
case PROTO_645_2007_FN_WRITE_DATA:
{
cctt_write_data_cmd_handle(header);
break;
}
default:
break;
}
return 0;
}
uint8_t iot_cco_resp_topo_set_query_info(uint8_t done, uint16_t resp_cnt)
{
if (done) {
os_mem_set(&g_cctt_context, 0, sizeof(cctt_context_t));
} else {
g_cctt_context.q_topo_pos += resp_cnt;
if (g_cctt_context.q_topo_cnt != 0xFFFF) {
g_cctt_context.q_topo_cnt -= resp_cnt;
}
}
return 0;
}
void cctt_init(void)
{
g_cctt_context.plc_nw_state = PLC_NW_OPEN;
g_local_rs485.ready = false;
}
#endif /* PLC_SUPPORT_CCO_ROLE */