Files
VivaMyo-firmware-test/project/ble_peripheral/ble_app_vivaMayo/main.c
2026-04-08 16:59:20 +09:00

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();
}
}