Files
kunlun/app/smart_grid/protocol/proto_mwc.c
2024-09-28 14:24:04 +08:00

195 lines
6.9 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 shim includes */
#include "os_types_api.h"
#include "os_mem_api.h"
/* common includes */
#include "iot_utils_api.h"
#include "iot_errno_api.h"
#include "iot_crc_api.h"
#include "iot_rtc_api.h"
/* protocol includes */
#include "proto_mwc.h"
/* sequence number for dl raw read low meter commands sent out */
static uint8_t psdu_sn = 0;
/*
* @brief: get sn for dl raw read low power meter.
* @return: psdu dl sn, it ranges from 1 to 255.
*/
static uint8_t proto_mwc_get_psdu_dl_sn()
{
psdu_sn++;
if (psdu_sn == 0) {
psdu_sn = 1;
}
return psdu_sn;
}
/**
* @brief: convert hplc net snid to mwc proto channel index.
* @param plc_nid: hplc net snid.
* @param return: channel index.
*/
static uint8_t proto_mwc_convert_channel_id(uint32_t plc_nid)
{
// nid is the result of plc_nid mod 32, it ranges from 1 to 32.
uint8_t nid = (plc_nid & 0x1F) + 1;
return nid;
}
/**
* @brief: get real time.
* @param real_time: year, BIN format.
*/
static void proto_mwc_get_real_time(proto_mwc_real_time_t *real_time)
{
uint8_t real_week;
iot_time_tm_t tm;
iot_rtc_get(&tm);
real_week = iot_calc_week(tm.tm_year, tm.tm_mon, tm.tm_mday);
real_time->sec = iot_byte_to_bcd(tm.tm_sec);
real_time->min = iot_byte_to_bcd(tm.tm_min);
real_time->hour = iot_byte_to_bcd(tm.tm_hour);
real_time->week = iot_byte_to_bcd(real_week);
real_time->day = iot_byte_to_bcd(tm.tm_mday);
real_time->month = iot_byte_to_bcd(tm.tm_mon);
real_time->year = iot_byte_to_bcd(tm.tm_year % 100);
}
uint32_t proto_mwc_handle_raw_mr_lp_meter(uint8_t *mr_data, uint8_t *data,
uint16_t data_len, uint32_t plc_nid, uint8_t *lp_meter_mac,
uint8_t *dau_mac)
{
uint16_t len;
uint16_t crc_itu = 0;
proto_mwc_phy_phr_t *phr = (proto_mwc_phy_phr_t *)mr_data;
proto_mwc_psdu_header_t *psdu_head = NULL;
proto_mwc_psdu_clct_raw_t *psdu_data = NULL;
proto_mwc_phy_phr_tail_t *phr_tail = NULL;
len = PROTO_MWC_RAW_MR_FRAME_LEN + data_len -
sizeof(phr->data_len) - sizeof(crc_itu);
if (len > 0xFF) {
return ERR_FAIL;
}
phr->data_len = (uint8_t)len;
phr->channel_idx = proto_mwc_convert_channel_id(plc_nid) * 2;
phr->proto_ver = PROTO_MWC_PHR_PROTO_VER;
phr->phr_cs = (phr->data_len ^ phr->channel_idx) ^ phr->proto_ver;
psdu_head = (proto_mwc_psdu_header_t *)phr->data;
psdu_head->control = PROTO_MWC_PSDU_CTRL_FIELD;
psdu_head->sn = proto_mwc_get_psdu_dl_sn();
psdu_head->panid = PROTO_MWC_PSDU_PANID_DEFAULT;
os_mem_cpy(psdu_head->dest_addr, lp_meter_mac, PROTO_MWC_PSDU_ADDR_LEN);
os_mem_set(psdu_head->source_addr, 0, PROTO_MWC_PSDU_ADDR_LEN);
os_mem_cpy(psdu_head->source_addr, dau_mac, PROTO_MWC_ADDR_LEN);
psdu_head->payload.cmd_type = PROTO_MWC_PSDU_CMD_CLCT_RAW;
psdu_data = (proto_mwc_psdu_clct_raw_t *)psdu_head->payload.data;
psdu_data->baud_rate = 0;
psdu_data->timeout = 0;
psdu_data->data_len = (uint8_t)data_len;
os_mem_cpy(psdu_data->data, data, data_len);
phr_tail = (proto_mwc_phy_phr_tail_t *)(psdu_data->data + data_len);
crc_itu = iot_getcrc16(mr_data, phr->data_len + sizeof(phr->data_len),
IOT_CRC16_TYPE_X25);
phr_tail->crc = crc_itu;
return ERR_OK;
}
void proto_mwc_handle_cfg_lp_meter(uint8_t *cfg_data, uint32_t plc_nid,
uint16_t slot_id, uint16_t panid, uint8_t *lp_meter_mac, uint8_t *dau_mac)
{
uint8_t len = PROTO_MWC_CFG_LP_METER_LEN;
uint16_t crc_itu = 0;
proto_mwc_phy_phr_t *phr = (proto_mwc_phy_phr_t *)cfg_data;
proto_mwc_psdu_header_t *psdu_head = NULL;
proto_mwc_psdu_cfg_lp_meter_t *psdu_data = NULL;
proto_mwc_phy_phr_tail_t *phr_tail = NULL;
phr->data_len = len - sizeof(phr->data_len) - sizeof(crc_itu);
phr->channel_idx = PROTO_MWC_PSDU_CHANNEL_DEFAULT;
phr->proto_ver = PROTO_MWC_PHR_PROTO_VER;
phr->phr_cs = (phr->data_len ^ phr->channel_idx) ^ phr->proto_ver;
psdu_head = (proto_mwc_psdu_header_t *)phr->data;
psdu_head->control = PROTO_MWC_PSDU_CTRL_FIELD;
psdu_head->sn = proto_mwc_get_psdu_dl_sn();
psdu_head->panid = PROTO_MWC_PSDU_PANID_DEFAULT;
os_mem_cpy(psdu_head->dest_addr, lp_meter_mac, PROTO_MWC_PSDU_ADDR_LEN);
os_mem_set(psdu_head->source_addr, 0, PROTO_MWC_PSDU_ADDR_LEN);
os_mem_cpy(psdu_head->source_addr, dau_mac, PROTO_MWC_ADDR_LEN);
psdu_head->payload.cmd_type = PROTO_MWC_PSDU_CMD_CONFIG_LP_METER;
psdu_data = (proto_mwc_psdu_cfg_lp_meter_t *)psdu_head->payload.data;
psdu_data->channel_group = proto_mwc_convert_channel_id(plc_nid);
os_mem_cpy(psdu_data->dau_mac, dau_mac, PROTO_MWC_ADDR_LEN);
psdu_data->panid = panid;
psdu_data->slot_time = slot_id;
proto_mwc_get_real_time(&psdu_data->real_time);
psdu_data->work_mode = PROTO_MWC_PSDU_WORK_MODE_VALID;
psdu_data->work_time = PROTO_MWC_PSDU_WORK_TIME_DEFAULT;
phr_tail = (proto_mwc_phy_phr_tail_t *)(psdu_data + 1);
crc_itu = iot_getcrc16(cfg_data, len - sizeof(crc_itu), IOT_CRC16_TYPE_X25);
phr_tail->crc = crc_itu;
}
proto_mwc_psdu_data_t *proto_mwc_get_psdu_data(uint8_t *cfg_ack_data,
uint32_t len)
{
proto_mwc_psdu_data_t *psdu_data;
proto_mwc_psdu_lp_meter_ack_t *mr_ack;
proto_mwc_psdu_cfg_ack_t *cfg_ack;
if (len < sizeof(proto_mwc_phy_phr_t) + sizeof(proto_mwc_psdu_header_t)) {
return NULL;
}
len = len - sizeof(proto_mwc_phy_phr_t) - sizeof(proto_mwc_psdu_header_t);
psdu_data = (proto_mwc_psdu_data_t *)(cfg_ack_data +
sizeof(proto_mwc_phy_phr_t) + sizeof(proto_mwc_psdu_header_t) -
sizeof(proto_mwc_psdu_data_t));
switch (psdu_data->cmd_type) {
case PROTO_MWC_PSDU_CMD_LP_METER_ACK:
{
mr_ack = (proto_mwc_psdu_lp_meter_ack_t *)psdu_data->data;
if (len < sizeof(*mr_ack) + mr_ack->data_len) {
return NULL;
}
break;
}
case PROTO_MWC_PSDU_CMD_CONFIG_ACK:
{
cfg_ack = (proto_mwc_psdu_cfg_ack_t *)psdu_data->data;
if (len < sizeof(*cfg_ack)) {
return NULL;
}
break;
}
default:
return NULL;
}
return psdu_data;
}