353 lines
9.0 KiB
C
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;
|
|
}
|
|
|