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

353 lines
9.0 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_pkt_api.h"
#include "iot_errno_api.h"
#include "iot_bitops_api.h"
#include "iot_bitmap_api.h"
#include "iot_module_api.h"
#include "iot_uart_api.h"
/* proto includes */
#include "proto_3761.h"
static uint32_t proto_3761_baud_tab[] = { 300, 600, 1200, 2400, 4800, 7200,
9600, 19200};
static uint8_t seq = PROTO_3761_SN_MAX;
static uint8_t proto_3761_to_baud_id(uint32_t baud)
{
uint8_t i;
for (i = 0; i < IOT_ARRAY_CNT(proto_3761_baud_tab); i++) {
if (proto_3761_baud_tab[i] == baud)
break;
}
return i;
}
uint8_t proto_3761_is_bcast_addr(proto_3761_addr_t *addr)
{
if (addr->is_group && addr->dev_addr == PROTO_3761_BCAST_DEV_ADRR)
return 1;
return 0;
}
static void proto_3761_fill_pn(uint8_t *buf, uint16_t pn)
{
if (pn == PROTO_3761_PN_0) {
buf[0] = buf[1] = 0;
} else if (pn == PROTO_3761_PN_ALL) {
buf[0] = 0xFF;
buf[1] = 0x00;
} else {
IOT_ASSERT(pn <= PROTO_3761_PN_MAX);
buf[0] |= (1 << ((pn - 1) & 0x7));
buf[1] = (uint8_t)((pn - 1) / 8 + 1);
}
}
static uint16_t proto_3761_calc_pn(uint8_t *buf, uint16_t *pn)
{
uint16_t temp;
if (buf[0] == 0xFF && buf[1] == 0x0) {
temp = PROTO_3761_PN_ALL;
} else if (buf[0] == 0x00 && buf[1] == 0x00) {
temp = PROTO_3761_PN_0;
} else if (iot_bitops_ffs(buf[0])) {
temp = (buf[1] - 1) * 8 + iot_bitops_ffs(buf[0]);
} else {
return ERR_FAIL;
}
*pn = temp;
return ERR_OK;
}
static void proto_3761_fill_fn(uint8_t *buf, uint16_t fn)
{
IOT_ASSERT(fn);
buf[0] |= (1 << (fn - 1) % 8);
buf[1] = (uint8_t)((fn - 1) / 8);
}
uint16_t proto_3761_calc_fn(uint8_t *buf, uint16_t *fn)
{
uint16_t temp;
if (iot_bitops_ffs(buf[0])) {
temp = buf[1] * 8 + iot_bitops_ffs(buf[0]);
} else {
return ERR_FAIL;
}
*fn = temp;
return ERR_OK;
}
void proto_3761_fill_addr(proto_3761_addr_t *addr, uint8_t msa,
uint16_t dev_addr, uint16_t area_code)
{
iot_uint32_to_bcd(area_code,
PROTO_3761_AREA_CODE_LEN,
addr->area_code);
addr->dev_addr = dev_addr;
if (dev_addr == PROTO_3761_BCAST_DEV_ADRR)
addr->is_group = 1;
else
addr->is_group = 0;
addr->msa = msa;
}
uint8_t proto_3761_calc_cs(proto_3761_hdr_t *hdr)
{
uint16_t i;
uint8_t sum = 0;
for (i = 0; i < hdr->len1; i++) {
sum += hdr->data[i];
}
return sum;
}
iot_pkt_t *proto_3761_build_afn10f01_dl_msg(uint8_t *ds,
uint16_t len, uint32_t baud, uint8_t port,
uint8_t parity, uint8_t timeout, module_id_t mid,
uint16_t *dev_addr, uint16_t *area_code, uint8_t sn)
{
uint16_t des_area_code = 9999;
uint16_t temp = 0, des_dev_addr = PROTO_3761_BCAST_DEV_ADRR;
uint8_t b_id, *data;
iot_pkt_t *pkt;
proto_3761_hdr_t *hdr;
proto_3761_user_data_t *user_data;
proto_3761_app_hdr_t *app_hdr;
proto_3761_data_uint_t *du;
proto_3761_afn10f1_dl_t *dl;
proto_3761_tail_t *tail;
pkt = iot_pkt_alloc(sizeof(*hdr) + sizeof(*user_data)
+ sizeof(*app_hdr) + sizeof(*du) + sizeof(*dl) + len
+ sizeof(*tail), mid);
if (!pkt)
goto out;
data = iot_pkt_data(pkt);
hdr = (proto_3761_hdr_t *)data;
hdr->start_char1 = PROTO_3761_START_CHAR;
hdr->start_char2 = PROTO_3761_START_CHAR;
/* for 1376.1 protocol, this field is fixed to 2 */
hdr->proto_code1 = 0x2;
hdr->proto_code2 = 0x2;
hdr->len1 = 0;
hdr->len2 = 0;
data += sizeof(*hdr);
iot_pkt_put(pkt, sizeof(*hdr));
user_data = (proto_3761_user_data_t *)data;
user_data->ctrl.dir = PROTO_3761_DIR_MASTER;
user_data->ctrl.prm = 1;
user_data->ctrl.fn = PROTO_3761_FN_P_REQ_CLASS1_DATA;
user_data->ctrl.fcv = 0;
user_data->ctrl.fcb_acd = 0;
if (dev_addr) {
des_dev_addr = *dev_addr;
}
if (area_code) {
des_area_code = *area_code;
}
proto_3761_fill_addr(&user_data->addr_filed, 1,
des_dev_addr, des_area_code);
temp += sizeof(*user_data);
data += sizeof(*user_data);
app_hdr = (proto_3761_app_hdr_t *)data;
app_hdr->afn = PROTO_3761_AFN_10;
app_hdr->fin = 1;
app_hdr->fir = 1;
app_hdr->tpv = 0;
app_hdr->seq = sn & 0xF;
app_hdr->con = 1;
temp += sizeof(*app_hdr);
data += sizeof(*app_hdr);
du = (proto_3761_data_uint_t *)data;
proto_3761_fill_pn(du->pn, PROTO_3761_PN_0);
proto_3761_fill_fn(du->fn, 1);
temp += sizeof(*du);
data += sizeof(*du);
dl = (proto_3761_afn10f1_dl_t *)data;
dl->port = port;
dl->stop_bit_num = PROTO_3761_UART_STOP_1_BIT;
dl->data_bit_num = PROTO_3761_UART_DATA_8_BIT;
if (parity == IOT_UART_PARITY_EVEN || parity == IOT_UART_PARITY_ODD) {
dl->parity_valid = 1;
dl->parity = (parity == IOT_UART_PARITY_ODD);
}
b_id = proto_3761_to_baud_id(baud);
if (b_id == PROTO_3761_UART_BAUD_ID_MAX)
b_id = PROTO_3761_UART_BAUD_ID_2400;
dl->buad_id = b_id;
dl->uint_is_sec = 1;
dl->timeout1 = timeout;
dl->timeout2 = 30;
data += sizeof(*dl);
temp += sizeof(*dl);
dl->len = len;
os_mem_cpy(dl->data, ds, len);
data += len;
temp += len;
/* fill in the pass word. At present, fill in all 0 */
os_mem_set(data, 0x0, PROTO_3761_PW_LEN);
data += PROTO_3761_PW_LEN;
temp += PROTO_3761_PW_LEN;
hdr->len1 = hdr->len2 = temp;
tail = (proto_3761_tail_t *)data;
tail->cs = proto_3761_calc_cs(hdr);
tail->end_char = PROTO_3761_END_CHAR;
iot_pkt_put(pkt, hdr->len1 + sizeof(*tail));
out:
return pkt;
}
uint32_t proto_3761_sanity_check(uint8_t **data, uint16_t *len)
{
proto_3761_hdr_t *hdr;
proto_3761_tail_t *tail;
uint16_t i, len_t = *len;
uint8_t *ds = *data;
for (i = 0x0; i < *len; i++) {
if (ds[0] == PROTO_3761_START_CHAR) {
break;
}
ds++;
len_t--;
}
if (len_t < sizeof(*hdr)) {
goto err;
}
hdr = (proto_3761_hdr_t *)ds;
if (hdr->start_char2 != PROTO_3761_START_CHAR) {
goto err;
}
if (hdr->proto_code1 != 0x2
|| hdr->proto_code1 != 0x2) {
goto err;
}
if (hdr->len1 != hdr->len2) {
goto err;
}
len_t -= sizeof(*hdr);
ds += sizeof(*hdr);
if (len_t < sizeof(*tail) + hdr->len1) {
goto err;
}
*len = hdr->len1;
*data = ds;
ds += hdr->len1;
tail = (proto_3761_tail_t *)ds;
if (tail->cs != proto_3761_calc_cs(hdr)) {
goto err;
}
if (tail->end_char != PROTO_3761_END_CHAR) {
goto err;
}
return ERR_OK;
err:
return ERR_FAIL;
}
uint32_t proto_3761_parse(uint8_t *data, uint16_t len,
proto_3761_app_data_desc_t *app_desc)
{
proto_3761_app_hdr_t *hdr;
proto_3761_user_data_t *user_data;
uint32_t ret;
ret = proto_3761_sanity_check(&data, &len);
if (ret) {
goto err;
}
if (len < sizeof(*user_data)) {
goto err;
}
user_data = (proto_3761_user_data_t *)data;
len -= sizeof(*user_data);
data += sizeof(*user_data);
if (len < sizeof(*hdr)) {
goto err;
}
hdr = (proto_3761_app_hdr_t *)data;
data += sizeof(*hdr);
len -= sizeof(*hdr);
app_desc->addr_filed = user_data->addr_filed;
app_desc->dir = user_data->ctrl.dir;
app_desc->prm = user_data->ctrl.prm;
app_desc->afn = hdr->afn;
app_desc->seq = hdr->seq;
app_desc->data = data;
app_desc->len = len;
return ERR_OK;
err:
return ERR_FAIL;
}
uint32_t proto_3761_du_parse(uint16_t *pn, uint16_t *fn, uint8_t **data,
uint16_t *len)
{
proto_3761_data_uint_t *du;
uint8_t *ds = *data;
uint32_t ret;
if (*len < sizeof(*du)) {
goto err;
}
du = (proto_3761_data_uint_t *)ds;
*len -= sizeof(*du);
ds += sizeof(*du);
ret = proto_3761_calc_pn(du->pn, pn);
if (ret) {
goto err;
}
ret = proto_3761_calc_fn(du->fn, fn);
if (ret) {
goto err;
}
*data = ds;
return ERR_OK;
err:
return ERR_FAIL;
}
uint8_t proto_3761_get_sn(void)
{
/* range: 0 - 15 */
seq++;
if (seq > PROTO_3761_SN_MAX) {
seq = 0;
}
return seq;
}