mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-21 21:41:13 +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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
} 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
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
* @param obex_parser
|
||||
* @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
|
||||
*/
|
||||
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 buffer_size of header_buffer
|
||||
* @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_len chunk length
|
||||
* @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,
|
||||
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 */
|
||||
|
||||
|
@ -137,6 +137,74 @@ TEST(OBEX_PARSER, SetPathResponse){
|
||||
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[]){
|
||||
return CommandLineTestRunner::RunAllTests(argc, argv);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user