うおーるぼっとをWiiリモコンでコントロールする新しいプログラムです。 以前のものより、Wiiリモコンが早く繋がる様になりました。 It is a program which controls A with the Wii remote. ※ A Bluetooth dongle and a Wii remote control are needed.

Dependencies:   USBHost mbed FATFileSystem mbed-rtos

Committer:
jksoft
Date:
Mon Jun 10 16:01:50 2013 +0000
Revision:
0:fccb789424fc
1.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jksoft 0:fccb789424fc 1 /*
jksoft 0:fccb789424fc 2 * Copyright (C) 2009-2012 by Matthias Ringwald
jksoft 0:fccb789424fc 3 *
jksoft 0:fccb789424fc 4 * Redistribution and use in source and binary forms, with or without
jksoft 0:fccb789424fc 5 * modification, are permitted provided that the following conditions
jksoft 0:fccb789424fc 6 * are met:
jksoft 0:fccb789424fc 7 *
jksoft 0:fccb789424fc 8 * 1. Redistributions of source code must retain the above copyright
jksoft 0:fccb789424fc 9 * notice, this list of conditions and the following disclaimer.
jksoft 0:fccb789424fc 10 * 2. Redistributions in binary form must reproduce the above copyright
jksoft 0:fccb789424fc 11 * notice, this list of conditions and the following disclaimer in the
jksoft 0:fccb789424fc 12 * documentation and/or other materials provided with the distribution.
jksoft 0:fccb789424fc 13 * 3. Neither the name of the copyright holders nor the names of
jksoft 0:fccb789424fc 14 * contributors may be used to endorse or promote products derived
jksoft 0:fccb789424fc 15 * from this software without specific prior written permission.
jksoft 0:fccb789424fc 16 * 4. Any redistribution, use, or modification is done solely for
jksoft 0:fccb789424fc 17 * personal benefit and not for any commercial purpose or for
jksoft 0:fccb789424fc 18 * monetary gain.
jksoft 0:fccb789424fc 19 *
jksoft 0:fccb789424fc 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
jksoft 0:fccb789424fc 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
jksoft 0:fccb789424fc 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
jksoft 0:fccb789424fc 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
jksoft 0:fccb789424fc 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
jksoft 0:fccb789424fc 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
jksoft 0:fccb789424fc 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
jksoft 0:fccb789424fc 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
jksoft 0:fccb789424fc 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
jksoft 0:fccb789424fc 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
jksoft 0:fccb789424fc 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
jksoft 0:fccb789424fc 31 * SUCH DAMAGE.
jksoft 0:fccb789424fc 32 *
jksoft 0:fccb789424fc 33 * Please inquire about commercial licensing options at btstack@ringwald.ch
jksoft 0:fccb789424fc 34 *
jksoft 0:fccb789424fc 35 */
jksoft 0:fccb789424fc 36
jksoft 0:fccb789424fc 37 /*
jksoft 0:fccb789424fc 38 * rfcomm.c
jksoft 0:fccb789424fc 39 */
jksoft 0:fccb789424fc 40
jksoft 0:fccb789424fc 41 #include <stdio.h>
jksoft 0:fccb789424fc 42 #include <stdlib.h>
jksoft 0:fccb789424fc 43 #include <string.h> // memcpy
jksoft 0:fccb789424fc 44 #include <stdint.h>
jksoft 0:fccb789424fc 45
jksoft 0:fccb789424fc 46 #include <btstack/btstack.h>
jksoft 0:fccb789424fc 47 #include <btstack/hci_cmds.h>
jksoft 0:fccb789424fc 48 #include <btstack/utils.h>
jksoft 0:fccb789424fc 49
jksoft 0:fccb789424fc 50 #include <btstack/utils.h>
jksoft 0:fccb789424fc 51 #include "btstack_memory.h"
jksoft 0:fccb789424fc 52 #include "hci.h"
jksoft 0:fccb789424fc 53 #include "hci_dump.h"
jksoft 0:fccb789424fc 54 #include "debug.h"
jksoft 0:fccb789424fc 55 #include "rfcomm.h"
jksoft 0:fccb789424fc 56
jksoft 0:fccb789424fc 57 // workaround for missing PRIxPTR on mspgcc (16/20-bit MCU)
jksoft 0:fccb789424fc 58 #ifndef PRIxPTR
jksoft 0:fccb789424fc 59 #if defined(__MSP430X__) && defined(__MSP430X_LARGE__)
jksoft 0:fccb789424fc 60 #define PRIxPTR "lx"
jksoft 0:fccb789424fc 61 #else
jksoft 0:fccb789424fc 62 #define PRIxPTR "x"
jksoft 0:fccb789424fc 63 #endif
jksoft 0:fccb789424fc 64 #endif
jksoft 0:fccb789424fc 65
jksoft 0:fccb789424fc 66
jksoft 0:fccb789424fc 67 // Control field values bit no. 1 2 3 4 PF 6 7 8
jksoft 0:fccb789424fc 68 #define BT_RFCOMM_SABM 0x3F // 1 1 1 1 1 1 0 0
jksoft 0:fccb789424fc 69 #define BT_RFCOMM_UA 0x73 // 1 1 0 0 1 1 1 0
jksoft 0:fccb789424fc 70 #define BT_RFCOMM_DM 0x0F // 1 1 1 1 0 0 0 0
jksoft 0:fccb789424fc 71 #define BT_RFCOMM_DM_PF 0x1F // 1 1 1 1 1 0 0 0
jksoft 0:fccb789424fc 72 #define BT_RFCOMM_DISC 0x53 // 1 1 0 0 1 0 1 0
jksoft 0:fccb789424fc 73 #define BT_RFCOMM_UIH 0xEF // 1 1 1 1 0 1 1 1
jksoft 0:fccb789424fc 74 #define BT_RFCOMM_UIH_PF 0xFF // 1 1 1 1 0 1 1 1
jksoft 0:fccb789424fc 75
jksoft 0:fccb789424fc 76 // Multiplexer message types
jksoft 0:fccb789424fc 77 #define BT_RFCOMM_CLD_CMD 0xC3
jksoft 0:fccb789424fc 78 #define BT_RFCOMM_FCON_CMD 0xA3
jksoft 0:fccb789424fc 79 #define BT_RFCOMM_FCON_RSP 0xA1
jksoft 0:fccb789424fc 80 #define BT_RFCOMM_FCOFF_CMD 0x63
jksoft 0:fccb789424fc 81 #define BT_RFCOMM_FCOFF_RSP 0x61
jksoft 0:fccb789424fc 82 #define BT_RFCOMM_MSC_CMD 0xE3
jksoft 0:fccb789424fc 83 #define BT_RFCOMM_MSC_RSP 0xE1
jksoft 0:fccb789424fc 84 #define BT_RFCOMM_NSC_RSP 0x11
jksoft 0:fccb789424fc 85 #define BT_RFCOMM_PN_CMD 0x83
jksoft 0:fccb789424fc 86 #define BT_RFCOMM_PN_RSP 0x81
jksoft 0:fccb789424fc 87 #define BT_RFCOMM_RLS_CMD 0x53
jksoft 0:fccb789424fc 88 #define BT_RFCOMM_RLS_RSP 0x51
jksoft 0:fccb789424fc 89 #define BT_RFCOMM_RPN_CMD 0x93
jksoft 0:fccb789424fc 90 #define BT_RFCOMM_RPN_RSP 0x91
jksoft 0:fccb789424fc 91 #define BT_RFCOMM_TEST_CMD 0x23
jksoft 0:fccb789424fc 92 #define BT_RFCOMM_TEST_RSP 0x21
jksoft 0:fccb789424fc 93
jksoft 0:fccb789424fc 94 #define RFCOMM_MULIPLEXER_TIMEOUT_MS 60000
jksoft 0:fccb789424fc 95
jksoft 0:fccb789424fc 96 // FCS calc
jksoft 0:fccb789424fc 97 #define BT_RFCOMM_CODE_WORD 0xE0 // pol = x8+x2+x1+1
jksoft 0:fccb789424fc 98 #define BT_RFCOMM_CRC_CHECK_LEN 3
jksoft 0:fccb789424fc 99 #define BT_RFCOMM_UIHCRC_CHECK_LEN 2
jksoft 0:fccb789424fc 100
jksoft 0:fccb789424fc 101 #include "l2cap.h"
jksoft 0:fccb789424fc 102
jksoft 0:fccb789424fc 103 // used for debugging
jksoft 0:fccb789424fc 104 // #define RFCOMM_LOG_CREDITS
jksoft 0:fccb789424fc 105
jksoft 0:fccb789424fc 106 // global rfcomm data
jksoft 0:fccb789424fc 107 static uint16_t rfcomm_client_cid_generator; // used for client channel IDs
jksoft 0:fccb789424fc 108
jksoft 0:fccb789424fc 109 // linked lists for all
jksoft 0:fccb789424fc 110 static linked_list_t rfcomm_multiplexers = NULL;
jksoft 0:fccb789424fc 111 static linked_list_t rfcomm_channels = NULL;
jksoft 0:fccb789424fc 112 static linked_list_t rfcomm_services = NULL;
jksoft 0:fccb789424fc 113
jksoft 0:fccb789424fc 114 static void (*app_packet_handler)(void * connection, uint8_t packet_type,
jksoft 0:fccb789424fc 115 uint16_t channel, uint8_t *packet, uint16_t size);
jksoft 0:fccb789424fc 116
jksoft 0:fccb789424fc 117 static void rfcomm_run(void);
jksoft 0:fccb789424fc 118 static void rfcomm_hand_out_credits(void);
jksoft 0:fccb789424fc 119 static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event);
jksoft 0:fccb789424fc 120 static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event);
jksoft 0:fccb789424fc 121 static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel);
jksoft 0:fccb789424fc 122 static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event);
jksoft 0:fccb789424fc 123
jksoft 0:fccb789424fc 124
jksoft 0:fccb789424fc 125 // MARK: RFCOMM CLIENT EVENTS
jksoft 0:fccb789424fc 126
jksoft 0:fccb789424fc 127 // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
jksoft 0:fccb789424fc 128 static void rfcomm_emit_connection_request(rfcomm_channel_t *channel) {
jksoft 0:fccb789424fc 129 uint8_t event[11];
jksoft 0:fccb789424fc 130 event[0] = RFCOMM_EVENT_INCOMING_CONNECTION;
jksoft 0:fccb789424fc 131 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 132 bt_flip_addr(&event[2], channel->multiplexer->remote_addr);
jksoft 0:fccb789424fc 133 event[8] = channel->dlci >> 1;
jksoft 0:fccb789424fc 134 bt_store_16(event, 9, channel->rfcomm_cid);
jksoft 0:fccb789424fc 135 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 136 (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
jksoft 0:fccb789424fc 137 }
jksoft 0:fccb789424fc 138
jksoft 0:fccb789424fc 139 // API Change: BTstack-0.3.50x uses
jksoft 0:fccb789424fc 140 // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
jksoft 0:fccb789424fc 141 // next Cydia release will use SVN version of this
jksoft 0:fccb789424fc 142 // data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
jksoft 0:fccb789424fc 143 static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status) {
jksoft 0:fccb789424fc 144 uint8_t event[16];
jksoft 0:fccb789424fc 145 uint8_t pos = 0;
jksoft 0:fccb789424fc 146 event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
jksoft 0:fccb789424fc 147 event[pos++] = sizeof(event) - 2;
jksoft 0:fccb789424fc 148 event[pos++] = status;
jksoft 0:fccb789424fc 149 bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
jksoft 0:fccb789424fc 150 bt_store_16(event, pos, channel->multiplexer->con_handle); pos += 2;
jksoft 0:fccb789424fc 151 event[pos++] = channel->dlci >> 1;
jksoft 0:fccb789424fc 152 bt_store_16(event, pos, channel->rfcomm_cid); pos += 2; // channel ID
jksoft 0:fccb789424fc 153 bt_store_16(event, pos, channel->max_frame_size); pos += 2; // max frame size
jksoft 0:fccb789424fc 154 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 155 (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
jksoft 0:fccb789424fc 156 }
jksoft 0:fccb789424fc 157
jksoft 0:fccb789424fc 158 static void rfcomm_emit_channel_open_failed_outgoing_memory(void * connection, bd_addr_t *addr, uint8_t server_channel){
jksoft 0:fccb789424fc 159 uint8_t event[16];
jksoft 0:fccb789424fc 160 uint8_t pos = 0;
jksoft 0:fccb789424fc 161 event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
jksoft 0:fccb789424fc 162 event[pos++] = sizeof(event) - 2;
jksoft 0:fccb789424fc 163 event[pos++] = BTSTACK_MEMORY_ALLOC_FAILED;
jksoft 0:fccb789424fc 164 bt_flip_addr(&event[pos], *addr); pos += 6;
jksoft 0:fccb789424fc 165 bt_store_16(event, pos, 0); pos += 2;
jksoft 0:fccb789424fc 166 event[pos++] = server_channel;
jksoft 0:fccb789424fc 167 bt_store_16(event, pos, 0); pos += 2; // channel ID
jksoft 0:fccb789424fc 168 bt_store_16(event, pos, 0); pos += 2; // max frame size
jksoft 0:fccb789424fc 169 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 170 (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
jksoft 0:fccb789424fc 171 }
jksoft 0:fccb789424fc 172
jksoft 0:fccb789424fc 173 // data: event(8), len(8), creidts incoming(8), new credits incoming(8), credits outgoing(8)
jksoft 0:fccb789424fc 174 static inline void rfcomm_emit_credit_status(rfcomm_channel_t * channel) {
jksoft 0:fccb789424fc 175 #ifdef RFCOMM_LOG_CREDITS
jksoft 0:fccb789424fc 176 uint8_t event[5];
jksoft 0:fccb789424fc 177 event[0] = 0x88;
jksoft 0:fccb789424fc 178 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 179 event[2] = channel->credits_incoming;
jksoft 0:fccb789424fc 180 event[3] = channel->new_credits_incoming;
jksoft 0:fccb789424fc 181 event[4] = channel->credits_outgoing;
jksoft 0:fccb789424fc 182 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 183 #endif
jksoft 0:fccb789424fc 184 }
jksoft 0:fccb789424fc 185
jksoft 0:fccb789424fc 186 // data: event(8), len(8), rfcomm_cid(16)
jksoft 0:fccb789424fc 187 static void rfcomm_emit_channel_closed(rfcomm_channel_t * channel) {
jksoft 0:fccb789424fc 188 uint8_t event[4];
jksoft 0:fccb789424fc 189 event[0] = RFCOMM_EVENT_CHANNEL_CLOSED;
jksoft 0:fccb789424fc 190 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 191 bt_store_16(event, 2, channel->rfcomm_cid);
jksoft 0:fccb789424fc 192 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 193 (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
jksoft 0:fccb789424fc 194 }
jksoft 0:fccb789424fc 195
jksoft 0:fccb789424fc 196 static void rfcomm_emit_credits(rfcomm_channel_t * channel, uint8_t credits) {
jksoft 0:fccb789424fc 197 uint8_t event[5];
jksoft 0:fccb789424fc 198 event[0] = RFCOMM_EVENT_CREDITS;
jksoft 0:fccb789424fc 199 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 200 bt_store_16(event, 2, channel->rfcomm_cid);
jksoft 0:fccb789424fc 201 event[4] = credits;
jksoft 0:fccb789424fc 202 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 203 (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
jksoft 0:fccb789424fc 204 }
jksoft 0:fccb789424fc 205
jksoft 0:fccb789424fc 206 static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
jksoft 0:fccb789424fc 207 uint8_t event[4];
jksoft 0:fccb789424fc 208 event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
jksoft 0:fccb789424fc 209 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 210 event[2] = status;
jksoft 0:fccb789424fc 211 event[3] = channel;
jksoft 0:fccb789424fc 212 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 213 (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
jksoft 0:fccb789424fc 214 }
jksoft 0:fccb789424fc 215
jksoft 0:fccb789424fc 216 // MARK: RFCOMM MULTIPLEXER HELPER
jksoft 0:fccb789424fc 217
jksoft 0:fccb789424fc 218 static uint16_t rfcomm_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
jksoft 0:fccb789424fc 219
jksoft 0:fccb789424fc 220 // Assume RFCOMM header with credits and single byte length field
jksoft 0:fccb789424fc 221 uint16_t max_frame_size = l2cap_mtu - 5;
jksoft 0:fccb789424fc 222
jksoft 0:fccb789424fc 223 // single byte can denote len up to 127
jksoft 0:fccb789424fc 224 if (max_frame_size > 127) {
jksoft 0:fccb789424fc 225 max_frame_size--;
jksoft 0:fccb789424fc 226 }
jksoft 0:fccb789424fc 227
jksoft 0:fccb789424fc 228 log_info("rfcomm_max_frame_size_for_l2cap_mtu: %u -> %u\n", l2cap_mtu, max_frame_size);
jksoft 0:fccb789424fc 229 return max_frame_size;
jksoft 0:fccb789424fc 230 }
jksoft 0:fccb789424fc 231
jksoft 0:fccb789424fc 232 static void rfcomm_multiplexer_initialize(rfcomm_multiplexer_t *multiplexer){
jksoft 0:fccb789424fc 233
jksoft 0:fccb789424fc 234 memset(multiplexer, 0, sizeof(rfcomm_multiplexer_t));
jksoft 0:fccb789424fc 235
jksoft 0:fccb789424fc 236 multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
jksoft 0:fccb789424fc 237 multiplexer->l2cap_credits = 0;
jksoft 0:fccb789424fc 238 multiplexer->send_dm_for_dlci = 0;
jksoft 0:fccb789424fc 239 multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
jksoft 0:fccb789424fc 240 }
jksoft 0:fccb789424fc 241
jksoft 0:fccb789424fc 242 static rfcomm_multiplexer_t * rfcomm_multiplexer_create_for_addr(bd_addr_t *addr){
jksoft 0:fccb789424fc 243
jksoft 0:fccb789424fc 244 // alloc structure
jksoft 0:fccb789424fc 245 rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t*)btstack_memory_rfcomm_multiplexer_get();
jksoft 0:fccb789424fc 246 if (!multiplexer) return NULL;
jksoft 0:fccb789424fc 247
jksoft 0:fccb789424fc 248 // fill in
jksoft 0:fccb789424fc 249 rfcomm_multiplexer_initialize(multiplexer);
jksoft 0:fccb789424fc 250 BD_ADDR_COPY(&multiplexer->remote_addr, addr);
jksoft 0:fccb789424fc 251
jksoft 0:fccb789424fc 252 // add to services list
jksoft 0:fccb789424fc 253 linked_list_add(&rfcomm_multiplexers, (linked_item_t *) multiplexer);
jksoft 0:fccb789424fc 254
jksoft 0:fccb789424fc 255 return multiplexer;
jksoft 0:fccb789424fc 256 }
jksoft 0:fccb789424fc 257
jksoft 0:fccb789424fc 258 static rfcomm_multiplexer_t * rfcomm_multiplexer_for_addr(bd_addr_t *addr){
jksoft 0:fccb789424fc 259 linked_item_t *it;
jksoft 0:fccb789424fc 260 for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
jksoft 0:fccb789424fc 261 rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
jksoft 0:fccb789424fc 262 if (BD_ADDR_CMP(addr, multiplexer->remote_addr) == 0) {
jksoft 0:fccb789424fc 263 return multiplexer;
jksoft 0:fccb789424fc 264 };
jksoft 0:fccb789424fc 265 }
jksoft 0:fccb789424fc 266 return NULL;
jksoft 0:fccb789424fc 267 }
jksoft 0:fccb789424fc 268
jksoft 0:fccb789424fc 269 static rfcomm_multiplexer_t * rfcomm_multiplexer_for_l2cap_cid(uint16_t l2cap_cid) {
jksoft 0:fccb789424fc 270 linked_item_t *it;
jksoft 0:fccb789424fc 271 for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
jksoft 0:fccb789424fc 272 rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
jksoft 0:fccb789424fc 273 if (multiplexer->l2cap_cid == l2cap_cid) {
jksoft 0:fccb789424fc 274 return multiplexer;
jksoft 0:fccb789424fc 275 };
jksoft 0:fccb789424fc 276 }
jksoft 0:fccb789424fc 277 return NULL;
jksoft 0:fccb789424fc 278 }
jksoft 0:fccb789424fc 279
jksoft 0:fccb789424fc 280 static int rfcomm_multiplexer_has_channels(rfcomm_multiplexer_t * multiplexer){
jksoft 0:fccb789424fc 281 linked_item_t *it;
jksoft 0:fccb789424fc 282 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 283 rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
jksoft 0:fccb789424fc 284 if (channel->multiplexer == multiplexer) {
jksoft 0:fccb789424fc 285 return 1;
jksoft 0:fccb789424fc 286 }
jksoft 0:fccb789424fc 287 }
jksoft 0:fccb789424fc 288 return 0;
jksoft 0:fccb789424fc 289 }
jksoft 0:fccb789424fc 290
jksoft 0:fccb789424fc 291 // MARK: RFCOMM CHANNEL HELPER
jksoft 0:fccb789424fc 292
jksoft 0:fccb789424fc 293 static void rfcomm_dump_channels(void){
jksoft 0:fccb789424fc 294 #ifndef EMBEDDED
jksoft 0:fccb789424fc 295 linked_item_t * it;
jksoft 0:fccb789424fc 296 int channels = 0;
jksoft 0:fccb789424fc 297 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 298 rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
jksoft 0:fccb789424fc 299 log_info("Channel #%u: addr %p, state %u\n", channels, channel, channel->state);
jksoft 0:fccb789424fc 300 channels++;
jksoft 0:fccb789424fc 301 }
jksoft 0:fccb789424fc 302 #endif
jksoft 0:fccb789424fc 303 }
jksoft 0:fccb789424fc 304
jksoft 0:fccb789424fc 305 static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer,
jksoft 0:fccb789424fc 306 rfcomm_service_t *service, uint8_t server_channel){
jksoft 0:fccb789424fc 307
jksoft 0:fccb789424fc 308 // don't use 0 as channel id
jksoft 0:fccb789424fc 309 if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
jksoft 0:fccb789424fc 310
jksoft 0:fccb789424fc 311 // setup channel
jksoft 0:fccb789424fc 312 memset(channel, 0, sizeof(rfcomm_channel_t));
jksoft 0:fccb789424fc 313
jksoft 0:fccb789424fc 314 channel->state = RFCOMM_CHANNEL_CLOSED;
jksoft 0:fccb789424fc 315 channel->state_var = RFCOMM_CHANNEL_STATE_VAR_NONE;
jksoft 0:fccb789424fc 316
jksoft 0:fccb789424fc 317 channel->multiplexer = multiplexer;
jksoft 0:fccb789424fc 318 channel->service = service;
jksoft 0:fccb789424fc 319 channel->rfcomm_cid = rfcomm_client_cid_generator++;
jksoft 0:fccb789424fc 320 channel->max_frame_size = multiplexer->max_frame_size;
jksoft 0:fccb789424fc 321
jksoft 0:fccb789424fc 322 channel->credits_incoming = 0;
jksoft 0:fccb789424fc 323 channel->credits_outgoing = 0;
jksoft 0:fccb789424fc 324 channel->packets_granted = 0;
jksoft 0:fccb789424fc 325
jksoft 0:fccb789424fc 326 // incoming flow control not active
jksoft 0:fccb789424fc 327 channel->new_credits_incoming = 0x30;
jksoft 0:fccb789424fc 328 channel->incoming_flow_control = 0;
jksoft 0:fccb789424fc 329
jksoft 0:fccb789424fc 330 if (service) {
jksoft 0:fccb789424fc 331 // incoming connection
jksoft 0:fccb789424fc 332 channel->outgoing = 0;
jksoft 0:fccb789424fc 333 channel->dlci = (server_channel << 1) | multiplexer->outgoing;
jksoft 0:fccb789424fc 334 if (channel->max_frame_size > service->max_frame_size) {
jksoft 0:fccb789424fc 335 channel->max_frame_size = service->max_frame_size;
jksoft 0:fccb789424fc 336 }
jksoft 0:fccb789424fc 337 channel->incoming_flow_control = service->incoming_flow_control;
jksoft 0:fccb789424fc 338 channel->new_credits_incoming = service->incoming_initial_credits;
jksoft 0:fccb789424fc 339 } else {
jksoft 0:fccb789424fc 340 // outgoing connection
jksoft 0:fccb789424fc 341 channel->outgoing = 1;
jksoft 0:fccb789424fc 342 channel->dlci = (server_channel << 1) | (multiplexer->outgoing ^ 1);
jksoft 0:fccb789424fc 343 }
jksoft 0:fccb789424fc 344 }
jksoft 0:fccb789424fc 345
jksoft 0:fccb789424fc 346 // service == NULL -> outgoing channel
jksoft 0:fccb789424fc 347 static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
jksoft 0:fccb789424fc 348 rfcomm_service_t * service, uint8_t server_channel){
jksoft 0:fccb789424fc 349
jksoft 0:fccb789424fc 350 log_info("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
jksoft 0:fccb789424fc 351 rfcomm_dump_channels();
jksoft 0:fccb789424fc 352
jksoft 0:fccb789424fc 353 // alloc structure
jksoft 0:fccb789424fc 354 rfcomm_channel_t * channel = (rfcomm_channel_t*)btstack_memory_rfcomm_channel_get();
jksoft 0:fccb789424fc 355 if (!channel) return NULL;
jksoft 0:fccb789424fc 356
jksoft 0:fccb789424fc 357 // fill in
jksoft 0:fccb789424fc 358 rfcomm_channel_initialize(channel, multiplexer, service, server_channel);
jksoft 0:fccb789424fc 359
jksoft 0:fccb789424fc 360 // add to services list
jksoft 0:fccb789424fc 361 linked_list_add(&rfcomm_channels, (linked_item_t *) channel);
jksoft 0:fccb789424fc 362
jksoft 0:fccb789424fc 363 return channel;
jksoft 0:fccb789424fc 364 }
jksoft 0:fccb789424fc 365
jksoft 0:fccb789424fc 366 static rfcomm_channel_t * rfcomm_channel_for_rfcomm_cid(uint16_t rfcomm_cid){
jksoft 0:fccb789424fc 367 linked_item_t *it;
jksoft 0:fccb789424fc 368 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 369 rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
jksoft 0:fccb789424fc 370 if (channel->rfcomm_cid == rfcomm_cid) {
jksoft 0:fccb789424fc 371 return channel;
jksoft 0:fccb789424fc 372 };
jksoft 0:fccb789424fc 373 }
jksoft 0:fccb789424fc 374 return NULL;
jksoft 0:fccb789424fc 375 }
jksoft 0:fccb789424fc 376
jksoft 0:fccb789424fc 377 static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multiplexer_t * multiplexer, uint8_t dlci){
jksoft 0:fccb789424fc 378 linked_item_t *it;
jksoft 0:fccb789424fc 379 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 380 rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
jksoft 0:fccb789424fc 381 if (channel->dlci == dlci && channel->multiplexer == multiplexer) {
jksoft 0:fccb789424fc 382 return channel;
jksoft 0:fccb789424fc 383 };
jksoft 0:fccb789424fc 384 }
jksoft 0:fccb789424fc 385 return NULL;
jksoft 0:fccb789424fc 386 }
jksoft 0:fccb789424fc 387
jksoft 0:fccb789424fc 388 static rfcomm_service_t * rfcomm_service_for_channel(uint8_t server_channel){
jksoft 0:fccb789424fc 389 linked_item_t *it;
jksoft 0:fccb789424fc 390 for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
jksoft 0:fccb789424fc 391 rfcomm_service_t * service = ((rfcomm_service_t *) it);
jksoft 0:fccb789424fc 392 if ( service->server_channel == server_channel){
jksoft 0:fccb789424fc 393 return service;
jksoft 0:fccb789424fc 394 };
jksoft 0:fccb789424fc 395 }
jksoft 0:fccb789424fc 396 return NULL;
jksoft 0:fccb789424fc 397 }
jksoft 0:fccb789424fc 398
jksoft 0:fccb789424fc 399 // MARK: RFCOMM SEND
jksoft 0:fccb789424fc 400
jksoft 0:fccb789424fc 401 /**
jksoft 0:fccb789424fc 402 * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
jksoft 0:fccb789424fc 403 */
jksoft 0:fccb789424fc 404 static int rfcomm_send_packet_for_multiplexer(rfcomm_multiplexer_t *multiplexer, uint8_t address, uint8_t control, uint8_t credits, uint8_t *data, uint16_t len){
jksoft 0:fccb789424fc 405
jksoft 0:fccb789424fc 406 if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) return BTSTACK_ACL_BUFFERS_FULL;
jksoft 0:fccb789424fc 407
jksoft 0:fccb789424fc 408 uint8_t * rfcomm_out_buffer = l2cap_get_outgoing_buffer();
jksoft 0:fccb789424fc 409
jksoft 0:fccb789424fc 410 uint16_t pos = 0;
jksoft 0:fccb789424fc 411 uint8_t crc_fields = 3;
jksoft 0:fccb789424fc 412
jksoft 0:fccb789424fc 413 rfcomm_out_buffer[pos++] = address;
jksoft 0:fccb789424fc 414 rfcomm_out_buffer[pos++] = control;
jksoft 0:fccb789424fc 415
jksoft 0:fccb789424fc 416 // length field can be 1 or 2 octets
jksoft 0:fccb789424fc 417 if (len < 128){
jksoft 0:fccb789424fc 418 rfcomm_out_buffer[pos++] = (len << 1)| 1; // bits 0-6
jksoft 0:fccb789424fc 419 } else {
jksoft 0:fccb789424fc 420 rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
jksoft 0:fccb789424fc 421 rfcomm_out_buffer[pos++] = len >> 7; // bits 7-14
jksoft 0:fccb789424fc 422 crc_fields++;
jksoft 0:fccb789424fc 423 }
jksoft 0:fccb789424fc 424
jksoft 0:fccb789424fc 425 // add credits for UIH frames when PF bit is set
jksoft 0:fccb789424fc 426 if (control == BT_RFCOMM_UIH_PF){
jksoft 0:fccb789424fc 427 rfcomm_out_buffer[pos++] = credits;
jksoft 0:fccb789424fc 428 }
jksoft 0:fccb789424fc 429
jksoft 0:fccb789424fc 430 // copy actual data
jksoft 0:fccb789424fc 431 if (len) {
jksoft 0:fccb789424fc 432 memcpy(&rfcomm_out_buffer[pos], data, len);
jksoft 0:fccb789424fc 433 pos += len;
jksoft 0:fccb789424fc 434 }
jksoft 0:fccb789424fc 435
jksoft 0:fccb789424fc 436 // UIH frames only calc FCS over address + control (5.1.1)
jksoft 0:fccb789424fc 437 if ((control & 0xef) == BT_RFCOMM_UIH){
jksoft 0:fccb789424fc 438 crc_fields = 2;
jksoft 0:fccb789424fc 439 }
jksoft 0:fccb789424fc 440 rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer, crc_fields); // calc fcs
jksoft 0:fccb789424fc 441
jksoft 0:fccb789424fc 442 int credits_taken = 0;
jksoft 0:fccb789424fc 443 if (multiplexer->l2cap_credits){
jksoft 0:fccb789424fc 444 credits_taken++;
jksoft 0:fccb789424fc 445 multiplexer->l2cap_credits--;
jksoft 0:fccb789424fc 446 } else {
jksoft 0:fccb789424fc 447 log_info( "rfcomm_send_packet addr %02x, ctrl %02x size %u without l2cap credits\n", address, control, pos);
jksoft 0:fccb789424fc 448 }
jksoft 0:fccb789424fc 449
jksoft 0:fccb789424fc 450 int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
jksoft 0:fccb789424fc 451
jksoft 0:fccb789424fc 452 if (err) {
jksoft 0:fccb789424fc 453 // undo credit counting
jksoft 0:fccb789424fc 454 multiplexer->l2cap_credits += credits_taken;
jksoft 0:fccb789424fc 455 }
jksoft 0:fccb789424fc 456 return err;
jksoft 0:fccb789424fc 457 }
jksoft 0:fccb789424fc 458
jksoft 0:fccb789424fc 459 // C/R Flag in Address
jksoft 0:fccb789424fc 460 // - terms: initiator = station that creates multiplexer with SABM
jksoft 0:fccb789424fc 461 // - terms: responder = station that responds to multiplexer setup with UA
jksoft 0:fccb789424fc 462 // "For SABM, UA, DM and DISC frames C/R bit is set according to Table 1 in GSM 07.10, section 5.2.1.2"
jksoft 0:fccb789424fc 463 // - command initiator = 1 /response responder = 1
jksoft 0:fccb789424fc 464 // - command responder = 0 /response initiator = 0
jksoft 0:fccb789424fc 465 // "For UIH frames, the C/R bit is always set according to section 5.4.3.1 in GSM 07.10.
jksoft 0:fccb789424fc 466 // This applies independently of what is contained wthin the UIH frames, either data or control messages."
jksoft 0:fccb789424fc 467 // - c/r = 1 for frames by initiating station, 0 = for frames by responding station
jksoft 0:fccb789424fc 468
jksoft 0:fccb789424fc 469 // C/R Flag in Message
jksoft 0:fccb789424fc 470 // "In the message level, the C/R bit in the command type field is set as stated in section 5.4.6.2 in GSM 07.10."
jksoft 0:fccb789424fc 471 // - If the C/R bit is set to 1 the message is a command
jksoft 0:fccb789424fc 472 // - if it is set to 0 the message is a response.
jksoft 0:fccb789424fc 473
jksoft 0:fccb789424fc 474 // temp/old messge construction
jksoft 0:fccb789424fc 475
jksoft 0:fccb789424fc 476 // new object oriented version
jksoft 0:fccb789424fc 477 static int rfcomm_send_sabm(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
jksoft 0:fccb789424fc 478 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2); // command
jksoft 0:fccb789424fc 479 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_SABM, 0, NULL, 0);
jksoft 0:fccb789424fc 480 }
jksoft 0:fccb789424fc 481
jksoft 0:fccb789424fc 482 static int rfcomm_send_disc(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
jksoft 0:fccb789424fc 483 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2); // command
jksoft 0:fccb789424fc 484 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DISC, 0, NULL, 0);
jksoft 0:fccb789424fc 485 }
jksoft 0:fccb789424fc 486
jksoft 0:fccb789424fc 487 static int rfcomm_send_ua(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
jksoft 0:fccb789424fc 488 uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
jksoft 0:fccb789424fc 489 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UA, 0, NULL, 0);
jksoft 0:fccb789424fc 490 }
jksoft 0:fccb789424fc 491
jksoft 0:fccb789424fc 492 static int rfcomm_send_dm_pf(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
jksoft 0:fccb789424fc 493 uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
jksoft 0:fccb789424fc 494 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DM_PF, 0, NULL, 0);
jksoft 0:fccb789424fc 495 }
jksoft 0:fccb789424fc 496
jksoft 0:fccb789424fc 497 static int rfcomm_send_uih_msc_cmd(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
jksoft 0:fccb789424fc 498 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
jksoft 0:fccb789424fc 499 uint8_t payload[4];
jksoft 0:fccb789424fc 500 uint8_t pos = 0;
jksoft 0:fccb789424fc 501 payload[pos++] = BT_RFCOMM_MSC_CMD;
jksoft 0:fccb789424fc 502 payload[pos++] = 2 << 1 | 1; // len
jksoft 0:fccb789424fc 503 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
jksoft 0:fccb789424fc 504 payload[pos++] = signals;
jksoft 0:fccb789424fc 505 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
jksoft 0:fccb789424fc 506 }
jksoft 0:fccb789424fc 507
jksoft 0:fccb789424fc 508 static int rfcomm_send_uih_msc_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
jksoft 0:fccb789424fc 509 uint8_t address = (1 << 0) | (multiplexer->outgoing<< 1);
jksoft 0:fccb789424fc 510 uint8_t payload[4];
jksoft 0:fccb789424fc 511 uint8_t pos = 0;
jksoft 0:fccb789424fc 512 payload[pos++] = BT_RFCOMM_MSC_RSP;
jksoft 0:fccb789424fc 513 payload[pos++] = 2 << 1 | 1; // len
jksoft 0:fccb789424fc 514 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
jksoft 0:fccb789424fc 515 payload[pos++] = signals;
jksoft 0:fccb789424fc 516 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
jksoft 0:fccb789424fc 517 }
jksoft 0:fccb789424fc 518
jksoft 0:fccb789424fc 519 static int rfcomm_send_uih_pn_command(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint16_t max_frame_size){
jksoft 0:fccb789424fc 520 uint8_t payload[10];
jksoft 0:fccb789424fc 521 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
jksoft 0:fccb789424fc 522 uint8_t pos = 0;
jksoft 0:fccb789424fc 523 payload[pos++] = BT_RFCOMM_PN_CMD;
jksoft 0:fccb789424fc 524 payload[pos++] = 8 << 1 | 1; // len
jksoft 0:fccb789424fc 525 payload[pos++] = dlci;
jksoft 0:fccb789424fc 526 payload[pos++] = 0xf0; // pre-defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
jksoft 0:fccb789424fc 527 payload[pos++] = 0; // priority
jksoft 0:fccb789424fc 528 payload[pos++] = 0; // max 60 seconds ack
jksoft 0:fccb789424fc 529 payload[pos++] = max_frame_size & 0xff; // max framesize low
jksoft 0:fccb789424fc 530 payload[pos++] = max_frame_size >> 8; // max framesize high
jksoft 0:fccb789424fc 531 payload[pos++] = 0x00; // number of retransmissions
jksoft 0:fccb789424fc 532 payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
jksoft 0:fccb789424fc 533 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
jksoft 0:fccb789424fc 534 }
jksoft 0:fccb789424fc 535
jksoft 0:fccb789424fc 536 // "The response may not change the DLCI, the priority, the convergence layer, or the timer value." RFCOMM-tutorial.pdf
jksoft 0:fccb789424fc 537 static int rfcomm_send_uih_pn_response(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,
jksoft 0:fccb789424fc 538 uint8_t priority, uint16_t max_frame_size){
jksoft 0:fccb789424fc 539 uint8_t payload[10];
jksoft 0:fccb789424fc 540 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
jksoft 0:fccb789424fc 541 uint8_t pos = 0;
jksoft 0:fccb789424fc 542 payload[pos++] = BT_RFCOMM_PN_RSP;
jksoft 0:fccb789424fc 543 payload[pos++] = 8 << 1 | 1; // len
jksoft 0:fccb789424fc 544 payload[pos++] = dlci;
jksoft 0:fccb789424fc 545 payload[pos++] = 0xe0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
jksoft 0:fccb789424fc 546 payload[pos++] = priority; // priority
jksoft 0:fccb789424fc 547 payload[pos++] = 0; // max 60 seconds ack
jksoft 0:fccb789424fc 548 payload[pos++] = max_frame_size & 0xff; // max framesize low
jksoft 0:fccb789424fc 549 payload[pos++] = max_frame_size >> 8; // max framesize high
jksoft 0:fccb789424fc 550 payload[pos++] = 0x00; // number of retransmissions
jksoft 0:fccb789424fc 551 payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
jksoft 0:fccb789424fc 552 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
jksoft 0:fccb789424fc 553 }
jksoft 0:fccb789424fc 554
jksoft 0:fccb789424fc 555 static int rfcomm_send_uih_rpn_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, rfcomm_rpn_data_t *rpn_data) {
jksoft 0:fccb789424fc 556 uint8_t payload[10];
jksoft 0:fccb789424fc 557 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
jksoft 0:fccb789424fc 558 uint8_t pos = 0;
jksoft 0:fccb789424fc 559 payload[pos++] = BT_RFCOMM_RPN_RSP;
jksoft 0:fccb789424fc 560 payload[pos++] = 8 << 1 | 1; // len
jksoft 0:fccb789424fc 561 payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
jksoft 0:fccb789424fc 562 payload[pos++] = rpn_data->baud_rate;
jksoft 0:fccb789424fc 563 payload[pos++] = rpn_data->flags;
jksoft 0:fccb789424fc 564 payload[pos++] = rpn_data->flow_control;
jksoft 0:fccb789424fc 565 payload[pos++] = rpn_data->xon;
jksoft 0:fccb789424fc 566 payload[pos++] = rpn_data->xoff;
jksoft 0:fccb789424fc 567 payload[pos++] = rpn_data->parameter_mask_0;
jksoft 0:fccb789424fc 568 payload[pos++] = rpn_data->parameter_mask_1;
jksoft 0:fccb789424fc 569 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
jksoft 0:fccb789424fc 570 }
jksoft 0:fccb789424fc 571
jksoft 0:fccb789424fc 572 static int rfcomm_send_uih_data(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t *data, uint16_t len){
jksoft 0:fccb789424fc 573 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);
jksoft 0:fccb789424fc 574 return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, data, len);
jksoft 0:fccb789424fc 575 }
jksoft 0:fccb789424fc 576
jksoft 0:fccb789424fc 577 static void rfcomm_send_uih_credits(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t credits){
jksoft 0:fccb789424fc 578 uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);
jksoft 0:fccb789424fc 579 rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH_PF, credits, NULL, 0);
jksoft 0:fccb789424fc 580 }
jksoft 0:fccb789424fc 581
jksoft 0:fccb789424fc 582 // MARK: RFCOMM MULTIPLEXER
jksoft 0:fccb789424fc 583
jksoft 0:fccb789424fc 584 static void rfcomm_multiplexer_finalize(rfcomm_multiplexer_t * multiplexer){
jksoft 0:fccb789424fc 585
jksoft 0:fccb789424fc 586 // remove (potential) timer
jksoft 0:fccb789424fc 587 if (multiplexer->timer_active) {
jksoft 0:fccb789424fc 588 run_loop_remove_timer(&multiplexer->timer);
jksoft 0:fccb789424fc 589 multiplexer->timer_active = 0;
jksoft 0:fccb789424fc 590 }
jksoft 0:fccb789424fc 591
jksoft 0:fccb789424fc 592 // close and remove all channels
jksoft 0:fccb789424fc 593 linked_item_t *it = (linked_item_t *) &rfcomm_channels;
jksoft 0:fccb789424fc 594 while (it->next){
jksoft 0:fccb789424fc 595 rfcomm_channel_t * channel = (rfcomm_channel_t *) it->next;
jksoft 0:fccb789424fc 596 if (channel->multiplexer == multiplexer) {
jksoft 0:fccb789424fc 597 // emit appropriate events
jksoft 0:fccb789424fc 598 if (channel->state == RFCOMM_CHANNEL_OPEN) {
jksoft 0:fccb789424fc 599 rfcomm_emit_channel_closed(channel);
jksoft 0:fccb789424fc 600 } else {
jksoft 0:fccb789424fc 601 rfcomm_emit_channel_opened(channel, RFCOMM_MULTIPLEXER_STOPPED);
jksoft 0:fccb789424fc 602 }
jksoft 0:fccb789424fc 603 // remove from list
jksoft 0:fccb789424fc 604 it->next = it->next->next;
jksoft 0:fccb789424fc 605 // free channel struct
jksoft 0:fccb789424fc 606 btstack_memory_rfcomm_channel_free(channel);
jksoft 0:fccb789424fc 607 } else {
jksoft 0:fccb789424fc 608 it = it->next;
jksoft 0:fccb789424fc 609 }
jksoft 0:fccb789424fc 610 }
jksoft 0:fccb789424fc 611
jksoft 0:fccb789424fc 612 // keep reference to l2cap channel
jksoft 0:fccb789424fc 613 uint16_t l2cap_cid = multiplexer->l2cap_cid;
jksoft 0:fccb789424fc 614
jksoft 0:fccb789424fc 615 // remove mutliplexer
jksoft 0:fccb789424fc 616 linked_list_remove( &rfcomm_multiplexers, (linked_item_t *) multiplexer);
jksoft 0:fccb789424fc 617 btstack_memory_rfcomm_multiplexer_free(multiplexer);
jksoft 0:fccb789424fc 618
jksoft 0:fccb789424fc 619 // close l2cap multiplexer channel, too
jksoft 0:fccb789424fc 620 l2cap_disconnect_internal(l2cap_cid, 0x13);
jksoft 0:fccb789424fc 621 }
jksoft 0:fccb789424fc 622
jksoft 0:fccb789424fc 623 static void rfcomm_multiplexer_timer_handler(timer_source_t *timer){
jksoft 0:fccb789424fc 624 rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t *) linked_item_get_user( (linked_item_t *) timer);
jksoft 0:fccb789424fc 625 if (!rfcomm_multiplexer_has_channels(multiplexer)){
jksoft 0:fccb789424fc 626 log_info( "rfcomm_multiplexer_timer_handler timeout: shutting down multiplexer!\n");
jksoft 0:fccb789424fc 627 rfcomm_multiplexer_finalize(multiplexer);
jksoft 0:fccb789424fc 628 }
jksoft 0:fccb789424fc 629 }
jksoft 0:fccb789424fc 630
jksoft 0:fccb789424fc 631 static void rfcomm_multiplexer_prepare_idle_timer(rfcomm_multiplexer_t * multiplexer){
jksoft 0:fccb789424fc 632 if (multiplexer->timer_active) {
jksoft 0:fccb789424fc 633 run_loop_remove_timer(&multiplexer->timer);
jksoft 0:fccb789424fc 634 multiplexer->timer_active = 0;
jksoft 0:fccb789424fc 635 }
jksoft 0:fccb789424fc 636 if (!rfcomm_multiplexer_has_channels(multiplexer)){
jksoft 0:fccb789424fc 637 // start timer for multiplexer timeout check
jksoft 0:fccb789424fc 638 run_loop_set_timer(&multiplexer->timer, RFCOMM_MULIPLEXER_TIMEOUT_MS);
jksoft 0:fccb789424fc 639 multiplexer->timer.process = rfcomm_multiplexer_timer_handler;
jksoft 0:fccb789424fc 640 linked_item_set_user((linked_item_t*) &multiplexer->timer, multiplexer);
jksoft 0:fccb789424fc 641 run_loop_add_timer(&multiplexer->timer);
jksoft 0:fccb789424fc 642 multiplexer->timer_active = 1;
jksoft 0:fccb789424fc 643 }
jksoft 0:fccb789424fc 644 }
jksoft 0:fccb789424fc 645
jksoft 0:fccb789424fc 646 static void rfcomm_multiplexer_opened(rfcomm_multiplexer_t *multiplexer){
jksoft 0:fccb789424fc 647 log_info("Multiplexer up and running\n");
jksoft 0:fccb789424fc 648 multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
jksoft 0:fccb789424fc 649
jksoft 0:fccb789424fc 650 rfcomm_channel_event_t event = { CH_EVT_MULTIPLEXER_READY };
jksoft 0:fccb789424fc 651
jksoft 0:fccb789424fc 652 // transition of channels that wait for multiplexer
jksoft 0:fccb789424fc 653 linked_item_t *it;
jksoft 0:fccb789424fc 654 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 655 rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
jksoft 0:fccb789424fc 656 if (channel->multiplexer != multiplexer) continue;
jksoft 0:fccb789424fc 657 rfcomm_channel_state_machine(channel, &event);
jksoft 0:fccb789424fc 658 }
jksoft 0:fccb789424fc 659
jksoft 0:fccb789424fc 660 rfcomm_run();
jksoft 0:fccb789424fc 661 rfcomm_multiplexer_prepare_idle_timer(multiplexer);
jksoft 0:fccb789424fc 662 }
jksoft 0:fccb789424fc 663
jksoft 0:fccb789424fc 664
jksoft 0:fccb789424fc 665 /**
jksoft 0:fccb789424fc 666 * @return handled packet
jksoft 0:fccb789424fc 667 */
jksoft 0:fccb789424fc 668 static int rfcomm_multiplexer_hci_event_handler(uint8_t *packet, uint16_t size){
jksoft 0:fccb789424fc 669 bd_addr_t event_addr;
jksoft 0:fccb789424fc 670 uint16_t psm;
jksoft 0:fccb789424fc 671 uint16_t l2cap_cid;
jksoft 0:fccb789424fc 672 hci_con_handle_t con_handle;
jksoft 0:fccb789424fc 673 rfcomm_multiplexer_t *multiplexer = NULL;
jksoft 0:fccb789424fc 674 switch (packet[0]) {
jksoft 0:fccb789424fc 675
jksoft 0:fccb789424fc 676 // accept incoming PSM_RFCOMM connection if no multiplexer exists yet
jksoft 0:fccb789424fc 677 case L2CAP_EVENT_INCOMING_CONNECTION:
jksoft 0:fccb789424fc 678 // data: event(8), len(8), address(48), handle (16), psm (16), source cid(16) dest cid(16)
jksoft 0:fccb789424fc 679 bt_flip_addr(event_addr, &packet[2]);
jksoft 0:fccb789424fc 680 con_handle = READ_BT_16(packet, 8);
jksoft 0:fccb789424fc 681 psm = READ_BT_16(packet, 10);
jksoft 0:fccb789424fc 682 l2cap_cid = READ_BT_16(packet, 12);
jksoft 0:fccb789424fc 683
jksoft 0:fccb789424fc 684 if (psm != PSM_RFCOMM) break;
jksoft 0:fccb789424fc 685
jksoft 0:fccb789424fc 686 multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
jksoft 0:fccb789424fc 687
jksoft 0:fccb789424fc 688 if (multiplexer) {
jksoft 0:fccb789424fc 689 log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - multiplexer already exists", l2cap_cid);
jksoft 0:fccb789424fc 690 l2cap_decline_connection_internal(l2cap_cid, 0x04); // no resources available
jksoft 0:fccb789424fc 691 return 1;
jksoft 0:fccb789424fc 692 }
jksoft 0:fccb789424fc 693
jksoft 0:fccb789424fc 694 // create and inititialize new multiplexer instance (incoming)
jksoft 0:fccb789424fc 695 multiplexer = rfcomm_multiplexer_create_for_addr(&event_addr);
jksoft 0:fccb789424fc 696 if (!multiplexer){
jksoft 0:fccb789424fc 697 log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - no memory left", l2cap_cid);
jksoft 0:fccb789424fc 698 l2cap_decline_connection_internal(l2cap_cid, 0x04); // no resources available
jksoft 0:fccb789424fc 699 return 1;
jksoft 0:fccb789424fc 700 }
jksoft 0:fccb789424fc 701
jksoft 0:fccb789424fc 702 multiplexer->con_handle = con_handle;
jksoft 0:fccb789424fc 703 multiplexer->l2cap_cid = l2cap_cid;
jksoft 0:fccb789424fc 704 multiplexer->state = RFCOMM_MULTIPLEXER_W4_SABM_0;
jksoft 0:fccb789424fc 705
jksoft 0:fccb789424fc 706 log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => accept", l2cap_cid);
jksoft 0:fccb789424fc 707 l2cap_accept_connection_internal(l2cap_cid);
jksoft 0:fccb789424fc 708 return 1;
jksoft 0:fccb789424fc 709
jksoft 0:fccb789424fc 710 // l2cap connection opened -> store l2cap_cid, remote_addr
jksoft 0:fccb789424fc 711 case L2CAP_EVENT_CHANNEL_OPENED:
jksoft 0:fccb789424fc 712 if (READ_BT_16(packet, 11) != PSM_RFCOMM) break;
jksoft 0:fccb789424fc 713 log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_RFCOMM\n");
jksoft 0:fccb789424fc 714 // get multiplexer for remote addr
jksoft 0:fccb789424fc 715 con_handle = READ_BT_16(packet, 9);
jksoft 0:fccb789424fc 716 l2cap_cid = READ_BT_16(packet, 13);
jksoft 0:fccb789424fc 717 bt_flip_addr(event_addr, &packet[3]);
jksoft 0:fccb789424fc 718 multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
jksoft 0:fccb789424fc 719 if (!multiplexer) {
jksoft 0:fccb789424fc 720 log_error("L2CAP_EVENT_CHANNEL_OPENED but no multiplexer prepared\n");
jksoft 0:fccb789424fc 721 return 1;
jksoft 0:fccb789424fc 722 }
jksoft 0:fccb789424fc 723 if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_CONNECT) {
jksoft 0:fccb789424fc 724 log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection\n");
jksoft 0:fccb789424fc 725 // wrong remote addr
jksoft 0:fccb789424fc 726 if (BD_ADDR_CMP(event_addr, multiplexer->remote_addr)) break;
jksoft 0:fccb789424fc 727 multiplexer->l2cap_cid = l2cap_cid;
jksoft 0:fccb789424fc 728 multiplexer->con_handle = con_handle;
jksoft 0:fccb789424fc 729 // send SABM #0
jksoft 0:fccb789424fc 730 multiplexer->state = RFCOMM_MULTIPLEXER_SEND_SABM_0;
jksoft 0:fccb789424fc 731 } else { // multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0
jksoft 0:fccb789424fc 732
jksoft 0:fccb789424fc 733 // set max frame size based on l2cap MTU
jksoft 0:fccb789424fc 734 multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
jksoft 0:fccb789424fc 735 }
jksoft 0:fccb789424fc 736 return 1;
jksoft 0:fccb789424fc 737
jksoft 0:fccb789424fc 738 // l2cap disconnect -> state = RFCOMM_MULTIPLEXER_CLOSED;
jksoft 0:fccb789424fc 739
jksoft 0:fccb789424fc 740 case L2CAP_EVENT_CREDITS:
jksoft 0:fccb789424fc 741 // data: event(8), len(8), local_cid(16), credits(8)
jksoft 0:fccb789424fc 742 l2cap_cid = READ_BT_16(packet, 2);
jksoft 0:fccb789424fc 743 multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
jksoft 0:fccb789424fc 744 if (!multiplexer) break;
jksoft 0:fccb789424fc 745 multiplexer->l2cap_credits += packet[4];
jksoft 0:fccb789424fc 746
jksoft 0:fccb789424fc 747 // log_info("L2CAP_EVENT_CREDITS: %u (now %u)\n", packet[4], multiplexer->l2cap_credits);
jksoft 0:fccb789424fc 748
jksoft 0:fccb789424fc 749 // new credits, continue with signaling
jksoft 0:fccb789424fc 750 rfcomm_run();
jksoft 0:fccb789424fc 751
jksoft 0:fccb789424fc 752 if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) break;
jksoft 0:fccb789424fc 753 rfcomm_hand_out_credits();
jksoft 0:fccb789424fc 754 return 1;
jksoft 0:fccb789424fc 755
jksoft 0:fccb789424fc 756 case DAEMON_EVENT_HCI_PACKET_SENT:
jksoft 0:fccb789424fc 757 // testing DMA done code
jksoft 0:fccb789424fc 758 rfcomm_run();
jksoft 0:fccb789424fc 759 break;
jksoft 0:fccb789424fc 760
jksoft 0:fccb789424fc 761 case L2CAP_EVENT_CHANNEL_CLOSED:
jksoft 0:fccb789424fc 762 // data: event (8), len(8), channel (16)
jksoft 0:fccb789424fc 763 l2cap_cid = READ_BT_16(packet, 2);
jksoft 0:fccb789424fc 764 multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
jksoft 0:fccb789424fc 765 if (!multiplexer) break;
jksoft 0:fccb789424fc 766 switch (multiplexer->state) {
jksoft 0:fccb789424fc 767 case RFCOMM_MULTIPLEXER_W4_SABM_0:
jksoft 0:fccb789424fc 768 case RFCOMM_MULTIPLEXER_W4_UA_0:
jksoft 0:fccb789424fc 769 case RFCOMM_MULTIPLEXER_OPEN:
jksoft 0:fccb789424fc 770 rfcomm_multiplexer_finalize(multiplexer);
jksoft 0:fccb789424fc 771 return 1;
jksoft 0:fccb789424fc 772 default:
jksoft 0:fccb789424fc 773 break;
jksoft 0:fccb789424fc 774 }
jksoft 0:fccb789424fc 775 break;
jksoft 0:fccb789424fc 776 default:
jksoft 0:fccb789424fc 777 break;
jksoft 0:fccb789424fc 778 }
jksoft 0:fccb789424fc 779 return 0;
jksoft 0:fccb789424fc 780 }
jksoft 0:fccb789424fc 781
jksoft 0:fccb789424fc 782 static int rfcomm_multiplexer_l2cap_packet_handler(uint16_t channel, uint8_t *packet, uint16_t size){
jksoft 0:fccb789424fc 783
jksoft 0:fccb789424fc 784 // get or create a multiplexer for a certain device
jksoft 0:fccb789424fc 785 rfcomm_multiplexer_t *multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
jksoft 0:fccb789424fc 786 if (!multiplexer) return 0;
jksoft 0:fccb789424fc 787
jksoft 0:fccb789424fc 788 // but only care for multiplexer control channel
jksoft 0:fccb789424fc 789 uint8_t frame_dlci = packet[0] >> 2;
jksoft 0:fccb789424fc 790 if (frame_dlci) return 0;
jksoft 0:fccb789424fc 791 const uint8_t length_offset = (packet[2] & 1) ^ 1; // to be used for pos >= 3
jksoft 0:fccb789424fc 792 const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0; // credits for uih_pf frames
jksoft 0:fccb789424fc 793 const uint8_t payload_offset = 3 + length_offset + credit_offset;
jksoft 0:fccb789424fc 794 switch (packet[1]){
jksoft 0:fccb789424fc 795
jksoft 0:fccb789424fc 796 case BT_RFCOMM_SABM:
jksoft 0:fccb789424fc 797 if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0){
jksoft 0:fccb789424fc 798 log_info("Received SABM #0\n");
jksoft 0:fccb789424fc 799 multiplexer->outgoing = 0;
jksoft 0:fccb789424fc 800 multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0;
jksoft 0:fccb789424fc 801 return 1;
jksoft 0:fccb789424fc 802 }
jksoft 0:fccb789424fc 803 break;
jksoft 0:fccb789424fc 804
jksoft 0:fccb789424fc 805 case BT_RFCOMM_UA:
jksoft 0:fccb789424fc 806 if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_UA_0) {
jksoft 0:fccb789424fc 807 // UA #0 -> send UA #0, state = RFCOMM_MULTIPLEXER_OPEN
jksoft 0:fccb789424fc 808 log_info("Received UA #0 \n");
jksoft 0:fccb789424fc 809 rfcomm_multiplexer_opened(multiplexer);
jksoft 0:fccb789424fc 810 return 1;
jksoft 0:fccb789424fc 811 }
jksoft 0:fccb789424fc 812 break;
jksoft 0:fccb789424fc 813
jksoft 0:fccb789424fc 814 case BT_RFCOMM_DISC:
jksoft 0:fccb789424fc 815 // DISC #0 -> send UA #0, close multiplexer
jksoft 0:fccb789424fc 816 log_info("Received DISC #0, (ougoing = %u)\n", multiplexer->outgoing);
jksoft 0:fccb789424fc 817 multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC;
jksoft 0:fccb789424fc 818 return 1;
jksoft 0:fccb789424fc 819
jksoft 0:fccb789424fc 820 case BT_RFCOMM_DM:
jksoft 0:fccb789424fc 821 // DM #0 - we shouldn't get this, just give up
jksoft 0:fccb789424fc 822 log_info("Received DM #0\n");
jksoft 0:fccb789424fc 823 log_info("-> Closing down multiplexer\n");
jksoft 0:fccb789424fc 824 rfcomm_multiplexer_finalize(multiplexer);
jksoft 0:fccb789424fc 825 return 1;
jksoft 0:fccb789424fc 826
jksoft 0:fccb789424fc 827 case BT_RFCOMM_UIH:
jksoft 0:fccb789424fc 828 if (packet[payload_offset] == BT_RFCOMM_CLD_CMD){
jksoft 0:fccb789424fc 829 // Multiplexer close down (CLD) -> close mutliplexer
jksoft 0:fccb789424fc 830 log_info("Received Multiplexer close down command\n");
jksoft 0:fccb789424fc 831 log_info("-> Closing down multiplexer\n");
jksoft 0:fccb789424fc 832 rfcomm_multiplexer_finalize(multiplexer);
jksoft 0:fccb789424fc 833 return 1;
jksoft 0:fccb789424fc 834 }
jksoft 0:fccb789424fc 835 break;
jksoft 0:fccb789424fc 836
jksoft 0:fccb789424fc 837 default:
jksoft 0:fccb789424fc 838 break;
jksoft 0:fccb789424fc 839
jksoft 0:fccb789424fc 840 }
jksoft 0:fccb789424fc 841 return 0;
jksoft 0:fccb789424fc 842 }
jksoft 0:fccb789424fc 843
jksoft 0:fccb789424fc 844 static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event){
jksoft 0:fccb789424fc 845
jksoft 0:fccb789424fc 846 // process stored DM responses
jksoft 0:fccb789424fc 847 if (multiplexer->send_dm_for_dlci){
jksoft 0:fccb789424fc 848 rfcomm_send_dm_pf(multiplexer, multiplexer->send_dm_for_dlci);
jksoft 0:fccb789424fc 849 multiplexer->send_dm_for_dlci = 0;
jksoft 0:fccb789424fc 850 }
jksoft 0:fccb789424fc 851
jksoft 0:fccb789424fc 852 switch (multiplexer->state) {
jksoft 0:fccb789424fc 853 case RFCOMM_MULTIPLEXER_SEND_SABM_0:
jksoft 0:fccb789424fc 854 switch (event) {
jksoft 0:fccb789424fc 855 case MULT_EV_READY_TO_SEND:
jksoft 0:fccb789424fc 856 log_info("Sending SABM #0 - (multi 0x%p)\n", multiplexer);
jksoft 0:fccb789424fc 857 multiplexer->state = RFCOMM_MULTIPLEXER_W4_UA_0;
jksoft 0:fccb789424fc 858 rfcomm_send_sabm(multiplexer, 0);
jksoft 0:fccb789424fc 859 break;
jksoft 0:fccb789424fc 860 default:
jksoft 0:fccb789424fc 861 break;
jksoft 0:fccb789424fc 862 }
jksoft 0:fccb789424fc 863 break;
jksoft 0:fccb789424fc 864 case RFCOMM_MULTIPLEXER_SEND_UA_0:
jksoft 0:fccb789424fc 865 switch (event) {
jksoft 0:fccb789424fc 866 case MULT_EV_READY_TO_SEND:
jksoft 0:fccb789424fc 867 log_info("Sending UA #0\n");
jksoft 0:fccb789424fc 868 multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
jksoft 0:fccb789424fc 869 rfcomm_send_ua(multiplexer, 0);
jksoft 0:fccb789424fc 870 rfcomm_multiplexer_opened(multiplexer);
jksoft 0:fccb789424fc 871 break;
jksoft 0:fccb789424fc 872 default:
jksoft 0:fccb789424fc 873 break;
jksoft 0:fccb789424fc 874 }
jksoft 0:fccb789424fc 875 break;
jksoft 0:fccb789424fc 876 case RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC:
jksoft 0:fccb789424fc 877 switch (event) {
jksoft 0:fccb789424fc 878 case MULT_EV_READY_TO_SEND:
jksoft 0:fccb789424fc 879 log_info("Sending UA #0\n");
jksoft 0:fccb789424fc 880 log_info("Closing down multiplexer\n");
jksoft 0:fccb789424fc 881 multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
jksoft 0:fccb789424fc 882 rfcomm_send_ua(multiplexer, 0);
jksoft 0:fccb789424fc 883 rfcomm_multiplexer_finalize(multiplexer);
jksoft 0:fccb789424fc 884 // try to detect authentication errors: drop link key if multiplexer closed before first channel got opened
jksoft 0:fccb789424fc 885 if (!multiplexer->at_least_one_connection){
jksoft 0:fccb789424fc 886 log_info("TODO: no connections established - delete link key prophylactically\n");
jksoft 0:fccb789424fc 887 // hci_send_cmd(&hci_delete_stored_link_key, multiplexer->remote_addr);
jksoft 0:fccb789424fc 888 }
jksoft 0:fccb789424fc 889 default:
jksoft 0:fccb789424fc 890 break;
jksoft 0:fccb789424fc 891 }
jksoft 0:fccb789424fc 892 break;
jksoft 0:fccb789424fc 893 default:
jksoft 0:fccb789424fc 894 break;
jksoft 0:fccb789424fc 895 }
jksoft 0:fccb789424fc 896 }
jksoft 0:fccb789424fc 897
jksoft 0:fccb789424fc 898 // MARK: RFCOMM CHANNEL
jksoft 0:fccb789424fc 899
jksoft 0:fccb789424fc 900 static void rfcomm_hand_out_credits(void){
jksoft 0:fccb789424fc 901 linked_item_t * it;
jksoft 0:fccb789424fc 902 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 903 rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
jksoft 0:fccb789424fc 904 if (channel->state != RFCOMM_CHANNEL_OPEN) {
jksoft 0:fccb789424fc 905 // log_info("RFCOMM_EVENT_CREDITS: multiplexer not open\n");
jksoft 0:fccb789424fc 906 continue;
jksoft 0:fccb789424fc 907 }
jksoft 0:fccb789424fc 908 if (channel->packets_granted) {
jksoft 0:fccb789424fc 909 // log_info("RFCOMM_EVENT_CREDITS: already packets granted\n");
jksoft 0:fccb789424fc 910 continue;
jksoft 0:fccb789424fc 911 }
jksoft 0:fccb789424fc 912 if (!channel->credits_outgoing) {
jksoft 0:fccb789424fc 913 // log_info("RFCOMM_EVENT_CREDITS: no outgoing credits\n");
jksoft 0:fccb789424fc 914 continue;
jksoft 0:fccb789424fc 915 }
jksoft 0:fccb789424fc 916 if (!channel->multiplexer->l2cap_credits){
jksoft 0:fccb789424fc 917 // log_info("RFCOMM_EVENT_CREDITS: no l2cap credits\n");
jksoft 0:fccb789424fc 918 continue;
jksoft 0:fccb789424fc 919 }
jksoft 0:fccb789424fc 920 // channel open, multiplexer has l2cap credits and we didn't hand out credit before -> go!
jksoft 0:fccb789424fc 921 // log_info("RFCOMM_EVENT_CREDITS: 1\n");
jksoft 0:fccb789424fc 922 channel->packets_granted += 1;
jksoft 0:fccb789424fc 923 rfcomm_emit_credits(channel, 1);
jksoft 0:fccb789424fc 924 }
jksoft 0:fccb789424fc 925 }
jksoft 0:fccb789424fc 926
jksoft 0:fccb789424fc 927 static void rfcomm_channel_send_credits(rfcomm_channel_t *channel, uint8_t credits){
jksoft 0:fccb789424fc 928 rfcomm_send_uih_credits(channel->multiplexer, channel->dlci, credits);
jksoft 0:fccb789424fc 929 channel->credits_incoming += credits;
jksoft 0:fccb789424fc 930
jksoft 0:fccb789424fc 931 rfcomm_emit_credit_status(channel);
jksoft 0:fccb789424fc 932 }
jksoft 0:fccb789424fc 933
jksoft 0:fccb789424fc 934 static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
jksoft 0:fccb789424fc 935
jksoft 0:fccb789424fc 936 log_info("rfcomm_channel_opened!\n");
jksoft 0:fccb789424fc 937
jksoft 0:fccb789424fc 938 rfChannel->state = RFCOMM_CHANNEL_OPEN;
jksoft 0:fccb789424fc 939 rfcomm_emit_channel_opened(rfChannel, 0);
jksoft 0:fccb789424fc 940 rfcomm_hand_out_credits();
jksoft 0:fccb789424fc 941
jksoft 0:fccb789424fc 942 // remove (potential) timer
jksoft 0:fccb789424fc 943 rfcomm_multiplexer_t *multiplexer = rfChannel->multiplexer;
jksoft 0:fccb789424fc 944 if (multiplexer->timer_active) {
jksoft 0:fccb789424fc 945 run_loop_remove_timer(&multiplexer->timer);
jksoft 0:fccb789424fc 946 multiplexer->timer_active = 0;
jksoft 0:fccb789424fc 947 }
jksoft 0:fccb789424fc 948 // hack for problem detecting authentication failure
jksoft 0:fccb789424fc 949 multiplexer->at_least_one_connection = 1;
jksoft 0:fccb789424fc 950
jksoft 0:fccb789424fc 951 // start next connection request if pending
jksoft 0:fccb789424fc 952 rfcomm_run();
jksoft 0:fccb789424fc 953 }
jksoft 0:fccb789424fc 954
jksoft 0:fccb789424fc 955 static void rfcomm_channel_packet_handler_uih(rfcomm_multiplexer_t *multiplexer, uint8_t * packet, uint16_t size){
jksoft 0:fccb789424fc 956 const uint8_t frame_dlci = packet[0] >> 2;
jksoft 0:fccb789424fc 957 const uint8_t length_offset = (packet[2] & 1) ^ 1; // to be used for pos >= 3
jksoft 0:fccb789424fc 958 const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0; // credits for uih_pf frames
jksoft 0:fccb789424fc 959 const uint8_t payload_offset = 3 + length_offset + credit_offset;
jksoft 0:fccb789424fc 960
jksoft 0:fccb789424fc 961 rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, frame_dlci);
jksoft 0:fccb789424fc 962 if (!channel) return;
jksoft 0:fccb789424fc 963
jksoft 0:fccb789424fc 964 // handle new outgoing credits
jksoft 0:fccb789424fc 965 if (packet[1] == BT_RFCOMM_UIH_PF) {
jksoft 0:fccb789424fc 966
jksoft 0:fccb789424fc 967 // add them
jksoft 0:fccb789424fc 968 uint16_t new_credits = packet[3+length_offset];
jksoft 0:fccb789424fc 969 channel->credits_outgoing += new_credits;
jksoft 0:fccb789424fc 970 log_info( "RFCOMM data UIH_PF, new credits: %u, now %u\n", new_credits, channel->credits_outgoing);
jksoft 0:fccb789424fc 971
jksoft 0:fccb789424fc 972 // notify channel statemachine
jksoft 0:fccb789424fc 973 rfcomm_channel_event_t channel_event = { CH_EVT_RCVD_CREDITS };
jksoft 0:fccb789424fc 974 rfcomm_channel_state_machine(channel, &channel_event);
jksoft 0:fccb789424fc 975 }
jksoft 0:fccb789424fc 976
jksoft 0:fccb789424fc 977 // contains payload?
jksoft 0:fccb789424fc 978 if (size - 1 > payload_offset){
jksoft 0:fccb789424fc 979
jksoft 0:fccb789424fc 980 // log_info( "RFCOMM data UIH_PF, size %u, channel %p\n", size-payload_offset-1, rfChannel->connection);
jksoft 0:fccb789424fc 981
jksoft 0:fccb789424fc 982 // decrease incoming credit counter
jksoft 0:fccb789424fc 983 if (channel->credits_incoming > 0){
jksoft 0:fccb789424fc 984 channel->credits_incoming--;
jksoft 0:fccb789424fc 985 }
jksoft 0:fccb789424fc 986
jksoft 0:fccb789424fc 987 // deliver payload
jksoft 0:fccb789424fc 988 (*app_packet_handler)(channel->connection, RFCOMM_DATA_PACKET, channel->rfcomm_cid,
jksoft 0:fccb789424fc 989 &packet[payload_offset], size-payload_offset-1);
jksoft 0:fccb789424fc 990 }
jksoft 0:fccb789424fc 991
jksoft 0:fccb789424fc 992 // automatically provide new credits to remote device, if no incoming flow control
jksoft 0:fccb789424fc 993 if (!channel->incoming_flow_control && channel->credits_incoming < 5){
jksoft 0:fccb789424fc 994 channel->new_credits_incoming = 0x30;
jksoft 0:fccb789424fc 995 }
jksoft 0:fccb789424fc 996
jksoft 0:fccb789424fc 997 rfcomm_emit_credit_status(channel);
jksoft 0:fccb789424fc 998
jksoft 0:fccb789424fc 999 // we received new RFCOMM credits, hand them out if possible
jksoft 0:fccb789424fc 1000 rfcomm_hand_out_credits();
jksoft 0:fccb789424fc 1001 }
jksoft 0:fccb789424fc 1002
jksoft 0:fccb789424fc 1003 static void rfcomm_channel_accept_pn(rfcomm_channel_t *channel, rfcomm_channel_event_pn_t *event){
jksoft 0:fccb789424fc 1004 // priority of client request
jksoft 0:fccb789424fc 1005 channel->pn_priority = event->priority;
jksoft 0:fccb789424fc 1006
jksoft 0:fccb789424fc 1007 // new credits
jksoft 0:fccb789424fc 1008 channel->credits_outgoing = event->credits_outgoing;
jksoft 0:fccb789424fc 1009
jksoft 0:fccb789424fc 1010 // negotiate max frame size
jksoft 0:fccb789424fc 1011 if (channel->max_frame_size > channel->multiplexer->max_frame_size) {
jksoft 0:fccb789424fc 1012 channel->max_frame_size = channel->multiplexer->max_frame_size;
jksoft 0:fccb789424fc 1013 }
jksoft 0:fccb789424fc 1014 if (channel->max_frame_size > event->max_frame_size) {
jksoft 0:fccb789424fc 1015 channel->max_frame_size = event->max_frame_size;
jksoft 0:fccb789424fc 1016 }
jksoft 0:fccb789424fc 1017
jksoft 0:fccb789424fc 1018 }
jksoft 0:fccb789424fc 1019
jksoft 0:fccb789424fc 1020 static void rfcomm_channel_finalize(rfcomm_channel_t *channel){
jksoft 0:fccb789424fc 1021
jksoft 0:fccb789424fc 1022 rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
jksoft 0:fccb789424fc 1023
jksoft 0:fccb789424fc 1024 // remove from list
jksoft 0:fccb789424fc 1025 linked_list_remove( &rfcomm_channels, (linked_item_t *) channel);
jksoft 0:fccb789424fc 1026
jksoft 0:fccb789424fc 1027 // free channel
jksoft 0:fccb789424fc 1028 btstack_memory_rfcomm_channel_free(channel);
jksoft 0:fccb789424fc 1029
jksoft 0:fccb789424fc 1030 // update multiplexer timeout after channel was removed from list
jksoft 0:fccb789424fc 1031 rfcomm_multiplexer_prepare_idle_timer(multiplexer);
jksoft 0:fccb789424fc 1032 }
jksoft 0:fccb789424fc 1033
jksoft 0:fccb789424fc 1034 static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event){
jksoft 0:fccb789424fc 1035
jksoft 0:fccb789424fc 1036 // TODO: if client max frame size is smaller than RFCOMM_DEFAULT_SIZE, send PN
jksoft 0:fccb789424fc 1037
jksoft 0:fccb789424fc 1038
jksoft 0:fccb789424fc 1039 // lookup existing channel
jksoft 0:fccb789424fc 1040 rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, dlci);
jksoft 0:fccb789424fc 1041
jksoft 0:fccb789424fc 1042 // log_info("rfcomm_channel_state_machine_2 lookup dlci #%u = 0x%08x - event %u\n", dlci, (int) channel, event->type);
jksoft 0:fccb789424fc 1043
jksoft 0:fccb789424fc 1044 if (channel) {
jksoft 0:fccb789424fc 1045 rfcomm_channel_state_machine(channel, event);
jksoft 0:fccb789424fc 1046 return;
jksoft 0:fccb789424fc 1047 }
jksoft 0:fccb789424fc 1048
jksoft 0:fccb789424fc 1049 // service registered?
jksoft 0:fccb789424fc 1050 rfcomm_service_t * service = rfcomm_service_for_channel(dlci >> 1);
jksoft 0:fccb789424fc 1051 // log_info("rfcomm_channel_state_machine_2 service dlci #%u = 0x%08x\n", dlci, (int) service);
jksoft 0:fccb789424fc 1052 if (!service) {
jksoft 0:fccb789424fc 1053 // discard request by sending disconnected mode
jksoft 0:fccb789424fc 1054 multiplexer->send_dm_for_dlci = dlci;
jksoft 0:fccb789424fc 1055 return;
jksoft 0:fccb789424fc 1056 }
jksoft 0:fccb789424fc 1057
jksoft 0:fccb789424fc 1058 // create channel for some events
jksoft 0:fccb789424fc 1059 switch (event->type) {
jksoft 0:fccb789424fc 1060 case CH_EVT_RCVD_SABM:
jksoft 0:fccb789424fc 1061 case CH_EVT_RCVD_PN:
jksoft 0:fccb789424fc 1062 case CH_EVT_RCVD_RPN_REQ:
jksoft 0:fccb789424fc 1063 case CH_EVT_RCVD_RPN_CMD:
jksoft 0:fccb789424fc 1064 // setup incoming channel
jksoft 0:fccb789424fc 1065 channel = rfcomm_channel_create(multiplexer, service, dlci >> 1);
jksoft 0:fccb789424fc 1066 if (!channel){
jksoft 0:fccb789424fc 1067 // discard request by sending disconnected mode
jksoft 0:fccb789424fc 1068 multiplexer->send_dm_for_dlci = dlci;
jksoft 0:fccb789424fc 1069 }
jksoft 0:fccb789424fc 1070 break;
jksoft 0:fccb789424fc 1071 default:
jksoft 0:fccb789424fc 1072 break;
jksoft 0:fccb789424fc 1073 }
jksoft 0:fccb789424fc 1074
jksoft 0:fccb789424fc 1075 if (!channel) {
jksoft 0:fccb789424fc 1076 // discard request by sending disconnected mode
jksoft 0:fccb789424fc 1077 multiplexer->send_dm_for_dlci = dlci;
jksoft 0:fccb789424fc 1078 return;
jksoft 0:fccb789424fc 1079 }
jksoft 0:fccb789424fc 1080 channel->connection = service->connection;
jksoft 0:fccb789424fc 1081 rfcomm_channel_state_machine(channel, event);
jksoft 0:fccb789424fc 1082 }
jksoft 0:fccb789424fc 1083
jksoft 0:fccb789424fc 1084 void rfcomm_channel_packet_handler(rfcomm_multiplexer_t * multiplexer, uint8_t *packet, uint16_t size){
jksoft 0:fccb789424fc 1085
jksoft 0:fccb789424fc 1086 // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
jksoft 0:fccb789424fc 1087 const uint8_t frame_dlci = packet[0] >> 2;
jksoft 0:fccb789424fc 1088 uint8_t message_dlci; // used by commands in UIH(_PF) packets
jksoft 0:fccb789424fc 1089 uint8_t message_len; // "
jksoft 0:fccb789424fc 1090
jksoft 0:fccb789424fc 1091 // rfcomm: (1) command/control
jksoft 0:fccb789424fc 1092 // -- credits_offset = 1 if command == BT_RFCOMM_UIH_PF
jksoft 0:fccb789424fc 1093 const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0; // credits for uih_pf frames
jksoft 0:fccb789424fc 1094 // rfcomm: (2) length. if bit 0 is cleared, 2 byte length is used. (little endian)
jksoft 0:fccb789424fc 1095 const uint8_t length_offset = (packet[2] & 1) ^ 1; // to be used for pos >= 3
jksoft 0:fccb789424fc 1096 // rfcomm: (3+length_offset) credits if credits_offset == 1
jksoft 0:fccb789424fc 1097 // rfcomm: (3+length_offest+credits_offset)
jksoft 0:fccb789424fc 1098 const uint8_t payload_offset = 3 + length_offset + credit_offset;
jksoft 0:fccb789424fc 1099
jksoft 0:fccb789424fc 1100 rfcomm_channel_event_t event;
jksoft 0:fccb789424fc 1101 rfcomm_channel_event_pn_t event_pn;
jksoft 0:fccb789424fc 1102 rfcomm_channel_event_rpn_t event_rpn;
jksoft 0:fccb789424fc 1103
jksoft 0:fccb789424fc 1104 // switch by rfcomm message type
jksoft 0:fccb789424fc 1105 switch(packet[1]) {
jksoft 0:fccb789424fc 1106
jksoft 0:fccb789424fc 1107 case BT_RFCOMM_SABM:
jksoft 0:fccb789424fc 1108 event.type = CH_EVT_RCVD_SABM;
jksoft 0:fccb789424fc 1109 log_info("Received SABM #%u\n", frame_dlci);
jksoft 0:fccb789424fc 1110 rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
jksoft 0:fccb789424fc 1111 break;
jksoft 0:fccb789424fc 1112
jksoft 0:fccb789424fc 1113 case BT_RFCOMM_UA:
jksoft 0:fccb789424fc 1114 event.type = CH_EVT_RCVD_UA;
jksoft 0:fccb789424fc 1115 log_info("Received UA #%u - channel opened\n",frame_dlci);
jksoft 0:fccb789424fc 1116 rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
jksoft 0:fccb789424fc 1117 break;
jksoft 0:fccb789424fc 1118
jksoft 0:fccb789424fc 1119 case BT_RFCOMM_DISC:
jksoft 0:fccb789424fc 1120 event.type = CH_EVT_RCVD_DISC;
jksoft 0:fccb789424fc 1121 rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
jksoft 0:fccb789424fc 1122 break;
jksoft 0:fccb789424fc 1123
jksoft 0:fccb789424fc 1124 case BT_RFCOMM_DM:
jksoft 0:fccb789424fc 1125 case BT_RFCOMM_DM_PF:
jksoft 0:fccb789424fc 1126 event.type = CH_EVT_RCVD_DM;
jksoft 0:fccb789424fc 1127 rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
jksoft 0:fccb789424fc 1128 break;
jksoft 0:fccb789424fc 1129
jksoft 0:fccb789424fc 1130 case BT_RFCOMM_UIH_PF:
jksoft 0:fccb789424fc 1131 case BT_RFCOMM_UIH:
jksoft 0:fccb789424fc 1132
jksoft 0:fccb789424fc 1133 message_len = packet[payload_offset+1] >> 1;
jksoft 0:fccb789424fc 1134
jksoft 0:fccb789424fc 1135 switch (packet[payload_offset]) {
jksoft 0:fccb789424fc 1136 case BT_RFCOMM_PN_CMD:
jksoft 0:fccb789424fc 1137 message_dlci = packet[payload_offset+2];
jksoft 0:fccb789424fc 1138 event_pn.super.type = CH_EVT_RCVD_PN;
jksoft 0:fccb789424fc 1139 event_pn.priority = packet[payload_offset+4];
jksoft 0:fccb789424fc 1140 event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
jksoft 0:fccb789424fc 1141 event_pn.credits_outgoing = packet[payload_offset+9];
jksoft 0:fccb789424fc 1142 log_info("Received UIH Parameter Negotiation Command for #%u\n", message_dlci);
jksoft 0:fccb789424fc 1143 rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
jksoft 0:fccb789424fc 1144 break;
jksoft 0:fccb789424fc 1145
jksoft 0:fccb789424fc 1146 case BT_RFCOMM_PN_RSP:
jksoft 0:fccb789424fc 1147 message_dlci = packet[payload_offset+2];
jksoft 0:fccb789424fc 1148 event_pn.super.type = CH_EVT_RCVD_PN_RSP;
jksoft 0:fccb789424fc 1149 event_pn.priority = packet[payload_offset+4];
jksoft 0:fccb789424fc 1150 event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
jksoft 0:fccb789424fc 1151 event_pn.credits_outgoing = packet[payload_offset+9];
jksoft 0:fccb789424fc 1152 log_info("UIH Parameter Negotiation Response max frame %u, credits %u\n",
jksoft 0:fccb789424fc 1153 event_pn.max_frame_size, event_pn.credits_outgoing);
jksoft 0:fccb789424fc 1154 rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
jksoft 0:fccb789424fc 1155 break;
jksoft 0:fccb789424fc 1156
jksoft 0:fccb789424fc 1157 case BT_RFCOMM_MSC_CMD:
jksoft 0:fccb789424fc 1158 message_dlci = packet[payload_offset+2] >> 2;
jksoft 0:fccb789424fc 1159 event.type = CH_EVT_RCVD_MSC_CMD;
jksoft 0:fccb789424fc 1160 log_info("Received MSC CMD for #%u, \n", message_dlci);
jksoft 0:fccb789424fc 1161 rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
jksoft 0:fccb789424fc 1162 break;
jksoft 0:fccb789424fc 1163
jksoft 0:fccb789424fc 1164 case BT_RFCOMM_MSC_RSP:
jksoft 0:fccb789424fc 1165 message_dlci = packet[payload_offset+2] >> 2;
jksoft 0:fccb789424fc 1166 event.type = CH_EVT_RCVD_MSC_RSP;
jksoft 0:fccb789424fc 1167 log_info("Received MSC RSP for #%u\n", message_dlci);
jksoft 0:fccb789424fc 1168 rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
jksoft 0:fccb789424fc 1169 break;
jksoft 0:fccb789424fc 1170
jksoft 0:fccb789424fc 1171 case BT_RFCOMM_RPN_CMD:
jksoft 0:fccb789424fc 1172 message_dlci = packet[payload_offset+2] >> 2;
jksoft 0:fccb789424fc 1173 switch (message_len){
jksoft 0:fccb789424fc 1174 case 1:
jksoft 0:fccb789424fc 1175 log_info("Received Remote Port Negotiation for #%u\n", message_dlci);
jksoft 0:fccb789424fc 1176 event.type = CH_EVT_RCVD_RPN_REQ;
jksoft 0:fccb789424fc 1177 rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
jksoft 0:fccb789424fc 1178 break;
jksoft 0:fccb789424fc 1179 case 8:
jksoft 0:fccb789424fc 1180 log_info("Received Remote Port Negotiation (Info) for #%u\n", message_dlci);
jksoft 0:fccb789424fc 1181 event_rpn.super.type = CH_EVT_RCVD_RPN_CMD;
jksoft 0:fccb789424fc 1182 event_rpn.data.baud_rate = packet[payload_offset+3];
jksoft 0:fccb789424fc 1183 event_rpn.data.flags = packet[payload_offset+4];
jksoft 0:fccb789424fc 1184 event_rpn.data.flow_control = packet[payload_offset+5];
jksoft 0:fccb789424fc 1185 event_rpn.data.xon = packet[payload_offset+6];
jksoft 0:fccb789424fc 1186 event_rpn.data.xoff = packet[payload_offset+7];
jksoft 0:fccb789424fc 1187 event_rpn.data.parameter_mask_0 = packet[payload_offset+8];
jksoft 0:fccb789424fc 1188 event_rpn.data.parameter_mask_1 = packet[payload_offset+9];
jksoft 0:fccb789424fc 1189 rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_rpn);
jksoft 0:fccb789424fc 1190 break;
jksoft 0:fccb789424fc 1191 default:
jksoft 0:fccb789424fc 1192 break;
jksoft 0:fccb789424fc 1193 }
jksoft 0:fccb789424fc 1194 break;
jksoft 0:fccb789424fc 1195
jksoft 0:fccb789424fc 1196 default:
jksoft 0:fccb789424fc 1197 log_error("Received unknown UIH packet - 0x%02x\n", packet[payload_offset]);
jksoft 0:fccb789424fc 1198 break;
jksoft 0:fccb789424fc 1199 }
jksoft 0:fccb789424fc 1200 break;
jksoft 0:fccb789424fc 1201
jksoft 0:fccb789424fc 1202 default:
jksoft 0:fccb789424fc 1203 log_error("Received unknown RFCOMM message type %x\n", packet[1]);
jksoft 0:fccb789424fc 1204 break;
jksoft 0:fccb789424fc 1205 }
jksoft 0:fccb789424fc 1206
jksoft 0:fccb789424fc 1207 // trigger next action - example W4_PN_RSP: transition to SEND_SABM which only depends on "can send"
jksoft 0:fccb789424fc 1208 rfcomm_run();
jksoft 0:fccb789424fc 1209 }
jksoft 0:fccb789424fc 1210
jksoft 0:fccb789424fc 1211 void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
jksoft 0:fccb789424fc 1212
jksoft 0:fccb789424fc 1213 // multiplexer handler
jksoft 0:fccb789424fc 1214 int handled = 0;
jksoft 0:fccb789424fc 1215 switch (packet_type) {
jksoft 0:fccb789424fc 1216 case HCI_EVENT_PACKET:
jksoft 0:fccb789424fc 1217 handled = rfcomm_multiplexer_hci_event_handler(packet, size);
jksoft 0:fccb789424fc 1218 break;
jksoft 0:fccb789424fc 1219 case L2CAP_DATA_PACKET:
jksoft 0:fccb789424fc 1220 handled = rfcomm_multiplexer_l2cap_packet_handler(channel, packet, size);
jksoft 0:fccb789424fc 1221 break;
jksoft 0:fccb789424fc 1222 default:
jksoft 0:fccb789424fc 1223 break;
jksoft 0:fccb789424fc 1224 }
jksoft 0:fccb789424fc 1225
jksoft 0:fccb789424fc 1226 if (handled) {
jksoft 0:fccb789424fc 1227 rfcomm_run();
jksoft 0:fccb789424fc 1228 return;
jksoft 0:fccb789424fc 1229 }
jksoft 0:fccb789424fc 1230
jksoft 0:fccb789424fc 1231 // we only handle l2cap packet over open multiplexer channel now
jksoft 0:fccb789424fc 1232 if (packet_type != L2CAP_DATA_PACKET) {
jksoft 0:fccb789424fc 1233 (*app_packet_handler)(NULL, packet_type, channel, packet, size);
jksoft 0:fccb789424fc 1234 return;
jksoft 0:fccb789424fc 1235 }
jksoft 0:fccb789424fc 1236 rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
jksoft 0:fccb789424fc 1237 if (!multiplexer || multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
jksoft 0:fccb789424fc 1238 (*app_packet_handler)(NULL, packet_type, channel, packet, size);
jksoft 0:fccb789424fc 1239 return;
jksoft 0:fccb789424fc 1240 }
jksoft 0:fccb789424fc 1241
jksoft 0:fccb789424fc 1242 // channel data ?
jksoft 0:fccb789424fc 1243 // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
jksoft 0:fccb789424fc 1244 const uint8_t frame_dlci = packet[0] >> 2;
jksoft 0:fccb789424fc 1245
jksoft 0:fccb789424fc 1246 if (frame_dlci && (packet[1] == BT_RFCOMM_UIH || packet[1] == BT_RFCOMM_UIH_PF)) {
jksoft 0:fccb789424fc 1247 rfcomm_channel_packet_handler_uih(multiplexer, packet, size);
jksoft 0:fccb789424fc 1248 rfcomm_run();
jksoft 0:fccb789424fc 1249 return;
jksoft 0:fccb789424fc 1250 }
jksoft 0:fccb789424fc 1251
jksoft 0:fccb789424fc 1252 rfcomm_channel_packet_handler(multiplexer, packet, size);
jksoft 0:fccb789424fc 1253 }
jksoft 0:fccb789424fc 1254
jksoft 0:fccb789424fc 1255 static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel){
jksoft 0:fccb789424fc 1256 // log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u \n", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
jksoft 0:fccb789424fc 1257 if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP) == 0) return 0;
jksoft 0:fccb789424fc 1258 if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP) == 0) return 0;
jksoft 0:fccb789424fc 1259 if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS) == 0) return 0;
jksoft 0:fccb789424fc 1260 if (channel->credits_outgoing == 0) return 0;
jksoft 0:fccb789424fc 1261
jksoft 0:fccb789424fc 1262 return 1;
jksoft 0:fccb789424fc 1263 }
jksoft 0:fccb789424fc 1264
jksoft 0:fccb789424fc 1265 static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event){
jksoft 0:fccb789424fc 1266
jksoft 0:fccb789424fc 1267 // log_info("rfcomm_channel_state_machine: state %u, state_var %04x, event %u\n", channel->state, channel->state_var ,event->type);
jksoft 0:fccb789424fc 1268
jksoft 0:fccb789424fc 1269 rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
jksoft 0:fccb789424fc 1270
jksoft 0:fccb789424fc 1271 // TODO: integrate in common switch
jksoft 0:fccb789424fc 1272 if (event->type == CH_EVT_RCVD_DISC){
jksoft 0:fccb789424fc 1273 rfcomm_emit_channel_closed(channel);
jksoft 0:fccb789424fc 1274 channel->state = RFCOMM_CHANNEL_SEND_UA_AFTER_DISC;
jksoft 0:fccb789424fc 1275 return;
jksoft 0:fccb789424fc 1276 }
jksoft 0:fccb789424fc 1277
jksoft 0:fccb789424fc 1278 // TODO: integrate in common switch
jksoft 0:fccb789424fc 1279 if (event->type == CH_EVT_RCVD_DM){
jksoft 0:fccb789424fc 1280 log_info("Received DM message for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1281 log_info("-> Closing channel locally for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1282 rfcomm_emit_channel_closed(channel);
jksoft 0:fccb789424fc 1283 rfcomm_channel_finalize(channel);
jksoft 0:fccb789424fc 1284 return;
jksoft 0:fccb789424fc 1285 }
jksoft 0:fccb789424fc 1286
jksoft 0:fccb789424fc 1287 // remote port negotiation command - just accept everything for now
jksoft 0:fccb789424fc 1288 //
jksoft 0:fccb789424fc 1289 // "The RPN command can be used before a new DLC is opened and should be used whenever the port settings change."
jksoft 0:fccb789424fc 1290 // "The RPN command is specified as optional in TS 07.10, but it is mandatory to recognize and respond to it in RFCOMM.
jksoft 0:fccb789424fc 1291 // (Although the handling of individual settings are implementation-dependent.)"
jksoft 0:fccb789424fc 1292 //
jksoft 0:fccb789424fc 1293
jksoft 0:fccb789424fc 1294 // TODO: integrate in common switch
jksoft 0:fccb789424fc 1295 if (event->type == CH_EVT_RCVD_RPN_CMD){
jksoft 0:fccb789424fc 1296 // control port parameters
jksoft 0:fccb789424fc 1297 rfcomm_channel_event_rpn_t *event_rpn = (rfcomm_channel_event_rpn_t*) event;
jksoft 0:fccb789424fc 1298 memcpy(&channel->rpn_data, &event_rpn->data, sizeof(rfcomm_rpn_data_t));
jksoft 0:fccb789424fc 1299 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
jksoft 0:fccb789424fc 1300 return;
jksoft 0:fccb789424fc 1301 }
jksoft 0:fccb789424fc 1302
jksoft 0:fccb789424fc 1303 // TODO: integrate in common switch
jksoft 0:fccb789424fc 1304 if (event->type == CH_EVT_RCVD_RPN_REQ){
jksoft 0:fccb789424fc 1305 // default rpn rsp
jksoft 0:fccb789424fc 1306 rfcomm_rpn_data_t rpn_data;
jksoft 0:fccb789424fc 1307 rpn_data.baud_rate = 0xa0; /* 9600 bps */
jksoft 0:fccb789424fc 1308 rpn_data.flags = 0x03; /* 8-n-1 */
jksoft 0:fccb789424fc 1309 rpn_data.flow_control = 0; /* no flow control */
jksoft 0:fccb789424fc 1310 rpn_data.xon = 0xd1; /* XON */
jksoft 0:fccb789424fc 1311 rpn_data.xoff = 0xd3; /* XOFF */
jksoft 0:fccb789424fc 1312 rpn_data.parameter_mask_0 = 0x7f; /* parameter mask, all values set */
jksoft 0:fccb789424fc 1313 rpn_data.parameter_mask_1 = 0x3f; /* parameter mask, all values set */
jksoft 0:fccb789424fc 1314 memcpy(&channel->rpn_data, &rpn_data, sizeof(rfcomm_rpn_data_t));
jksoft 0:fccb789424fc 1315 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
jksoft 0:fccb789424fc 1316 return;
jksoft 0:fccb789424fc 1317 }
jksoft 0:fccb789424fc 1318
jksoft 0:fccb789424fc 1319 // TODO: integrate in common swich
jksoft 0:fccb789424fc 1320 if (event->type == CH_EVT_READY_TO_SEND){
jksoft 0:fccb789424fc 1321 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP){
jksoft 0:fccb789424fc 1322 log_info("Sending Remote Port Negotiation RSP for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1323 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
jksoft 0:fccb789424fc 1324 rfcomm_send_uih_rpn_rsp(multiplexer, channel->dlci, &channel->rpn_data);
jksoft 0:fccb789424fc 1325 return;
jksoft 0:fccb789424fc 1326 }
jksoft 0:fccb789424fc 1327 }
jksoft 0:fccb789424fc 1328
jksoft 0:fccb789424fc 1329 rfcomm_channel_event_pn_t * event_pn = (rfcomm_channel_event_pn_t*) event;
jksoft 0:fccb789424fc 1330
jksoft 0:fccb789424fc 1331 switch (channel->state) {
jksoft 0:fccb789424fc 1332 case RFCOMM_CHANNEL_CLOSED:
jksoft 0:fccb789424fc 1333 switch (event->type){
jksoft 0:fccb789424fc 1334 case CH_EVT_RCVD_SABM:
jksoft 0:fccb789424fc 1335 log_info("-> Inform app\n");
jksoft 0:fccb789424fc 1336 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
jksoft 0:fccb789424fc 1337 channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
jksoft 0:fccb789424fc 1338 rfcomm_emit_connection_request(channel);
jksoft 0:fccb789424fc 1339 break;
jksoft 0:fccb789424fc 1340 case CH_EVT_RCVD_PN:
jksoft 0:fccb789424fc 1341 rfcomm_channel_accept_pn(channel, event_pn);
jksoft 0:fccb789424fc 1342 log_info("-> Inform app\n");
jksoft 0:fccb789424fc 1343 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
jksoft 0:fccb789424fc 1344 channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
jksoft 0:fccb789424fc 1345 rfcomm_emit_connection_request(channel);
jksoft 0:fccb789424fc 1346 break;
jksoft 0:fccb789424fc 1347 default:
jksoft 0:fccb789424fc 1348 break;
jksoft 0:fccb789424fc 1349 }
jksoft 0:fccb789424fc 1350 break;
jksoft 0:fccb789424fc 1351
jksoft 0:fccb789424fc 1352 case RFCOMM_CHANNEL_INCOMING_SETUP:
jksoft 0:fccb789424fc 1353 switch (event->type){
jksoft 0:fccb789424fc 1354 case CH_EVT_RCVD_SABM:
jksoft 0:fccb789424fc 1355 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
jksoft 0:fccb789424fc 1356 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
jksoft 0:fccb789424fc 1357 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
jksoft 0:fccb789424fc 1358 }
jksoft 0:fccb789424fc 1359 break;
jksoft 0:fccb789424fc 1360 case CH_EVT_RCVD_PN:
jksoft 0:fccb789424fc 1361 rfcomm_channel_accept_pn(channel, event_pn);
jksoft 0:fccb789424fc 1362 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
jksoft 0:fccb789424fc 1363 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
jksoft 0:fccb789424fc 1364 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
jksoft 0:fccb789424fc 1365 }
jksoft 0:fccb789424fc 1366 break;
jksoft 0:fccb789424fc 1367 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1368 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP){
jksoft 0:fccb789424fc 1369 log_info("Sending UIH Parameter Negotiation Respond for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1370 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
jksoft 0:fccb789424fc 1371 rfcomm_send_uih_pn_response(multiplexer, channel->dlci, channel->pn_priority, channel->max_frame_size);
jksoft 0:fccb789424fc 1372 }
jksoft 0:fccb789424fc 1373 else if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_UA){
jksoft 0:fccb789424fc 1374 log_info("Sending UA #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1375 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
jksoft 0:fccb789424fc 1376 rfcomm_send_ua(multiplexer, channel->dlci);
jksoft 0:fccb789424fc 1377 }
jksoft 0:fccb789424fc 1378 if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) && (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM)) {
jksoft 0:fccb789424fc 1379 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
jksoft 0:fccb789424fc 1380 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
jksoft 0:fccb789424fc 1381 channel->state = RFCOMM_CHANNEL_DLC_SETUP;
jksoft 0:fccb789424fc 1382 }
jksoft 0:fccb789424fc 1383 break;
jksoft 0:fccb789424fc 1384
jksoft 0:fccb789424fc 1385 default:
jksoft 0:fccb789424fc 1386 break;
jksoft 0:fccb789424fc 1387 }
jksoft 0:fccb789424fc 1388 break;
jksoft 0:fccb789424fc 1389
jksoft 0:fccb789424fc 1390 case RFCOMM_CHANNEL_W4_MULTIPLEXER:
jksoft 0:fccb789424fc 1391 switch (event->type) {
jksoft 0:fccb789424fc 1392 case CH_EVT_MULTIPLEXER_READY:
jksoft 0:fccb789424fc 1393 log_info("Muliplexer opened, sending UIH PN next\n");
jksoft 0:fccb789424fc 1394 channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
jksoft 0:fccb789424fc 1395 break;
jksoft 0:fccb789424fc 1396 default:
jksoft 0:fccb789424fc 1397 break;
jksoft 0:fccb789424fc 1398 }
jksoft 0:fccb789424fc 1399 break;
jksoft 0:fccb789424fc 1400
jksoft 0:fccb789424fc 1401 case RFCOMM_CHANNEL_SEND_UIH_PN:
jksoft 0:fccb789424fc 1402 switch (event->type) {
jksoft 0:fccb789424fc 1403 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1404 log_info("Sending UIH Parameter Negotiation Command for #%u (channel 0x%p)\n", channel->dlci, channel );
jksoft 0:fccb789424fc 1405 channel->state = RFCOMM_CHANNEL_W4_PN_RSP;
jksoft 0:fccb789424fc 1406 rfcomm_send_uih_pn_command(multiplexer, channel->dlci, channel->max_frame_size);
jksoft 0:fccb789424fc 1407 break;
jksoft 0:fccb789424fc 1408 default:
jksoft 0:fccb789424fc 1409 break;
jksoft 0:fccb789424fc 1410 }
jksoft 0:fccb789424fc 1411 break;
jksoft 0:fccb789424fc 1412
jksoft 0:fccb789424fc 1413 case RFCOMM_CHANNEL_W4_PN_RSP:
jksoft 0:fccb789424fc 1414 switch (event->type){
jksoft 0:fccb789424fc 1415 case CH_EVT_RCVD_PN_RSP:
jksoft 0:fccb789424fc 1416 // update max frame size
jksoft 0:fccb789424fc 1417 if (channel->max_frame_size > event_pn->max_frame_size) {
jksoft 0:fccb789424fc 1418 channel->max_frame_size = event_pn->max_frame_size;
jksoft 0:fccb789424fc 1419 }
jksoft 0:fccb789424fc 1420 // new credits
jksoft 0:fccb789424fc 1421 channel->credits_outgoing = event_pn->credits_outgoing;
jksoft 0:fccb789424fc 1422 channel->state = RFCOMM_CHANNEL_SEND_SABM_W4_UA;
jksoft 0:fccb789424fc 1423 break;
jksoft 0:fccb789424fc 1424 default:
jksoft 0:fccb789424fc 1425 break;
jksoft 0:fccb789424fc 1426 }
jksoft 0:fccb789424fc 1427 break;
jksoft 0:fccb789424fc 1428
jksoft 0:fccb789424fc 1429 case RFCOMM_CHANNEL_SEND_SABM_W4_UA:
jksoft 0:fccb789424fc 1430 switch (event->type) {
jksoft 0:fccb789424fc 1431 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1432 log_info("Sending SABM #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1433 channel->state = RFCOMM_CHANNEL_W4_UA;
jksoft 0:fccb789424fc 1434 rfcomm_send_sabm(multiplexer, channel->dlci);
jksoft 0:fccb789424fc 1435 break;
jksoft 0:fccb789424fc 1436 default:
jksoft 0:fccb789424fc 1437 break;
jksoft 0:fccb789424fc 1438 }
jksoft 0:fccb789424fc 1439 break;
jksoft 0:fccb789424fc 1440
jksoft 0:fccb789424fc 1441 case RFCOMM_CHANNEL_W4_UA:
jksoft 0:fccb789424fc 1442 switch (event->type){
jksoft 0:fccb789424fc 1443 case CH_EVT_RCVD_UA:
jksoft 0:fccb789424fc 1444 channel->state = RFCOMM_CHANNEL_DLC_SETUP;
jksoft 0:fccb789424fc 1445 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
jksoft 0:fccb789424fc 1446 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
jksoft 0:fccb789424fc 1447 break;
jksoft 0:fccb789424fc 1448 default:
jksoft 0:fccb789424fc 1449 break;
jksoft 0:fccb789424fc 1450 }
jksoft 0:fccb789424fc 1451 break;
jksoft 0:fccb789424fc 1452
jksoft 0:fccb789424fc 1453 case RFCOMM_CHANNEL_DLC_SETUP:
jksoft 0:fccb789424fc 1454 switch (event->type){
jksoft 0:fccb789424fc 1455 case CH_EVT_RCVD_MSC_CMD:
jksoft 0:fccb789424fc 1456 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD;
jksoft 0:fccb789424fc 1457 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
jksoft 0:fccb789424fc 1458 break;
jksoft 0:fccb789424fc 1459 case CH_EVT_RCVD_MSC_RSP:
jksoft 0:fccb789424fc 1460 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP;
jksoft 0:fccb789424fc 1461 break;
jksoft 0:fccb789424fc 1462
jksoft 0:fccb789424fc 1463 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1464 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD){
jksoft 0:fccb789424fc 1465 log_info("Sending MSC CMD for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1466 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
jksoft 0:fccb789424fc 1467 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD;
jksoft 0:fccb789424fc 1468 rfcomm_send_uih_msc_cmd(multiplexer, channel->dlci , 0x8d); // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
jksoft 0:fccb789424fc 1469 break;
jksoft 0:fccb789424fc 1470 }
jksoft 0:fccb789424fc 1471 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
jksoft 0:fccb789424fc 1472 log_info("Sending MSC RSP for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1473 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
jksoft 0:fccb789424fc 1474 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP;
jksoft 0:fccb789424fc 1475 rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d); // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
jksoft 0:fccb789424fc 1476 break;
jksoft 0:fccb789424fc 1477 }
jksoft 0:fccb789424fc 1478 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS){
jksoft 0:fccb789424fc 1479 log_info("Providing credits for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1480 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
jksoft 0:fccb789424fc 1481 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS;
jksoft 0:fccb789424fc 1482 if (channel->new_credits_incoming) {
jksoft 0:fccb789424fc 1483 uint8_t new_credits = channel->new_credits_incoming;
jksoft 0:fccb789424fc 1484 channel->new_credits_incoming = 0;
jksoft 0:fccb789424fc 1485 rfcomm_channel_send_credits(channel, new_credits);
jksoft 0:fccb789424fc 1486 }
jksoft 0:fccb789424fc 1487 break;
jksoft 0:fccb789424fc 1488
jksoft 0:fccb789424fc 1489 }
jksoft 0:fccb789424fc 1490 break;
jksoft 0:fccb789424fc 1491 default:
jksoft 0:fccb789424fc 1492 break;
jksoft 0:fccb789424fc 1493 }
jksoft 0:fccb789424fc 1494 // finally done?
jksoft 0:fccb789424fc 1495 if (rfcomm_channel_ready_for_open(channel)){
jksoft 0:fccb789424fc 1496 channel->state = RFCOMM_CHANNEL_OPEN;
jksoft 0:fccb789424fc 1497 rfcomm_channel_opened(channel);
jksoft 0:fccb789424fc 1498 }
jksoft 0:fccb789424fc 1499 break;
jksoft 0:fccb789424fc 1500
jksoft 0:fccb789424fc 1501 case RFCOMM_CHANNEL_OPEN:
jksoft 0:fccb789424fc 1502 switch (event->type){
jksoft 0:fccb789424fc 1503 case CH_EVT_RCVD_MSC_CMD:
jksoft 0:fccb789424fc 1504 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
jksoft 0:fccb789424fc 1505 break;
jksoft 0:fccb789424fc 1506 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1507 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
jksoft 0:fccb789424fc 1508 log_info("Sending MSC RSP for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1509 channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
jksoft 0:fccb789424fc 1510 rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d); // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
jksoft 0:fccb789424fc 1511 break;
jksoft 0:fccb789424fc 1512 }
jksoft 0:fccb789424fc 1513 if (channel->new_credits_incoming) {
jksoft 0:fccb789424fc 1514 uint8_t new_credits = channel->new_credits_incoming;
jksoft 0:fccb789424fc 1515 channel->new_credits_incoming = 0;
jksoft 0:fccb789424fc 1516 rfcomm_channel_send_credits(channel, new_credits);
jksoft 0:fccb789424fc 1517 break;
jksoft 0:fccb789424fc 1518 }
jksoft 0:fccb789424fc 1519 break;
jksoft 0:fccb789424fc 1520 case CH_EVT_RCVD_CREDITS: {
jksoft 0:fccb789424fc 1521 // notify daemon -> might trigger re-try of parked connections
jksoft 0:fccb789424fc 1522 uint8_t event[1] = { DAEMON_EVENT_NEW_RFCOMM_CREDITS };
jksoft 0:fccb789424fc 1523 (*app_packet_handler)(channel->connection, DAEMON_EVENT_PACKET, channel->rfcomm_cid, event, sizeof(event));
jksoft 0:fccb789424fc 1524 break;
jksoft 0:fccb789424fc 1525 }
jksoft 0:fccb789424fc 1526 default:
jksoft 0:fccb789424fc 1527 break;
jksoft 0:fccb789424fc 1528 }
jksoft 0:fccb789424fc 1529 break;
jksoft 0:fccb789424fc 1530
jksoft 0:fccb789424fc 1531 case RFCOMM_CHANNEL_SEND_DM:
jksoft 0:fccb789424fc 1532 switch (event->type) {
jksoft 0:fccb789424fc 1533 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1534 log_info("Sending DM_PF for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1535 // don't emit channel closed - channel was never open
jksoft 0:fccb789424fc 1536 channel->state = RFCOMM_CHANNEL_CLOSED;
jksoft 0:fccb789424fc 1537 rfcomm_send_dm_pf(multiplexer, channel->dlci);
jksoft 0:fccb789424fc 1538 rfcomm_channel_finalize(channel);
jksoft 0:fccb789424fc 1539 break;
jksoft 0:fccb789424fc 1540 default:
jksoft 0:fccb789424fc 1541 break;
jksoft 0:fccb789424fc 1542 }
jksoft 0:fccb789424fc 1543 break;
jksoft 0:fccb789424fc 1544
jksoft 0:fccb789424fc 1545 case RFCOMM_CHANNEL_SEND_DISC:
jksoft 0:fccb789424fc 1546 switch (event->type) {
jksoft 0:fccb789424fc 1547 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1548 channel->state = RFCOMM_CHANNEL_CLOSED;
jksoft 0:fccb789424fc 1549 rfcomm_send_disc(multiplexer, channel->dlci);
jksoft 0:fccb789424fc 1550 rfcomm_emit_channel_closed(channel);
jksoft 0:fccb789424fc 1551 rfcomm_channel_finalize(channel);
jksoft 0:fccb789424fc 1552 break;
jksoft 0:fccb789424fc 1553 default:
jksoft 0:fccb789424fc 1554 break;
jksoft 0:fccb789424fc 1555 }
jksoft 0:fccb789424fc 1556 break;
jksoft 0:fccb789424fc 1557
jksoft 0:fccb789424fc 1558 case RFCOMM_CHANNEL_SEND_UA_AFTER_DISC:
jksoft 0:fccb789424fc 1559 switch (event->type) {
jksoft 0:fccb789424fc 1560 case CH_EVT_READY_TO_SEND:
jksoft 0:fccb789424fc 1561 log_info("Sending UA after DISC for #%u\n", channel->dlci);
jksoft 0:fccb789424fc 1562 channel->state = RFCOMM_CHANNEL_CLOSED;
jksoft 0:fccb789424fc 1563 rfcomm_send_ua(multiplexer, channel->dlci);
jksoft 0:fccb789424fc 1564 rfcomm_channel_finalize(channel);
jksoft 0:fccb789424fc 1565 break;
jksoft 0:fccb789424fc 1566 default:
jksoft 0:fccb789424fc 1567 break;
jksoft 0:fccb789424fc 1568 }
jksoft 0:fccb789424fc 1569 break;
jksoft 0:fccb789424fc 1570
jksoft 0:fccb789424fc 1571 default:
jksoft 0:fccb789424fc 1572 break;
jksoft 0:fccb789424fc 1573 }
jksoft 0:fccb789424fc 1574 }
jksoft 0:fccb789424fc 1575
jksoft 0:fccb789424fc 1576
jksoft 0:fccb789424fc 1577 // MARK: RFCOMM RUN
jksoft 0:fccb789424fc 1578 // process outstanding signaling tasks
jksoft 0:fccb789424fc 1579 static void rfcomm_run(void){
jksoft 0:fccb789424fc 1580
jksoft 0:fccb789424fc 1581 linked_item_t *it;
jksoft 0:fccb789424fc 1582 linked_item_t *next;
jksoft 0:fccb789424fc 1583
jksoft 0:fccb789424fc 1584 for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = next){
jksoft 0:fccb789424fc 1585
jksoft 0:fccb789424fc 1586 next = it->next; // be prepared for removal of channel in state machine
jksoft 0:fccb789424fc 1587
jksoft 0:fccb789424fc 1588 rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
jksoft 0:fccb789424fc 1589
jksoft 0:fccb789424fc 1590 if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) {
jksoft 0:fccb789424fc 1591 // log_info("rfcomm_run cannot send l2cap packet for #%u, credits %u\n", multiplexer->l2cap_cid, multiplexer->l2cap_credits);
jksoft 0:fccb789424fc 1592 continue;
jksoft 0:fccb789424fc 1593 }
jksoft 0:fccb789424fc 1594 // log_info("rfcomm_run: multi 0x%08x, state %u\n", (int) multiplexer, multiplexer->state);
jksoft 0:fccb789424fc 1595
jksoft 0:fccb789424fc 1596 rfcomm_multiplexer_state_machine(multiplexer, MULT_EV_READY_TO_SEND);
jksoft 0:fccb789424fc 1597 }
jksoft 0:fccb789424fc 1598
jksoft 0:fccb789424fc 1599 for (it = (linked_item_t *) rfcomm_channels; it ; it = next){
jksoft 0:fccb789424fc 1600
jksoft 0:fccb789424fc 1601 next = it->next; // be prepared for removal of channel in state machine
jksoft 0:fccb789424fc 1602
jksoft 0:fccb789424fc 1603 rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
jksoft 0:fccb789424fc 1604 rfcomm_multiplexer_t * multiplexer = channel->multiplexer;
jksoft 0:fccb789424fc 1605
jksoft 0:fccb789424fc 1606 if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) continue;
jksoft 0:fccb789424fc 1607
jksoft 0:fccb789424fc 1608 rfcomm_channel_event_t event = { CH_EVT_READY_TO_SEND };
jksoft 0:fccb789424fc 1609 rfcomm_channel_state_machine(channel, &event);
jksoft 0:fccb789424fc 1610 }
jksoft 0:fccb789424fc 1611 }
jksoft 0:fccb789424fc 1612
jksoft 0:fccb789424fc 1613 // MARK: RFCOMM BTstack API
jksoft 0:fccb789424fc 1614
jksoft 0:fccb789424fc 1615 void rfcomm_init(void){
jksoft 0:fccb789424fc 1616 rfcomm_client_cid_generator = 0;
jksoft 0:fccb789424fc 1617 rfcomm_multiplexers = NULL;
jksoft 0:fccb789424fc 1618 rfcomm_services = NULL;
jksoft 0:fccb789424fc 1619 rfcomm_channels = NULL;
jksoft 0:fccb789424fc 1620 }
jksoft 0:fccb789424fc 1621
jksoft 0:fccb789424fc 1622 // register packet handler
jksoft 0:fccb789424fc 1623 void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
jksoft 0:fccb789424fc 1624 uint16_t channel, uint8_t *packet, uint16_t size)){
jksoft 0:fccb789424fc 1625 app_packet_handler = handler;
jksoft 0:fccb789424fc 1626 }
jksoft 0:fccb789424fc 1627
jksoft 0:fccb789424fc 1628 // send packet over specific channel
jksoft 0:fccb789424fc 1629 int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
jksoft 0:fccb789424fc 1630
jksoft 0:fccb789424fc 1631 rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
jksoft 0:fccb789424fc 1632 if (!channel){
jksoft 0:fccb789424fc 1633 log_error("rfcomm_send_internal cid %u doesn't exist!\n", rfcomm_cid);
jksoft 0:fccb789424fc 1634 return 0;
jksoft 0:fccb789424fc 1635 }
jksoft 0:fccb789424fc 1636
jksoft 0:fccb789424fc 1637 if (!channel->credits_outgoing){
jksoft 0:fccb789424fc 1638 log_info("rfcomm_send_internal cid %u, no rfcomm outgoing credits!\n", rfcomm_cid);
jksoft 0:fccb789424fc 1639 return RFCOMM_NO_OUTGOING_CREDITS;
jksoft 0:fccb789424fc 1640 }
jksoft 0:fccb789424fc 1641
jksoft 0:fccb789424fc 1642 if (!channel->packets_granted){
jksoft 0:fccb789424fc 1643 log_info("rfcomm_send_internal cid %u, no rfcomm credits granted!\n", rfcomm_cid);
jksoft 0:fccb789424fc 1644 return RFCOMM_NO_OUTGOING_CREDITS;
jksoft 0:fccb789424fc 1645 }
jksoft 0:fccb789424fc 1646
jksoft 0:fccb789424fc 1647 // log_info("rfcomm_send_internal: len %u... outgoing credits %u, l2cap credit %us, granted %u\n",
jksoft 0:fccb789424fc 1648 // len, channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
jksoft 0:fccb789424fc 1649
jksoft 0:fccb789424fc 1650
jksoft 0:fccb789424fc 1651 // send might cause l2cap to emit new credits, update counters first
jksoft 0:fccb789424fc 1652 channel->credits_outgoing--;
jksoft 0:fccb789424fc 1653 int packets_granted_decreased = 0;
jksoft 0:fccb789424fc 1654 if (channel->packets_granted) {
jksoft 0:fccb789424fc 1655 channel->packets_granted--;
jksoft 0:fccb789424fc 1656 packets_granted_decreased++;
jksoft 0:fccb789424fc 1657 }
jksoft 0:fccb789424fc 1658
jksoft 0:fccb789424fc 1659 int result = rfcomm_send_uih_data(channel->multiplexer, channel->dlci, data, len);
jksoft 0:fccb789424fc 1660
jksoft 0:fccb789424fc 1661 if (result != 0) {
jksoft 0:fccb789424fc 1662 channel->credits_outgoing++;
jksoft 0:fccb789424fc 1663 channel->packets_granted += packets_granted_decreased;
jksoft 0:fccb789424fc 1664 log_info("rfcomm_send_internal: error %d\n", result);
jksoft 0:fccb789424fc 1665 return result;
jksoft 0:fccb789424fc 1666 }
jksoft 0:fccb789424fc 1667
jksoft 0:fccb789424fc 1668 // log_info("rfcomm_send_internal: now outgoing credits %u, l2cap credit %us, granted %u\n",
jksoft 0:fccb789424fc 1669 // channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
jksoft 0:fccb789424fc 1670
jksoft 0:fccb789424fc 1671 rfcomm_hand_out_credits();
jksoft 0:fccb789424fc 1672
jksoft 0:fccb789424fc 1673 return result;
jksoft 0:fccb789424fc 1674 }
jksoft 0:fccb789424fc 1675
jksoft 0:fccb789424fc 1676 void rfcomm_create_channel2(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t incoming_flow_control, uint8_t initial_credits){
jksoft 0:fccb789424fc 1677 log_info("rfcomm_create_channel_internal to %s, at channel #%02x, flow control %u, init credits %u\n", bd_addr_to_str(*addr), server_channel,
jksoft 0:fccb789424fc 1678 incoming_flow_control, initial_credits);
jksoft 0:fccb789424fc 1679
jksoft 0:fccb789424fc 1680 // create new multiplexer if necessary
jksoft 0:fccb789424fc 1681 rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_addr(addr);
jksoft 0:fccb789424fc 1682 if (!multiplexer) {
jksoft 0:fccb789424fc 1683 multiplexer = rfcomm_multiplexer_create_for_addr(addr);
jksoft 0:fccb789424fc 1684 if (!multiplexer){
jksoft 0:fccb789424fc 1685 rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
jksoft 0:fccb789424fc 1686 return;
jksoft 0:fccb789424fc 1687 }
jksoft 0:fccb789424fc 1688 multiplexer->outgoing = 1;
jksoft 0:fccb789424fc 1689 multiplexer->state = RFCOMM_MULTIPLEXER_W4_CONNECT;
jksoft 0:fccb789424fc 1690 }
jksoft 0:fccb789424fc 1691
jksoft 0:fccb789424fc 1692 // prepare channel
jksoft 0:fccb789424fc 1693 rfcomm_channel_t * channel = rfcomm_channel_create(multiplexer, NULL, server_channel);
jksoft 0:fccb789424fc 1694 if (!channel){
jksoft 0:fccb789424fc 1695 rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
jksoft 0:fccb789424fc 1696 return;
jksoft 0:fccb789424fc 1697 }
jksoft 0:fccb789424fc 1698 channel->connection = connection;
jksoft 0:fccb789424fc 1699 channel->incoming_flow_control = incoming_flow_control;
jksoft 0:fccb789424fc 1700 channel->new_credits_incoming = initial_credits;
jksoft 0:fccb789424fc 1701
jksoft 0:fccb789424fc 1702 // start multiplexer setup
jksoft 0:fccb789424fc 1703 if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
jksoft 0:fccb789424fc 1704
jksoft 0:fccb789424fc 1705 channel->state = RFCOMM_CHANNEL_W4_MULTIPLEXER;
jksoft 0:fccb789424fc 1706
jksoft 0:fccb789424fc 1707 l2cap_create_channel_internal(connection, rfcomm_packet_handler, *addr, PSM_RFCOMM, l2cap_max_mtu());
jksoft 0:fccb789424fc 1708
jksoft 0:fccb789424fc 1709 return;
jksoft 0:fccb789424fc 1710 }
jksoft 0:fccb789424fc 1711
jksoft 0:fccb789424fc 1712 channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
jksoft 0:fccb789424fc 1713
jksoft 0:fccb789424fc 1714 // start connecting, if multiplexer is already up and running
jksoft 0:fccb789424fc 1715 rfcomm_run();
jksoft 0:fccb789424fc 1716 }
jksoft 0:fccb789424fc 1717
jksoft 0:fccb789424fc 1718 void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits){
jksoft 0:fccb789424fc 1719 rfcomm_create_channel2(connection, addr, server_channel, 1, initial_credits);
jksoft 0:fccb789424fc 1720 }
jksoft 0:fccb789424fc 1721
jksoft 0:fccb789424fc 1722 void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t server_channel){
jksoft 0:fccb789424fc 1723 rfcomm_create_channel2(connection, addr, server_channel, 0, 0x30);
jksoft 0:fccb789424fc 1724 }
jksoft 0:fccb789424fc 1725
jksoft 0:fccb789424fc 1726 void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
jksoft 0:fccb789424fc 1727 rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
jksoft 0:fccb789424fc 1728 if (channel) {
jksoft 0:fccb789424fc 1729 channel->state = RFCOMM_CHANNEL_SEND_DISC;
jksoft 0:fccb789424fc 1730 }
jksoft 0:fccb789424fc 1731
jksoft 0:fccb789424fc 1732 // process
jksoft 0:fccb789424fc 1733 rfcomm_run();
jksoft 0:fccb789424fc 1734 }
jksoft 0:fccb789424fc 1735
jksoft 0:fccb789424fc 1736
jksoft 0:fccb789424fc 1737 void rfcomm_register_service2(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){
jksoft 0:fccb789424fc 1738 // check if already registered
jksoft 0:fccb789424fc 1739 rfcomm_service_t * service = rfcomm_service_for_channel(channel);
jksoft 0:fccb789424fc 1740 if (service){
jksoft 0:fccb789424fc 1741 rfcomm_emit_service_registered(connection, RFCOMM_CHANNEL_ALREADY_REGISTERED, channel);
jksoft 0:fccb789424fc 1742 return;
jksoft 0:fccb789424fc 1743 }
jksoft 0:fccb789424fc 1744
jksoft 0:fccb789424fc 1745 // alloc structure
jksoft 0:fccb789424fc 1746 service = (rfcomm_service_t*)btstack_memory_rfcomm_service_get();
jksoft 0:fccb789424fc 1747 if (!service) {
jksoft 0:fccb789424fc 1748 rfcomm_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, channel);
jksoft 0:fccb789424fc 1749 return;
jksoft 0:fccb789424fc 1750 }
jksoft 0:fccb789424fc 1751
jksoft 0:fccb789424fc 1752 // register with l2cap if not registered before, max MTU
jksoft 0:fccb789424fc 1753 if (linked_list_empty(&rfcomm_services)){
jksoft 0:fccb789424fc 1754 l2cap_register_service_internal(NULL, rfcomm_packet_handler, PSM_RFCOMM, 0xffff);
jksoft 0:fccb789424fc 1755 }
jksoft 0:fccb789424fc 1756
jksoft 0:fccb789424fc 1757 // fill in
jksoft 0:fccb789424fc 1758 service->connection = connection;
jksoft 0:fccb789424fc 1759 service->server_channel = channel;
jksoft 0:fccb789424fc 1760 service->max_frame_size = max_frame_size;
jksoft 0:fccb789424fc 1761 service->incoming_flow_control = incoming_flow_control;
jksoft 0:fccb789424fc 1762 service->incoming_initial_credits = initial_credits;
jksoft 0:fccb789424fc 1763
jksoft 0:fccb789424fc 1764 // add to services list
jksoft 0:fccb789424fc 1765 linked_list_add(&rfcomm_services, (linked_item_t *) service);
jksoft 0:fccb789424fc 1766
jksoft 0:fccb789424fc 1767 // done
jksoft 0:fccb789424fc 1768 rfcomm_emit_service_registered(connection, 0, channel);
jksoft 0:fccb789424fc 1769 }
jksoft 0:fccb789424fc 1770
jksoft 0:fccb789424fc 1771 void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits){
jksoft 0:fccb789424fc 1772 rfcomm_register_service2(connection, channel, max_frame_size, 1, initial_credits);
jksoft 0:fccb789424fc 1773 }
jksoft 0:fccb789424fc 1774
jksoft 0:fccb789424fc 1775 void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
jksoft 0:fccb789424fc 1776 rfcomm_register_service2(connection, channel, max_frame_size, 0, 0x30);
jksoft 0:fccb789424fc 1777 }
jksoft 0:fccb789424fc 1778
jksoft 0:fccb789424fc 1779 void rfcomm_unregister_service_internal(uint8_t service_channel){
jksoft 0:fccb789424fc 1780 rfcomm_service_t *service = rfcomm_service_for_channel(service_channel);
jksoft 0:fccb789424fc 1781 if (!service) return;
jksoft 0:fccb789424fc 1782 linked_list_remove(&rfcomm_services, (linked_item_t *) service);
jksoft 0:fccb789424fc 1783 btstack_memory_rfcomm_service_free(service);
jksoft 0:fccb789424fc 1784
jksoft 0:fccb789424fc 1785 // unregister if no services active
jksoft 0:fccb789424fc 1786 if (linked_list_empty(&rfcomm_services)){
jksoft 0:fccb789424fc 1787 // bt_send_cmd(&l2cap_unregister_service, PSM_RFCOMM);
jksoft 0:fccb789424fc 1788 l2cap_unregister_service_internal(NULL, PSM_RFCOMM);
jksoft 0:fccb789424fc 1789 }
jksoft 0:fccb789424fc 1790 }
jksoft 0:fccb789424fc 1791
jksoft 0:fccb789424fc 1792 void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
jksoft 0:fccb789424fc 1793 log_info("Received Accept Connction\n");
jksoft 0:fccb789424fc 1794 rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
jksoft 0:fccb789424fc 1795 if (!channel) return;
jksoft 0:fccb789424fc 1796 switch (channel->state) {
jksoft 0:fccb789424fc 1797 case RFCOMM_CHANNEL_INCOMING_SETUP:
jksoft 0:fccb789424fc 1798 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED;
jksoft 0:fccb789424fc 1799 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_PN){
jksoft 0:fccb789424fc 1800 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
jksoft 0:fccb789424fc 1801 }
jksoft 0:fccb789424fc 1802 if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM){
jksoft 0:fccb789424fc 1803 channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
jksoft 0:fccb789424fc 1804 }
jksoft 0:fccb789424fc 1805 break;
jksoft 0:fccb789424fc 1806 default:
jksoft 0:fccb789424fc 1807 break;
jksoft 0:fccb789424fc 1808 }
jksoft 0:fccb789424fc 1809
jksoft 0:fccb789424fc 1810 // process
jksoft 0:fccb789424fc 1811 rfcomm_run();
jksoft 0:fccb789424fc 1812 }
jksoft 0:fccb789424fc 1813
jksoft 0:fccb789424fc 1814 void rfcomm_decline_connection_internal(uint16_t rfcomm_cid){
jksoft 0:fccb789424fc 1815 log_info("Received Decline Connction\n");
jksoft 0:fccb789424fc 1816 rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
jksoft 0:fccb789424fc 1817 if (!channel) return;
jksoft 0:fccb789424fc 1818 switch (channel->state) {
jksoft 0:fccb789424fc 1819 case RFCOMM_CHANNEL_INCOMING_SETUP:
jksoft 0:fccb789424fc 1820 channel->state = RFCOMM_CHANNEL_SEND_DM;
jksoft 0:fccb789424fc 1821 break;
jksoft 0:fccb789424fc 1822 default:
jksoft 0:fccb789424fc 1823 break;
jksoft 0:fccb789424fc 1824 }
jksoft 0:fccb789424fc 1825
jksoft 0:fccb789424fc 1826 // process
jksoft 0:fccb789424fc 1827 rfcomm_run();
jksoft 0:fccb789424fc 1828 }
jksoft 0:fccb789424fc 1829
jksoft 0:fccb789424fc 1830 void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits){
jksoft 0:fccb789424fc 1831 rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
jksoft 0:fccb789424fc 1832 if (!channel) return;
jksoft 0:fccb789424fc 1833 if (!channel->incoming_flow_control) return;
jksoft 0:fccb789424fc 1834 channel->new_credits_incoming += credits;
jksoft 0:fccb789424fc 1835
jksoft 0:fccb789424fc 1836 // process
jksoft 0:fccb789424fc 1837 rfcomm_run();
jksoft 0:fccb789424fc 1838 }
jksoft 0:fccb789424fc 1839
jksoft 0:fccb789424fc 1840 //
jksoft 0:fccb789424fc 1841 void rfcomm_close_connection(void *connection){
jksoft 0:fccb789424fc 1842 linked_item_t *it;
jksoft 0:fccb789424fc 1843
jksoft 0:fccb789424fc 1844 // close open channels
jksoft 0:fccb789424fc 1845 for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
jksoft 0:fccb789424fc 1846 rfcomm_channel_t * channel = (rfcomm_channel_t *)it;
jksoft 0:fccb789424fc 1847 if (channel->connection != connection) continue;
jksoft 0:fccb789424fc 1848 channel->state = RFCOMM_CHANNEL_SEND_DISC;
jksoft 0:fccb789424fc 1849 }
jksoft 0:fccb789424fc 1850
jksoft 0:fccb789424fc 1851 // unregister services
jksoft 0:fccb789424fc 1852 it = (linked_item_t *) &rfcomm_services;
jksoft 0:fccb789424fc 1853 while (it->next) {
jksoft 0:fccb789424fc 1854 rfcomm_service_t * service = (rfcomm_service_t *) it->next;
jksoft 0:fccb789424fc 1855 if (service->connection == connection){
jksoft 0:fccb789424fc 1856 it->next = it->next->next;
jksoft 0:fccb789424fc 1857 btstack_memory_rfcomm_service_free(service);
jksoft 0:fccb789424fc 1858 } else {
jksoft 0:fccb789424fc 1859 it = it->next;
jksoft 0:fccb789424fc 1860 }
jksoft 0:fccb789424fc 1861 }
jksoft 0:fccb789424fc 1862
jksoft 0:fccb789424fc 1863 // process
jksoft 0:fccb789424fc 1864 rfcomm_run();
jksoft 0:fccb789424fc 1865 }
jksoft 0:fccb789424fc 1866
jksoft 0:fccb789424fc 1867
jksoft 0:fccb789424fc 1868
jksoft 0:fccb789424fc 1869