21 Commits

Author SHA1 Message Date
chain40 c933e15399 feat: Implement the BLE UART service. 2025-06-21 11:45:06 +08:00
chain40 ef19d6b72f bsp update 2025-06-10 22:10:33 +08:00
chain40 089114368e fix: 修正 peripheral 斷線後重連, 不會將資料寫入 sram 的問題 2025-01-13 23:08:07 +08:00
chain40 27560b237d feat: GCC 13.3.1 / GDB 15.1 / r3 2025-01-09 21:35:36 +08:00
Roy_01 fe55899830 feat: GCC 13.3.1 / GDB 15.1 2024-09-12 11:20:49 +08:00
chain40 14a4dec57b feat: 寫入 inst char 以及讀取 data char 會在 rtt 顯示 2024-05-21 19:26:55 +08:00
chain40 d3812a8b72 bugfix: 修正 peer address 的 type 判斷錯誤的問題 2024-05-08 00:29:39 +08:00
chain40 df70d69851 bugfix: 修正 cc2650 相容性實作 2024-05-08 00:04:58 +08:00
chain40 440f443a99 feat: 升級 gcc 版本 12.3.1, 升級 gdb 版本 13.2 2024-01-31 23:14:10 +08:00
chain40 32f5fee764 bugfix: 支援不同的 addree type 連線
1. Public address (cc2650 目前使用, 需向 ieee 註冊)
2. Random static address (bmd380 目前使用)
3. Resolvable random private address (未使用)
4. Non-resolvable random private address (未使用)
2024-01-31 23:14:06 +08:00
chain40 7fc5b54c47 feat: 當接收到 notify 時, 會根據不同的 char handle 執行對應的 callback
1. 目前只有 regular_data_char_handle 有實作
2024-01-31 22:50:01 +08:00
Roy_01 370d6cc80f updated response of disconnection and connection timeout 2023-10-03 16:02:00 +08:00
chain40 d99848592b bugfix: 修正掉資料的問題 (已排除)
原因: 因為連線後的 connection interval 設為 20ms, 造成 EIS 在 100sps 狀況下會掉資料

修正方式: 將連線後的 connection interval 設為 8~10ms, 即可排除 EIS 掉資料的問題

其它: 將程式碼優化調整為 -O0, 利於程式碼除錯
2023-08-15 23:30:50 +08:00
chain40 401c592281 bugfix: 修正掉資料的問題 (未解決, 僅降低發生率)
1. 程式優化為 -O0, 所以效能受限! 將優化改為 -O2 可大幅提升效能

2. 由於 gpiote 中斷有使用到 freertos api, 所以 gpiote 中斷優先權必需低於 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, 所以將 gpiote 優先權修改為 _PRIO_APP_MID 可排除掉資料的問題

3. 將 mem_drv_stream 的 buffer size 調整為 4096 bytes (確保 streambuffer 不會被塞爆)
2023-08-14 22:37:10 +08:00
chain40 415f4adfe9 bugfix: 修正自動結束的mode, 有發現沒有收到notify的最後一筆資料的問題
1. 原本是要收到 4 筆以上的資料才上寫入 sram, 現在只要收到 1筆資料就可以寫入 sram, 並切換 sram
2023-08-14 13:07:38 +08:00
chain40 9fc58b51fe Refactoring: 當 on_ins_write_char() 寫入資料如果發生錯誤, 會在 rtt viewer 顯示 2023-08-14 10:48:10 +08:00
chain40 508ac99c0d bugfix: 修正當連線成功之後, 如果重複連線會發生錯誤的問題 2023-08-14 10:45:26 +08:00
chain40 6158961dcf bugfix: NRF_BLE_GQ_QUEUE_SIZE 太小只有 6 bytes, 所以當 characteristic 寫入大於 6 bytes 會寫入失敗
1) NRF_BLE_GQ_QUEUE_SIZE 改為 256
2) NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN 改為 256
3) NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN 改為 256
4) NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT 改為 32
5) NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE 改為 256
2023-08-14 10:43:53 +08:00
chain40 be584e2900 cc2650_compitable 2023-08-11 09:15:53 +08:00
charles 8ff9a297d5 add sram_drv 2023-06-14 13:23:12 +08:00
chain40 6acd56bf8f host command suppor
1. support check_mem_survive, scan, connect, disconnect host command.

2. create a host_cmd.py to valid host commands

3. add uart_drv_rx_mutex/uart_drv_tx_mutex to lock uart tx/rx

4. add host_scan_filter_match_cb() to send device infomation to host.

5. add le_gap_disconnet()

6. freertos enable check stack overflow

