MXC-A36-Demo/MCU/examples/application/btdm_audio/Src/app_at.c

702 lines
25 KiB
C
Raw Permalink Normal View History

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "fr30xx.h"
#include "co_util.h"
#include "bt_types.h"
#include "me_api.h"
#include "hfg_api.h"
#include "gatt_api.h"
#include "app_at.h"
#include "app_task.h"
#include "app_ble.h"
#include "app_bt.h"
#include "app_audio.h"
#include "btdm_mem.h"
#include "fdb_app.h"
#include "user_bt.h"
#include "dsp_mem.h"
#include "heap.h"
#define AT_RECV_MAX_LEN 32
static uint8_t app_at_recv_char;
static uint8_t at_recv_buffer[AT_RECV_MAX_LEN];
static uint8_t at_recv_index = 0;
static uint8_t at_recv_state = 0;
void btdm_host_send_vendor_cmd(uint8_t type, uint8_t length, void *data);
void btdm_host_vendor_cmd_cmp_evt(uint8_t status, uint8_t len, uint8_t const *param)
{
printf("status: 0x%02x.\r\n", status);
for (uint32_t i=0; i<len; i++) {
printf("%02x ", param[i]);
}
printf("\r\n");
}
static void app_at_recv_cmd_A(uint8_t sub_cmd, uint8_t *data)
{
switch(sub_cmd)
{
// case 'A':
// {
// mac_addr_t addr;
// addr.addr[5] = ascii_strn2val((const char *)&data[0], 16, 2);
// addr.addr[4] = ascii_strn2val((const char *)&data[2], 16, 2);
// addr.addr[3] = ascii_strn2val((const char *)&data[4], 16, 2);
// addr.addr[2] = ascii_strn2val((const char *)&data[6], 16, 2);
// addr.addr[1] = ascii_strn2val((const char *)&data[8], 16, 2);
// addr.addr[0] = ascii_strn2val((const char *)&data[10], 16, 2);
// gap_start_conn(&addr, ascii_strn2val((const char *)&data[12], 16, 2), 64, 64, 0, 500);
// }
// break;
// case 'B':
// {
// gap_stop_conn();
// }
// break;
case 'A':
{
uint8_t addr = ascii_strn2val((const char *)&data[0], 16, 2);
btdm_host_send_vendor_cmd(0x00, 1, &addr);
}
printf("OK\r\n");
break;
case 'B':
{
uint8_t buffer[2];
buffer[0] = ascii_strn2val((const char *)&data[0], 16, 2);
buffer[1] = ascii_strn2val((const char *)&data[3], 16, 2);
btdm_host_send_vendor_cmd(0x01, 2, (void *)&buffer[0]);
}
printf("OK\r\n");
break;
case 'C':
{
uint32_t addr = ascii_strn2val((const char *)&data[0], 16, 8);
btdm_host_send_vendor_cmd(0x02, 4, (void *)&addr);
}
printf("OK\r\n");
break;
case 'D':
{
uint32_t buffer[2];
buffer[0] = ascii_strn2val((const char *)&data[0], 16, 8);
buffer[1] = ascii_strn2val((const char *)&data[9], 16, 8);
btdm_host_send_vendor_cmd(0x03, 8, (void *)&buffer[0]);
}
printf("OK\r\n");
break;
case 'G':
printf("hello world!\r\n");
break;
case 'H':
printf("VAL: 0x%08x.\r\n", *(volatile uint32_t *)ascii_strn2val((const char *)&data[0], 16, 8));
break;
case 'I':
*(volatile uint32_t *)ascii_strn2val((const char *)&data[0], 16, 8) = ascii_strn2val((const char *)&data[9], 16, 8);
printf("OK\r\n");
break;
case 'J':
printf("OOL VAL: 0x%02x.\r\n", ool_read(ascii_strn2val((const char *)&data[0], 16, 2)));
break;
case 'K':
ool_write(ascii_strn2val((const char *)&data[0], 16, 2), ascii_strn2val((const char *)&data[3], 16, 2));
printf("OK\r\n");
break;
case 'L':
printf("VAL: 0x%02x.\r\n", *(volatile uint8_t *)(ascii_strn2val((const char *)&data[0], 16, 8)));
break;
case 'M':
*(volatile uint8_t *)(ascii_strn2val((const char *)&data[0], 16, 8)) = ascii_strn2val((const char *)&data[9], 16, 2);
printf("OK\r\n");
break;
// case 'P':
// co_printf("VAL: 0x%02x.\r\n", *(uint8_t *)(MODEM_BASE + ascii_strn2val((const char *)&data[0], 16, 2)));
// break;
// case 'Q':
// *(uint8_t *)(MODEM_BASE + ascii_strn2val((const char *)&data[0], 16, 2)) = ascii_strn2val((const char *)&data[3], 16, 2);
// co_printf("OK\r\n");
// break;
// case 'S':
// co_printf("VAL: 0x%02x.\r\n", frspim_rd(FR_SPI_RF_COB_CHAN, ascii_strn2val((const char *)&data[0], 16, 2), 1));
// break;
// case 'T':
// frspim_wr(FR_SPI_RF_COB_CHAN, ascii_strn2val((const char *)&data[0], 16, 2), 1, ascii_strn2val((const char *)&data[3], 16, 2));
// co_printf("OK\r\n");
// break;
case 'U':
{
uint32_t *ptr = (uint32_t *)(ascii_strn2val((const char *)&data[0], 16, 8) & (~3));
uint8_t count = ascii_strn2val((const char *)&data[9], 16, 2);
uint32_t *start = (uint32_t *)((uint32_t)ptr & (~0x0f));
for(uint8_t i=0; i<count;) {
if(((uint32_t)start & 0x0c) == 0) {
printf("0x%08x: ", (uint32_t)start);
}
if(start < ptr) {
printf(" ");
}
else {
i++;
printf("%08x", *start);
}
if(((uint32_t)start & 0x0c) == 0x0c) {
printf("\r\n");
}
else {
printf(" ");
}
start++;
}
}
break;
case 'V':
flash_erase(QSPI0, ascii_strn2val((const char *)&data[0], 16, 8), ascii_strn2val((const char *)&data[9], 16, 8));
break;
case 'W':
{
uint32_t curr_free, min_free;
dsp_mem_get_usage(&curr_free, &min_free);
printf("DSP MEM: %d, %d\r\n", curr_free, min_free);
}
break;
case 'X':
{
void system_reset(void);
system_reset();
}
break;
case 'Y':
heap_dump_used_mem(ascii_strn2val((const char *)&data[0], 16, 2));
break;
case 'Z':
printf("MEM usage\r\n \
\tHEAP_TYPE_SRAM_BLOCK: %d, %d\r\n \
\tHEAP_TYPE_DRAM_BLOCK: %d, %d\r\n \
\tHEAP_TYPE_BTDM_BLOCK: %d, %d\r\n \
\tTOTAL USAGE: %d\r\n", \
heap_get_mem_usage(HEAP_TYPE_SRAM_BLOCK), heap_get_mem_usage_single(HEAP_TYPE_SRAM_BLOCK), \
heap_get_mem_usage(HEAP_TYPE_DRAM_BLOCK), heap_get_mem_usage_single(HEAP_TYPE_DRAM_BLOCK), \
heap_get_mem_usage(HEAP_TYPE_BTDM_BLOCK), heap_get_mem_usage_single(HEAP_TYPE_BTDM_BLOCK), \
heap_get_max_mem_usage());
break;
default:
break;
}
}
static void user_hci_callback(const BtEvent *event)
{
printf("event type = %d\r\n",event->eType);
if(event->eType == BTEVENT_COMMAND_COMPLETE){
btdm_free(event->p.meToken);
}
}
static void app_at_recv_cmd_B(uint8_t sub_cmd, uint8_t *data)
{
struct gap_ble_addr peer_addr;
BD_ADDR addr;
HfgResponse *rsp;
BtStatus status;
MeCommandToken *token;
uint16_t page_timeout = 0x400;
switch(sub_cmd) {
case 'A':
// AT#BA00
//app_ble_start_advertising(ascii_strn2val((const char *)&data[0], 16, 2));
break;
case 'B':
// AT#BB01
//app_ble_stop_advertising(ascii_strn2val((const char *)&data[0], 16, 2));
break;
case 'C':
app_ble_scan_start();
break;
case 'D':
app_ble_scan_stop();
break;
case 'E':
// AT#BE0123456789ab_01
peer_addr.addr.addr[5] = ascii_strn2val((const char *)&data[0], 16, 2);
peer_addr.addr.addr[4] = ascii_strn2val((const char *)&data[2], 16, 2);
peer_addr.addr.addr[3] = ascii_strn2val((const char *)&data[4], 16, 2);
peer_addr.addr.addr[2] = ascii_strn2val((const char *)&data[6], 16, 2);
peer_addr.addr.addr[1] = ascii_strn2val((const char *)&data[8], 16, 2);
peer_addr.addr.addr[0] = ascii_strn2val((const char *)&data[10], 16, 2);
peer_addr.addr_type = ascii_strn2val((const char *)&data[13], 16, 2);
app_ble_conn_start(&peer_addr);
break;
case 'F':
app_ble_conn_stop();
break;
#if BTDM_STACK_ENABLE_BT == 1
case 'H':
ME_Inquiry(BT_IAC_GIAC, 5, 5);
break;
case 'I':
ME_CancelInquiry();
break;
case 'J':
{
BtStatus status;
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
status = HFG_CreateServiceLink(&hfg_channel[0], &addr);
if (status == BT_STATUS_PENDING) {
printf("Opening Channel...\r\n");
} else {
printf("Could not open channel, status: %d\r\n", status);
}
}
break;
case 'K':
status = BT_STATUS_NO_RESOURCES;
rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse));
if(rsp != NULL){
status = HFG_CreateCodecConnection(&hfg_channel[0], 1, rsp);
}
if(status != BT_STATUS_PENDING){
btdm_free((void *)rsp);
}
printf("status = %d\r\n",status);
break;
case 'L':
flashdb_del(FDB_KEY_BT_LINKKEY);
break;
case 'M':
token = btdm_malloc(sizeof(MeCommandToken));
token->p.general.in.hciCommand = 0x0c18;//HCC_WRITE_PAGE_TIMEOUT;
token->p.general.in.parmLen = 2;
token->p.general.in.parms = (uint8_t *)&page_timeout;
token->callback = user_hci_callback; //token is freed at this callback
status = ME_SendHciCommandAsync(token);
printf("status = %d\r\n",status);
break;
case 'N':
{
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
user_bt_env.connect_times = 3;
status = bt_connect(&addr);
printf("status = %d\r\n",status);
}
break;
#endif
case 'O':
// {
// uint8_t battery_level[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
// struct gatt_send_event ntf[6];
// uint8_t i=0;
// for(i=0;i<6;i++){
// ntf[i].conidx = 0;
// ntf[i].svc_id = svc_id;
// ntf[i].att_idx = 2;
// ntf[i].data_len = 15;
// ntf[i].p_data = &battery_level[0];
// gatt_notification(&ntf[i]);
// }
// }
break;
case 'P':
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
bt_disconnect(&addr,false);
break;
case 'Q':
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
bt_disconnect(&addr,true);
break;
case 'R':
// ME_SetLocalDeviceName((const uint8_t *)"FR30xx_m", sizeof("FR30xx_m"));
//app_btdm_init();
break;
case 'S':
{
BtAccessModeInfo access_mode_nc = {
.inqInterval = 0x800,
.inqWindow = 0x12,
.pageInterval = 0x800,
.pageWindow = 0x12,
};
status = bt_enter_pairing(BAM_GENERAL_ACCESSIBLE, &access_mode_nc);
printf("status = %d\r\n",status);
}
break;
case 'T':
{
status = bt_exit_pairing();
printf("status = %d\r\n",status);
}
break;
case 'U':
{
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
bt_exit_pairing();
bt_connect(&addr);
}
break;
}
printf("OK\r\n");
}
uint8_t voltage_str[] = "AT+IPHONEACCEV=1,1,6";
uint8_t cmps_str[] = "AT+CPMS=?";
uint8_t clk_str[] = "AT+CCLK=?";
//bt hf&pbap related cmd
static void app_at_recv_cmd_C(uint8_t sub_cmd, uint8_t *data)
{
BtStatus status;
BD_ADDR addr;
switch(sub_cmd) {
case 'A':
status = bt_answer_call(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
break;
case 'B':
status = bt_hang_up(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
break;
case 'C':
status = bt_redial(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
break;
case 'D':
{
uint8_t number[] = "10086";
status = bt_dial_number(user_bt_env.last_active_index,number,sizeof(number));
printf("status = %d\r\n",status);
}
break;
case 'E':
status = bt_list_current_calls(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
break;
case 'F':
status = bt_transfer_sco(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
break;
case 'G':
{
uint8_t dtmf = data[0];
status = bt_send_dtmf(user_bt_env.last_active_index,dtmf);
printf("status = %d\r\n",status);
}
break;
case 'H':
{
//vol---[0x00,0x0f]
uint8_t vol = ascii_strn2val((const char*)&data[0],16,2);
status = bt_report_spk_volume(user_bt_env.last_active_index,vol);
printf("status = %d\r\n",status);
}
break;
case 'I':
{
status = bt_send_hf_cmd(user_bt_env.last_active_index,voltage_str);
printf("status = %d\r\n",status);
}
break;
case 'J':
{
uint8_t enabled = ascii_strn2val((const char*)&data[0],16,2);
status = bt_enable_voice_recognition(user_bt_env.last_active_index, enabled);
printf("status = %d\r\n",status);
}
break;
case 'K':
printf("voice recog enabled : %d\r\n",bt_is_voice_rec_active(user_bt_env.last_active_index));
break;
case 'L':
// addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
// addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
// addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
// addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
// addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
// addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
if(user_bt_get_state(user_bt_env.last_active_index) >= BT_STATE_CONNECTED){
printf("pbap client %d\r\n",pbap_client[user_bt_env.last_active_index].cApp.connState);
status = PBAP_ClientConnect(&pbap_client[user_bt_env.last_active_index],&user_bt_env.dev[user_bt_env.last_active_index].remote_bd);
if(status == BT_STATUS_PENDING){
user_bt_env.dev[user_bt_env.last_active_index].pbap_client = &pbap_client[user_bt_env.last_active_index];
}
}
printf("status = %d\r\n",status);
break;
case 'M':
status = PBAP_ClientDisconnect(&pbap_client[user_bt_env.last_active_index]);
printf("status = %d\r\n",status);
break;
case 'N':
{
uint8_t pbName[64];
PbapPullPbParms parms;
memcpy(pbName,PB_LOCAL_MCH_NAME,sizeof(PB_LOCAL_MCH_NAME));
parms.pbName = pbName;
memset(parms.filter.byte,0,PBAP_FILTER_SIZE);
parms.filter.byte[0] = 0x84;
parms.listStartOffset = 0;
parms.maxListCount = 4; //0---search missed call and total pb size
parms.format= VCARD_FORMAT_30;
status = PBAP_PullPhonebook(&pbap_client[0], &parms);
printf("status = %d\r\n",status);
}
break;
case 'O':
{
PbapPullVcardListingParms parms;
uint8_t search_val[12]; //= "13262651013";
memcpy(search_val,&data[0],11);
uint8_t folder[] = "telecom/pb";
parms.folderName = folder;
parms.order = VCARD_SORT_ORDER_INDEXED;
parms.listStartOffset = 0x00;
parms.maxListCount = 4;
parms.searchAttribute = VCARD_SEARCH_ATTRIB_NUMBER;
parms.searchValue = search_val;
status = PBAP_PullVcardListing(&pbap_client[0], &parms);
printf("status = %d\r\n",status);
}
break;
case 'P':
{
uint8_t pbName[64];
PbapPullPbParms parms;
memcpy(pbName,PB_LOCAL_STORE_NAME,sizeof(PB_LOCAL_STORE_NAME));
parms.pbName = pbName;
memset(parms.filter.byte,0,PBAP_FILTER_SIZE);
parms.filter.byte[0] = 0x07;//0x84;
parms.listStartOffset = 0;
parms.maxListCount = 20; //0---search missed call and total pb size
parms.format= VCARD_FORMAT_30;
status = PBAP_PullPhonebook(&pbap_client[0], &parms);
printf("status = %d\r\n",status);
}
break;
case 'X':
{
uint8_t mute_str[] = "AT+CMUT=1";
status = bt_send_hf_cmd(user_bt_env.last_active_index,mute_str);
printf("status = %d\r\n",status);
}
break;
case 'Y':
{
status = bt_send_hf_cmd(user_bt_env.last_active_index,clk_str);
printf("status = %d\r\n",status);
}
case 'Z':
{
uint8_t mute_str[] = "AT+CCLK?";
status = bt_send_hf_cmd(user_bt_env.last_active_index,mute_str);
printf("status = %d\r\n",status);
}
break;
default:
break;
}
printf("OK\r\n");
}
///bt media related cmd
static void app_at_recv_cmd_E(uint8_t sub_cmd, uint8_t *data)
{
BD_ADDR addr;
BtStatus status;
switch(sub_cmd) {
case 'A':
status = AVRCP_SetPanelKey(user_bt_env.dev[user_bt_env.last_active_index].rcp_chan, AVRCP_POP_PLAY, TRUE);
printf("status = %d\r\n",status);
break;
case 'B':
status = AVRCP_SetPanelKey(user_bt_env.dev[user_bt_env.last_active_index].rcp_chan, AVRCP_POP_PAUSE, TRUE);
printf("status = %d\r\n",status);
break;
case 'C':
status = AVRCP_SetPanelKey(user_bt_env.dev[user_bt_env.last_active_index].rcp_chan, AVRCP_POP_FORWARD, TRUE);
printf("status = %d\r\n",status);
break;
case 'D':
{
status = AVRCP_SetPanelKey(user_bt_env.dev[user_bt_env.last_active_index].rcp_chan, AVRCP_POP_BACKWARD, TRUE);
printf("status = %d\r\n",status);
}
break;
case 'E':
{
uint8_t vol = ascii_strn2val((const char*)&data[0],16,2);
status = bt_set_media_volume(user_bt_env.last_active_index,vol);
printf("status = %d\r\n",status);
}
break;
case 'F':
{
status = bt_get_media_info(user_bt_env.last_active_index,0x41);
printf("status = %d\r\n",status);
}
break;
case 'G':
{
status = bt_get_playstatus(user_bt_env.last_active_index);
printf("status = %d\r\n",status);
}
break;
case 'H':
addr.A[0] = ascii_strn2val((const char*)&data[0],16,2);
addr.A[1] = ascii_strn2val((const char*)&data[2],16,2);
addr.A[2] = ascii_strn2val((const char*)&data[4],16,2);
addr.A[3] = ascii_strn2val((const char*)&data[6],16,2);
addr.A[4] = ascii_strn2val((const char*)&data[8],16,2);
addr.A[5] = ascii_strn2val((const char*)&data[10],16,2);
status = spp_connect(&spp_dev[0],&addr);
printf("status = %d\r\n",status);
break;
case 'I':
status = spp_disconnect(&spp_dev[0]);
printf("status = %d\r\n",status);
break;
case 'J':
{
uint8_t test_data[] = {'1','2','3','4'};
status = spp_send(&spp_dev[0],test_data,sizeof(test_data));
printf("status = %d\r\n",status);
}
break;
default:
break;
}
printf("OK\r\n");
}
static void app_at_recv_cmd_D(uint8_t sub_cmd, uint8_t *data)
{
switch(sub_cmd) {
case 'A':
flash_erase(QSPI0, ascii_strn2val((const char*)&data[0],16,8), 0x1000);
break;
default:
break;
}
printf("OK\r\n");
}
void app_at_cmd_recv_handler(uint8_t *data, uint16_t length)
{
switch(data[0])
{
case 'A':
app_at_recv_cmd_A(data[1], &data[2]);
break;
case 'B':
app_at_recv_cmd_B(data[1], &data[2]);
break;
case 'C':
app_at_recv_cmd_C(data[1], &data[2]);
break;
case 'D':
app_at_recv_cmd_D(data[1], &data[2]);
break;
case 'E':
app_at_recv_cmd_E(data[1], &data[2]);
break;
default:
break;
}
}
static void app_at_recv_c(uint8_t c)
{
switch(at_recv_state)
{
case 0:
if(c == 'A')
{
at_recv_state++;
}
break;
case 1:
if(c == 'T')
at_recv_state++;
else
at_recv_state = 0;
break;
case 2:
if(c == '#')
at_recv_state++;
else
at_recv_state = 0;
break;
case 3:
at_recv_buffer[at_recv_index++] = c;
if((c == '\n')
||(at_recv_index >= AT_RECV_MAX_LEN))
{
struct app_task_event *event;
event = app_task_event_alloc(APP_TASK_EVENT_AT_CMD, at_recv_index, false);
if(event) {
memcpy(event->param, at_recv_buffer, at_recv_index);
app_task_event_post(event, false);
}
at_recv_state = 0;
at_recv_index = 0;
}
break;
}
}
void app_at_rx_done(struct __UART_HandleTypeDef *handle)
{
app_at_recv_c(app_at_recv_char);
if (handle) {
uart_receive_IT(handle, &app_at_recv_char, 1);
}
}
void app_at_init(struct __UART_HandleTypeDef *handle)
{
uart_receive_IT(handle, &app_at_recv_char, 1);
}