430 lines
11 KiB
C
430 lines
11 KiB
C
#include <string.h>
|
|
|
|
#ifdef __cplusplus
|
|
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"
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "message_buffer.h"
|
|
#include "semphr.h"
|
|
#include "task.h"
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
extern uint32_t uart_drv_rx(void *, uint32_t);
|
|
extern uint32_t uart_drv_tx(void *, uint32_t);
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
} ins_survive_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
} ins_scan_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
uint8_t addr_type;
|
|
uint8_t addr[6];
|
|
} ins_connect_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
} ins_disconnect_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
uint8_t handle;
|
|
uint8_t write_data[255];
|
|
} ins_write_char_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint8_t opcode;
|
|
uint8_t len;
|
|
uint8_t handle;
|
|
} ins_read_char_t;
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
uint8_t opcode;
|
|
union
|
|
{
|
|
uint8_t len;
|
|
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;
|
|
|
|
#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
|
|
|
|
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 INST_SUFFIX 0xF1
|
|
|
|
static MessageBufferHandle_t host_cmd_msg;
|
|
|
|
static void success_ack(void)
|
|
{
|
|
uint8_t ack[] = { 0x04, 0x00, 0x01, 0x03 };
|
|
uart_drv_tx(ack, sizeof(ack));
|
|
}
|
|
|
|
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: %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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
for (;;)
|
|
{
|
|
static uint8_t buf[256] = { 0 };
|
|
host_ins_t *p_ins = (void *)buf;
|
|
|
|
p_ins->raw.opcode = INS_IDLE;
|
|
p_ins->raw.len = 0;
|
|
|
|
size_t recv = xMessageBufferReceive(host_cmd_msg, buf, sizeof(buf), portMAX_DELAY);
|
|
|
|
switch (p_ins->raw.opcode)
|
|
{
|
|
case INS_SCAN:
|
|
on_ins_scan(&p_ins->scan);
|
|
break;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void host_cmd_recv_task(void *p_arg)
|
|
{
|
|
for (;;)
|
|
{
|
|
static uint8_t buf[256];
|
|
|
|
uint32_t recv = uart_drv_rx(buf, sizeof(buf));
|
|
uint32_t offset = 0;
|
|
|
|
while (offset < recv)
|
|
{
|
|
host_ins_t *p_ins = (void *)&buf[offset];
|
|
|
|
taskENTER_CRITICAL();
|
|
|
|
if (p_ins->raw.payload[p_ins->raw.len] == INST_SUFFIX)
|
|
{
|
|
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, 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);
|
|
}
|