hfp.c (5ebff8020d95919f5a4fa00a07ae0d456deae24b) hfp.c (471dea41ab395d4c7fcbf32edf8a18b239742ccb)
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 80 unchanged lines hidden (view full) ---

89
90static hfp_sdp_query_context_t hfp_sdp_query_context;
91static btstack_context_callback_registration_t hfp_sdp_query_request;
92
93
94
95
96
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 80 unchanged lines hidden (view full) ---

89
90static hfp_sdp_query_context_t hfp_sdp_query_context;
91static btstack_context_callback_registration_t hfp_sdp_query_request;
92
93
94
95
96
97// custom commands
98static btstack_linked_list_t hfp_custom_commands_ag;
97
98// prototypes
99static hfp_link_settings_t hfp_next_link_setting_for_connection(hfp_link_settings_t current_setting, hfp_connection_t * hfp_connection, uint8_t eSCO_S4_supported);
100static void parse_sequence(hfp_connection_t * context);
101
102static const char * hfp_hf_features[] = {
103 "EC and/or NR function",
104 "Three-way calling",

--- 1036 unchanged lines hidden (view full) ---

1141 { "+VGS:", HFP_CMD_SET_SPEAKER_GAIN},
1142 { "+VGS=", HFP_CMD_SET_SPEAKER_GAIN},
1143 { "ERROR", HFP_CMD_ERROR},
1144 { "NOP", HFP_CMD_NONE}, // dummy command used by unit tests
1145 { "OK", HFP_CMD_OK },
1146 { "RING", HFP_CMD_RING },
1147};
1148
99
100// prototypes
101static hfp_link_settings_t hfp_next_link_setting_for_connection(hfp_link_settings_t current_setting, hfp_connection_t * hfp_connection, uint8_t eSCO_S4_supported);
102static void parse_sequence(hfp_connection_t * context);
103
104static const char * hfp_hf_features[] = {
105 "EC and/or NR function",
106 "Three-way calling",

--- 1036 unchanged lines hidden (view full) ---

1143 { "+VGS:", HFP_CMD_SET_SPEAKER_GAIN},
1144 { "+VGS=", HFP_CMD_SET_SPEAKER_GAIN},
1145 { "ERROR", HFP_CMD_ERROR},
1146 { "NOP", HFP_CMD_NONE}, // dummy command used by unit tests
1147 { "OK", HFP_CMD_OK },
1148 { "RING", HFP_CMD_RING },
1149};
1150
1151static const hfp_custom_at_command_t * hfp_custom_command_lookup(const char * text){
1152 btstack_linked_list_iterator_t it;
1153 btstack_linked_list_iterator_init(&it, &hfp_custom_commands_ag);
1154 while (btstack_linked_list_iterator_has_next(&it)) {
1155 hfp_custom_at_command_t *at_command = (hfp_custom_at_command_t *) btstack_linked_list_iterator_next(&it);
1156 int match = strcmp(text, at_command->command);
1157 if (match == 0) {
1158 return at_command;
1159 }
1160 }
1161 return NULL;
1162}
1163
1149static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
1150
1151 // table lookup based on role
1152 uint16_t num_entries;
1153 hfp_command_entry_t * table;
1154 if (isHandsFree == 0){
1155 table = hfp_ag_commmand_table;
1156 num_entries = sizeof(hfp_ag_commmand_table) / sizeof(hfp_command_entry_t);

--- 22 unchanged lines hidden (view full) ---

1179
1180 // note: if parser in CMD_HEADER state would treats digits and maybe '+' as separator, match on "ATD" would work.
1181 // note: phone number is currently expected in line_buffer[3..]
1182 // prefix match on 'ATD', AG only
1183 if ((isHandsFree == 0) && (strncmp(line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0)){
1184 return HFP_CMD_CALL_PHONE_NUMBER;
1185 }
1186
1164static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
1165
1166 // table lookup based on role
1167 uint16_t num_entries;
1168 hfp_command_entry_t * table;
1169 if (isHandsFree == 0){
1170 table = hfp_ag_commmand_table;
1171 num_entries = sizeof(hfp_ag_commmand_table) / sizeof(hfp_command_entry_t);

--- 22 unchanged lines hidden (view full) ---

1194
1195 // note: if parser in CMD_HEADER state would treats digits and maybe '+' as separator, match on "ATD" would work.
1196 // note: phone number is currently expected in line_buffer[3..]
1197 // prefix match on 'ATD', AG only
1198 if ((isHandsFree == 0) && (strncmp(line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0)){
1199 return HFP_CMD_CALL_PHONE_NUMBER;
1200 }
1201
1202 // check for custom commands, AG only
1203 if (isHandsFree == 0) {
1204 const hfp_custom_at_command_t * custom_at_command = hfp_custom_command_lookup(line_buffer);
1205 if (custom_at_command != NULL){
1206 return HFP_CMD_CUSTOM_MESSAGE;
1207 }
1208 }
1209
1187 // Valid looking, but unknown commands/responses
1188 if ((isHandsFree == 0) && (strncmp(line_buffer, "AT+", 3) == 0)){
1189 return HFP_CMD_UNKNOWN;
1190 }
1191
1192 if ((isHandsFree != 0) && (strncmp(line_buffer, "+", 1) == 0)){
1193 return HFP_CMD_UNKNOWN;
1194 }

--- 9 unchanged lines hidden (view full) ---

1204static int hfp_parser_is_buffer_empty(hfp_connection_t * hfp_connection){
1205 return hfp_connection->line_size == 0;
1206}
1207
1208static int hfp_parser_is_end_of_line(uint8_t byte){
1209 return (byte == '\n') || (byte == '\r');
1210}
1211
1210 // Valid looking, but unknown commands/responses
1211 if ((isHandsFree == 0) && (strncmp(line_buffer, "AT+", 3) == 0)){
1212 return HFP_CMD_UNKNOWN;
1213 }
1214
1215 if ((isHandsFree != 0) && (strncmp(line_buffer, "+", 1) == 0)){
1216 return HFP_CMD_UNKNOWN;
1217 }

--- 9 unchanged lines hidden (view full) ---

1227static int hfp_parser_is_buffer_empty(hfp_connection_t * hfp_connection){
1228 return hfp_connection->line_size == 0;
1229}
1230
1231static int hfp_parser_is_end_of_line(uint8_t byte){
1232 return (byte == '\n') || (byte == '\r');
1233}
1234
1212static void hfp_parser_reset_line_buffer(hfp_connection_t *hfp_connection) {
1235void hfp_parser_reset_line_buffer(hfp_connection_t *hfp_connection) {
1213 hfp_connection->line_size = 0;
1214 // we don't set the first byte to '\0' to allow access to last argument e.g. in hfp_hf_handle_rfcommand
1215}
1216
1217static void hfp_parser_store_if_token(hfp_connection_t * hfp_connection, uint8_t byte){
1218 switch (byte){
1219 case ',':
1220 case '-':

--- 86 unchanged lines hidden (view full) ---

1307 default:
1308 hfp_connection->command = HFP_CMD_UNKNOWN;
1309 break;
1310 }
1311 }
1312
1313 log_info("command string '%s', handsfree %u -> cmd id %u", (char *)hfp_connection->line_buffer, isHandsFree, hfp_connection->command);
1314
1236 hfp_connection->line_size = 0;
1237 // we don't set the first byte to '\0' to allow access to last argument e.g. in hfp_hf_handle_rfcommand
1238}
1239
1240static void hfp_parser_store_if_token(hfp_connection_t * hfp_connection, uint8_t byte){
1241 switch (byte){
1242 case ',':
1243 case '-':

--- 86 unchanged lines hidden (view full) ---

1330 default:
1331 hfp_connection->command = HFP_CMD_UNKNOWN;
1332 break;
1333 }
1334 }
1335
1336 log_info("command string '%s', handsfree %u -> cmd id %u", (char *)hfp_connection->line_buffer, isHandsFree, hfp_connection->command);
1337
1338 // store command id for custom command and just store rest of line
1339 if (hfp_connection->command == HFP_CMD_CUSTOM_MESSAGE){
1340 const hfp_custom_at_command_t * at_command = hfp_custom_command_lookup((const char *)hfp_connection->line_buffer);
1341 hfp_connection->ag_custom_at_command_id = at_command->command_id;
1342 hfp_connection->parser_state = HFP_PARSER_CUSTOM_COMMAND;
1343 return true;
1344 }
1345
1315 // next state
1316 hfp_connection->found_equal_sign = false;
1317 hfp_parser_reset_line_buffer(hfp_connection);
1318 hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
1319
1320 return processed;
1321
1322 case HFP_PARSER_CMD_SEQUENCE:

--- 111 unchanged lines hidden (view full) ---

1434
1435 hfp_parser_reset_line_buffer(hfp_connection);
1436
1437 if (hfp_connection->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
1438 hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
1439 }
1440 return true;
1441
1346 // next state
1347 hfp_connection->found_equal_sign = false;
1348 hfp_parser_reset_line_buffer(hfp_connection);
1349 hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
1350
1351 return processed;
1352
1353 case HFP_PARSER_CMD_SEQUENCE:

--- 111 unchanged lines hidden (view full) ---

1465
1466 hfp_parser_reset_line_buffer(hfp_connection);
1467
1468 if (hfp_connection->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
1469 hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
1470 }
1471 return true;
1472
1473 case HFP_PARSER_CUSTOM_COMMAND:
1474 hfp_parser_store_byte(hfp_connection, byte);
1475 return true;
1476
1442 default:
1443 btstack_assert(false);
1444 return true;
1445 }
1446}
1447
1448void hfp_parse(hfp_connection_t * hfp_connection, uint8_t byte, int isHandsFree){
1449 bool processed = false;

--- 520 unchanged lines hidden (view full) ---

1970void hfp_deinit(void){
1971 hfp_allowed_sco_packet_types = 0;
1972 hfp_connections = NULL;
1973 hfp_hf_callback = NULL;
1974 hfp_ag_callback = NULL;
1975 hfp_hf_rfcomm_packet_handler = NULL;
1976 hfp_ag_rfcomm_packet_handler = NULL;
1977 hfp_sco_establishment_active = NULL;
1477 default:
1478 btstack_assert(false);
1479 return true;
1480 }
1481}
1482
1483void hfp_parse(hfp_connection_t * hfp_connection, uint8_t byte, int isHandsFree){
1484 bool processed = false;

--- 520 unchanged lines hidden (view full) ---

2005void hfp_deinit(void){
2006 hfp_allowed_sco_packet_types = 0;
2007 hfp_connections = NULL;
2008 hfp_hf_callback = NULL;
2009 hfp_ag_callback = NULL;
2010 hfp_hf_rfcomm_packet_handler = NULL;
2011 hfp_ag_rfcomm_packet_handler = NULL;
2012 hfp_sco_establishment_active = NULL;
2013 hfp_custom_commands_ag = NULL;
1978 (void) memset(&hfp_sdp_query_context, 0, sizeof(hfp_sdp_query_context_t));
1979 (void) memset(&hfp_sdp_query_request, 0, sizeof(btstack_context_callback_registration_t));
1980}
1981
1982void hfp_set_sco_packet_types(uint16_t packet_types){
1983 hfp_allowed_sco_packet_types = packet_types;
1984}
1985

--- 58 unchanged lines hidden (view full) ---

2044 printable[i++] = packet[pos];
2045 break;
2046 }
2047 }
2048 printable[i] = 0;
2049 log_info("%s: '%s'", tag, printable);
2050#endif
2051}
2014 (void) memset(&hfp_sdp_query_context, 0, sizeof(hfp_sdp_query_context_t));
2015 (void) memset(&hfp_sdp_query_request, 0, sizeof(btstack_context_callback_registration_t));
2016}
2017
2018void hfp_set_sco_packet_types(uint16_t packet_types){
2019 hfp_allowed_sco_packet_types = packet_types;
2020}
2021

--- 58 unchanged lines hidden (view full) ---

2080 printable[i++] = packet[pos];
2081 break;
2082 }
2083 }
2084 printable[i] = 0;
2085 log_info("%s: '%s'", tag, printable);
2086#endif
2087}
2088
2089void hfp_register_custom_ag_command(hfp_custom_at_command_t * custom_at_command){
2090 btstack_linked_list_add(&hfp_custom_commands_ag, (btstack_linked_item_t *) custom_at_command);
2091}