408 lines
14 KiB
C
408 lines
14 KiB
C
/*******************************************************************************
|
|
* @file main.c
|
|
* @brief MEDiThings VivaMayo - Main Application Entry Point
|
|
* @author Charles KWON <charleskwon@medithings.co.kr>
|
|
* @date 2025-01-30
|
|
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
|
*
|
|
* @version 1.17
|
|
* @note 2025-01-30 Refactored into modular structure (Charles KWON)
|
|
* @note 2025-12-31 Added comprehensive function documentation (Charles KWON)
|
|
* @note 2025-11-27 Firmware cleanup and refactoring (Charles KWON)
|
|
******************************************************************************/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "debug_print.h"
|
|
#include "app_uart.h"
|
|
|
|
/* Nordic SDK */
|
|
#include "nordic_common.h"
|
|
#include "nrf.h"
|
|
#include "nrf_gpio.h"
|
|
#include "nrf_sdh.h"
|
|
#include "nrf_sdh_soc.h"
|
|
#include "nrf_sdh_ble.h"
|
|
#include "nrf_pwr_mgmt.h"
|
|
#include "nrf_delay.h"
|
|
#include "nrf_log.h"
|
|
#include "nrf_log_ctrl.h"
|
|
#include "nrf_log_default_backends.h"
|
|
#include "app_timer.h"
|
|
#include "app_error.h"
|
|
#include "bsp.h"
|
|
#include "bsp_btn_ble.h"
|
|
#include "ble_nus.h"
|
|
|
|
/* Application Modules */
|
|
#include "ble/ble_core.h"
|
|
#include "ble/ble_services.h"
|
|
#include "ble/ble_data_tx.h"
|
|
#include "power/power_ctrl.h"
|
|
#include "peripheral/uart_handler.h"
|
|
#include "config/device_config.h"
|
|
|
|
#if FEATURE_SECURE_CONNECTION
|
|
#include "ble/ble_security.h"
|
|
#include "nrf_ble_lesc.h"
|
|
#endif
|
|
|
|
/* Hardware and Measurement Modules */
|
|
#include "main.h"
|
|
#include "main_timer.h"
|
|
#include "battery_saadc.h"
|
|
#include "measurements.h"
|
|
#include "full_agc.h"
|
|
#include "meas_pd_voltage_simple.h"
|
|
#include "meas_pd_voltage_half.h"
|
|
/* #include "meas_pd_voltage_full.h" */ /* Moved to unuse/ - FEATURE_PRINTF=0, not used */
|
|
#include "meas_pd_voltage_custom.h"
|
|
#include "meas_pd_imm.h"
|
|
#include "meas_pd_48.h"
|
|
#include "power_control.h"
|
|
#include "cat_interface.h"
|
|
#include "fstorage.h"
|
|
#include "drivers/w25q32/w25q32.h"
|
|
|
|
/* Crypto */
|
|
#include "nrf_crypto.h"
|
|
|
|
/*******************************************************************************
|
|
* @section BUILD_CONFIG Build Configuration
|
|
* @brief Compile-time feature flags and debug settings
|
|
* @details Controls boot mode selection between minimal (Power+BLE only) and
|
|
* full initialization (includes EEPROM and all peripherals).
|
|
|
|
* Set DEBUG_MINIMAL_BOOT=1 for rapid debugging without EEPROM dependency.
|
|
******************************************************************************/
|
|
|
|
#define DEBUG_MINIMAL_BOOT 1 /**< 1: Power+BLE only (no EEPROM), 0: Full boot */
|
|
|
|
/*******************************************************************************
|
|
* @section CONSTANTS Symbolic Constants
|
|
* @brief Application-wide constant definitions
|
|
* @details Magic numbers and compile-time constants used for error handling,
|
|
* fault detection, and system-level operations.
|
|
******************************************************************************/
|
|
|
|
#define DEAD_BEEF 0xDEADBEEF
|
|
|
|
/*******************************************************************************
|
|
* @section GLOBALS Global Variables
|
|
* @brief Shared runtime state and data buffers
|
|
* @details BLE transmission buffers, command type state, and cross-module
|
|
* flags. External declarations reference state from other modules.
|
|
* @warning Global state should be accessed with care in interrupt context.
|
|
******************************************************************************/
|
|
|
|
char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
|
|
uint16_t ble_bin_buff[BLE_NUS_MAX_DATA_LEN/2];
|
|
which_cmd_t cmd_type_t;
|
|
|
|
/* External state flags from other modules */
|
|
extern bool ble_got_new_data;
|
|
extern bool motion_data_once;
|
|
extern bool adc_enabled;
|
|
extern bool con_single;
|
|
extern bool info4;
|
|
extern uint8_t add_cycle;
|
|
extern bool motion_raw_data_enabled;
|
|
|
|
/*******************************************************************************
|
|
* @section FWD_DECL Forward Declarations
|
|
* @brief Static function prototypes
|
|
* @details Internal initialization and handler functions declared here for
|
|
* proper ordering. Visibility limited to this translation unit.
|
|
******************************************************************************/
|
|
|
|
static void timers_init(void);
|
|
static void log_init(void);
|
|
static void power_management_init(void);
|
|
static void buttons_leds_init(bool * p_erase_bonds);
|
|
#if !DEBUG_MINIMAL_BOOT
|
|
static void gpio_init(void);
|
|
#endif
|
|
static void idle_state_handle(void);
|
|
|
|
/*******************************************************************************
|
|
* @section ASSERT Assert Handler
|
|
* @brief System fault callback for SDK assertions
|
|
* @details Invoked by Nordic SDK on fatal errors. Provides fault location
|
|
* (file and line) for debugging via app_error_handler.
|
|
******************************************************************************/
|
|
|
|
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
|
|
{
|
|
app_error_handler(DEAD_BEEF, line_num, p_file_name);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section INIT Initialization Functions
|
|
* @brief System and peripheral initialization routines
|
|
* @details Configures logging, power management, timers, and BSP components.
|
|
* Call order is critical - see main() for proper sequencing.
|
|
******************************************************************************/
|
|
|
|
static void log_init(void)
|
|
{
|
|
ret_code_t err_code = NRF_LOG_INIT(NULL);
|
|
APP_ERROR_CHECK(err_code);
|
|
NRF_LOG_DEFAULT_BACKENDS_INIT();
|
|
}
|
|
|
|
static void power_management_init(void)
|
|
{
|
|
ret_code_t err_code;
|
|
err_code = nrf_pwr_mgmt_init();
|
|
APP_ERROR_CHECK(err_code);
|
|
}
|
|
|
|
static void timers_init(void)
|
|
{
|
|
ret_code_t err_code = app_timer_init();
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
/* Power control timers */
|
|
power_ctrl_timers_init();
|
|
|
|
/* Application timers */
|
|
main_timer_init();
|
|
battery_timer_init();
|
|
imm_check_timer_init();
|
|
m48_check_timer_init();
|
|
full_agc_timer_init();
|
|
full_agc_send_timer_init();
|
|
mea_send_timer_init();
|
|
power_timer_init();
|
|
w25q_test_timer_init();
|
|
|
|
/* full_timer_init() - Moved to unuse/, FEATURE_PRINTF=0 so not used */
|
|
}
|
|
|
|
static void buttons_leds_init(bool * p_erase_bonds)
|
|
{
|
|
bsp_event_t startup_event;
|
|
|
|
uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, power_bsp_event_handler);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
err_code = bsp_btn_ble_init(NULL, &startup_event);
|
|
APP_ERROR_CHECK(err_code);
|
|
|
|
*p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section PWR_HOLD Power Hold Initialization
|
|
* @brief Latches power supply on boot
|
|
* @details Configures P0.08 (POWER_HOLD) as output HIGH to maintain VCC.
|
|
* CRITICAL: Must be the first call in main() - any delay risks
|
|
* power loss if button is released before latch is set.
|
|
* @note Uses direct register access for minimum latency.
|
|
******************************************************************************/
|
|
static void power_hold_init(void)
|
|
{
|
|
/* P0.08 = POWER_HOLD, configure as output and set HIGH to maintain power */
|
|
NRF_P0->DIRSET = (1 << 8);
|
|
NRF_P0->OUTSET = (1 << 8);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section MIN_GPIO Minimal GPIO Initialization (Debug Mode)
|
|
* @brief Reduced GPIO setup for rapid debugging
|
|
* @details Initializes only essential pins: POWER_BUTTON input, POWER_HOLD
|
|
* output, and power control GPIOs. Skips LEDs, PD array, gain
|
|
* switches, and EEPROM control for faster boot.
|
|
* @pre DEBUG_MINIMAL_BOOT must be set to 1
|
|
******************************************************************************/
|
|
static void minimal_gpio_init(void)
|
|
{
|
|
nrf_gpio_cfg_input(POWER_BUTTON, NRF_GPIO_PIN_NOPULL);
|
|
nrf_gpio_cfg_output(POWER_HOLD);
|
|
nrf_gpio_pin_set(POWER_HOLD);
|
|
power_gpio_init();
|
|
LOG_PRINTF("[GPIO] Minimal OK\r\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section MIN_CFG Default Configuration Loader (Debug Mode)
|
|
* @brief Loads hardcoded defaults bypassing EEPROM
|
|
* @details Sets factory defaults for serial number, passkey, PD timing,
|
|
* and bonding state. Used when EEPROM is unavailable or for
|
|
* rapid iteration during development.
|
|
* @pre DEBUG_MINIMAL_BOOT must be set to 1
|
|
******************************************************************************/
|
|
static void load_default_config(void)
|
|
{
|
|
/* Direct assignment of variables defined in device_config.h */
|
|
memset(SERIAL_NO, 0, sizeof(SERIAL_NO));
|
|
memcpy(SERIAL_NO, "2025VIVAM00001", 14);
|
|
|
|
memset(m_static_passkey, 0, sizeof(m_static_passkey));
|
|
memcpy(m_static_passkey, "123456", 6);
|
|
|
|
m_pd_delay_us = 8000;
|
|
m_pd_adc_cnt = 8;
|
|
bond_data_delete = true;
|
|
|
|
LOG_PRINTF("[CFG] Default (S/N=%s)\r\n", SERIAL_NO);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section FULL_GPIO Full GPIO Initialization (Production Mode)
|
|
* @brief Complete peripheral GPIO configuration
|
|
* @details Initializes all hardware interfaces: LEDs, photodiode array (PD),
|
|
* trigger switches, AGC gain control, power management, and EEPROM.
|
|
* All outputs are set to safe default states (LEDs off, PD off).
|
|
* @pre DEBUG_MINIMAL_BOOT must be set to 0
|
|
******************************************************************************/
|
|
#if !DEBUG_MINIMAL_BOOT
|
|
static void gpio_init(void)
|
|
{
|
|
nrf_gpio_cfg_input(POWER_BUTTON, NRF_GPIO_PIN_NOPULL);
|
|
|
|
LED_CONFIG();
|
|
LED_ALLOFF();
|
|
|
|
PD_CONFIG();
|
|
PD_ALLOFF();
|
|
|
|
trig_r_CONFIG();
|
|
trig_SW(false);
|
|
|
|
GAIN_SW_CONFIG();
|
|
AGC_GAIN_SW(false);
|
|
|
|
power_gpio_init();
|
|
eeprom_control(OFF);
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* @section IDLE Idle State Handler
|
|
* @brief Low-power idle loop processing
|
|
* @details Handles security operations (LESC if enabled), flushes NRF_LOG
|
|
* buffer, then enters System ON sleep via nrf_pwr_mgmt_run().
|
|
* CPU wakes on any enabled interrupt (BLE, timer, GPIO).
|
|
******************************************************************************/
|
|
|
|
static void idle_state_handle(void)
|
|
{
|
|
#if FEATURE_SECURE_CONNECTION
|
|
security_idle_state_handle();
|
|
#endif
|
|
|
|
if (NRF_LOG_PROCESS() == false) {
|
|
nrf_pwr_mgmt_run();
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* @section MAIN Application Entry Point
|
|
* @brief System initialization and main loop
|
|
* @details Boot sequence: Power latch → UART → Logging → GPIO → Timers →
|
|
* Config → BSP → Power Mgmt → BLE Stack → GAP → GATT → Services →
|
|
* Advertising → Connection Params → Power Button Handler.
|
|
* Main loop runs idle_state_handle() for low-power operation.
|
|
* @note Initialization order is critical for proper hardware bringup.
|
|
******************************************************************************/
|
|
|
|
/* LED slow blink macro (approximately 0.5 second period) */
|
|
#define LED_BLINK() do { \
|
|
NRF_P0->OUTSET = (1 << 12); \
|
|
for (volatile uint32_t _d = 0; _d < 1000000; _d++); \
|
|
NRF_P0->OUTCLR = (1 << 12); \
|
|
for (volatile uint32_t _d = 0; _d < 1000000; _d++); \
|
|
} while(0)
|
|
|
|
#define LED_PAUSE() do { \
|
|
for (volatile uint32_t _d = 0; _d < 2000000; _d++); \
|
|
} while(0)
|
|
|
|
int main(void)
|
|
{
|
|
#if FEATURE_SECURE_CONNECTION
|
|
bool erase_bonds_local = false;
|
|
#endif
|
|
|
|
/* Configure LED output (P0.12) */
|
|
NRF_P0->DIRSET = (1 << 12);
|
|
|
|
power_hold_init();
|
|
|
|
if (power_off_duble_prohibit) return 0;
|
|
cnt_s = 0;
|
|
|
|
uart_handler_init();
|
|
nrf_delay_ms(100); /* Wait for UART peripheral stabilization */
|
|
log_init();
|
|
|
|
g_log_enable = true; /* Enable boot logging (set to false to disable boot logs) */
|
|
|
|
LOG_PRINTF("\r\n\r\n");
|
|
LOG_PRINTF("========================================\r\n");
|
|
LOG_PRINTF(" vivaMayo UART OK\r\n");
|
|
LOG_PRINTF("========================================\r\n");
|
|
|
|
#if DEBUG_MINIMAL_BOOT
|
|
LOG_PRINTF("[1] GPIO (minimal)\r\n");
|
|
minimal_gpio_init();
|
|
#else
|
|
LOG_PRINTF("[1] GPIO (full)\r\n");
|
|
gpio_init();
|
|
#endif
|
|
info4 = false;
|
|
|
|
LOG_PRINTF("[2] Timers\r\n");
|
|
timers_init();
|
|
|
|
LOG_PRINTF("[4] Buttons/LEDs\r\n");
|
|
#if FEATURE_SECURE_CONNECTION
|
|
buttons_leds_init(&erase_bonds_local);
|
|
erase_bonds = erase_bonds_local;
|
|
#else
|
|
bool dummy_erase;
|
|
buttons_leds_init(&dummy_erase);
|
|
#endif
|
|
|
|
LOG_PRINTF("[5] PWR\r\n"); nrf_delay_ms(10);
|
|
power_management_init();
|
|
LOG_PRINTF("[6] BLE\r\n"); nrf_delay_ms(10);
|
|
ble_stack_init();
|
|
|
|
/* Flash Storage - must be after BLE stack (SoftDevice required) */
|
|
/* and before GAP params (to use loaded config for device name) */
|
|
LOG_PRINTF("[6.5] FDS\r\n"); nrf_delay_ms(10);
|
|
fs_storage_init();
|
|
config_load();
|
|
|
|
LOG_PRINTF("[6.6] Config\r\n");
|
|
load_device_configuration();
|
|
|
|
/* W25Q32 Flash - NOT initialized during boot
|
|
* Initialize via BLE command after advertising starts
|
|
* (부팅 시 SPIM + BSP 이벤트 충돌로 SYSTEM OFF 발생 방지) */
|
|
|
|
LOG_PRINTF("[7] GAP\r\n"); nrf_delay_ms(10);
|
|
gap_params_init();
|
|
gatt_init();
|
|
services_init();
|
|
LOG_PRINTF("[8] ADV\r\n"); nrf_delay_ms(10);
|
|
advertising_init();
|
|
conn_params_init();
|
|
power_ctrl_timers_start();
|
|
/* advertising_start() is invoked from power_ctrl.c after 5ms delay */
|
|
|
|
nrf_delay_ms(20);
|
|
LOG_PRINTF("=== READY ===\r\n");
|
|
|
|
/*----------------------------------------------------------
|
|
* Main Loop: Idle State Handler
|
|
*----------------------------------------------------------*/
|
|
for (;;)
|
|
{
|
|
idle_state_handle();
|
|
}
|
|
}
|