Add reusable firmware info module
This commit is contained in:
121
c/firmware-info/src/firmware_info.c
Normal file
121
c/firmware-info/src/firmware_info.c
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "firmware_info.h"
|
||||
|
||||
static const char months[12][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
static int is_digit(char value) { return (value >= '0') && (value <= '9'); }
|
||||
|
||||
static int two_digits(const char *text, uint8_t *result)
|
||||
{
|
||||
char high = text[0];
|
||||
char low = text[1];
|
||||
if (high == ' ') high = '0';
|
||||
if (!is_digit(high) || !is_digit(low)) return 0;
|
||||
*result = (uint8_t)(((uint8_t)(high - '0') * 10U) + (uint8_t)(low - '0'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int four_digits(const char *text, uint16_t *result)
|
||||
{
|
||||
uint16_t value = 0U;
|
||||
uint8_t i;
|
||||
for (i = 0U; i < 4U; ++i) {
|
||||
if (!is_digit(text[i])) return 0;
|
||||
value = (uint16_t)(value * 10U + (uint16_t)(text[i] - '0'));
|
||||
}
|
||||
*result = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
firmware_info_status_t firmware_info_validate(const firmware_info_t *info)
|
||||
{
|
||||
uint8_t i;
|
||||
if (info == NULL) return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
if ((info->major > 255U) || (info->minor > 255U) || (info->patch > 999U)
|
||||
|| (info->year < 2000U) || (info->year > 2199U)
|
||||
|| (info->month < 1U) || (info->month > 12U)
|
||||
|| (info->day < 1U) || (info->day > 31U)
|
||||
|| (info->hour > 23U) || (info->minute > 59U) || (info->second > 59U)) {
|
||||
return FIRMWARE_INFO_OUT_OF_RANGE;
|
||||
}
|
||||
for (i = 0U; i < FIRMWARE_INFO_BUILD_ID_SIZE; ++i) {
|
||||
if ((info->build_id[i] < 0x20) || (info->build_id[i] > 0x7e))
|
||||
return FIRMWARE_INFO_OUT_OF_RANGE;
|
||||
}
|
||||
return FIRMWARE_INFO_OK;
|
||||
}
|
||||
|
||||
firmware_info_status_t firmware_info_set_build_id(firmware_info_t *info,
|
||||
const char *build_id)
|
||||
{
|
||||
uint8_t i;
|
||||
if ((info == NULL) || (build_id == NULL)) return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
for (i = 0U; i < FIRMWARE_INFO_BUILD_ID_SIZE && build_id[i] != '\0'; ++i) {
|
||||
if ((build_id[i] < 0x20) || (build_id[i] > 0x7e))
|
||||
return FIRMWARE_INFO_OUT_OF_RANGE;
|
||||
info->build_id[i] = build_id[i];
|
||||
}
|
||||
for (; i < FIRMWARE_INFO_BUILD_ID_SIZE; ++i) info->build_id[i] = '0';
|
||||
info->build_id[FIRMWARE_INFO_BUILD_ID_SIZE] = '\0';
|
||||
return FIRMWARE_INFO_OK;
|
||||
}
|
||||
|
||||
firmware_info_status_t firmware_info_parse_build_stamp(
|
||||
const char *date_text, const char *time_text, firmware_info_t *info)
|
||||
{
|
||||
uint8_t month;
|
||||
uint8_t found = 0U;
|
||||
if ((date_text == NULL) || (time_text == NULL) || (info == NULL))
|
||||
return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
for (month = 0U; month < 12U; ++month) {
|
||||
if ((date_text[0] == months[month][0]) && (date_text[1] == months[month][1])
|
||||
&& (date_text[2] == months[month][2])) { found = 1U; break; }
|
||||
}
|
||||
if (!found || !two_digits(&date_text[4], &info->day)
|
||||
|| !four_digits(&date_text[7], &info->year)
|
||||
|| !two_digits(&time_text[0], &info->hour)
|
||||
|| !two_digits(&time_text[3], &info->minute)
|
||||
|| !two_digits(&time_text[6], &info->second)) return FIRMWARE_INFO_OUT_OF_RANGE;
|
||||
info->month = (uint8_t)(month + 1U);
|
||||
return FIRMWARE_INFO_OK;
|
||||
}
|
||||
|
||||
firmware_info_status_t firmware_info_to_registers(
|
||||
const firmware_info_t *info, uint16_t *registers, size_t count)
|
||||
{
|
||||
uint8_t i;
|
||||
firmware_info_status_t status;
|
||||
if ((registers == NULL) || (count < FIRMWARE_INFO_REGISTER_COUNT))
|
||||
return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
status = firmware_info_validate(info);
|
||||
if (status != FIRMWARE_INFO_OK) return status;
|
||||
registers[0] = FIRMWARE_INFO_CONTRACT_VERSION;
|
||||
registers[1] = info->major; registers[2] = info->minor; registers[3] = info->patch;
|
||||
registers[4] = info->year;
|
||||
registers[5] = (uint16_t)(((uint16_t)info->month << 8U) | info->day);
|
||||
registers[6] = (uint16_t)(((uint16_t)info->hour << 8U) | info->minute);
|
||||
registers[7] = info->second;
|
||||
for (i = 0U; i < 4U; ++i)
|
||||
registers[8U + i] = (uint16_t)(((uint16_t)(uint8_t)info->build_id[i * 2U] << 8U)
|
||||
| (uint8_t)info->build_id[i * 2U + 1U]);
|
||||
return FIRMWARE_INFO_OK;
|
||||
}
|
||||
|
||||
firmware_info_status_t firmware_info_to_le_bytes(
|
||||
const firmware_info_t *info, uint8_t *payload, size_t size)
|
||||
{
|
||||
uint16_t words[FIRMWARE_INFO_REGISTER_COUNT];
|
||||
uint8_t i;
|
||||
firmware_info_status_t status;
|
||||
if ((payload == NULL) || (size < FIRMWARE_INFO_PAYLOAD_SIZE))
|
||||
return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
status = firmware_info_to_registers(info, words, FIRMWARE_INFO_REGISTER_COUNT);
|
||||
if (status != FIRMWARE_INFO_OK) return status;
|
||||
for (i = 0U; i < FIRMWARE_INFO_REGISTER_COUNT; ++i) {
|
||||
payload[i * 2U] = (uint8_t)words[i];
|
||||
payload[i * 2U + 1U] = (uint8_t)(words[i] >> 8U);
|
||||
}
|
||||
return FIRMWARE_INFO_OK;
|
||||
}
|
||||
13
c/firmware-info/src/firmware_info_port.c
Normal file
13
c/firmware-info/src/firmware_info_port.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "firmware_info_port.h"
|
||||
|
||||
firmware_info_status_t firmware_info_port_describe(firmware_info_t *info)
|
||||
{
|
||||
firmware_info_status_t status;
|
||||
if (info == NULL) return FIRMWARE_INFO_INVALID_ARGUMENT;
|
||||
info->major = (uint16_t)FIRMWARE_VERSION_MAJOR;
|
||||
info->minor = (uint16_t)FIRMWARE_VERSION_MINOR;
|
||||
info->patch = (uint16_t)FIRMWARE_VERSION_PATCH;
|
||||
status = firmware_info_set_build_id(info, FIRMWARE_BUILD_ID);
|
||||
if (status != FIRMWARE_INFO_OK) return status;
|
||||
return firmware_info_parse_build_stamp(__DATE__, __TIME__, info);
|
||||
}
|
||||
Reference in New Issue
Block a user