mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-23 00:39:51 +00:00
obex_parser: add obex_app_param_parser
This commit is contained in:
parent
63cff0c949
commit
3a6b6ac96a
@ -249,3 +249,89 @@ obex_parser_header_state_t obex_parser_header_store(uint8_t * header_buffer, uin
|
|||||||
return OBEX_PARSER_HEADER_INCOMPLETE;
|
return OBEX_PARSER_HEADER_INCOMPLETE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* OBEX App Param Parser */
|
||||||
|
|
||||||
|
void obex_app_param_parser_init(obex_app_param_parser_t * parser, obex_app_param_parser_callback_t callback, uint8_t param_size, void * user_data){
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_W4_TYPE;
|
||||||
|
parser->callback = callback;
|
||||||
|
parser->user_data = user_data;
|
||||||
|
parser->param_size = param_size;
|
||||||
|
parser->param_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
obex_app_param_parser_params_state_t obex_app_param_parser_process_data(obex_app_param_parser_t *parser, const uint8_t *data_buffer, uint16_t data_len){
|
||||||
|
while ((data_len > 0) && (parser->param_pos < parser->param_size)){
|
||||||
|
uint16_t bytes_to_consume = 1;
|
||||||
|
switch(parser->state){
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_INVALID:
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID;
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_W4_TYPE:
|
||||||
|
parser->tag_id = *data_buffer;
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_W4_LEN;
|
||||||
|
break;
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_W4_LEN:
|
||||||
|
parser->tag_len = *data_buffer;
|
||||||
|
if ((parser->param_pos + parser->tag_len) > parser->param_size){
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_INVALID;
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID;
|
||||||
|
}
|
||||||
|
parser->tag_pos = 0;
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_W4_VALUE;
|
||||||
|
break;
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_W4_VALUE:
|
||||||
|
bytes_to_consume = btstack_min(parser->tag_len - parser->tag_pos, data_len);
|
||||||
|
(*parser->callback)(parser->user_data, parser->tag_id, parser->tag_len, parser->tag_pos, data_buffer, bytes_to_consume);
|
||||||
|
parser->tag_pos += bytes_to_consume;
|
||||||
|
if (parser->tag_pos == parser->tag_len){
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_W4_TYPE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
btstack_unreachable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_buffer += bytes_to_consume;
|
||||||
|
data_len -= bytes_to_consume;
|
||||||
|
parser->param_pos += bytes_to_consume;
|
||||||
|
|
||||||
|
// all bytes read? then check state
|
||||||
|
if (parser->param_pos == parser->param_size){
|
||||||
|
if (parser->state == OBEX_APP_PARAM_PARSER_STATE_W4_TYPE){
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_COMPLETE;
|
||||||
|
} else {
|
||||||
|
parser->state = OBEX_APP_PARAM_PARSER_STATE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_len > 0){
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (parser->state){
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_COMPLETE:
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE;
|
||||||
|
case OBEX_APP_PARAM_PARSER_STATE_INVALID:
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID;
|
||||||
|
default:
|
||||||
|
return OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
obex_app_param_parser_tag_state_t obex_app_param_parser_tag_store(uint8_t * header_buffer, uint8_t buffer_size, uint8_t total_len,
|
||||||
|
uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len){
|
||||||
|
uint16_t bytes_to_store = btstack_min(buffer_size - data_offset, data_len);
|
||||||
|
memcpy(&header_buffer[data_offset], data_buffer, bytes_to_store);
|
||||||
|
uint16_t new_offset = data_offset + bytes_to_store;
|
||||||
|
if (new_offset > buffer_size){
|
||||||
|
return OBEX_APP_PARAM_PARSER_TAG_OVERRUN;
|
||||||
|
} else if (new_offset == total_len) {
|
||||||
|
return OBEX_APP_PARAM_PARSER_TAG_COMPLETE;
|
||||||
|
} else {
|
||||||
|
return OBEX_APP_PARAM_PARSER_TAG_INCOMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -113,10 +113,54 @@ typedef struct {
|
|||||||
uint8_t header_id;
|
uint8_t header_id;
|
||||||
} obex_parser_t;
|
} obex_parser_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to process chunked data
|
||||||
|
* @param user_data provided in obex_parser_init
|
||||||
|
* @param header_id current OBEX header ID
|
||||||
|
* @param total_len of header
|
||||||
|
* @param data_offset
|
||||||
|
* @param data_len
|
||||||
|
* @param data_buffer
|
||||||
|
*/
|
||||||
|
typedef void (*obex_app_param_parser_callback_t)(void * user_data, uint8_t tag_id, uint8_t total_len, uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE,
|
||||||
|
OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE,
|
||||||
|
OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN,
|
||||||
|
OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID,
|
||||||
|
} obex_app_param_parser_params_state_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OBEX_APP_PARAM_PARSER_TAG_INCOMPLETE,
|
||||||
|
OBEX_APP_PARAM_PARSER_TAG_COMPLETE,
|
||||||
|
OBEX_APP_PARAM_PARSER_TAG_OVERRUN,
|
||||||
|
} obex_app_param_parser_tag_state_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_W4_TYPE = 0,
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_W4_LEN,
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_W4_VALUE,
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_COMPLETE,
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_INVALID,
|
||||||
|
OBEX_APP_PARAM_PARSER_STATE_OVERRUN,
|
||||||
|
} obex_app_param_parser_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
obex_app_param_parser_callback_t callback;
|
||||||
|
obex_app_param_parser_state_t state;
|
||||||
|
void * user_data;
|
||||||
|
uint16_t param_size;
|
||||||
|
uint16_t param_pos;
|
||||||
|
uint16_t tag_len;
|
||||||
|
uint16_t tag_pos;
|
||||||
|
uint8_t tag_id;
|
||||||
|
} obex_app_param_parser_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize OBEX Parser for next OBEX request
|
* Initialize OBEX Parser for next OBEX request
|
||||||
* @param obex_parser
|
* @param obex_parser
|
||||||
* @param function to call for fields that are not registered
|
* @param function to call for field data
|
||||||
* @param user_data provided to callback function
|
* @param user_data provided to callback function
|
||||||
*/
|
*/
|
||||||
void obex_parser_init_for_request(obex_parser_t * obex_parser, obex_parser_callback_t obex_parser_callback, void * user_data);
|
void obex_parser_init_for_request(obex_parser_t * obex_parser, obex_parser_callback_t obex_parser_callback, void * user_data);
|
||||||
@ -125,7 +169,7 @@ void obex_parser_init_for_request(obex_parser_t * obex_parser, obex_parser_callb
|
|||||||
* Initialize OBEX Parser for next OBEX response
|
* Initialize OBEX Parser for next OBEX response
|
||||||
* @param obex_parser
|
* @param obex_parser
|
||||||
* @param opcode of request - needed as responses with additional fields like connect and set path
|
* @param opcode of request - needed as responses with additional fields like connect and set path
|
||||||
* @param function to call for fields that are not registered
|
* @param function to call for field data
|
||||||
* @param user_data provided to callback function
|
* @param user_data provided to callback function
|
||||||
*/
|
*/
|
||||||
void obex_parser_init_for_response(obex_parser_t * obex_parser, uint8_t opcode, obex_parser_callback_t obex_parser_callback, void * user_data);
|
void obex_parser_init_for_response(obex_parser_t * obex_parser, uint8_t opcode, obex_parser_callback_t obex_parser_callback, void * user_data);
|
||||||
@ -151,7 +195,7 @@ void obex_parser_get_operation_info(obex_parser_t * obex_parser, obex_parser_ope
|
|||||||
* @param header_buffer
|
* @param header_buffer
|
||||||
* @param buffer_size of header_buffer
|
* @param buffer_size of header_buffer
|
||||||
* @param total_len of header value
|
* @param total_len of header value
|
||||||
* @param data_offset of chunkc to store
|
* @param data_offset of chunk to store
|
||||||
* @param data_buffer
|
* @param data_buffer
|
||||||
* @param data_len chunk length
|
* @param data_len chunk length
|
||||||
* @return OBEX_PARSER_HEADER_COMPLETE when header value complete
|
* @return OBEX_PARSER_HEADER_COMPLETE when header value complete
|
||||||
@ -159,6 +203,38 @@ void obex_parser_get_operation_info(obex_parser_t * obex_parser, obex_parser_ope
|
|||||||
obex_parser_header_state_t obex_parser_header_store(uint8_t * header_buffer, uint16_t buffer_size, uint16_t total_len,
|
obex_parser_header_state_t obex_parser_header_store(uint8_t * header_buffer, uint16_t buffer_size, uint16_t total_len,
|
||||||
uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len);
|
uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize OBEX Application Param Parser
|
||||||
|
* @param parser
|
||||||
|
* @param function to call for tag data
|
||||||
|
* @param param_size of OBEX_HEADER_APPLICATION_PARAMETERS header
|
||||||
|
* @param user_data provided to callback function
|
||||||
|
*/
|
||||||
|
void obex_app_param_parser_init(obex_app_param_parser_t * parser, obex_app_param_parser_callback_t callback, uint8_t param_size, void * user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process OBEX App Param data
|
||||||
|
* @param parser
|
||||||
|
* @param data_len
|
||||||
|
* @param data_buffer
|
||||||
|
* @return OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE if packet has been completely parsed
|
||||||
|
*/
|
||||||
|
obex_app_param_parser_params_state_t obex_app_param_parser_process_data(obex_app_param_parser_t *parser, const uint8_t *data_buffer, uint16_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to collect tag chunks in fixed-size data buffer
|
||||||
|
* @param tag_buffer
|
||||||
|
* @param buffer_size of data buffer
|
||||||
|
* @param total_len of tag value
|
||||||
|
* @param data_offset of chunk to store
|
||||||
|
* @param data_buffer
|
||||||
|
* @param data_len chunk length
|
||||||
|
* @return OBEX_APP_PARAM_PARSER_TAG_COMPLETE when tag complete
|
||||||
|
*/
|
||||||
|
|
||||||
|
obex_app_param_parser_tag_state_t obex_app_param_parser_tag_store(uint8_t * tag_buffer, uint8_t buffer_size, uint8_t total_len,
|
||||||
|
uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len);
|
||||||
|
|
||||||
|
|
||||||
/* API_END */
|
/* API_END */
|
||||||
|
|
||||||
|
@ -137,6 +137,74 @@ TEST(OBEX_PARSER, SetPathResponse){
|
|||||||
parse_response(OBEX_OPCODE_SETPATH);
|
parse_response(OBEX_OPCODE_SETPATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** App Param Parser */
|
||||||
|
|
||||||
|
static uint8_t test_tag_id;
|
||||||
|
static uint8_t test_tag_buffer[100];
|
||||||
|
static uint16_t test_tag_len;
|
||||||
|
|
||||||
|
void app_param_parser_callback(void * user_data, uint8_t tag_id, uint8_t total_len, uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len){
|
||||||
|
if (obex_app_param_parser_tag_store(test_header_buffer, sizeof(test_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_APP_PARAM_PARSER_TAG_COMPLETE){
|
||||||
|
test_tag_len = total_len;
|
||||||
|
test_tag_id = tag_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_GROUP(APP_PARAM_PARSER){
|
||||||
|
obex_app_param_parser_t parser;
|
||||||
|
void setup(void){
|
||||||
|
test_tag_id = 0;
|
||||||
|
test_tag_len = 0;
|
||||||
|
}
|
||||||
|
void teardown(void){
|
||||||
|
}
|
||||||
|
void parse_app_params(const uint8_t * app_params, uint8_t param_len){
|
||||||
|
obex_app_param_parser_init(&parser, &app_param_parser_callback, param_len, NULL);
|
||||||
|
for (int i = 0; i < param_len - 1;i++){
|
||||||
|
obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &app_params[i], 1);
|
||||||
|
CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE, parser_state);
|
||||||
|
}
|
||||||
|
if (param_len > 0){
|
||||||
|
obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &app_params[param_len-1], 1);
|
||||||
|
CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE, parser_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TEST(APP_PARAM_PARSER, EmptyParams){
|
||||||
|
parse_app_params(NULL, 0);
|
||||||
|
CHECK_EQUAL(0, test_tag_id);
|
||||||
|
CHECK_EQUAL(0, test_tag_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(APP_PARAM_PARSER, SingleParam){
|
||||||
|
uint8_t message[] = { 0x01, 0x02, 0x03, 0x4};
|
||||||
|
parse_app_params(message, sizeof(message));
|
||||||
|
CHECK_EQUAL(1, test_tag_id);
|
||||||
|
CHECK_EQUAL(2, test_tag_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(APP_PARAM_PARSER, Overrun){
|
||||||
|
uint8_t message[] = { 0x01, 0x02, 0x03, 0x4};
|
||||||
|
parse_app_params(message, sizeof(message));
|
||||||
|
obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &message[0], 1);
|
||||||
|
CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN, parser_state);
|
||||||
|
CHECK_EQUAL(1, test_tag_id);
|
||||||
|
CHECK_EQUAL(2, test_tag_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(APP_PARAM_PARSER, InvalidTagLen){
|
||||||
|
uint8_t message[] = { 0x01, 0x04, 0x03, 0x4};
|
||||||
|
obex_app_param_parser_t parser;
|
||||||
|
obex_app_param_parser_init(&parser, &app_param_parser_callback, sizeof(message), NULL);
|
||||||
|
obex_app_param_parser_params_state_t parser_state;
|
||||||
|
parser_state = obex_app_param_parser_process_data(&parser, &message[0], 1);
|
||||||
|
CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE, parser_state);
|
||||||
|
parser_state = obex_app_param_parser_process_data(&parser, &message[1], 1);
|
||||||
|
CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID, parser_state);
|
||||||
|
CHECK_EQUAL(0, test_tag_id);
|
||||||
|
CHECK_EQUAL(0, test_tag_len);
|
||||||
|
}
|
||||||
|
|
||||||
int main (int argc, const char * argv[]){
|
int main (int argc, const char * argv[]){
|
||||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user