fix: BLE TX 먹통 해결 및 메모리 안전성 개선
- binary_tx_handler를 dr_binary_tx_safe로 전체 교체 (APP_ERROR_CHECK 제거) - data_tx_handler APP_ERROR_CHECK → DBG_PRINTF 교체 - memset/memcpy 하드코딩 크기를 define 상수로 교체 (버퍼 오버런 수정) - SERIAL_NO_LENGTH, HW_NO_LENGTH, PASSKEY_LENGTH를 main.h로 통합 - 미사용 HW 드라이버/EEPROM 코드 삭제, TWI를 i2c_manager.c로 통합 - EEPROM → FDS 전환, 코드 리뷰 현황 문서 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -710,7 +710,6 @@ void dr_adc_print_buffer(const uint16_t *buffer, uint16_t num_samples)
|
||||
*============================================================================*/
|
||||
|
||||
/* External BLE NUS functions and variables from main.c */
|
||||
extern void binary_tx_handler(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
extern void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
extern void dr_sd_delay_ms(uint32_t ms);
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
|
||||
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
|
||||
extern void format_data(uint8_t *buffer, const char *tag, uint16_t *data, uint8_t length);
|
||||
extern void binary_tx_handler(uint8_t *buffer, uint8_t length);
|
||||
extern uint8_t ble_bin_buffer[];
|
||||
|
||||
/* Use dr_binary_tx_safe from main.c - has retry logic for BLE TX queue */
|
||||
extern void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
|
||||
void dr_ble_return_1(const char *tag, uint16_t value)
|
||||
|
||||
533
pc_firm/dr_w25q32/dr_w25q32.c
Normal file
533
pc_firm/dr_w25q32/dr_w25q32.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*******************************************************************************
|
||||
* @file dr_w25q32.c
|
||||
* @brief W25Q32 SPI Flash Driver for nRF52840
|
||||
* Software SPI (bit-bang) implementation
|
||||
* @date 2026-03-12
|
||||
*
|
||||
* @details Bit-bang SPI driver for W25Q32 NOR Flash.
|
||||
* SPI Mode 0 (CPOL=0, CPHA=0):
|
||||
* - SCLK idle LOW
|
||||
* - Data sampled on rising edge
|
||||
* - Data shifted out on falling edge
|
||||
*
|
||||
* W25Q32 SPI timing:
|
||||
* CS ──┐ ┌──
|
||||
* └────────────────────────────────────┘
|
||||
* CLK ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
|
||||
* ─────┘ └──┘ └──┘ └── ... ┘ └──┘ └────
|
||||
* DI <CMD7><CMD6><CMD5>...<D1 ><D0 >
|
||||
* DO <Z ><Z ><Z >...<D1 ><D0 >
|
||||
******************************************************************************/
|
||||
|
||||
#include "dr_w25q32.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "debug_print.h"
|
||||
#include <string.h>
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE DEFINES
|
||||
*============================================================================*/
|
||||
|
||||
#define DR_PIN_NUM(pin) ((pin) & 0x1F)
|
||||
#define DR_PIN_PORT(pin) (((pin) >> 5) & 0x01)
|
||||
|
||||
/* Pin masks for direct register access */
|
||||
#define FLASH_CS_MASK (1UL << DR_PIN_NUM(DR_FLASH_PIN_CS))
|
||||
#define FLASH_SCLK_MASK (1UL << DR_PIN_NUM(DR_FLASH_PIN_SCLK))
|
||||
#define FLASH_MISO_MASK (1UL << DR_PIN_NUM(DR_FLASH_PIN_MISO))
|
||||
#define FLASH_MOSI_MASK (1UL << DR_PIN_NUM(DR_FLASH_PIN_MOSI))
|
||||
|
||||
/* Port registers - all pins on P0 */
|
||||
#define FLASH_PORT NRF_P0 // NRF_P0: 포트 레지스터에 접근하는 베이스 포인터(포트 전체 제어 X)
|
||||
|
||||
/* Timeout for busy wait (ms) */
|
||||
#define BUSY_TIMEOUT_PAGE_PROGRAM 10
|
||||
#define BUSY_TIMEOUT_SECTOR_ERASE 500
|
||||
#define BUSY_TIMEOUT_BLOCK_ERASE 2000
|
||||
#define BUSY_TIMEOUT_CHIP_ERASE 60000
|
||||
|
||||
/* W25Q32 JEDEC ID expected values */
|
||||
#define W25Q32_MANUFACTURER_ID 0xEF
|
||||
#define W25Q32_MEMORY_TYPE 0x40
|
||||
#define W25Q32_CAPACITY 0x16
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
static bool m_initialized = false;
|
||||
|
||||
/*==============================================================================
|
||||
* LOW-LEVEL SPI BIT-BANG
|
||||
*
|
||||
* W25Q32 uses SPI Mode 0:
|
||||
* - CPOL=0: Clock idle LOW
|
||||
* - CPHA=0: Data sampled on rising edge, shifted on falling edge
|
||||
*============================================================================*/
|
||||
|
||||
static inline void flash_cs_low(void)
|
||||
{
|
||||
FLASH_PORT->OUTCLR = FLASH_CS_MASK;
|
||||
}
|
||||
|
||||
static inline void flash_cs_high(void)
|
||||
{
|
||||
FLASH_PORT->OUTSET = FLASH_CS_MASK;
|
||||
}
|
||||
|
||||
static inline void flash_sclk_low(void)
|
||||
{
|
||||
FLASH_PORT->OUTCLR = FLASH_SCLK_MASK;
|
||||
}
|
||||
|
||||
static inline void flash_sclk_high(void)
|
||||
{
|
||||
FLASH_PORT->OUTSET = FLASH_SCLK_MASK;
|
||||
}
|
||||
|
||||
static inline void flash_mosi_high(void)
|
||||
{
|
||||
FLASH_PORT->OUTSET = FLASH_MOSI_MASK;
|
||||
}
|
||||
|
||||
static inline void flash_mosi_low(void)
|
||||
{
|
||||
FLASH_PORT->OUTCLR = FLASH_MOSI_MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t flash_read_miso(void)
|
||||
{
|
||||
return (FLASH_PORT->IN & FLASH_MISO_MASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send one byte via SPI (MSB first)
|
||||
*/
|
||||
static void spi_send_byte(uint8_t byte)
|
||||
{
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
/* Set MOSI */
|
||||
if (byte & (1 << i))
|
||||
flash_mosi_high();
|
||||
else
|
||||
flash_mosi_low();
|
||||
|
||||
/* Rising edge - data sampled by slave */
|
||||
flash_sclk_high();
|
||||
__NOP();
|
||||
__NOP();
|
||||
|
||||
/* Falling edge */
|
||||
flash_sclk_low();
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receive one byte via SPI (MSB first)
|
||||
* @note Sends 0xFF (MOSI high) while reading
|
||||
*/
|
||||
static uint8_t spi_recv_byte(void)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
|
||||
flash_mosi_high(); /* Keep MOSI high during read */
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
/* Rising edge - sample MISO */
|
||||
flash_sclk_high();
|
||||
__NOP();
|
||||
__NOP();
|
||||
|
||||
if (flash_read_miso())
|
||||
byte |= (1 << i);
|
||||
|
||||
/* Falling edge */
|
||||
flash_sclk_low();
|
||||
__NOP();
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize GPIO pins
|
||||
*/
|
||||
static void flash_gpio_init(void)
|
||||
{
|
||||
/* CS: Output, HIGH (deselected) */
|
||||
nrf_gpio_cfg_output(DR_FLASH_PIN_CS);
|
||||
nrf_gpio_pin_set(DR_FLASH_PIN_CS);
|
||||
|
||||
/* SCLK: Output, LOW (idle for Mode 0) */
|
||||
nrf_gpio_cfg_output(DR_FLASH_PIN_SCLK);
|
||||
nrf_gpio_pin_clear(DR_FLASH_PIN_SCLK);
|
||||
|
||||
/* MOSI: Output, HIGH */
|
||||
nrf_gpio_cfg_output(DR_FLASH_PIN_MOSI);
|
||||
nrf_gpio_pin_set(DR_FLASH_PIN_MOSI);
|
||||
|
||||
/* MISO: Input, no pull */
|
||||
nrf_gpio_cfg_input(DR_FLASH_PIN_MISO, NRF_GPIO_PIN_NOPULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send Write Enable command (0x06)
|
||||
*/
|
||||
static void flash_write_enable(void)
|
||||
{
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_WRITE_ENABLE);
|
||||
flash_cs_high();
|
||||
__NOP(); __NOP(); __NOP(); __NOP();
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_init(void)
|
||||
{
|
||||
DBG_PRINTF("[FLASH] Init\n");
|
||||
flash_gpio_init();
|
||||
m_initialized = true;
|
||||
DBG_PRINTF("[FLASH] Init OK\n");
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
void dr_w25q32_uninit(void)
|
||||
{
|
||||
if (!m_initialized) return;
|
||||
|
||||
DBG_PRINTF("[FLASH] Uninit\n");
|
||||
|
||||
/* CS high (deselect) */
|
||||
nrf_gpio_pin_set(DR_FLASH_PIN_CS);
|
||||
|
||||
/* Release pins to default */
|
||||
nrf_gpio_cfg_default(DR_FLASH_PIN_CS);
|
||||
|
||||
/* Don't release shared pins (SCLK, MISO, MOSI) -
|
||||
they may be in use by ADC121S051 */
|
||||
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
bool dr_w25q32_is_initialized(void)
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - IDENTIFICATION
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_read_jedec_id(dr_flash_jedec_t *jedec) //JEDEC ID 읽기 (0xEF, 0x40, 0x16)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (!jedec) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_READ_JEDEC_ID);
|
||||
jedec->manufacturer_id = spi_recv_byte();
|
||||
jedec->memory_type = spi_recv_byte();
|
||||
jedec->capacity = spi_recv_byte();
|
||||
flash_cs_high();
|
||||
|
||||
DBG_PRINTF("[FLASH] JEDEC ID: 0x%02X 0x%02X 0x%02X\n",
|
||||
jedec->manufacturer_id, jedec->memory_type, jedec->capacity);
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_read_uid(uint8_t *uid) // 8바이트 고유 ID 읽기
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (!uid) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_READ_UID);
|
||||
|
||||
/* 4 dummy bytes */
|
||||
spi_send_byte(0x00);
|
||||
spi_send_byte(0x00);
|
||||
spi_send_byte(0x00);
|
||||
spi_send_byte(0x00);
|
||||
|
||||
/* 8-byte unique ID */
|
||||
for (int i = 0; i < DR_FLASH_UID_LENGTH; i++)
|
||||
{
|
||||
uid[i] = spi_recv_byte();
|
||||
}
|
||||
flash_cs_high();
|
||||
|
||||
DBG_PRINTF("[FLASH] UID: %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]);
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - STATUS
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_read_status(uint8_t *status)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (!status) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_READ_STATUS1);
|
||||
*status = spi_recv_byte();
|
||||
flash_cs_high();
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
bool dr_w25q32_is_busy(void)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
dr_w25q32_read_status(&status);
|
||||
return (status & DR_FLASH_SR1_BUSY) ? true : false;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_wait_busy(uint32_t timeout_ms)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
|
||||
while (timeout_ms > 0)
|
||||
{
|
||||
if (!dr_w25q32_is_busy())
|
||||
return DR_FLASH_OK;
|
||||
|
||||
nrf_delay_ms(1);
|
||||
timeout_ms--;
|
||||
}
|
||||
|
||||
return DR_FLASH_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - READ
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_read(uint32_t addr, uint8_t *buf, uint32_t len) // 데이터 읽기 (주소, 길이)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (!buf || len == 0) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
if (addr + len > DR_FLASH_TOTAL_SIZE) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
DBG_PRINTF("[FLASH] Read addr=0x%06X len=%d\n", addr, len);
|
||||
|
||||
flash_cs_low();
|
||||
|
||||
/* Command + 24-bit address */
|
||||
spi_send_byte(DR_FLASH_CMD_READ_DATA);
|
||||
spi_send_byte((addr >> 16) & 0xFF);
|
||||
spi_send_byte((addr >> 8) & 0xFF);
|
||||
spi_send_byte((addr ) & 0xFF);
|
||||
|
||||
/* Read data */
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
buf[i] = spi_recv_byte();
|
||||
}
|
||||
|
||||
flash_cs_high();
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - WRITE
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_write(uint32_t addr, const uint8_t *data, uint32_t len) // 페이지 쓰기 (최대 256B)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (!data || len == 0 || len > DR_FLASH_PAGE_SIZE)
|
||||
return DR_FLASH_ERR_INVALID_PARAM;
|
||||
if (addr + len > DR_FLASH_TOTAL_SIZE)
|
||||
return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
/* Check page boundary crossing */
|
||||
uint32_t page_offset = addr % DR_FLASH_PAGE_SIZE;
|
||||
if (page_offset + len > DR_FLASH_PAGE_SIZE)
|
||||
return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
DBG_PRINTF("[FLASH] Write addr=0x%06X len=%d\n", addr, len);
|
||||
|
||||
/* Write Enable */
|
||||
flash_write_enable();
|
||||
|
||||
/* Page Program */
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_PAGE_PROGRAM);
|
||||
spi_send_byte((addr >> 16) & 0xFF);
|
||||
spi_send_byte((addr >> 8) & 0xFF);
|
||||
spi_send_byte((addr ) & 0xFF);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
spi_send_byte(data[i]);
|
||||
}
|
||||
|
||||
flash_cs_high();
|
||||
|
||||
/* Wait for programming to complete */
|
||||
dr_flash_err_t err = dr_w25q32_wait_busy(BUSY_TIMEOUT_PAGE_PROGRAM);
|
||||
if (err != DR_FLASH_OK)
|
||||
DBG_PRINTF("[FLASH] Write TIMEOUT!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - ERASE
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_erase_sector(uint32_t addr) // 4KB 섹터 삭제
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (addr >= DR_FLASH_TOTAL_SIZE) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
DBG_PRINTF("[FLASH] Erase sector addr=0x%06X\n", addr);
|
||||
|
||||
flash_write_enable();
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_SECTOR_ERASE);
|
||||
spi_send_byte((addr >> 16) & 0xFF);
|
||||
spi_send_byte((addr >> 8) & 0xFF);
|
||||
spi_send_byte((addr ) & 0xFF);
|
||||
flash_cs_high();
|
||||
|
||||
dr_flash_err_t err = dr_w25q32_wait_busy(BUSY_TIMEOUT_SECTOR_ERASE);
|
||||
if (err != DR_FLASH_OK)
|
||||
DBG_PRINTF("[FLASH] Erase sector TIMEOUT!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_erase_block_32k(uint32_t addr) // 블록 삭제
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (addr >= DR_FLASH_TOTAL_SIZE) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
DBG_PRINTF("[FLASH] Erase block 32K addr=0x%06X\n", addr);
|
||||
|
||||
flash_write_enable();
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_BLOCK_ERASE_32K);
|
||||
spi_send_byte((addr >> 16) & 0xFF);
|
||||
spi_send_byte((addr >> 8) & 0xFF);
|
||||
spi_send_byte((addr ) & 0xFF);
|
||||
flash_cs_high();
|
||||
|
||||
dr_flash_err_t err = dr_w25q32_wait_busy(BUSY_TIMEOUT_BLOCK_ERASE);
|
||||
if (err != DR_FLASH_OK)
|
||||
DBG_PRINTF("[FLASH] Erase block 32K TIMEOUT!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_erase_block_64k(uint32_t addr) // 블록 삭제
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
if (addr >= DR_FLASH_TOTAL_SIZE) return DR_FLASH_ERR_INVALID_PARAM;
|
||||
|
||||
DBG_PRINTF("[FLASH] Erase block 64K addr=0x%06X\n", addr);
|
||||
|
||||
flash_write_enable();
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_BLOCK_ERASE_64K);
|
||||
spi_send_byte((addr >> 16) & 0xFF);
|
||||
spi_send_byte((addr >> 8) & 0xFF);
|
||||
spi_send_byte((addr ) & 0xFF);
|
||||
flash_cs_high();
|
||||
|
||||
dr_flash_err_t err = dr_w25q32_wait_busy(BUSY_TIMEOUT_BLOCK_ERASE);
|
||||
if (err != DR_FLASH_OK)
|
||||
DBG_PRINTF("[FLASH] Erase block 64K TIMEOUT!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_chip_erase(void) // 전체 삭제
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
|
||||
DBG_PRINTF("[FLASH] Chip erase...\n");
|
||||
|
||||
flash_write_enable();
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_CHIP_ERASE);
|
||||
flash_cs_high();
|
||||
|
||||
dr_flash_err_t err = dr_w25q32_wait_busy(BUSY_TIMEOUT_CHIP_ERASE);
|
||||
if (err == DR_FLASH_OK)
|
||||
DBG_PRINTF("[FLASH] Chip erase OK\n");
|
||||
else
|
||||
DBG_PRINTF("[FLASH] Chip erase TIMEOUT!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - POWER MANAGEMENT
|
||||
*============================================================================*/
|
||||
|
||||
dr_flash_err_t dr_w25q32_deep_powerdown(void) // 저전력 모드 (~1uA)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
|
||||
DBG_PRINTF("[FLASH] Deep power-down\n");
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_POWER_DOWN);
|
||||
flash_cs_high();
|
||||
|
||||
/* tDP: CS high to deep power-down = 3us max */
|
||||
nrf_delay_us(5);
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
dr_flash_err_t dr_w25q32_wakeup(void) // 저전력 모드 해제(깨우기)
|
||||
{
|
||||
if (!m_initialized) return DR_FLASH_ERR_NOT_INIT;
|
||||
|
||||
DBG_PRINTF("[FLASH] Wakeup\n");
|
||||
|
||||
flash_cs_low();
|
||||
spi_send_byte(DR_FLASH_CMD_RELEASE_PD);
|
||||
flash_cs_high();
|
||||
|
||||
/* tRES1: CS high to standby = 3us max */
|
||||
nrf_delay_us(5);
|
||||
|
||||
return DR_FLASH_OK;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - DEBUG / TEST
|
||||
*============================================================================*/
|
||||
|
||||
bool dr_w25q32_test(void) // JEDEC ID로 통신 테스트
|
||||
{
|
||||
dr_flash_jedec_t jedec;
|
||||
|
||||
if (dr_w25q32_read_jedec_id(&jedec) != DR_FLASH_OK)
|
||||
{
|
||||
DBG_PRINTF("[FLASH] Test FAIL - read error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pass = (jedec.manufacturer_id == W25Q32_MANUFACTURER_ID &&
|
||||
jedec.memory_type == W25Q32_MEMORY_TYPE &&
|
||||
jedec.capacity == W25Q32_CAPACITY);
|
||||
|
||||
DBG_PRINTF("[FLASH] Test %s\n", pass ? "PASS" : "FAIL");
|
||||
return pass;
|
||||
}
|
||||
245
pc_firm/dr_w25q32/dr_w25q32.h
Normal file
245
pc_firm/dr_w25q32/dr_w25q32.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/*******************************************************************************
|
||||
* @file dr_w25q32.h
|
||||
* @brief W25Q32 SPI Flash Driver for nRF52840
|
||||
* 32Mbit (4MB) Serial NOR Flash Memory
|
||||
* @date 2026-03-12
|
||||
*
|
||||
* @details Software SPI (bit-bang) driver for W25Q32RVXHJQ.
|
||||
* Shares SPI bus (SCK/MISO/MOSI) with ADC121S051.
|
||||
* Only CS pin is unique (P0.24).
|
||||
*
|
||||
* Pin connections:
|
||||
* nRF52840 W25Q32 (U16)
|
||||
* P0.24 -----> /CS (pin 1)
|
||||
* P0.15 <----- DO (pin 2, MISO)
|
||||
* P0.16 -----> DI (pin 5, MOSI)
|
||||
* P0.14 -----> CLK (pin 6)
|
||||
*
|
||||
* @note WP (pin 3) and HOLD (pin 7) are pulled HIGH via 10k resistors.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DR_W25Q32_H
|
||||
#define DR_W25Q32_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_gpio.h"
|
||||
|
||||
/*==============================================================================
|
||||
* PIN CONFIGURATION
|
||||
*============================================================================*/
|
||||
#define DR_FLASH_PIN_CS NRF_GPIO_PIN_MAP(0, 24) /* Chip Select - SPI_CS_FLASH(P0.24) */
|
||||
#define DR_FLASH_PIN_SCLK NRF_GPIO_PIN_MAP(0, 14) /* Serial Clock(shared) - SPI_SCK(P0.14) */
|
||||
#define DR_FLASH_PIN_MISO NRF_GPIO_PIN_MAP(0, 15) /* DI_(IO0)(shared) - SPI_MOSI(P0.15) */
|
||||
#define DR_FLASH_PIN_MOSI NRF_GPIO_PIN_MAP(0, 16) /* DO_(IO1)(shared) - SPI_MISO(P0.16) */
|
||||
|
||||
/*==============================================================================
|
||||
* W25Q32 SPECIFICATIONS
|
||||
*============================================================================*/
|
||||
#define DR_FLASH_PAGE_SIZE 256 /**< Page size (bytes) */
|
||||
#define DR_FLASH_SECTOR_SIZE 4096 /**< Sector size (bytes, 4KB) */
|
||||
#define DR_FLASH_BLOCK_32K (32*1024) /**< 32KB block */
|
||||
#define DR_FLASH_BLOCK_64K (64*1024) /**< 64KB block */
|
||||
#define DR_FLASH_TOTAL_SIZE (4*1024*1024) /**< 4MB total */
|
||||
#define DR_FLASH_UID_LENGTH 8 /**< Unique ID length (bytes) */
|
||||
|
||||
/*==============================================================================
|
||||
* W25Q32 COMMAND OPCODES
|
||||
*============================================================================*/
|
||||
#define DR_FLASH_CMD_WRITE_ENABLE 0x06
|
||||
#define DR_FLASH_CMD_WRITE_DISABLE 0x04
|
||||
#define DR_FLASH_CMD_READ_STATUS1 0x05
|
||||
#define DR_FLASH_CMD_READ_STATUS2 0x35
|
||||
#define DR_FLASH_CMD_WRITE_STATUS 0x01
|
||||
#define DR_FLASH_CMD_READ_DATA 0x03
|
||||
#define DR_FLASH_CMD_PAGE_PROGRAM 0x02
|
||||
#define DR_FLASH_CMD_SECTOR_ERASE 0x20 /**< 4KB erase */
|
||||
#define DR_FLASH_CMD_BLOCK_ERASE_32K 0x52 /**< 32KB erase */
|
||||
#define DR_FLASH_CMD_BLOCK_ERASE_64K 0xD8 /**< 64KB erase */
|
||||
#define DR_FLASH_CMD_CHIP_ERASE 0xC7 /**< Full chip erase */
|
||||
#define DR_FLASH_CMD_POWER_DOWN 0xB9 /**< Deep power-down */
|
||||
#define DR_FLASH_CMD_RELEASE_PD 0xAB /**< Release from deep power-down */
|
||||
#define DR_FLASH_CMD_READ_UID 0x4B /**< Read unique ID */
|
||||
#define DR_FLASH_CMD_READ_JEDEC_ID 0x9F /**< Read JEDEC ID */
|
||||
#define DR_FLASH_CMD_READ_MFR_ID 0x90 /**< Read manufacturer/device ID */
|
||||
|
||||
/* Status Register 1 bits */
|
||||
#define DR_FLASH_SR1_BUSY 0x01 /**< Erase/Write in progress */
|
||||
#define DR_FLASH_SR1_WEL 0x02 /**< Write enable latch */
|
||||
|
||||
/*==============================================================================
|
||||
* ERROR CODES
|
||||
*============================================================================*/
|
||||
typedef enum {
|
||||
DR_FLASH_OK = 0,
|
||||
DR_FLASH_ERR_NOT_INIT,
|
||||
DR_FLASH_ERR_INVALID_PARAM,
|
||||
DR_FLASH_ERR_TIMEOUT,
|
||||
DR_FLASH_ERR_WRITE_FAILED,
|
||||
DR_FLASH_ERR_JEDEC_MISMATCH
|
||||
} dr_flash_err_t;
|
||||
|
||||
/*==============================================================================
|
||||
* DATA STRUCTURES
|
||||
*============================================================================*/
|
||||
|
||||
/** @brief JEDEC ID structure */
|
||||
typedef struct {
|
||||
uint8_t manufacturer_id; /**< 0xEF = Winbond */
|
||||
uint8_t memory_type; /**< 0x40 = SPI */
|
||||
uint8_t capacity; /**< 0x16 = 32Mbit */
|
||||
} dr_flash_jedec_t;
|
||||
|
||||
/*==============================================================================
|
||||
* INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize W25Q32 Flash driver
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Sets up GPIO pins. Does NOT wake chip from deep power-down.
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_init(void);
|
||||
|
||||
/**
|
||||
* @brief Uninitialize driver, release GPIO pins
|
||||
*/
|
||||
void dr_w25q32_uninit(void);
|
||||
|
||||
/**
|
||||
* @brief Check if driver is initialized
|
||||
*/
|
||||
bool dr_w25q32_is_initialized(void);
|
||||
|
||||
/*==============================================================================
|
||||
* IDENTIFICATION
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read JEDEC ID (manufacturer, type, capacity)
|
||||
* @param jedec Pointer to JEDEC ID structure
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Expected: manufacturer=0xEF, type=0x40, capacity=0x16
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_read_jedec_id(dr_flash_jedec_t *jedec);
|
||||
|
||||
/**
|
||||
* @brief Read 8-byte unique ID
|
||||
* @param uid Buffer to store 8-byte UID (must be >= 8 bytes)
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_read_uid(uint8_t *uid);
|
||||
|
||||
/*==============================================================================
|
||||
* READ
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read data from flash
|
||||
* @param addr 24-bit start address (0x000000 ~ 0x3FFFFF)
|
||||
* @param buf Buffer to store read data
|
||||
* @param len Number of bytes to read
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_read(uint32_t addr, uint8_t *buf, uint32_t len);
|
||||
|
||||
/*==============================================================================
|
||||
* WRITE
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Write data to flash (page program, max 256 bytes)
|
||||
* @param addr 24-bit start address (must be page-aligned for best results)
|
||||
* @param data Data to write
|
||||
* @param len Number of bytes (1~256, must not cross page boundary)
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Automatically sends Write Enable before programming.
|
||||
* Waits for completion (BUSY flag).
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_write(uint32_t addr, const uint8_t *data, uint32_t len);
|
||||
|
||||
/*==============================================================================
|
||||
* ERASE
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Erase 4KB sector
|
||||
* @param addr Any address within the sector to erase
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Typical 45ms, max 400ms. Waits for completion.
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_erase_sector(uint32_t addr);
|
||||
|
||||
/**
|
||||
* @brief Erase 32KB block
|
||||
* @param addr Any address within the block
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_erase_block_32k(uint32_t addr);
|
||||
|
||||
/**
|
||||
* @brief Erase 64KB block
|
||||
* @param addr Any address within the block
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_erase_block_64k(uint32_t addr);
|
||||
|
||||
/**
|
||||
* @brief Erase entire chip
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Takes 6~50 seconds. Use with caution.
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_chip_erase(void);
|
||||
|
||||
/*==============================================================================
|
||||
* POWER MANAGEMENT
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enter deep power-down mode (~1uA)
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_deep_powerdown(void);
|
||||
|
||||
/**
|
||||
* @brief Release from deep power-down
|
||||
* @return dr_flash_err_t Error code
|
||||
* @note Requires ~3us recovery time (handled internally)
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_wakeup(void);
|
||||
|
||||
/*==============================================================================
|
||||
* STATUS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read Status Register 1
|
||||
* @param status Pointer to store status byte
|
||||
* @return dr_flash_err_t Error code
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_read_status(uint8_t *status);
|
||||
|
||||
/**
|
||||
* @brief Check if flash is busy (erase/write in progress)
|
||||
* @return true if busy
|
||||
*/
|
||||
bool dr_w25q32_is_busy(void);
|
||||
|
||||
/**
|
||||
* @brief Wait until flash is not busy
|
||||
* @param timeout_ms Maximum wait time in milliseconds
|
||||
* @return dr_flash_err_t DR_FLASH_OK or DR_FLASH_ERR_TIMEOUT
|
||||
*/
|
||||
dr_flash_err_t dr_w25q32_wait_busy(uint32_t timeout_ms);
|
||||
|
||||
/*==============================================================================
|
||||
* DEBUG / TEST
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Test flash communication by reading JEDEC ID
|
||||
* @return true if JEDEC ID matches W25Q32 (0xEF, 0x40, 0x16)
|
||||
*/
|
||||
bool dr_w25q32_test(void);
|
||||
|
||||
#endif /* DR_W25Q32_H */
|
||||
@@ -39,7 +39,7 @@ extern void param_error(const char *cmd);
|
||||
/* BLE transmission */
|
||||
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
|
||||
extern void ascii_format_data(uint8_t *buffer, const char *tag, const char *ascii, uint8_t len);
|
||||
extern void binary_tx_handler(const uint8_t *buffer, uint16_t length);
|
||||
extern void dr_binary_tx_safe(const uint8_t *buffer, uint16_t length);
|
||||
extern void dr_sd_delay_ms(uint32_t ms); /* Softdevice-friendly delay */
|
||||
|
||||
/* FDS config (fstorage) */
|
||||
@@ -83,7 +83,8 @@ extern bool go_device_power_off;
|
||||
extern bool go_NVIC_SystemReset;
|
||||
extern bool bond_data_delete;
|
||||
extern uint8_t m_reset_status;
|
||||
extern ret_code_t eeprom_write_byte(uint16_t mem_address, uint8_t data);
|
||||
extern void config_save(void);
|
||||
extern config_data_t m_config;
|
||||
|
||||
/* AGC_GAIN_SW is a macro in measurements.h - replicate here */
|
||||
#include "nrf_gpio.h"
|
||||
@@ -302,7 +303,7 @@ static int Cmd_mfv(const ParsedCmd *cmd);
|
||||
static int Cmd_msp(const ParsedCmd *cmd); /* IMU 6-axis raw data (single shot) */
|
||||
|
||||
static int Cmd_mpa(const ParsedCmd *cmd); /* Piezo TX/RX Activate */
|
||||
static int Cmd_mpb(const ParsedCmd *cmd); /* Piezo TX/RX Deactivate 26.03.13 */
|
||||
static int Cmd_mpb(const ParsedCmd *cmd); /* Piezo TX/RX Deactivate */
|
||||
static int Cmd_mpc(const ParsedCmd *cmd); /* Piezo Burst Capture */
|
||||
static int Cmd_mdc(const ParsedCmd *cmd); /* Piezo ADC Capture */
|
||||
static int Cmd_mec(const ParsedCmd *cmd); /* Piezo Burst + ADC capture */
|
||||
@@ -427,7 +428,7 @@ int dr_cmd_parser(const uint8_t *buf, uint8_t len)
|
||||
/* CRC 실패 시 에러 응답 전송 */
|
||||
if (g_plat.crc_check && g_plat.tx_bin) {
|
||||
single_format_data(ble_bin_buffer, "crc!", 65530);
|
||||
binary_tx_handler(ble_bin_buffer, 3);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
return -1; /* CRC 실패 또는 파싱 실패 → 음수로 old parser에 위임 */
|
||||
}
|
||||
@@ -474,7 +475,7 @@ static int Cmd_mta(const ParsedCmd *cmd)
|
||||
|
||||
if (g_plat.tx_bin) {
|
||||
single_format_data(ble_bin_buffer, "rta:", mode);
|
||||
binary_tx_handler(ble_bin_buffer, 3);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -515,7 +516,7 @@ static int Cmd_sta(const ParsedCmd *cmd)
|
||||
|
||||
if (g_plat.tx_bin) {
|
||||
single_format_data(ble_bin_buffer, "sta:", mode);
|
||||
binary_tx_handler(ble_bin_buffer, 3);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -683,7 +684,7 @@ static int Cmd_ssq(const ParsedCmd *cmd)
|
||||
g_plat.log("[Cmd_ssq] Power off\r\n");
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "rsq:", val);
|
||||
binary_tx_handler(ble_bin_buffer, 2);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
go_device_power_off = true;
|
||||
main_timer_start();
|
||||
return 1;
|
||||
@@ -698,11 +699,12 @@ static int Cmd_ssr(const ParsedCmd *cmd)
|
||||
g_plat.log("[Cmd_ssr] Bond delete + reset\r\n");
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "rsr:", val);
|
||||
binary_tx_handler(ble_bin_buffer, 2);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
bond_data_delete = true;
|
||||
eeprom_write_byte(0x0060, (uint8_t)bond_data_delete);
|
||||
m_config.bond_data_delete = (uint8_t)bond_data_delete;
|
||||
m_reset_status = 2;
|
||||
eeprom_write_byte(0x0065, m_reset_status);
|
||||
m_config.reset_status = m_reset_status;
|
||||
config_save();
|
||||
nrf_delay_ms(5);
|
||||
go_NVIC_SystemReset = true;
|
||||
main_timer_start();
|
||||
@@ -718,9 +720,10 @@ static int Cmd_sss(const ParsedCmd *cmd)
|
||||
g_plat.log("[Cmd_sss] Device reset\r\n");
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "rss:", val);
|
||||
binary_tx_handler(ble_bin_buffer, 2);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
m_reset_status = 2;
|
||||
eeprom_write_byte(0x0065, m_reset_status);
|
||||
m_config.reset_status = m_reset_status;
|
||||
config_save();
|
||||
nrf_delay_ms(5);
|
||||
go_NVIC_SystemReset = true;
|
||||
main_timer_start();
|
||||
@@ -736,7 +739,7 @@ static int Cmd_sst(const ParsedCmd *cmd)
|
||||
g_plat.log("[Cmd_sst] Ready\r\n");
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "rst:", val);
|
||||
binary_tx_handler(ble_bin_buffer, 2);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -747,7 +750,7 @@ static int Cmd_mfv(const ParsedCmd *cmd)
|
||||
g_plat.log("[Cmd_mfv] FW=%s\r\n", DR_DEVICE_VERSION);
|
||||
}
|
||||
ascii_format_data(ble_bin_buffer, "rfv:", DR_DEVICE_VERSION, 12);
|
||||
binary_tx_handler(ble_bin_buffer, 8);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -764,7 +767,7 @@ static int Cmd_mpa(const ParsedCmd *cmd)
|
||||
|
||||
if (g_plat.tx_bin) {
|
||||
single_format_data(ble_bin_buffer, "rpa:", 1);
|
||||
binary_tx_handler(ble_bin_buffer, 3);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -783,7 +786,7 @@ static int Cmd_mpb(const ParsedCmd *cmd)
|
||||
|
||||
if (g_plat.tx_bin) {
|
||||
single_format_data(ble_bin_buffer, "rpb:", 1);
|
||||
binary_tx_handler(ble_bin_buffer, 3);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -856,9 +859,9 @@ static int Cmd_mpc(const ParsedCmd *cmd)
|
||||
case 4:
|
||||
dr_piezo_burst_sw_22mhz((uint8_t)cycles);
|
||||
break;
|
||||
case 9:
|
||||
/*case 9:
|
||||
dr_piezo_burst_sw_19mhz((uint8_t)cycles);
|
||||
break;
|
||||
break;*/
|
||||
case 1:
|
||||
default:
|
||||
dr_piezo_burst_sw((uint8_t)cycles); /* 2.1MHz */
|
||||
@@ -982,7 +985,7 @@ static int Cmd_mdc(const ParsedCmd *cmd)
|
||||
ble_bin_buffer[11] = (uint8_t)(echo.baseline_raw >> 8);
|
||||
ble_bin_buffer[12] = (uint8_t)(echo.num_samples & 0xFF);
|
||||
ble_bin_buffer[13] = (uint8_t)(echo.num_samples >> 8);
|
||||
binary_tx_handler(ble_bin_buffer, 7); /* 14 bytes = 7 words */
|
||||
dr_binary_tx_safe(ble_bin_buffer, 7); /* 14 bytes = 7 words */
|
||||
nrf_delay_ms(100); /* Wait for BLE stack */
|
||||
|
||||
/* Packet 2~N: rdd: data packets with packed 12-bit samples */
|
||||
@@ -1009,7 +1012,7 @@ static int Cmd_mdc(const ParsedCmd *cmd)
|
||||
|
||||
/* Ensure even byte count for word alignment */
|
||||
if (dst_idx & 1) ble_bin_buffer[dst_idx++] = 0;
|
||||
binary_tx_handler(ble_bin_buffer, dst_idx / 2); /* bytes to words */
|
||||
dr_binary_tx_safe(ble_bin_buffer, dst_idx / 2); /* bytes to words */
|
||||
nrf_delay_ms(100); /* Inter-packet delay */
|
||||
}
|
||||
|
||||
@@ -1020,7 +1023,7 @@ static int Cmd_mdc(const ParsedCmd *cmd)
|
||||
ble_bin_buffer[3] = ':';
|
||||
ble_bin_buffer[4] = (uint8_t)(total_packets & 0xFF);
|
||||
ble_bin_buffer[5] = (uint8_t)(total_packets >> 8);
|
||||
binary_tx_handler(ble_bin_buffer, 3); /* 6 bytes = 3 words */
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3); /* 6 bytes = 3 words */
|
||||
|
||||
if (g_plat.log && g_log_enable) {
|
||||
g_plat.log("[Cmd_mdc] sent rdb+rdd*%u+rde (%u samples)\r\n",
|
||||
@@ -1295,7 +1298,7 @@ static int Cmd_mwh(const ParsedCmd *cmd)
|
||||
}
|
||||
|
||||
ascii_format_data(ble_bin_buffer, "rwh:", buf, 12);
|
||||
binary_tx_handler(ble_bin_buffer, 8);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1321,7 +1324,7 @@ static int Cmd_mws(const ParsedCmd *cmd)
|
||||
}
|
||||
|
||||
ascii_format_data(ble_bin_buffer, "rws:", buf, 12);
|
||||
binary_tx_handler(ble_bin_buffer, 8);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1331,7 +1334,7 @@ static int Cmd_mrh(const ParsedCmd *cmd)
|
||||
(void)cmd;
|
||||
memcpy(HW_NO, m_config.hw_no, 12);
|
||||
ascii_format_data(ble_bin_buffer, "rrh:", HW_NO, 12);
|
||||
binary_tx_handler(ble_bin_buffer, 8);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1341,7 +1344,7 @@ static int Cmd_mrs(const ParsedCmd *cmd)
|
||||
(void)cmd;
|
||||
memcpy(SERIAL_NO, m_config.serial_no, 12);
|
||||
ascii_format_data(ble_bin_buffer, "rrs:", SERIAL_NO, 12);
|
||||
binary_tx_handler(ble_bin_buffer, 8);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user