blob: f6c6e551c64f7cece7918d49e24539738135f84d [file] [log] [blame]
/**
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* Copyright (c) 2020 Silicon Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************************************/
/**
* @file
* @brief Code for manipulating the incoming and
*outgoing messages in a flat memory buffer.
*******************************************************************************
******************************************************************************/
#include "af.h"
#include "config.h"
#include "util.h"
using namespace chip;
//------------------------------------------------------------------------------
// these variables are for storing responses that are created by zcl-utils
// in functions called from emberIncomingMsgHandler. The response is sent
// from emberAfTick (meant to be called immediately after emberTick).
// There is only space for one response as each call to emberTick will
// only result in a single call to emberIncomingMsgHandler. If the device
// receives multiple ZCL messages, the stack will queue these and hand
// these to the application via emberIncomingMsgHandler one at a time.
EmberApsFrame emberAfResponseApsFrame;
NodeId emberAfResponseDestination;
uint8_t appResponseData[EMBER_AF_RESPONSE_BUFFER_LEN];
uint16_t appResponseLength;
// Used for empty string
static uint16_t zeroLenByte = 0;
static uint8_t * zeroLenBytePtr = (uint8_t *) &zeroLenByte;
//------------------------------------------------------------------------------
// Utilities for adding bytes to the response buffer: appResponseData. These
// functions take care of incrementing appResponseLength.
void emberAfClearResponseData(void)
{
emberAfResponseType = ZCL_UTIL_RESP_NORMAL;
// To prevent accidentally sending to someone else,
// set the destination to ourselves.
emberAfResponseDestination = 0 /* emberAfGetNodeId() */;
memset(appResponseData, 0, EMBER_AF_RESPONSE_BUFFER_LEN);
appResponseLength = 0;
memset(&emberAfResponseApsFrame, 0, sizeof(EmberApsFrame));
}
uint8_t * emberAfPutInt8uInResp(uint8_t value)
{
// emberAfDebugPrint("try %x max %x\r\n", appResponseLength, EMBER_AF_RESPONSE_BUFFER_LEN);
if (appResponseLength < EMBER_AF_RESPONSE_BUFFER_LEN)
{
// emberAfDebugPrint("put %x at spot %x\r\n", value, appResponseLength);
appResponseData[appResponseLength] = value;
appResponseLength++;
return &appResponseData[appResponseLength - 1];
}
return NULL;
}
uint16_t * emberAfPutInt16uInResp(uint16_t value)
{
uint8_t * low = emberAfPutInt8uInResp(LOW_BYTE(value));
uint8_t * high = emberAfPutInt8uInResp(HIGH_BYTE(value));
if (low && high)
{
return (uint16_t *) low;
}
else
{
return NULL;
}
}
uint32_t * emberAfPutInt32uInResp(uint32_t value)
{
uint8_t * a = emberAfPutInt8uInResp(BYTE_0(value));
uint8_t * b = emberAfPutInt8uInResp(BYTE_1(value));
uint8_t * c = emberAfPutInt8uInResp(BYTE_2(value));
uint8_t * d = emberAfPutInt8uInResp(BYTE_3(value));
if (a && b && c && d)
{
return (uint32_t *) a;
}
else
{
return NULL;
}
}
uint32_t * emberAfPutInt24uInResp(uint32_t value)
{
uint8_t * a = emberAfPutInt8uInResp(BYTE_0(value));
uint8_t * b = emberAfPutInt8uInResp(BYTE_1(value));
uint8_t * c = emberAfPutInt8uInResp(BYTE_2(value));
if (a && b && c)
{
return (uint32_t *) a;
}
else
{
return NULL;
}
}
uint8_t * emberAfPutBlockInResp(const uint8_t * data, uint16_t length)
{
if ((appResponseLength + length) < EMBER_AF_RESPONSE_BUFFER_LEN)
{
memmove(appResponseData + appResponseLength, data, length);
appResponseLength = static_cast<uint16_t>(appResponseLength + length);
return &appResponseData[appResponseLength - length];
}
else
{
return NULL;
}
}
uint8_t * emberAfPutStringInResp(const uint8_t * buffer)
{
uint8_t length = emberAfStringLength(buffer);
return emberAfPutBlockInResp(buffer, static_cast<uint16_t>(length + 1));
}
uint8_t * emberAfPutDateInResp(EmberAfDate * value)
{
uint8_t * a = emberAfPutInt8uInResp(value->year);
uint8_t * b = emberAfPutInt8uInResp(value->month);
uint8_t * c = emberAfPutInt8uInResp(value->dayOfMonth);
uint8_t * d = emberAfPutInt8uInResp(value->dayOfWeek);
if (a && b && c && d)
{
return a;
}
else
{
return NULL;
}
}
// ------------------------------------
// Utilities for reading from RAM buffers (reading from incoming message
// buffer)
// ------------------------------------
// retrieves an uint32_t which contains between 1 and 4 bytes of relevent data
// depending on number of bytes requested.
uint32_t emberAfGetInt(const uint8_t * message, uint16_t currentIndex, uint16_t msgLen, uint8_t bytes)
{
uint32_t result = 0;
uint8_t i = bytes;
if ((currentIndex + bytes) > msgLen)
{
emberAfDebugPrintln("GetInt, %x bytes short", bytes);
emberAfDebugFlush();
return 0;
}
while (i > 0)
{
result = (result << 8) + message[(currentIndex + i) - 1];
i--;
}
return result;
}
uint32_t emberAfGetInt32u(const uint8_t * message, uint16_t currentIndex, uint16_t msgLen)
{
return emberAfGetInt(message, currentIndex, msgLen, 4);
}
uint32_t emberAfGetInt24u(const uint8_t * message, uint16_t currentIndex, uint16_t msgLen)
{
return emberAfGetInt(message, currentIndex, msgLen, 3);
}
uint16_t emberAfGetInt16u(const uint8_t * message, uint16_t currentIndex, uint16_t msgLen)
{
return (uint16_t) emberAfGetInt(message, currentIndex, msgLen, 2);
}
uint8_t * emberAfGetString(uint8_t * message, uint16_t currentIndex, uint16_t msgLen)
{
// Strings must contain at least one byte for the length.
if (msgLen <= currentIndex)
{
emberAfDebugPrintln("GetString: %p", "buffer too short");
return zeroLenBytePtr;
}
// Starting from the current index, there must be enough bytes in the message
// for the string and the length byte.
if (msgLen < currentIndex + emberAfStringLength(&message[currentIndex]) + 1)
{
emberAfDebugPrintln("GetString: %p", "len byte wrong");
return zeroLenBytePtr;
}
return &message[currentIndex];
}
uint8_t * emberAfGetLongString(uint8_t * message, uint16_t currentIndex, uint16_t msgLen)
{
// Long strings must contain at least two bytes for the length.
if (msgLen <= currentIndex + 1)
{
emberAfDebugPrintln("GetLongString: %p", "buffer too short");
return zeroLenBytePtr;
}
// Starting from the current index, there must be enough bytes in the message
// for the string and the length bytes.
if (msgLen < currentIndex + emberAfLongStringLength(&message[currentIndex]) + 2)
{
emberAfDebugPrintln("GetLongString: %p", "len bytes wrong");
return zeroLenBytePtr;
}
return &message[currentIndex];
}
uint8_t emberAfStringLength(const uint8_t * buffer)
{
// The first byte specifies the length of the string. A length of 0xFF means
// the string is invalid and there is no character data.
return (buffer[0] == 0xFF ? 0 : buffer[0]);
}
uint16_t emberAfLongStringLength(const uint8_t * buffer)
{
// The first two bytes specify the length of the long string. A length of
// 0xFFFF means the string is invalid and there is no character data.
uint16_t length = emberAfGetInt16u(buffer, 0, 2);
return (length == 0xFFFF ? 0 : length);
}
uint8_t emberAfGetDate(uint8_t * message, uint16_t currentIndex, uint16_t msgLen, EmberAfDate * destination)
{
if ((currentIndex + 4) > msgLen)
{
emberAfDebugPrintln("GetDate, %x bytes short", 4);
emberAfDebugFlush();
return 0;
}
destination->year = message[(currentIndex + 0)];
destination->month = message[(currentIndex + 1)];
destination->dayOfMonth = message[(currentIndex + 2)];
destination->dayOfWeek = message[(currentIndex + 3)];
return 4;
}