12 #define MIN(a, b) ((a < b) ? (a) : (b))
14 #define MAX_EP_SIZE 64
15 #define HID_HEADER_SIZE 3
16 #define MAX_KNX_TELEGRAM_SIZE 263
17 #define KNX_HID_REPORT_ID 0x01
18 #define PROTOCOL_VERSION 0x00
19 #define PROTOCOL_HEADER_LENGTH 0x08
22 #define MAX_DATASIZE_START_PACKET 52
23 #define MAX_DATASIZE_PARTIAL_PACKET 61
25 #define PACKET_TYPE_START 1
26 #define PACKET_TYPE_END 2
27 #define PACKET_TYPE_PARTIAL 4
40 : _cemiServer(cemiServer),
53 loadNextTxFrame(&buffer, &length);
61 if (rxHaveCompletePacket)
63 handleHidReportRxQueue();
64 rxHaveCompletePacket =
false;
75 void UsbTunnelInterface::addBufferTxQueue(uint8_t* data, uint16_t length)
77 _queue_buffer_t* tx_buffer =
new _queue_buffer_t;
79 tx_buffer->length = MAX_EP_SIZE;
80 tx_buffer->data =
new uint8_t[MAX_EP_SIZE];
81 tx_buffer->next =
nullptr;
83 memcpy(tx_buffer->data, data, tx_buffer->length);
84 memset(&tx_buffer->data[length], 0x00, MAX_EP_SIZE - length);
86 if (_tx_queue.back ==
nullptr)
88 _tx_queue.front = _tx_queue.back = tx_buffer;
92 _tx_queue.back->next = tx_buffer;
93 _tx_queue.back = tx_buffer;
97 bool UsbTunnelInterface::isTxQueueEmpty()
99 if (_tx_queue.front ==
nullptr)
107 void UsbTunnelInterface::loadNextTxFrame(uint8_t** sendBuffer, uint16_t* sendBufferLength)
109 if (_tx_queue.front ==
nullptr)
114 _queue_buffer_t* tx_buffer = _tx_queue.front;
115 *sendBuffer = tx_buffer->data;
116 *sendBufferLength = tx_buffer->length;
117 _tx_queue.front = tx_buffer->next;
119 if (_tx_queue.front ==
nullptr)
121 _tx_queue.back =
nullptr;
126 #ifdef DEBUG_TX_HID_REPORT
127 print(
"TX HID report: len: ");
129 uint8_t len = (*sendBuffer)[2];
132 for (
int i = 0; i < len; i++)
134 if ((*sendBuffer)[i] < 16)
137 print((*sendBuffer)[i], HEX);
147 uint16_t maxData = MAX_DATASIZE_START_PACKET;
148 uint8_t packetType = PACKET_TYPE_START;
150 if (length > maxData)
152 packetType |= PACKET_TYPE_PARTIAL;
156 uint8_t* buffer =
nullptr;
162 for (uint8_t seqNum = 1; seqNum < 6; seqNum++)
164 uint16_t copyLen = MIN(length, maxData);
167 if (packetType & PACKET_TYPE_START)
169 buffer =
new uint8_t[copyLen + 8 + HID_HEADER_SIZE];
170 buffer[2] = 8 + copyLen;
171 buffer[3] = PROTOCOL_VERSION;
172 buffer[4] = PROTOCOL_HEADER_LENGTH;
174 buffer[7] = (uint8_t) protId;
178 memcpy(&buffer[11], &data[offset], copyLen);
182 buffer =
new uint8_t[copyLen];
184 memcpy(&buffer[0], &data[offset], copyLen);
189 if (offset >= length)
191 packetType |= PACKET_TYPE_END;
194 buffer[0] = KNX_HID_REPORT_ID;
195 buffer[1] = ((seqNum << 4) & 0xF0) | (packetType & 0x07);
197 addBufferTxQueue(buffer, (buffer[2] + HID_HEADER_SIZE));
201 if (offset >= length)
206 packetType &= ~PACKET_TYPE_START;
207 maxData = MAX_DATASIZE_PARTIAL_PACKET;
217 if (data[0] == KNX_HID_REPORT_ID)
221 uint8_t packetLength = data[2] + HID_HEADER_SIZE;
222 UsbTunnelInterface::addBufferRxQueue(data, packetLength);
225 if ((data[1] & PACKET_TYPE_END) == PACKET_TYPE_END)
228 rxHaveCompletePacket =
true;
233 UsbTunnelInterface::_queue_t UsbTunnelInterface::_rx_queue;
234 bool UsbTunnelInterface::rxHaveCompletePacket =
false;
236 void UsbTunnelInterface::addBufferRxQueue(
const uint8_t* data, uint16_t length)
238 _queue_buffer_t* rx_buffer =
new _queue_buffer_t;
240 rx_buffer->length = length;
241 rx_buffer->data =
new uint8_t[rx_buffer->length];
242 rx_buffer->next =
nullptr;
244 memcpy(rx_buffer->data, data, rx_buffer->length);
246 if (_rx_queue.back ==
nullptr)
248 _rx_queue.front = _rx_queue.back = rx_buffer;
252 _rx_queue.back->next = rx_buffer;
253 _rx_queue.back = rx_buffer;
257 bool UsbTunnelInterface::isRxQueueEmpty()
259 if (_rx_queue.front ==
nullptr)
267 void UsbTunnelInterface::loadNextRxBuffer(uint8_t** receiveBuffer, uint16_t* receiveBufferLength)
269 if (_rx_queue.front ==
nullptr)
274 _queue_buffer_t* rx_buffer = _rx_queue.front;
275 *receiveBuffer = rx_buffer->data;
276 *receiveBufferLength = rx_buffer->length;
277 _rx_queue.front = rx_buffer->next;
279 if (_rx_queue.front ==
nullptr)
281 _rx_queue.back =
nullptr;
286 #ifdef DEBUG_RX_HID_REPORT
287 print(
"RX HID report: len: ");
288 println(*receiveBufferLength, DEC);
290 for (
int i = 0; i < (*receiveBufferLength); i++)
292 if ((*receiveBuffer)[i] < 16)
295 print((*receiveBuffer)[i], HEX);
303 void UsbTunnelInterface::handleTransferProtocolPacket(uint8_t* data, uint16_t length)
305 if (data[0] == PROTOCOL_VERSION &&
306 data[1] == PROTOCOL_HEADER_LENGTH)
309 popWord(bodyLength, (uint8_t*)&data[2]);
313 handleBusAccessServerProtocol((
ServiceIdType)data[5], &data[8], bodyLength);
317 if (data[5] == (uint8_t)
CEMI)
320 CemiFrame frame((uint8_t*)&data[8], bodyLength);
332 println(
"Error: Only cEMI is supported!");
338 void UsbTunnelInterface::handleHidReportRxQueue()
340 if (isRxQueueEmpty())
342 println(
"Error: RX HID report queue was empty!");
346 uint8_t tpPacket[MAX_KNX_TELEGRAM_SIZE + PROTOCOL_HEADER_LENGTH];
348 bool success =
false;
356 for (
int expSeqNum = 1; expSeqNum < 6; expSeqNum++)
362 loadNextRxBuffer(&data, &bufSize);
365 uint8_t seqNum = data[1] >> 4;
366 uint8_t packetType = data[1] & 0x07;
367 uint8_t packetLength = MIN(data[2], bufSize - HID_HEADER_SIZE);
370 if (expSeqNum != seqNum)
372 println(
"Error: Wrong sequence number!");
378 if ((expSeqNum == 1) && ((packetType & PACKET_TYPE_START) != PACKET_TYPE_START))
380 println(
"Error: Sequence number 1 does not contain a START packet!");
386 if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START))
388 println(
"Error: Sequence number (!=1) contains a START packet!");
394 if ((expSeqNum != 1) && ((packetType & PACKET_TYPE_PARTIAL) != PACKET_TYPE_PARTIAL))
396 println(
"Error: Sequence number (!=1) must be a PARTIAL packet!");
402 if ((packetType & PACKET_TYPE_START) == PACKET_TYPE_START)
408 memcpy(&tpPacket[offset], &data[3], packetLength);
412 offset += packetLength;
415 if ((packetType & PACKET_TYPE_END) == PACKET_TYPE_END)
425 handleTransferProtocolPacket(tpPacket, offset);
429 println(
"Error: Did not find END packet!");
433 void UsbTunnelInterface::handleBusAccessServerProtocol(
ServiceIdType servId,
const uint8_t* requestData, uint16_t packetLength)
442 respData[0] = (uint8_t) featureId;
447 println(
"Device Feature Get: Supported EMI types");
454 println(
"Device Feature Get: Host Device Descriptor Type 0");
455 pushWord(_maskVersion, &respData[1]);
460 println(
"Device Feature Get: Bus connection status");
466 println(
"Device Feature Get: KNX manufacturer code");
467 pushWord(_manufacturerId, &respData[1]);
472 println(
"Device Feature Get: Active EMI type");
473 respData[1] = (uint8_t)
CEMI;
491 print(
"Device Feature Set: Active EMI type: ");
493 if (requestData[1] < 16)
522 const uint8_t UsbTunnelInterface::descHidReport[] =
557 return &descHidReport[0];
562 return sizeof(descHidReport);
uint8_t * pushWord(uint16_t w, uint8_t *data)
const uint8_t * popWord(uint16_t &w, const uint8_t *data)
This is an implementation of the cEMI server as specified in .
void frameReceived(CemiFrame &frame)
static void receiveHidReport(uint8_t const *data, uint16_t bufSize)
void sendCemiFrame(CemiFrame &frame)
UsbTunnelInterface(CemiServer &cemiServer, uint16_t manufacturerId, uint16_t maskVersion)
static const uint8_t * getKnxHidReportDescriptor()
static uint16_t getHidReportDescriptorLength()
bool sendHidReport(uint8_t *data, uint16_t length)
bool isSendHidReportPossible()
@ HostDeviceDescriptorType0