.. _program_listing_file_src_knx_tp_frame.h: Program Listing for File tp_frame.h =================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/knx/tp_frame.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #pragma GCC optimize("O3") #include "cemi_frame.h" #include #include #include // Means that the frame is invalid #define TP_FRAME_FLAG_INVALID 0b10000000 // Means that the frame is an extended frame #define TP_FRAME_FLAG_EXTENDED 0b01000000 // Means that the frame has been repeated #define TP_FRAME_FLAG_REPEATED 0b00100000 // Means that the frame comes from the device itself #define TP_FRAME_FLAG_ECHO 0b00010000 // Means that the frame is processed by this device #define TP_FRAME_FLAG_ADDRESSED 0b00001000 // Means that the frame has been acked with BUSY #define TP_FRAME_FLAG_ACK_BUSY 0b00000100 // Means that the frame has been acked with NACK #define TP_FRAME_FLAG_ACK_NACK 0b00000010 // Means that the frame has been acked #define TP_FRAME_FLAG_ACK 0b00000001 class TpFrame { private: uint8_t* _data; uint16_t _size; uint16_t _maxSize; uint8_t _flags = 0; /* * Sets a few flags based on the control byte */ inline void presetFlags() { if (isExtended()) addFlags(TP_FRAME_FLAG_EXTENDED); if (isRepeated()) addFlags(TP_FRAME_FLAG_REPEATED); } public: /* * Convert a CemiFrame into a TpFrame */ TpFrame(CemiFrame& cemiFrame) { _size = cemiFrame.telegramLengthtTP(); _maxSize = cemiFrame.telegramLengthtTP(); _data = (uint8_t*)malloc(cemiFrame.telegramLengthtTP()); cemiFrame.fillTelegramTP(_data); presetFlags(); } /* * Create a TpFrame with a reserved space. * Used for incoming parsing. */ TpFrame(uint16_t maxSize = 263) : _maxSize(maxSize) { _data = (uint8_t*)malloc(_maxSize); _size = 0; } /* * Free the data area */ ~TpFrame() { free(_data); } /* * Add a byte at end. * Used for incoming parsing. */ inline void addByte(uint8_t byte) { if (!isFull()) { _data[_size] = byte; _size++; } // Read meta data for flags if (_size == 1) presetFlags(); } /* * Current frame size. This may differ from the actual size as long as the frame is not complete. */ inline uint16_t size() { return _size; } /* * Returns the assigned flags */ inline uint16_t flags() { return _flags; } /* * Adds one or more flags */ inline void addFlags(uint8_t flags) { _flags |= flags; } /* * Returns a pointer to the data */ inline uint8_t* data() { return _data; } /* * Returns the byte corresponding to the specified position */ inline uint8_t data(uint16_t pos) { return _data[pos]; } /* * Resets the internal values to refill the frame. */ inline void reset() { _size = 0; _flags = 0; // It is important to fill the _data with zeros so that the length is 0 as long as the value has not yet been read in. memset(_data, 0x0, _maxSize); } /* * Checks whether the frame has been imported completely */ inline bool isFull() { return _size >= (_size >= 7 ? fullSize() : _maxSize); } /* * Returns is the frame exteneded or not */ inline bool isExtended() { return (_data[0] & 0xD3) == 0x10; } /* * Returns the source * Assumes that enough data has been imported. */ inline uint16_t source() { return isExtended() ? (_data[2] << 8) + _data[3] : (_data[1] << 8) + _data[2]; } inline std::string humanSource() { uint16_t value = source(); char buffer[10]; sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111)); return buffer; } inline std::string humanDestination() { uint16_t value = destination(); char buffer[10]; if (isGroupAddress()) sprintf(buffer, "%02i/%02i/%03i", (value >> 11 & 0b1111), (value >> 8 & 0b111), (value & 0b11111111)); else sprintf(buffer, "%02i.%02i.%03i", (value >> 12 & 0b1111), (value >> 8 & 0b1111), (value & 0b11111111)); return buffer; } /* * Returns the destination * Assumes that enough data has been imported. */ inline uint16_t destination() { return isExtended() ? (_data[4] << 8) + _data[5] : (_data[3] << 8) + _data[4]; } /* * Returns the payload size (with checksum) * Assumes that enough data has been imported. */ inline uint8_t payloadSize() { return isExtended() ? _data[6] : _data[5] & 0b1111; } /* * Returns the header size */ inline uint8_t headerSize() { return isExtended() ? 9 : 8; } /* * Returns the frame size based on header and payload size. * Assumes that enough data has been imported. */ inline uint16_t fullSize() { return headerSize() + payloadSize(); } /* * Returns if the destination is a group address * Assumes that enough data has been imported. */ inline bool isGroupAddress() { return isExtended() ? (_data[1] >> 7) & 0b1 : (_data[5] >> 7) & 0b1; } /* * Calculates the size of a CemiFrame. A CemiFrame has 2 additional bytes at the beginning. * An additional byte is added to a standard frame, as this still has to be converted into an extendend. */ uint16_t cemiSize() { return fullSize() + (isExtended() ? 2 : 3) - 1; // -1 without CRC } uint8_t* cemiData() { uint8_t* cemiBuffer = (uint8_t*)malloc(cemiSize()); // Das CEMI erwartet die Daten im Extended format inkl. zwei zusätzlicher Bytes am Anfang. cemiBuffer[0] = 0x29; cemiBuffer[1] = 0x0; cemiBuffer[2] = _data[0]; if (isExtended()) { memcpy(cemiBuffer + 2, _data, fullSize() - 1); // -1 without CRC } else { cemiBuffer[3] = _data[5] & 0xF0; memcpy(cemiBuffer + 4, _data + 1, 4); cemiBuffer[8] = _data[5] & 0x0F; memcpy(cemiBuffer + 9, _data + 6, cemiBuffer[8] + 2 - 1); // -1 without CRC } return cemiBuffer; } /* * Checks whether the frame is complete and valid. */ inline bool isValid() { if (!isComplete()) return false; uint8_t sum = 0; const uint16_t s = fullSize() - 1; for (uint16_t i = 0; i < s; i++) sum ^= _data[i]; return _data[s] == (uint8_t)~sum; } /* * Checks whether the frame is long enough to match the length specified in the frame */ inline bool isComplete() { return _size == fullSize(); } inline bool isRepeated() { return !(_data[0] & 0b100000); } };