Initial commit

This commit is contained in:
2026-04-24 10:52:47 +09:00
commit 1707dc6349
1423 changed files with 1161776 additions and 0 deletions
@@ -0,0 +1,33 @@
// file: debug_print.h
/*******************************************************************************
* Debug print macros (conditional compilation)
*
* Debug output macros using SEGGER RTT (Real Time Transfer).
* Sends logs to the PC in real time via J-Link debugger.
* Minimal impact on system timing since UART is not used.
*
* === Conditional compilation ===
* ENABLE_PRINTF = 1: DBG_PRINTF maps to SEGGER_RTT_printf (channel 0)
* -> Actual log output (for debugging)
* ENABLE_PRINTF = 0: DBG_PRINTF maps to an empty macro
* -> Completely removed from code (for release builds)
*
* === Usage ===
* DBG_PRINTF("val: %d\r\n", value); // Same format string as printf
* View output in SEGGER RTT Viewer or J-Link RTT Client.
******************************************************************************/
#ifndef DEBUG_PRINT_H
#define DEBUG_PRINT_H
#define ENABLE_PRINTF 1 /* 1=Enable debug output, 0=Disable globally */
#if ENABLE_PRINTF
#include "SEGGER_RTT.h"
/* Print formatted string to SEGGER RTT channel 0 */
#define DBG_PRINTF(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
/* Empty macro: compiler removes all call-site code */
#define DBG_PRINTF(...) // Do nothing
#endif
#endif // DEBUG_PRINT_H
@@ -0,0 +1,292 @@
/*******************************************************************************
* @file led_control.c
* @brief Direct LED control driver
* @date 2026-03-30
*
* Implements dual-color LED (green/orange) blink patterns with a single app_timer.
* Simple on/off states use immediate GPIO control without a timer.
* Complex patterns (e.g. error) are handled by a phase-based state machine.
******************************************************************************/
#include "led_control.h"
#include "nrf_gpio.h"
#include "app_timer.h"
/*==============================================================================
* Internal constants
*============================================================================*/
#define MS_TO_TICKS(ms) APP_TIMER_TICKS(ms)
/*==============================================================================
* Colors
*============================================================================*/
#define COLOR_NONE 0
#define COLOR_GREEN 1
#define COLOR_ORANGE 2
/*==============================================================================
* Error pattern constants (No.7)
* 3Hz blink x3 = 166ms on + 166ms off x 3 = ~1s, then off for 1s
*============================================================================*/
#define ERROR_BLINK_ON_MS 166
#define ERROR_BLINK_OFF_MS 166
#define ERROR_BLINK_COUNT 3
#define ERROR_PAUSE_MS 1000
/*==============================================================================
* Pattern table (for simple blink)
*============================================================================*/
typedef struct
{
uint32_t on_ms; /* LED on duration (ms) */
uint32_t off_ms; /* LED off duration (ms) */
uint8_t color; /* COLOR_GREEN or COLOR_ORANGE */
bool repeat; /* true: repeat forever, false: once then OFF */
} led_pattern_t;
static const led_pattern_t m_patterns[LED_STATE_COUNT] =
{
[LED_STATE_OFF] = { 0, 0, COLOR_NONE, false },
[LED_STATE_POWER_ON] = { 2000, 0, COLOR_GREEN, false }, /* Green on 2s, stay on */
[LED_STATE_POWER_OFF] = { 2000, 0, COLOR_GREEN, false }, /* Green on 2s, then OFF */
[LED_STATE_ADVERTISING] = { 500, 500, COLOR_GREEN, true }, /* Green blink 1s interval */
[LED_STATE_DETACH_WARNING] = { 1000, 3000, COLOR_GREEN, true }, /* Green 1s on / 3s off */
[LED_STATE_ALIGN_SEARCHING] = { 1000, 1000, COLOR_ORANGE, true }, /* Orange blink 1s interval */
[LED_STATE_ALIGN_COMPLETE] = { 3000, 1000, COLOR_GREEN, true }, /* Green 3s on / 1s off */
[LED_STATE_ERROR] = { 0, 0, COLOR_ORANGE, true } /* Separate state machine */
};
/*==============================================================================
* Module variables
*============================================================================*/
APP_TIMER_DEF(m_led_timer);
static led_state_t m_current_state = LED_STATE_OFF;
static bool m_phase_on; /* true: LED on phase, false: off phase */
/* Error pattern only */
static uint8_t m_error_blink_cnt; /* Blink count so far */
static uint8_t m_error_phase; /* 0: blink-on, 1: blink-off, 2: pause */
/*==============================================================================
* GPIO helpers
*============================================================================*/
static inline void led_green_on(void)
{
#if LED_ACTIVE_LOW
nrf_gpio_pin_clear(LED_PIN_GREEN);
#else
nrf_gpio_pin_set(LED_PIN_GREEN);
#endif
}
static inline void led_green_off(void)
{
#if LED_ACTIVE_LOW
nrf_gpio_pin_set(LED_PIN_GREEN);
#else
nrf_gpio_pin_clear(LED_PIN_GREEN);
#endif
}
static inline void led_orange_on(void)
{
#if LED_ACTIVE_LOW
nrf_gpio_pin_clear(LED_PIN_ORANGE);
#else
nrf_gpio_pin_set(LED_PIN_ORANGE);
#endif
}
static inline void led_orange_off(void)
{
#if LED_ACTIVE_LOW
nrf_gpio_pin_set(LED_PIN_ORANGE);
#else
nrf_gpio_pin_clear(LED_PIN_ORANGE);
#endif
}
static void led_all_off(void)
{
led_green_off();
led_orange_off();
}
static void led_color_on(uint8_t color)
{
led_all_off();
if (color == COLOR_GREEN) led_green_on();
else if (color == COLOR_ORANGE) led_orange_on();
}
/*==============================================================================
* Timer start helper
*============================================================================*/
static void timer_start_ms(uint32_t ms)
{
if (ms == 0) return;
app_timer_start(m_led_timer, MS_TO_TICKS(ms), NULL);
}
/*==============================================================================
* Error pattern state machine (No.7)
* phase 0: LED ON (166ms) → phase 1
* phase 1: LED OFF (166ms) → cnt++ → cnt<3 ? phase 0 : phase 2
* phase 2: PAUSE (1000ms) → cnt=0, phase 0
*============================================================================*/
static void error_pattern_start(void)
{
m_error_blink_cnt = 0;
m_error_phase = 0;
led_color_on(COLOR_ORANGE);
timer_start_ms(ERROR_BLINK_ON_MS);
}
static void error_pattern_tick(void)
{
switch (m_error_phase)
{
case 0: /* ON phase done -> OFF */
led_all_off();
m_error_phase = 1;
timer_start_ms(ERROR_BLINK_OFF_MS);
break;
case 1: /* OFF phase done */
m_error_blink_cnt++;
if (m_error_blink_cnt < ERROR_BLINK_COUNT)
{
/* Back to ON */
m_error_phase = 0;
led_color_on(COLOR_ORANGE);
timer_start_ms(ERROR_BLINK_ON_MS);
}
else
{
/* 3 blinks done -> pause */
m_error_phase = 2;
timer_start_ms(ERROR_PAUSE_MS);
}
break;
case 2: /* Pause done -> restart */
m_error_blink_cnt = 0;
m_error_phase = 0;
led_color_on(COLOR_ORANGE);
timer_start_ms(ERROR_BLINK_ON_MS);
break;
default:
break;
}
}
/*==============================================================================
* Timer callback
*============================================================================*/
static void led_timer_handler(void * p_context)
{
(void)p_context;
/* Error state handled separately */
if (m_current_state == LED_STATE_ERROR)
{
error_pattern_tick();
return;
}
const led_pattern_t * p = &m_patterns[m_current_state];
if (m_phase_on)
{
/* ON -> OFF transition */
led_all_off();
m_phase_on = false;
if (p->off_ms > 0)
{
timer_start_ms(p->off_ms);
}
else if (!p->repeat)
{
/* One-shot: if off_ms == 0, stay on (POWER_ON) or turn off (POWER_OFF) */
if (m_current_state == LED_STATE_POWER_OFF)
{
led_all_off();
m_current_state = LED_STATE_OFF;
}
/* POWER_ON: stay lit, no timer */
}
}
else
{
/* OFF -> ON transition */
if (p->repeat)
{
led_color_on(p->color);
m_phase_on = true;
timer_start_ms(p->on_ms);
}
/* No current case where repeat == false && off_ms > 0 */
}
}
/*==============================================================================
* Public functions
*============================================================================*/
void led_init(void)
{
/* Configure GPIO outputs */
nrf_gpio_cfg_output(LED_PIN_GREEN);
nrf_gpio_cfg_output(LED_PIN_ORANGE);
led_all_off();
/* Create timer (single-shot) */
app_timer_create(&m_led_timer, APP_TIMER_MODE_SINGLE_SHOT, led_timer_handler);
m_current_state = LED_STATE_OFF;
}
void led_set_state(led_state_t state)
{
if (state >= LED_STATE_COUNT) return;
/* Stop previous pattern */
app_timer_stop(m_led_timer);
led_all_off();
m_current_state = state;
m_phase_on = false;
const led_pattern_t * p = &m_patterns[state];
switch (state)
{
case LED_STATE_OFF:
/* Already all off */
break;
/* Error pattern: separate state machine */
case LED_STATE_ERROR:
error_pattern_start();
break;
/* All others: start from ON phase */
default:
led_color_on(p->color);
m_phase_on = true;
if (p->on_ms > 0)
{
timer_start_ms(p->on_ms);
}
break;
}
}
led_state_t led_get_state(void)
{
return m_current_state;
}
@@ -0,0 +1,52 @@
/*******************************************************************************
* @file led_control.h
* @brief Direct LED control driver
* @date 2026-03-30
*
* Controls dual-color LED green(P0.12) + orange(P0.29) via app_timer.
* On/off timing, color, and repeat pattern managed per state in a table.
******************************************************************************/
#ifndef LED_CONTROL_H__
#define LED_CONTROL_H__
#include <stdint.h>
#include <stdbool.h>
/*==============================================================================
* LED pin definitions
*============================================================================*/
#define LED_PIN_GREEN NRF_GPIO_PIN_MAP(0, 12) /* Green LED */
#define LED_PIN_ORANGE NRF_GPIO_PIN_MAP(0, 29) /* Orange LED */
#define LED_ACTIVE_LOW 1 /* 1 = Active Low (LED on when GPIO LOW) */
/*==============================================================================
* LED state enumeration
*============================================================================*/
typedef enum
{
LED_STATE_OFF = 0, /* All LEDs off */
LED_STATE_POWER_ON, /* 1: Power ON - green on 2s */
LED_STATE_POWER_OFF, /* 2: Power OFF - green on 2s then off */
LED_STATE_ADVERTISING, /* 3: BLE advertising - green blink 1s interval (repeat) */
LED_STATE_DETACH_WARNING, /* 4: Normal operation (detached) - green 1s on / 3s off (repeat) */
LED_STATE_ALIGN_SEARCHING, /* 5: Alignment mode (searching) - orange blink 1s interval (repeat) */
LED_STATE_ALIGN_COMPLETE, /* 6: Alignment mode (complete) - green 3s on / 1s off */
LED_STATE_ERROR, /* 7: Error - orange 3Hz blink x3 / off 1s (repeat) */
LED_STATE_COUNT /* Array size */
} led_state_t;
/*==============================================================================
* Public functions
*============================================================================*/
/** @brief Initialize LED GPIO + create timer - call once from main() */
void led_init(void);
/** @brief Change LED state - immediately stops previous pattern and starts new one */
void led_set_state(led_state_t state);
/** @brief Get current LED state */
led_state_t led_get_state(void);
#endif /* LED_CONTROL_H__ */
@@ -0,0 +1,288 @@
/*******************************************************************************
TEST medi50 Dec 23
*******************************************************************************
*
* [Module overview]
* Main event loop timer module (10ms interval, single-shot mode).
*
* Dispatches sensor data collection and system control events via flags.
* Uses app_timer single-shot mode; after processing, call main_timer_start()
* manually to restart if needed.
*
* [Event flags and processing order]
* motion_raw_data_enabled -> IMU data read (calls icm42670_main)
* - motion_data_once == true: one-shot read (after HW I2C init)
* - motion_data_once == false: continuous read (when not waiting for BLE TX)
* go_batt -> Battery voltage measurement (battery_level_meas)
* go_temp -> Temperature measurement (tmp235_voltage_level_meas)
* go_device_power_off -> Device power OFF (device_power_off)
* go_sleep_mode_enter -> Enter sleep mode (sleep_mode_enter)
* go_NVIC_SystemReset -> NVIC system reset
*
* [info4 mode measurement order]
* IMU continuous read -> go_batt (battery) -> go_temp (temp) -> motion_data_once (IMU one-shot)
* After temperature measurement, motion_data_once=true to return to IMU.
*
* [Timer settings]
* - Normal mode: 10ms interval (MAIN_LOOP_INTERVAL)
* - FEATURE_DETAIL_VALUE_FULL mode: 80ms interval (for detail printout)
*
******************************************************************************/
#include "sdk_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_drv_gpiote.h"
#include "battery_saadc.h"
#include "app_timer.h"
#include "main.h"
#include "app_raw_main.h"
#include "main_timer.h"
#include "tmp235_q1.h"
//#include "fstorage.h"
#include "power_control.h"
#include "main.h" /* 2026-03-17: cmd_parse.h removed, use main.h */
#include "debug_print.h"
#include "i2c_manager.h" //add cj
/* Main loop single-shot timer instance */
APP_TIMER_DEF(m_main_loop_timer_id);
#if FEATURE_DETAIL_VALUE_FULL
/* Detail printout mode: run main loop at 80ms interval */
#define MAIN_LOOP_INTERVAL 80 /* Timer for Full_Mode main processing when detail printout is enabled */
//extern bool pd_adc_full_a_start;
//extern bool pd_adc_full_b_start;
//extern bool pd_adc_full_c_start;
//extern bool pd_adc_full_d_start;
//extern bool pd_adc_full_end;
extern which_cmd_t cmd_type_t;
#else
/* Normal mode: run main loop at 10ms interval */
#define MAIN_LOOP_INTERVAL 10
#endif
/* ========================================================================== */
/* Event flags (set by external modules, processed in main_loop) */
/* ========================================================================== */
bool go_batt= false; /* Battery measurement request flag */
bool go_temp= false; /* Temperature measurement request flag */
bool go_device_power_off = false; /* Device power OFF request flag */
bool go_sleep_mode_enter = false; /* Sleep mode entry request flag */
bool go_NVIC_SystemReset = false; /* System reset request flag */
bool motion_raw_data_enabled = false; /* IMU motion data read enable flag */
bool ble_got_new_data = false; /* BLE new data transmission complete */
bool motion_data_once = false; /* IMU one-shot read mode (true: read once) */
/**
* @brief Main event loop (single-shot timer callback)
*
* Flag-based event dispatcher; processes actions based on set flags.
* Since the timer is single-shot, call main_timer_start() again from
* within the handler to continue execution.
*
* [Processing priority] (checked in code order)
* 1. IMU motion data (motion_raw_data_enabled)
* 2. Battery measurement (go_batt)
* 3. Temperature measurement (go_temp)
* 4. Power OFF (go_device_power_off)
* 5. Sleep mode (go_sleep_mode_enter)
* 6. System reset (go_NVIC_SystemReset)
*/
void main_loop(void * p_context) /* For x ms */
{
UNUSED_PARAMETER(p_context);
#if FEATURE_DETAIL_VALUE_FULL
// if(pd_adc_full_a_start == true) { // A mode
// main_timer_stop();
// printf("main_loop_A\r\n");
// full_adc_start();
// }else if(pd_adc_full_b_start == true) { // B mode
// main_timer_stop();
// printf("main_loop_B\r\n");
// full_adc_start();
// }else if(pd_adc_full_c_start == true) { // C mode
// main_timer_stop();
// printf("main_loop_C\r\n");
// full_adc_start();
// }else if(pd_adc_full_d_start == true) { // D mode
// main_timer_stop();
// printf("main_loop_D\r\n");
// full_adc_start();
// }else if(pd_adc_full_end == true) { // Completed
// pd_adc_full_end = false;
// main_timer_stop();
// printf("main_loop_END\r\n");
// if(cmd_type_t == CMD_BLE) {
// full_send_timer_start();
// }
// }
#endif
// For Motion Data Sampling
/* ---- IMU motion data read ---- */
/*
* If motion_raw_data_enabled is true, read IMU (ICM42670P) data.
*
* motion_data_once == true:
* One-shot read mode. Initialize HW I2C then call icm42670_main() once.
* Used in info4 mode to return to IMU after battery/temp measurement.
*
* motion_data_once == false:
* Continuous read mode. If not waiting for BLE TX (ble_got_new_data==false),
* call icm42670_main() and restart timer after 10ms for repeated execution.
*/
if (motion_raw_data_enabled == true)
{
main_timer_stop(); /* Stop timer (prevent re-entry) */
if (motion_data_once == true)
{
/* One-shot mode: init HW I2C then read IMU data once */
hw_i2c_init_once(); /* Switch to HW TWI mode (400kHz) */
icm42670_main(); /* Read and process IMU data */
}
else
{
/* Continuous mode: repeat read if not waiting for BLE TX */
if (ble_got_new_data==false)
{
//for(uint16_t i=0 ; i<60 ;i++)
//{
DBG_PRINTF("IMU \r\n");
icm42670_main(); /* Read IMU data */
motion_raw_data_enabled = true; /* Keep flag set (continuous read) */
main_timer_start_ms(1000); /* Next IMU read after 1s */
}
// else if(ble_got_new_data==true){
// motion_data_once = true;
// }
}
}
/* ---- Battery voltage measurement ---- */
/*
* If go_batt is true, measure battery level.
* Called after IMU continuous read in info4 mode.
* Timer remains stopped after measurement.
*/
if (go_batt == true)
{
DBG_PRINTF("IMU BATT\r\n");
main_timer_stop(); /* Stop timer */
go_batt = false; /* Consume flag (one-shot) */
// go_temp = true;
battery_level_meas(); /* Measure battery voltage via SAADC */
// nrf_delay_ms(20);
// m48_adc_start_init();
// main_timer_start();
}
/* ---- Temperature measurement ---- */
/*
* If go_temp is true, measure temperature via TMP235-Q1 sensor.
* Called after battery measurement in info4 mode.
* After completion, sets motion_data_once=true so the next IMU read
* uses one-shot mode (with HW I2C re-init).
*/
if (go_temp == true)
{
DBG_PRINTF("IMU Temp\r\n");
main_timer_stop(); /* Stop timer */
// go_batt = false;
go_temp = false; /* Consume flag (one-shot) */
motion_data_once = true; /* Switch next IMU read to one-shot mode */
tmp235_voltage_level_meas(); /* Measure TMP235-Q1 temperature sensor voltage */
// motion_raw_data_enabled = true;
// main_timer_start();
}
/* ---- System control event handling ---- */
/* Device power OFF handling */
if (go_device_power_off == true)
{
main_timer_stop(); /* Stop timer */
DBG_PRINTF("Off main_timer\r\n");
device_power_off(); /* Execute device power OFF */
}
/* Sleep mode entry handling */
if (go_sleep_mode_enter == true)
{
main_timer_stop(); /* Stop timer */
DBG_PRINTF("sleep main timer\r\n");
sleep_mode_enter(); /* Execute sleep mode entry */
}
/* NVIC system reset handling */
if (go_NVIC_SystemReset == true)
{
main_timer_stop(); /* Stop timer */
NVIC_SystemReset(); /* ARM Cortex-M4 system reset */
}
}
/**
* @brief Start main loop timer
*
* Single-shot mode; calls main_loop() after MAIN_LOOP_INTERVAL (10ms or 80ms)
*/
void main_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(MAIN_LOOP_INTERVAL), NULL));
}
/**
* @brief Start main loop timer with specified interval (ms)
*
* Used when a different period than the default is needed (e.g. IMU streaming)
*/
void main_timer_start_ms(uint32_t interval_ms)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(interval_ms), NULL));
}
/**
* @brief Stop main loop timer
*/
void main_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_main_loop_timer_id));
}
/**
* @brief Initialize main loop timer (call once at app startup)
*
* Creates a single-shot timer with main_loop() as callback.
* Must manually restart via main_timer_start() after each firing.
*/
void main_timer_init(void)
{
APP_ERROR_CHECK(app_timer_create(&m_main_loop_timer_id, APP_TIMER_MODE_SINGLE_SHOT, main_loop));
}
@@ -0,0 +1,37 @@
/*******************************************************************************
* @file timer_routine.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [Header overview]
* Public interface header for the main event loop timer.
*
* Uses a single-shot timer at 10ms (normal) or 80ms (detail) interval.
* The main_loop() callback handles sensor data collection and system control.
*
* [Key functions]
* main_timer_start() : Start timer (single-shot, manual restart required)
* main_timer_stop() : Stop timer
* main_timer_init() : Initialize timer (call once at app startup)
*
******************************************************************************/
#ifndef TIMER_ROUTINE_H__
#define TIMER_ROUTINE_H__
/** @brief Start main loop timer (single-shot, calls main_loop after MAIN_LOOP_INTERVAL) */
void main_timer_start(void);
/** @brief Start main loop timer with specified interval (ms) */
void main_timer_start_ms(uint32_t interval_ms);
/** @brief Stop main loop timer */
void main_timer_stop(void);
/** @brief Initialize main loop timer (call once at startup, creates single-shot timer) */
void main_timer_init(void);
#endif //TIMER_ROUTINE_H__
@@ -0,0 +1,188 @@
/*******************************************************************************
TEST medi50 Dec 23
//=========power_control.c====================
*******************************************************************************
*
* [Module overview]
* Device power sequence manager (power on / off / sleep).
*
* [Power-on flow]
* device_activated()
* -> Start power_loop timer -> completes immediately (no sensor init needed)
* -> Sensor (IMU) is handled by imu_read_direct() at measurement time
*
* [Sleep mode]
* device_sleep_mode()
* -> Clear processing flag
*
* [Reactivation]
* device_reactivated()
* -> Re-init I2C then restart power sequence from the beginning
*
* [Timer]
* Single-shot app_timer, calls power_loop at 20ms interval
*
******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "power_control.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "app_timer.h"
#include "debug_print.h"
#include "i2c_manager.h"
/* Single-shot timer instance for power sequence */
APP_TIMER_DEF(m_power_timer_id);
/* Power sequence state machine timer interval (20ms) */
// 2025-12-08 change to #define POWER_LOOP_INTERVAL 30 -> 20
#define POWER_LOOP_INTERVAL 20
/* Power sequence current step (0: I2C init, 1: reserved, 2: complete) */
static uint8_t p_order;
/* Power sequence lock flag (true = sequence in progress) */
bool lock_check = false;
/**
* @brief Enter device sleep mode
*
* @return 0 (always succeeds)
*/
int device_sleep_mode(void)
{
int rc = 0;
nrf_delay_ms(2);
DBG_PRINTF("Device_Sleep_Mode OK!\r\n");
nrf_delay_ms(10);
return rc;
}
/**
* @brief Power on device (start power sequence)
*
* Resets the sequence step to 0, sets the lock flag, and starts
* the timer to drive the power_loop() state machine.
*
* @return 0 (always succeeds)
*/
int device_activated(void)
{
int rc = 0;
p_order = 0; /* State machine start step (Step 0: I2C init) */
lock_check =true; /* Lock: power sequence in progress */
power_timer_start(); /* First power_loop() call after 20ms */
return rc;
}
/**
* @brief Power-up sequence state machine
*
* Executes hardware initialization steps
* Called by app_timer at POWER_LOOP_INTERVAL (20ms)
*
* Sequence:
* 0: I2C init
* 1: (reserved)
* 2: Complete
*/
/*
* Power sequence state machine (20ms single-shot timer callback).
*
* [Execution flow]
* 1) Timer callback entry -> stop timer (single-shot)
* 2) Execute init step for current p_order
* 3) If p_order < 2, advance to next step and restart timer
* 4) If p_order == 2, power sequence complete
*
* No sensor init needed -- imu_read_direct() handles it per measurement.
*/
void power_loop(void *p_context)
{
UNUSED_PARAMETER(p_context);
power_timer_stop(); /* Stop current timer (single-shot, manual restart needed) */
/* No sensor init needed -- imu_read_direct() handles it per measurement */
/* Add switch(p_order) here if future power sequence steps are needed */
p_order = 2;
/* Advance to next step or finish */
/* Advance to next step or finish sequence */
if (p_order < 2)
{
p_order++; /* Move to next step */
power_timer_start(); /* Execute next step after 20ms */
}
else
{
/* Power sequence fully complete */
DBG_PRINTF("[PWR] Device Activated OK!\r\n");
}
}
/**
* @brief Reactivate device (on wake from sleep)
*
* Re-initializes I2C and restarts the power sequence from the beginning.
* Called when waking from sleep mode.
*
* @return 0 (always succeeds)
*/
int device_reactivated(void)
{
int rc = 0;
sw_i2c_init_once(); /* Re-initialize I2C bus */
nrf_delay_ms(10); /* Stabilization delay */
lock_check = true; /* Lock: power sequence in progress */
p_order = 0; /* Restart state machine from Step 0 */
power_timer_start(); /* Start power_loop() after 20ms */
return rc;
}
/**
* @brief Start power sequence timer
*
* Single-shot mode; calls power_loop() after POWER_LOOP_INTERVAL (20ms).
*/
void power_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_power_timer_id, APP_TIMER_TICKS(POWER_LOOP_INTERVAL), NULL));
}
/**
* @brief Stop power sequence timer
*/
void power_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_power_timer_id));
}
/**
* @brief Initialize power sequence timer (call once at app startup)
*
* Creates a single-shot timer with power_loop() as callback.
* Must manually restart via power_timer_start() after each step.
*/
void power_timer_init(void) //active start
{
APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_SINGLE_SHOT, power_loop));
// 2025-12-08 change to APP_TIMER_MODE_REPEATED mode
//APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_REPEATED, power_loop));
}
@@ -0,0 +1,48 @@
/*******************************************************************************
* @file power_control.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [Header overview]
* Public interface header for the device power sequence manager.
*
* [Key functions]
* device_activated() : Power on -> start power_loop state machine
* device_sleep_mode() : Enter sleep mode (stop processing)
* device_reactivated() : Wake from sleep -> restart power sequence
* power_loop() : 20ms power sequence state machine callback
* power_timer_start/stop : Power sequence timer control
* power_timer_init() : Initialize power sequence timer (call once at startup)
*
******************************************************************************/
#ifndef _POWER_CONTROL_H_
#define _POWER_CONTROL_H_
#include "main.h"
/** @brief Enter device sleep mode (clears processing flag) */
int device_sleep_mode(void);
/** @brief Power on device (start power sequence state machine) */
int device_activated(void);
/** @brief Reactivate device (re-init I2C and restart sequence on wake from sleep) */
int device_reactivated(void);
/** @brief Power sequence state machine (20ms timer callback, Step 0->1->2) */
void power_loop(void * p_context); /* For x ms */
/** @brief Start power sequence timer (20ms single-shot) */
void power_timer_start(void);
/** @brief Stop power sequence timer */
void power_timer_stop(void);;
/** @brief Initialize power sequence timer (call once at app startup) */
void power_timer_init(void);
#endif //_POWER_CONTROL_H_
@@ -0,0 +1,186 @@
/**
* @file ble_quick_security.c
* @brief Ultra-simple BLE Security Configuration Implementation
*
* Compatible with existing debug_print.h system.
*/
#include "ble_quick_security.h"
#include "peer_manager_handler.h"
#include "nrf_ble_lesc.h"
#include "app_error.h"
#include <string.h>
// Use existing debug system
#include "debug_print.h"
// Module state
static struct {
bool dev_mode;
bool bonds_delete_pending;
} m_state = {0};
/**
* @brief Initialize BLE security
*/
void ble_security_quick_init(bool development_mode)
{
ret_code_t err_code;
ble_gap_sec_params_t sec_params;
// Save mode
m_state.dev_mode = development_mode;
m_state.bonds_delete_pending = false;
// Initialize Peer Manager FIRST
err_code = pm_init();
APP_ERROR_CHECK(err_code);
// Initialize LESC module (ECDH P-256 key pair generation)
err_code = nrf_ble_lesc_init();
APP_ERROR_CHECK(err_code);
// Configure security parameters
memset(&sec_params, 0, sizeof(ble_gap_sec_params_t));
if (development_mode) {
// ===== DEVELOPMENT MODE: No security =====
sec_params.bond = 0; // No bonding
sec_params.mitm = 0; // No MITM
sec_params.lesc = 0; // No LESC
sec_params.keypress = 0;
sec_params.io_caps = BLE_GAP_IO_CAPS_NONE; // No passkey
sec_params.oob = 0;
sec_params.min_key_size = 7;
sec_params.max_key_size = 16;
DBG_PRINTF("DEV MODE: Security DISABLED - Fast connection\r\n");
// Delete all bonds (async)
err_code = pm_peers_delete();
if (err_code == NRF_SUCCESS) {
m_state.bonds_delete_pending = true;
DBG_PRINTF("DEV MODE: Deleting all bonds...\r\n");
}
} else {
// ===== PRODUCTION MODE: Full security =====
sec_params.bond = 1; // Enable bonding
sec_params.mitm = 1; // Enable MITM
sec_params.lesc = 1; // LE Secure Connections (ECDH P-256)
sec_params.keypress = 0;
sec_params.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; // Show passkey
sec_params.oob = 0;
sec_params.min_key_size = 7;
sec_params.max_key_size = 16;
sec_params.kdist_own.enc = 1;
sec_params.kdist_own.id = 1;
sec_params.kdist_peer.enc = 1;
sec_params.kdist_peer.id = 1;
DBG_PRINTF("PROD MODE: Security ENABLED - Full protection\r\n");
}
// Apply security parameters
err_code = pm_sec_params_set(&sec_params);
APP_ERROR_CHECK(err_code);
}
/**
* @brief Get current mode
*/
bool ble_security_is_dev_mode(void)
{
return m_state.dev_mode;
}
/**
* @brief PM event handler
*/
void ble_security_quick_pm_handler(pm_evt_t const *p_evt)
{
ret_code_t err_code;
// DEV mode: do not forward security failure events to SDK handler (prevent disconnect)
if (m_state.dev_mode && p_evt->evt_id == PM_EVT_CONN_SEC_FAILED) {
DBG_PRINTF("Security failed: error=%d\r\n",
p_evt->params.conn_sec_failed.error);
DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n");
return;
}
// Call standard handlers (required)
pm_handler_on_pm_evt(p_evt);
pm_handler_flash_clean(p_evt);
// Handle events
switch (p_evt->evt_id) {
case PM_EVT_CONN_SEC_SUCCEEDED:
if (m_state.dev_mode) {
DBG_PRINTF("DEV: Connected (no security)\r\n");
} else {
pm_conn_sec_status_t status;
if (pm_conn_sec_status_get(p_evt->conn_handle, &status) == NRF_SUCCESS) {
DBG_PRINTF("PROD: Link secured - LESC=%d MITM=%d bonded=%d\r\n",
status.lesc, status.mitm_protected, status.bonded);
} else {
DBG_PRINTF("PROD: Link secured (bonded)\r\n");
}
}
break;
case PM_EVT_CONN_SEC_FAILED:
DBG_PRINTF("Security failed: error=%d\r\n",
p_evt->params.conn_sec_failed.error);
if (m_state.dev_mode) {
// DEV mode: ignore security failure, keep connection
DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n");
break;
}
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING) {
// Key missing: attempt re-pairing, fall back to disconnect on failure
err_code = pm_conn_secure(p_evt->conn_handle, true);
if (err_code != NRF_ERROR_INVALID_STATE &&
err_code != NRF_ERROR_BUSY &&
err_code != BLE_ERROR_INVALID_CONN_HANDLE) {
APP_ERROR_CHECK(err_code);
}
if (err_code != NRF_SUCCESS) {
// Re-pairing not possible -> disconnect
pm_handler_disconnect_on_sec_failure(p_evt);
}
} else {
// Other security failure -> delete bond then attempt re-pairing
pm_peer_id_t peer_id;
if (pm_peer_id_get(p_evt->conn_handle, &peer_id) == NRF_SUCCESS
&& peer_id != PM_PEER_ID_INVALID) {
pm_peer_delete(peer_id);
}
err_code = pm_conn_secure(p_evt->conn_handle, true);
if (err_code != NRF_SUCCESS) {
pm_handler_disconnect_on_sec_failure(p_evt);
}
}
break;
case PM_EVT_CONN_SEC_CONFIG_REQ:
{
pm_conn_sec_config_t config = {
.allow_repairing = true
};
pm_conn_sec_config_reply(p_evt->conn_handle, &config);
}
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
if (m_state.bonds_delete_pending) {
m_state.bonds_delete_pending = false;
DBG_PRINTF("DEV MODE: Bonds cleared!\r\n");
}
break;
default:
break;
}
}
@@ -0,0 +1,56 @@
/**
* @file ble_quick_security.h
* @brief Ultra-simple BLE Security Configuration
*
* ONE function call to control entire security behavior.
* Works with existing debug_print.h system.
*/
#ifndef BLE_QUICK_SECURITY_H
#define BLE_QUICK_SECURITY_H
#include <stdint.h>
#include <stdbool.h>
#include "peer_manager.h"
/**
* @brief Initialize BLE security with ONE simple parameter
*
* @param[in] development_mode true (1) = Fast development (no security)
* false (0) = Production (full security)
*
* Development mode (1):
* - No pairing/bonding required
* - Auto-deletes all bonds on startup
* - Instant connection
* - Fast iteration
*
* Production mode (0):
* - Full security with passkey
* - Bonding preserved
* - MITM protection
* - Secure deployment
*
* Usage in main.c:
* #define BLE_DEV_MODE 1 // or 0
* ble_security_quick_init(BLE_DEV_MODE);
*/
void ble_security_quick_init(bool development_mode);
/**
* @brief Get current mode
* @return true if in development mode, false if production
*/
bool ble_security_is_dev_mode(void);
/**
* @brief Peer Manager event handler
*
* Call this from your pm_evt_handler() function.
* It handles all security events automatically.
*
* @param[in] p_evt Peer Manager event
*/
void ble_security_quick_pm_handler(pm_evt_t const *p_evt);
#endif // BLE_QUICK_SECURITY_H