/** * @file main.c * @brief Donghui ORPC OTA Application Firmware - Main Entry * * Application firmware for leisure boat / spa control system with * 4G Cat.1 OTA upgrade capability. * * Startup sequence: * 1. System init (HAL) * 2. AT driver init (4G module) * 3. Power on 4G module * 4. OTA Agent init (check for pending upgrade report) * 5. Main application control loop with OTA background task */ #include "stm32g4xx_hal.h" #include #include #include "firmware_map.h" #include "at_driver.h" #include "ota_agent.h" #include "spi_flash.h" /* ==================== Application state ==================== */ typedef struct { uint32_t sys_tick; /* System uptime in ms */ uint8_t app_state; /* Application state */ uint8_t error_code; /* Last error code */ uint32_t last_gpio_tick; /* LED heartbeat timer */ } App_Context_t; static App_Context_t g_app; /* GPIO pins */ #define LED_STATUS_PIN GPIO_PIN_0 /* PC0 */ #define LED_ERROR_PIN GPIO_PIN_1 /* PC1 */ #define LED_STATUS_PORT GPIOC #define LED_ERROR_PORT GPIOC /* Application states */ #define APP_STATE_INIT 0 #define APP_STATE_NET_INIT 1 #define APP_STATE_RUNNING 2 #define APP_STATE_UPGRADE 3 #define APP_STATE_ERROR 0xFF /* ==================== Forward declarations ==================== */ static void app_init(void); static void app_loop(void); static void gpio_init(void); static void gpio_heartbeat(void); static void flash_param_init(void); /* ==================== HAL Tick (SysTick) ==================== */ volatile uint32_t g_sys_tick = 0; void SysTick_Handler(void) { g_sys_tick++; } uint32_t HAL_GetTick(void) { return g_sys_tick; } void HAL_Delay(uint32_t ms) { uint32_t start = g_sys_tick; while ((g_sys_tick - start) < ms); } /* ==================== Application entry ==================== */ int main(void) { /* Clear BSS manually (already done in startup, but safe) */ app_init(); /* Heartbeat LED */ gpio_heartbeat(); /* Initialize OTA agent */ OTA_Agent_Init(); /* Power on 4G module and wait for readiness */ AT_Init(); AT_PowerOn(); if (AT_WaitReady(15000)) { /* Module is ready, check SIM and network */ AT_CheckSIM(); AT_CheckNetwork(); } /* Main control loop */ while (1) { app_loop(); } return 0; } /* ==================== Initialization ==================== */ static void app_init(void) { /* Reset app context */ memset(&g_app, 0, sizeof(g_app)); g_app.app_state = APP_STATE_INIT; /* Init HAL */ HAL_Init(); /* Init GPIO */ gpio_init(); /* Init SPI Flash */ FLASH_Init(); /* Check/correct boot params in case of corruption */ flash_param_init(); g_app.app_state = APP_STATE_NET_INIT; } static void gpio_init(void) { /* Enable GPIOC clock */ __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitTypeDef gpio = {0}; gpio.Pin = LED_STATUS_PIN | LED_ERROR_PIN; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_STATUS_PORT, &gpio); /* Start with both LEDs off */ HAL_GPIO_WritePin(LED_STATUS_PORT, LED_STATUS_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_ERROR_PORT, LED_ERROR_PIN, GPIO_PIN_SET); } static void flash_param_init(void) { BootParam_t param; const BootParam_t *p = (const BootParam_t *)PARAM_SECTOR_ADDR; /* Read param sector */ memcpy(¶m, p, sizeof(BootParam_t)); /* If corrupted, re-initialize */ if (param.magic != 0xA5A5A5A5 || param.tail_magic != 0x5A5A5A5A) { /* Will be handled by bootloader on next reset */ /* For now, just report error */ HAL_GPIO_WritePin(LED_ERROR_PORT, LED_ERROR_PIN, GPIO_PIN_RESET); } } /* ==================== Main loop ==================== */ static void app_loop(void) { uint32_t tick = HAL_GetTick(); /* Run OTA agent task every 100ms */ static uint32_t last_ota_tick = 0; if (tick - last_ota_tick >= 100) { last_ota_tick = tick; OTA_Agent_Task(); } /* Heartbeat LED toggle every 1 second */ if (tick - g_app.last_gpio_tick >= 1000) { g_app.last_gpio_tick = tick; gpio_heartbeat(); } /* Application-specific control logic goes here */ /* Boat motor control, battery management, communication, etc. */ /* Low-power idle if no OTA in progress */ if (!OTA_IsBusy()) { __WFI(); /* Wait for interrupt (wake by SysTick or UART) */ } } static void gpio_heartbeat(void) { static uint8_t toggle = 0; toggle = !toggle; if (OTA_IsBusy()) { /* Fast blink during OTA */ HAL_GPIO_WritePin(LED_STATUS_PORT, LED_STATUS_PIN, toggle ? GPIO_PIN_RESET : GPIO_PIN_SET); } else { /* Slow blink normal operation */ HAL_GPIO_TogglePin(LED_STATUS_PORT, LED_STATUS_PIN); } } /* ==================== HAL MSP Init (weak, needed by HAL) ==================== */ void HAL_MspInit(void) { /* Configure priority grouping */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); }