fully track RPN requests and inform client about port configuration

This commit is contained in:
matthias.ringwald@gmail.com 2014-01-12 10:27:07 +00:00
parent 62fa196c23
commit 335952a48f
3 changed files with 69 additions and 16 deletions

View File

@ -201,7 +201,7 @@ extern "C" {
#define RFCOMM_EVENT_REMOTE_MODEM_STATUS 0x87
// data: event (8), len(8), rfcomm_cid (16), rpn_data_t (67)
#define RFCOMM_EVENT_PORT_NEGOTIATION 0x88
#define RFCOMM_EVENT_PORT_CONFIGURATION 0x88
// data: event(8), len(8), status(8), service_record_handle(32)

View File

@ -236,6 +236,15 @@ void rfcomm_emit_remote_line_status(rfcomm_channel_t *channel, uint8_t line_stat
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
}
void rfcomm_emit_port_configuration(rfcomm_channel_t *channel){
// notify client about new settings
uint8_t event[2+sizeof(rfcomm_rpn_data_t)];
event[0] = RFCOMM_EVENT_PORT_CONFIGURATION;
event[1] = sizeof(rfcomm_rpn_data_t);
memcpy(&event[2], (uint8_t*) &channel->rpn_data, sizeof(rfcomm_rpn_data_t));
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->rfcomm_cid, (uint8_t*)&event, sizeof(event));
}
// MARK RFCOMM RPN DATA HELPER
static void rfcomm_rpn_data_set_defaults(rfcomm_rpn_data_t * rpn_data){
rpn_data->baud_rate = RPN_BAUD_9600; /* 9600 bps */
@ -247,6 +256,39 @@ static void rfcomm_rpn_data_set_defaults(rfcomm_rpn_data_t * rpn_data){
rpn_data->parameter_mask_1 = 0x3f; /* parameter mask, all values set */
}
static void rfcomm_rpn_data_update(rfcomm_rpn_data_t * dest, rfcomm_rpn_data_t * src){
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_BAUD){
dest->baud_rate = src->baud_rate;
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_DATA_BITS){
dest->flags = (dest->flags & 0xfc) | (src->flags & 0x03);
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_STOP_BITS){
dest->flags = (dest->flags & 0xfb) | (src->flags & 0x04);
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_PARITY){
dest->flags = (dest->flags & 0xf7) | (src->flags & 0x08);
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_PARITY_TYPE){
dest->flags = (dest->flags & 0xfc) | (src->flags & 0x30);
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_XON_CHAR){
dest->xon = src->xon;
}
if (src->parameter_mask_0 & RPN_PARAM_MASK_0_XOFF_CHAR){
dest->xoff = src->xoff;
}
int i;
for (i=0; i < 6 ; i++){
uint8_t mask = 1 << i;
if (src->parameter_mask_1 & mask){
dest->flags = (dest->flags & ~mask) | (src->flags & mask);
}
}
// always copy parameter mask, too. informative for client, needed for response
dest->parameter_mask_0 = src->parameter_mask_0;
dest->parameter_mask_1 = src->parameter_mask_1;
}
// MARK: RFCOMM MULTIPLEXER HELPER
static uint16_t rfcomm_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
@ -1170,6 +1212,7 @@ static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
rfChannel->state = RFCOMM_CHANNEL_OPEN;
rfcomm_emit_channel_opened(rfChannel, 0);
rfcomm_emit_port_configuration(rfChannel);
rfcomm_hand_out_credits();
// remove (potential) timer
@ -1408,20 +1451,14 @@ void rfcomm_channel_packet_handler(rfcomm_multiplexer_t * multiplexer, uint8_t
message_dlci = packet[payload_offset+2] >> 2;
switch (message_len){
case 1:
log_info("Received Remote Port Negotiation for #%u\n", message_dlci);
log_info("Received Remote Port Negotiation Request for #%u\n", message_dlci);
event.type = CH_EVT_RCVD_RPN_REQ;
rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
break;
case 8:
log_info("Received Remote Port Negotiation (Info) for #%u\n", message_dlci);
log_info("Received Remote Port Negotiation Update for #%u\n", message_dlci);
event_rpn.super.type = CH_EVT_RCVD_RPN_CMD;
event_rpn.data.baud_rate = packet[payload_offset+3];
event_rpn.data.flags = packet[payload_offset+4];
event_rpn.data.flow_control = packet[payload_offset+5];
event_rpn.data.xon = packet[payload_offset+6];
event_rpn.data.xoff = packet[payload_offset+7];
event_rpn.data.parameter_mask_0 = packet[payload_offset+8];
event_rpn.data.parameter_mask_1 = packet[payload_offset+9];
event_rpn.data = *(rfcomm_rpn_data_t*) &packet[payload_offset+3];
rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_rpn);
break;
default:
@ -1555,14 +1592,10 @@ static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_chann
if (event->type == CH_EVT_RCVD_RPN_CMD){
// control port parameters
rfcomm_channel_event_rpn_t *event_rpn = (rfcomm_channel_event_rpn_t*) event;
memcpy(&channel->rpn_data, &event_rpn->data, sizeof(rfcomm_rpn_data_t));
rfcomm_rpn_data_update(&channel->rpn_data, &event_rpn->data);
rfcomm_channel_state_add(channel, RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP);
// notify client about new settings
uint8_t event[2+sizeof(rfcomm_rpn_data_t)];
event[0] = RFCOMM_EVENT_PORT_NEGOTIATION;
event[1] = sizeof(rfcomm_rpn_data_t);
memcpy(&event[2], (uint8_t*) &event_rpn->data, sizeof(rfcomm_rpn_data_t));
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->rfcomm_cid, (uint8_t*)&event, sizeof(event));
rfcomm_emit_port_configuration(channel);
return;
}

View File

@ -109,6 +109,26 @@ typedef enum rpn_flow_control {
RPN_FLOW_CONTROL_RTC_ON_OUTPUT = 1 << 5,
} rpn_flow_control_t;
#define RPN_PARAM_MASK_0_BAUD 0x01
#define RPN_PARAM_MASK_0_DATA_BITS 0x02
#define RPN_PARAM_MASK_0_STOP_BITS 0x04
#define RPN_PARAM_MASK_0_PARITY 0x08
#define RPN_PARAM_MASK_0_PARITY_TYPE 0x10
#define RPN_PARAM_MASK_0_XON_CHAR 0x20
#define RPN_PARAM_MASK_0_XOFF_CHAR 0x40
#define RPN_PARAM_MASK_0_RESERVED 0x80
// @note: values are identical to rpn_flow_control_t
#define RPN_PARAM_MASK_1_XONOFF_ON_INPUT 0x01
#define RPN_PARAM_MASK_1_XONOFF_ON_OUTPUT 0x02
#define RPN_PARAM_MASK_1_RTR_ON_INPUT 0x04
#define RPN_PARAM_MASK_1_RTR_ON_OUTPUT 0x08
#define RPN_PARAM_MASK_1_RTC_ON_INPUT 0x10
#define RPN_PARAM_MASK_1_RTC_ON_OUTPUT 0x20
#define RPN_PARAM_MASK_1_RESERVED_0 0x40
#define RPN_PARAM_MASK_1_RESERVED_1 0x80
// private structs
typedef enum {
RFCOMM_MULTIPLEXER_CLOSED = 1,