코드 정리

- 주석 영문으로 변경
- Allman 스타일로 통일
This commit is contained in:
2026-04-16 12:01:51 +09:00
parent c98d9ae14e
commit 2861cb9815
35 changed files with 2406 additions and 2557 deletions

View File

@@ -167,7 +167,10 @@ dr_adc_err_t dr_adc_init(void)
void dr_adc_uninit(void)
{
if (!m_initialized) return;
if (!m_initialized)
{
return;
}
nrfx_spim_uninit(&m_spim);
@@ -187,8 +190,14 @@ bool dr_adc_is_initialized(void)
dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value)
{
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
if (raw_value == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (!m_initialized)
{
return DR_ADC_ERR_NOT_INIT;
}
if (raw_value == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
*raw_value = spim_read_raw();
@@ -197,12 +206,21 @@ dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value)
dr_adc_err_t dr_adc_read(dr_adc_result_t *result)
{
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
if (result == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (!m_initialized)
{
return DR_ADC_ERR_NOT_INIT;
}
if (result == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
dr_adc_err_t err = dr_adc_read_raw(&result->raw);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
result->voltage_mv = dr_adc_raw_to_mv(result->raw);
return DR_ADC_OK;
@@ -210,18 +228,29 @@ dr_adc_err_t dr_adc_read(dr_adc_result_t *result)
dr_adc_err_t dr_adc_read_averaged(dr_adc_result_t *result, uint16_t num_samples)
{
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
if (result == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
if (!m_initialized)
{
return DR_ADC_ERR_NOT_INIT;
}
if (result == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
uint32_t sum = 0;
uint16_t raw;
for (uint16_t i = 0; i < num_samples; i++)
{
dr_adc_err_t err = dr_adc_read_raw(&raw);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
sum += raw;
}
@@ -243,11 +272,18 @@ dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples)
uint16_t i;
NRF_SPIM_Type *spim = m_spim.p_reg;
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
if (buffer == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
if (!m_initialized)
{
return DR_ADC_ERR_NOT_INIT;
}
if (buffer == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
spim->RXD.MAXCNT = 2;
for (i = 0; i < num_samples; i++)
@@ -268,8 +304,14 @@ dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples)
dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t *config)
{
if (!m_initialized) return DR_ADC_ERR_NOT_INIT;
if (echo == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (!m_initialized)
{
return DR_ADC_ERR_NOT_INIT;
}
if (echo == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Use default config if not provided */
dr_adc_echo_config_t cfg;
@@ -286,8 +328,9 @@ dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t
/* Validate config */
if (cfg.num_samples == 0 || cfg.num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Use module-level buffer (16KB too large for stack) */
/* Optional delay before capture */
@@ -298,7 +341,10 @@ dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t
/* Capture echo samples into module-level buffer */
dr_adc_err_t err = dr_adc_capture_echo(m_echo_buffer, cfg.num_samples);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
/* Analyze captured data */
return dr_adc_analyze_echo(m_echo_buffer, cfg.num_samples, echo, cfg.threshold_raw);
@@ -309,9 +355,14 @@ dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
{
(void)cycles; /* Not used - ADC test only */
if (echo == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
if (echo == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Initialize echo structure */
echo->peak_raw = 0;
@@ -325,7 +376,10 @@ dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
if (!m_initialized)
{
dr_adc_err_t init_err = dr_adc_init();
if (init_err != DR_ADC_OK) return init_err;
if (init_err != DR_ADC_OK)
{
return init_err;
}
}
/* Settling time for ADC power */
@@ -339,7 +393,10 @@ dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
/* Capture ADC samples into module-level buffer */
dr_adc_err_t err = dr_adc_capture_echo(m_echo_buffer, num_samples);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
/* Analyze captured data */
return dr_adc_analyze_echo(m_echo_buffer, num_samples, echo, 100);
@@ -353,9 +410,15 @@ const uint16_t* dr_adc_get_echo_buffer(void)
dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
dr_adc_echo_t *echo, uint16_t threshold)
{
if (buffer == NULL || echo == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0) return DR_ADC_ERR_INVALID_PARAM;
if (buffer == NULL || echo == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (num_samples == 0)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Calculate baseline from first few samples */
uint16_t baseline_samples = (num_samples > 8) ? 8 : num_samples;
echo->baseline_raw = dr_adc_calc_baseline(buffer, baseline_samples);
@@ -371,8 +434,7 @@ dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
echo->num_samples = num_samples;
/* Check if valid echo detected */
if (echo->peak_raw < threshold ||
echo->peak_raw <= echo->baseline_raw)
if (echo->peak_raw < threshold || echo->peak_raw <= echo->baseline_raw)
{
return DR_ADC_ERR_NO_ECHO;
}
@@ -380,8 +442,7 @@ dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
return DR_ADC_OK;
}
void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
uint16_t *peak_value, uint16_t *peak_index)
void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples, uint16_t *peak_value, uint16_t *peak_index)
{
/*
* Posterior wall detection for bladder measurement
@@ -403,8 +464,10 @@ void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
{
uint16_t val = buffer[i];
/* Skip abnormally high values (noise/saturation) */
if (val > MAX_VALID_VALUE) continue;
if (val > MAX_VALID_VALUE)
{
continue;
}
if (val > max_val)
{
max_val = val;
@@ -412,14 +475,23 @@ void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
}
}
if (peak_value != NULL) *peak_value = max_val;
if (peak_index != NULL) *peak_index = max_idx;
if (peak_value != NULL)
{
*peak_value = max_val;
}
if (peak_index != NULL)
{
*peak_index = max_idx;
}
}
uint16_t dr_adc_calc_baseline(const uint16_t *buffer, uint16_t num_samples)
{
if (buffer == NULL || num_samples == 0) return 0;
if (buffer == NULL || num_samples == 0)
{
return 0;
}
uint32_t sum = 0;
for (uint16_t i = 0; i < num_samples; i++)
{
@@ -484,7 +556,10 @@ bool dr_adc_test(void)
void dr_adc_print_buffer(const uint16_t *buffer, uint16_t num_samples)
{
#ifdef DEBUG_ADC
if (buffer == NULL || num_samples == 0) return;
if (buffer == NULL || num_samples == 0)
{
return;
}
ADC_LOG("Echo buffer (%d samples):", num_samples);
@@ -560,30 +635,50 @@ extern void dr_piezo_select_channel(uint8_t channel);
/**
* @brief Integrated burst + capture + BLE transmit (16-bit raw data)
*
* reb+red merged protocol: header와 데이터를 첫 패킷에 합침
* reb+red merged protocol: header and data merged into first packet
*
* Response format:
* Packet 1 (reb:): num_samples(2) + raw_data(up to 238 bytes = 119 samples)
* Packet 2~N (red:): pkt_idx(2) + raw_data(up to 238 bytes) — 119샘플 초과 시만
* Final (raa:): status(2) — skip_raa=0 일 때만
* Packet 2~N (red:): pkt_idx(2) + raw_data(up to 238 bytes) — only if > 119 samples
* Final (raa:): status(2) — only when skip_raa=0
*
* With 100 samples: 200 bytes = reb:(6+200) = 206 bytes (단일 패킷)
* With 100 samples: 200 bytes = reb:(6+200) = 206 bytes (single packet)
*/
dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_us,
uint16_t num_samples, uint8_t cycles,
uint16_t averaging, uint8_t piezo_ch,
uint8_t *ble_buffer, uint8_t skip_raa)
{
if (ble_buffer == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
if (ble_buffer == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
if (freq_option > 9) freq_option = 0; /* Invalid -> default 1.8MHz */
if (cycles < 3 || cycles > 7) cycles = 5; /* Valid range: 3~7, default 5 */
if (averaging == 0) averaging = 1; /* Minimum 1 */
if (averaging > 1000) averaging = 1000; /* Maximum 1000 */
if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0; /* 채널 범위 검증 */
}
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (freq_option > 9)
{
freq_option = 0; /* Invalid -> default 1.8MHz */
}
if (cycles < 3 || cycles > 7)
{
cycles = 5; /* Valid range: 3~7, default 5 */
}
if (averaging == 0)
{
averaging = 1; /* Minimum 1 */
}
if (averaging > 1000)
{
averaging = 1000; /* Maximum 1000 */
}
if (piezo_ch >= MAA_NUM_CHANNELS)
{
piezo_ch = 0; /* clamp channel range */
}
/* echo 분석은 PC에서 raw 데이터로 직접 수행 */
/* echo analysis is done on the PC from raw data */
/* Accumulator buffer for averaging (32-bit to prevent overflow) */
static uint32_t accum_buffer[DR_ADC_ECHO_SAMPLES_MAX];
@@ -594,7 +689,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
if (!m_initialized)
{
dr_adc_err_t init_err = dr_adc_init();
if (init_err != DR_ADC_OK) {
if (init_err != DR_ADC_OK)
{
return init_err;
}
}
@@ -605,15 +701,17 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
/*--- Step 2: Select piezo channel ---*/
dr_piezo_select_channel(piezo_ch);
/* MUX 전환 후 S/H 커패시터 안정화를 위한 dummy read */
/* dummy read after MUX switch to settle S/H capacitor */
(void)spim_read_raw();
/*--- Step 3~5: Burst + Delay + Capture ---*/
if (averaging == 1) {
if (averaging == 1)
{
/*=== SINGLE MEASUREMENT (no averaging) - direct path ===*/
/* Execute piezo burst based on frequency option */
switch (freq_option) {
switch (freq_option)
{
case 0:
default:
dr_piezo_burst_sw_18mhz(cycles); /* 1.8MHz (default) */
@@ -636,25 +734,32 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
}
/* Delay before capture (configurable, default 20us) */
if (delay_us > 0) {
if (delay_us > 0)
{
nrf_delay_us(delay_us);
}
/* Capture ADC samples directly to m_echo_buffer */
dr_adc_err_t err = dr_adc_capture_echo(m_echo_buffer, num_samples);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
//ADC_LOG("mec: single measurement (no averaging)");
}
else {
else
{
/*=== MULTIPLE MEASUREMENTS (with averaging) ===*/
/* Note: accum_buffer already cleared by memset at function start */
for (uint16_t avg_iter = 0; avg_iter < averaging; avg_iter++) {
for (uint16_t avg_iter = 0; avg_iter < averaging; avg_iter++)
{
/* Wait for previous echo to decay before next measurement
* 1ms = ~77cm round-trip decay time (sound speed 1.54mm/us)
* Skip delay on first iteration */
if (avg_iter > 0) {
if (avg_iter > 0)
{
nrf_delay_us(500); /* 500us between measurements */
}
@@ -663,7 +768,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
dr_piezo_select_channel(piezo_ch);
/* Execute piezo burst based on frequency option */
switch (freq_option) {
switch (freq_option)
{
case 0:
default:
dr_piezo_burst_sw_18mhz(cycles); /* 1.8MHz (default) */
@@ -686,22 +792,28 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
}
/* Delay before capture (configurable, default 20us) */
if (delay_us > 0) {
if (delay_us > 0)
{
nrf_delay_us(delay_us);
}
/* Capture ADC samples */
dr_adc_err_t err = dr_adc_capture_echo(m_echo_buffer, num_samples);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
/* Accumulate samples */
for (uint16_t i = 0; i < num_samples; i++) {
for (uint16_t i = 0; i < num_samples; i++)
{
accum_buffer[i] += m_echo_buffer[i];
}
}
/* Calculate average and store back to m_echo_buffer */
for (uint16_t i = 0; i < num_samples; i++) {
for (uint16_t i = 0; i < num_samples; i++)
{
m_echo_buffer[i] = (uint16_t)(accum_buffer[i] / averaging);
}
@@ -722,7 +834,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
uint16_t dst_idx = BLE_REB_HEADER_LEN;
uint16_t first_chunk = (total_data_bytes > BLE_REB_DATA_LEN) ? BLE_REB_DATA_LEN : total_data_bytes;
while (src_idx < num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk) {
while (src_idx < num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk)
{
uint16_t sample = m_echo_buffer[src_idx++] & 0x0FFF;
ble_buffer[dst_idx++] = (uint8_t)(sample >> 8);
ble_buffer[dst_idx++] = (uint8_t)(sample & 0xFF);
@@ -732,7 +845,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
/* Continuation packets (red:) — only if data didn't fit in reb: */
uint16_t pkt = 0;
while (src_idx < num_samples) {
while (src_idx < num_samples)
{
dr_sd_delay_ms(BLE_PACKET_DELAY_MS);
ble_buffer[0] = 'r'; ble_buffer[1] = 'e'; ble_buffer[2] = 'd'; ble_buffer[3] = ':';
@@ -740,7 +854,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
ble_buffer[5] = (uint8_t)(pkt & 0xFF);
dst_idx = BLE_RED_HEADER_LEN;
while (src_idx < num_samples && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN) {
while (src_idx < num_samples && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN)
{
uint16_t sample = m_echo_buffer[src_idx++] & 0x0FFF;
ble_buffer[dst_idx++] = (uint8_t)(sample >> 8);
ble_buffer[dst_idx++] = (uint8_t)(sample & 0xFF);
@@ -751,7 +866,8 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
}
/* raa: completion — skip_raa: 0=send (mec), 1=skip (maa - caller sends final raa) */
if (!skip_raa) {
if (!skip_raa)
{
dr_sd_delay_ms(BLE_PACKET_DELAY_MS);
ble_buffer[0] = 'r'; ble_buffer[1] = 'a'; ble_buffer[2] = 'a'; ble_buffer[3] = ':';
ble_buffer[4] = 0x00;
@@ -774,14 +890,34 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
uint16_t averaging, uint8_t piezo_ch,
dr_maa_channel_t *out_channel)
{
if (out_channel == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > MAA_SAMPLES_MAX)
if (out_channel == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
if (freq_option > 3) freq_option = 0;
if (cycles < 3 || cycles > 7) cycles = 5;
if (averaging == 0) averaging = 1;
if (averaging > 1000) averaging = 1000;
if (piezo_ch > (MAA_NUM_CHANNELS - 1)) piezo_ch = 0;
}
if (num_samples == 0 || num_samples > MAA_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (freq_option > 3)
{
freq_option = 0;
}
if (cycles < 3 || cycles > 7)
{
cycles = 5;
}
if (averaging == 0)
{
averaging = 1;
}
if (averaging > 1000)
{
averaging = 1000;
}
if (piezo_ch > (MAA_NUM_CHANNELS - 1))
{
piezo_ch = 0;
}
/* Accumulator buffer for averaging */
static uint32_t accum_buffer[MAA_SAMPLES_MAX];
@@ -790,22 +926,26 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
if (!m_initialized)
{
dr_adc_err_t init_err = dr_adc_init();
if (init_err != DR_ADC_OK) return init_err;
if (init_err != DR_ADC_OK)
{
return init_err;
}
}
//nrf_delay_us(100);
/* 채널 선택(MUX) : 1.3ms */
/* channel select (MUX) : ~1.3 ms */
dr_piezo_select_channel(piezo_ch);
/* MUX 전환 후 S/H 커패시터 안정화를 위한 dummy read */
/* dummy read after MUX switch to settle S/H capacitor */
(void)spim_read_raw();
/* 채널당 반복 측정 횟수만큼 */
/* repeat measurement 'averaging' times per channel */
for (uint16_t avg_iter = 0; avg_iter < averaging; avg_iter++)
{
/* TX 펄스 출력(Burst) */
switch (freq_option) {
/* TX burst pulse */
switch (freq_option)
{
case 0:
default:
dr_piezo_burst_sw_18mhz(cycles);
@@ -821,16 +961,19 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
break;
}
/* TX 펄스 출력 후 ADC 시작 시까지 대기 시간 */
/* delay from TX burst to ADC start */
if (delay_us > 0)
{
nrf_delay_us(delay_us);
}
/* 측정 ADC 샘플 수만큼 캡처 */
/* capture num_samples ADC readings */
dr_adc_err_t err = dr_adc_capture_echo(m_echo_buffer, num_samples);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
/* Accumulate */
for (uint16_t i = 0; i < num_samples; i++)
@@ -846,7 +989,7 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
}
out_channel->num_samples = num_samples;
/* peak/baseline 분석은 PC에서 raw 데이터로 직접 수행 */
/* peak/baseline analysis is done on the PC from raw data */
return DR_ADC_OK;
}
@@ -855,7 +998,8 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
uint8_t *ble_buffer)
{
if (ch_data == NULL || ble_buffer == NULL) {
if (ch_data == NULL || ble_buffer == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
@@ -869,7 +1013,8 @@ dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
uint16_t dst_idx = BLE_REB_HEADER_LEN;
uint16_t first_chunk = (total_data_bytes > BLE_REB_DATA_LEN) ? BLE_REB_DATA_LEN : total_data_bytes;
while (src_idx < ch_data->num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk) {
while (src_idx < ch_data->num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk)
{
uint16_t sample = ch_data->samples[src_idx++] & 0x0FFF;
ble_buffer[dst_idx++] = (uint8_t)(sample >> 8);
ble_buffer[dst_idx++] = (uint8_t)(sample & 0xFF);
@@ -879,7 +1024,8 @@ dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
/* Continuation packets (red:) — only if data didn't fit in reb: */
uint16_t pkt = 0;
while (src_idx < ch_data->num_samples) {
while (src_idx < ch_data->num_samples)
{
dr_sd_delay_ms(BLE_PACKET_DELAY_MS);
ble_buffer[0] = 'r'; ble_buffer[1] = 'e'; ble_buffer[2] = 'd'; ble_buffer[3] = ':';
@@ -887,7 +1033,8 @@ dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
ble_buffer[5] = (uint8_t)(pkt & 0xFF);
dst_idx = BLE_RED_HEADER_LEN;
while (src_idx < ch_data->num_samples && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN) {
while (src_idx < ch_data->num_samples && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN)
{
uint16_t sample = ch_data->samples[src_idx++] & 0x0FFF;
ble_buffer[dst_idx++] = (uint8_t)(sample >> 8);
ble_buffer[dst_idx++] = (uint8_t)(sample & 0xFF);
@@ -909,8 +1056,11 @@ dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples
uint8_t *out_buffer, uint16_t *out_size)
{
if (samples == NULL || out_buffer == NULL || out_size == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0) {
}
if (num_samples == 0)
{
*out_size = 0;
return DR_ADC_OK;
}
@@ -922,13 +1072,17 @@ dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples
out_buffer[idx++] = (uint8_t)(samples[0] & 0xFF);
/* Delta encode remaining samples */
for (uint16_t i = 1; i < num_samples; i++) {
for (uint16_t i = 1; i < num_samples; i++)
{
int16_t delta = (int16_t)samples[i] - (int16_t)samples[i-1];
if (delta >= -127 && delta <= 127) {
if (delta >= -127 && delta <= 127)
{
/* Normal delta: fits in signed 8-bit */
out_buffer[idx++] = (int8_t)delta;
} else {
}
else
{
/* Out of range: escape + 16-bit raw value */
out_buffer[idx++] = DELTA_ESCAPE_BYTE;
out_buffer[idx++] = (uint8_t)(samples[i] >> 8);
@@ -944,7 +1098,10 @@ dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples
dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
uint8_t *ble_buffer)
{
if (ch_data == NULL || ble_buffer == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (ch_data == NULL || ble_buffer == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Compress data first */
static uint8_t delta_buffer[400]; /* Worst case: 140*3 = 420 bytes */
@@ -952,7 +1109,10 @@ dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
dr_adc_err_t err = dr_adc_delta_compress(ch_data->samples, ch_data->num_samples,
delta_buffer, &compressed_size);
if (err != DR_ADC_OK) return err;
if (err != DR_ADC_OK)
{
return err;
}
ADC_LOG("maa delta: %u samples -> %u bytes (%.0f%%)",
ch_data->num_samples, compressed_size,
@@ -971,17 +1131,22 @@ dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
uint16_t dst_idx = BLE_RDB_HEADER_LEN;
uint16_t src_idx = 0;
uint16_t first_chunk = (compressed_size > rdb_data_cap) ? rdb_data_cap : compressed_size;
while (src_idx < first_chunk) {
while (src_idx < first_chunk)
{
ble_buffer[dst_idx++] = delta_buffer[src_idx++];
}
/* Pad to word boundary if needed */
if (dst_idx & 1) ble_buffer[dst_idx++] = 0;
if (dst_idx & 1)
{
ble_buffer[dst_idx++] = 0;
}
dr_binary_tx_safe(ble_buffer, dst_idx / 2);
/* Continuation packets (rdd:) — only if data didn't fit */
uint16_t pkt = 0;
while (src_idx < compressed_size) {
while (src_idx < compressed_size)
{
dr_sd_delay_ms(BLE_PACKET_DELAY_MS);
ble_buffer[0] = 'r'; ble_buffer[1] = 'd'; ble_buffer[2] = 'd'; ble_buffer[3] = ':';
@@ -989,10 +1154,14 @@ dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
ble_buffer[5] = (uint8_t)(pkt & 0xFF);
dst_idx = BLE_RED_HEADER_LEN;
while (src_idx < compressed_size && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN) {
while (src_idx < compressed_size && (dst_idx - BLE_RED_HEADER_LEN) < BLE_RED_DATA_LEN)
{
ble_buffer[dst_idx++] = delta_buffer[src_idx++];
}
if (dst_idx & 1) ble_buffer[dst_idx++] = 0;
if (dst_idx & 1)
{
ble_buffer[dst_idx++] = 0;
}
dr_binary_tx_safe(ble_buffer, dst_idx / 2);
pkt++;
@@ -1012,14 +1181,17 @@ dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
/* Global async context */
static maa_async_ctx_t g_maa_ctx = { .state = MAA_ASYNC_IDLE };
/* (version marker 제거 — reb+red merged protocol) */
/* (reb+red merged protocol) */
/**
* @brief Capture one channel (internal helper)
*/
static dr_adc_err_t maa_async_capture_channel(uint8_t ch)
{
if (ch > (MAA_NUM_CHANNELS - 1)) return DR_ADC_ERR_INVALID_PARAM;
if (ch > (MAA_NUM_CHANNELS - 1))
{
return DR_ADC_ERR_INVALID_PARAM;
}
dr_adc_err_t err = dr_adc_capture_channel_only(
g_maa_ctx.freq_option,
@@ -1038,7 +1210,7 @@ static dr_adc_err_t maa_async_capture_channel(uint8_t ch)
* @brief Send reb: header + data merged for current channel
*
* reb: tag(4) + num_samples(2) + data(up to 238 bytes)
* 100샘플(200B) 이하면 이 패킷 하나로 채널 전송 완료
* If <= 100 samples (200B), the channel completes in this single packet
*/
static void maa_async_send_header(void)
{
@@ -1055,22 +1227,26 @@ static void maa_async_send_header(void)
uint16_t dst_idx = BLE_REB_HEADER_LEN;
uint16_t first_chunk = (total_data_bytes > BLE_REB_DATA_LEN) ? BLE_REB_DATA_LEN : total_data_bytes;
uint16_t src_idx = 0;
while (src_idx < ch->num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk) {
while (src_idx < ch->num_samples && (dst_idx - BLE_REB_HEADER_LEN) < first_chunk)
{
uint16_t sample = ch->samples[src_idx++];
buf[dst_idx++] = (uint8_t)(sample >> 8);
buf[dst_idx++] = (uint8_t)(sample & 0xFF);
}
dr_binary_tx_safe(buf, dst_idx / 2);
dr_sd_delay_ms(5); /* dr_binary_tx_safe 내부 재시도(40ms)로 TX 완료 보장, 최소 딜레이만 */
dr_sd_delay_ms(5); /* minimal delay; dr_binary_tx_safe retries internally (40 ms) */
g_maa_ctx.current_pkt = 0;
g_maa_ctx.data_offset = src_idx * 2; /* 이미 전송한 바이트 수 */
g_maa_ctx.data_offset = src_idx * 2; /* bytes already sent */
/* 데이터가 첫 패킷에 다 들어갔으면 바로 다음 채널로 */
if (g_maa_ctx.data_offset >= total_data_bytes) {
g_maa_ctx.state = MAA_ASYNC_TX_DATA; /* send_data_packet()에서 false 반환 → 다음 채널 */
} else {
/* if all data fit in the first packet, advance to next channel */
if (g_maa_ctx.data_offset >= total_data_bytes)
{
g_maa_ctx.state = MAA_ASYNC_TX_DATA; /* send_data_packet() returns false -> next channel */
}
else
{
g_maa_ctx.state = MAA_ASYNC_TX_DATA;
}
}
@@ -1138,17 +1314,17 @@ static void maa_async_send_completion(uint16_t status)
//if (g_plat.log) g_plat.log("-------------------------------------------------------------------------------------\r\n");
/* 캡처 완료 → Piezo TX/RX 전원 OFF */
/* capture complete -> Piezo TX/RX power OFF */
dr_piezo_power_off();
g_maa_ctx.state = MAA_ASYNC_IDLE;
//ADC_LOG("maa_async: complete, status=0x%04X", status);
/* 완료 콜백 호출 (mbb? 등에서 센서 측정 체인 트리거용) */
/* completion callback (used by mbb? to trigger sensor chain) */
if (g_maa_ctx.on_complete_cb)
{
void (*cb)(void) = g_maa_ctx.on_complete_cb;
g_maa_ctx.on_complete_cb = NULL; /* 1회성: 재호출 방지 */
g_maa_ctx.on_complete_cb = NULL; /* one-shot: prevent re-entry */
cb();
}
}
@@ -1168,9 +1344,14 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us, uint16_t nu
return DR_ADC_ERR_NOT_INIT; /* Already running */
}
if (ble_buffer == NULL) return DR_ADC_ERR_INVALID_PARAM;
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
if (ble_buffer == NULL)
{
return DR_ADC_ERR_INVALID_PARAM;
}
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
{
return DR_ADC_ERR_INVALID_PARAM;
}
/* Initialize context */
g_maa_ctx.freq_option = freq_option;
@@ -1182,9 +1363,9 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us, uint16_t nu
g_maa_ctx.current_ch = 0;
g_maa_ctx.current_pkt = 0;
g_maa_ctx.data_offset = 0;
g_maa_ctx.on_complete_cb = NULL; /* 기본: 콜백 없음 (maa?) */
g_maa_ctx.on_complete_cb = NULL; /* default: no callback (maa?) */
/* 전채널 캡처: BLE 전송 없이 6채널 전부 캡처 완료 후 TX 시작 */
/* capture all channels without BLE TX, then start transmission */
g_maa_ctx.state = MAA_ASYNC_CAPTURING;
for (ch = 0; ch < MAA_NUM_CHANNELS; ch++)
@@ -1192,16 +1373,19 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us, uint16_t nu
err = maa_async_capture_channel(ch);
if (err != DR_ADC_OK)
{
if (g_plat.log) g_plat.log("[maa] maa_async_start: CH%u capture failed (%d)", ch, err);
if (g_plat.log)
{
g_plat.log("[maa] maa_async_start: CH%u capture failed (%d)", ch, err);
}
maa_async_send_completion(0xFFF0 | ch);
return err;
}
}
/* peak 로그와 raw 덤프 사이 구분 */
/* separator between peak log and raw dump */
//if (g_plat.log) g_plat.log("\r\n");
/* 캡처 완료 → Piezo TX/RX 전원 OFF (BLE 전송 중 불필요) */
/* capture done -> Piezo TX/RX power OFF (not needed during BLE TX) */
dr_piezo_power_off();
/* Send CH0 header - this will trigger TX_RDY for subsequent packets */
@@ -1217,7 +1401,8 @@ bool maa_async_on_tx_ready(void)
return false;
}
switch (g_maa_ctx.state) {
switch (g_maa_ctx.state)
{
case MAA_ASYNC_TX_DATA:
/* Send next data packet */
if (!maa_async_send_data_packet())
@@ -1234,7 +1419,7 @@ bool maa_async_on_tx_ready(void)
}
else
{
/* 이미 전채널 캡처됨, 바로 헤더 전송 */
/* all channels already captured, send header directly */
g_maa_ctx.state = MAA_ASYNC_CAPTURING;
maa_async_send_header();
}
@@ -1274,16 +1459,18 @@ maa_async_state_t maa_async_get_state(void)
}
/*==============================================================================
* 비동기 측정 상태 IDLE로 초기화 - BLE 연결이 끊어지는 경우 먹통 현상 방지
* maa_async_abort - Reset async state to IDLE
*
* Prevents hang when BLE disconnects mid-measurement.
*============================================================================*/
void maa_async_abort(void)
{
if (g_maa_ctx.state != MAA_ASYNC_IDLE)
{
ADC_LOG("maa_async_abort: aborting from state %d", g_maa_ctx.state);
g_maa_ctx.state = MAA_ASYNC_IDLE; // 측정 상태 IDLE로 초기화
g_maa_ctx.on_complete_cb = NULL; // abort 후 콜백 호출 방지
dr_piezo_power_off(); // 전체 측정 중간에 끊기는 경우 Piezo TX/RX Sleep
g_maa_ctx.state = MAA_ASYNC_IDLE;
g_maa_ctx.on_complete_cb = NULL;
dr_piezo_power_off();
}
}

View File

@@ -450,8 +450,8 @@ typedef struct {
uint16_t averaging; /**< Averaging count */
uint8_t *ble_buffer; /**< Working buffer for BLE packets */
dr_maa_channel_t channels[MAA_NUM_CHANNELS]; /**< Captured data for each channel */
bool pre_capture_all; /**< true: 전채널 캡처 완료 후 일괄 전송 (mbb) */
void (*on_complete_cb)(void); /**< 비동기 캡처 완료 후 호출될 콜백 (NULL이면 미사용) */
bool pre_capture_all; /**< true: capture all channels before transmitting (mbb) */
void (*on_complete_cb)(void); /**< callback after async capture completes (NULL = none) */
} maa_async_ctx_t;
/**
@@ -500,15 +500,14 @@ maa_async_state_t maa_async_get_state(void);
void maa_async_abort(void);
/**
* @brief 자동 전원 플래그 설정 (완료 후 자동 power off)
* @brief Set auto power-off flag (power off after completion)
*/
void maa_async_set_auto_power(bool on);
void maa_async_set_pre_capture_all(bool on);
/**
* @brief 비동기 캡처 완료 콜백 설정
* raa: 전송 + 전원 OFF 이후 호출된다. NULL이면 콜백 없음.
* @brief Set async capture completion callback
* Called after raa: is transmitted and power-off. NULL = no callback.
*/
void maa_async_set_on_complete(void (*cb)(void));