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

917 lines
27 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.
****************************************************************************/
#include "iot_errno_api.h"
#include "os_utils_api.h"
#include "iot_uart_api.h"
#include "iot_version_api.h"
#include "iot_system_api.h"
#include "proto_spg_cco.h"
#include "iot_sg_ctrl_api.h"
#include "proto_645.h"
#if (IOT_SG_CONTROLLER_ENABLE)
/* report max scan node count */
#define IOT_CTRL_SCAN_NODE_MAX_CNT (200)
/* command from contrl application */
typedef struct _ctrl_spg_frame_pkt_t {
/* main application function code */
uint8_t afn;
/* seccondary application function code */
uint8_t fn;
/* sequence number of ctrl command */
uint8_t app_sn;
/* length of the applied data (unit: byte)*/
uint16_t app_data_len;
/* applied data */
uint8_t *app_data;
}ctrl_spg_frame_pkt_t;
typedef struct _spg_cctt_drv_data {
/* seq number */
uint8_t sn;
/* requested meter mac */
uint8_t req_mac[IOT_MAC_ADDR_LEN];
/* destination mac in address field */
uint8_t dest_mac[IOT_MAC_ADDR_LEN];
} spg_cctt_drv_data;
static spg_cctt_drv_data *drv_data = NULL;
static uint32_t iot_spg_ctrl_send_uart_sn_ext(uint8_t role, uint8_t afn,
uint8_t fn, iot_pkt_t *pkt, uint8_t sn, uint8_t mac_used, uint8_t *req_mac,
uint8_t *dec_mac, uint8_t di2)
{
uint8_t *data = NULL;
proto_spg_hdr_t *pkt_hdr = NULL;
proto_spg_addr_field_t *spg_addr_ptr = NULL;
proto_spg_app_data_t *spg_app_ptr = NULL;
uint8_t *cs_ptr = NULL; //pointer to checksum
uint16_t index = 0;
uint16_t app_data_len = (uint16_t)iot_pkt_data_len(pkt);
data = iot_pkt_push(pkt, proto_spg_get_header_len(mac_used));
IOT_ASSERT(data);
if ((iot_pkt_block_len(pkt, IOT_PKT_BLOCK_DATA) + PROTO_SPG_CS_BCODE_LEN) !=
proto_spg_get_proto_pkt_len(mac_used, app_data_len)) {
iot_pkt_free(pkt);
return ERR_NOMEM;
}
pkt_hdr = (proto_spg_hdr_t*)data;
pkt_hdr->sof_byte = PROTO_SPG_SOF_BYTE;
pkt_hdr->ctrl_byte.dir = PROTO_SPG_DIR_UP_LINK;
if (role == PROTO_SPG_PRM_SLAVE) {
/* response Message */
pkt_hdr->ctrl_byte.prm = PROTO_SPG_PRM_SLAVE;
} else {
/* report message */
pkt_hdr->ctrl_byte.prm = PROTO_SPG_PRM_MASTER;
}
pkt_hdr->ctrl_byte.addr = PROTO_SPG_NO_ADDRESS;
pkt_hdr->ctrl_byte.ver = PROTO_SPG_DEFAULT_VERSION;
pkt_hdr->ctrl_byte.rsvd = 0;
index += sizeof(proto_spg_hdr_t);
if (mac_used && req_mac && dec_mac) {
spg_addr_ptr = (proto_spg_addr_field_t *)(data+index);
pkt_hdr->ctrl_byte.addr = PROTO_SPG_WITH_ADDRESS;
/* only src mac and dest mac for up link */
os_mem_cpy(spg_addr_ptr->src_mac, req_mac, PROTO_SPG_MAC_ADDR_LEN);
index += PROTO_SPG_MAC_ADDR_LEN;
os_mem_cpy(spg_addr_ptr->dest_mac, dec_mac, PROTO_SPG_MAC_ADDR_LEN);
index += PROTO_SPG_MAC_ADDR_LEN;
}
spg_app_ptr = (proto_spg_app_data_t *)(data+index);
spg_app_ptr->afn = afn;
spg_app_ptr->seq = sn;
spg_app_ptr->di[0] = fn;
spg_app_ptr->di[1] = afn;
spg_app_ptr->di[2] = di2;
spg_app_ptr->di[3] = (uint8_t)PROTO_SPG_APP_CTRL_DI3;
index += sizeof(proto_spg_app_data_t);
/* skip app data as app data is already in iot_pkt */
index += app_data_len;
/* check sum field */
cs_ptr = (data +index);
index++;
/* tail of the frame */
data[index] = PROTO_SPG_EOF_BYTE;
index++;
pkt_hdr->len = index;
*cs_ptr = proto_spg_get_checksum(data + PROTO_SPG_CTRL_OFFSET,
index - PROTO_SPG_CTRL_OFFSET - PROTO_SPG_CHECKSUM_LEN -
PROTO_SPG_BACKCODE_LEN);
// put checksum and back code. 2 byte.
iot_pkt_put(pkt, PROTO_SPG_CS_BCODE_LEN);
iot_ctrl_uart_send(pkt);
return ERR_OK;
}
static uint32_t iot_spg_ctrl_send_uart_sn(uint8_t role, uint8_t afn,
uint8_t fn, iot_pkt_t *pkt, uint8_t di2, uint8_t mac_used, uint8_t sn)
{
if (mac_used) {
return iot_spg_ctrl_send_uart_sn_ext(role, afn, fn, pkt, sn,
SPG_USED_ADDR, drv_data->dest_mac, drv_data->req_mac, di2);
} else {
return iot_spg_ctrl_send_uart_sn_ext(role, afn, fn, pkt, sn,
SPG_NO_USED_ADDR, NULL, NULL, di2);
}
}
static uint32_t iot_spg_ctrl_send_uart(uint8_t role, uint8_t afn, uint8_t fn,
const uint8_t *app_data, uint16_t len, uint8_t di2, uint8_t mac_used,
uint8_t sn)
{
iot_pkt_t *pkt = NULL;
uint8_t *pkt_data = NULL;
pkt = iot_pkt_alloc(proto_spg_get_pkt_len(mac_used, len),
IOT_SMART_GRID_MID);
IOT_ASSERT(pkt);
pkt_data = iot_pkt_reserve(pkt, proto_spg_get_rsvd_len(mac_used));
if (app_data && len) {
os_mem_cpy(pkt_data, app_data, len);
iot_pkt_put(pkt, len);
}
return iot_spg_ctrl_send_uart_sn(role, afn, fn, pkt, di2, mac_used, sn);
}
static uint32_t iot_spg_ctrl_drv_init()
{
uint32_t ret = 0;
uint32_t result = ERR_OK;
iot_frame_fmt fmt = { 0 };
if (!drv_data) {
drv_data = os_mem_malloc(IOT_SMART_GRID_MID,
sizeof(*drv_data));
if (!drv_data) {
return ERR_NOMEM;
}
}
/* config the UART port settings */
fmt.preamble_code[0] = PROTO_SPG_SOF_BYTE;
fmt.preamble_codelen = PROTO_SPG_PRECODE_LEN;
fmt.datalen_offset = 0;
fmt.datalen_size = PROTO_SPG_LENGTH_SIZE;
fmt.backcode_offset = 0;
fmt.backcode_len = PROTO_SPG_BACKCODE_LEN;
/* in uart data parsing, datalen means raw data to be send,
* excluding preamble/datalen/backcode. For datalen field in
* spg 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_SPG_EOF_BYTE;
fmt.frame_timeout = CTRL_FRAME_PARSE_TIMEOUT;
fmt.timeout_mode = TIMEOUT_PERDATA;
fmt.check_frame_func = proto_spg_check_frame_handler;
ret = iot_sg_ctrl_config_uart(PROTO_SPG_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_spg_ctrl_drv_deinit()
{
if (drv_data) {
os_mem_free(drv_data);
drv_data = NULL;
}
return;
}
static void iot_spg_ctrl_freq_band_handler(
iot_plc_freq_band_info_query_rpt_t *rpt)
{
spg_query_freq_band_t rsp = { 0 };
rsp.freq_band = rpt->freq_band;
/* report this response to UART/APP */
iot_spg_ctrl_send_uart(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_03,
PROTO_SPG_F90, (uint8_t *)&rsp, (uint16_t)sizeof(rsp),
PROTO_SPG_APP_DI2_00, SPG_NO_USED_ADDR, drv_data->sn);
}
static void iot_spg_ctrl_send_00h02_nack(uint8_t reason, uint8_t sn)
{
spg_afn00_fn02_reject_t reject = { 0 };
reject.err_no = reason;
iot_spg_ctrl_send_uart(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_00, PROTO_SPG_F2,
(uint8_t*)&reject, sizeof(reject), PROTO_SPG_APP_DI2_01,
SPG_NO_USED_ADDR, sn);
}
static void iot_spg_ctrl_send_00h01_ack(uint8_t sn)
{
spg_afn00_fn01_conf_t conf = { 0 };
conf.wait_duration = PROTO_SPG_DEFAULT_WAIT_TIME;
iot_spg_ctrl_send_uart(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_00, PROTO_SPG_F1,
(uint8_t*)&conf, sizeof(conf), PROTO_SPG_APP_DI2_01,
SPG_NO_USED_ADDR, sn);
}
static void iot_spg_ctrl_set_freq_band_result(uint8_t result)
{
if (!result) {
iot_spg_ctrl_send_00h01_ack(drv_data->sn);
} else {
iot_spg_ctrl_send_00h02_nack(PROTO_SPG_ERR_COMM_TIMEOUT, drv_data->sn);
}
}
static void iot_spg_ctrl_01h_f01(ctrl_spg_frame_pkt_t *frm)
{
iot_spg_ctrl_send_00h01_ack(frm->app_sn);
os_delay(1000);
iot_system_restart(IOT_SYS_RST_REASON_CCTT_REQ);
}
static void iot_spg_ctrl_rpt_data_transfer_handle(uint8_t sn,
uint8_t *data, uint16_t len, uint8_t data_type)
{
spg_afn22_fn01_data_send_ul_t *rsp;
iot_pkt_t *rpt_pkt;
uint16_t rpt_pkt_len;
rpt_pkt_len = len + sizeof(*rsp);
rpt_pkt = iot_pkt_alloc(proto_spg_get_pkt_len(SPG_NO_USED_ADDR,
rpt_pkt_len), IOT_SMART_GRID_MID);
IOT_ASSERT(rpt_pkt);
rsp = (spg_afn22_fn01_data_send_ul_t *)iot_pkt_reserve(rpt_pkt,
proto_spg_get_rsvd_len(SPG_NO_USED_ADDR));
rsp->data_type = data_type;
rsp->data_len = len;
os_mem_cpy(rsp->data, data, len);
proto_645_add33_handle(rsp->data, len);
iot_pkt_put(rpt_pkt, rpt_pkt_len);
iot_spg_ctrl_send_uart_sn(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_22,
PROTO_SPG_F1, rpt_pkt, PROTO_SPG_APP_DI2_05, SPG_NO_USED_ADDR, sn);
}
static uint32_t iot_spg_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)addr;
(void)dev_type;
(void)proto_type;
switch (evt_type) {
case IOT_CTRL_EVENT_DEVICE_CONNECT_CONF:
iot_sg_ctrl_printf("%s connect conf\n", __FUNCTION__);
break;
case IOT_CTRL_EVENT_DEVICE_CONNECT_FAIL:
iot_spg_ctrl_send_00h02_nack(PROTO_SPG_ERR_COMM_TIMEOUT, sn);
break;
case IOT_CTRL_EVENT_DEVICE_CONNECTED:
iot_spg_ctrl_send_00h01_ack(sn);
break;
case IOT_CTRL_EVENT_DEVICE_DISCONNECTED:
iot_sg_ctrl_printf("%s disconnected\n", __FUNCTION__);
break;
case IOT_CTRL_EVENT_CCO_DATA_RPT:
iot_spg_ctrl_rpt_data_transfer_handle(sn, data, len,
PROTO_SPG_CTRL_DATA_TYPE_CCO_CTRL);
break;
case IOT_CTRL_EVENT_PASSTHROUGH_RPT:
iot_spg_ctrl_rpt_data_transfer_handle(sn, data, len,
PROTO_SPG_CTRL_DATA_TYPE_PASSTHROUGH);
break;
default:
iot_sg_ctrl_printf("%s event:%d invalid\n", __FUNCTION__, evt_type);
break;
}
return ERR_OK;
}
static void iot_spg_ctrl_01h_init(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
if (PROTO_SPG_F1 == frm->fn) {
iot_spg_ctrl_01h_f01(frm);
} else {
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
}
iot_pkt_free(pkt);
}
static void iot_spg_ctrl_03h_f01()
{
spg_afn03_fn01_hw_info_ul_t rsp_data;
iot_build_info_t ts_info;
/* hw info */
uint16_t sw_version = (iot_version_packed() & 0xFFFF);
rsp_data.info.vendor_id = iot_sg_ctrl_get_vendor_id();
rsp_data.info.chip_code = iot_sg_ctrl_get_chip_code();
iot_version_get_user_build_info(&ts_info);
rsp_data.info.day = iot_byte_to_bcd(ts_info.day);
rsp_data.info.month = iot_byte_to_bcd(ts_info.month);
rsp_data.info.year = iot_byte_to_bcd(ts_info.year);
rsp_data.info.version[0] = (sw_version & 0xFF);
rsp_data.info.version[1] = (sw_version >> 8);
iot_spg_ctrl_send_uart(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_03, PROTO_SPG_F1,
(const uint8_t *)&rsp_data, sizeof(rsp_data), PROTO_SPG_APP_DI2_00,
SPG_NO_USED_ADDR, drv_data->sn);
}
static void iot_spg_ctrl_03h_read_param(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason;
switch (frm->fn) {
case PROTO_SPG_F1:
iot_spg_ctrl_03h_f01();
break;
case PROTO_SPG_F90:
iot_sg_ctrl_get_freq_band_msg();
break;
default:
reason = PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
iot_pkt_free(pkt);
}
static void iot_spg_ctrl_04h_f90(ctrl_spg_frame_pkt_t *frm)
{
uint8_t reason = PROTO_SPG_ERR_OTHER;
uint32_t result = ERR_FAIL;
spg_set_freq_band_t *app_data =
(spg_set_freq_band_t *)frm->app_data;
uint16_t len = frm->app_data_len;
if (!app_data) {
reason = PROTO_SPG_ERR_INVALID_DATA;
goto out;
}
if (len < sizeof(*app_data)) {
reason = PROTO_SPG_ERR_INVALID_DATA_LEN;
goto out;
}
iot_sg_ctrl_set_freq_band_msg(app_data->freq_band);
result = ERR_OK;
out:
if (ERR_FAIL == result) {
iot_spg_ctrl_send_00h02_nack(reason, frm->app_sn);
}
}
static void iot_spg_ctrl_04h_set_param(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason;
switch (frm->fn) {
case PROTO_SPG_F90:
iot_spg_ctrl_04h_f90(frm);
break;
default:
reason = PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
iot_pkt_free(pkt);
}
uint8_t iot_spg_ctrl_get_proto_data_sn(uint8_t *data, uint16_t data_len,
uint8_t *app_sn)
{
uint8_t result = ERR_FAIL, *spg_hdr;
proto_spg_hdr_t *headr_data = NULL;
proto_spg_addr_field_t *addr_data = NULL;
proto_spg_app_data_t *app_data = NULL;
spg_hdr = proto_spg_sanity_check(data, data_len, &result,
PROTO_SPG_APP_CTRL_DI3);
if (spg_hdr) {
headr_data = (proto_spg_hdr_t*)spg_hdr;
if (headr_data->ctrl_byte.addr) {
addr_data = (proto_spg_addr_field_t*)(spg_hdr +
PROTO_SPG_DATA_OFFSET);
app_data = (proto_spg_app_data_t*)(spg_hdr + PROTO_SPG_DATA_OFFSET +
sizeof(*addr_data));
} else {
app_data = (proto_spg_app_data_t*)(spg_hdr + PROTO_SPG_DATA_OFFSET);
}
*app_sn = app_data->seq;
return ERR_OK;
}
return result;
}
static void iot_sg_ctrl_cco_ctrl_data_send(uint8_t *data, uint16_t data_len,
uint8_t app_sn, iot_pkt_t *pkt)
{
uint8_t reason = PROTO_SPG_ERR_INVALID_DATA;
uint32_t result = ERR_OK;
uint8_t sn;
proto_645_sub33_handle(data, data_len);
if (iot_spg_ctrl_get_proto_data_sn(data, data_len, &sn) != ERR_OK) {
iot_sg_ctrl_data_print("error data", data, data_len);
reason = PROTO_SPG_ERR_INVALID_DATA;
result = ERR_FAIL;
goto out;
}
iot_pkt_set_data(pkt, data);
iot_pkt_set_tail(pkt, data + data_len);
if (iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_MR_CCO, sn, pkt)) {
reason = PROTO_SPG_ERR_OTHER;
result = ERR_FAIL;
}
out:
if (ERR_OK != result) {
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, app_sn);
iot_pkt_free(pkt);
}
}
static void iot_sg_ctrl_passthrough_data_send(uint8_t *data, uint16_t data_len,
uint8_t app_sn, iot_pkt_t *pkt)
{
uint8_t reason = PROTO_SPG_ERR_INVALID_DATA;
uint8_t sn = 0;
uint32_t result = ERR_OK;
proto_645_sub33_handle(data, data_len);
switch (iot_sg_ctrl_get_connect_role()) {
case IOT_PLC_DEV_ROLE_CCO:
{
if (iot_spg_ctrl_get_proto_data_sn(data, data_len, &sn) != ERR_OK) {
reason = PROTO_SPG_ERR_INVALID_DATA;
result = ERR_FAIL;
goto out;
}
break;
}
case IOT_PLC_DEV_ROLE_STA:
case IOT_PLC_DEV_ROLE_PCO:
{
if (iot_sg_ctrl_get_sta_passthrough_state()) {
reason = PROTO_SPG_ERR_MASTER_IS_BUSY;
result = ERR_FAIL;
goto out;
}
if (proto_645_format_check(data, data_len, PROTO_645_DIR_MASTER)
== NULL) {
reason = PROTO_SPG_ERR_INVALID_DATA;
result = ERR_FAIL;
goto out;
}
break;
}
default:
reason = PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
result = ERR_FAIL;
goto out;
}
iot_pkt_set_data(pkt, data);
iot_pkt_set_tail(pkt, data + data_len);
if (sn) {
result = iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_PASSTHROUGH, sn,
pkt);
} else {
result = iot_sg_ctrl_send_data(PROTO_CTRL_CMD_TYPE_PASSTHROUGH,
IOT_CTRL_PASSTHROUGH_SN, pkt);
}
if (result != ERR_OK) {
reason = PROTO_SPG_ERR_INVALID_DATA;
}
out:
if (ERR_OK != result) {
iot_sg_ctrl_data_print("error data", data, data_len);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, app_sn);
iot_pkt_free(pkt);
}
}
static void iot_sg_ctrl_data_send_handle(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
uint8_t consumed = 0;
spg_afn22_fn01_data_send_dl_t *req;
req = (spg_afn22_fn01_data_send_dl_t *)frm->app_data;
switch (req->data_type) {
case PROTO_SPG_CTRL_DATA_TYPE_CCO_CTRL:
{
iot_sg_ctrl_cco_ctrl_data_send(req->data, req->data_len, frm->app_sn,
pkt);
consumed = 1;
break;
}
case PROTO_SPG_CTRL_DATA_TYPE_PASSTHROUGH:
{
iot_sg_ctrl_passthrough_data_send(req->data, req->data_len, frm->app_sn,
pkt);
consumed = 1;
break;
}
default:
iot_sg_ctrl_printf("%s:data type error,reason is %lu, data type is %lu",
__FUNCTION__, reason, req->data_type);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
if (!consumed) {
iot_pkt_free(pkt);
}
}
static void iot_spg_ctrl_22h_data_send(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
uint8_t consumed = 0;
switch (frm->fn) {
case PROTO_SPG_F1:
{
iot_sg_ctrl_data_send_handle(frm, pkt);
consumed = 1;
break;
}
default:
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
if (!consumed) {
iot_pkt_free(pkt);
}
}
static void iot_spg_ctrl_41h_f01(ctrl_spg_frame_pkt_t *frm)
{
uint8_t cnt;
uint8_t i;
uint16_t rsp_len;
spg_afn41_fn01_rpt_node_info_ul *rsp_data = NULL;
ctrl_node_info_t *node_info = NULL;
iot_pkt_t *tmp_pkt;
iot_pkt_t *tmp2_pkt = NULL;
cnt = iot_sg_ctrl_get_scan_node_cnt();
if (cnt > IOT_CTRL_SCAN_NODE_MAX_CNT) {
iot_sg_ctrl_printf("WARNING: %s scan count: %d exceed \n", cnt);
cnt = IOT_CTRL_SCAN_NODE_MAX_CNT;
} else if (!cnt) {
goto out;
}
tmp2_pkt = iot_pkt_alloc(cnt * sizeof(ctrl_node_info_t),
IOT_SMART_GRID_MID);
IOT_ASSERT(tmp2_pkt);
node_info = (ctrl_node_info_t *)iot_pkt_data(tmp2_pkt);
cnt = iot_sg_ctrl_get_scan_node_info(node_info, 1, cnt);
out:
rsp_len = sizeof(*rsp_data) + cnt * sizeof(spg_ctrl_node_info_t);
tmp_pkt = iot_pkt_alloc(proto_spg_get_pkt_len(SPG_NO_USED_ADDR,
rsp_len), IOT_SMART_GRID_MID);
IOT_ASSERT(tmp_pkt);
rsp_data = (spg_afn41_fn01_rpt_node_info_ul*)iot_pkt_reserve(tmp_pkt,
proto_spg_get_rsvd_len(SPG_NO_USED_ADDR));
rsp_data->total_cnt = cnt;
for (i = 0; i < cnt; i++, node_info++) {
rsp_data->node_info[i].nid = node_info->nid;
rsp_data->node_info[i].band_id = node_info->band_id;
iot_mac_addr_cpy(rsp_data->node_info[i].addr, node_info->addr);
}
if (tmp2_pkt) {
iot_pkt_free(tmp2_pkt);
}
iot_pkt_put(tmp_pkt, rsp_len);
iot_spg_ctrl_send_uart_sn(PROTO_SPG_PRM_SLAVE, PROTO_SPG_AFN_41,
PROTO_SPG_F1, tmp_pkt, PROTO_SPG_APP_DI2_00, SPG_NO_USED_ADDR,
frm->app_sn);
}
static void iot_spg_ctrl_41h_f02(ctrl_spg_frame_pkt_t *frm)
{
uint32_t reason = PROTO_SPG_ERR_INVALID_DATA;
uint32_t result = ERR_OK;
spg_afn41_fn02_req_connect_node_dl_t *req =
(spg_afn41_fn02_req_connect_node_dl_t *)frm->app_data;
uint16_t len = frm->app_data_len;
if (len < sizeof(spg_afn41_fn02_req_connect_node_dl_t)) {
/* invalid data length */
reason = PROTO_SPG_ERR_INVALID_DATA_LEN;
result = ERR_FAIL;
goto out;
}
if (ERR_OK != iot_sg_ctrl_proto_connect_from_scan_node(req->addr,
frm->app_sn)) {
reason = PROTO_SPG_ERR_INVALID_DATA;
result = ERR_FAIL;
}
out:
if (ERR_OK != result) {
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
}
}
static void iot_spg_ctrl_41h_scan_node_mgr(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
switch (frm->fn) {
case PROTO_SPG_F1:
{
iot_spg_ctrl_41h_f01(frm);
break;
}
case PROTO_SPG_F2:
{
iot_spg_ctrl_41h_f02(frm);
break;
}
default:
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
iot_pkt_free(pkt);
}
static void iot_spg_ctrl_f0h_f01(ctrl_spg_frame_pkt_t *frm)
{
spg_afnf0_fn01_req_connect_node_dl_t *cmd = NULL;
uint32_t result = ERR_OK;
uint8_t reason = PROTO_SPG_ERR_INVALID_DATA;
cmd = (spg_afnf0_fn01_req_connect_node_dl_t*)frm->app_data;
uint16_t len = frm->app_data_len;
if (len < sizeof(spg_afnf0_fn01_req_connect_node_dl_t)) {
reason = PROTO_SPG_ERR_INVALID_DATA_LEN;
result = ERR_FAIL;
goto out;
}
if (ERR_OK != iot_sg_ctrl_proto_connect(cmd->addr,
(uint8_t)frm->app_sn)) {
reason = PROTO_SPG_ERR_INVALID_DATA;
result = ERR_FAIL;
}
out:
if (ERR_OK != result) {
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
}
}
static void iot_spg_ctrl_f0h_f02(ctrl_spg_frame_pkt_t *frm)
{
iot_sg_ctrl_reset_connet_status();
iot_spg_ctrl_send_00h01_ack(frm->app_sn);
}
static void iot_spg_ctrl_f0h_cmd(ctrl_spg_frame_pkt_t *frm, iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
uint8_t consumed = 0;
switch (frm->fn) {
case PROTO_SPG_F1:
{
iot_spg_ctrl_f0h_f01(frm);
break;
}
case PROTO_SPG_F2:
{
iot_spg_ctrl_f0h_f02(frm);
break;
}
default:
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : 0x%02X,"
"fn : 0x%02X\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
break;
}
if (!consumed) {
iot_pkt_free(pkt);
}
}
static void iot_spg_ctrl_send_data_handle(ctrl_spg_frame_pkt_t *frm,
iot_pkt_t *pkt)
{
uint32_t reason= PROTO_SPG_ERR_MASTER_UNSUPPORTED_CMD;
uint32_t result = ERR_OK;
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_SPG_AFN_01:
{
iot_spg_ctrl_01h_init(frm, pkt);
break;
}
case PROTO_SPG_AFN_03:
{
iot_spg_ctrl_03h_read_param(frm, pkt);
break;
}
case PROTO_SPG_AFN_04:
{
iot_spg_ctrl_04h_set_param(frm, pkt);
break;
}
case PROTO_SPG_AFN_22:
{
iot_spg_ctrl_22h_data_send(frm, pkt);
break;
}
case PROTO_SPG_AFN_41:
{
iot_spg_ctrl_41h_scan_node_mgr(frm, pkt);
break;
}
case PROTO_SPG_AFN_F0:
{
iot_spg_ctrl_f0h_cmd(frm, pkt);
break;
}
default:
result = ERR_FAIL;
break;
}
if (ERR_OK != result) {
iot_sg_ctrl_printf("%s:data_handle error,reason is %lu,afn : %x,"
"fn : %x\n", __FUNCTION__, reason, frm->afn, frm->fn);
iot_spg_ctrl_send_00h02_nack((uint8_t)reason, frm->app_sn);
iot_pkt_free(pkt);
}
}
/**
* @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_spg_ctrl_uart_data_recv_handle(iot_pkt_t *pkt)
{
uint8_t *spg_hdr;
uint16_t len = (uint16_t)iot_pkt_data_len(pkt);
proto_spg_hdr_t *headr_data = NULL;
proto_spg_addr_field_t *addr_data = NULL;
proto_spg_app_data_t *app_data = NULL;
ctrl_spg_frame_pkt_t spg_cmd;
uint32_t result = ERR_OK;
if(len < sizeof(proto_spg_hdr_t)){
goto err;
}
spg_hdr = proto_spg_sanity_check(iot_pkt_data(pkt), len,
(uint8_t *)&result, PROTO_SPG_APP_CTRL_DI3);
if (!spg_hdr) {
goto err;
}
headr_data = (proto_spg_hdr_t*)spg_hdr;
if (headr_data->ctrl_byte.addr) {
addr_data = (proto_spg_addr_field_t*)(spg_hdr + PROTO_SPG_DATA_OFFSET);
app_data = (proto_spg_app_data_t*)(spg_hdr + PROTO_SPG_DATA_OFFSET +
sizeof(*addr_data));
/* record mac msg */
os_mem_cpy(drv_data->dest_mac, addr_data->dest_mac,
PROTO_SPG_MAC_ADDR_LEN);
os_mem_cpy(drv_data->req_mac, addr_data->src_mac,
PROTO_SPG_MAC_ADDR_LEN);
/* offset address length */
headr_data->len -= PROTO_SPG_MAC_ADDR_LEN;
headr_data->len -= PROTO_SPG_MAC_ADDR_LEN;
} else {
os_mem_set(drv_data->dest_mac, 0, PROTO_SPG_MAC_ADDR_LEN);
os_mem_set(drv_data->req_mac, 0, PROTO_SPG_MAC_ADDR_LEN);
app_data = (proto_spg_app_data_t*)(spg_hdr + PROTO_SPG_DATA_OFFSET);
}
/* check di data */
if ((app_data->di[3] != PROTO_SPG_APP_CTRL_DI3) ||
(app_data->di[1] != app_data->afn)) {
goto err;
}
/* record seq msg */
drv_data->sn = app_data->seq;
spg_cmd.app_sn = app_data->seq;
spg_cmd.afn = app_data->afn;
spg_cmd.fn = app_data->di[0];
spg_cmd.app_data_len = headr_data->len - PROTO_SPG_FIX_FIELD_LEN -
sizeof(proto_spg_app_data_t);
if (!spg_cmd.app_data_len) {
spg_cmd.app_data = NULL;
} else {
spg_cmd.app_data = app_data->data;
}
iot_spg_ctrl_send_data_handle(&spg_cmd, pkt);
goto out;
err:
iot_pkt_free(pkt);
result = ERR_FAIL;
out:
return result;
}
static uint32_t iot_spg_ctrl_check_data_handle(iot_pkt_t *pkt)
{
uint8_t *spg_hdr;
uint16_t len = (uint16_t)iot_pkt_data_len(pkt);
uint8_t ctrl = 0;
uint32_t result = ERR_FAIL;
if(len < sizeof(proto_spg_hdr_t)){
return result;
}
spg_hdr = proto_spg_sanity_check(iot_pkt_data(pkt), len,
(uint8_t *)&result, PROTO_SPG_APP_CTRL_DI3);
if (!spg_hdr) {
return result;
}
ctrl = spg_hdr[PROTO_SPG_CTRL_OFFSET];
if ((ctrl & 0x07) == PROTO_CTRL_COMMUNICAT_RSVD) {
result = ERR_OK;
}
return result;
}
iot_ctrl_drv_t g_spg_ctrl_drv = {
.drv_id = IOT_CTRL_DRV_ID_SPG,
.init = iot_spg_ctrl_drv_init,
.deinit = iot_spg_ctrl_drv_deinit,
.event_report_handle = iot_spg_ctrl_event_report_handle,
.ctrl_drv_data_handle = iot_spg_ctrl_uart_data_recv_handle,
.check_data_handle = iot_spg_ctrl_check_data_handle,
.freq_band_report_cb = iot_spg_ctrl_freq_band_handler,
.freq_band_set_result_cb = iot_spg_ctrl_set_freq_band_result,
};
#endif /* IOT_SG_CONTROLLER_ENABLE */