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;
 | 
						|
}
 | 
						|
 |