7. freertos increase timer task stack
2023-06-09 19:17:35 +08:00
20 changed files with 2132 additions and 553 deletions
+3 -3
View File
@@ -63,7 +63,7 @@
#define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES ( 6 )
#define configMINIMAL_STACK_SIZE ( 192 )
#define configTOTAL_HEAP_SIZE ( 32 * 1024 )
#define configTOTAL_HEAP_SIZE ( 64 * 1024 )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
@@ -80,7 +80,7 @@
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_MALLOC_FAILED_HOOK 0
/* Run time and task stats gathering related definitions. */
@@ -96,7 +96,7 @@
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH ( 80 )
#define configTIMER_TASK_STACK_DEPTH ( 256 )
/* Tickless Idle configuration. */
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
+23 -12
View File
@@ -15,9 +15,9 @@ extern "C"
#define NRF_LOG_BACKEND_UART_ENABLED 0
#define NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS 1
#define NRF_LOG_BACKEND_RTT_TX_RETRY_CNT 3
#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64
#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 256
#define NRF_LOG_DEFERRED 0
#define NRF_LOG_USES_TIMESTAMP 0
#define NRF_LOG_USES_TIMESTAMP 1
#define NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF_ENABLED 0
// SEGGER-RTT
@@ -152,15 +152,15 @@ extern "C"
// Priority for dispatching the BLE events to the Scanning Module.
#define NRF_BLE_SCAN_OBSERVER_PRIO 1
// Scanning interval. Determines the scan interval in units of 0.625 millisecond.
#define NRF_BLE_SCAN_SCAN_INTERVAL 160
#define NRF_BLE_SCAN_SCAN_INTERVAL 600
// Duration of a scanning session in units of 10 ms. Range: 0x0001 - 0xFFFF (10 ms to 10.9225 ms). If set to 0x0000, the scanning continues until it is explicitly disabled.
#define NRF_BLE_SCAN_SCAN_DURATION 0
// Scanning window. Determines the scanning window in units of 0.625 millisecond.
#define NRF_BLE_SCAN_SCAN_WINDOW 80
#define NRF_BLE_SCAN_SCAN_WINDOW 400
// Determines the supervision time-out in units of 10 millisecond.
#define NRF_BLE_SCAN_SUPERVISION_TIMEOUT 4000
// Determines minimum connection interval in milliseconds.
#define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL 7.5
#define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL 8
// Determines maximum connection interval in milliseconds.
#define NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL 20
// Determines the slave latency in counts of connection events.
@@ -168,9 +168,9 @@ extern "C"
// Enabling filters for the Scanning Module.
#define NRF_BLE_SCAN_FILTER_ENABLE 1
// Number of filters for UUIDs.
#define NRF_BLE_SCAN_UUID_CNT 0
#define NRF_BLE_SCAN_UUID_CNT 1
// Number of name filters.
#define NRF_BLE_SCAN_NAME_CNT 2
#define NRF_BLE_SCAN_NAME_CNT 0
// Number of short name filters.
#define NRF_BLE_SCAN_SHORT_NAME_CNT 0
// Number of address filters.
@@ -183,15 +183,15 @@ extern "C"
#define NRF_BLE_GQ_ENABLED 1
// Default size of a single element in the pool of memory objects.
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE 20
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_SIZE 256
// Default number of elements in the pool of memory objects.
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT 8
#define NRF_BLE_GQ_DATAPOOL_ELEMENT_COUNT 32
// Maximal size of the data inside GATTC write request (in bytes).
#define NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN 2
#define NRF_BLE_GQ_GATTC_WRITE_MAX_DATA_LEN 256
// Maximal size of the data inside GATTC notification or indication request (in bytes).
#define NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN 16
#define NRF_BLE_GQ_GATTS_HVX_MAX_DATA_LEN 256
// Queue size for BLE GATT Queue module.
#define NRF_BLE_GQ_QUEUE_SIZE 6
#define NRF_BLE_GQ_QUEUE_SIZE 256
// Priority with which BLE events are dispatched to the GATT Queue module.
#define NRF_BLE_GQ_BLE_OBSERVER_PRIO 1
@@ -211,6 +211,17 @@ extern "C"
// Enable GATT MTU exchange initiation
#define NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED 1
// The maximum number of characteristics present in a service record
#define BLE_GATT_DB_MAX_CHARS 16
// Custom UUID service & char
#define BLE_UUID_CUSTOM_SERVICE 0xFFF0
#define BLE_UUID_SIMPLEPROFILECHAR(n) (BLE_UUID_CUSTOM_SERVICE + n)
// Uart UUID service & char
#define BLE_UUID_UART_SERVICE 0xFFF8
#define BLE_UUID_UART_CHAR(n) (BLE_UUID_UART_SERVICE + n)
#define COUNTOF(x) (sizeof(x) / sizeof(x[0]))
#ifdef __cplusplus
+5 -2
View File
@@ -25,6 +25,7 @@
<ProjectFile>bmd380_central.vcxproj</ProjectFile>
<RemoteBuildEnvironment>
<Records />
<EnvironmentSetupFiles />
</RemoteBuildEnvironment>
<ParallelJobCount>1</ParallelJobCount>
<SuppressDirectoryChangeMessages>true</SuppressDirectoryChangeMessages>
@@ -94,15 +95,17 @@
<EnableAsyncExecutionMode>false</EnableAsyncExecutionMode>
<AsyncModeSupportsBreakpoints>true</AsyncModeSupportsBreakpoints>
<TemporaryBreakConsolidationTimeout>0</TemporaryBreakConsolidationTimeout>
<BacktraceFrameLimit>0</BacktraceFrameLimit>
<EnableNonStopMode>false</EnableNonStopMode>
<MaxBreakpointLimit>0</MaxBreakpointLimit>
<EnableVerboseMode>true</EnableVerboseMode>
<EnablePrettyPrinters>false</EnablePrettyPrinters>
<EnableAbsolutePathReporting>true</EnableAbsolutePathReporting>
</AdditionalGDBSettings>
<DebugMethod>
<ID>jlink-jtag</ID>
<InterfaceID>com.sysprogs.debug.jlink.jlinksw</InterfaceID>
<InterfaceSerialNumber>000682409936</InterfaceSerialNumber>
<InterfaceSerialNumber>000601012352</InterfaceSerialNumber>
<Configuration xsi:type="com.visualgdb.edp.segger.settings">
<CommandLine>-select USB -device $$SYS:MCU_ID$$ -speed auto -if SWD</CommandLine>
<ProgramMode>Enabled</ProgramMode>
@@ -129,7 +132,7 @@
<EndOfStackSymbol>_estack</EndOfStackSymbol>
<TimestampProviderTicksPerSecond>0</TimestampProviderTicksPerSecond>
<KeepConsoleAfterExit>false</KeepConsoleAfterExit>
<UnusedStackFillPattern xsi:nil="true" />
<UnusedStackFillPattern>2779096485</UnusedStackFillPattern>
<CheckInterfaceDrivers>true</CheckInterfaceDrivers>
</Debug>
</VisualGDBProjectSettings2>
+14 -4
View File
@@ -32,13 +32,15 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|VisualGDB'">
<GNUConfigurationType>Debug</GNUConfigurationType>
<ToolchainID>com.visualgdb.arm-eabi</ToolchainID>
<ToolchainVersion>10.3.1/10.2.90/r1</ToolchainVersion>
<ToolchainVersion>14.2.1/15.2/r2</ToolchainVersion>
<MCUPropertyListFile>$(ProjectDir)nrf5x.props</MCUPropertyListFile>
<UseCCache>true</UseCCache>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|VisualGDB'">
<ToolchainID>com.visualgdb.arm-eabi</ToolchainID>
<ToolchainVersion>10.3.1/10.2.90/r1</ToolchainVersion>
<ToolchainVersion>14.2.1/15.2/r2</ToolchainVersion>
<MCUPropertyListFile>$(ProjectDir)nrf5x.props</MCUPropertyListFile>
<UseCCache>true</UseCCache>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|VisualGDB'">
<ClCompile>
@@ -49,13 +51,16 @@
<SupportRTTI>false</SupportRTTI>
<AdditionalOptions />
<CPPLanguageStandard />
<Optimization>O0</Optimization>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<LinkerScript>nRF52811_XXAA_s140.lds</LinkerScript>
<LibrarySearchDirectories>%(Link.LibrarySearchDirectories)</LibrarySearchDirectories>
<AdditionalLibraryNames>%(Link.AdditionalLibraryNames)</AdditionalLibraryNames>
<AdditionalLinkerInputs>%(Link.AdditionalLinkerInputs)</AdditionalLinkerInputs>
<AdditionalOptions />
<AdditionalOptions>
</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|VisualGDB'">
@@ -65,6 +70,7 @@
<CLanguageStandard>GNU99</CLanguageStandard>
<SupportExceptions>false</SupportExceptions>
<SupportRTTI>false</SupportRTTI>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<LinkerScript>nRF52811_XXAA_s140.lds</LinkerScript>
@@ -77,6 +83,11 @@
</ImportGroup>
<ItemGroup>
<ClCompile Include="host_tasks.c" />
<ClCompile Include="le_gatt_c.c" />
<ClCompile Include="le_uart_c.c" />
<ClCompile Include="mem_drv.c" />
<ClCompile Include="sram_drv.c" />
<ClCompile Include="syscalls.c" />
<ClCompile Include="uart_drv.c" />
<None Include="nrf5x.props" />
<ClCompile Include="$(BSP_ROOT)\nRF5x\modules\nrfx\mdk\system_nrf52840.c" />
@@ -379,7 +390,6 @@
<ClCompile Include="..\bmd380_sdk\components\libraries\queue\nrf_queue.c" />
<ClCompile Include="le_db_discovery.c" />
<ClCompile Include="le_dis_c.c" />
<ClCompile Include="le_eis_c.c" />
<ClCompile Include="le_gap.c" />
<ClCompile Include="le_gatt.c" />
<ClCompile Include="le_gap_queue.c" />
+15 -3
View File
@@ -1667,15 +1667,27 @@
<ClCompile Include="le_dis_c.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="le_eis_c.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="uart_drv.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="host_tasks.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="sram_drv.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="le_gatt_c.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="mem_drv.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="syscalls.c">
<Filter>Source files</Filter>
</ClCompile>
<ClCompile Include="le_uart_c.c">
<Filter>Source files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\bmd380_sdk\components\ble\ble_services\ble_dis_c\ble_dis_c.h">
+300 -75
View File
@@ -5,9 +5,15 @@ extern "C"
{
#endif
#include "ble_advdata.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_scan.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_freertos.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
@@ -27,13 +33,13 @@ typedef struct
{
uint8_t opcode;
uint8_t len;
} host_cmd_survive_t;
} ins_survive_t;
typedef struct
{
uint8_t opcode;
uint8_t len;
} host_cmd_scan_t;
} ins_scan_t;
typedef struct
{
@@ -41,28 +47,28 @@ typedef struct
uint8_t len;
uint8_t addr_type;
uint8_t addr[6];
} host_cmd_connect_t;
} ins_connect_t;
typedef struct
{
uint8_t opcode;
uint8_t len;
} host_cmd_disconnect_t;
} ins_disconnect_t;
typedef struct
{
uint8_t opcode;
uint8_t len;
uint8_t handle;
uint8_t write_date[0];
} host_cmd_write_char_t;
uint8_t write_data[255];
} ins_write_char_t;
typedef struct
{
uint8_t opcode;
uint8_t len;
uint8_t handle;
} host_cmd_read_char_t;
} ins_read_char_t;
typedef union
{
@@ -75,60 +81,231 @@ typedef union
uint8_t payload[255];
};
} raw;
ins_survive_t survive;
ins_scan_t scan;
ins_connect_t connect;
ins_disconnect_t disconnect;
ins_write_char_t write_char;
ins_read_char_t read_char;
} host_ins_t;
host_cmd_survive_t survive;
host_cmd_scan_t scan;
host_cmd_connect_t connect;
host_cmd_disconnect_t disconnect;
host_cmd_write_char_t write_char;
host_cmd_read_char_t read_char;
#define EVT_ALL 0xFFFF
#define EVT_MEM_RETURN_DATA 0x0010
#define EVT_MEM_NOTIFY_HANDLE 0x0040
#define EVT_MEM_UART_ROUTINE 0x0080
#define EVT_MEM_INS_SCAN 0x0100
#define EVT_MEM_INS_CONNECT 0x0200
#define EVT_MEM_INS_WRITE 0x0400
#define EVT_MEM_INS_READ 0x0800
#define EVT_MEM_INS_DISCONNECT 0x1000
#define EVT_MEM_INS_CHECK_SURVIVE 0x2000
} host_command_t;
typedef enum
{
INS_IDLE = 0x00,
INS_RESET = 0x01,
INS_KEY = 0x02,
INS_SCAN = 0x03,
INS_SCAN_RESPONSE = 0x04,
INS_CONNECT = 0x05,
INS_WRITE_CHAR = 0x06,
INS_READ_CHAR = 0x07,
INS_DISCONNECT = 0x08,
INS_PREPARE_CONNECT = 0x09,
INS_CHECK_SURVIVE = 0x0A
} ctrl_instr_t;
#define CMD_NULL 0x00
#define CMD_SURVIVE 0x0A
#define CMD_SCAN 0x03
#define CMD_CONNECT 0x05
#define CMD_DISCONNECT 0x08
#define CMD_WR_CHAR 0x06
#define CMD_RD_CHAR 0x07
#define CMD_SUFFIX 0xF1
#define INST_SUFFIX 0xF1
static MessageBufferHandle_t host_cmd_msg;
void on_connect(host_cmd_connect_t *p_cmd)
static void success_ack(void)
{
extern void le_scan_stop(void);
extern void le_gap_connet(ble_gap_addr_t * p_peer_addr, nrf_ble_scan_t * p_scan);
extern const nrf_ble_scan_t *le_scan_obj(void);
le_scan_stop();
ble_gap_addr_t gap_addr;
gap_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
gap_addr.addr_id_peer = 0;
memcpy(gap_addr.addr, p_cmd->addr, sizeof((gap_addr.addr)));
le_gap_connet((void *)&gap_addr, (void *)le_scan_obj());
char rsp_buf[64];
sprintf(rsp_buf, "%s(%02X:%02X:%02X:%02X:%02X:%02X)\r\n", __FUNCTION__, gap_addr.addr[5], gap_addr.addr[4], gap_addr.addr[3], gap_addr.addr[2], gap_addr.addr[1], gap_addr.addr[0]);
NRF_LOG_INFO("%s", rsp_buf);
p_cmd->opcode = CMD_NULL;
p_cmd->len = 0;
uint8_t ack[] = { 0x04, 0x00, 0x01, 0x03 };
uart_drv_tx(ack, sizeof(ack));
}
void on_scan(host_cmd_scan_t *p_cmd)
static void disconnect_and_timeout_ack(void)
{
uint8_t ack[] = { 0x04, 0x00, 0x01, 0xFF };
uart_drv_tx(ack, sizeof(ack));
}
static void on_ins_scan(ins_scan_t *p_ins)
{
extern void le_scan_start(void);
le_scan_start();
}
static void on_ins_connect(ins_connect_t *p_ins)
{
ble_gap_addr_t peer_addr;
peer_addr.addr_id_peer = 0;
peer_addr.addr_type = BLE_GAP_ADDR_TYPE_ANONYMOUS;
peer_addr.addr[0] = p_ins->addr[5];
peer_addr.addr[1] = p_ins->addr[4];
peer_addr.addr[2] = p_ins->addr[3];
peer_addr.addr[3] = p_ins->addr[2];
peer_addr.addr[4] = p_ins->addr[1];
peer_addr.addr[5] = p_ins->addr[0];
extern void le_scan_stop(void);
le_scan_stop();
vTaskDelay(pdMS_TO_TICKS(3));
extern void le_scan_get_peer_addr(ble_gap_addr_t * p_peer_addr);
le_scan_get_peer_addr(&peer_addr);
if (peer_addr.addr_type == BLE_GAP_ADDR_TYPE_ANONYMOUS)
{
extern void le_scan_start(void);
le_scan_start();
return;
}
extern void le_gap_connet(ble_gap_addr_t * p_peer_addr);
le_gap_connet(&peer_addr);
char rsp_buf[64];
sprintf(rsp_buf, "%s() \r\n", __FUNCTION__);
uart_drv_tx(rsp_buf, strlen(rsp_buf));
sprintf(rsp_buf, "%s: %02X:%02X:%02X:%02X:%02X:%02X", "Connect to", peer_addr.addr[5], peer_addr.addr[4], peer_addr.addr[3], peer_addr.addr[2], peer_addr.addr[1], peer_addr.addr[0]);
NRF_LOG_INFO("%s", rsp_buf);
}
p_cmd->opcode = CMD_NULL;
p_cmd->len = 0;
static void on_ins_write_char(ins_write_char_t *p_ins)
{
uint16_t write_size = p_ins->len - sizeof(p_ins->handle) - 1;
NRF_LOG_INFO("write handle: 0x%02X", p_ins->handle);
{
uint8_t *p_start = (void *)p_ins->write_data;
uint32_t loop = write_size / 8;
uint32_t remain = write_size % 8;
for (int i = 0; i < loop; i++)
{
NRF_LOG_HEXDUMP_INFO(p_start, 8);
p_start += 8;
}
if (remain)
{
NRF_LOG_HEXDUMP_INFO(p_start, remain);
}
}
extern ret_code_t le_gatt_c_write_req(uint32_t handle, void *, uint16_t);
ret_code_t err_code = le_gatt_c_write_req(p_ins->handle, p_ins->write_data, write_size);
APP_ERROR_CHECK(err_code);
success_ack();
}
static void on_ins_read_char(ins_read_char_t *p_ins)
{
NRF_LOG_INFO("read handle: 0x%02X", p_ins->handle);
extern ret_code_t le_gatt_c_read_char_req(uint32_t handle);
ret_code_t ret_code = le_gatt_c_read_char_req(p_ins->handle);
}
static void on_ins_disconnect(ins_disconnect_t *p_ins)
{
extern void le_gap_disconnet(uint16_t);
le_gap_disconnet(0);
}
static void on_ins_survive(ins_survive_t *p_ins)
{
success_ack();
}
void host_read_char_cb(uint8_t *p_data, uint16_t len)
{
static union
{
struct
{
uint16_t rsp_code;
uint8_t payload[];
};
uint8_t arr[256];
} read_char_rsp = {
.rsp_code = 0x0004
};
memcpy(read_char_rsp.payload, p_data, len);
uart_drv_tx(&read_char_rsp, sizeof(read_char_rsp.rsp_code) + len);
{
uint8_t *p_start = p_data;
uint32_t loop = len / 8;
uint32_t remain = len % 8;
for (int i = 0; i < loop; i++)
{
NRF_LOG_HEXDUMP_INFO(p_start, 8);
p_start += 8;
}
if (remain)
{
NRF_LOG_HEXDUMP_INFO(p_start, remain);
}
}
}
typedef struct
{
const uint16_t company_identifier;
struct
{
const uint8_t company_code[5];
const uint8_t hw_ver[4];
const uint16_t battery_level;
} __PACKED data;
} manu_spec_data_t;
void host_scan_filter_match_cb(
void *p_manu_spec_data,
uint32_t manu_spec_data_len,
char *p_device_name,
uint32_t device_name_len,
ble_gap_addr_t const *peer_addr,
int16_t rssi)
{
typedef struct
{
uint16_t hci_packet_event;
uint8_t len;
uint8_t addr[6];
uint8_t manu_spec_data[15];
uint8_t dev_name[21];
} __PACKED host_scan_rsp_t;
static host_scan_rsp_t host_scan_rsp;
memset(&host_scan_rsp, 0x00, sizeof(host_scan_rsp));
host_scan_rsp.hci_packet_event = 0x0004;
host_scan_rsp.len = sizeof(host_scan_rsp_t) - offsetof(host_scan_rsp_t, addr);
memcpy(host_scan_rsp.addr, peer_addr->addr, sizeof(host_scan_rsp.addr));
memcpy((void *)&host_scan_rsp.manu_spec_data, p_manu_spec_data, sizeof(host_scan_rsp.manu_spec_data));
memcpy((void *)host_scan_rsp.dev_name, p_device_name, device_name_len);
uart_drv_tx(&host_scan_rsp, sizeof(host_scan_rsp));
char peer_addr_str[(2 + 1) * BLE_GAP_ADDR_LEN + 1] = { 0 };
sprintf(peer_addr_str, "%02X:%02X:%02X:%02X:%02X:%02X", host_scan_rsp.addr[5], host_scan_rsp.addr[4], host_scan_rsp.addr[3], host_scan_rsp.addr[2], host_scan_rsp.addr[1], host_scan_rsp.addr[0]);
NRF_LOG_INFO("Found: %s [%s, %ddb]",
host_scan_rsp.dev_name,
peer_addr_str,
rssi);
}
void host_connected_cb(void)
{
success_ack();
}
static void host_cmd_exec_task(void *p_arg)
@@ -136,18 +313,32 @@ static void host_cmd_exec_task(void *p_arg)
for (;;)
{
static uint8_t buf[256] = { 0 };
host_ins_t *p_ins = (void *)buf;
size_t recv = xMessageBufferReceive(host_cmd_msg, buf, sizeof(buf), pdMS_TO_TICKS(25));
p_ins->raw.opcode = INS_IDLE;
p_ins->raw.len = 0;
host_command_t *p_cmd = (void *)buf;
size_t recv = xMessageBufferReceive(host_cmd_msg, buf, sizeof(buf), portMAX_DELAY);
switch (p_cmd->raw.opcode)
switch (p_ins->raw.opcode)
{
case CMD_CONNECT:
on_connect(&p_cmd->connect);
case INS_SCAN:
on_ins_scan(&p_ins->scan);
break;
case CMD_SCAN:
on_scan(&p_cmd->scan);
case INS_CONNECT:
on_ins_connect(&p_ins->connect);
break;
case INS_WRITE_CHAR:
on_ins_write_char(&p_ins->write_char);
break;
case INS_READ_CHAR:
on_ins_read_char(&p_ins->read_char);
break;
case INS_DISCONNECT:
on_ins_disconnect(&p_ins->disconnect);
break;
case INS_CHECK_SURVIVE:
on_ins_survive(&p_ins->survive);
break;
default:
break;
@@ -166,39 +357,73 @@ static void host_cmd_recv_task(void *p_arg)
while (offset < recv)
{
host_command_t *p_cmd = (void *)&buf[offset];
host_ins_t *p_ins = (void *)&buf[offset];
taskENTER_CRITICAL();
switch (p_cmd->raw.opcode)
if (p_ins->raw.payload[p_ins->raw.len] == INST_SUFFIX)
{
case CMD_CONNECT:
if (p_cmd->raw.payload[p_cmd->raw.len] == CMD_SUFFIX)
{
xMessageBufferSend(host_cmd_msg, p_cmd, sizeof(host_cmd_connect_t), pdMS_TO_TICKS(0));
offset += sizeof(host_cmd_connect_t);
}
break;
case CMD_SCAN:
if (p_cmd->raw.payload[p_cmd->raw.len] == CMD_SUFFIX)
{
xMessageBufferSend(host_cmd_msg, p_cmd, sizeof(host_cmd_scan_t), pdMS_TO_TICKS(0));
offset += sizeof(host_cmd_scan_t);
}
break;
default:
offset++;
break;
switch (p_ins->raw.opcode)
{
case INS_CHECK_SURVIVE:
xMessageBufferSend(host_cmd_msg, p_ins, sizeof(ins_survive_t), pdMS_TO_TICKS(0));
offset += sizeof(ins_survive_t);
break;
case INS_CONNECT:
xMessageBufferSend(host_cmd_msg, p_ins, sizeof(ins_connect_t), pdMS_TO_TICKS(0));
offset += sizeof(ins_connect_t);
break;
case INS_DISCONNECT:
xMessageBufferSend(host_cmd_msg, p_ins, sizeof(ins_disconnect_t), pdMS_TO_TICKS(0));
offset += sizeof(ins_disconnect_t);
break;
case INS_SCAN:
xMessageBufferSend(host_cmd_msg, p_ins, sizeof(ins_scan_t), pdMS_TO_TICKS(0));
offset += sizeof(ins_scan_t);
break;
case INS_READ_CHAR:
xMessageBufferSend(host_cmd_msg, p_ins, sizeof(ins_read_char_t), pdMS_TO_TICKS(0));
offset += sizeof(ins_read_char_t);
break;
case INS_WRITE_CHAR:
xMessageBufferSend(host_cmd_msg, p_ins, offsetof(ins_write_char_t, handle) + p_ins->write_char.len, pdMS_TO_TICKS(0));
offset += offsetof(ins_write_char_t, handle) + p_ins->write_char.len;
break;
default:
offset++;
break;
}
}
else
{
offset++;
}
taskEXIT_CRITICAL();
}
}
}
static void host_tasks_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
ret_code_t err_code;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
break;
case BLE_GAP_EVT_DISCONNECTED:
case BLE_GAP_EVT_TIMEOUT:
disconnect_and_timeout_ack();
break;
default:
break;
}
}
void host_tasks_init(void)
{
host_cmd_msg = xMessageBufferCreate(1024);
xTaskCreate(host_cmd_recv_task, "cmd_recv", 128, NULL, 5, NULL);
xTaskCreate(host_cmd_exec_task, "cmd_exec", 128, NULL, 2, NULL);
xTaskCreate(host_cmd_recv_task, "cmd_recv", 128, NULL, 3, NULL);
xTaskCreate(host_cmd_exec_task, "cmd_exec", 512, NULL, 3, NULL);
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_tasks_observer, 3, host_tasks_handler, NULL);
}
+6 -2
View File
@@ -26,8 +26,10 @@ static void db_disc_handler(ble_db_discovery_evt_t *p_evt)
NRF_LOG_INFO("BLE_DB_DISCOVERY_COMPLETE");
extern void le_dis_c_on_db_disc_evt(ble_db_discovery_evt_t * p_evt);
le_dis_c_on_db_disc_evt(p_evt);
extern void le_eis_c_on_db_disc_evt(ble_db_discovery_evt_t * p_evt);
le_eis_c_on_db_disc_evt(p_evt);
extern void le_gatt_c_on_db_disc_evt(ble_db_discovery_evt_t * p_evt);
le_gatt_c_on_db_disc_evt(p_evt);
extern void le_uart_c_on_db_disc_evt(ble_db_discovery_evt_t * p_evt);
le_uart_c_on_db_disc_evt(p_evt);
break;
case BLE_DB_DISCOVERY_ERROR:
NRF_LOG_INFO("BLE_DB_DISCOVERY_ERROR");
@@ -37,6 +39,8 @@ static void db_disc_handler(ble_db_discovery_evt_t *p_evt)
break;
case BLE_DB_DISCOVERY_AVAILABLE:
NRF_LOG_INFO("BLE_DB_DISCOVERY_AVAILABLE");
extern void host_connected_cb(void);
host_connected_cb();
break;
default:
break;
-307
View File
@@ -1,307 +0,0 @@
#ifdef __cplusplus
extern "C"
{
#endif
#include "ble_db_discovery.h"
#include "ble_gattc.h"
#include "ble_srv_common.h"
#include "nrf_ble_gq.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#ifdef __cplusplus
}
#endif
/**< Used vendor specific UUID. */
#define BLE_EIS_BASE_UUID \
{ \
0x4D, 0x3C, 0x56, 0x45, 0x12, 0x8B, 0x44, 0x1D, 0x8D, 0x6F, 0xC5, 0x95, 0x00, 0x00, 0x9B, 0xD8 \
}
#define BLE_UUID_EIS_SERVICE 0x0001
#define BLE_UUID_EIS_REGULAR_DATA_CHAR 0x0002
#define BLE_UUID_EIS_LOW_FREQ_DATA_CHAR 0x0003
#define BLE_UUID_EIS_AUXILIARY_DATA_CHAR 0x0004
#define BLE_UUID_EIS_STATUS_CHAR 0x0005
#define BLE_UUID_EIS_EVENT_CHAR 0x0006
struct ble_eis_c_s
{
uint16_t conn_handle;
void (*evt_handler)(ble_evt_t const *p_ble_evt, void *p_context);
uint16_t regular_data_char_handle;
uint16_t low_freq_data_char_handle;
uint16_t auxiliary_data_char_handle;
uint16_t status_char_handle;
uint16_t event_char_handle;
};
typedef struct ble_eis_c_s ble_eis_c_t;
static ble_eis_c_t m_eis_c;
static void on_disconnected(ble_eis_c_t *p_ble_eis_c, ble_evt_t const *p_ble_evt)
{
p_ble_eis_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_eis_c->regular_data_char_handle = BLE_GATT_HANDLE_INVALID;
p_ble_eis_c->auxiliary_data_char_handle = BLE_GATT_HANDLE_INVALID;
p_ble_eis_c->status_char_handle = BLE_GATT_HANDLE_INVALID;
p_ble_eis_c->event_char_handle = BLE_GATT_HANDLE_INVALID;
}
static void on_connected(ble_eis_c_t *p_ble_eis_c, ble_evt_t const *p_ble_evt)
{
}
static void on_hvx(ble_eis_c_t *p_ble_eis_c, ble_evt_t const *p_ble_evt)
{
static int idx = 0;
static uint begin = 0;
idx++;
if (begin == 0)
{
begin = xTaskGetTickCount();
}
else
{
static char str[64];
float kb = 8 * idx * 240 / 1024.0;
float timespan = (xTaskGetTickCount() - begin) / 1000.0;
snprintf(str, sizeof(str), "%s(): %.2fkbps", __FUNCTION__, kb / timespan);
NRF_LOG_INFO("%s", str);
}
}
static void on_read_rsp(ble_eis_c_t *p_ble_eis_c, ble_evt_t const *p_ble_evt)
{
}
ret_code_t le_eis_ccdc_configure(uint16_t conn_handle, uint16_t char_handle, bool notification_enable)
{
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
if (char_handle == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
NRF_LOG_INFO("Configuring CCCD. CCCD Handle = 0x%04X, Connection Handle = 0x%04X",
char_handle + 1,
conn_handle);
nrf_ble_gq_req_t cccd_req;
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
uint8_t cccd[BLE_CCCD_VALUE_LEN];
cccd[0] = LSB_16(cccd_val);
cccd[1] = MSB_16(cccd_val);
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
cccd_req.params.gattc_write.handle = m_eis_c.regular_data_char_handle + 1;
cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
cccd_req.params.gattc_write.offset = 0;
cccd_req.params.gattc_write.p_value = cccd;
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
extern nrf_ble_gq_t *le_gap_queue(void);
return nrf_ble_gq_item_add(le_gap_queue(), &cccd_req, m_eis_c.conn_handle);
}
static void le_eis_c_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
ble_eis_c_t *p_ble_eis_c = (ble_eis_c_t *)p_context;
if ((p_ble_eis_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_eis_c, p_ble_evt);
break;
case BLE_GAP_EVT_CONNECTED:
on_connected(p_ble_eis_c, p_ble_evt);
break;
case BLE_GATTC_EVT_HVX:
/*
Handle Value Notification or Indication event.
Confirm indication with @ref sd_ble_gattc_hv_confirm.
See @ref ble_gattc_evt_hvx_t. */
on_hvx(p_ble_eis_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
/*
Read Response event.
See @ref ble_gattc_evt_read_rsp_t. */
on_read_rsp(p_ble_eis_c, p_ble_evt);
break;
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
/*
Primary Service Discovery Response event.
See @ref ble_gattc_evt_prim_srvc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_REL_DISC_RSP:
/*
Relationship Discovery Response event.
See @ref ble_gattc_evt_rel_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP:
/*
Characteristic Discovery Response event.
See @ref ble_gattc_evt_char_disc_rsp_t. */
break;
case BLE_GATTC_EVT_DESC_DISC_RSP:
/*
Descriptor Discovery Response event.
See @ref ble_gattc_evt_desc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP:
/*
Attribute Information Response event.
See @ref ble_gattc_evt_attr_info_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
/*
Read By UUID Response event.
See @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VALS_READ_RSP:
/*
Read multiple Response event.
See @ref ble_gattc_evt_char_vals_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_RSP:
/*
Write Response event.
See @ref ble_gattc_evt_write_rsp_t. */
break;
case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
/*
Exchange MTU Response event.
See @ref ble_gattc_evt_exchange_mtu_rsp_t. */
break;
case BLE_GATTC_EVT_TIMEOUT:
/*
Timeout event.
See @ref ble_gattc_evt_timeout_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:
/*
Write without Response transmission complete. */
__BKPT(255);
break;
default:
// No implementation needed.
break;
}
}
void le_eis_c_cccd_timer_cb(TimerHandle_t xTimer)
{
static int cnt = 0;
if (cnt++ < 10)
{
NRF_LOG_INFO("Configuring CCCD Countdow: %d", 11 - cnt);
}
else
{
le_eis_ccdc_configure(m_eis_c.conn_handle, m_eis_c.regular_data_char_handle, true);
le_eis_ccdc_configure(m_eis_c.conn_handle, m_eis_c.low_freq_data_char_handle, true);
le_eis_ccdc_configure(m_eis_c.conn_handle, m_eis_c.auxiliary_data_char_handle, true);
le_eis_ccdc_configure(m_eis_c.conn_handle, m_eis_c.status_char_handle, true);
le_eis_ccdc_configure(m_eis_c.conn_handle, m_eis_c.event_char_handle, true);
xTimerStop(xTimer, pdMS_TO_TICKS(0));
}
}
static TimerHandle_t le_eis_c_cccd_timer = NULL;
void le_eis_c_init(void)
{
m_eis_c.evt_handler = le_eis_c_evt_handler;
m_eis_c.conn_handle = BLE_CONN_HANDLE_INVALID;
m_eis_c.regular_data_char_handle = BLE_GATT_HANDLE_INVALID;
m_eis_c.auxiliary_data_char_handle = BLE_GATT_HANDLE_INVALID;
m_eis_c.status_char_handle = BLE_GATT_HANDLE_INVALID;
m_eis_c.event_char_handle = BLE_GATT_HANDLE_INVALID;
ble_uuid128_t base_uuid = { .uuid128 = BLE_EIS_BASE_UUID };
ret_code_t err_code;
uint8_t uuid_type;
ble_uuid_t eis_uuid = {
.type = BLE_UUID_TYPE_UNKNOWN,
.uuid = BLE_UUID_EIS_SERVICE,
};
err_code = sd_ble_uuid_vs_add(&base_uuid, &eis_uuid.type);
ble_db_discovery_evt_register(&eis_uuid);
NRF_SDH_BLE_OBSERVER(m_eis_c_observer, BLE_DIS_C_BLE_OBSERVER_PRIO, le_eis_c_evt_handler, &m_eis_c);
le_eis_c_cccd_timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, le_eis_c_cccd_timer_cb);
}
void le_eis_c_on_db_disc_evt(ble_db_discovery_evt_t *p_evt)
{
ble_gatt_db_char_t *p_chars = p_evt->params.discovered_db.charateristics;
// Check if the service discovery is necessary for the link and if the event handler is present.
if (m_eis_c.evt_handler == NULL || m_eis_c.conn_handle == p_evt->conn_handle)
{
return;
}
// Check if the eis service was discovered.
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_EIS_SERVICE) &&
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_VENDOR_BEGIN))
{
m_eis_c.conn_handle = p_evt->conn_handle;
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
switch (p_chars[i].characteristic.uuid.uuid)
{
case BLE_UUID_EIS_REGULAR_DATA_CHAR:
m_eis_c.regular_data_char_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_EIS_LOW_FREQ_DATA_CHAR:
m_eis_c.low_freq_data_char_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_EIS_AUXILIARY_DATA_CHAR:
m_eis_c.auxiliary_data_char_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_EIS_STATUS_CHAR:
m_eis_c.status_char_handle = p_chars[i].characteristic.handle_value;
break;
case BLE_UUID_EIS_EVENT_CHAR:
m_eis_c.event_char_handle = p_chars[i].characteristic.handle_value;
break;
default:
break;
}
}
xTimerStart(le_eis_c_cccd_timer, 0);
}
}
+54 -8
View File
@@ -26,22 +26,63 @@ extern "C"
}
#endif
void le_gap_init(const char *device_name, uint16_t usAppearance)
bool is_connected = false;
static void le_gap_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
// TODO...
ret_code_t err_code;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
is_connected = true;
break;
case BLE_GAP_EVT_DISCONNECTED:
is_connected = false;
break;
default:
break;
}
}
void le_gap_connet(ble_gap_addr_t *p_peer_addr, nrf_ble_scan_t *p_scan)
void le_gap_init(const char *device_name, uint16_t usAppearance)
{
// If address is correct, stop scanning and initiate connection with peripheral device.
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_gap_observer, 3, le_gap_handler, NULL);
}
void le_gap_connet(ble_gap_addr_t *p_peer_addr)
{
if (is_connected)
{
return;
}
// If address is correct, stop scanning and initiate connection with peripheral device.
const ble_gap_conn_params_t conn_params = {
.conn_sup_timeout =
(uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT, UNIT_10_MS),
.min_conn_interval =
(uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS),
.max_conn_interval =
(uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS),
.slave_latency =
(uint16_t)NRF_BLE_SCAN_SLAVE_LATENCY,
};
extern ble_gap_scan_params_t *le_scan_params(void);
ret_code_t err_code = sd_ble_gap_connect(p_peer_addr,
&p_scan->scan_params,
&p_scan->conn_params,
le_scan_params(),
&conn_params,
APP_BLE_CONN_CFG_TAG);
APP_ERROR_CHECK(err_code);
}
void le_gap_disconnet(uint16_t conn_handle)
{
ret_code_t err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
}
void le_gap_phy_update(uint16_t conn_handle)
{
NRF_LOG_INFO("Send PHY update request.");
@@ -58,10 +99,15 @@ void le_gap_conn_param_update(uint16_t conn_handle)
NRF_LOG_INFO("Central Preferred Connection Parameters.");
// Set GAP Central Preferred Connection Parameters.
ble_gap_conn_params_t const gap_conn_params = {
.min_conn_interval = MSEC_TO_UNITS(8, UNIT_1_25_MS), /**< Minimum connection interval (7.5 ms) */
.max_conn_interval = MSEC_TO_UNITS(20, UNIT_1_25_MS), /**< Maximum connection interval (20 ms). */
.min_conn_interval = MSEC_TO_UNITS(8, UNIT_1_25_MS), /**< Minimum connection interval ( 7.5 ms) */
.max_conn_interval = MSEC_TO_UNITS(10, UNIT_1_25_MS), /**< Maximum connection interval (10.0 ms). */
.slave_latency = 8, /**< Slave latency. */
.conn_sup_timeout = MSEC_TO_UNITS(10000, UNIT_10_MS) /**< Connection supervisory timeout (10s). */
};
sd_ble_gap_conn_param_update(conn_handle, &gap_conn_params);
}
bool le_gap_is_connected(void)
{
return is_connected;
}
+351
View File
@@ -0,0 +1,351 @@
#ifdef __cplusplus
extern "C"
{
#endif
#include "ble_db_discovery.h"
#include "ble_gattc.h"
#include "ble_srv_common.h"
#include "nrf_ble_gq.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#ifdef __cplusplus
}
#endif
#define MAX_CHAR_CNT 16
extern nrf_ble_gq_t *le_gap_queue(void);
struct ble_gatt_c_s
{
void (*evt_handler)(ble_evt_t const *p_ble_evt, void *p_context);
uint16_t conn_handle;
uint16_t char_handles[MAX_CHAR_CNT];
};
uint16_t handle_mapping[MAX_CHAR_CNT];
typedef struct ble_gatt_c_s ble_gatt_c_t;
static ble_gatt_c_t m_gatt_c;
static void on_disconnected(ble_gatt_c_t *p_ble_gatt_c, ble_evt_t const *p_ble_evt)
{
p_ble_gatt_c->conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(p_ble_gatt_c->char_handles); i++)
{
p_ble_gatt_c->char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
}
static uint32_t hvx_cnt = 0;
static TickType_t hvx_begin = 0;
static void on_connected(ble_gatt_c_t *p_ble_gatt_c, ble_evt_t const *p_ble_evt)
{
hvx_cnt = 0;
hvx_begin = 0;
extern void mem_board_reset(void);
mem_board_reset();
}
static void on_hvx(ble_gatt_c_t *p_ble_gatt_c, ble_evt_t const *p_ble_evt)
{
ble_gattc_evt_hvx_t *hvx = (void *)&p_ble_evt->evt.gattc_evt.params.hvx;
uint32_t len = hvx->len;
uint8_t *p = (uint8_t *)hvx->data;
extern void mem_notify_cb(uint8_t * p, uint32_t len);
mem_notify_cb(p, len);
}
static void on_read_rsp(ble_gatt_c_t *p_le_gatt_c, ble_evt_t const *p_ble_evt)
{
extern void host_read_char_cb(uint8_t * p_data, uint16_t len);
uint16_t handle = p_ble_evt->evt.gattc_evt.params.read_rsp.handle;
for (int i = 0; i < COUNTOF(p_le_gatt_c->char_handles); i++)
{
if (handle_mapping[i] == handle)
{
ble_gattc_evt_read_rsp_t const *p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
host_read_char_cb((uint8_t *)p_response->data, p_response->len);
break;
}
}
}
ret_code_t le_gatt_ccdc_configure(uint16_t conn_handle, uint16_t char_handle, bool notification_enable)
{
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
__BKPT(255);
return NRF_ERROR_INVALID_PARAM;
}
if (char_handle == BLE_GATT_HANDLE_INVALID)
{
__BKPT(255);
return NRF_ERROR_INVALID_PARAM;
}
NRF_LOG_INFO("Configuring CCCD Handle = 0x%04X, Connection Handle = 0x%04X",
char_handle + 1,
conn_handle);
nrf_ble_gq_req_t cccd_req;
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INVALID;
uint8_t cccd[BLE_CCCD_VALUE_LEN];
cccd[0] = LSB_16(cccd_val);
cccd[1] = MSB_16(cccd_val);
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
cccd_req.params.gattc_write.handle = char_handle + 1;
cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
cccd_req.params.gattc_write.offset = 0;
cccd_req.params.gattc_write.p_value = cccd;
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &cccd_req, conn_handle);
}
static void le_gatt_c_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
ble_gatt_c_t *p_ble_gatt_c = (ble_gatt_c_t *)p_context;
if ((p_ble_gatt_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_gatt_c, p_ble_evt);
break;
case BLE_GAP_EVT_CONNECTED:
on_connected(p_ble_gatt_c, p_ble_evt);
break;
case BLE_GATTC_EVT_HVX:
/*
Handle Value Notification or Indication event.
Confirm indication with @ref sd_ble_gattc_hv_confirm.
See @ref ble_gattc_evt_hvx_t. */
on_hvx(p_ble_gatt_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
/*
Read Response event.
See @ref ble_gattc_evt_read_rsp_t. */
on_read_rsp(p_ble_gatt_c, p_ble_evt);
break;
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
/*
Primary Service Discovery Response event.
See @ref ble_gattc_evt_prim_srvc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_REL_DISC_RSP:
/*
Relationship Discovery Response event.
See @ref ble_gattc_evt_rel_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP:
/*
Characteristic Discovery Response event.
See @ref ble_gattc_evt_char_disc_rsp_t. */
break;
case BLE_GATTC_EVT_DESC_DISC_RSP:
/*
Descriptor Discovery Response event.
See @ref ble_gattc_evt_desc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP:
/*
Attribute Information Response event.
See @ref ble_gattc_evt_attr_info_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
/*
Read By UUID Response event.
See @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VALS_READ_RSP:
/*
Read multiple Response event.
See @ref ble_gattc_evt_char_vals_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_RSP:
/*
Write Response event.
See @ref ble_gattc_evt_write_rsp_t. */
break;
case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
/*
Exchange MTU Response event.
See @ref ble_gattc_evt_exchange_mtu_rsp_t. */
break;
case BLE_GATTC_EVT_TIMEOUT:
/*
Timeout event.
See @ref ble_gattc_evt_timeout_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:
/*
Write without Response transmission complete. */
__BKPT(255);
break;
default:
// No implementation needed.
break;
}
}
void le_gatt_c_cccd_timer_cb(TimerHandle_t xTimer)
{
xTimerStop(xTimer, pdMS_TO_TICKS(0));
for (int i = 0; i < COUNTOF(m_gatt_c.char_handles); i++)
{
le_gatt_ccdc_configure(m_gatt_c.conn_handle, m_gatt_c.char_handles[i], true);
}
NRF_LOG_INFO("Enable notifications. ");
}
static TimerHandle_t le_gatt_c_cccd_timer = NULL;
void le_gatt_c_init(void)
{
m_gatt_c.evt_handler = le_gatt_c_evt_handler;
m_gatt_c.conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(m_gatt_c.char_handles); i++)
{
m_gatt_c.char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
ret_code_t err_code;
uint8_t uuid_type;
ble_uuid_t uuid = {
.type = BLE_UUID_TYPE_BLE,
.uuid = BLE_UUID_CUSTOM_SERVICE,
};
err_code = ble_db_discovery_evt_register(&uuid);
APP_ERROR_CHECK(err_code);
NRF_SDH_BLE_OBSERVER(m_gatt_c_observer, BLE_DIS_C_BLE_OBSERVER_PRIO, le_gatt_c_evt_handler, &m_gatt_c);
le_gatt_c_cccd_timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, le_gatt_c_cccd_timer_cb);
}
void le_gatt_c_on_db_disc_evt(ble_db_discovery_evt_t *p_evt)
{
ble_gatt_db_char_t *p_chars = p_evt->params.discovered_db.charateristics;
// Check if the service discovery is necessary for the link and if the event handler is present.
if (m_gatt_c.evt_handler == NULL || m_gatt_c.conn_handle == p_evt->conn_handle)
{
return;
}
// Check if the custom service was discovered.
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_CUSTOM_SERVICE) &&
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
{
m_gatt_c.conn_handle = p_evt->conn_handle;
for (int i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
for (int j = 0; j < COUNTOF(m_gatt_c.char_handles); j++)
{
if (p_chars[i].characteristic.uuid.uuid == BLE_UUID_SIMPLEPROFILECHAR(j + 1))
{
m_gatt_c.char_handles[j] = p_chars[i].characteristic.handle_value;
handle_mapping[j] = m_gatt_c.char_handles[j];
break;
}
}
}
}
}
static void le_gatt_c_error_handler(uint32_t nrf_error, void *p_contex, uint16_t conn_handle)
{
UNUSED_PARAMETER(conn_handle);
__BKPT(255);
}
ret_code_t le_gatt_c_read_char_req(uint32_t handle)
{
ble_gatt_c_t *p_le_gatt_c = &m_gatt_c;
if (p_le_gatt_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
for (int i = 0; i < COUNTOF(p_le_gatt_c->char_handles); i++)
{
if (handle_mapping[i] == handle)
{
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
gq_req.error_handler.cb = le_gatt_c_error_handler;
gq_req.error_handler.p_ctx = p_le_gatt_c;
gq_req.params.gattc_read.handle = p_le_gatt_c->char_handles[i];
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, p_le_gatt_c->conn_handle);
}
}
return NRF_ERROR_INVALID_PARAM;
}
ret_code_t le_gatt_c_write_req(uint32_t handle, uint8_t const *p_data, uint16_t len)
{
ble_gatt_c_t *p_le_gatt_c = &m_gatt_c;
if (p_le_gatt_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
for (int i = 0; i < COUNTOF(p_le_gatt_c->char_handles); i++)
{
if (handle_mapping[i] == handle)
{
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
gq_req.error_handler.cb = le_gatt_c_error_handler;
gq_req.error_handler.p_ctx = p_le_gatt_c;
gq_req.params.gattc_write.handle = p_le_gatt_c->char_handles[i];
gq_req.params.gattc_write.p_value = p_data;
gq_req.params.gattc_write.len = len;
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, p_le_gatt_c->conn_handle);
}
else if (handle_mapping[i] + 1 == handle)
{
uint16_t enable = *(uint16_t *)p_data & 0x0001;
return le_gatt_ccdc_configure(m_gatt_c.conn_handle, handle_mapping[i], enable);
}
}
return NRF_ERROR_INVALID_PARAM;
}
+98 -116
View File
@@ -22,169 +22,151 @@ extern "C"
#include "nrf_sdh_freertos.h"
#include "ble_advdata.h"
#include "ble_gap.h"
#include "nrf_ble_scan.h"
#ifdef __cplusplus
}
#endif
NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */
#define MAX_DEV_NAME_LEN ((BLE_GAP_ADV_SET_DATA_SIZE_MAX + 1) - AD_DATA_OFFSET)
typedef struct
{
const uint16_t company_identifier;
struct
{
const uint8_t company_code[5];
const uint8_t hw_ver[4];
const uint16_t bat_volt;
} __PACKED data;
} manu_spec_data_t;
static void found_device_cb(manu_spec_data_t *p_manu_spec_data, char *p_device_name, ble_gap_addr_t const *peer_addr, int16_t rssi)
{
char company_code[6] = { 0, 0, 0, 0, 0, 0 };
uint32_t hw_ver = 0;
uint16_t bat_volt = 0;
if (p_manu_spec_data)
{
memcpy(company_code, &p_manu_spec_data->data.company_code[0], sizeof(p_manu_spec_data->data.company_code));
memcpy(&hw_ver, &p_manu_spec_data->data.hw_ver[0], sizeof(p_manu_spec_data->data.hw_ver));
memcpy(&bat_volt, &p_manu_spec_data->data.bat_volt, sizeof(p_manu_spec_data->data.bat_volt));
hw_ver = __REV(hw_ver);
}
char peer_addr_str[(2 + 1) * BLE_GAP_ADDR_LEN + 1];
if (peer_addr)
{
sprintf(peer_addr_str, "%02X:%02X:%02X:%02X:%02X:%02X", peer_addr->addr[5], peer_addr->addr[4], peer_addr->addr[3], peer_addr->addr[2], peer_addr->addr[1], peer_addr->addr[0]);
}
NRF_LOG_INFO("Found: %s [%s, %s, 0x%08X, %d, %ddb]",
p_device_name,
peer_addr_str,
company_code,
hw_ver,
bat_volt,
rssi);
}
static void on_adv_report(ble_gap_evt_adv_report_t const *p_adv_report)
{
// Initialize advertisement report for parsing.
ret_code_t err_code;
uint16_t field_len = 0;
uint16_t offset = 0;
void *p_manu_spec_data = NULL;
char dev_name[MAX_DEV_NAME_LEN];
memset(dev_name, 0x00, MAX_DEV_NAME_LEN);
// Search for advertising names.
uint32_t device_name_len = ble_advdata_search(p_adv_report->data.p_data,
p_adv_report->data.len,
&offset,
BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
if (device_name_len)
{
uint8_t *p = (uint8_t *)p_adv_report->data.p_data;
memcpy(dev_name, &p[offset], device_name_len);
}
// Search for advertising manufacturer spec data
field_len = ble_advdata_search(p_adv_report->data.p_data,
p_adv_report->data.len,
&offset,
BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA);
if (field_len)
offset = 0;
uint32_t manu_spec_data_len =
ble_advdata_search(p_adv_report->data.p_data, p_adv_report->data.len, &offset, BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA);
if (manu_spec_data_len)
{
p_manu_spec_data = &p_adv_report->data.p_data[offset];
}
// Search for advertising names.
field_len = ble_advdata_search(p_adv_report->data.p_data,
p_adv_report->data.len,
&offset,
BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
if (field_len)
{
uint8_t *p = (uint8_t *)p_adv_report->data.p_data;
memcpy(dev_name, &p[offset], field_len);
}
extern void host_scan_filter_match_cb(
void *p_manu_spec_data,
uint32_t manu_spec_data_len,
char *p_device_name,
uint32_t device_name_len,
ble_gap_addr_t const *peer_addr,
int16_t rssi);
found_device_cb(p_manu_spec_data, dev_name, &p_adv_report->peer_addr, p_adv_report->rssi);
host_scan_filter_match_cb(
p_manu_spec_data,
manu_spec_data_len,
dev_name,
device_name_len,
&p_adv_report->peer_addr,
p_adv_report->rssi);
}
static void scan_evt_handler(scan_evt_t const *p_scan_evt)
static uint8_t scan_buffer[BLE_GAP_SCAN_BUFFER_MAX];
static ble_data_t const adv_report_buffer = { .p_data = scan_buffer,
.len = BLE_GAP_SCAN_BUFFER_MAX };
static ble_uuid_t const filter_uuid = { .type = BLE_UUID_TYPE_BLE, .uuid = 0xFFF0 };
static uint64_t mac = 0;
static uint32_t peer_addr_idx = 0;
static ble_gap_addr_t peer_addr_list[16];
void le_scan_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
ret_code_t err_code;
ble_gap_evt_adv_report_t const *p_adv_report = &p_ble_evt->evt.gap_evt.params.adv_report;
uint16_t data_len = p_ble_evt->evt.gap_evt.params.adv_report.data.len;
ble_gap_addr_t const *peer_addr = &p_ble_evt->evt.gap_evt.params.adv_report.peer_addr;
uint64_t u64_peer_addr = 0;
memcpy(&u64_peer_addr, peer_addr, sizeof(peer_addr->addr));
switch (p_scan_evt->scan_evt_id)
if (ble_advdata_uuid_find(p_adv_report->data.p_data, data_len, &filter_uuid))
{
case NRF_BLE_SCAN_EVT_CONNECTING_ERROR: {
/**< Error occurred when establishing the connection.
In this event, an error is passed from the function call @ref sd_ble_gap_connect. */
err_code = p_scan_evt->params.connecting_err.err_code;
APP_ERROR_CHECK(err_code);
mac = u64_peer_addr;
if (peer_addr)
{
char peer_addr_str[(2 + 1) * BLE_GAP_ADDR_LEN + 1] = { 0 };
peer_addr_list[peer_addr_idx++ % COUNTOF(peer_addr_list)] = *peer_addr;
sprintf(peer_addr_str, "%02X:%02X:%02X:%02X:%02X:%02X", peer_addr->addr[5], peer_addr->addr[4], peer_addr->addr[3], peer_addr->addr[2], peer_addr->addr[1], peer_addr->addr[0]);
NRF_LOG_INFO("%s", peer_addr_str);
}
break;
case NRF_BLE_SCAN_EVT_FILTER_MATCH: {
/**< A filter is matched or all filters are matched in the multifilter mode. */
on_adv_report(p_scan_evt->params.filter_match.p_adv_report);
}
else if (mac == u64_peer_addr)
{
on_adv_report(p_adv_report);
}
sd_ble_gap_scan_start(NULL, &adv_report_buffer);
}
void le_scan_get_peer_addr(ble_gap_addr_t *p_peer_addr)
{
for (uint32_t i = 0; i < COUNTOF(peer_addr_list); i++)
{
if (memcmp(peer_addr_list[i].addr, p_peer_addr->addr, BLE_GAP_ADDR_LEN) == 0)
{
p_peer_addr->addr_type = peer_addr_list[i].addr_type;
break;
}
break;
case NRF_BLE_SCAN_EVT_CONNECTED:
/**< Connected to device. */
break;
case NRF_BLE_SCAN_EVT_WHITELIST_REQUEST:
/**< Request the whitelist from the main application. For whitelist scanning to work, the whitelist must be set when this event occurs. */
break;
case NRF_BLE_SCAN_EVT_WHITELIST_ADV_REPORT:
/**< Send notification to the main application when a device from the whitelist is found. */
break;
case NRF_BLE_SCAN_EVT_NOT_FOUND:
/**< The filter was not matched for the scan data. */
break;
case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
/**< Scan timeout. */
break;
default:
break;
}
}
static char const *m_target_periph_name[] = ELITE_DEVICE_NAME_LIST;
static ble_gap_scan_params_t scan_params = {
.active = 1,
.interval = NRF_BLE_SCAN_SCAN_INTERVAL,
.window = NRF_BLE_SCAN_SCAN_WINDOW,
.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
.scan_phys = BLE_GAP_PHY_1MBPS,
.timeout = BLE_GAP_SCAN_TIMEOUT_UNLIMITED,
.channel_mask = {0, 0, 0, 0, 0},
.report_incomplete_evts = 0,
.extended = 0,
};
void le_scan_init(void)
{
ret_code_t err_code;
nrf_ble_scan_init_t init_scan;
memset(&init_scan, 0, sizeof(init_scan));
init_scan.connect_if_match = false;
init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
APP_ERROR_CHECK(err_code);
for (int i = 0; i < COUNTOF(m_target_periph_name); i++)
{
err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name[i]);
APP_ERROR_CHECK(err_code);
}
err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false);
APP_ERROR_CHECK(err_code);
// TODO...
}
bool is_scanning = false;
void le_scan_start(void)
{
ret_code_t ret;
NRF_LOG_INFO("Start scanning for device name \"%s\", \"%s\".",
(uint32_t)m_target_periph_name[0],
(uint32_t)m_target_periph_name[1]);
ret = nrf_ble_scan_start(&m_scan);
APP_ERROR_CHECK(ret);
if (is_scanning != true)
{
NRF_LOG_INFO("Start scanning for UUID service 0x%04X.",
BLE_UUID_CUSTOM_SERVICE);
is_scanning = true;
peer_addr_idx = 0;
memset(peer_addr_list, 0x00, sizeof(peer_addr_list));
sd_ble_gap_scan_start(&scan_params, &adv_report_buffer);
}
}
void le_scan_stop(void)
{
NRF_LOG_INFO("Stop scanning.");
nrf_ble_scan_stop();
sd_ble_gap_scan_stop();
is_scanning = false;
}
const nrf_ble_scan_t *le_scan_obj(void)
ble_gap_scan_params_t *le_scan_params(void)
{
return &m_scan;
return &scan_params;
}
+466
View File
@@ -0,0 +1,466 @@
#ifdef __cplusplus
extern "C"
{
#endif
#include "ble_db_discovery.h"
#include "ble_gattc.h"
#include "ble_srv_common.h"
#include "nrf_ble_gq.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "FreeRTOS.h"
#include "message_buffer.h"
#include "semphr.h"
#include "task.h"
#include "timers.h"
#ifdef __cplusplus
}
#endif
#define MAX_CHAR_CNT 4
extern nrf_ble_gq_t *le_gap_queue(void);
struct le_uart_c_s
{
void (*evt_handler)(ble_evt_t const *p_ble_evt, void *p_context);
uint16_t conn_handle;
uint16_t char_handles[MAX_CHAR_CNT];
TimerHandle_t le_uart_c_cccd_timer;
MessageBufferHandle_t rx_msg;
SemaphoreHandle_t baud_sem;
uint32_t baud_rate;
};
#define UART_TX_HAND_IDX 0
#define UART_RX_HAND_IDX 1
#define UART_BAUD_HAND_IDX 2
typedef struct le_uart_c_s le_uart_c_t;
static le_uart_c_t m_le_uart_c;
static void on_disconnected(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
p_le_uart_c->conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(p_le_uart_c->char_handles); i++)
{
p_le_uart_c->char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
}
static void on_connected(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
xTimerStart(p_le_uart_c->le_uart_c_cccd_timer, 0);
}
static void on_hvx(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
ble_gattc_evt_hvx_t *hvx = (void *)&p_ble_evt->evt.gattc_evt.params.hvx;
if (p_le_uart_c->rx_msg)
{
taskENTER_CRITICAL();
xMessageBufferSend(p_le_uart_c->rx_msg, (void *)hvx->data, hvx->len, 0);
taskEXIT_CRITICAL();
}
}
static void on_read_rsp(le_uart_c_t *p_le_uart_c, ble_evt_t const *p_ble_evt)
{
uint16_t handle = p_ble_evt->evt.gattc_evt.params.read_rsp.handle;
ble_gattc_evt_read_rsp_t const *p_rsp = &p_ble_evt->evt.gattc_evt.params.read_rsp;
if (handle == p_le_uart_c->char_handles[UART_RX_HAND_IDX])
{
}
else if (handle == p_le_uart_c->char_handles[UART_BAUD_HAND_IDX])
{
xSemaphoreGive(m_le_uart_c.baud_sem);
m_le_uart_c.baud_rate = *(uint32_t *)p_rsp->data;
}
}
ret_code_t le_uart_ccdc_configure(uint16_t conn_handle, uint16_t char_handle, bool notification_enable)
{
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
if (char_handle == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
NRF_LOG_INFO("Configuring CCCD Handle = 0x%04X, Connection Handle = 0x%04X",
char_handle + 1,
conn_handle);
nrf_ble_gq_req_t cccd_req;
uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INVALID;
uint8_t cccd[BLE_CCCD_VALUE_LEN];
cccd[0] = LSB_16(cccd_val);
cccd[1] = MSB_16(cccd_val);
memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
cccd_req.params.gattc_write.handle = char_handle + 1;
cccd_req.params.gattc_write.len = BLE_CCCD_VALUE_LEN;
cccd_req.params.gattc_write.offset = 0;
cccd_req.params.gattc_write.p_value = cccd;
cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &cccd_req, conn_handle);
}
static void le_uart_c_cccd_timer_cb(TimerHandle_t xTimer)
{
xTimerStop(xTimer, pdMS_TO_TICKS(0));
extern ret_code_t le_uart_rx_notify(bool enable);
le_uart_rx_notify(true);
xMessageBufferReset(m_le_uart_c.rx_msg);
}
static void le_uart_c_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
{
le_uart_c_t *p_le_uart_c = (le_uart_c_t *)p_context;
if ((p_le_uart_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_le_uart_c, p_ble_evt);
break;
case BLE_GAP_EVT_CONNECTED:
on_connected(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_HVX:
/*
Handle Value Notification or Indication event.
Confirm indication with @ref sd_ble_gattc_hv_confirm.
See @ref ble_gattc_evt_hvx_t. */
on_hvx(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_READ_RSP:
/*
Read Response event.
See @ref ble_gattc_evt_read_rsp_t. */
on_read_rsp(p_le_uart_c, p_ble_evt);
break;
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
/*
Primary Service Discovery Response event.
See @ref ble_gattc_evt_prim_srvc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_REL_DISC_RSP:
/*
Relationship Discovery Response event.
See @ref ble_gattc_evt_rel_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP:
/*
Characteristic Discovery Response event.
See @ref ble_gattc_evt_char_disc_rsp_t. */
break;
case BLE_GATTC_EVT_DESC_DISC_RSP:
/*
Descriptor Discovery Response event.
See @ref ble_gattc_evt_desc_disc_rsp_t. */
break;
case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP:
/*
Attribute Information Response event.
See @ref ble_gattc_evt_attr_info_disc_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
/*
Read By UUID Response event.
See @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_CHAR_VALS_READ_RSP:
/*
Read multiple Response event.
See @ref ble_gattc_evt_char_vals_read_rsp_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_RSP:
/*
Write Response event.
See @ref ble_gattc_evt_write_rsp_t. */
break;
case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
/*
Exchange MTU Response event.
See @ref ble_gattc_evt_exchange_mtu_rsp_t. */
break;
case BLE_GATTC_EVT_TIMEOUT:
/*
Timeout event.
See @ref ble_gattc_evt_timeout_t. */
__BKPT(255);
break;
case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:
/*
Write without Response transmission complete. */
__BKPT(255);
break;
default:
// No implementation needed.
break;
}
}
void le_uart_c_on_db_disc_evt(ble_db_discovery_evt_t *p_evt)
{
ble_gatt_db_char_t *p_chars = p_evt->params.discovered_db.charateristics;
// Check if the service discovery is necessary for the link and if the event handler is present.
if (m_le_uart_c.evt_handler == NULL || m_le_uart_c.conn_handle == p_evt->conn_handle)
{
return;
}
// Check if the uart service was discovered.
if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
(p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_UART_SERVICE) &&
(p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
{
m_le_uart_c.conn_handle = p_evt->conn_handle;
for (int i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
for (int j = 0; j < COUNTOF(m_le_uart_c.char_handles); j++)
{
if (p_chars[i].characteristic.uuid.uuid == BLE_UUID_UART_CHAR(j + 1))
{
m_le_uart_c.char_handles[j] = p_chars[i].characteristic.handle_value;
break;
}
}
}
}
}
static void le_uart_c_error_handler(uint32_t nrf_error, void *p_contex, uint16_t conn_handle)
{
UNUSED_PARAMETER(conn_handle);
__BKPT(255);
}
ret_code_t le_uart_tx(uint8_t const *p_data, uint16_t len)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_write.handle = m_le_uart_c.char_handles[UART_TX_HAND_IDX];
gq_req.params.gattc_write.p_value = p_data;
gq_req.params.gattc_write.len = len;
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
}
ret_code_t le_uart_rx_notify(bool enable)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
if (m_le_uart_c.char_handles[UART_RX_HAND_IDX] == BLE_GATT_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
ret_code_t ret = le_uart_ccdc_configure(m_le_uart_c.conn_handle, m_le_uart_c.char_handles[UART_RX_HAND_IDX], enable);
if (ret == NRF_SUCCESS)
{
NRF_LOG_INFO(enable == true ? "Enable Rx notifications." : "Disable Rx notifications.");
}
return ret;
}
ret_code_t le_uart_rx(uint8_t *p_data, uint16_t len, uint32_t timeout)
{
size_t recv_size = 0;
if (timeout)
{
recv_size = xMessageBufferReceive(m_le_uart_c.rx_msg, p_data, len, timeout);
}
else
{
taskENTER_CRITICAL();
recv_size = xMessageBufferReceive(m_le_uart_c.rx_msg, p_data, len, 0);
taskEXIT_CRITICAL();
}
if (recv_size)
{
return recv_size;
}
return NRF_ERROR_TIMEOUT;
}
ret_code_t le_uart_baudrate_get(uint32_t *baudrate)
{
ret_code_t ret;
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_read.handle = m_le_uart_c.char_handles[UART_BAUD_HAND_IDX];
ret = nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
if (ret == NRF_SUCCESS)
{
if (xSemaphoreTake(m_le_uart_c.baud_sem, pdMS_TO_TICKS(100)) == pdFALSE)
{
return NRF_ERROR_TIMEOUT;
}
*baudrate = m_le_uart_c.baud_rate;
}
return ret;
}
ret_code_t le_uart_baudrate_set(uint32_t baudrate)
{
if (m_le_uart_c.conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_ble_gq_req_t gq_req;
memset(&gq_req, 0, sizeof(gq_req));
gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
gq_req.error_handler.cb = le_uart_c_error_handler;
gq_req.error_handler.p_ctx = &m_le_uart_c;
gq_req.params.gattc_write.handle = m_le_uart_c.char_handles[UART_BAUD_HAND_IDX];
gq_req.params.gattc_write.p_value = (void *)&baudrate;
gq_req.params.gattc_write.len = sizeof(baudrate);
gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
return nrf_ble_gq_item_add(le_gap_queue(), &gq_req, m_le_uart_c.conn_handle);
}
static void ble_uart_echo(void *p_arg)
{
void le_scan_start(void);
le_scan_start();
vTaskDelay(pdMS_TO_TICKS(3000));
void le_scan_stop(void);
le_scan_stop();
vTaskDelay(pdMS_TO_TICKS(10));
ble_gap_addr_t peer_addr;
peer_addr.addr_id_peer = 0;
peer_addr.addr_type = BLE_GAP_ADDR_TYPE_ANONYMOUS;
peer_addr.addr[0] = 0xDA;
peer_addr.addr[1] = 0x71;
peer_addr.addr[2] = 0x1F;
peer_addr.addr[3] = 0x1F;
peer_addr.addr[4] = 0x05;
peer_addr.addr[5] = 0xDC;
extern void le_scan_get_peer_addr(ble_gap_addr_t * p_peer_addr);
le_scan_get_peer_addr(&peer_addr);
vTaskDelay(pdMS_TO_TICKS(10));
extern void le_gap_connet(ble_gap_addr_t * p_peer_addr);
le_gap_connet(&peer_addr);
vTaskDelay(pdMS_TO_TICKS(1000));
uint32_t get_baud = 1000000;
uint32_t set_baud = 115200;
extern ret_code_t le_uart_baudrate_get(uint32_t * baudrate);
le_uart_baudrate_get(&get_baud);
NRF_LOG_INFO("Get Baud rate: %d", get_baud);
extern ret_code_t le_uart_baudrate_set(uint32_t baudrate);
le_uart_baudrate_set(set_baud);
NRF_LOG_INFO("Set Baud rate: %d", set_baud);
le_uart_baudrate_get(&get_baud);
NRF_LOG_INFO("Get Baud rate: %d", get_baud);
extern ret_code_t le_uart_tx(uint8_t const *p_data, uint16_t len);
uint8_t str[] = "ABCDEF";
le_uart_tx(str, strlen(str));
for (;;)
{
uint8_t recv[256];
uint32_t size;
size = le_uart_rx(recv, sizeof(recv), portMAX_DELAY);
le_uart_tx(recv, size);
}
}
void le_uart_c_init(void)
{
m_le_uart_c.rx_msg = xMessageBufferCreate(4096);
m_le_uart_c.baud_sem = xSemaphoreCreateBinary();
m_le_uart_c.evt_handler = le_uart_c_evt_handler;
m_le_uart_c.conn_handle = BLE_CONN_HANDLE_INVALID;
for (int i = 0; i < COUNTOF(m_le_uart_c.char_handles); i++)
{
m_le_uart_c.char_handles[i] = BLE_GATT_HANDLE_INVALID;
}
ret_code_t err_code;
uint8_t uuid_type;
ble_uuid_t uuid = {
.type = BLE_UUID_TYPE_BLE,
.uuid = BLE_UUID_UART_SERVICE,
};
err_code = ble_db_discovery_evt_register(&uuid);
APP_ERROR_CHECK(err_code);
NRF_SDH_BLE_OBSERVER(m_uart_c_observer, 1, le_uart_c_evt_handler, &m_le_uart_c);
m_le_uart_c.le_uart_c_cccd_timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)1, le_uart_c_cccd_timer_cb);
#if 1
xTaskCreate(ble_uart_echo, "ble uart echo", 2048, NULL, 3, NULL);
#endif
}
+21 -8
View File
@@ -40,8 +40,11 @@ static void le_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
ret_code_t err_code;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_ADV_REPORT:
break;
case BLE_GAP_EVT_ADV_REPORT: {
extern void le_scan_handler(ble_evt_t const *p_ble_evt, void *p_context);
le_scan_handler(p_ble_evt, p_context);
}
break;
case BLE_GAP_EVT_PHY_UPDATE:
NRF_LOG_INFO("PHY update procedure is complete.");
break;
@@ -50,20 +53,19 @@ static void le_evt_handler(ble_evt_t const *p_ble_evt, void *p_context)
break;
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected to peer.");
le_scan_stop();
le_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle);
le_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle);
le_db_discovery_start(p_ble_evt->evt.gap_evt.conn_handle);
break;
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected from peer.");
le_scan_start();
break;
case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
le_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle);
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING: {
ret_code_t err_code = sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0);
ret_code_t err_code = sd_ble_gatts_sys_attr_set(
p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0);
APP_ERROR_CHECK(err_code);
}
break;
@@ -105,15 +107,21 @@ static void initialize(void *p_context)
extern void uart_drv_init(void);
uart_drv_init();
extern void mem_board_init(void);
mem_board_init();
extern void le_db_discovery_init(void);
le_db_discovery_init();
extern void le_dis_c_init(void);
le_dis_c_init();
extern void le_eis_c_init(void);
le_eis_c_init();
extern void le_gatt_c_init(void);
le_gatt_c_init();
extern void le_uart_c_init(void);
le_uart_c_init();
extern void le_gap_init(void);
le_gap_init();
@@ -129,7 +137,7 @@ static void initialize(void *p_context)
int main(void)
{
NRF_LOG_INIT(NULL, 0);
NRF_LOG_INIT(xTaskGetTickCount, configTICK_RATE_HZ);
NRF_LOG_DEFAULT_BACKENDS_INIT();
NRF_LOG_INFO("%s Build: %s %s", LE_DEVICE_NAME, __TIME__, __DATE__);
@@ -145,3 +153,8 @@ int main(void)
__BKPT(255);
}
}
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
__BKPT(255);
}
+283
View File
@@ -0,0 +1,283 @@
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "nrf_spim.h"
#include "FreeRTOS.h"
#include "message_buffer.h"
#include "semphr.h"
#include "stream_buffer.h"
#include "task.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#ifdef __cplusplus
}
#endif
#define MEM_SEL_PIN NRF_GPIO_PIN_MAP(1, 9)
#define MEM_BZY_PIN NRF_GPIO_PIN_MAP(0, 8)
#define MEM_REQ_PIN NRF_GPIO_PIN_MAP(0, 6)
#define RAM_SEL_PIN NRF_GPIO_PIN_MAP(0, 5)
#define MEM_TEST_01_PIN NRF_GPIO_PIN_MAP(0, 26)
#define MEM_TEST_02_PIN NRF_GPIO_PIN_MAP(0, 17)
#define MEM_TEST_03_PIN NRF_GPIO_PIN_MAP(0, 21)
#define MEM_TEST_04_PIN NRF_GPIO_PIN_MAP(0, 19)
#define MEM_TEST_05_PIN NRF_GPIO_PIN_MAP(0, 22)
#define MEM_SEL_GPIOTE_ID 0
#define MEM_REQ_GPIOTE_ID 1
#define MEM_DATA_UNIT 40
#define MEM_DUMP 0
static int ram_sel = 0;
static SemaphoreHandle_t mem_sel_semphr = NULL;
static TaskHandle_t mem_drv_task_handle = NULL;
static StreamBufferHandle_t mem_drv_stream = NULL;
typedef struct
{
struct
{
union
{
uint32_t val;
struct
{
uint16_t len;
uint16_t marker;
} __PACKED;
} header[3];
} green_frame;
uint8_t red_frame[2048];
} mem_data_t;
mem_data_t mem_data;
uint32_t mem_notify_cnt = 0;
uint32_t mem_req;
uint32_t mem_sel;
void mem_ram_select(int select)
{
ram_sel = select;
switch (ram_sel)
{
case 0:
nrf_gpio_pin_clear(RAM_SEL_PIN);
break;
case 1:
nrf_gpio_pin_set(RAM_SEL_PIN);
break;
default:
break;
}
NRF_LOG_INFO("Select SRAM: %d", ram_sel);
}
extern int sram_drv_write(uint32_t addr, void *p_dest, uint32_t len);
extern int sram_drv_read(uint32_t addr, void *p_dest, uint32_t len);
static bool chk_sram_swtich_evt(uint32_t *new_ram_sel)
{
/************************************************
* When the mem_sel is in a low-level state,
* the state of mem_req is considered valid.
************************************************/
while (mem_sel == false)
{
vTaskDelay(pdMS_TO_TICKS(5));
/* sync mem_req status */
mem_req = nrf_gpio_pin_read(MEM_REQ_PIN);
if (mem_req != ram_sel)
{
*new_ram_sel = mem_req;
return true;
}
}
return false;
}
static void mem_drv_task(void *p_arg)
{
extern void sram_drv_init(void);
sram_drv_init();
extern void sram_drv_reset(void);
mem_ram_select(0);
sram_drv_reset();
mem_ram_select(1);
sram_drv_reset();
mem_ram_select(0);
for (;;)
{
uint32_t new_ram_sel;
xSemaphoreTake(mem_sel_semphr, portMAX_DELAY);
if (chk_sram_swtich_evt(&new_ram_sel) == false)
{
continue;
}
vTaskDelay(pdMS_TO_TICKS(100));
uint32_t green_frame_size = sizeof(mem_data.green_frame);
uint32_t red_frame_size = 0;
uint32_t total_size = 0;
/* read red frame data from streambuffer */
taskENTER_CRITICAL();
red_frame_size = xStreamBufferReceive(mem_drv_stream, mem_data.red_frame, sizeof(mem_data.red_frame), 0);
taskEXIT_CRITICAL();
/* write green & red frame data to sram */
total_size = green_frame_size + red_frame_size;
mem_data.green_frame.header[0].len = __REVSH(total_size);
mem_data.green_frame.header[0].marker = __REVSH(0xA55A);
mem_data.green_frame.header[1].val = mem_data.green_frame.header[0].val;
mem_data.green_frame.header[2].val = mem_data.green_frame.header[0].val;
sram_drv_write(0x0000, &mem_data, total_size);
/* switch sram */
mem_ram_select(new_ram_sel);
#if MEM_DUMP
for (uint32_t i = 0; i < total_size / 32; i++)
{
uint8_t *p = (uint8_t *)&mem_data;
NRF_LOG_HEXDUMP_INFO(&p[i * 32], 32);
}
if (total_size % 32)
{
uint8_t *p = (uint8_t *)&mem_data;
NRF_LOG_HEXDUMP_INFO(&p[(total_size / 32) * 32], total_size % 32);
}
#endif
NRF_LOG_INFO("Write: %4d bytes, and switch sram done!!!", total_size);
}
}
void mem_board_reset(void)
{
mem_notify_cnt = 0;
xStreamBufferReset(mem_drv_stream);
}
void mem_notify_cb(uint8_t *p, uint32_t len)
{
/* write red frame data to streambuffer */
static struct
{
uint8_t prefix;
uint8_t cnt;
uint8_t len;
uint8_t content[64];
} swap_buf;
swap_buf.prefix = 0xFF;
swap_buf.cnt = mem_notify_cnt++;
swap_buf.len = len;
memcpy(swap_buf.content, p, len);
swap_buf.content[len + 0] = 0;
swap_buf.content[len + 1] = 0;
swap_buf.content[len + 2] = 0;
swap_buf.content[len + 3] = 0;
swap_buf.content[len + 4] = 0;
uint32_t sum = 0;
for (int i = 0; i < len; i++)
{
sum += p[i];
}
sum += swap_buf.prefix;
sum += swap_buf.cnt;
sum += swap_buf.len;
swap_buf.content[len + 5] = sum & 0xFF;
taskENTER_CRITICAL();
xStreamBufferSend(mem_drv_stream, &swap_buf, 3 + len + 6, 0);
taskEXIT_CRITICAL();
}
void mem_board_init(void)
{
// Config RAM test pin
nrf_gpio_cfg_input(MEM_TEST_01_PIN, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(MEM_TEST_02_PIN, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(MEM_TEST_03_PIN, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(MEM_TEST_04_PIN, NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_input(MEM_TEST_05_PIN, NRF_GPIO_PIN_PULLUP);
// Config RAM select pin
nrf_gpio_cfg_output(RAM_SEL_PIN);
nrf_gpio_pin_clear(RAM_SEL_PIN);
// Config PI Ctrl pin
nrf_gpio_cfg_input(MEM_SEL_PIN, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_input(MEM_REQ_PIN, NRF_GPIO_PIN_NOPULL);
nrf_gpiote_event_configure(MEM_SEL_GPIOTE_ID, MEM_SEL_PIN, NRF_GPIOTE_POLARITY_TOGGLE);
nrf_gpiote_event_enable(MEM_SEL_GPIOTE_ID);
nrf_gpiote_int_enable(0x01 << MEM_SEL_GPIOTE_ID);
nrf_gpiote_event_configure(MEM_REQ_GPIOTE_ID, MEM_REQ_PIN, NRF_GPIOTE_POLARITY_TOGGLE);
nrf_gpiote_event_enable(MEM_REQ_GPIOTE_ID);
nrf_gpiote_int_enable(0x01 << MEM_REQ_GPIOTE_ID);
// Create Semphr & Task
mem_sel_semphr = xSemaphoreCreateBinary();
mem_drv_stream = xStreamBufferCreate(4096, 1);
xTaskCreate(mem_drv_task, "mem_drv", 256, NULL, 5, NULL);
sd_nvic_SetPriority(GPIOTE_IRQn, _PRIO_APP_MID);
sd_nvic_EnableIRQ(GPIOTE_IRQn);
}
static void mem_sel_isr(void)
{
mem_sel = nrf_gpio_pin_read(MEM_SEL_PIN);
if (mem_sel == 0)
{
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(mem_sel_semphr, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
static void mem_req_isr(void)
{
mem_req = nrf_gpio_pin_read(MEM_REQ_PIN);
}
void GPIOTE_IRQHandler(void)
{
if (NRF_GPIOTE->EVENTS_IN[MEM_SEL_GPIOTE_ID])
{
NRF_GPIOTE->EVENTS_IN[MEM_SEL_GPIOTE_ID] = 0;
mem_sel_isr();
return;
}
if (NRF_GPIOTE->EVENTS_IN[MEM_REQ_GPIOTE_ID])
{
NRF_GPIOTE->EVENTS_IN[MEM_REQ_GPIOTE_ID] = 0;
mem_req_isr();
return;
}
}
+1 -1
View File
@@ -18,7 +18,7 @@
<Link>
<LinkerScript Condition="'%(Link.LinkerScript)' == ''">$(BSP_ROOT)/nRF5x/LinkerScripts/nRF52840_XXAA_S140_reserve.lds</LinkerScript>
<LibrarySearchDirectories>$(BSP_ROOT)/nRF5x/SoftdeviceLibraries/hard;$(BSP_ROOT)/nRF5x/LinkerScripts;%(Link.LibrarySearchDirectories)</LibrarySearchDirectories>
<AdditionalOptions>--specs=nano.specs -u _printf_float --specs=nosys.specs -mabi=aapcs %(Link.AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>--specs=nano.specs -u _printf_float --specs=nosys.specs -Wl,--no-warn-rwx-segments -mabi=aapcs %(Link.AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<PropertyGroup>
+3 -3
View File
@@ -2,9 +2,9 @@
<EmbeddedProfile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ToolchainID>com.visualgdb.arm-eabi</ToolchainID>
<ToolchainVersion>
<GCC>10.3.1</GCC>
<GDB>10.2.90</GDB>
<Revision>1</Revision>
<GCC>14.2.1</GCC>
<GDB>15.2</GDB>
<Revision>2</Revision>
</ToolchainVersion>
<BspID>com.sysprogs.arm.nordic.nrf5x</BspID>
<BspVersion>17.0</BspVersion>
+118
View File
@@ -0,0 +1,118 @@
import serial
import os
import time
def survive_cmd(ser):
send = [0x0A, 0x01, 0xF1]
ser.write(send)
read = ser.read(4)
print("recv: " + " ".join("%02X" % b for b in read))
def scan_cmd(ser, is_raw_data=True):
send = [0x03, 0x01, 0xF1]
ser.write(send)
peer_addr = []
for i in range(10):
hci_packet_event = ser.read(2)
if int.from_bytes(hci_packet_event, "little") != 0x0004:
continue
len = ser.read(1)
payload = ser.read(int.from_bytes(len, "little"))
peer_addr = payload[0:6]
if is_raw_data:
print(
"recv: "
+ " ".join("0x%02X" % b for b in hci_packet_event)
+ " "
+ " ".join("0x%02X" % b for b in len)
+ " "
+ " ".join("0x%02X" % b for b in payload)
)
else:
print("-" * 100)
print(" peer address: " + ":".join("%02X" % b for b in payload[0:6]))
print("product module: " + str(payload[6:10], "utf-8"))
print(" hw version: " + " ".join("%02X" % b for b in payload[10:14]))
print(" build time: " + " ".join("%02X" % b for b in payload[14:16]))
print(" Parameter1: " + str(payload[16:19], "utf-8"))
print(
" battery volt: "
+ str(int.from_bytes(payload[19:21], "big") / 1000.0)
+ "V"
)
print(" device name: " + str(payload[21:], "utf-8"))
return peer_addr
def connect(ser, peer_addr=[]):
send = [0x05, 0x08, 0x00]
send += peer_addr
send += [0xF1]
ser.write(send)
read = ser.read(4)
print("recv: " + " ".join("%02X" % b for b in read))
def disconnect(ser):
send = [0x08, 0x01, 0xF1]
ser.write(send)
read = ser.read(4)
print("recv: " + " ".join("%02X" % b for b in read))
def write_char(ser: serial.Serial, handle: int, write_data: tuple):
send = [0x06, len(write_data)+2, handle]
send += write_data
send += [0xF1]
ser.write(send)
def read_char(ser: serial.Serial, handle: int):
send = [0x07, 0x02, handle, 0xF1]
ser.write(send)
read = ser.read(0xFFFF)
print("recv: " + " ".join("%02X" % b for b in read))
def main():
# set comport
ser = serial.Serial("COM15", 57600, 8, inter_byte_timeout=0.01)
# send survive cmd
survive_cmd(ser)
# send scan cmd
peer_addr = scan_cmd(ser, False)
time.sleep(10)
return
# send connect cmd with peer addr
connect(ser, peer_addr)
time.sleep(3)
# send write char to enable notify
write_char(ser, 0x0024, [0xc4,0xf0,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
time.sleep(0.1)
write_char(ser, 0x0024, [0x74,0x10,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
time.sleep(0.1)
read_char(ser, 0x0021)
# 130500040000000000000000000000000000001c
time.sleep(0.2)
# send write char to enable notify
#write_char(ser, 0x0028, 1)
#time.sleep(5)
# send write char to disable notify
#write_char(ser, 0x0028, 0)
# send read char to disable notify
#read_char(ser, 0x0027)
# send disconnect cmd
disconnect(ser)
ser.close()
if __name__ == "__main__":
main()
+198
View File
@@ -0,0 +1,198 @@
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "nrf_gpio.h"
#include "nrf_spim.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#ifdef __cplusplus
}
#endif
#define SRAM_23K640 0
#define SRAM_23K256
#define SRAM_DEVICE SRAM_23K640
#define SRAM_BANK_NUM 2
#define READ_CMD (0b00000011)
#define WRITE_CMD (0b00000010)
#define READ_STATUS_CMD (0b00000101)
#define WRITE_STATUS_CMD (0b00000001)
#define BYTE_MODE (0b00000010)
#define PAGE_MODE (0b10000010)
#define SEQ_MODE (0b01000010)
#define RESVD_MODE (0b11000010)
#define HOLD_DISABLE (0b00000001)
#if (SRAM_DEVICE == SRAM_23K640)
#define SRAM_SIZE (64 * 1024 / 8)
#elif (SRAM_DEVICE == SRAM_23K256)
#define SRAM_SIZE (256 * 1024 / 8)
#else
#error "unvalid external sram device"
#endif
#define SRAM_SPIM (NRF_SPIM3)
#define CS_PIN NRF_GPIO_PIN_MAP(0, 7)
#define SCLK_PIN NRF_GPIO_PIN_MAP(0, 12)
#define MOSI_PIN NRF_GPIO_PIN_MAP(0, 14)
#define MISO_PIN NRF_GPIO_PIN_MAP(0, 11)
static SemaphoreHandle_t txrx_end_sem;
static SemaphoreHandle_t sram_mutex;
static void write_bytes(void *p, uint32_t len)
{
nrf_spim_tx_buffer_set(SRAM_SPIM, p, len);
nrf_spim_rx_buffer_set(SRAM_SPIM, p, 0);
nrf_spim_task_trigger(SRAM_SPIM, NRF_SPIM_TASK_START);
xSemaphoreTake(txrx_end_sem, portMAX_DELAY);
}
static void read_bytes(void *p, uint32_t len)
{
nrf_spim_tx_buffer_set(SRAM_SPIM, p, 0);
nrf_spim_rx_buffer_set(SRAM_SPIM, p, len);
nrf_spim_task_trigger(SRAM_SPIM, NRF_SPIM_TASK_START);
xSemaphoreTake(txrx_end_sem, portMAX_DELAY);
}
static void read_write_bytes(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len)
{
static uint8_t recv[256];
nrf_spim_tx_buffer_set(SRAM_SPIM, tx, tx_len);
nrf_spim_rx_buffer_set(SRAM_SPIM, recv, tx_len + rx_len);
nrf_spim_task_trigger(SRAM_SPIM, NRF_SPIM_TASK_START);
xSemaphoreTake(txrx_end_sem, portMAX_DELAY);
memcpy(rx, &recv[tx_len], rx_len);
}
static void write_status(uint8_t mode)
{
uint8_t buf[] = {
WRITE_STATUS_CMD, mode
};
write_bytes(buf, sizeof(buf));
}
static void read_status(uint8_t *mode)
{
uint8_t send[] = {
READ_STATUS_CMD
};
read_write_bytes(send, sizeof(send), mode, sizeof(*mode));
}
static void write_inst_addr(uint32_t inst, uint32_t addr)
{
uint8_t buf[] = {
inst,
(addr & 0x0000FF00) >> 0x08,
(addr & 0x000000FF) >> 0x00
};
write_bytes(buf, sizeof(buf));
}
void sram_drv_write_status(uint8_t mode)
{
xSemaphoreTake(sram_mutex, portMAX_DELAY);
nrf_gpio_pin_clear(CS_PIN);
write_status(mode | HOLD_DISABLE);
nrf_gpio_pin_set(CS_PIN);
xSemaphoreGive(sram_mutex);
}
void sram_drv_read_status(uint8_t *mode)
{
xSemaphoreTake(sram_mutex, portMAX_DELAY);
nrf_gpio_pin_clear(CS_PIN);
read_status(mode);
nrf_gpio_pin_set(CS_PIN);
xSemaphoreGive(sram_mutex);
}
int sram_drv_write(uint32_t addr, void *p_dest, uint32_t len)
{
xSemaphoreTake(sram_mutex, portMAX_DELAY);
nrf_gpio_pin_clear(CS_PIN);
write_inst_addr(WRITE_CMD, addr);
write_bytes(p_dest, len);
nrf_gpio_pin_set(CS_PIN);
xSemaphoreGive(sram_mutex);
return 0;
}
int sram_drv_read(uint32_t addr, void *p_dest, uint32_t len)
{
xSemaphoreTake(sram_mutex, portMAX_DELAY);
nrf_gpio_pin_clear(CS_PIN);
write_inst_addr(READ_CMD, addr);
read_bytes(p_dest, len);
nrf_gpio_pin_set(CS_PIN);
xSemaphoreGive(sram_mutex);
return 0;
}
static uint8_t dummy[32] = { 0 };
void sram_drv_reset(void)
{
sram_drv_write_status(SEQ_MODE);
memset(dummy, 0x00, COUNTOF(dummy));
for (int i = 0; i < SRAM_SIZE / COUNTOF(dummy); i++)
{
uint32_t addr = i * COUNTOF(dummy);
sram_drv_write(addr, dummy, sizeof(dummy));
}
}
void sram_drv_init(void)
{
txrx_end_sem = xSemaphoreCreateBinary();
sram_mutex = xSemaphoreCreateMutex();
// Config SPI mosi pin
nrf_gpio_cfg_output(MOSI_PIN);
nrf_gpio_pin_clear(MOSI_PIN);
// Config SPI miso pin
nrf_gpio_cfg_input(MISO_PIN, NRF_GPIO_PIN_PULLDOWN);
// Config SPI clk pin
nrf_gpio_cfg_output(SCLK_PIN);
nrf_gpio_pin_clear(SCLK_PIN);
// Config SPI cs pin
nrf_gpio_cfg_output(CS_PIN);
nrf_gpio_pin_set(CS_PIN);
// Config SPI module
nrf_spim_configure(SRAM_SPIM, NRF_SPIM_MODE_0, NRF_SPIM_BIT_ORDER_MSB_FIRST);
nrf_spim_frequency_set(SRAM_SPIM, NRF_SPIM_FREQ_16M);
nrf_spim_pins_set(SRAM_SPIM, SCLK_PIN, MOSI_PIN, MISO_PIN);
nrf_spim_orc_set(SRAM_SPIM, 0x00);
// Enable SPI module
nrf_spim_enable(SRAM_SPIM);
// Enable interrput (for easyDMA)
sd_nvic_SetPriority(SPIM3_IRQn, _PRIO_APP_MID);
sd_nvic_EnableIRQ(SPIM3_IRQn);
nrf_spim_int_enable(SRAM_SPIM, NRF_SPIM_INT_END_MASK);
}
void SPIM3_IRQHandler(void)
{
if (nrf_spim_int_enable_check(SRAM_SPIM, NRF_SPIM_INT_END_MASK))
{
nrf_spim_event_clear(SRAM_SPIM, NRF_SPIM_EVENT_END);
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(txrx_end_sem, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
+155
View File
@@ -0,0 +1,155 @@
/**
******************************************************************************
* @file syscalls.c
* @author Auto-generated by STM32CubeIDE
* @brief STM32CubeIDE Minimal System calls file
*
* For more information about which c-functions
* need which of these lowlevel functions
* please consult the Newlib libc-manual
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
char *__env[1] = { 0 };
char **environ = __env;
/* Functions */
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {} /* Make sure we hang here */
}
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}
int _close(int file)
{
return -1;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}
+18 -9
View File
@@ -21,11 +21,13 @@ extern "C"
#endif
#define HOST_UART (NRF_UARTE0)
#define HOST_uart_drv_tx_PIN 6
#define HOST_UART_RX_PIN 8
#define HOST_UART_DRV_TX_PIN NRF_GPIO_PIN_MAP(0, 4)
#define HOST_UART_DRV_RX_PIN NRF_GPIO_PIN_MAP(0, 27)
static SemaphoreHandle_t uart_drv_tx_sem;
static SemaphoreHandle_t uart_drv_rx_sem;
static SemaphoreHandle_t uart_drv_tx_mutex;
static SemaphoreHandle_t uart_drv_rx_mutex;
uint32_t uart_drv_rx(void *p_data, uint16_t len)
{
@@ -33,6 +35,7 @@ uint32_t uart_drv_rx(void *p_data, uint16_t len)
{
__BKPT(255);
}
xSemaphoreTake(uart_drv_rx_mutex, portMAX_DELAY);
nrf_uarte_rx_buffer_set(HOST_UART, p_data, len);
nrf_uarte_event_clear(HOST_UART, NRF_UARTE_EVENT_RXTO);
nrf_uarte_event_clear(HOST_UART, NRF_UARTE_EVENT_ENDRX);
@@ -44,7 +47,9 @@ uint32_t uart_drv_rx(void *p_data, uint16_t len)
} while (xSemaphoreTake(uart_drv_rx_sem, pdMS_TO_TICKS(3)));
nrf_uarte_task_trigger(HOST_UART, NRF_UARTE_TASK_STOPRX);
xSemaphoreTake(uart_drv_rx_sem, portMAX_DELAY);
return nrf_uarte_rx_amount_get(HOST_UART);
uint32_t recv_bytes = nrf_uarte_rx_amount_get(HOST_UART);
xSemaphoreGive(uart_drv_rx_mutex);
return recv_bytes;
}
void uart_drv_tx(void *p_data, uint16_t len)
@@ -53,22 +58,26 @@ void uart_drv_tx(void *p_data, uint16_t len)
{
__BKPT(255);
}
xSemaphoreTake(uart_drv_tx_mutex, portMAX_DELAY);
HOST_UART->TXD.PTR = (uint32_t)p_data;
HOST_UART->TXD.MAXCNT = len;
nrf_uarte_task_trigger(HOST_UART, NRF_UARTE_TASK_STARTTX);
xSemaphoreTake(uart_drv_tx_sem, portMAX_DELAY);
xSemaphoreGive(uart_drv_tx_mutex);
}
void uart_drv_init(void)
{
uart_drv_rx_sem = xSemaphoreCreateBinary();
uart_drv_tx_sem = xSemaphoreCreateBinary();
uart_drv_rx_sem = xSemaphoreCreateBinary();
uart_drv_tx_sem = xSemaphoreCreateBinary();
uart_drv_rx_mutex = xSemaphoreCreateMutex();
uart_drv_tx_mutex = xSemaphoreCreateMutex();
nrf_gpio_cfg_output(HOST_uart_drv_tx_PIN);
nrf_gpio_cfg_input(HOST_UART_RX_PIN, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_output(HOST_UART_DRV_TX_PIN);
nrf_gpio_cfg_input(HOST_UART_DRV_RX_PIN, NRF_GPIO_PIN_NOPULL);
nrf_uarte_configure(HOST_UART, NRF_UARTE_PARITY_EXCLUDED, NRF_UARTE_HWFC_DISABLED);
nrf_uarte_baudrate_set(HOST_UART, NRF_UARTE_BAUDRATE_57600);
nrf_uarte_txrx_pins_set(HOST_UART, HOST_uart_drv_tx_PIN, HOST_UART_RX_PIN);
nrf_uarte_baudrate_set(HOST_UART, NRF_UARTE_BAUDRATE_115200);
nrf_uarte_txrx_pins_set(HOST_UART, HOST_UART_DRV_TX_PIN, HOST_UART_DRV_RX_PIN);
nrf_uarte_hwfc_pins_disconnect(HOST_UART);
nrf_uarte_enable(HOST_UART);