Files
kunlun/app/sg_ctrl/iot_sg_ctrl_gw_drv.c

608 lines
17 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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.
****************************************************************************/
#include "iot_errno_api.h"
#include "iot_board_api.h"
#include "iot_plc_msg_api.h"
#include "proto_3762.h"
#include "proto_3762_vendor.h"
#include "iot_sg_ctrl_api.h"
#if (IOT_SG_CONTROLLER_ENABLE)
static uint16_t app_sn = 0;
static uint8_t connect_state = 0;
/* command from app */
typedef struct _ctrl_frame_pkt_t {
/* msdu sequence number */
uint16_t app_sn;
/* app function number definition */
uint8_t afn;
/* function code for each command */
uint8_t fn;
/* app_data */
uint8_t *app_data;
/* 3762 data len */
uint16_t app_data_len;
} ctrl_frame_pkt_t;
static uint8_t iot_sg_ctrl_send_uart(uint8_t afn, uint8_t fn,
uint8_t *app_data, uint16_t len, uint8_t *mac_buf, uint32_t mac_cnt,
uint8_t sn)
{
pkt_3762_hdr_t *pkt_hdr;
iot_pkt_t *pkt;
uint8_t *data, *cs_ptr = NULL, ret = ERR_OK;
uint16_t index = 0;
pkt = iot_pkt_alloc(proto_3762_get_pkt_len(mac_cnt, len),
IOT_SMART_GRID_MID);
if (!pkt) {
ret = ERR_NOMEM;
goto out;
}
data = iot_pkt_data(pkt);
pkt_hdr = (pkt_3762_hdr_t*)data;
pkt_hdr->sof_byte = PROTO_3762_SOF_BYTE;
pkt_hdr->ctrl_byte.dir = PROTO_3762_DIR_UP_LINK;
pkt_hdr->ctrl_byte.prm = PROTO_3762_PRM_SLAVE;
pkt_hdr->ctrl_byte.phy_type = PROTO_3762_PHY_TYPE_PLC;
/* user_data = &data[index]; */
os_mem_set(&pkt_hdr->user_data.res.ul_info, 0, sizeof(pkt_hdr->user_data));
pkt_hdr->user_data.res.ul_info.route_flag = 0;
pkt_hdr->user_data.res.ul_info.phy_phase = 0;
pkt_hdr->user_data.res.ul_info.sn = sn;
pkt_hdr->user_data.res.ul_info.channel_id = 0;
pkt_hdr->user_data.res.ul_info.event_flag = 0;
pkt_hdr->user_data.res.ul_info.line_flag = 0;
pkt_hdr->user_data.res.ul_info.tsfm_status = 0;
index += sizeof(pkt_3762_hdr_t);
if (mac_cnt) {
pkt_hdr->user_data.res.ul_info.comm_module = 1;
/* only src mac and dest mac for up link */
os_mem_cpy(data + index, mac_buf, mac_cnt * PROTO_3762_MAC_ADDR_LEN);
index += (uint16_t)mac_cnt * PROTO_3762_MAC_ADDR_LEN;
}
/* set AFN */
data[index] = afn;
index++;
/* set Fn */
data[index] = 1 << ((fn - 1) % 8); /* DT1 */
index++;
data[index] = (fn - 1) / 8; /* DT2 */
index++;
os_mem_cpy(data + index, app_data, len);
index += len;
cs_ptr = &data[index++]; /* set the checksum byte pointer */
data[index] = PROTO_3762_EOF_BYTE;
index++;
pkt_hdr->len = index;
*cs_ptr = proto_3762_get_checksum(data[PROTO_3762_CTRL_OFFSET],
data + PROTO_3762_DATA_OFFSET,
index - PROTO_3762_DATA_OFFSET - 2);
// put checksum and back code. 2 byte.
iot_pkt_put(pkt, index);
iot_ctrl_uart_send(pkt);
out:
return ret;
}
static uint32_t iot_sg_ctrl_drv_init()
{
uint32_t ret = 0;
uint32_t result = ERR_OK;
iot_frame_fmt fmt = { 0 };
/* config the UART port settings */
fmt.preamble_code[0] = PROTO_3762_2013_START_CHAR;
fmt.preamble_codelen = 1;
fmt.datalen_offset = 0;
fmt.datalen_size = 2;
fmt.backcode_offset = 0;
fmt.backcode_len = 1;
/* in uart data parsing, datalen means raw data to be send,
* excluding preamble/datalen/backcode. For datalen field in
* 3762 datagram means the length of the whole datagram, we shall
* set the datalen_fix as below.
*/
fmt.datalen_fix = fmt.preamble_codelen +
fmt.datalen_size + fmt.backcode_len;
fmt.backcode[0] = PROTO_3762_2013_END_CHAR;
fmt.frame_timeout = CTRL_FRAME_PARSE_TIMEOUT;
fmt.timeout_mode = TIMEOUT_PERDATA;
fmt.check_frame_func = proto_3762_check_frame_handler;
ret = iot_sg_ctrl_config_uart(IOT_SG_CTRL_DEFAULT_BAUD,
(uint8_t)IOT_UART_PARITY_EVEN, (uint8_t)IOT_UART_DLEN_8_BITS,
(uint8_t)IOT_UART_STOP_1_BITS, &fmt);
if (!ret) {
result = ERR_FAIL;
}
return result;
}
static void iot_sg_ctrl_drv_deinit()
{
return;
}
static void iot_sg_ctrl_send_00h01_ack(uint8_t sn)
{
afn00_fn01_conf_13_t reject = { 0 };
reject.cmd_state = 1;
iot_sg_ctrl_send_uart(PROTO_3762_AFN_00, PROTO_3762_F1, (uint8_t*)&reject,
sizeof(reject), NULL, 0, sn);
}
static void iot_sg_ctrl_send_00h02_nack(uint8_t reason, uint8_t sn)
{
afn00_fn02_reject_t reject = { 0 };
reject.err_no = reason;
iot_sg_ctrl_send_uart(PROTO_3762_AFN_00, PROTO_3762_F2, (uint8_t*)&reject,
sizeof(reject), NULL, 0, sn);
}
static void iot_sg_ctrl_send_f0_f250_status_rpt(uint8_t connect,
uint8_t role, uint8_t *addr, uint8_t sn)
{
afnf0_fn250_status_rpt_ul_t uart_rpt;
os_mem_set(&uart_rpt, 0, sizeof(uart_rpt));
if (connect) {
uart_rpt.ready = PROTO_3762_STATE_CONNECTED;
if (role == PROTO_CTRL_DEV_ROLE_CCO) {
uart_rpt.connect_role = PROTO_3762_DEV_ROLE_CCO;
} else {
uart_rpt.connect_role = PROTO_3762_DEV_ROLE_STA;
}
iot_mac_addr_cpy(uart_rpt.addr, addr);
} else {
uart_rpt.ready = PROTO_3762_STATE_DISCONNECTED;
}
iot_sg_ctrl_send_uart(PROTO_3762_AFN_F0, PROTO_3762_F250,
(uint8_t *)&uart_rpt, sizeof(uart_rpt), NULL, 0, sn);
}
static void iot_sg_ctrl_rpt_id_info(uint8_t *data, uint16_t len, uint8_t sn)
{
uint32_t pkt_len;
iot_pkt_t *pkt = NULL;
afn10h_fn40_query_node_id_ul_t *rsp;
iot_sg_ctrl_id_info_t *id_info = (iot_sg_ctrl_id_info_t *)data;
(void)len;
pkt_len = id_info->id_len + sizeof(afn10h_fn40_query_node_id_ul_t);
pkt = (iot_pkt_t *)iot_pkt_alloc(pkt_len, IOT_SMART_GRID_MID);
IOT_ASSERT(pkt);
rsp = (afn10h_fn40_query_node_id_ul_t *)iot_pkt_data(pkt);
rsp->dev_type = id_info->dev_type;
iot_mac_addr_cpy(rsp->mac, id_info->addr);
rsp->id_type = id_info->id_type;
rsp->id_len = id_info->id_len;
rsp->dev_type = id_info->dev_type;
os_mem_cpy(rsp->id_info, id_info->info, id_info->id_len);
iot_pkt_put(pkt, pkt_len);
iot_sg_ctrl_send_uart(PROTO_3762_AFN_10, PROTO_3762_F40, iot_pkt_data(pkt),
(uint16_t)pkt_len, NULL, 0, sn);
iot_pkt_free(pkt);
}
static uint32_t iot_sg_ctrl_event_report_handle(uint8_t sn,
uint8_t *addr, uint8_t dev_type, uint32_t proto_type,
uint8_t evt_type, uint8_t *data, uint16_t len)
{
(void)proto_type;
switch (evt_type) {
case IOT_CTRL_EVENT_DEVICE_CONNECT_CONF:
iot_sg_ctrl_send_00h01_ack(sn);
break;
case IOT_CTRL_EVENT_DEVICE_CONNECT_FAIL:
iot_sg_ctrl_send_00h02_nack(COMM_TIMEOUT, sn);
break;
case IOT_CTRL_EVENT_DEVICE_CONNECTED:
connect_state = 1;
iot_sg_ctrl_send_f0_f250_status_rpt(1, dev_type, addr, sn);
break;
case IOT_CTRL_EVENT_DEVICE_DISCONNECTED:
connect_state = 0;
iot_sg_ctrl_send_f0_f250_status_rpt(0, dev_type, addr, sn);
break;
case IOT_CTRL_EVENT_METER_DATA:
iot_sg_ctrl_send_uart(PROTO_3762_AFN_13, PROTO_3762_F1, data, len,
NULL, 0, sn);
break;
case IOT_CTRL_EVENT_ID_INFO:
iot_sg_ctrl_rpt_id_info(data, len, sn);
break;
default:
break;
}
return ERR_OK;
}
static void iot_sg_ctrl_f0h_f249(ctrl_frame_pkt_t *frm)
{
uint32_t result = ERR_FAIL;
uint8_t reason = MASTER_UNSUPPORTED_CMD;
afnf0_fn249_connect_conf_dl_t *cmd =
(afnf0_fn249_connect_conf_dl_t*)frm->app_data;
uint16_t len = frm->app_data_len;
if (len < sizeof(afnf0_fn249_connect_conf_dl_t)) {
reason = INVALID_DATA_LEN;
goto out;
}
if (iot_board_check_magic_no(cmd->magic_no) == 0) {
iot_sg_ctrl_printf("%s : magic_no check fail \n", __FUNCTION__);
goto out;
}
if (ERR_OK == iot_sg_ctrl_proto_connect(cmd->dst_mac,
(uint8_t)frm->app_sn)) {
result = ERR_OK;
}
out:
if (ERR_OK != result) {
iot_sg_ctrl_send_00h02_nack(reason, (uint8_t)frm->app_sn);
}
}
static void iot_sg_ctrl_f0h_debug(ctrl_frame_pkt_t *frm)
{
uint32_t result = ERR_FAIL;
uint8_t reason = MASTER_UNSUPPORTED_CMD;
switch (frm->fn) {
case PROTO_3762_F249:
{
iot_sg_ctrl_f0h_f249(frm);
result = ERR_OK;
break;
}
default:
break;
}
if (ERR_OK !=result) {
iot_sg_ctrl_send_00h02_nack(reason, (uint8_t)frm->app_sn);
}
}
static void iot_sg_ctrl_send_data_handle_cco(ctrl_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint8_t reason;
uint8_t consumed = 0;
iot_sg_ctrl_printf("%s: afn = 0x%02X, fn = 0n%lu, sn: %d \n", __FUNCTION__,
frm->afn, frm->fn, frm->app_sn);
switch (frm->afn) {
case PROTO_3762_AFN_F0:
{
switch (frm->fn) {
case PROTO_3762_F249:
{
iot_sg_ctrl_f0h_debug(frm);
goto out;
}
case PROTO_3762_F233:
case PROTO_3762_F234:
{
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
case PROTO_3762_AFN_05:
{
switch (frm->fn) {
case PROTO_3762_F131:
{
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
case PROTO_3762_AFN_10:
{
switch (frm->fn) {
case PROTO_3762_F2:
case PROTO_3762_F21:
{
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
case PROTO_3762_AFN_11:
{
switch (frm->fn) {
case PROTO_3762_F126:
case PROTO_3762_F127:
{
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
case PROTO_3762_AFN_13:
{
switch (frm->fn) {
case PROTO_3762_F1:
{
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
consumed = 1;
if (iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_MR_CCO,
(uint8_t)frm->app_sn, pkt)) {
reason = INVALID_DATA;
goto err;
}
goto out;
err:
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,fn : %x\n",
__FUNCTION__, reason, frm->afn, frm->fn);
iot_sg_ctrl_send_00h02_nack(reason, (uint8_t)app_sn);
out:
if (!consumed) {
iot_pkt_free(pkt);
}
return;
}
static void iot_sg_ctrl_send_data_handle_sta(ctrl_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint8_t reason;
uint8_t consumed = 0;
iot_sg_ctrl_printf("%s: afn = 0x%02X, fn = 0n%lu, sn: %d \n", __FUNCTION__,
frm->afn, frm->fn, frm->app_sn);
switch (frm->afn) {
case PROTO_3762_AFN_F0:
{
iot_sg_ctrl_f0h_debug(frm);
break;
}
case PROTO_3762_AFN_13:
{
switch (frm->fn) {
case PROTO_3762_F1:
{
afn13_fn01_router_data_fwd_2013_t *req;
datagram_t *datagram;
req = (afn13_fn01_router_data_fwd_2013_t *)(frm->app_data);
datagram = (datagram_t *)req->mac[req->sec_node_cnt];
iot_pkt_set_data(pkt, datagram->data);
iot_pkt_set_tail(pkt, datagram->data + datagram->data_len);
consumed = 1;
if (iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_MR_STA,
(uint8_t)frm->app_sn, pkt)) {
reason = INVALID_DATA;
goto err;
}
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
case PROTO_3762_AFN_10:
{
switch (frm->fn) {
case PROTO_3762_F40:
{
afn10h_fn40_query_node_id_dl_t *req;
req = (afn10h_fn40_query_node_id_dl_t *)frm->app_data;
if (!connect_state) {
iot_sg_ctrl_proto_connect(req->mac, (uint8_t)frm->app_sn);
}
iot_pkt_set_data(pkt, &(req->id_type));
iot_pkt_set_tail(pkt, &(req->id_type) + sizeof(req->id_type));
consumed = 1;
if (iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_QR_CHIP_ID_STA,
(uint8_t)frm->app_sn, pkt)) {
reason = INVALID_DATA;
goto err;
}
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
break;
}
default:
reason = MASTER_UNSUPPORTED_CMD;
goto err;
}
goto out;
err:
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,fn : %x\n",
__FUNCTION__, reason, frm->afn, frm->fn);
iot_sg_ctrl_send_00h02_nack(reason, (uint8_t)app_sn);
out:
if (!consumed) {
iot_pkt_free(pkt);
}
return;
}
static void iot_sg_ctrl_send_data_handle(ctrl_frame_pkt_t *frm, iot_pkt_t *pkt)
{
switch (iot_sg_ctrl_get_connect_role()) {
case IOT_PLC_DEV_ROLE_INVALID:
case IOT_PLC_DEV_ROLE_CCO:
iot_sg_ctrl_send_data_handle_cco(frm, pkt);
break;
case IOT_PLC_DEV_ROLE_STA:
case IOT_PLC_DEV_ROLE_PCO:
iot_sg_ctrl_send_data_handle_sta(frm, pkt);
break;
default:
break;
}
}
/**
* @brief iot_sg_ctrl_uart_data_recv_handle - receive uart data
* @param pkt: include full 3762 frame, the pkt whill be free
*/
static uint32_t iot_sg_ctrl_uart_data_recv_handle(iot_pkt_t *pkt)
{
uint8_t *data = iot_pkt_data(pkt);
uint16_t len = (uint16_t)iot_pkt_data_len(pkt);
uint8_t *app_data = NULL, addr_cnt;
uint8_t result;
uint16_t app_data_len = len;
user_data_t *user_data = NULL;
ctrl_frame_pkt_t frm = {0};
uint32_t relsut = ERR_OK;
if (len < sizeof(user_data_t) + PROTO_3762_DATA_OFFSET) {
result = INVALID_DATA;
goto err;
}
parse_3762:
user_data = (user_data_t*)(data + PROTO_3762_DATA_OFFSET);
result = (uint8_t)proto_3762_sanity_check(data, app_data_len);
if ((result == INVALID_DATA_LEN) || (result == INVALID_FORMAT)) {
do {
app_data_len--;
data += 1;
if (data[0] == PROTO_3762_SOF_BYTE) {
goto parse_3762;
}
} while (app_data_len > PROTO_3762_FIX_FIELD_LEN);
goto err;
} else if (result) {
goto err;
}
if (app_data_len < sizeof(user_data_t) + PROTO_3762_DATA_OFFSET) {
result = INVALID_DATA;
goto err;
}
app_data = user_data->data;
app_data_len -= (sizeof(user_data->res) + PROTO_3762_DATA_OFFSET);
if (user_data->res.dl_info.comm_module != 0) {
addr_cnt = 2 + user_data->res.dl_info.rpter_level;
app_data += PROTO_3762_MAC_ADDR_LEN * addr_cnt;
app_data_len -= PROTO_3762_MAC_ADDR_LEN * addr_cnt;
}
frm.app_sn = user_data->res.dl_info.sn;
app_sn = frm.app_sn;
frm.afn = app_data[0];
frm.fn = proto_3762_get_fn_code(app_data + 1);
frm.app_data_len = app_data_len - (PROTO_3762_AFN_FN_LEN +
PROTO_3762_CHECKSUM_LEN + PROTO_3762_BACKCODE_LEN);
frm.app_data = (app_data + PROTO_3762_AFN_FN_LEN);
iot_sg_ctrl_send_data_handle(&frm, pkt);
goto out;
err:
iot_pkt_free(pkt);
relsut = ERR_FAIL;
out:
return relsut;
}
static uint32_t iot_sg_ctrl_check_data_handle(iot_pkt_t *pkt)
{
uint8_t *data = iot_pkt_data(pkt);
uint16_t len = (uint16_t)iot_pkt_data_len(pkt);
uint8_t ctrl = 0;
uint32_t result = INVALID_DATA;
if (len < sizeof(user_data_t) + PROTO_3762_DATA_OFFSET) {
return result;
}
parse_3762:
result = proto_3762_sanity_check(data, len);
if ((result == INVALID_DATA_LEN) || (result == INVALID_FORMAT)) {
do {
len--;
data += 1;
if (data[0] == PROTO_3762_SOF_BYTE) {
goto parse_3762;
}
} while (len > PROTO_3762_FIX_FIELD_LEN);
goto out;
} else if (result) {
goto out;
}
if (len < sizeof(user_data_t) + PROTO_3762_DATA_OFFSET) {
result = INVALID_DATA;
goto out;
}
ctrl = data[PROTO_3762_CTRL_OFFSET];
if ((ctrl & 0x1f) == PROTO_CTRL_COMMUNICAT_PLC) {
result = ERR_OK;
} else {
result = INVALID_DATA;
}
out:
return result;
}
iot_ctrl_drv_t g_sg_ctrl_drv = {
.drv_id = IOT_CTRL_DRV_ID_SG,
.init = iot_sg_ctrl_drv_init,
.deinit = iot_sg_ctrl_drv_deinit,
.event_report_handle = iot_sg_ctrl_event_report_handle,
.ctrl_drv_data_handle = iot_sg_ctrl_uart_data_recv_handle,
.check_data_handle = iot_sg_ctrl_check_data_handle,
.freq_band_report_cb = NULL,
.freq_band_set_result_cb = NULL,
};
#endif /* IOT_SG_CONTROLLER_ENABLE */