Files
kunlun/app/iot_micro_cctt_app/cctt/iot_cctt_utils.c

629 lines
18 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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.
****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "os_lock_api.h"
#include "os_timer_api.h"
#include "os_utils_api.h"
#include "iot_io_api.h"
#include "iot_rtc_api.h"
#include "iot_oem_api.h"
#include "iot_plc_api.h"
#include "iot_pkt_api.h"
#include "iot_task_api.h"
#include "iot_task_api.h"
#include "iot_errno_api.h"
#include "iot_utils_api.h"
#include "iot_cctt_utils.h"
#include "iot_plc_msg_api.h"
#include "iot_cctt_comm_module.h"
#include "iot_cctt_config.h"
#include "iot_system_api.h"
#include "driver/iot_gpio.h"
#include "iot_board_api.h"
#if (IOT_APP_SELECTION == IOT_APP_DEF_22_GE_MICRO_CCTT)
#include "iot_proto_ge.h"
#include "iot_proto_common.h"
#endif // end of #if (IOT_APP_SELECTION == IOT_APP_DEF_22_GE_MICRO_CCTT)
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
#define IOT_CCTT_INVALID_GPIO (0xFF)
#define IOT_CCTT_INTERNAL_GPIO(n) (n)
#define IOT_CCTT_KL1_EXT_GPIO(n) (iot_gpio_get_inner_gpio_num() + (n))
/* iot concentrator module, version 3.0 */
#ifndef HW_VERSION_IOT_CCTT_V3_0
#define HW_VERSION_IOT_CCTT_V3_0 0x720A0100 //114.10.01.00
#endif
/* iot concentrator module, version 3.5 */
#ifndef HW_VERSION_IOT_CCTT_V3_5
#define HW_VERSION_IOT_CCTT_V3_5 0x760A0100 //118.10.01.00
#endif
/* CRC table for the CRC-16. */
/* The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
static const uint16_t iot_crc16_tab[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
/**
* @brief : calc crc16 with poly 0x8005, init 0xFFFF, xorout=0x0000
*
* @param data: data to calc
* @param len : length of data
* @return crc16 checksum
*/
static uint16_t iot_cctt_utils_calc_crc16(uint8_t *data, uint32_t len)
{
register uint16_t crc = 0xFFFF;
if((NULL == data) || (len == 0)) {
return 0;
}
while (len--) {
crc = (crc>>8) ^ iot_crc16_tab[(crc ^ *data++) & 0xff];
}
return crc;
}
/**
* @brief : get cctt ethernet mac address
* try to use mac address of cco firstly, if failed, use random mac
*
* @param p_mac : buffer to store mac address
* @return none
*/
void iot_cctt_utils_get_eth_mac(uint8_t *p_mac)
{
if (NULL == p_mac) {
return;
}
iot_oem_get_module_mac(p_mac);
p_mac[0] &= 0xFE; // to avoid to use multicast mac address
iot_cctt_utils_dump_bin("[cctt utils]eth mac", p_mac, IOT_MAC_ADDR_LEN);
}
/**
* @brief : query cctt plc mac address
*
* @param p_mac : buffer to store mac address
* @return ERR_OK if success, error code otherwise
*/
uint8_t iot_cctt_utils_get_cctt_mac(uint8_t *p_mac)
{
uint8_t ret = ERR_FAIL;
if (NULL != p_mac) {
iot_cctt_cfg_get_nv_cctt_mac(p_mac);
ret = ERR_OK;
}
return ret;
}
/**
* @brief : set cctt plc mac address
*
* @param p_mac : buffer to store mac address
* @return ERR_OK if success, error code otherwise
*/
uint8_t iot_cctt_utils_set_cctt_mac(uint8_t *p_mac)
{
uint8_t ret = ERR_OK;
/* save cctt mac to customer part, avoid mac changed after fw update */
iot_cctt_cfg_set_cctt_mac(p_mac);
return ret;
}
/**
* @brief : build login frame
*
* @param p_buff : buffer to store login frame
* @param len : length of p_frame
* @return ERR_OK if success, error code otherwise
*/
uint8_t iot_cctt_utils_build_dbg_svr_login_frm(uint8_t appid,
uint8_t *p_buff,
uint32_t len)
{
iot_cctt_tools_login_frame_t *p_login_frame;
uint8_t mac_address[IOT_MAC_ADDR_LEN];
uint16_t crc16;
p_login_frame = (iot_cctt_tools_login_frame_t*)p_buff;
if ((NULL == p_buff) || (len < sizeof(iot_cctt_tools_login_frame_t))) {
return ERR_INVAL;
}
iot_cctt_utils_get_cctt_mac(mac_address);
p_login_frame->preamble = 0xAAAA;
p_login_frame->cctt_id[0] = mac_address[0];
p_login_frame->cctt_id[1] = (mac_address[1] & 0xF0) | (mac_address[3]&0x0F);
p_login_frame->cctt_id[2] = mac_address[4];
p_login_frame->cctt_id[3] = mac_address[5];
p_login_frame->app_id = appid;
p_login_frame->fn = 0x44;
p_login_frame->sub_fn = 0x20;
p_login_frame->seq = 0x00;
p_login_frame->need_ack = 0x01;
p_login_frame->reserved = 0xFF;
p_login_frame->index = 0x00;
p_login_frame->length[0] = 0x00;
p_login_frame->length[1] = 0x06;
p_login_frame->tail = 0xFF;
iot_mac_addr_cpy(p_login_frame->mac, mac_address);
crc16 = iot_cctt_utils_calc_crc16(p_buff,
sizeof(iot_cctt_tools_login_frame_t) - 3);
p_login_frame->crc16[0] = crc16 >> 8;
p_login_frame->crc16[1] = crc16 & 0xFF;
return ERR_OK;
}
/**
* @brief : check whether the data in p_buff is query frame from debug server
*
* @param p_buff : pointer to data to check
* @param len : length of data
* @return true if it's a query frame, false otherwise
*/
bool_t iot_cctt_utils_is_dbg_svr_query_frm(uint8_t *p_buff, uint32_t len)
{
const uint8_t cctt_id_request[] = {
0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x20, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x49, 0xFF,
};
if ((NULL != p_buff) && (sizeof(cctt_id_request) == len) &&
(0 == os_mem_cmp(cctt_id_request, p_buff, sizeof(cctt_id_request)))) {
return true;
} else {
return false;
}
}
/**
* @brief : dump data to log buffer
*
* @param descr : descrption of data
* @param p_data : data to dump
* @param len : length of data
* @return void
*/
void iot_cctt_utils_dump_bin(char *descr, uint8_t *p_data, uint32_t len)
{
iot_cus_printf("%s:", descr);
while (len != 0) {
iot_cus_printf("%02X ", *p_data);
p_data++;
len--;
}
iot_cus_printf("\n");
}
/**
* @brief : smart dump data to log buffer, if data is all printable string
* dump as string format, if not, dump as hex format otherwise
*
* @param descr : descrption of data
* @param p_data : data to dump
* @param len : length of data
* @return void
*/
void iot_cctt_utils_smart_dump(char *descr, uint8_t *p_data, uint32_t len)
{
char str_buff[1024];
char *p_str = str_buff;
uint32_t i;
bool_t print_as_str = true;
for (i = 0; i < len; i++) {
if (p_str + 3 >= str_buff + sizeof(str_buff)) {
/* buffer not enough, print as hex code */
print_as_str = false;
break;
}
if ((p_data[i] >= 0x20) && (p_data[i] < 0x80)) {
*p_str++ = p_data[i];
} else if ('\r' == p_data[i]) {
*p_str++ = '\\';
*p_str++ = 'r';
} else if ('\n' == p_data[i]) {
*p_str++ = '\\';
*p_str++ = 'n';
} else {
/* include non-printable character, print as hex code */
print_as_str = false;
break;
}
}
if (print_as_str) {
*p_str = '\0';
iot_cus_printf("%s: %s\r\n", descr, str_buff);
} else {
iot_cctt_utils_dump_bin(descr, p_data, len);
}
}
/**
* @brief : check if character is valid hex char
*
* @param c : character value to check
* @return 1 if hex char, 0 otherwise
*/
uint8_t iot_cctt_utils_char_is_hex(char c)
{
if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f')) {
return 1;
} else {
return 0;
}
}
/**
* @brief : check if character is valid number char
*
* @param c : character value to check
* @return 1 if hex char, 0 otherwise
*/
uint8_t iot_cctt_utils_char_is_number(char c)
{
if(c >= '0' && c <= '9') {
return 1;
} else {
return 0;
}
}
/**
* @brief : parse ip address from specified string
*
* @param p_str : string to parse
* @param p_ip : buffer to store ip address
* @return ERR_OK if success, error code otherwise
*/
uint8_t iot_cctt_utils_ip_str_parse(uint8_t *p_str, uint8_t *p_ip)
{
uint32_t temp;
uint32_t ip_idx = 0;
if ((NULL == p_str) || (NULL == p_ip)) {
return ERR_FAIL;
}
os_mem_set(p_ip, 0x00, IOT_IP4_ADDR_LEN);
while (*p_str) {
if (iot_cctt_utils_char_is_number(*p_str)) {
temp = p_ip[ip_idx];
temp = temp * 10 + *p_str - '0';
if (temp > 255) {
return ERR_FAIL;
}
p_ip[ip_idx] = temp;
} else if ('.' == *p_str) {
ip_idx++;
if (ip_idx >= IOT_IP4_ADDR_LEN) {
return ERR_FAIL;
}
} else {
return ERR_FAIL;
}
p_str++;
}
return ERR_OK;
}
/**
* @brief: reboot cctt
*
* @param reason: reason of requesting to reboot cctt
* @return none
*/
void iot_cctt_utils_reboot_cctt(iot_cctt_utils_reboot_cctt_reason_e reason)
{
char *p_reboot_reason_str = "unknown reason ";
switch (reason) {
case IOT_CCTT_REBOOT_REASON_MGR_AT_CMD_REQ:
p_reboot_reason_str = "reboot cmd from at manager";
break;
case IOT_CCTT_REBOOT_REASON_IOT_DISCONN_TO:
p_reboot_reason_str = "disconnect timeout from iot app";
break;
default:
break;
}
iot_cus_printf("cctt reboot because of reason:%s\n", p_reboot_reason_str);
iot_system_restart(IOT_SYS_RST_REASON_APP_REQ);
}
/**
* @brief: check whether the specified year is leap year
*
* @param year: year number to check
* @return 1 if year is leap year, 0 otherwise
*/
static inline int iot_cctt_utils_is_leap_year(unsigned int year)
{
int ret = 0;
if (((!(year % 4)) && (year % 100)) || !(year % 400)) {
ret = 1;
}
return ret;
}
/**
* @brief: calc the number of days from the beginning of year to the month
*
* @param month: the month to calc days
* @param year: the year to calc days
* @return: the number of days from the beginning of year to the month
*/
static int iot_cctt_utils_calc_month_days(unsigned int month, unsigned int year)
{
static const unsigned char rtc_days_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int ret = 0;
ret = rtc_days_in_month[month];
if (iot_cctt_utils_is_leap_year(year) && (month == 1)) {
ret++;
}
return ret;
}
/**
* @brief: Convert seconds since 01-01-1970 00:00:00 to iot_time_tm_t date.
*
* @param time: seconds since 01-01-1970 00:00:00
* @param p_tm: iot_time_tm_t pointer to store converted time
* @return none
*/
void iot_cctt_utils_time64_to_tm(uint64_t time, iot_time_tm_t *p_tm)
{
unsigned int month, year;
unsigned long secs;
int days;
if (NULL == p_tm) {
return;
}
/* time must be positive */
days = time / 86400;
secs = time - (unsigned int) days * 86400;
year = 1970 + days / 365;
days -= (year - 1970) * 365
+ LEAPS_THRU_END_OF(year - 1)
- LEAPS_THRU_END_OF(1970 - 1);
if (days < 0) {
year -= 1;
days += 365 + iot_cctt_utils_is_leap_year(year);
}
p_tm->tm_year = year;
for (month = 0; month < 11; month++) {
int newdays;
newdays = days - iot_cctt_utils_calc_month_days(month, year);
if (newdays < 0)
break;
days = newdays;
}
p_tm->tm_mon = month + 1;
p_tm->tm_mday = days + 1;
p_tm->tm_hour = secs / 3600;
secs -= p_tm->tm_hour * 3600;
p_tm->tm_min = secs / 60;
p_tm->tm_sec = secs - p_tm->tm_min * 60;
}
/*
* @brief: Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* @param p_tm : pointed to iot_time_tm_t
* @return seconds since 1970-01-01 00:00:00
*/
uint64_t iot_cctt_utils_tm_to_time64(iot_time_tm_t *p_tm)
{
unsigned int year, month, day, hour, minute, second;
if (NULL == p_tm) {
return 0;
}
year = p_tm->tm_year;
month = p_tm->tm_mon;
day = p_tm->tm_mday;
hour = p_tm->tm_hour;
minute = p_tm->tm_min;
second = p_tm->tm_sec;
/* 1..12 -> 11,12,1..10 */
if (0 >= (int) (month -= 2)) {
month += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
return ((((uint64_t)
(year/4 - year/100 + year/400 + 367*month/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours */
)*60 + minute /* now have minutes */
)*60 + second; /* finally seconds */
}
/*
* @brief: query gpio pin number according to gpio id.
*
* @param gpio_id: gpio identifier, see iot_cctt_utils_gpio_id_e definition
* @return gpio number if success, 0xFF otherwise
*/
uint8_t iot_cctt_utils_get_gpio(iot_cctt_utils_gpio_id_e gpio_id)
{
uint8_t gpio_pin = IOT_CCTT_INVALID_GPIO;
switch (iot_board_hw_version_hex()) {
case HW_VERSION_IOT_CCTT_V3_0: /* micro cctt 3.0 hardware */
switch (gpio_id) {
case IOT_CCTT_GPIO_ID_ETH_RST:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(9);
break;
case IOT_CCTT_GPIO_ID_4G_RST:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(0);
break;
case IOT_CCTT_GPIO_ID_EXT_WDI:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(7);
break;
case IOT_CCTT_GPIO_ID_RSD_SWITCH_IN:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(48);
break;
case IOT_CCTT_GPIO_ID_RSD_LED_OUT:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(12);
break;
case IOT_CCTT_GPIO_ID_RS485_CTL:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(36);
break;
case IOT_CCTT_GPIO_ID_RS485_LED:
gpio_pin = IOT_CCTT_INVALID_GPIO;
break;
case IOT_CCTT_GPIO_ID_UPGD_LED:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(8);
break;
case IOT_CCTT_GPIO_ID_PLC_LED:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(44);
break;
case IOT_CCTT_GPIO_ID_UPLINK_LED:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(45);
break;
default:
break;
}
break;
case HW_VERSION_IOT_CCTT_V3_5: /* micro cctt 3.5 hardware */
default:
switch (gpio_id) {
case IOT_CCTT_GPIO_ID_ETH_RST:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(1);
break;
case IOT_CCTT_GPIO_ID_4G_RST:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(3);
break;
case IOT_CCTT_GPIO_ID_EXT_WDI:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(0);
break;
case IOT_CCTT_GPIO_ID_RSD_SWITCH_IN:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(48);
break;
case IOT_CCTT_GPIO_ID_RSD_LED_OUT:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(4);
break;
case IOT_CCTT_GPIO_ID_RS485_CTL:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(36);
break;
case IOT_CCTT_GPIO_ID_RS485_LED:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(5);
break;
case IOT_CCTT_GPIO_ID_UPGD_LED:
gpio_pin = IOT_CCTT_KL1_EXT_GPIO(2);
break;
case IOT_CCTT_GPIO_ID_PLC_LED:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(44);
break;
case IOT_CCTT_GPIO_ID_UPLINK_LED:
gpio_pin = IOT_CCTT_INTERNAL_GPIO(45);
break;
default:
break;
}
break;
}
return gpio_pin;
}