1 /*
2    This example code is in the Public Domain (or CC0 licensed, at your option.)
3 
4    Unless required by applicable law or agreed to in writing, this
5    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6    CONDITIONS OF ANY KIND, either express or implied.
7 */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include "esp_hf_ag_api.h"
12 #include "app_hf_msg_set.h"
13 #include "bt_app_hf.h"
14 #include "esp_console.h"
15 #include "argtable3/argtable3.h"
16 #include "esp_log.h"
17 
18 // if you want to connect a specific device, add it's bda here
19 esp_bd_addr_t hf_peer_addr = {0xB0, 0xF1, 0xA3, 0x01, 0x2D,0x2E};
hf_msg_show_usage(void)20 void hf_msg_show_usage(void)
21 {
22     printf("########################################################################\n");
23     printf("HFP AG command usage manual\n");
24     printf("HFP AG commands begins with \"hf\" and end with \";\"\n");
25     printf("Supported commands are as follows, arguments are embraced with < and >\n\n");
26     printf("hf con;                   -- set up connection with peer device\n");
27     printf("hf dis;                   -- disconnection with peer device\n");
28     printf("hf cona;                  -- set up audio connection with peer device\n");
29     printf("hf disa;                  -- release audio connection with peer device\n");
30     printf("hf vron;                  -- start voice recognition\n");
31     printf("hf vroff;                 -- stop voice recognition\n");
32     printf("hf vu <tgt> <vol>;        -- volume update\n");
33     printf("     tgt: 0-speaker, 1-microphone\n");
34     printf("     vol: volume gain ranges from 0 to 15\n");
35     printf("hf ind <call> <ntk> <callsetup> <sig>;       -- unsolicited indication device status to HF Client\n");
36     printf("     call: call status [0,1]\n");
37     printf("     callsetup: call setup status [0,3]\n");
38     printf("     ntk: network status [0,1]\n");
39     printf("     sig: signal strength value from 0~5\n");
40     printf("hf ate <rep> <err>;       -- send extended at error code\n");
41     printf("     rep: response code from 0 to 7\n");
42     printf("     err: error code from 0 to 32\n");
43     printf("hf iron;                  -- in-band ring tone provided\n");
44     printf("hf iroff;                 -- in-band ring tone not provided\n");
45     printf("hf ac;                    -- Answer Incoming Call from AG\n");
46     printf("hf rc;                    -- Reject Incoming Call from AG\n");
47     printf("hf d <num>;               -- Dial Number by AG, e.g. hf d 11223344\n");
48     printf("hf end;                   -- End up a call by AG\n");
49     printf("hf h;                     -- to see the command for HFP AG\n");
50     printf("########################################################################\n");
51 }
52 
53 #define HF_CMD_HANDLER(cmd)    static int hf_##cmd##_handler(int argn, char **argv)
54 
HF_CMD_HANDLER(help)55 HF_CMD_HANDLER(help)
56 {
57     hf_msg_show_usage();
58     return 0;
59 }
60 
HF_CMD_HANDLER(conn)61 HF_CMD_HANDLER(conn)
62 {
63     printf("Connect.\n");
64     esp_bt_hf_connect(hf_peer_addr);
65     return 0;
66 }
67 
HF_CMD_HANDLER(disc)68 HF_CMD_HANDLER(disc)
69 {
70     printf("Disconnect\n");
71     esp_bt_hf_disconnect(hf_peer_addr);
72     return 0;
73 }
74 
HF_CMD_HANDLER(conn_audio)75 HF_CMD_HANDLER(conn_audio)
76 {
77     printf("Connect Audio\n");
78     esp_bt_hf_connect_audio(hf_peer_addr);
79     return 0;
80 }
81 
HF_CMD_HANDLER(disc_audio)82 HF_CMD_HANDLER(disc_audio)
83 {
84     printf("Disconnect Audio\n");
85     esp_bt_hf_disconnect_audio(hf_peer_addr);
86     return 0;
87 }
88 
89 //AT+BVRA
HF_CMD_HANDLER(vra_on)90 HF_CMD_HANDLER(vra_on)
91 {
92     printf("Start Voice Recognition.\n");
93     esp_bt_hf_vra(hf_peer_addr,1);
94     return 0;
95 }
96 //AT+BVRA
HF_CMD_HANDLER(vra_off)97 HF_CMD_HANDLER(vra_off)
98 {
99     printf("Stop Voicer Recognition.\n");
100     esp_bt_hf_vra(hf_peer_addr,0);
101     return 0;
102 }
103 
104 //AT+VGS or AT+VGM
HF_CMD_HANDLER(volume_control)105 HF_CMD_HANDLER(volume_control)
106 {
107     if (argn != 3) {
108         printf("Insufficient number of arguments");
109         return 1;
110     }
111     int target, volume;
112     if (sscanf(argv[1], "%d", &target) != 1 ||
113         (target != ESP_HF_VOLUME_CONTROL_TARGET_SPK &&
114         target != ESP_HF_VOLUME_CONTROL_TARGET_MIC)) {
115         printf("Invalid argument for target %s\n", argv[1]);
116         return 1;
117     }
118     if (sscanf(argv[2], "%d", &volume) != 1 ||
119             (volume < 0 || volume > 15)) {
120         printf("Invalid argument for volume %s\n", argv[2]);
121         return 1;
122     }
123     printf("Volume Update\n");
124     esp_bt_hf_volume_control(hf_peer_addr, target, volume);
125     return 0;
126 }
127 
128 //+CIEV
HF_CMD_HANDLER(ind_change)129 HF_CMD_HANDLER(ind_change)
130 {
131     if (argn != 5) {
132         printf("Insufficient number of arguments");
133         return 1;
134     }
135 
136     int call_state, ntk_state, call_setup_state, signal;
137 
138     if (sscanf(argv[1], "%d", &call_state) != 1 ||
139         (call_state != ESP_HF_CALL_STATUS_NO_CALLS &&
140         call_state != ESP_HF_CALL_STATUS_CALL_IN_PROGRESS)) {
141         printf("Invalid argument for call state %s\n", argv[1]);
142         return 1;
143     }
144     if (sscanf(argv[2], "%d", &call_setup_state) != 1 ||
145         (call_setup_state < ESP_HF_CALL_SETUP_STATUS_IDLE || call_setup_state > ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING)) {
146         printf("Invalid argument for callsetup state %s\n", argv[2]);
147         return 1;
148     }
149     if (sscanf(argv[3], "%d", &ntk_state) != 1 ||
150         (ntk_state != ESP_HF_NETWORK_STATE_NOT_AVAILABLE &&
151         ntk_state != ESP_HF_NETWORK_STATE_AVAILABLE)) {
152         printf("Invalid argument for netwrok state %s\n", argv[3]);
153         return 1;
154     }
155     if (sscanf(argv[4], "%d", &signal) != 1 ||
156             (signal < 0 || signal > 5)) {
157         printf("Invalid argument for signal %s\n", argv[4]);
158         return 1;
159     }
160     printf("Device Indicator Changed!\n");
161     esp_bt_hf_indchange_notification(hf_peer_addr, call_state, call_setup_state, ntk_state, signal);
162     return 0;
163 }
164 
165 //AT+CMEE
HF_CMD_HANDLER(cme_err)166 HF_CMD_HANDLER(cme_err)
167 {
168     if (argn != 3) {
169         printf("Insufficient number of arguments");
170         return 1;
171     }
172 
173     int response_code, error_code;
174     if (sscanf(argv[1], "%d", &response_code) != 1 ||
175         (response_code < ESP_HF_AT_RESPONSE_CODE_OK && response_code > ESP_HF_AT_RESPONSE_CODE_CME)) {
176         printf("Invalid argument for response_code %s\n", argv[1]);
177         return 1;
178     }
179 
180     if (sscanf(argv[2], "%d", &error_code) != 1 ||
181             (error_code < ESP_HF_CME_AG_FAILURE || error_code > ESP_HF_CME_NETWORK_NOT_ALLOWED)) {
182         printf("Invalid argument for volume %s\n", argv[2]);
183         return 1;
184     }
185 
186     printf("Send CME Error.\n");
187     esp_bt_hf_cmee_response(hf_peer_addr,response_code,error_code);
188     return 0;
189 }
190 
191 //+BSIR:1
HF_CMD_HANDLER(ir_on)192 HF_CMD_HANDLER(ir_on)
193 {
194     printf("Enable Voicer Recognition.\n");
195     esp_bt_hf_bsir(hf_peer_addr,1);
196     return 0;
197 }
198 
199 //+BSIR:0
HF_CMD_HANDLER(ir_off)200 HF_CMD_HANDLER(ir_off)
201 {
202     printf("Disable Voicer Recognition.\n");
203     esp_bt_hf_bsir(hf_peer_addr,0);
204     return 0;
205 }
206 
207 //Answer Call from AG
HF_CMD_HANDLER(ac)208 HF_CMD_HANDLER(ac)
209 {
210     printf("Answer Call from AG.\n");
211     char *number = {"123456"};
212     esp_bt_hf_answer_call(hf_peer_addr,1,0,1,1,number,0);
213     return 0;
214 }
215 
216 //Reject Call from AG
HF_CMD_HANDLER(rc)217 HF_CMD_HANDLER(rc)
218 {
219     printf("Reject Call from AG.\n");
220     char *number = {"123456"};
221     esp_bt_hf_reject_call(hf_peer_addr,0,0,0,0,number,0);
222     return 0;
223 }
224 
225 //End Call from AG
HF_CMD_HANDLER(end)226 HF_CMD_HANDLER(end)
227 {
228     printf("End Call from AG.\n");
229     char *number = {"123456"};
230     esp_bt_hf_end_call(hf_peer_addr,0,0,0,0,number,0);
231     return 0;
232 }
233 
234 //Dial Call from AG
HF_CMD_HANDLER(d)235 HF_CMD_HANDLER(d)
236 {
237     if (argn != 2) {
238         printf("Insufficient number of arguments");
239     } else {
240         printf("Dial number %s\n", argv[1]);
241         esp_bt_hf_out_call(hf_peer_addr,1,0,1,2,argv[1],0);
242     }
243     return 0;
244 }
245 
246 static hf_msg_hdl_t hf_cmd_tbl[] = {
247     {0,    "h",            hf_help_handler},
248     {5,    "con",          hf_conn_handler},
249     {10,   "dis",          hf_disc_handler},
250     {20,   "cona",         hf_conn_audio_handler},
251     {30,   "disa",         hf_disc_audio_handler},
252     {40,   "vu",           hf_volume_control_handler},
253     {50,   "ind",          hf_ind_change_handler},
254     {60,   "vron",         hf_vra_on_handler},
255     {70,   "vroff",        hf_vra_off_handler},
256     {80,   "ate",          hf_cme_err_handler},
257     {90,   "iron",         hf_ir_on_handler},
258     {100,  "iroff",        hf_ir_off_handler},
259     {110,  "ac",           hf_ac_handler},
260     {120,  "rc",           hf_rc_handler},
261     {130,  "end",          hf_end_handler},
262     {140,  "d",            hf_d_handler},
263 };
264 
hf_get_cmd_tbl(void)265 hf_msg_hdl_t *hf_get_cmd_tbl(void)
266 {
267     return hf_cmd_tbl;
268 }
269 
hf_get_cmd_tbl_size(void)270 size_t hf_get_cmd_tbl_size(void)
271 {
272     return sizeof(hf_cmd_tbl) / sizeof(hf_msg_hdl_t);
273 }
274 
275 #define HF_ORDER(name)   name##_cmd
276 enum hf_cmd_name {
277     h = 0,      /*show command manual*/
278     con,        /*set up connection with peer device*/
279     dis,        /*disconnection with peer device*/
280     cona,       /*set up audio connection with peer device*/
281     disa,       /*release connection with peer device*/
282     vu,         /*volume update*/
283     ind,        /*unsolicited indication device status to HF Client*/
284     vron,       /*start voice recognition*/
285     vroff,      /*stop voice recognition*/
286     ate,        /*send extended at error code*/
287     iron,       /*in-band ring tone provided*/
288     iroff,      /*in-band ring tone not provided*/
289     ac,         /*Answer Incoming Call from AG*/
290     rc,         /*Reject Incoming Call from AG*/
291     end,        /*End up a call by AG*/
292     d           /*Dial Number by AG, e.g. d 11223344*/
293 };
294 static char *hf_cmd_explain[] = {
295     "show command manual",
296     "set up connection with peer device",
297     "disconnection with peer device",
298     "set up audio connection with peer device",
299     "release connection with peer device",
300     "volume update",
301     "unsolicited indication device status to HF Client",
302     "start voice recognition",
303     "stop voice recognition",
304     "send extended at error code",
305     "in-band ring tone provided",
306     "in-band ring tone not provided",
307     "Answer Incoming Call from AG",
308     "Reject Incoming Call from AG",
309     "End up a call by AG",
310     "Dial Number by AG, e.g. d 11223344",
311 };
312 typedef struct {
313     struct arg_str *tgt;
314     struct arg_str *vol;
315     struct arg_end *end;
316 } vu_args_t;
317 
318 typedef struct {
319     struct arg_str *call;
320     struct arg_str *ntk;
321     struct arg_str *callsetup;
322     struct arg_str *sig;
323     struct arg_end *end;
324 } ind_args_t;
325 
326 typedef struct {
327     struct arg_str *rep;
328     struct arg_str *err;
329     struct arg_end *end;
330 } ate_args_t;
331 
332 static vu_args_t vu_args;
333 static ind_args_t ind_args;
334 static ate_args_t ate_args;
335 
register_hfp_ag(void)336 void register_hfp_ag(void)
337 {
338 
339         const esp_console_cmd_t HF_ORDER(con) = {
340             .command = "con",
341             .help = hf_cmd_explain[con],
342             .hint = NULL,
343             .func = hf_cmd_tbl[con].handler,
344         };
345         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(con)));
346 
347         const esp_console_cmd_t HF_ORDER(dis) = {
348             .command = "dis",
349             .help = hf_cmd_explain[dis],
350             .hint = NULL,
351             .func = hf_cmd_tbl[dis].handler,
352         };
353         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(dis)));
354 
355         const esp_console_cmd_t HF_ORDER(cona) = {
356             .command = "cona",
357             .help = hf_cmd_explain[cona],
358             .hint = NULL,
359             .func = hf_cmd_tbl[cona].handler,
360         };
361         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(cona)));
362 
363         const esp_console_cmd_t HF_ORDER(disa) = {
364             .command = "disa",
365             .help = hf_cmd_explain[disa],
366             .hint = NULL,
367             .func = hf_cmd_tbl[disa].handler,
368         };
369         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(disa)));
370 
371 
372 
373         const esp_console_cmd_t HF_ORDER(ac) = {
374             .command = "ac",
375             .help = hf_cmd_explain[ac],
376             .hint = NULL,
377             .func = hf_cmd_tbl[ac].handler,
378         };
379         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(ac)));
380 
381         const esp_console_cmd_t HF_ORDER(rc) = {
382             .command = "rc",
383             .help = hf_cmd_explain[rc],
384             .hint = NULL,
385             .func = hf_cmd_tbl[rc].handler,
386         };
387         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(rc)));
388 
389         const esp_console_cmd_t HF_ORDER(d) = {
390             .command = "d",
391             .help = hf_cmd_explain[d],
392             .hint = "<num>",
393             .func = hf_cmd_tbl[d].handler,
394         };
395         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(d)));
396 
397 
398 
399         const esp_console_cmd_t HF_ORDER(vron) = {
400             .command = "vron",
401             .help = hf_cmd_explain[vron],
402             .hint = NULL,
403             .func = hf_cmd_tbl[vron].handler,
404         };
405         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(vron)));
406 
407         const esp_console_cmd_t HF_ORDER(vroff) = {
408             .command = "vroff",
409             .help = hf_cmd_explain[vroff],
410             .hint = NULL,
411             .func = hf_cmd_tbl[vroff].handler,
412         };
413         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(vroff)));
414 
415         vu_args.tgt = arg_str1(NULL, NULL, "<tgt>", "\n        0-speaker\n        1-microphone");
416         vu_args.vol = arg_str1(NULL, NULL, "<vol>", "volume gain ranges from 0 to 15");
417         vu_args.end = arg_end(1);
418         const esp_console_cmd_t HF_ORDER(vu) = {
419             .command = "vu",
420             .help = hf_cmd_explain[vu],
421             .hint = NULL,
422             .func = hf_cmd_tbl[vu].handler,
423             .argtable = &vu_args
424         };
425         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(vu)));
426 
427         const esp_console_cmd_t HF_ORDER(end) = {
428             .command = "end",
429             .help = hf_cmd_explain[end],
430             .hint = NULL,
431             .func = hf_cmd_tbl[end].handler,
432         };
433         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(end)));
434 
435         const esp_console_cmd_t HF_ORDER(iron) = {
436             .command = "iron",
437             .help = hf_cmd_explain[iron],
438             .hint = NULL,
439             .func = hf_cmd_tbl[iron].handler,
440         };
441         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(iron)));
442 
443         const esp_console_cmd_t HF_ORDER(iroff) = {
444             .command = "iroff",
445             .help = hf_cmd_explain[iroff],
446             .hint = NULL,
447             .func = hf_cmd_tbl[iroff].handler,
448         };
449         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(iroff)));
450 
451         ind_args.call = arg_str1(NULL, NULL, "<call>", "call status [0,1]");
452         ind_args.callsetup = arg_str1(NULL, NULL, "<callsetup>", "call setup status [0,3]");
453         ind_args.ntk = arg_str1(NULL, NULL, "<ntk>", "network status [0,1]");
454         ind_args.sig = arg_str1(NULL, NULL, "<sig>", "signal strength value from 0~5");
455         ind_args.end = arg_end(1);
456         const esp_console_cmd_t HF_ORDER(ind) = {
457             .command = "ind",
458             .help = hf_cmd_explain[ind],
459             .hint = NULL,
460             .func = hf_cmd_tbl[ind].handler,
461             .argtable = &ind_args
462         };
463         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(ind)));
464 
465         ate_args.err = arg_str1(NULL, NULL, "<err>", "error code from 0 to 32");
466         ate_args.rep = arg_str1(NULL, NULL, "<rep>", "response code from 0 to 7");
467         ate_args.end = arg_end(1);
468         const esp_console_cmd_t HF_ORDER(ate) = {
469             .command = "ate",
470             .help = hf_cmd_explain[ate],
471             .hint = NULL,
472             .func = hf_cmd_tbl[ate].handler,
473             .argtable = &ate_args
474         };
475         ESP_ERROR_CHECK(esp_console_cmd_register(&HF_ORDER(ate)));
476 }
477