Initial Commit
This commit is contained in:
@@ -26,9 +26,7 @@
|
||||
#include "imu_i2c.h"
|
||||
#include "main.h"
|
||||
|
||||
/*==============================================================================
|
||||
* ADC 디바이스트리 설정
|
||||
*============================================================================*/
|
||||
/* ADC 디바이스트리 설정 */
|
||||
#define ZEPHYR_USER_NODE DT_PATH(zephyr_user)
|
||||
|
||||
/* 디바이스트리에서 ADC 채널 스펙 가져오기 (gain, ref, acq time, input, resolution, oversampling) */
|
||||
@@ -36,78 +34,79 @@ static const struct adc_dt_spec battery_adc = ADC_DT_SPEC_GET_BY_NAME(ZEPHYR_USE
|
||||
|
||||
static int16_t adc_buffer;
|
||||
|
||||
/*==============================================================================
|
||||
* Module variables
|
||||
*============================================================================*/
|
||||
/* Module variables */
|
||||
volatile bool battery_saadc_done = false;
|
||||
volatile uint16_t info_batt = 0;
|
||||
|
||||
static struct k_timer battery_timer;
|
||||
static struct k_work battery_work;
|
||||
|
||||
/* 60초 내부 모니터 전용 카운터
|
||||
* - 앱 측정 명령(mbb?)이 없는 일반 상태에서만 사용
|
||||
* - mbb? 성공 시 연속 측정 판정으로 넘어가므로 0으로 초기화
|
||||
/*
|
||||
* 60초 내부 모니터 전용 카운터
|
||||
* - 앱 측정 명령(mbb?/mtb?)이 없는 일반 상태에서만 사용
|
||||
* - mbb? 성공 시 mbb? 측정 판정으로 넘어가므로 0으로 초기화
|
||||
*/
|
||||
static uint8_t periodic_low_battery_cnt;
|
||||
static uint8_t periodic_high_temperature_cnt;
|
||||
|
||||
/* 연속 측정(mbb?) 응답값 전용 카운터
|
||||
/*
|
||||
* 주기 측정(mbb?) 응답값 전용 카운터
|
||||
* - mbb? 응답에 포함된 배터리/IMU 온도 값으로 판정
|
||||
* - 측정 실패 시 호출되지 않으므로 기존 카운트 유지
|
||||
*/
|
||||
static uint8_t continuous_low_battery_cnt;
|
||||
static uint8_t continuous_high_temperature_cnt;
|
||||
|
||||
/* 정렬 상태 보호 판정 차단 플래그
|
||||
/*
|
||||
* 정렬 상태 보호 판정 차단 플래그
|
||||
* - mls?로 ALIGN_SEARCHING/ALIGN_COMPLETE 진입 시 true
|
||||
* - 정렬 중에는 배터리/온도 보호 판정 자체를 진행하지 않음
|
||||
*/
|
||||
static bool alignment_mode_active;
|
||||
|
||||
/* 최근 mbb? 성공 이후 내부 60초 모니터를 잠시 막는 기준 시각
|
||||
* - 연속 측정 중에는 mbb? 응답값으로 보호 판정
|
||||
/*
|
||||
* 최근 mbb? 성공 이후 내부 60초 모니터를 잠시 막는 기준 시각
|
||||
* - 주기 측정 중에는 mbb? 응답값으로 보호 판정
|
||||
* - 이 값보다 현재 시간이 작으면 60초 내부 모니터는 skip
|
||||
*/
|
||||
static int64_t continuous_monitor_active_until_ms;
|
||||
|
||||
#define BATTERY_MONITOR_LIMIT_COUNT 5U
|
||||
#define BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT 30U
|
||||
#define HIGH_TEMPERATURE_CDEG 4000 /* 40.00 C */
|
||||
#define CONTINUOUS_MONITOR_ACTIVE_MS 15000 /* mbb? 10초 주기 대비 여유 */
|
||||
#define BATTERY_MONITOR_LIMIT_COUNT 5U // 정렬모드(mtb?)나 주기 측정(mbb?)이 아닌 경우 60초 주기 5회 연속 저전압 감지 시 전원 OFF(5분)
|
||||
#define BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT 10U // 주기 측정 10회 연속 저전압 감지 시 전원 OFF(100초)
|
||||
#define HIGH_TEMPERATURE_CDEG 4000 // 40.00 C
|
||||
#define CONTINUOUS_MONITOR_ACTIVE_MS 15000 // mbb? 10초 주기 대비 여유
|
||||
|
||||
#define BATTERY_MONITOR_INTERVAL_MS 60000 /* 60초 주기 */
|
||||
#define BATTERY_MONITOR_INTERVAL_MS 60000 // 정렬모드(mtb?)나 주기 측정(mbb?)이 아닌 경우 저전압/고온 모니터 주기 60초
|
||||
|
||||
/*==============================================================================
|
||||
/*
|
||||
* 전압 변환 (ADC raw → mV 변환)
|
||||
* 공식: (raw × 600 / 4095) × 6 × 1.42
|
||||
* 정수 연산: raw × 600 × 6 × 142 / (4095 × 100)
|
||||
*============================================================================*/
|
||||
*/
|
||||
static int adc_raw_to_mv(int16_t raw)
|
||||
{
|
||||
if (raw < 0)
|
||||
{
|
||||
raw = 0;
|
||||
}
|
||||
/* 오버플로 방지: 600 × 6 × 142 = 511,200 → raw 최대 4095 → 4095 × 511200 = ~2B → int32 OK */
|
||||
// 오버플로 방지: 600 × 6 × 142 = 511,200 → raw 최대 4095 → 4095 × 511200 = ~2B → int32 OK
|
||||
int32_t mv = ((int32_t)raw * 600 * 6 * 142) / (4095 * 100);
|
||||
return (int)mv;
|
||||
}
|
||||
|
||||
static bool continuous_monitor_is_active(void)
|
||||
{
|
||||
/* 마지막 mbb? 성공 이후 CONTINUOUS_MONITOR_ACTIVE_MS 안쪽이면 연속 측정 중으로 간주 */
|
||||
return (continuous_monitor_active_until_ms > 0) &&
|
||||
(k_uptime_get() < continuous_monitor_active_until_ms);
|
||||
// 마지막 mbb? 성공 이후 CONTINUOUS_MONITOR_ACTIVE_MS 안쪽이면 주기 측정(mbb?) 중으로 간주
|
||||
return (continuous_monitor_active_until_ms > 0) && (k_uptime_get() < continuous_monitor_active_until_ms);
|
||||
}
|
||||
|
||||
static void record_battery_value(int batt_mv, uint8_t *cnt,
|
||||
uint8_t limit, const char *mode)
|
||||
/*
|
||||
* mode별 카운터만 전달받아 공통 판정 로직 사용
|
||||
* - periodic: 60초 내부 모니터, limit 5
|
||||
* - continuous: mbb? 응답값 기반, limit 10
|
||||
*/
|
||||
static void record_battery_value(int batt_mv, uint8_t *cnt, uint8_t limit, const char *mode)
|
||||
{
|
||||
/* mode별 카운터만 전달받아 공통 판정 로직 사용
|
||||
* - periodic: 60초 내부 모니터, limit 5
|
||||
* - continuous: mbb? 응답값 기반, limit 30
|
||||
*/
|
||||
if (batt_mv <= LOW_BATTERY_VOLTAGE)
|
||||
{
|
||||
if (*cnt < UINT8_MAX)
|
||||
@@ -115,8 +114,7 @@ static void record_battery_value(int batt_mv, uint8_t *cnt,
|
||||
(*cnt)++;
|
||||
}
|
||||
|
||||
DBG_PRINTF("[BATT] LOW! mode=%s cnt=%u/%u mv=%d\r\n",
|
||||
mode, *cnt, limit, batt_mv);
|
||||
DBG_PRINTF("[BATT] LOW! mode=%s cnt=%u/%u mv=%d\r\n", mode, *cnt, limit, batt_mv);
|
||||
|
||||
if (*cnt >= limit)
|
||||
{
|
||||
@@ -131,14 +129,14 @@ static void record_battery_value(int batt_mv, uint8_t *cnt,
|
||||
}
|
||||
}
|
||||
|
||||
static void record_temperature_value(int16_t temp_cdeg, uint8_t *cnt,
|
||||
uint8_t limit, const char *mode)
|
||||
/*
|
||||
* IMU 온도는 centi-degree 단위
|
||||
* - 4000 = 40.00 C
|
||||
* - 40.00 C 이상이면 고온 카운트 증가
|
||||
* - 기준 미만이면 해당 mode 카운터 초기화
|
||||
*/
|
||||
static void record_temperature_value(int16_t temp_cdeg, uint8_t *cnt, uint8_t limit, const char *mode)
|
||||
{
|
||||
/* IMU 온도는 centi-degree 단위
|
||||
* - 4000 = 40.00 C
|
||||
* - 40.00 C 이상이면 고온 카운트 증가
|
||||
* - 기준 미만이면 해당 mode 카운터 초기화
|
||||
*/
|
||||
if (temp_cdeg >= HIGH_TEMPERATURE_CDEG)
|
||||
{
|
||||
if (*cnt < UINT8_MAX)
|
||||
@@ -166,20 +164,17 @@ static void record_temperature_value(int16_t temp_cdeg, uint8_t *cnt,
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Public functions
|
||||
*============================================================================*/
|
||||
|
||||
/* Public functions */
|
||||
void battery_adc_init(void)
|
||||
{
|
||||
/* ADC 디바이스 준비 상태 확인 */
|
||||
// ADC 디바이스 준비 상태 확인
|
||||
if (!adc_is_ready_dt(&battery_adc))
|
||||
{
|
||||
DBG_PRINTF("[BATT] ADC device not ready\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 디바이스트리 설정으로 채널 구성 */
|
||||
// 디바이스트리 설정으로 채널 구성
|
||||
int err = adc_channel_setup_dt(&battery_adc);
|
||||
if (err)
|
||||
{
|
||||
@@ -195,7 +190,7 @@ void battery_adc_init(void)
|
||||
|
||||
int battery_read_mv(void)
|
||||
{
|
||||
/* 매번 채널 재설정 (다른 센서와 SAADC 공유 시 필요) */
|
||||
// 매번 채널 재설정 (다른 센서와 SAADC 공유 시 필요)
|
||||
int err = adc_channel_setup_dt(&battery_adc);
|
||||
if (err)
|
||||
{
|
||||
@@ -203,7 +198,7 @@ int battery_read_mv(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 디바이스트리에서 시퀀스 초기화 (channels, resolution, oversampling) */
|
||||
// 디바이스트리에서 시퀀스 초기화 (channels, resolution, oversampling)
|
||||
struct adc_sequence seq = {0};
|
||||
|
||||
err = adc_sequence_init_dt(&battery_adc, &seq);
|
||||
@@ -216,7 +211,7 @@ int battery_read_mv(void)
|
||||
seq.buffer = &adc_buffer;
|
||||
seq.buffer_size = sizeof(adc_buffer);
|
||||
|
||||
/* ADC 읽기 */
|
||||
// ADC 읽기
|
||||
err = adc_read_dt(&battery_adc, &seq);
|
||||
if (err)
|
||||
{
|
||||
@@ -233,13 +228,13 @@ int battery_read_mv(void)
|
||||
return mv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 정렬 상태 진입/해제는 mls? 명령에서 전달
|
||||
* - enabled true: 보호 판정 중지 + 기존 누적값 초기화
|
||||
* - enabled false: 다음 조건부터 다시 판정 가능
|
||||
*/
|
||||
void battery_protection_set_alignment_mode(bool enabled)
|
||||
{
|
||||
/* 정렬 상태 진입/해제는 mls? 명령에서 전달
|
||||
* - enabled true: 보호 판정 중지 + 기존 누적값 초기화
|
||||
* - enabled false: 다음 조건부터 다시 판정 가능
|
||||
*/
|
||||
alignment_mode_active = enabled;
|
||||
if (enabled)
|
||||
{
|
||||
@@ -250,55 +245,43 @@ void battery_protection_set_alignment_mode(bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mbb? 측정 성공 시에만 호출
|
||||
* - 실패한 측정은 호출되지 않아서 continuous 카운트 유지
|
||||
* - 정렬 중에는 응답값이 있어도 보호 판정 제외
|
||||
* - mbb?가 들어온 직후에는 내부 60초 모니터 대신 응답값 기반 판정 사용
|
||||
*/
|
||||
void battery_protection_record_continuous(int batt_mv, int16_t temp_cdeg)
|
||||
{
|
||||
/* mbb? 측정 성공 시에만 호출
|
||||
* - 실패한 측정은 호출되지 않아서 continuous 카운트 유지
|
||||
* - 정렬 중에는 응답값이 있어도 보호 판정 제외
|
||||
*/
|
||||
// 정렬모드 중에는 continuous 보호 판정 제외
|
||||
if (alignment_mode_active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* mbb?가 들어온 직후에는 내부 60초 모니터 대신 응답값 기반 판정 사용
|
||||
* - periodic 카운터는 섞이지 않게 초기화
|
||||
* - continuous 카운터는 아래 record_* 함수에서 값에 따라 증가/초기화
|
||||
*/
|
||||
// 15초 후 일반 60초 주기 모니터 재개
|
||||
continuous_monitor_active_until_ms = k_uptime_get() + CONTINUOUS_MONITOR_ACTIVE_MS;
|
||||
|
||||
// periodic 모니터 카운트 초기화
|
||||
periodic_low_battery_cnt = 0;
|
||||
periodic_high_temperature_cnt = 0;
|
||||
|
||||
record_battery_value(batt_mv,
|
||||
&continuous_low_battery_cnt,
|
||||
BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT,
|
||||
"continuous");
|
||||
record_temperature_value(temp_cdeg,
|
||||
&continuous_high_temperature_cnt,
|
||||
BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT,
|
||||
"continuous");
|
||||
record_battery_value(batt_mv, &continuous_low_battery_cnt, BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT, "continuous");
|
||||
record_temperature_value(temp_cdeg, &continuous_high_temperature_cnt, BATTERY_CONTINUOUS_MONITOR_LIMIT_COUNT, "continuous");
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 주기 모니터링 타이머
|
||||
*============================================================================*/
|
||||
|
||||
/* k_work 핸들러: 스레드 컨텍스트에서 ADC 읽기 (adc_read는 블로킹이라 ISR 불가) */
|
||||
|
||||
static void battery_work_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
/* 보호 판정 제외 구간
|
||||
* - 정렬 중: 정책상 보호 판정 미진행
|
||||
* - 최근 mbb? 성공 직후: mbb? 응답값 기반 continuous 판정이 담당
|
||||
*/
|
||||
// 일반 60초 주기 보호 판정 제외 구간: 정렬모드 또는 주기 측정
|
||||
if (alignment_mode_active || continuous_monitor_is_active())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 측정 처리 중이거나 IMU FIFO 사용 중(정렬모드)이면 I2C 접근 충돌 방지 */
|
||||
// I2C 접근 충돌 방지: 긴 측정 명령 처리 중이거나 IMU FIFO 동작 중
|
||||
if (processing || imu_fifo_is_active())
|
||||
{
|
||||
return;
|
||||
@@ -311,14 +294,8 @@ static void battery_work_handler(struct k_work *work)
|
||||
return;
|
||||
}
|
||||
|
||||
/* 일반 상태의 60초 내부 모니터 판정
|
||||
* - 저전압이면 periodic_low_battery_cnt 증가
|
||||
* - 정상 전압이면 periodic_low_battery_cnt 초기화
|
||||
*/
|
||||
record_battery_value(batt,
|
||||
&periodic_low_battery_cnt,
|
||||
BATTERY_MONITOR_LIMIT_COUNT,
|
||||
"periodic");
|
||||
// 정렬모드나 주기 측정 중이 아닌 경우 60초 내부 모니터 판정(배터리)
|
||||
record_battery_value(batt, &periodic_low_battery_cnt, BATTERY_MONITOR_LIMIT_COUNT, "periodic");
|
||||
|
||||
int16_t temp_cdeg = 0;
|
||||
int temp_ret = imu_read_temperature_cdeg(&temp_cdeg);
|
||||
@@ -329,14 +306,8 @@ static void battery_work_handler(struct k_work *work)
|
||||
return;
|
||||
}
|
||||
|
||||
/* 일반 상태의 IMU 온도 판정
|
||||
* - 고온이면 periodic_high_temperature_cnt 증가
|
||||
* - 정상 온도이면 periodic_high_temperature_cnt 초기화
|
||||
*/
|
||||
record_temperature_value(temp_cdeg,
|
||||
&periodic_high_temperature_cnt,
|
||||
BATTERY_MONITOR_LIMIT_COUNT,
|
||||
"periodic");
|
||||
// 정렬모드나 주기 측정 중이 아닌 경우 60초 내부 모니터 판정(온도)
|
||||
record_temperature_value(temp_cdeg, &periodic_high_temperature_cnt, BATTERY_MONITOR_LIMIT_COUNT, "periodic");
|
||||
}
|
||||
|
||||
/* 타이머 ISR → k_work 예약 */
|
||||
|
||||
Reference in New Issue
Block a user