#include #include #include #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; ieType); 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); }