195 lines
6.9 KiB
C
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;
|
|
} |