Вынеси программные часы, коррекцию по ProtoCAN RTCSETUP и атомарную метку логгера в переносимое ядро без глобального состояния. Подключи eCAN-A и CPU Timer2 отдельным портом F28335; зафиксируй календарные границы, переполнение, задержку RX и защиту IRQ в хостовых тестах.
66 lines
8.7 KiB
C
66 lines
8.7 KiB
C
#ifndef GLOBAL_TIME_H /* Защищает единый контракт часов от повторного включения. */
|
||
#define GLOBAL_TIME_H /* Отмечает подключённый интерфейс программных глобальных часов. */
|
||
#include <stdint.h> /* Фиксирует разрядность счётчиков и поддерживает 16-битный char TI C28x. */
|
||
#ifdef __cplusplus /* Сохраняет совместимость C-библиотеки с приложениями C++. */
|
||
extern "C" { /* Экспортирует функции без изменения имён компилятором C++. */
|
||
#endif /* Завершает условное объявление C ABI. */
|
||
#define GT_RTC_ID 0x00000030UL /* ProtoCAN: Route=0, Type/ID=0, BROADCAST=0, RTCSETUP=3 в Body[15:4]. */
|
||
#define GT_READY_BODY 0x3000U /* Контракт GLOBAL_TIME.md: DISCRETE/FLAGS=3, страница общих флагов=0. */
|
||
#define GT_READY_RETRY_MS 1000UL /* Повторяет сообщение готовности раз в секунду до первой синхронизации. */
|
||
typedef struct gt_frame { /* Описывает classic CAN независимо от регистров и размера char процессора. */
|
||
uint32_t id; /* Хранит только 29 бит идентификатора, без служебных битов драйвера. */
|
||
uint16_t extended; /* Единица означает IDE=1; стандартные кадры часы игнорируют. */
|
||
uint16_t remote; /* Единица означает RTR; удалённый запрос не содержит время. */
|
||
uint16_t dlc; /* Считает октеты на линии, а не sizeof элементов массива C28x. */
|
||
uint16_t data[8]; /* Каждый элемент содержит один октет 0..255 даже при CHAR_BIT=16. */
|
||
} gt_frame; /* Завершает переносимый контейнер кадра. */
|
||
typedef struct gt_datetime { /* Представляет календарь без зависимости от time_t и часового пояса ОС. */
|
||
uint16_t year; /* Полный год; входной ProtoCAN поддерживает 2000..2099. */
|
||
uint16_t month; /* Номер месяца 1..12, без BCD-кодирования. */
|
||
uint16_t day; /* Число месяца с проверкой високосного февраля. */
|
||
uint16_t weekday; /* День недели 0..6; профиль использует 0=воскресенье, 1=понедельник. */
|
||
uint16_t hour; /* Часы 0..23 в 24-часовом формате. */
|
||
uint16_t minute; /* Минуты 0..59; leap seconds протокол не передаёт. */
|
||
uint16_t second; /* Секунды 0..59 согласно существующему RTCSETUP. */
|
||
uint16_t millisecond; /* Доля секунды 0..999; RTCSETUP задаёт нулевую долю. */
|
||
} gt_datetime; /* Завершает публичный календарный тип. */
|
||
typedef struct gt_stamp { /* Даёт логгеру согласованную метку и её качество одним чтением. */
|
||
uint32_t seconds; /* Секунды от 2000-01-01 00:00:00 в шкале времени мастера. */
|
||
uint16_t millisecond; /* Миллисекундная доля текущей секунды. */
|
||
uint16_t synchronized; /* Ноль до первого корректного RTCSETUP, единица после него. */
|
||
uint32_t uptime_ms; /* Независимый счётчик работы modulo 2^32; коррекции его не меняют. */
|
||
uint32_t sync_uptime_ms; /* Момент приёма последнего RTCSETUP для оценки давности синхронизации. */
|
||
uint32_t generation; /* Число коррекций; логгер отличает участки до и после перевода часов. */
|
||
int64_t correction_ms; /* Последнее смещение новых часов относительно старых, в миллисекундах. */
|
||
uint16_t weekday; /* Принятый день недели, продвигаемый при каждом переходе через полночь. */
|
||
} gt_stamp; /* Завершает атомарно читаемый снимок. */
|
||
typedef struct gt_port { /* Передаёт ядру короткие критические секции и неблокирующую отправку CAN. */
|
||
void *user; /* Контекст платформы, передаваемый каждому callback без преобразования. */
|
||
uint16_t (*enter)(void *user); /* Запрещает IRQ и возвращает прежнее состояние для вложенных вызовов. */
|
||
void (*leave)(void *user, uint16_t state); /* Восстанавливает прежнее состояние IRQ, включая вызовы из ISR. */
|
||
int (*send)(void *user, const gt_frame *frame); /* Копирует кадр до возврата; 1=принят, 0=занято/ошибка. */
|
||
} gt_port; /* Завершает платформенный контракт; heap и аппаратный RTC не нужны. */
|
||
typedef struct gt_clock { /* Хранит состояние одного узла; инициализация обязательна до разрешения ISR. */
|
||
gt_port port; /* Содержит проверенные callbacks и контекст платформы. */
|
||
volatile gt_stamp stamp; /* Меняется только при удержании блокировки IRQ. */
|
||
uint16_t device_type; /* Три адресных бита ProtoCAN, диапазон 0..7. */
|
||
uint16_t device_id; /* Четыре адресных бита экземпляра, диапазон 0..15. */
|
||
uint16_t ready; /* Устанавливается приложением после завершения всей инициализации платы. */
|
||
uint16_t announced; /* Помнит принятую транспортом отправку готовности, даже если часы уже синхронизированы. */
|
||
uint32_t sent_uptime_ms; /* Ограничивает частоту повторов готовности монотонной шкалой. */
|
||
} gt_clock; /* Состояние допускает статическое выделение памяти на микроконтроллере. */
|
||
int gt_init(gt_clock *clock, const gt_port *port, uint16_t device_type, uint16_t device_id); /* Проверяет адрес/callbacks и явно очищает RAM, включая TI COFF. */
|
||
void gt_tick_1ms(gt_clock *clock); /* Вызывается ровно один раз за аппаратную миллисекунду и выполняет только короткую арифметику. */
|
||
void gt_get(gt_clock *clock, gt_stamp *out); /* Атомарно копирует всю метку; допустим вызов из main, логгера и ISR. */
|
||
void gt_ready(gt_clock *clock); /* Идемпотентно разрешает сообщение «плата инициализирована»; CAN отправляется из poll. */
|
||
void gt_poll(gt_clock *clock); /* Вызывается единственным потребителем в main; не ждёт освобождения CAN. */
|
||
int gt_receive(gt_clock *clock, const gt_frame *frame, uint32_t received_uptime_ms); /* Проверяет RTCSETUP и компенсирует задержку от приёма до обработки, менее 2^32 мс. */
|
||
int gt_make_rtc(const gt_datetime *date, gt_frame *out); /* Даёт верхнему уровню кодировщик штатного 7-октетного broadcast. */
|
||
int gt_parse_ready(const gt_frame *frame, uint16_t *device_type, uint16_t *device_id); /* Позволяет мастеру распознать готовность и выбрать ответ RTCSETUP. */
|
||
int gt_calendar(const gt_stamp *stamp, gt_datetime *out); /* Преобразует согласованный снимок в календарь; до синхронизации возвращает 0. */
|
||
uint64_t gt_timestamp_ms(const gt_stamp *stamp); /* Возвращает широкую метку от 2000 года без переполнения через 49,7 суток. */
|
||
#ifdef __cplusplus /* Закрывает C ABI только для компилятора C++. */
|
||
} /* Завершает блок функций с C-связыванием. */
|
||
#endif /* Завершает проверку языка потребителя. */
|
||
#endif /* Завершает защиту публичного заголовка. */
|