diff --git a/src/knx/bau.cpp b/src/knx/bau.cpp index 2b71c2f..3d32f28 100644 --- a/src/knx/bau.cpp +++ b/src/knx/bau.cpp @@ -257,7 +257,7 @@ void BusAccessUnit::domainAddressSerialNumberReadIndication(Priority priority, H } void BusAccessUnit::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint32_t &numberOfElements, uint16_t startIndex, - uint8_t *data, uint32_t &dataSize) + uint8_t **data, uint32_t &dataSize) { } diff --git a/src/knx/bau.h b/src/knx/bau.h index 31c4117..602a626 100644 --- a/src/knx/bau.h +++ b/src/knx/bau.h @@ -120,5 +120,5 @@ class BusAccessUnit virtual void domainAddressSerialNumberReadIndication(Priority priority, HopCountType hopType, uint8_t* knxSerialNumber); virtual void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint32_t &numberOfElements, uint16_t startIndex, - uint8_t *data, uint32_t &dataSize); + uint8_t **data, uint32_t &dataSize); }; diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index e71510a..543ffa8 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -393,7 +393,7 @@ void BauSystemB::systemNetworkParameterReadIndication(Priority priority, HopCoun } void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, - uint32_t &numberOfElements, uint16_t startIndex, uint8_t *data, uint32_t &dataSize) + uint32_t &numberOfElements, uint16_t startIndex, uint8_t **data, uint32_t &dataSize) { uint32_t size = 0; uint32_t elementCount = numberOfElements; @@ -404,13 +404,13 @@ void BauSystemB::propertyValueRead(ObjectType objectType, uint8_t objectInstance { uint8_t elementSize = obj->propertySize((PropertyID)propertyId); size = elementSize * numberOfElements; - data = new uint8_t [size]; - obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); + *data = new uint8_t [size]; + obj->readProperty((PropertyID)propertyId, startIndex, elementCount, *data); } else { elementCount = 0; - data = nullptr; + *data = nullptr; } numberOfElements = elementCount; diff --git a/src/knx/bau_systemB.h b/src/knx/bau_systemB.h index 978b94e..24cf18c 100644 --- a/src/knx/bau_systemB.h +++ b/src/knx/bau_systemB.h @@ -62,7 +62,7 @@ class BauSystemB : protected BusAccessUnit uint16_t propertyId, uint8_t* testInfo, uint16_t testinfoLength) override; void connectConfirm(uint16_t tsap) override; void propertyValueRead(ObjectType objectType, uint8_t objectInstance, uint8_t propertyId, uint32_t &numberOfElements, uint16_t startIndex, - uint8_t *data, uint32_t &dataSize) override; + uint8_t **data, uint32_t &dataSize) override; virtual InterfaceObject* getInterfaceObject(uint8_t idx) = 0; virtual InterfaceObject* getInterfaceObject(ObjectType objectType, uint8_t objectInstance) = 0; diff --git a/src/knx/cemi_server.cpp b/src/knx/cemi_server.cpp index 5b2f7f2..f9cb7c4 100644 --- a/src/knx/cemi_server.cpp +++ b/src/knx/cemi_server.cpp @@ -89,31 +89,109 @@ void CemiServer::frameReceived(CemiFrame& frame) case M_PropRead_req: { - uint8_t* data; - uint32_t dataSize; - //ObjectType opjectType = data[] - //_bau.propertyValueRead() println("M_PropRead_req"); + + uint16_t objectType; + popWord(objectType, &frame.data()[1]); + uint8_t objectInstance = frame.data()[3]; + uint8_t propertyId = frame.data()[4]; + uint32_t numberOfElements = frame.data()[5] >> 4; + uint16_t startIndex = frame.data()[6] | ((frame.data()[5]&0x0F)<<8); + uint8_t* data = nullptr; + uint32_t dataSize = 0; + + // propertyValueRead() allocates memory for the data! Needs to be deleted again! + _bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize); + + if (data && dataSize && numberOfElements) + { + // Prepare positive response + uint8_t responseData[7 + dataSize]; + memcpy(responseData, frame.data(), 7); + memcpy(&responseData[7], data, dataSize); + + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropRead_con); + _usbTunnelInterface.sendCemiFrame(responseFrame); + + delete data; + } + else + { + // Prepare negative response + uint8_t responseData[7 + 1]; + memcpy(responseData, frame.data(), sizeof(responseData)); + responseData[7] = Void_DP; // Set cEMI error code + responseData[5] = 0; // Set Number of elements to zero + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropRead_con); + _usbTunnelInterface.sendCemiFrame(responseFrame); + } break; } case M_PropWrite_req: { + println("M_PropWrite_req"); + + uint16_t objectType; + popWord(objectType, &frame.data()[1]); + uint8_t objectInstance = frame.data()[3]; + uint8_t propertyId = frame.data()[4]; + uint32_t numberOfElements = frame.data()[5] >> 4; + uint16_t startIndex = frame.data()[6] | ((frame.data()[5]&0x0F)<<8); + uint8_t* requestData = &frame.data()[7]; + uint32_t requestDataSize = frame.dataLength() - 7; + // propertyValueRead() allocates memory for the data! Needs to be deleted again! + //_bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, data, dataSize); +if (propertyId != 0x34 && objectType!= OT_CEMI_SERVER) +{ +numberOfElements = 0; +} + if (numberOfElements) + { + // Prepare positive response + uint8_t responseData[7]; + memcpy(responseData, frame.data(), sizeof(responseData)); + + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropWrite_con); + _usbTunnelInterface.sendCemiFrame(responseFrame); + } + else + { + // Prepare negative response + uint8_t responseData[7 + 1]; + memcpy(responseData, frame.data(), sizeof(responseData)); + responseData[7] = Illegal_Command; // Set cEMI error code + responseData[5] = 0; // Set Number of elements to zero + + CemiFrame responseFrame(responseData, sizeof(responseData)); + responseFrame.messageCode(M_PropWrite_con); + _usbTunnelInterface.sendCemiFrame(responseFrame); + } break; } case M_FuncPropCommand_req: { + println("M_FuncPropCommand_req"); break; } case M_FuncPropStateRead_req: { + println("M_FuncPropStateRead_req"); break; } case M_Reset_req: { + println("M_Reset_req"); + // A real device reset does not work with USB + // M_Reset_ind is not mandatory for USB and KNXNET/IP + // Flush the EEPROM before resetting + //_bau.writeMemory(); break; } diff --git a/src/knx/usb_data_link_layer.cpp b/src/knx/usb_data_link_layer.cpp index 8cf0e36..7dcd879 100644 --- a/src/knx/usb_data_link_layer.cpp +++ b/src/knx/usb_data_link_layer.cpp @@ -239,11 +239,24 @@ void sendKnxTunnelHidReport(uint8_t* data, uint16_t length) // Copy cEMI frame to buffer memcpy(&buffer[11], data, length + HID_HEADER_SIZE + 8); - buffer[2] = 8 + length; // KNX USB Transfer Protocol Header length (8, only first packet!) + cEMI length - pushWord(length, &data[5]); // KNX USB Transfer Protocol Body length (cEMI length) + buffer[2] = 8 + length; // KNX USB Transfer Protocol Header length (8, only first packet!) + cEMI length + pushWord(length, &buffer[5]); // KNX USB Transfer Protocol Body length (cEMI length) +/* + Serial1.print("TX HID report: len: "); + Serial1.println(buffer[2], DEC); + + for (int i = 0; i < (buffer[2] + HID_HEADER_SIZE); i++) + { + if (buffer[i] < 16) + Serial1.print("0"); + Serial1.print(buffer[i], HEX); + Serial1.print(" "); + } + Serial1.println(""); +*/ // We do not use reportId of the sendReport()-API here but instead provide it in the first byte of the buffer - usb_hid.sendReport(0, data, MAX_EP_SIZE); + usb_hid.sendReport(0, buffer, MAX_EP_SIZE); } // Invoked when received SET_REPORT control request or @@ -262,6 +275,7 @@ void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8 { uint8_t packetLength = data[2]; +/* Serial1.print("RX HID report: len: "); Serial1.println(packetLength, DEC); @@ -273,6 +287,7 @@ void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8 Serial1.print(" "); } Serial1.println(""); +*/ if (data[3] == 0x00 && // Protocol version (fixed 0x00) data[4] == 0x08) // USB KNX Transfer Protocol Header Length (fixed 0x08)