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.

704 lines
20 KiB
C

/*****************************************************************************
* file Src/common.c
* author YuLiang
* version 1.0.0
* date 10-Jun-2022
* brief This file provides all the common related operation functions.
******************************************************************************
* Attention
*
* <h2><center>&copy; COPYRIGHT(c) 2022 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 WTOE 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 ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include "rtc.h"
#include "common.h"
#include "dev_config.h"
#include "cli.h"
#include "flash_log.h"
/* Private define ------------------------------------------------------------*/
/* CRC32 使用. */
#define CRC32_CHAR_BIT 8
/* 中断中打印限制长度. */
#define USART_PRINT_BUF_LEN 128
/* 公共监控任务标志位长度. */
#define COMMON_SYS_FLAG_LEN 4
/* Private typedef -----------------------------------------------------------*/
/* 公共监控任务操作参数. */
typedef struct
{
uint8_t flag[COMMON_SYS_FLAG_LEN];
uint32_t reset_delay;
} common_sys_data_t;
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* 公共监控任务使用. */
const osThreadAttr_t COMMON_SYS_attributes = {
.name = "COMMON_SYS",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
static common_sys_data_t common_sys_data;
static RTC_DateTypeDef common_date;
static RTC_TimeTypeDef common_time;
char *energy_str[ADC_ENERGY_CNT] =
{
"NONE",
"NORMAL",
"SLEEP",
"FORCE"
};
/* CRC使用. */
static const unsigned char bit_mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
static uint32_t crc32Table[256];
/* 软件看门狗标志. */
static uint32_t common_watchdog;
static uint8_t is_watchdog_hw_reset = TRUE;
/* 串口打印使用的端口. */
extern UART_HandleTypeDef *cli_uart;
/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* 判断当情是否在中断中. */
static int _is_handler_mode(void)
{
return __get_IPSR() != 0;
}
/* 公共监控任务操作处理函数. */
static void _common_sys_handle(void)
{
if (bit_list_tst(common_sys_data.flag, COM_SYS_SAVE_CONFIG))
{
bit_list_clr(common_sys_data.flag, COM_SYS_SAVE_CONFIG);
dev_config_save();
}
if (bit_list_tst(common_sys_data.flag, COM_SYS_SAVE_RECORD))
{
bit_list_clr(common_sys_data.flag, COM_SYS_SAVE_RECORD);
dev_record_save();
}
if (bit_list_tst(common_sys_data.flag, COM_SYS_SAVE_INFO))
{
bit_list_clr(common_sys_data.flag, COM_SYS_SAVE_INFO);
dev_info_save();
}
if (bit_list_tst(common_sys_data.flag, COM_SYS_RESET))
{
if (0 == common_sys_data.reset_delay)
{
st_write(&st_data);
HAL_NVIC_SystemReset();
}
else
common_sys_data.reset_delay--;
}
if (bit_list_tst(common_sys_data.flag, COM_SYS_SHUTDOWN))
{
bit_list_clr(common_sys_data.flag, COM_SYS_SHUTDOWN);
st_write(&st_data);
system_shtudown(common_sys_data.reset_delay);
}
}
/* 公共监控主任务循环. */
static void _common_sys_start(void *argument)
{
uint8_t count = 0;
for (;;)
{
osDelay(250);
/* 每 250ms 发送一次串口数据. */
cli_data_buf_send_hw();
/* 每 1s 处理一次配置和重启操作. */
if (0 == (count & 0x03))
{
_common_sys_handle();
HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
common_watchdog_set(COM_WDG_COM);
}
if (is_watchdog_hw_reset)
{
is_watchdog_hw_reset = FALSE;
HAL_GPIO_WritePin(WDG_GPIO_Port, WDG_Pin, GPIO_PIN_SET);
osDelay(1);
HAL_GPIO_WritePin(WDG_GPIO_Port, WDG_Pin, GPIO_PIN_RESET);
vty_print("WDG %d\r\n", HAL_GetTick());
}
count++;
}
}
/* Interface functions -------------------------------------------------------*/
void bit_list_set(uint8_t *bit_list, uint32_t bit)
{
bit_list[bit / 8] |= bit_mask[bit % 8];
}
int bit_list_tst(uint8_t *bit_list, uint32_t bit)
{
return (bit_list[bit / 8] & bit_mask[bit % 8]) ? 1 : 0;
}
void bit_list_clr(uint8_t *bit_list, uint32_t bit)
{
bit_list[bit / 8] &= ~bit_mask[bit % 8];
}
/* 在中断中发送通知. */
void notify_to_task(TaskHandle_t task)
{
BaseType_t higher_task_woken;
/* xHigherPriorityTaskWoken 必须被初始化为 pdFALSE. 如果调用vTaskNotifyGiveFromISR()
会解除 vHandlingTask 任务的阻塞状, 并且 vHandlingTask 任务的优先级高于当前处于运行
状的任务, 则 xHigherPriorityTaskWoken 将会自动被设置为 pdTRUE. */
higher_task_woken = pdFALSE;
/* 向一个任务发送通知, xHandlingTask 是该任务的句柄. */
vTaskNotifyGiveFromISR(task, &higher_task_woken);
/* 如果 xHigherPriorityTaskWoken 为 pdTRUE, 则强制上下文切换. 这个宏的实现取决于移植层,
可能会调用 portEND_SWITCHING_ISR. */
portYIELD_FROM_ISR(higher_task_woken);
}
/* 在中断中发送通知, 带通知值. */
void notify_to_task_form_val(TaskHandle_t task, uint32_t val)
{
BaseType_t higher_task_woken;
/* xHigherPriorityTaskWoken 必须被初始化为 pdFALSE. 如果调用 vTaskNotifyGiveFromISR()
会解除 vHandlingTask 任务的阻塞状, 并且 vHandlingTask 任务的优先级高于当前处于运行
状的任务, 则 xHigherPriorityTaskWoken 将会自动被设置为 pdTRUE. */
higher_task_woken = pdFALSE;
/* 向一个任务发送通知,xHandlingTask是该任务的句柄. */
xTaskNotifyFromISR(task, val, eSetValueWithOverwrite, &higher_task_woken);
/* 如果 xHigherPriorityTaskWoken 为 pdTRUE, 则强制上下文切换. 这个宏的实现取决于移植层,
可能会调用 portEND_SWITCHING_ISR. */
portYIELD_FROM_ISR(higher_task_woken);
}
/* 芯片进入睡眠模式, time 为设置的睡眠时间, 必须大于 1. */
void system_shtudown(uint32_t time)
{
/* 设置时间必须大于 1. */
if (0 == time)
{
time = 1;
}
vty_print_usart("SD %d\r\n", time);
/* 设置为 RTC 唤醒. */
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, time - 1, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
/* 关闭系统时钟, 避免被系统时钟唤醒. */
HAL_SuspendTick();
/* 进入 shutdown 模式. */
HAL_PWR_EnterSTANDBYMode();
}
uint8_t crc8(uint8_t *p, uint8_t len)
{
unsigned char crc = 0;
unsigned char i, crc_1byte, abyte;
while(len--) //len为总共要校验的字节数
{
crc_1byte = 0; //设定crc_1byte初值为0
abyte = crc ^ *p++;
for(i = 0; i < 8; i++)
{
if (((crc_1byte ^ abyte) & 0x01))
{
crc_1byte ^= 0x18;
crc_1byte >>= 1;
crc_1byte |= 0x80;
}
else
{
crc_1byte >>= 1;
}
abyte >>= 1;
}
crc = crc_1byte;
}
return crc;
}
/* 计算CRC16/MODBUS. */
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;
}
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;
}
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 vty_print(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (IS_MONITOR_BIT_SET(dev_config.flag, DEV_FLAG_CLI))
{
if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_OS))
cli_usart_data_buf_send(format, ap);
else
cli_usart_data_buf_send_without_os(format, ap);
}
va_end(ap);
}
/* 打印错误信息vty. */
void vty_print_error(char const *func, int line, int rv)
{
vty_print("%s(%d): Error generation %d.\r\n", func, line, rv);
}
/* 通过 usart1 输出格式化字符. 原地等待发送, 与操作系统无关,
* 可以在中断中使用, 尽量不要在中断中使用, 太耗时间. */
void vty_print_usart(char *format, ...)
{
static char buf[USART_PRINT_BUF_LEN];
if (IS_MONITOR_BIT_SET(dev_config.flag, DEV_FLAG_CLI))
{
va_list ap;
va_start(ap, format);
/* 中断只能在串口输出. */
if (_is_handler_mode() != 0)
{
taskDISABLE_INTERRUPTS();
if (vsnprintf(buf, USART_PRINT_BUF_LEN, format, ap) > 0)
{
HAL_UART_AbortTransmit(cli_uart);
HAL_UART_Transmit(cli_uart, (uint8_t*)buf, strlen(buf), 1000);
}
taskENABLE_INTERRUPTS();
}
else
{
while(HAL_UART_STATE_BUSY_TX == cli_uart->gState)
{
continue;
}
if (vsnprintf(buf, USART_PRINT_BUF_LEN, format, ap) > 0)
{
HAL_UART_Transmit(cli_uart, (uint8_t*)buf, strlen(buf), 1000);
}
}
va_end(ap);
}
}
/* 打印错误信息串口, 可以在中断中使用. */
void vty_print_error_usart(char const *func, int line, int rv)
{
vty_print_usart("Error generation %s(%d) is %d.\r\n", func, line, rv);
}
/* buf 16进制打印 */
void buf_print(uint8_t *buf, int32_t len)
{
int32_t i = 0;
for(i = 0; i < len;)
{
vty_print("%02x ", buf[i++]);
if(0 == i % 32)
{
vty_print("\r\n");
}
}
if(i % 32 != 0)
{
vty_print("\r\n");
}
return;
}
/* buf 16进制打印 */
void buf_print_division(uint8_t *buf, int32_t len, uint16_t division)
{
int32_t i = 0;
for(i = 0; i < len;)
{
vty_print("%02x ", buf[i++]);
if(0 == i % division)
{
vty_print("\r\n");
}
}
if (i % division != 0)
{
vty_print("\r\n");
}
return;
}
/* 公共监控任务初始化. */
void common_sys_init(void)
{
osThreadNew(_common_sys_start, NULL, &COMMON_SYS_attributes);
}
/* 公共监控任务操作接口. */
void common_sys_set(uint8_t flag, void *arg)
{
bit_list_set(common_sys_data.flag, flag);
switch(flag)
{
case COM_SYS_RESET:
MONITOR_BITMAP_SET(system_init_flag, SYS_INIT_RESET);
common_sys_data.reset_delay = *(uint32_t*)arg;
break;
case COM_SYS_SHUTDOWN:
if (!IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_SHUTDOWN))
{
MONITOR_BITMAP_SET(system_init_flag, SYS_INIT_SHUTDOWN);
common_sys_data.reset_delay = *(uint32_t*)arg;
}
break;
default:
break;
}
}
/* 设置看门狗标记. */
void common_watchdog_set(uint32_t id)
{
common_watchdog |= id;
}
/* 清除看门狗标记. */
void common_watchdog_clr(void)
{
common_watchdog = 0;
}
/* 查询看门狗标记.0-没有置位,1-置位. */
int32_t common_watchdog_tst(uint32_t id)
{
return common_watchdog & id;
}
/* 查询看门狗标记.0-没有置位,1-置位. */
int32_t common_watchdog_tst_all(void)
{
uint32_t temp = COM_WDG_COM | COM_WDG_ADC | COM_WDG_CLI | COM_WDG_DAU | COM_WDG_GPS;
return ((common_watchdog & temp) == temp);
}
/* 通知程序喂硬件看门狗. */
void common_watchdog_hw_refresh(void)
{
is_watchdog_hw_reset = TRUE;
}
/* 计算绝对值. */
uint32_t abs_cal(int32_t a, int32_t b)
{
return (a > b ? a - b : b - a);
}
/* 计算绝对值. */
uint32_t abs_cal_u(uint32_t a, uint32_t b)
{
return (a > b ? a - b : b - a);
}
void rtc_time_set(uint32_t utc)
{
utc += 8 * 3600;
struct tm *day = NULL;
time_t temp = 0;
HAL_RTC_GetTime(&hrtc, &time_structure, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &date_structure, RTC_FORMAT_BIN);
tm_structure.tm_year = date_structure.Year + 100;
tm_structure.tm_mon = date_structure.Month - 1;
tm_structure.tm_mday = date_structure.Date;
tm_structure.tm_hour = time_structure.Hours;
tm_structure.tm_min = time_structure.Minutes;
tm_structure.tm_sec = time_structure.Seconds;
temp = mktime(&tm_structure);
if (abs_cal_u(temp, utc) > 1)
{
//vty_print("%ld %d\r\n", temp, utc);
memset(&time_structure,0,sizeof(RTC_TimeTypeDef));
memset(&date_structure,0,sizeof(RTC_DateTypeDef));
day = localtime(&utc);
time_structure.Hours = day->tm_hour;
time_structure.Minutes = day->tm_min;
time_structure.Seconds = day->tm_sec;
HAL_RTC_SetTime(&hrtc, &time_structure, RTC_FORMAT_BIN);
if (day->tm_year >= 100)
{
date_structure.Year = day->tm_year - 100;
}
date_structure.Month = day->tm_mon + 1;
date_structure.Date = day->tm_mday;
HAL_RTC_SetDate(&hrtc, &date_structure, RTC_FORMAT_BIN);
vty_print("Set date to %d/%d/%d %d:%d:%d.\r\n", date_structure.Year, date_structure.Month, date_structure.Date,
time_structure.Hours, time_structure.Minutes, time_structure.Seconds);
}
}
void restart_ontime(void)
{
uint32_t sleep_time = 65;
HAL_RTC_GetTime(&hrtc, &common_time, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &common_date, RTC_FORMAT_BIN);
if (0 == dev_config.csg_reset_time[0])
{
if (common_time.Hours == dev_config.csg_reset_time[1]
&& common_time.Minutes == dev_config.csg_reset_time[2])
{
flash_log_write(FLASH_LOG_TYPE_WARNING, "Ontime restart %ds\r\n", sleep_time);
common_sys_set(COM_SYS_SHUTDOWN, (void*)&sleep_time);
}
}
else
{
if (common_date.Date == dev_config.csg_reset_time[0]
&& common_time.Hours == dev_config.csg_reset_time[1]
&& common_time.Minutes == dev_config.csg_reset_time[2])
{
flash_log_write(FLASH_LOG_TYPE_WARNING, "Ontime restart %ds\r\n", sleep_time);
common_sys_set(COM_SYS_SHUTDOWN, (void*)&sleep_time);
}
}
}
#if LD_DEBUG
/* debug 模块使能 bitmap. */
static uint8_t dbg_module[DBG_BYTE_LEN];
/* 开指定模块的 debug. */
static void _dbg_on(uint8_t module)
{
bit_list_set(dbg_module, module);
}
/* 关指定模块的debug */
static void _dbg_off(uint8_t module)
{
bit_list_clr(dbg_module, module);
}
/* 关所有模块的debug */
static void _dbg_all_off(void)
{
memset(dbg_module, 0, DBG_BYTE_LEN);
}
/* 获取当前模块debug状态 */
int32_t dbg_stat_get(uint8_t module)
{
return bit_list_tst(dbg_module, module);
}
/* debug模块函数分发,flag=1代表是否是开启lwip debug. */
int32_t dbg_cmd_hander(uint8_t cmd, uint8_t data)
{
switch(cmd)
{
case DBG_CMD_ON:
_dbg_on(data);
break;
case DBG_CMD_OFF:
_dbg_off(data);
break;
case DBG_CMD_OFF_ALL:
_dbg_all_off();
break;
default:
break;
}
return HAL_OK;
}
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#if !defined(iap_htons)
/**
* Convert an u16_t from host- to network byte order.
*
* @param n u16_t in host byte order
* @return n in network byte order
*/
uint16_t iap_htons(uint16_t n)
{
return (uint16_t)PP_HTONS(n);
}
#endif /* iap_htons */
#if !defined(iap_htonl)
/**
* Convert an u32_t from host- to network byte order.
*
* @param n u32_t in host byte order
* @return n in network byte order
*/
uint32_t iap_htonl(uint32_t n)
{
return (uint32_t)PP_HTONL(n);
}
#endif /* iap_htonl */
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
/******************* (C) COPYRIGHT LandPower ***** END OF FILE ****************/