/* * @Author: * @day: 2023-04-11 08:21:19 * @LastEditors: xxx * @LastEditTime: 2023-08-15 10:14:58 * @Description: * email: * Copyright (c) 2023 by xxx, All Rights Reserved. */ #include "../inc/lib.h" #include #include #include "cmac.h" const uint8_t _days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const uint16_t _month_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; static uint32_t crc32_table[256]; // CRC32表 // ASSIC码数组转字符串 void assic_to_str(uint8_t *assic, uint8_t len, uint8_t *str) { for (uint8_t i = 0; i < len; i++) { if (assic[i] == 0) { str[i] = 48; } else { str[i] = (char)assic[i]; } } } // 每隔三位数加逗号,将数字转为每隔3位整数由逗号“,”分隔的字符串 void add_commas(uint32_t num, char *result) { char temp[64]; sprintf(temp, "%d", num); int32_t len = strlen(temp); int32_t commas = (len - 1) / 3; int32_t index = 0; int32_t resultIndex = 0; for (int32_t i = len - 1; i >= 0; i--) { result[resultIndex++] = temp[i]; index++; if (index % 3 == 0 && commas > 0) { result[resultIndex++] = ','; commas--; } } result[resultIndex] = '\0'; // Reverse the result string int32_t start = 0; int32_t end = resultIndex - 1; while (start < end) { char temp = result[start]; result[start] = result[end]; result[end] = temp; start++; end--; } } void get_cpu_id(uint32_t *id) { #ifdef STM32 // 获取CPU唯一的ID id[0] = *(uint32_t *)(UID_BASE); id[1] = *(uint32_t *)(UID_BASE + 4); id[2] = *(uint32_t *)(UID_BASE + 8); #endif } uint32_t cpu_encrypt(void) { uint32_t cpuid[3]; #ifdef STM32 // 获取CPU唯一的ID cpuid[0] = *(uint32_t *)(UID_BASE); cpuid[1] = *(uint32_t *)(UID_BASE + 4); cpuid[2] = *(uint32_t *)(UID_BASE + 8); #endif // 加密算法,很简单的加密算法 uint32_t encrypt_code = (cpuid[0] >> 3) + (cpuid[1] >> 1) + (cpuid[2] >> 2); return encrypt_code; } // 判断加密 BOOL cpu_judge_encrypt(uint32_t cupid_encrypt) { uint32_t cpuid[4]; #ifdef STM32 // 获取CPU唯一的ID cpuid[0] = *(uint32_t *)(UID_BASE); cpuid[1] = *(uint32_t *)(UID_BASE + 4); cpuid[2] = *(uint32_t *)(UID_BASE + 8); #endif // 加密算法,很简单的加密算法 cpuid[3] = (cpuid[0] >> 3) + (cpuid[1] >> 1) + (cpuid[2] >> 2); // 检查Flash中的UID是否合法 return (cupid_encrypt == cpuid[3]); } void convert_seconds(uint32_t total_seconds, char *date) { uint32_t days = total_seconds / 86400; uint32_t hours = (total_seconds % 86400) / 3600; uint32_t minutes = (total_seconds % 3600) / 60; uint32_t seconds = total_seconds % 60; if (days > 0) { if (days > 1000) { sprintf(date, "%02d d %02d h", days, hours); } else { sprintf(date, "%02d d %02d h %02d m", days, hours, minutes); } } else if (hours > 0) { sprintf(date, "%02d h %02d m %02d s", hours, minutes, seconds); } else if (minutes > 0) { sprintf(date, "%02d m %02d s", minutes, seconds); } else { sprintf(date, "%02d s", seconds); } } /** * @brief Generate the CRC32 lookup table. * * This function generates the CRC32 lookup table used for fast computation of the * CRC32 checksum. The table is generated using the polynomial 0xEDB88320, which is a * common polynomial used in CRC32 calculations. */ static void generate_crc32_table() { static BOOL is_init = FALSE; if (is_init) { return; } uint32_t polynomial = 0xEDB88320; for (uint32_t i = 0; i < 256; i++) { uint32_t crc = i; for (uint32_t j = 0; j < 8; j++) { crc = (crc & 1) ? (crc >> 1) ^ polynomial : crc >> 1; } crc32_table[i] = crc; } is_init = TRUE; } /** * @brief 版本号1.0拆解成1和0 * @param {uint8_t} *version_str * @param {uint8_t} *hi * @param {uint8_t} *lo * @return {*} */ void version_split(uint8_t *version_str, uint8_t *hi, uint8_t *lo) { uint8_t flag = 1; for (uint8_t i = 0; version_str[i] != '\0'; i++) { if (version_str[i] == '.') { flag = 0; continue; } if (flag) { *hi = *hi * 10 + (version_str[i] - '0'); } else { *lo = *lo * 10 + (version_str[i] - '0'); } } } // 反序数组 void reverse(uint8_t *buf, uint16_t len) { uint8_t tmp; uint16_t i; for (i = 0; i < len / 2; i++) { tmp = buf[i]; buf[i] = buf[len - i - 1]; buf[len - i - 1] = tmp; } } /*** * @brief 判断是否在数组中 * @param {uint8_t} *arr 数组 * @param {uint8_t} len 数组长度 * @param {uint8_t} val 要判断的值 * @return {*} TRUE: 在数组中 */ BOOL is_in_array(uint16_t *arr, uint16_t len, uint16_t val) { uint16_t i; for (i = 0; i < len; i++) { if (arr[i] == val) { return TRUE; } } return FALSE; } /** * 计算并返回指定数据区域crc的值 * * @param data: 待计算的数据区首地址 * @param length: 待计算的数据区长度 * * @return crc计算的结果 */ uint16_t crc16_compute(const uint8_t *const data, uint16_t length) { uint16_t crcVal = 0xffff; const uint8_t *ptr = data; for (uint16_t i = 0; i < length; i++) { crcVal ^= (uint16_t)*ptr++; for (uint8_t j = 0; j < 8; j++) { if (crcVal & 0x0001) { crcVal = (crcVal >> 1) ^ 0x8401; } else { crcVal >>= 1; } } } return crcVal; } /** * @brief Calculate the CRC32 value of a data buffer. * * This function calculates the CRC32 value of a data buffer using the lookup table method. * The lookup table is generated using the polynomial 0xEDB88320, which is a common polynomial used in CRC32 calculations. * * @param data The data buffer to calculate the CRC32 value of. * @param length The length of the data buffer in bytes. * @return The CRC32 value of the data buffer. */ uint32_t crc32_compute(const uint8_t *const data, uint16_t length) { generate_crc32_table(); uint32_t crc = 0xFFFFFFFF; for (size_t i = 0; i < length; i++) { crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF]; } return crc ^ 0xFFFFFFFF; } /** * @brief 计算 64 位 CRC 值 * * 根据给定的数据块和长度,使用 AES-CMAC 算法和 CRC32 算法计算 64 位 CRC 值。 * 使用这个函数heap设置0x800 * * @param data 数据块指针 * @param length 数据块长度 * * @return 返回计算得到的 64 位 CRC 值 */ uint64_t crc64_compute(const uint8_t *const data, const uint16_t length) { uint8_t cmac_key[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; // 密钥 uint8_t dst[4]; uint8_t mic[16]; uint8_t *p; uint32_t lo = 0, hi = 0; AES_CMAC_CTX AesCmacCtx[1]; // 密钥扩展表 AES_CMAC_Init(AesCmacCtx); // 完成密钥扩展表的初始化 AES_CMAC_SetKey(AesCmacCtx, cmac_key); // 完成密钥扩展表数据 // 存放生成校验数据的数组 AES_CMAC_Update(AesCmacCtx, data, length & 0xFF); // 完成数据的奇偶校验 AES_CMAC_Final(mic, AesCmacCtx); // 生成16个字节的校验表 uint32_t xor_vol = (uint32_t)((uint32_t)mic[3] << 24 | (uint32_t)mic[2] << 16 | (uint32_t)mic[1] << 8 | (uint32_t)mic[0]); // 取表4个字节作为校验码 p = (uint8_t *)&xor_vol; osel_memcpy(dst, p, 4); lo = (uint32_t)dst[0] << 24 | (uint32_t)dst[1] << 16 | (uint32_t)dst[2] << 8 | (uint32_t)dst[3]; hi = crc32_compute(data, length); return ((uint64_t)hi << 32) | lo; } /** * 计算并返回指定数据区域异或的值 * * @param data: 待计算的数据区首地址 * @param length: 待计算的数据区长度 * * @return 异或计算的结果 */ uint8_t xor_compute(const uint8_t *const data, uint16_t length) { uint16_t i; const uint8_t *ptr = data; uint8_t xor = 0; for (i = 0; i < length; i++) { xor ^= *ptr; ptr++; } return xor; } // 通过bit位获取置1个数量 uint8_t get_bit_num(uint8_t bit) { uint8_t num = 0; while (bit) { if (bit & 0x01) { num++; } bit >>= 1; } return num; } // 通过bit位获取置1的位置 BOOL is_bit_set(int32_t x, int32_t k) { int32_t mask = 1 << k; return (x & mask) != 0; } // 判断数组是否全是同一个值 BOOL is_same_value(uint8_t *buf, uint16_t len, uint8_t value) { uint16_t i; for (i = 0; i < len; i++) { if (buf[i] != value) { return FALSE; } } return TRUE; } // 检查是否是闰年 uint8_t is_leap_year(uint16_t year) { return (year % 400 == 0) || (year % 100 != 0 && year % 4 == 0); } // 检查日期是否合法 BOOL is_valid_date(uint8_t year, uint8_t month, uint8_t day) { if (year < 1 || month < 1 || month > 12 || day < 1) { return false; } uint8_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 如果是闰年,2月有29天 if (is_leap_year(year)) { days_in_month[1] = 29; } return day <= days_in_month[month - 1]; } // 检查时间是否合法 BOOL is_valid_time(uint8_t hour, uint8_t minute, uint8_t second) { return (hour < 24) && (minute < 60) && (second < 60); } // 检查日期和时间是否合法 BOOL is_valid_datetime(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { return is_valid_date(year, month, day) && is_valid_time(hour, minute, second); } // 计算从1970年1月1日到给定年月日的天数 uint32_t days_since_1970(uint16_t year, uint8_t month, uint8_t day) { static const uint8_t month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; uint32_t days = 0; uint16_t y = 1970; // 计算整年过去的天数 while (y < year) { days += is_leap_year(y) ? 366 : 365; y++; } // 计算当前年份中过去的天数 for (int32_t m = 0; m < month - 1; m++) { days += month_days[m]; if (m == 1 && is_leap_year(year)) { // 如果是2月且是闰年,多加一天 days++; } } // 加上当前月的天数 days += day - 1; // 因为day是从1开始的,而我们需要的是从0开始的偏移量 return days; } // 将日期转换为秒数 uint32_t date_to_seconds(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { uint32_t secs = 0; uint32_t days = days_since_1970(year, month, day); secs = days * 24 * 60 * 60; // 一天有24小时,每小时有60分钟,每分钟有60秒 secs += hour * 60 * 60 + minute * 60 + second; return secs; } // 函数用于将秒数转换为日期和时间,年份4位 void seconds_to_date(uint32_t total_seconds, rtc_date_t *date, rtc_time_t *time) { uint16_t year = 1970; // Unix时间戳的起始年份 uint8_t month = 1; uint8_t day = 1; uint32_t seconds = total_seconds; uint8_t hours, minutes, secs; // 正确处理小时、分钟和秒 hours = (seconds / 3600) % 24; minutes = (seconds / 60) % 60; secs = seconds % 60; // 计算日期 uint32_t days = total_seconds / (24 * 3600); seconds = total_seconds % (24 * 3600); // 更新seconds为剩余秒数 for (; days > 0; days--) { // 当前月份的天数 uint8_t days_in_month = 31; if (month == 2) { days_in_month = is_leap_year(year) ? 29 : 28; } else if (month == 4 || month == 6 || month == 9 || month == 11) { days_in_month = 30; } if (++day > days_in_month) { day = 1; if (++month > 12) { month = 1; year++; } } } // 将结果存储到结构体中 date->year = year; date->month = month; date->day = day; time->hour = hours; time->minute = minutes; time->second = secs; } // 计算一年中的第几天 uint16_t dayOfyear(uint16_t year, uint8_t month, uint8_t day) { uint8_t month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; uint16_t total; total = day; if (month > 2 && is_leap_year(year)) total += 1; for (uint8_t i = 0; i < month - 1; i++) { total += month_days[i]; } return total; } // 计算一年中的第几周 uint16_t weekOfyear(uint16_t year, uint8_t month, uint8_t day) { uint16_t day_of_year = dayOfyear(year, month, day); return (day_of_year - 1) / 7 + 1; } // 获取今天星期几 uint8_t get_weekday(uint16_t year, uint8_t month, uint8_t day) { uint8_t w = 0; if (month == 1 || month == 2) { month += 12; year--; } w = (day + 2 * month + 3 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400) % 7; return w + 1; } // 传入十六进制0x23 返回十进制23 uint8_t hex_format_dec(uint8_t hex) { char buf[4]; osel_memset((uint8_t *)buf, 0, 4); sprintf(buf, "%x", hex); int32_t dec = 0; int32_t weight = 1; int32_t len = strlen(buf); for (int32_t i = len - 1; i >= 0; i--) { if (buf[i] >= '0' && buf[i] <= '9') { dec += (buf[i] - '0') * weight; } else if (buf[i] >= 'A' && buf[i] <= 'F') { dec += (buf[i] - 'A' + 10) * weight; } else if (buf[i] >= 'a' && buf[i] <= 'f') { dec += (buf[i] - 'a' + 10) * weight; } weight *= 10; } return dec; } // 传入十进制23 返回十六进制0x23 uint8_t dec_format_hex(uint8_t dec) { char buf[4]; osel_memset((uint8_t *)buf, 0, 4); sprintf(buf, "%d", dec); uint8_t hex = 0; uint8_t len = strlen(buf); for (uint8_t i = 0; i < len; i++) { char c = buf[i]; if (c >= '0' && c <= '9') { hex = hex * 16 + (c - '0'); } else { continue; } } return hex; } /** * @brief 日期时间转时间戳 * @param {rtc_date_t} date * @param {rtc_time_t} time * @return {*} * @note 年份是从2000年开始的 */ uint32_t time2stamp(const rtc_date_t *const date, const rtc_time_t *const time) { uint32_t result; uint16_t year = date->year + 2000; // (time->hour - 0) * 3600 中的0改成8是北京时间的时区 result = (year - 1970) * 365 * 24 * 3600 + (_month_days[date->month - 1] + date->day - 1) * 24 * 3600 + (time->hour - 0) * 3600 + time->minute * 60 + time->second; result += (date->month > 2 && (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)) * 24 * 3600; // 闰月 year -= 1969; result += (year / 4 - year / 100 + year / 400) * 24 * 3600; // 闰年 return result; } /** * @brief 时间戳转日期时间 * @param {uint32_t} stamp * @param {rtc_date_t} *date * @param {rtc_time_t} *time * @return {*} * @note */ void stamp2time(uint32_t stamp, rtc_date_t *date, rtc_time_t *time) { uint32_t days; uint16_t leap_num; time->second = stamp % 60; stamp /= 60; // 获取分 time->minute = stamp % 60; // stamp += 8 * 60; // 不需要加8小时 stamp /= 60; // 获取小时 time->hour = stamp % 24; days = stamp / 24; leap_num = (days + 365) / 1461; if (((days + 366) % 1461) == 0) { date->year = (days / 366) + 1970 - 2000; date->month = 12; date->day = 31; } else { days -= leap_num; date->year = (days / 365) + 1970 - 2000; days %= 365; days += 1; if (((date->year % 4) == 0) && (days == 60)) { date->month = 2; date->day = 29; } else { if (((date->year % 4) == 0) && (days > 60)) --days; for (date->month = 0; _days[date->month] < days; date->month++) { days -= _days[date->month]; } ++date->month; date->day = days; } } } /**************************排序**************************/ static void swap(uint16_t *a, uint16_t *b) { uint16_t t = *a; *a = *b; *b = t; } static int32_t partition(uint16_t arr[], int32_t low, int32_t high) { uint16_t pivot = arr[high]; int32_t i = (low - 1); for (int32_t j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } // 快速排序 void quicksort(uint16_t arr[], int32_t low, int32_t high) { if (low < high) { int32_t pi = partition(arr, low, high); quicksort(arr, low, pi - 1); quicksort(arr, pi + 1, high); } } // 插入排序 数据集小的时候效率高 void insertion_sort(uint16_t arr[], uint16_t n) { uint16_t i, j; uint16_t key; for (i = 1; i < n; i++) { key = arr[i]; j = i; // 将大于key的元素向后移动一个位置 while (j > 0 && arr[j - 1] > key) { arr[j] = arr[j - 1]; j = j - 1; } arr[j] = key; } } /**************************线性拟合**************************/ /** * @brief 计算平均值 * * 根据给定的点集和指示标志,计算 X 或 Y 坐标的平均值。 * * @param points 点集指针 * @param count 点集数量 * @param isX 是否计算 X 坐标的平均值,为 1 则计算 X 坐标的平均值,为 0 则计算 Y 坐标的平均值 * * @return 返回计算得到的平均值 */ static float32 average(const point_t *points, int32_t count, int32_t isX) { float32 sum = 0.0f; for (int32_t i = 0; i < count; ++i) { sum += isX ? points[i].x : points[i].y; } return sum / count; } /** * @brief 计算线性回归函数值 * * 根据给定的 x 值和线性函数参数,计算并返回线性回归函数的值。 y = a * x + b * * @param x 输入的 x 值 * @param param 线性函数参数结构体,包含斜率 a 和截距 b * * @return 线性回归函数的值 */ static float32 calculate_linear_regression_func(float32 x, linear_func_param_t param) { return param.a * x + param.b; } /** * @brief 计算线性回归参数 * * 根据给定的数据点集合,计算线性回归的参数。 * * @param points 数据点集合指针 * @param count 数据点数量 * * @return 线性回归参数结构体 * * @note 如果数据点数量少于2,则会输出错误日志并断言失败 */ linear_func_param_t calculate_linear_regression(const point_t *points, int32_t count) { if (count < 2) { LOG_PRINT("参数points至少需要两组数据\n"); DBG_ASSERT(FALSE __DBG_LINE); } float32 xAverage = average(points, count, 1); float32 yAverage = average(points, count, 0); float32 sumXY = 0.0, sumXX = 0.0; for (int32_t i = 0; i < count; ++i) { float32 dX = points[i].x - xAverage; float32 dY = points[i].y - yAverage; sumXY += dX * dY; sumXX += dX * dX; } linear_func_param_t result; result.a = sumXY / sumXX; result.b = yAverage - result.a * xAverage; return result; } // 求线性度 公式 dYmax / Y * 100% float32 get_linearity_value(const point_t *points, int32_t count, linear_func_param_t param) { float32 dYMax = 0.0f; for (int32_t i = 0; i < count; ++i) { float32 y = calculate_linear_regression_func(points[i].x, param); float32 dY = ABS(y - points[i].y); if (dY > dYMax) dYMax = dY; } float32 yFirst = calculate_linear_regression_func(points[0].x, param); float32 yLast = calculate_linear_regression_func(points[count - 1].x, param); return dYMax / ABS(yLast - yFirst) * 100; } /** // 示例使用 int main() { point_t points[] = {{1, 2}, {2, 3}, {3, 4}}; // 示例点数组 int count = sizeof(points) / sizeof(points[0]); linear_func_param_t param = calculate_linear_regression(points, count); printf("Linear Regression: y = %f * x + %f\n", param.a, param.b); double linearity = get_linearity_value(points, count, param); printf("Linearity Value: %f%%\n", linearity); return 0; } */ /**************************线性拟合**************************/