You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

709 lines
17 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/******************************************************************************
* file lib/management/common.c
* author YuLiang
* version 1.0.0
* date 14-Sep-2021
* brief This file provides all the common operation functions.
*
******************************************************************************
* Attention
*
* <h2><center>&copy; COPYRIGHT(c) 2021 LandPower</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of LandPower nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* 标准C库头文件. */
#include <sys/time.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* 用户代码头文件. */
#include "vty.h"
/* Private define ------------------------------------------------------------*/
/* CRC32 使用. */
#define CRC32_CHAR_BIT 8
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* 时间缓存结构体. */
typedef struct _time_cache
{
time_t last; /* 最后一次时间缓存数据. */
size_t len; /* buf中数据的长度. */
char buf[TIME_STR_LEN]; /* 时间数据转化的字符串. */
} time_cache_t;
/* Private variables ---------------------------------------------------------*/
static struct timeval sd_start, sd_end;
static uint32_t crc32Table[256];
extern int8_t is_system_reboot;
/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* 在时间后面根据precision长度,添加更加精确的时间字符串. */
static size_t _time_string_prec_add(char *buf, size_t len, int32_t precision, struct timeval *clock)
{
static const int divisor[] = {0, 100000, 10000, 1000, 100, 10, 1};
char *p = NULL;
/* 最多统计到us */
if (precision > 6)
precision = 6;
p = buf + len + 1 + precision;
*p-- = '\0';
clock->tv_usec /= divisor[precision];
do
{
*p-- = '0' + (clock->tv_usec % 10);
clock->tv_usec /= 10;
}
while(--precision > 0);
*p = '.';
return len + 1 + precision;
}
/* Interface functions -------------------------------------------------------*/
/* description: 将字符串转为小写.
param: str -- 需要转换的字符转
return: 转换后的字符串 */
char *str_to_lower(char *str)
{
uint32_t i = 0;
if (str != NULL)
{
for(i = 0; str[i] != '\0'; i++)
{
str[i] = tolower(str[i]);
}
}
return str;
}
/* description: 去掉字符串中的多余空格.
param: str -- 需要转换操作的字符转
omit_end -- omit_end(TRUE)表示会将字符串尾部的空格全部消除
omit_end(FALSE)表示如果尾部有空格允许保留1个空格
return: 操作后的字符串 */
char *str_omit_space(char *str, bool omit_end)
{
char *front = str;
char *last = str;
if (NULL == str)
{
return NULL;
}
while(' ' == *front)
front++;
while((*front) != '\0')
{
if (' ' == *front)
{
while((*++front) == ' ');
if ('\0' == *front && omit_end)
;
else
{
*last = ' ';
last++;
}
}
else
{
*last = *front;
front++;
last++;
}
}
*last = '\0';
return str;
}
/* description: 根据传入的精度precision,将时间字符串填到buf.
param: precision -- 精度,几位小数
buf -- 存储转换后字符串的buffer
buflen -- buf的大小
return: 返回字符串长度,如果失败,返回0 */
size_t time_string(int32_t precision, char *buf, size_t buflen)
{
static time_cache_t cache;
struct timeval clock;
/* 获取时间数据clock. */
gettimeofday(&clock, NULL);
/* 更新时间到字符串,cache是静态的,如果两次time_string调用在1秒之内,将沿用上次的cache. */
if (cache.last != clock.tv_sec)
{
struct tm *tm = NULL;
cache.last = clock.tv_sec;
tm = localtime(&cache.last);
cache.len = strftime(cache.buf, sizeof(cache.buf), "%Y/%m/%d %H:%M:%S", tm);
}
if (buflen > cache.len)
{
memcpy(buf, cache.buf, cache.len);
/* 计算秒之后的精度. */
if ((precision > 0) && (buflen > cache.len + 1 + precision))
return _time_string_prec_add(buf, cache.len, precision, &clock);
buf[cache.len] = '\0';
return cache.len;
}
/* buf太小,无法生成字符串. */
if (buflen > 0)
buf[0] = '\0';
return 0;
}
/* description: 获取错误代码字符串.
param: errnum -- 错误代码
return: 获取的字符串 */
const char *safe_strerror(int errnum)
{
const char *s = strerror(errnum);
return (s != NULL) ? s : "Unknown error";
}
/* description: 按16进制打印buf数据.
param: buf -- 数据
len -- 数据长度
return: */
void buf_print(char *buf, int32_t len)
{
int32_t i = 0;
for(i = 0; i < len;)
{
printh("%02x ", (uint8_t)buf[i++]);
if(0 == i % 32)
{
printh("\r\n");
}
}
if(i % 32 != 0)
{
printh("\r\n\n");
}
else
{
printh("\n");
}
return;
}
/* description: 通过 ip 生成 mac 地址.
param: ip_str -- 输入 ip 地址
mac -- 输出 mac 地址
return: E_XXXX */
int32_t mac_generate_from_ip(char *ip_str, uint8_t *mac)
{
struct sockaddr_in server;
uint32_t ip = 0;
uint32_t temp = 0;
if (NULL == ip_str || NULL == mac)
{
return E_BAD_PARAM;
}
/* 将 ip_str 转为数字. */
if (inet_aton(ip_str, &server.sin_addr) < 0)
{
DBG(DBG_M_CLI, "inet_aton ip is error!\r\n");
return E_BAD_PARAM;
}
ip = server.sin_addr.s_addr;
/* 产生 mac. */
srand(time(NULL));
temp = rand();
mac[0] = 0x68;
mac[1] = temp & 0xff;
mac[2] = (temp >> 8) & 0xff;
mac[3] = (temp >> 16) & 0xff;
mac[4] = (temp >> 24) & 0xff;
mac[5] = (ip >> 24) & 0xff;
return E_NONE;
}
/* description: 计算CRC16/MODBUS.
param: data -- 数据
size -- 数据长度
return: 计算的crc值 */
uint16_t crc16(uint8_t *data, uint16_t size)
{
uint16_t crc = 0xFFFF;
uint8_t i = 0;
while(size--)
{
crc = crc ^ *data++;
for(i = 0; i < 8; i++)
{
if ((crc & 0x0001) > 0)
{
crc = crc >> 1;
crc = crc ^ 0xa001;
}
else
crc = crc >> 1;
}
}
return crc;
}
void invert_uint8(unsigned char *dest_buf, unsigned char *src_buf)
{
int i;
unsigned char tmp[4];
tmp[0] = 0;
for (i = 0; i < 8; i++)
{
if (src_buf[0] & (1 << i))
tmp[0] |= 1 << (7 - i);
}
dest_buf[0] = tmp[0];
}
void invert_uint16(unsigned short *dest_buf, unsigned short *src_buf)
{
int i;
unsigned short tmp[4];
tmp[0] = 0;
for (i = 0; i < 16; i++)
{
if (src_buf[0] & (1 << i))
tmp[0] |= 1 << (15 - i);
}
dest_buf[0] = tmp[0];
}
uint16_t crc16_modbus(uint8_t *data, uint16_t size)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (size--)
{
wChar = *(data++);
invert_uint8(&wChar, &wChar);
wCRCin ^= (wChar << 8);
int i = 0;
for (i = 0; i < 8; i++)
{
if (wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
invert_uint16(&wCRCin, &wCRCin);
return (wCRCin);
}
uint32_t crc32_reflect(uint32_t value, uint8_t bits)
{
uint32_t reflection = 0;
for(uint8_t i = 0; i < bits ; i++)
{
if (value & (1u << i))
reflection |= 1 << (bits - 1 - i);
}
return reflection;
}
/* crc32 初始化. */
void crc32_table_init(void)
{
uint32_t int1 = 1;
uint32_t const value_high_bit = int1 << 31u;
uint8_t dividend = 0;
do
{
uint32_t remainder = 0;
for(uint8_t mask = 1u << (CRC32_CHAR_BIT - 1u); mask; mask >>= 1)
{
if (dividend & mask)
remainder ^= value_high_bit;
if (remainder & value_high_bit)
{
remainder <<= 1;
remainder ^= 0x04C11DB7u;
}
else
remainder <<= 1;
}
crc32Table[crc32_reflect(dividend, CRC32_CHAR_BIT)] = crc32_reflect(remainder, 32);
}
while(++dividend);
}
uint32_t crc32(void const *buf, uint16_t byte_count)
{
uint32_t rem = 0xFFFFFFFF;
uint8_t const * const b_begin = (uint8_t*)buf;
uint8_t const * const b_end = b_begin + byte_count;
for(uint8_t const *p = b_begin; p < b_end; p++)
{
uint8_t const byte_index = *p ^ rem;
rem >>= CRC32_CHAR_BIT;
rem ^= crc32Table[ byte_index ];
}
return ~rem;
}
/**
* @brief 计算crc32值.
* @param buf: 数据.
* @param len: 数据长度.
* @retval crc32值.
*/
uint32_t crc32_update(uint32_t crc, char* buf, uint32_t len)
{
uint32_t i = 0;
for(i = 0; i < len; i++)
crc = crc32Table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
return crc;
}
/* description: 时间统计开始.
param:
return: */
void speed_detection_stat(void)
{
gettimeofday(&sd_start, NULL);
}
/* description: 时间统计结束.
param:
return: */
void speed_detection_end(void)
{
float timeuse;
gettimeofday(&sd_end, NULL);
timeuse = 1000000 * (sd_end.tv_sec - sd_start.tv_sec) + sd_end.tv_usec - sd_start.tv_usec;
timeuse /= 1000000;
printh("Used Time:%f\r\n", timeuse);
}
/* description: 通用打印函数.
param:
return: */
int printh(const char *format, ...)
{
va_list args;
va_start(args, format);
vty_print(format, args);
va_end(args);
return 0;
}
/* description: 获取int16_t类型的版本号.
param:
return: int16_t类型的版本号 */
uint16_t sofrware_version_get(void)
{
char version_str[16];
char *str = NULL;
char *p = NULL;
uint16_t version = 0;
snprintf(version_str, 16, "%s", version_get());
str = strtok_r(version_str, ".", &p);
while(str != NULL)
{
version = version << 8;
version |= (uint8_t)(atoi(str));
str = strtok_r(NULL, ".", &p);
}
return version;
}
/* description: 根据传入的字符串转换成mac地址.
param:
return: */
int32_t str_to_mac(char *mac_str, OUT uint8_t *mac)
{
char *str = NULL;
char *p = NULL;
uint8_t len = 0;
uint8_t i = 0;
/* 按:分词 */
str = strtok_r(mac_str, ":", &p);
while(str != NULL)
{
/* 检查mac长度 */
if (len >= 6)
{
return E_BAD_PARAM;
}
/* 检查字符串 */
for(i = 0; str[i] && str[i] != '\0'; i++)
{
if (!((str[i] >= '0' && str[i] <= '9')
|| (str[i] >= 'a' && str[i] <= 'f')
|| (str[i] >= 'A' && str[i] <= 'F')))
{
return E_BAD_PARAM;
}
}
/* 检查数据长度 */
if (i != 2)
{
return E_BAD_PARAM;
}
mac[len++] = strtol(str, NULL, 16);
/* 获取下个数据 */
str = strtok_r(NULL, ":", &p);
}
return E_NONE;
}
/* description: 根据传入的字符串转换成设备id.
param:
return: */
int32_t str_to_id(char *id_str, OUT uint32_t *id)
{
char *str = NULL;
char *p = NULL;
uint8_t len = 0;
uint8_t i = 0;
/* 按:分词 */
str = strtok_r(id_str, ".", &p);
while(str != NULL && len < 2)
{
/* 检查id长度 */
if (len >= 2)
{
return E_BAD_PARAM;
}
/* 检查字符串 */
for(i = 0; str[i] && str[i] != '\0'; i++)
{
if (!(str[i] >= '0' && str[i] <= '9'))
{
return E_BAD_PARAM;
}
}
id[len++] = strtol(str, NULL, 10);
/* 获取下个数据 */
str = strtok_r(NULL, ".", &p);
}
return E_NONE;
}
int32_t bitmap_set(uint8_t *buf, int32_t nbit, int32_t buf_len)
{
if ((NULL == buf) || (nbit >= buf_len * 8))
{
return E_BAD_PARAM;
}
buf[nbit / 8] |= 1 << (nbit % 8);
return E_NONE;
}
int32_t bitmap_reset(uint8_t *buf, int32_t nbit, int32_t buf_len)
{
if ((NULL == buf) || (nbit >= buf_len * 8))
{
return E_BAD_PARAM;
}
buf[nbit / 8] &= ~(1 << (nbit % 8));
return E_NONE;
}
int32_t is_bitmap_set(uint8_t *buf, int32_t nbit, int32_t buf_len)
{
if ((NULL == buf) || (nbit >= buf_len * 8))
{
return FALSE;
}
return buf[nbit / 8] & (1 << (nbit % 8));
}
int32_t time_str_to_long(char *date, char *time, uint32_t *t)
{
struct tm stm;
int32_t year, month, day, hour, minute,second;
if (sscanf(date, "%d-%d-%d", &year, &month, &day) != 3)
{
return E_BAD_PARAM;
}
if (sscanf(time, "%d:%d:%d", &hour, &minute, &second) != 3)
{
return E_BAD_PARAM;
}
stm.tm_year = year - 1900;
stm.tm_mon = month - 1;
stm.tm_mday = day;
stm.tm_hour = hour;
stm.tm_min = minute;
stm.tm_sec = second;
stm.tm_isdst = 0;
*t = mktime(&stm);
return E_NONE;
}
uint16_t version_str_to_int(void)
{
uint32_t version_m = 0;
uint32_t version_s = 0;
uint32_t version_hm = 0;
uint32_t version_hs = 0;
uint32_t n = 0;
n = sscanf(version_get(), "%d.%d.%d.%d", &version_hm, &version_hs, &version_m, &version_s);
if (n != 4)
{
return 0xffff;
}
return (version_m << 8 | (version_s & 0xff)) & 0xffff;
}
void time_set(time_t timestamp)
{
struct tm *p =localtime(&timestamp);
struct tm tptr = {0};
struct timeval tv = {0};
tptr.tm_year = p->tm_year;
tptr.tm_mon = p->tm_mon;
tptr.tm_mday = p->tm_mday;
tptr.tm_hour = p->tm_hour;
tptr.tm_min = p->tm_min;
tptr.tm_sec = p->tm_sec;
tv.tv_sec = mktime(&tptr);
tv.tv_usec = 0;
settimeofday(&tv, NULL);
system("hwclock -w");
}
boot_msg_t g_bootmsg[] =
{
{BOOT_NONE, "Boot none."},
{BOOT_SYSTEM_RESET, "System reboot..."},
{BOOT_SYSTEM_LOGOUT, "System logout..."},
{BOOT_REMOTE_CFG_SET, "Remote device info change..."},
{BOOT_REMOTE_RESET, "Remote reboot..."},
{BOOT_REMOTE_UPDATE, "Remote update..."},
{BOOT_FILE_RECOVER, "File recover..."},
{BOOT_4G_ERR, "4G is disconnect..."},
{BOOT_CONNECT_ERR, "Server is disconnect..."},
{BOOT_TIMER, "Timer reset..."},
{BOOT_MAX, NULL}
};
void reboot_system(int module, BOOT_MSG type)
{
char *pmsg = NULL;
is_system_reboot = TRUE;
for (BOOT_MSG i = BOOT_NONE; i < BOOT_MAX; i++)
{
if (g_bootmsg[i].type == type)
{
pmsg = g_bootmsg[i].msg;
break;
}
}
if (pmsg)
{
log_out(module, LOG_LVL_WARN, pmsg);
//log_out(module, LOG_LVL_WARN, "Now,start reboot system...");
system("sync");
sleep(3);
system("reboot -f");
}
}
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/