Pulse Oximeter (NONIN) communicates with mbed via Bluetooth dongle and sends Heart Rate and Oxygen Saturation via GPRS module

Dependencies:   C12832 GPS GSM mbed

Fork of myBlueUSB_localfix by Nobuaki Aoki

Committer:
samialshorman
Date:
Tue Apr 14 21:48:07 2015 +0000
Revision:
3:55a622e3dbb5
Parent:
0:003889bc474f
Nonin (Pulse Oximeter) connected to mbed lpc 1768 by Bluetooth dongle and sends SMS including Heart Rate and Oxygen saturation by GPRS module

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nobukuma 0:003889bc474f 1 #include "mbed.h"
nobukuma 0:003889bc474f 2 #include "Utils.h"
nobukuma 0:003889bc474f 3 #include "RFCOMM.h"
nobukuma 0:003889bc474f 4
nobukuma 0:003889bc474f 5 // Control field values bit no. 1 2 3 4 5 6 7 8
nobukuma 0:003889bc474f 6 #define BT_RFCOMM_SABM 0x3F // 1 1 1 1 P/F 1 0 0
nobukuma 0:003889bc474f 7 #define BT_RFCOMM_UA 0x73 // 1 1 0 0 P/F 1 1 0
nobukuma 0:003889bc474f 8 #define BT_RFCOMM_DM 0x0F // 1 1 1 1 P/F 0 0 0
nobukuma 0:003889bc474f 9 #define BT_RFCOMM_DM_PF 0x1F
nobukuma 0:003889bc474f 10 #define BT_RFCOMM_DISC 0x53 // 1 1 0 0 P/F 0 1 0
nobukuma 0:003889bc474f 11 #define BT_RFCOMM_UIH 0xEF // 1 1 1 1 P/F 1 1 1
nobukuma 0:003889bc474f 12 #define BT_RFCOMM_UIH_PF 0xFF
nobukuma 0:003889bc474f 13
nobukuma 0:003889bc474f 14 // Multiplexer message types
nobukuma 0:003889bc474f 15 #define BT_RFCOMM_PN_CMD 0x83
nobukuma 0:003889bc474f 16 #define BT_RFCOMM_PN_RSP 0x81
nobukuma 0:003889bc474f 17 #define BT_RFCOMM_TEST_CMD 0x23
nobukuma 0:003889bc474f 18 #define BT_RFCOMM_TEST_RSP 0x21
nobukuma 0:003889bc474f 19 #define BT_RFCOMM_FCON_CMD 0xA3
nobukuma 0:003889bc474f 20 #define BT_RFCOMM_FCON_RSP 0xA1
nobukuma 0:003889bc474f 21 #define BT_RFCOMM_FCOFF_CMD 0x63
nobukuma 0:003889bc474f 22 #define BT_RFCOMM_FCOFF_RSP 0x61
nobukuma 0:003889bc474f 23 #define BT_RFCOMM_MSC_CMD 0xE3
nobukuma 0:003889bc474f 24 #define BT_RFCOMM_MSC_RSP 0xE1
nobukuma 0:003889bc474f 25 #define BT_RFCOMM_RPN_CMD 0x93
nobukuma 0:003889bc474f 26 #define BT_RFCOMM_RPN_RSP 0x91
nobukuma 0:003889bc474f 27 #define BT_RFCOMM_RLS_CMD 0x53
nobukuma 0:003889bc474f 28 #define BT_RFCOMM_RLS_RSP 0x51
nobukuma 0:003889bc474f 29 #define BT_RFCOMM_NSC_RSP 0x11
nobukuma 0:003889bc474f 30
nobukuma 0:003889bc474f 31 // FCS calc
nobukuma 0:003889bc474f 32 #define BT_RFCOMM_CODE_WORD 0xE0 // pol = x8+x2+x1+1
nobukuma 0:003889bc474f 33 #define BT_RFCOMM_CRC_CHECK_LEN 3
nobukuma 0:003889bc474f 34 #define BT_RFCOMM_UIHCRC_CHECK_LEN 2
nobukuma 0:003889bc474f 35
nobukuma 0:003889bc474f 36 #define NR_CREDITS 1
nobukuma 0:003889bc474f 37 #define INITIAL_CREDITS 1 //0...7
nobukuma 0:003889bc474f 38
nobukuma 0:003889bc474f 39 #define DCD (1<<7) //DV data carrier detect
nobukuma 0:003889bc474f 40 #define RI (1<<6) //IC ring indicator
nobukuma 0:003889bc474f 41 #define RTS (1<<3) //RTR request to send
nobukuma 0:003889bc474f 42 #define DSR (1<<2) //RTC data set ready
nobukuma 0:003889bc474f 43 #define FC (1<<1) //Flow Control
nobukuma 0:003889bc474f 44 #define EA (1<<0) //extended address (always 1)
nobukuma 0:003889bc474f 45 #define SIGNALS (DCD | RTS | DSR | EA)
nobukuma 0:003889bc474f 46
nobukuma 0:003889bc474f 47 #define DEBUG 1
nobukuma 0:003889bc474f 48 #define TAKE_INITIATIVE
nobukuma 0:003889bc474f 49
nobukuma 0:003889bc474f 50 RFCOMMManager rfcomm_manager;
nobukuma 0:003889bc474f 51
nobukuma 0:003889bc474f 52 //uint8_t rfcomm_out_buffer[1000];//seems a bit big as default max framesize is 127
nobukuma 0:003889bc474f 53 //unsigned rfcomm::maxframesize = MAX_FRAME_SIZE; //only initial value
nobukuma 0:003889bc474f 54
nobukuma 0:003889bc474f 55 //these functions are obtained from rfcomm.c on google code
nobukuma 0:003889bc474f 56 void _bt_rfcomm_send_sabm(unsigned short source_cid, unsigned char initiator, unsigned char channel);
nobukuma 0:003889bc474f 57 void _bt_rfcomm_send_uih_pn_command(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned short max_frame_size);
nobukuma 0:003889bc474f 58 void _bt_rfcomm_send_uih_msc_cmd(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned char signals);
nobukuma 0:003889bc474f 59 void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val);
nobukuma 0:003889bc474f 60 int rfcomm_send_packet(unsigned short source_cid, unsigned char address, unsigned char control, unsigned char credits, const unsigned char *data, unsigned short len);
nobukuma 0:003889bc474f 61 uint8_t crc8_calc(uint8_t *data, uint16_t len);
nobukuma 0:003889bc474f 62
nobukuma 0:003889bc474f 63
nobukuma 0:003889bc474f 64 //find a free socket slot for channel ch
nobukuma 0:003889bc474f 65 int rfcomm::find_slot(unsigned ch) {
nobukuma 0:003889bc474f 66 for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
nobukuma 0:003889bc474f 67 if (sckts[i] != 0) { //socket is in use
nobukuma 0:003889bc474f 68 RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
nobukuma 0:003889bc474f 69 if (s==0) {
nobukuma 0:003889bc474f 70 printf("find_slot: socket %d not found\n", sckts[i]);
nobukuma 0:003889bc474f 71 continue;
nobukuma 0:003889bc474f 72 }
nobukuma 0:003889bc474f 73 if (s->dlci >> 1 == ch) {
nobukuma 0:003889bc474f 74 printf("Channel %d is already in use on socket %d\n", ch, sckts[i]);
nobukuma 0:003889bc474f 75 return -1;
nobukuma 0:003889bc474f 76 }
nobukuma 0:003889bc474f 77 } else //slot is free
nobukuma 0:003889bc474f 78 return i;
nobukuma 0:003889bc474f 79 }
nobukuma 0:003889bc474f 80 return -2; //no free slots
nobukuma 0:003889bc474f 81 }
nobukuma 0:003889bc474f 82
nobukuma 0:003889bc474f 83 //find the rfcomm socket for dlci
nobukuma 0:003889bc474f 84 RFCOMMSocket* rfcomm::find_socket(unsigned dlci) {
nobukuma 0:003889bc474f 85 for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
nobukuma 0:003889bc474f 86 if (sckts[i] != 0) { //socket is in use
nobukuma 0:003889bc474f 87 RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
nobukuma 0:003889bc474f 88 if (s==0) {
nobukuma 0:003889bc474f 89 printf("find_socket: socket %d not found\n", sckts[i]);
nobukuma 0:003889bc474f 90 continue;
nobukuma 0:003889bc474f 91 }
nobukuma 0:003889bc474f 92 if (s->dlci == dlci) {
nobukuma 0:003889bc474f 93 return s;
nobukuma 0:003889bc474f 94 }
nobukuma 0:003889bc474f 95 }
nobukuma 0:003889bc474f 96 }
nobukuma 0:003889bc474f 97 printf("RFCOMMSocket for dlci %d was not found!\n", dlci);
nobukuma 0:003889bc474f 98 return 0; //socket not found
nobukuma 0:003889bc474f 99 }
nobukuma 0:003889bc474f 100
nobukuma 0:003889bc474f 101 //send a PN command to all sockets waiting to be opened
nobukuma 0:003889bc474f 102 void rfcomm::initChannels(int socket) {
nobukuma 0:003889bc474f 103 for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
nobukuma 0:003889bc474f 104 if (sckts[i] != 0) { //socket is in use
nobukuma 0:003889bc474f 105 RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
nobukuma 0:003889bc474f 106 if (s==0) {
nobukuma 0:003889bc474f 107 printf("initChannels: socket %d not found\n", sckts[i]);
nobukuma 0:003889bc474f 108 continue;
nobukuma 0:003889bc474f 109 }
nobukuma 0:003889bc474f 110 if (s->State == SocketState_Opening) {
nobukuma 0:003889bc474f 111 printf("Sending PN for DLCI %d on socket %d\n", s->dlci, sckts[i]);
nobukuma 0:003889bc474f 112 _bt_rfcomm_send_uih_pn_command(socket, 1, s->dlci, maxframesize);
nobukuma 0:003889bc474f 113 s->State = SocketState_L2CAP_Config_wait;
nobukuma 0:003889bc474f 114 }
nobukuma 0:003889bc474f 115 }
nobukuma 0:003889bc474f 116 }
nobukuma 0:003889bc474f 117 }
nobukuma 0:003889bc474f 118
nobukuma 0:003889bc474f 119 unsigned rfcomm::release_channel(unsigned dlci) {
nobukuma 0:003889bc474f 120 int n = 0;
nobukuma 0:003889bc474f 121 for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
nobukuma 0:003889bc474f 122 if (sckts[i] != 0) { //socket is in use
nobukuma 0:003889bc474f 123 RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
nobukuma 0:003889bc474f 124 if (s==0) {
nobukuma 0:003889bc474f 125 printf("Release: socket for dlci %d not found\n", dlci);
nobukuma 0:003889bc474f 126 continue;
nobukuma 0:003889bc474f 127 }
nobukuma 0:003889bc474f 128 if (s->dlci == dlci)
nobukuma 0:003889bc474f 129 sckts[i] = 0;
nobukuma 0:003889bc474f 130 else
nobukuma 0:003889bc474f 131 n++;
nobukuma 0:003889bc474f 132 }
nobukuma 0:003889bc474f 133 }
nobukuma 0:003889bc474f 134 return n;
nobukuma 0:003889bc474f 135 }
nobukuma 0:003889bc474f 136
nobukuma 0:003889bc474f 137 int rfcomm::Send(SocketInternal *sock, const u8* data, int len) {//also see if credits need to be send
nobukuma 0:003889bc474f 138 RFCOMMSocket *s = (RFCOMMSocket*)sock;
nobukuma 0:003889bc474f 139 char credits = 0;
nobukuma 0:003889bc474f 140 char control = BT_RFCOMM_UIH;
nobukuma 0:003889bc474f 141 if (len + 14 > maxframesize) //hci/l2cap header =8, rfcomm header ~ 6
nobukuma 0:003889bc474f 142 printf("Error! packetsize = %d, maxframesize = %d\n", len, maxframesize);
nobukuma 0:003889bc474f 143 if (s->peer_credits == 0) {//peer is low on credits
nobukuma 0:003889bc474f 144 credits = NR_CREDITS;
nobukuma 0:003889bc474f 145 control = BT_RFCOMM_UIH_PF;
nobukuma 0:003889bc474f 146 s->peer_credits += NR_CREDITS;//so provide some more
nobukuma 0:003889bc474f 147 }
nobukuma 0:003889bc474f 148 unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2);
nobukuma 0:003889bc474f 149 if (s->my_credits) {
nobukuma 0:003889bc474f 150 s->my_credits--;
nobukuma 0:003889bc474f 151 return rfcomm_send_packet(_l2cap, address, control, credits, data, len);
nobukuma 0:003889bc474f 152 } else
nobukuma 0:003889bc474f 153 return rfcomm_send_packet(_l2cap, address, control, credits, data, 0);//send an empty packet when credits run out
nobukuma 0:003889bc474f 154 }
nobukuma 0:003889bc474f 155
nobukuma 0:003889bc474f 156 int rfcomm::Close(SocketInternal* sock) {
nobukuma 0:003889bc474f 157 RFCOMMSocket *s = (RFCOMMSocket*)sock;
nobukuma 0:003889bc474f 158 int id = s->dlci;
nobukuma 0:003889bc474f 159 printf("Closing rfcomm dlci %d state=%d\n", id, s->State);
nobukuma 0:003889bc474f 160 Disconnect(s);
nobukuma 0:003889bc474f 161 int n = release_channel(id);
nobukuma 0:003889bc474f 162 printf("%d channels are still open\n", n);
nobukuma 0:003889bc474f 163 if (n == 0) {//all rfcomm channels are closed
nobukuma 0:003889bc474f 164 printf("....L2CAP must be closed as well\n");
nobukuma 0:003889bc474f 165 rfcomm_send_packet(_l2cap, (1 << 0) | (initiator << 1), BT_RFCOMM_DISC, 0, 0, 0); //close dlci0
nobukuma 0:003889bc474f 166 Socket_Close(_l2cap);
nobukuma 0:003889bc474f 167 _l2cap = 0; //return rfcomm to the pool
nobukuma 0:003889bc474f 168 }
nobukuma 0:003889bc474f 169 return 0;
nobukuma 0:003889bc474f 170 }
nobukuma 0:003889bc474f 171
nobukuma 0:003889bc474f 172 int rfcomm::SetOpt(SocketInternal *sock, int so, int* data, int len) {
nobukuma 0:003889bc474f 173 switch (so) {
nobukuma 0:003889bc474f 174 case SO_RECBUF:
nobukuma 0:003889bc474f 175 case SO_SNDBUF:
nobukuma 0:003889bc474f 176 maxframesize = *data; //pointless because setting takes effect only before socket is opened (before PN)
nobukuma 0:003889bc474f 177 break;
nobukuma 0:003889bc474f 178 default: return NOPROTOOPT;
nobukuma 0:003889bc474f 179 }
nobukuma 0:003889bc474f 180 return 0;
nobukuma 0:003889bc474f 181 }
nobukuma 0:003889bc474f 182
nobukuma 0:003889bc474f 183 int rfcomm::GetOpt(SocketInternal *sock, int so, int* data, int len) {
nobukuma 0:003889bc474f 184 switch (so) {
nobukuma 0:003889bc474f 185 case SO_RECBUF:
nobukuma 0:003889bc474f 186 case SO_SNDBUF:
nobukuma 0:003889bc474f 187 if (len >= sizeof(int))
nobukuma 0:003889bc474f 188 *data = maxframesize;
nobukuma 0:003889bc474f 189 break;
nobukuma 0:003889bc474f 190 default: return NOPROTOOPT;
nobukuma 0:003889bc474f 191 }
nobukuma 0:003889bc474f 192 return 0;
nobukuma 0:003889bc474f 193 }
nobukuma 0:003889bc474f 194
nobukuma 0:003889bc474f 195 int rfcomm::Disconnect(RFCOMMSocket *s) {
nobukuma 0:003889bc474f 196 unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2);
nobukuma 0:003889bc474f 197 return rfcomm_send_packet(_l2cap, address, BT_RFCOMM_DISC, 0, 0, 0);
nobukuma 0:003889bc474f 198 }
nobukuma 0:003889bc474f 199
nobukuma 0:003889bc474f 200 //expect this to be called with socket type=SOCKET_RFCOM and addr->psm = channel and addr->bdaddr is the BT addr
nobukuma 0:003889bc474f 201 //of the device to connect to.
nobukuma 0:003889bc474f 202 //eg. Socket_Open(SOCKET_RFCOM, rfcommaddr(bdaddr, chan), receiver_func, appl_obj);
nobukuma 0:003889bc474f 203 int rfcomm::Open(SocketInternal* sock, SocketAddrHdr* addr) {
nobukuma 0:003889bc474f 204 int ch = ((L2CAPAddr*)addr)->psm;//abused psm for channel ID
nobukuma 0:003889bc474f 205 RFCOMMSocket *s = (RFCOMMSocket*)sock;
nobukuma 0:003889bc474f 206 int slot = find_slot(ch);
nobukuma 0:003889bc474f 207 if (slot < 0) return 0;
nobukuma 0:003889bc474f 208 sckts[slot] = s->ID;
nobukuma 0:003889bc474f 209 s->serdevice = this;
nobukuma 0:003889bc474f 210 s->State = SocketState_Opening;
nobukuma 0:003889bc474f 211
nobukuma 0:003889bc474f 212 if (_l2cap == 0) { //no rfcomm -> l2cap connection yet
nobukuma 0:003889bc474f 213 printf("Need to open L2CAP channel first before opening RFCOMM channel %d\n", s->dlci);
nobukuma 0:003889bc474f 214 ((L2CAPAddr*)addr)->psm = L2CAP_PSM_RFCOMM;//open the l2cap channel and the rfcomm_ch channel
nobukuma 0:003889bc474f 215 initiator = 1;
nobukuma 0:003889bc474f 216 s->dlci = (ch<<1)|!initiator;
nobukuma 0:003889bc474f 217 _l2cap = Socket_Open(SOCKET_L2CAP, addr, OnRfCommControl, this);//this is the socket between the RFCOMM and the L2CAP layer
nobukuma 0:003889bc474f 218 if (_l2cap)
nobukuma 0:003889bc474f 219 printf("Successfully opened L2CAP channel on socket %d\n", _l2cap);
nobukuma 0:003889bc474f 220 else {
nobukuma 0:003889bc474f 221 printf("Opening L2CAP channel failed\n");
nobukuma 0:003889bc474f 222 sckts[slot] = 0;
nobukuma 0:003889bc474f 223 s->State = SocketState_Closed;
nobukuma 0:003889bc474f 224 return 0;
nobukuma 0:003889bc474f 225 }
nobukuma 0:003889bc474f 226 } else {//bypass the l2cap channel creation
nobukuma 0:003889bc474f 227 s->dlci = (ch<<1)|!initiator;
nobukuma 0:003889bc474f 228 _bt_rfcomm_send_uih_pn_command(_l2cap, initiator, s->dlci, maxframesize);
nobukuma 0:003889bc474f 229 s->State = SocketState_L2CAP_Config_wait;
nobukuma 0:003889bc474f 230 }
nobukuma 0:003889bc474f 231 return s->ID; //return the application unique socket nr.
nobukuma 0:003889bc474f 232 }
nobukuma 0:003889bc474f 233
nobukuma 0:003889bc474f 234 int rfcomm::set_remote_port_parameters(unsigned char dlci, port_settings *p) {
nobukuma 0:003889bc474f 235 _bt_rfcomm_send_uih_rpn_cmd(_l2cap, initiator, dlci, p);
nobukuma 0:003889bc474f 236 return 0;
nobukuma 0:003889bc474f 237 }
nobukuma 0:003889bc474f 238
nobukuma 0:003889bc474f 239 //socket is an L2CAP socket and state is the state of the L2CAP socket, not the RFCOMM socket
nobukuma 0:003889bc474f 240 void rfcomm::OnRfCommControl(int socket, SocketState state, const u8* data, int len, void* userData) {
nobukuma 0:003889bc474f 241 int packet_processed = 0;
nobukuma 0:003889bc474f 242 rfcomm* self = (rfcomm*)userData;
nobukuma 0:003889bc474f 243 const u8 initiator = self->initiator;
nobukuma 0:003889bc474f 244 printf("\x1B[%dm", 32); //debug: set a different colour
nobukuma 0:003889bc474f 245 printf("OnRfCommControl sock = %d, state = %d, length = %d\n", socket, state, len);
nobukuma 0:003889bc474f 246
nobukuma 0:003889bc474f 247 if (len == 0) {//client only
nobukuma 0:003889bc474f 248 if (state==SocketState_Open) {//callback after change to 'open', the rfcomm->l2cap channel is now open
nobukuma 0:003889bc474f 249 _bt_rfcomm_send_sabm(socket, initiator, 0); //setup the rfcomm control channel dlci==0
nobukuma 0:003889bc474f 250 return;
nobukuma 0:003889bc474f 251 }
nobukuma 0:003889bc474f 252 return; //or other states to handle, e.g. Closing or Closed
nobukuma 0:003889bc474f 253 }
nobukuma 0:003889bc474f 254 //we have data, so parse the header
nobukuma 0:003889bc474f 255 const u8 &addr = data[0];
nobukuma 0:003889bc474f 256 u8 dlci = addr>>2;
nobukuma 0:003889bc474f 257 const u8 &control = data[1];
nobukuma 0:003889bc474f 258 u16 length = data[2]>>1;
nobukuma 0:003889bc474f 259 const u8 *payload = data+3;
nobukuma 0:003889bc474f 260 const u8 *pFCS = data+len-1; //expected position of the CRC
nobukuma 0:003889bc474f 261 if (!(data[2]&1)) { //two byte length
nobukuma 0:003889bc474f 262 length += ((unsigned)data[3])<<7;
nobukuma 0:003889bc474f 263 payload++;
nobukuma 0:003889bc474f 264 }
nobukuma 0:003889bc474f 265 u8 credits = 0;
nobukuma 0:003889bc474f 266 if (control == BT_RFCOMM_UIH_PF)//this packet carries credits
nobukuma 0:003889bc474f 267 credits = *(payload++);
nobukuma 0:003889bc474f 268 //sanity check
nobukuma 0:003889bc474f 269 if (payload+length != pFCS)
nobukuma 0:003889bc474f 270 printf("RFCOMM size mismatch, expected %d payload bytes, got %d\n", length, pFCS-payload);
nobukuma 0:003889bc474f 271
nobukuma 0:003889bc474f 272 if (DEBUG) {
nobukuma 0:003889bc474f 273 printf("RFCOMM: EA=%d, C/R=%d, D=%d, ch=%d; control=%02X (P/F=%d); length=%d\n", addr&1, (addr>>1)&1, (addr>>2)&1, (addr>>3), control, (control>>4)&1, length);
nobukuma 0:003889bc474f 274 printfBytes("payload:", payload, length);
nobukuma 0:003889bc474f 275 }
nobukuma 0:003889bc474f 276 if (dlci == 0) { //dlci==0 control channel
nobukuma 0:003889bc474f 277 L2CAPSocket *s = (L2CAPSocket*)GetSocketInternal(socket);
nobukuma 0:003889bc474f 278 switch (control) {
nobukuma 0:003889bc474f 279 case BT_RFCOMM_UA:// received 1. message BT_RF_COMM_UA
nobukuma 0:003889bc474f 280 packet_processed++;
nobukuma 0:003889bc474f 281 if (s->si.State == SocketState_Closing || s->si.State==SocketState_L2CAP_WaitDisconnect) { //Confirmation of disconnect
nobukuma 0:003889bc474f 282 printf("Remote side confirmed disconnect for socket %d\n", s->si.ID);
nobukuma 0:003889bc474f 283 s->si.SetState(SocketState_Closed);
nobukuma 0:003889bc474f 284 break;
nobukuma 0:003889bc474f 285 }
nobukuma 0:003889bc474f 286 printf("Received RFCOMM unnumbered acknowledgement for channel 0 - multiplexer working\n");
nobukuma 0:003889bc474f 287 printf("Sending UIH Parameter Negotiation Command from OnRfCommControl\n");
nobukuma 0:003889bc474f 288 self->initChannels(socket);
nobukuma 0:003889bc474f 289 break;
nobukuma 0:003889bc474f 290 case BT_RFCOMM_UIH:// received UIH Parameter Negotiation Response
nobukuma 0:003889bc474f 291 switch (payload[0]) {
nobukuma 0:003889bc474f 292 case BT_RFCOMM_PN_RSP: {//client
nobukuma 0:003889bc474f 293 packet_processed++;
nobukuma 0:003889bc474f 294 printf("UIH Parameter Negotiation Response\n");
nobukuma 0:003889bc474f 295 printf("Sending SABM #%u\n", payload[2]);
nobukuma 0:003889bc474f 296 _bt_rfcomm_send_sabm(socket, initiator, payload[2]);//was rfcomm_ch
nobukuma 0:003889bc474f 297 RFCOMMSocket *r = self->find_socket(payload[2]);
nobukuma 0:003889bc474f 298 if (r==0) break;
nobukuma 0:003889bc474f 299 r->my_credits = payload[9]; //initial amount of credits
nobukuma 0:003889bc474f 300 self->maxframesize = min(self->maxframesize, payload[6] + (payload[7]<<8));
nobukuma 0:003889bc474f 301 printf("Max Frame Size = %d, got %d initial credits\n", self->maxframesize, payload[9]);
nobukuma 0:003889bc474f 302 }
nobukuma 0:003889bc474f 303 break;
nobukuma 0:003889bc474f 304 case BT_RFCOMM_PN_CMD: { //remote side sent PN command, mtu and initial credits
nobukuma 0:003889bc474f 305 packet_processed++;
nobukuma 0:003889bc474f 306 printf("UIH Parameter Negotiation Indication\n");
nobukuma 0:003889bc474f 307 self->maxframesize = min(self->maxframesize, payload[6] + (payload[7]<<8));
nobukuma 0:003889bc474f 308 unsigned char cred = payload[9] & 7;
nobukuma 0:003889bc474f 309 unsigned char _dlci = payload[2];
nobukuma 0:003889bc474f 310
nobukuma 0:003889bc474f 311 int skt = rfcomm_manager.find_socket(_dlci>>1);
nobukuma 0:003889bc474f 312 if (skt == 0) { //No-one is listening
nobukuma 0:003889bc474f 313 printf("No-one is Listening on channel %d\n", _dlci>>1);
nobukuma 0:003889bc474f 314 rfcomm_send_packet(socket, (_dlci<<2)|1, BT_RFCOMM_DM, 0, 0, 0);
nobukuma 0:003889bc474f 315 break;
nobukuma 0:003889bc474f 316 }
nobukuma 0:003889bc474f 317 RFCOMMSocket *r = (RFCOMMSocket*)GetSocketInternal(skt);
nobukuma 0:003889bc474f 318 r->my_credits = cred;
nobukuma 0:003889bc474f 319 r->peer_credits = INITIAL_CREDITS;
nobukuma 0:003889bc474f 320 unsigned char reply[10];
nobukuma 0:003889bc474f 321 memcpy(reply, payload, sizeof(reply));
nobukuma 0:003889bc474f 322 reply[0] = BT_RFCOMM_PN_RSP;//[1]=len, [2]=dlci, [4]=priority, [5]=timer(must be 0), [8] retransmissions (must be 0)
nobukuma 0:003889bc474f 323 reply[3] = payload[3]==0xF0 ? 0xE0 : 0; //support credit based flow control
nobukuma 0:003889bc474f 324 reply[6] = self->maxframesize;
nobukuma 0:003889bc474f 325 reply[7] = self->maxframesize>>8;
nobukuma 0:003889bc474f 326 reply[9] = payload[3]==0xF0 ? r->peer_credits : 0;
nobukuma 0:003889bc474f 327 printf("Max Frame Size = %d, give %d initial credits\n", self->maxframesize, reply[9]);
nobukuma 0:003889bc474f 328 rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, sizeof(reply));
nobukuma 0:003889bc474f 329 }
nobukuma 0:003889bc474f 330 break;
nobukuma 0:003889bc474f 331 case BT_RFCOMM_MSC_CMD:
nobukuma 0:003889bc474f 332 packet_processed++;
nobukuma 0:003889bc474f 333 {
nobukuma 0:003889bc474f 334 printf("Received BT_RFCOMM_MSC_IND\n");
nobukuma 0:003889bc474f 335 // fine with this, return the same status and ignore the value, there is no room in the socket to store the value, rfcomm could generate an event
nobukuma 0:003889bc474f 336 RFCOMMSocket *r = self->find_socket(payload[2]>>2);
nobukuma 0:003889bc474f 337 if (r==0) break;
nobukuma 0:003889bc474f 338 unsigned char reply[5];
nobukuma 0:003889bc474f 339 memcpy(reply, payload, 5); //keep length, dlci and value(s)
nobukuma 0:003889bc474f 340 reply[0] = BT_RFCOMM_MSC_RSP; // change command into response
nobukuma 0:003889bc474f 341 printf("Sending MSC_RSP (%d bytes)\n", length);
nobukuma 0:003889bc474f 342 rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, (payload[1]>>1)+2); // reply is 4 or 5 bytes
nobukuma 0:003889bc474f 343 switch (r->State) {
nobukuma 0:003889bc474f 344 case SocketState_L2CAP_Config_wait:
nobukuma 0:003889bc474f 345 r->State = SocketState_L2CAP_Config_wait_send;
nobukuma 0:003889bc474f 346 printf("Sending MSC_CMD\n");
nobukuma 0:003889bc474f 347 _bt_rfcomm_send_uih_msc_cmd(socket, initiator, payload[2]>>2, SIGNALS); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
nobukuma 0:003889bc474f 348 r->State = SocketState_L2CAP_Config_wait_rsp;
nobukuma 0:003889bc474f 349 break;
nobukuma 0:003889bc474f 350 case SocketState_L2CAP_Config_wait_reqrsp:
nobukuma 0:003889bc474f 351 r->State = SocketState_L2CAP_Config_wait_rsp;
nobukuma 0:003889bc474f 352 break;
nobukuma 0:003889bc474f 353 case SocketState_L2CAP_Config_wait_req:
nobukuma 0:003889bc474f 354 r->SetState(SocketState_Open);
nobukuma 0:003889bc474f 355 break;
nobukuma 0:003889bc474f 356 case SocketState_Open:
nobukuma 0:003889bc474f 357 //inform port adaptation layer
nobukuma 0:003889bc474f 358 printf("Received MSC IND in state Open for dlci 0x%02x\n", payload[2]>>2);
nobukuma 0:003889bc474f 359 break;
nobukuma 0:003889bc474f 360 default:
nobukuma 0:003889bc474f 361 printf("Received MSC IND in state %d for dlci 0x%02x\n", r->State, payload[2]>>2);
nobukuma 0:003889bc474f 362 }
nobukuma 0:003889bc474f 363 }
nobukuma 0:003889bc474f 364 break;
nobukuma 0:003889bc474f 365 case BT_RFCOMM_MSC_RSP:
nobukuma 0:003889bc474f 366 packet_processed++;
nobukuma 0:003889bc474f 367 {
nobukuma 0:003889bc474f 368 RFCOMMSocket *r = self->find_socket(payload[2]>>2);
nobukuma 0:003889bc474f 369 if (r==0) break;
nobukuma 0:003889bc474f 370 if (r->State == SocketState_L2CAP_Config_wait_reqrsp)
nobukuma 0:003889bc474f 371 r->State = SocketState_L2CAP_Config_wait_req;
nobukuma 0:003889bc474f 372 else if (r->State == SocketState_L2CAP_Config_wait_rsp)
nobukuma 0:003889bc474f 373 r->SetState(SocketState_Open);
nobukuma 0:003889bc474f 374 else
nobukuma 0:003889bc474f 375 printf("Received MSC confirmation in state %d for dlci 0x%02x\n", r->State, payload[2]>>2);
nobukuma 0:003889bc474f 376 }
nobukuma 0:003889bc474f 377 break;
nobukuma 0:003889bc474f 378 case BT_RFCOMM_RPN_CMD:
nobukuma 0:003889bc474f 379 packet_processed++;
nobukuma 0:003889bc474f 380 //accept and ignore all settings
nobukuma 0:003889bc474f 381 unsigned char reply[10];
nobukuma 0:003889bc474f 382 memcpy(reply, payload, length); //keep length, dlci and value(s)
nobukuma 0:003889bc474f 383 reply[0] = BT_RFCOMM_RPN_RSP; // change command into response
nobukuma 0:003889bc474f 384 printf("Responding to RPN indication (%d bytes)\n", length);
nobukuma 0:003889bc474f 385 rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, length);
nobukuma 0:003889bc474f 386 break;
nobukuma 0:003889bc474f 387 case BT_RFCOMM_RPN_RSP:
nobukuma 0:003889bc474f 388 packet_processed++;
nobukuma 0:003889bc474f 389 //ignore a response
nobukuma 0:003889bc474f 390 printf("Received RPN confirmation\n");
nobukuma 0:003889bc474f 391 break;
nobukuma 0:003889bc474f 392 default:
nobukuma 0:003889bc474f 393 printf("Unsupported multiplexer frame, type=%02XH\n", data[3]);
nobukuma 0:003889bc474f 394 }
nobukuma 0:003889bc474f 395 break;
nobukuma 0:003889bc474f 396 case BT_RFCOMM_DISC:
nobukuma 0:003889bc474f 397 printf("Remote site actively disconnected from DLCI0\n");
nobukuma 0:003889bc474f 398 rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection
nobukuma 0:003889bc474f 399 //intentional fall through
nobukuma 0:003889bc474f 400 case BT_RFCOMM_DM:
nobukuma 0:003889bc474f 401 packet_processed++;
nobukuma 0:003889bc474f 402 printf("Remote side refused connection on DLCI0\n");
nobukuma 0:003889bc474f 403 self->_l2cap = Socket_Close(socket);
nobukuma 0:003889bc474f 404 break;
nobukuma 0:003889bc474f 405 case BT_RFCOMM_SABM:
nobukuma 0:003889bc474f 406 packet_processed++;
nobukuma 0:003889bc474f 407 printf("Remote site is seeking connection on DLCI0\n"); //respond with UA
nobukuma 0:003889bc474f 408 rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection
nobukuma 0:003889bc474f 409 break;
nobukuma 0:003889bc474f 410 default:
nobukuma 0:003889bc474f 411 printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length);
nobukuma 0:003889bc474f 412 }
nobukuma 0:003889bc474f 413 } else { //data is for one of the serial sockets
nobukuma 0:003889bc474f 414 RFCOMMSocket *s = 0;
nobukuma 0:003889bc474f 415 if (control == BT_RFCOMM_SABM) { //req. for conn on this dlci
nobukuma 0:003889bc474f 416 //cannot call self->rfcomm::find_socket because it has no socket yet
nobukuma 0:003889bc474f 417 int skt = rfcomm_manager.find_socket(dlci>>1); //find the server socket
nobukuma 0:003889bc474f 418 s = (RFCOMMSocket*)GetSocketInternal(skt);//the listening socket
nobukuma 0:003889bc474f 419 if (s) {//move the listening socket to the appropriate rfcomm
nobukuma 0:003889bc474f 420 int slot = self->find_slot(dlci>>1);
nobukuma 0:003889bc474f 421 if (slot < 0) {
nobukuma 0:003889bc474f 422 printf("RFCOMM Channel %d is not free on rfcomm with l2cap socket %d\n", dlci>>1, self->_l2cap);
nobukuma 0:003889bc474f 423 return;
nobukuma 0:003889bc474f 424 }
nobukuma 0:003889bc474f 425 s->serdevice = self; //bind the socket to this refcomm entity
nobukuma 0:003889bc474f 426 self->sckts[slot] = skt;
nobukuma 0:003889bc474f 427 rfcomm_manager.remove_socket(skt);
nobukuma 0:003889bc474f 428 } else {
nobukuma 0:003889bc474f 429 printf("Couln't find a listening socket for dlci %d\n", dlci);
nobukuma 0:003889bc474f 430 return;
nobukuma 0:003889bc474f 431 }
nobukuma 0:003889bc474f 432 } else
nobukuma 0:003889bc474f 433 s = self->find_socket(dlci);
nobukuma 0:003889bc474f 434 if (s==0){
nobukuma 0:003889bc474f 435 printf("DLCI %d not found\n", dlci);
nobukuma 0:003889bc474f 436 return;
nobukuma 0:003889bc474f 437 }
nobukuma 0:003889bc474f 438 switch (control) {
nobukuma 0:003889bc474f 439 case BT_RFCOMM_SABM:
nobukuma 0:003889bc474f 440 packet_processed++;
nobukuma 0:003889bc474f 441 rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection
nobukuma 0:003889bc474f 442 s->State = SocketState_L2CAP_Config_wait; //wait for msc cmd
nobukuma 0:003889bc474f 443 #ifdef TAKE_INITIATIVE
nobukuma 0:003889bc474f 444 printf("Sending MSC_CMD\n");
nobukuma 0:003889bc474f 445 _bt_rfcomm_send_uih_msc_cmd(socket, initiator, dlci, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
nobukuma 0:003889bc474f 446 s->State = SocketState_L2CAP_Config_wait_reqrsp;
nobukuma 0:003889bc474f 447 #endif
nobukuma 0:003889bc474f 448 break;
nobukuma 0:003889bc474f 449 case BT_RFCOMM_UA:// received 2. message BT_RF_COMM_UA
nobukuma 0:003889bc474f 450 packet_processed++;
nobukuma 0:003889bc474f 451 if (s->State == SocketState_Closing) { //Confirmation of disconnect
nobukuma 0:003889bc474f 452 printf("Remote side confirmed disconnect for socket %d\n", s->ID);
nobukuma 0:003889bc474f 453 s->SetState(SocketState_Closed);
nobukuma 0:003889bc474f 454 break;
nobukuma 0:003889bc474f 455 }
nobukuma 0:003889bc474f 456 printf("Received RFCOMM unnumbered acknowledgement for dlci %u - channel opened\n", dlci);
nobukuma 0:003889bc474f 457 if (s->State == SocketState_L2CAP_Config_wait) {
nobukuma 0:003889bc474f 458 printf("Sending MSC CMD\n");
nobukuma 0:003889bc474f 459 _bt_rfcomm_send_uih_msc_cmd(socket, initiator, dlci, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
nobukuma 0:003889bc474f 460 s->State = SocketState_L2CAP_Config_wait_reqrsp;
nobukuma 0:003889bc474f 461 }
nobukuma 0:003889bc474f 462 break;
nobukuma 0:003889bc474f 463 case BT_RFCOMM_UIH_PF: //user data with credits
nobukuma 0:003889bc474f 464 printf("Got %u credits\n", credits);
nobukuma 0:003889bc474f 465 s->my_credits += credits;
nobukuma 0:003889bc474f 466 //intentional fall-through
nobukuma 0:003889bc474f 467 case BT_RFCOMM_UIH: //user data
nobukuma 0:003889bc474f 468 packet_processed++;
nobukuma 0:003889bc474f 469 if (DEBUG) {
nobukuma 0:003889bc474f 470 printf("RX: address %02x, control %02x: ", addr, control);
nobukuma 0:003889bc474f 471 printHex( payload, length);
nobukuma 0:003889bc474f 472 }
nobukuma 0:003889bc474f 473 if (length) {
nobukuma 0:003889bc474f 474 s->peer_credits--;
nobukuma 0:003889bc474f 475 s->Recv(payload, length);
nobukuma 0:003889bc474f 476 } else
nobukuma 0:003889bc474f 477 printf("Received empty packet\n");
nobukuma 0:003889bc474f 478 if (length == 0 || s->peer_credits == 0) {//send credits when peer runs out
nobukuma 0:003889bc474f 479 //char ini = !(dlci & 1);
nobukuma 0:003889bc474f 480 unsigned char address = (1 << 0) | (initiator << 1) | (dlci << 2);
nobukuma 0:003889bc474f 481 printf("send %d credits to dlci %d\n", NR_CREDITS, addr>>2);
nobukuma 0:003889bc474f 482 rfcomm_send_packet(socket, address, BT_RFCOMM_UIH_PF, NR_CREDITS, NULL, 0);
nobukuma 0:003889bc474f 483 s->peer_credits += NR_CREDITS;
nobukuma 0:003889bc474f 484 }
nobukuma 0:003889bc474f 485 break;
nobukuma 0:003889bc474f 486 case BT_RFCOMM_DISC:
nobukuma 0:003889bc474f 487 packet_processed++;
nobukuma 0:003889bc474f 488 printf("Received DISC IND for dlci %d\n", dlci);
nobukuma 0:003889bc474f 489 rfcomm_send_packet(socket, addr, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection
nobukuma 0:003889bc474f 490 s->SetState(SocketState_Closed);
nobukuma 0:003889bc474f 491 break;
nobukuma 0:003889bc474f 492 case BT_RFCOMM_DM:
nobukuma 0:003889bc474f 493 case BT_RFCOMM_DM_PF:
nobukuma 0:003889bc474f 494 packet_processed++;
nobukuma 0:003889bc474f 495 printf("Received DM IND (%02X) for dlci %d\n", control, dlci);
nobukuma 0:003889bc474f 496 s->SetState(SocketState_Closed);
nobukuma 0:003889bc474f 497 break;
nobukuma 0:003889bc474f 498 default:
nobukuma 0:003889bc474f 499 printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length);
nobukuma 0:003889bc474f 500 }
nobukuma 0:003889bc474f 501 }
nobukuma 0:003889bc474f 502
nobukuma 0:003889bc474f 503 if (!packet_processed) {
nobukuma 0:003889bc474f 504 // just dump data for now
nobukuma 0:003889bc474f 505 printf("??: address %02x, control %02x: ", data[0], data[1]);
nobukuma 0:003889bc474f 506 printHex( data, len );
nobukuma 0:003889bc474f 507 }
nobukuma 0:003889bc474f 508 printf("\x1B[%dm", 0);//reset terminal colour
nobukuma 0:003889bc474f 509 }
nobukuma 0:003889bc474f 510
nobukuma 0:003889bc474f 511 //should make the functions below member functions
nobukuma 0:003889bc474f 512
nobukuma 0:003889bc474f 513 /**
nobukuma 0:003889bc474f 514 * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
nobukuma 0:003889bc474f 515 */
nobukuma 0:003889bc474f 516 /* Questionable optimisation. When OFFSET==8 a buffer is (dynamically) allocated that provides space for the lower
nobukuma 0:003889bc474f 517 layer headers, this reduces copying to, and allocation of, a lower layer buffer. However, all other layers using
nobukuma 0:003889bc474f 518 HCI/L2CAP must do the same.
nobukuma 0:003889bc474f 519 */
nobukuma 0:003889bc474f 520 #define OFFSET 8
nobukuma 0:003889bc474f 521
nobukuma 0:003889bc474f 522 int rfcomm_send_packet(uint16_t source_cid, uint8_t address, uint8_t control, uint8_t credits, const uint8_t *data, uint16_t len) {
nobukuma 0:003889bc474f 523
nobukuma 0:003889bc474f 524 uint16_t pos = OFFSET;
nobukuma 0:003889bc474f 525 uint8_t crc_fields = 3;
nobukuma 0:003889bc474f 526
nobukuma 0:003889bc474f 527 #if OFFSET == 8
nobukuma 0:003889bc474f 528 uint8_t* rfcomm_out_buffer = new uint8_t[OFFSET+len+6];
nobukuma 0:003889bc474f 529 #else
nobukuma 0:003889bc474f 530 static uint8_t rfcomm_out_buffer[MAXFRAMESIZE+6];//seems a bit big as default max framesize is 127
nobukuma 0:003889bc474f 531 #endif
nobukuma 0:003889bc474f 532 rfcomm_out_buffer[pos++] = address;
nobukuma 0:003889bc474f 533 rfcomm_out_buffer[pos++] = control;
nobukuma 0:003889bc474f 534
nobukuma 0:003889bc474f 535 // length field can be 1 or 2 octets
nobukuma 0:003889bc474f 536 if (len < 128) {
nobukuma 0:003889bc474f 537 rfcomm_out_buffer[pos++] = (len << 1)| 1; // bits 0-6
nobukuma 0:003889bc474f 538 } else {
nobukuma 0:003889bc474f 539 rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
nobukuma 0:003889bc474f 540 rfcomm_out_buffer[pos++] = len >> 7; // bits 7-14
nobukuma 0:003889bc474f 541 crc_fields++;
nobukuma 0:003889bc474f 542 }
nobukuma 0:003889bc474f 543
nobukuma 0:003889bc474f 544 // add credits for UIH frames when PF bit is set
nobukuma 0:003889bc474f 545 if (control == BT_RFCOMM_UIH_PF) {
nobukuma 0:003889bc474f 546 rfcomm_out_buffer[pos++] = credits;
nobukuma 0:003889bc474f 547 }
nobukuma 0:003889bc474f 548
nobukuma 0:003889bc474f 549 // copy actual data
nobukuma 0:003889bc474f 550 memcpy(&rfcomm_out_buffer[pos], data, len);
nobukuma 0:003889bc474f 551 pos += len;
nobukuma 0:003889bc474f 552
nobukuma 0:003889bc474f 553 // UIH frames only calc FCS over address + control (5.1.1)
nobukuma 0:003889bc474f 554 if ((control & 0xef) == BT_RFCOMM_UIH) {
nobukuma 0:003889bc474f 555 crc_fields = 2;
nobukuma 0:003889bc474f 556 }
nobukuma 0:003889bc474f 557 rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer+OFFSET, crc_fields); // calc fcs
nobukuma 0:003889bc474f 558 int retval = Socket_Send( source_cid, rfcomm_out_buffer, pos);
nobukuma 0:003889bc474f 559 #if OFFSET == 8
nobukuma 0:003889bc474f 560 delete[] rfcomm_out_buffer;
nobukuma 0:003889bc474f 561 #endif
nobukuma 0:003889bc474f 562 if (retval <= 0)
nobukuma 0:003889bc474f 563 return retval;
nobukuma 0:003889bc474f 564 return len;//return the size of the payload
nobukuma 0:003889bc474f 565 }
nobukuma 0:003889bc474f 566
nobukuma 0:003889bc474f 567 void _bt_rfcomm_send_sabm(uint16_t source_cid, uint8_t initiator, uint8_t dlci) {
nobukuma 0:003889bc474f 568 uint8_t address = (1 << 0) | (initiator << 1) | (dlci << 2);
nobukuma 0:003889bc474f 569 rfcomm_send_packet(source_cid, address, BT_RFCOMM_SABM, 0, NULL, 0);
nobukuma 0:003889bc474f 570 }
nobukuma 0:003889bc474f 571
nobukuma 0:003889bc474f 572 void _bt_rfcomm_send_uih_pn_command(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint16_t max_frame_size) {
nobukuma 0:003889bc474f 573 uint8_t payload[10];
nobukuma 0:003889bc474f 574 uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
nobukuma 0:003889bc474f 575 uint8_t pos = 0;
nobukuma 0:003889bc474f 576 payload[pos++] = BT_RFCOMM_PN_CMD;
nobukuma 0:003889bc474f 577 payload[pos++] = 8 << 1 | 1; // len
nobukuma 0:003889bc474f 578 payload[pos++] = dlci;
nobukuma 0:003889bc474f 579 payload[pos++] = 0xf0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
nobukuma 0:003889bc474f 580 payload[pos++] = 0; // priority
nobukuma 0:003889bc474f 581 payload[pos++] = 0; // max 60 seconds ack
nobukuma 0:003889bc474f 582 payload[pos++] = max_frame_size & 0xff; // max framesize low
nobukuma 0:003889bc474f 583 payload[pos++] = max_frame_size >> 8; // max framesize high
nobukuma 0:003889bc474f 584 payload[pos++] = 0x00; // number of retransmissions
nobukuma 0:003889bc474f 585 payload[pos++] = INITIAL_CREDITS; // unused error recovery window
nobukuma 0:003889bc474f 586 rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
nobukuma 0:003889bc474f 587 }
nobukuma 0:003889bc474f 588
nobukuma 0:003889bc474f 589 void _bt_rfcomm_send_uih_data(uint16_t source_cid, uint8_t initiator, uint8_t channel, uint8_t *data, uint16_t len) {
nobukuma 0:003889bc474f 590 uint8_t address = (1 << 0) | (initiator << 1) | (!initiator << 2) | (channel << 3);
nobukuma 0:003889bc474f 591 rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, data, len);
nobukuma 0:003889bc474f 592 }
nobukuma 0:003889bc474f 593
nobukuma 0:003889bc474f 594 void _bt_rfcomm_send_uih_msc_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint8_t signals) {
nobukuma 0:003889bc474f 595 uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
nobukuma 0:003889bc474f 596 uint8_t payload[5];
nobukuma 0:003889bc474f 597 uint8_t pos = 0;
nobukuma 0:003889bc474f 598 payload[pos++] = BT_RFCOMM_MSC_CMD;
nobukuma 0:003889bc474f 599 payload[pos++] = 2 << 1 | 1; // len, should be adapted when adding break byte
nobukuma 0:003889bc474f 600 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); //C/R is always 1
nobukuma 0:003889bc474f 601 payload[pos++] = signals;
nobukuma 0:003889bc474f 602 // payload[pos++] = brk;
nobukuma 0:003889bc474f 603 rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
nobukuma 0:003889bc474f 604 }
nobukuma 0:003889bc474f 605
nobukuma 0:003889bc474f 606 void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val) {
nobukuma 0:003889bc474f 607 uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
nobukuma 0:003889bc474f 608 uint8_t payload[sizeof(port_settings)+3];
nobukuma 0:003889bc474f 609 uint8_t pos = 0;
nobukuma 0:003889bc474f 610 payload[pos++] = BT_RFCOMM_RPN_CMD;//type
nobukuma 0:003889bc474f 611 if (val) {
nobukuma 0:003889bc474f 612 payload[pos++] = ((1+sizeof(port_settings)) << 1) | 1; // len
nobukuma 0:003889bc474f 613 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2);
nobukuma 0:003889bc474f 614 memcpy(payload+pos, (char*)val, sizeof(port_settings));
nobukuma 0:003889bc474f 615 pos += sizeof(port_settings);
nobukuma 0:003889bc474f 616 } else {
nobukuma 0:003889bc474f 617 payload[pos++] = (1 << 1) | 1; // len
nobukuma 0:003889bc474f 618 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2);
nobukuma 0:003889bc474f 619 }
nobukuma 0:003889bc474f 620 rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
nobukuma 0:003889bc474f 621 }
nobukuma 0:003889bc474f 622
nobukuma 0:003889bc474f 623 int set_remote_port_parameters(int socket, port_settings *p) {
nobukuma 0:003889bc474f 624 RFCOMMSocket* si = (RFCOMMSocket*)GetSocketInternal(socket);//gets the RFCOMM socket
nobukuma 0:003889bc474f 625 if (!si || si->ID != socket)
nobukuma 0:003889bc474f 626 return ERR_SOCKET_NOT_FOUND;
nobukuma 0:003889bc474f 627 return si->serdevice->set_remote_port_parameters(si->dlci, p);
nobukuma 0:003889bc474f 628 }
nobukuma 0:003889bc474f 629
nobukuma 0:003889bc474f 630
nobukuma 0:003889bc474f 631 /*
nobukuma 0:003889bc474f 632 * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
nobukuma 0:003889bc474f 633 */
nobukuma 0:003889bc474f 634 static const uint8_t crc8table[256] = { /* reversed, 8-bit, poly=0x07 */
nobukuma 0:003889bc474f 635 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
nobukuma 0:003889bc474f 636 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
nobukuma 0:003889bc474f 637 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
nobukuma 0:003889bc474f 638 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
nobukuma 0:003889bc474f 639 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
nobukuma 0:003889bc474f 640 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
nobukuma 0:003889bc474f 641 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
nobukuma 0:003889bc474f 642 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
nobukuma 0:003889bc474f 643 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
nobukuma 0:003889bc474f 644 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
nobukuma 0:003889bc474f 645 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
nobukuma 0:003889bc474f 646 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
nobukuma 0:003889bc474f 647 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
nobukuma 0:003889bc474f 648 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
nobukuma 0:003889bc474f 649 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
nobukuma 0:003889bc474f 650 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
nobukuma 0:003889bc474f 651 };
nobukuma 0:003889bc474f 652
nobukuma 0:003889bc474f 653 #define CRC8_INIT 0xFF // Initial FCS value
nobukuma 0:003889bc474f 654 #define CRC8_OK 0xCF // Good final FCS value
nobukuma 0:003889bc474f 655 /*-----------------------------------------------------------------------------------*/
nobukuma 0:003889bc474f 656 uint8_t crc8(uint8_t *data, uint16_t len) {
nobukuma 0:003889bc474f 657 uint16_t count;
nobukuma 0:003889bc474f 658 uint8_t crc = CRC8_INIT;
nobukuma 0:003889bc474f 659 for (count = 0; count < len; count++)
nobukuma 0:003889bc474f 660 crc = crc8table[crc ^ data[count]];
nobukuma 0:003889bc474f 661 return crc;
nobukuma 0:003889bc474f 662 }
nobukuma 0:003889bc474f 663
nobukuma 0:003889bc474f 664 /*-----------------------------------------------------------------------------------*/
nobukuma 0:003889bc474f 665 uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum) {
nobukuma 0:003889bc474f 666 uint8_t crc;
nobukuma 0:003889bc474f 667
nobukuma 0:003889bc474f 668 crc = crc8(data, len);
nobukuma 0:003889bc474f 669
nobukuma 0:003889bc474f 670 crc = crc8table[crc ^ check_sum];
nobukuma 0:003889bc474f 671 if (crc == CRC8_OK)
nobukuma 0:003889bc474f 672 return 0; /* Valid */
nobukuma 0:003889bc474f 673 else
nobukuma 0:003889bc474f 674 return 1; /* Failed */
nobukuma 0:003889bc474f 675
nobukuma 0:003889bc474f 676 }
nobukuma 0:003889bc474f 677
nobukuma 0:003889bc474f 678 /*-----------------------------------------------------------------------------------*/
nobukuma 0:003889bc474f 679 uint8_t crc8_calc(uint8_t *data, uint16_t len) {
nobukuma 0:003889bc474f 680 /* Ones complement */
nobukuma 0:003889bc474f 681 return 0xFF - crc8(data, len);
nobukuma 0:003889bc474f 682 }