File CayenneLPP.hpp
File List > include > CayenneLPP.hpp
Go to the documentation of this file
/* This code is free software:
* you can redistribute it and/or modify it under the terms of a Creative
* Commons Attribution-NonCommercial 4.0 International License
* (http://creativecommons.org/licenses/by-nc/4.0/)
*
* Copyright (c) 2024 March by Klaasjan Wagenaar, Tristan Bosveld and Richard Kroesen
*/
#ifndef CAYENNE_LPP_HPP
#define CAYENNE_LPP_HPP
#include <stdint.h>
#include "CayenneReferences.hpp"
namespace PAYLOAD_ENCODER
{
template <size_t MaxSize>
class CayenneLPP
{
public:
explicit CayenneLPP(const uint8_t size) : operationalSize(size > MaxSize ? MaxSize : size), currentIndex(0)
{
for(size_t i = 0; i < MaxSize; i++) {
buffer[i] = 0;
}
}
CayenneLPP(const CayenneLPP& other) : operationalSize(other.operationalSize), currentIndex(other.currentIndex)
{
for(size_t i = 0; i < currentIndex; ++i)
{
buffer[i] = other.buffer[i];
}
}
CayenneLPP& operator=(const CayenneLPP& other) {
if (this != &other) {
currentIndex = other.currentIndex;
memcpyAVR(buffer, other.getBuffer(), currentIndex);
}
return *this;
}
~CayenneLPP() {}
/* REQUIRED FUNCTIONS by ASSIGNMENT #1 */
void reset()
{
currentIndex = 0; // Reset currentIndex when buffer is reset
}
size_t getSize(void) const
{
return currentIndex; // Returns the count of used bytes
}
const uint8_t *getBuffer(void) const
{
return buffer;
}
const uint8_t copy(uint8_t *destBuffer) const
{
if (!destBuffer)
{
return 0; // Safety check to ensure the destination buffer is valid
}
memcpyAVR(destBuffer, buffer, currentIndex);
return static_cast<uint8_t>(currentIndex);
}
/* END of REQUIRED FUNCTIONS by ASSIGNMENT #1 */
const uint8_t addDigitalInput(const uint8_t sensorChannel, const uint8_t value)
{
return addField(DATA_TYPES::DIG_IN, sensorChannel, value);
}
const uint8_t addDigitalOutput(const uint8_t sensorChannel, const uint8_t value)
{
return addField(DATA_TYPES::DIG_OUT, sensorChannel, value);
}
const uint8_t addAnalogInput(const uint8_t sensorChannel, const float value)
{
return addField(DATA_TYPES::ANL_IN, sensorChannel, value);
}
const uint8_t addAnalogOutput(const uint8_t sensorChannel, const float value)
{
return addField(DATA_TYPES::ANL_OUT, sensorChannel, value);
}
const uint8_t addIllumination(const uint8_t sensorChannel, const uint16_t value)
{
return addField(DATA_TYPES::ILLUM_SENS, sensorChannel, value);
}
const uint8_t addPresence(const uint8_t sensorChannel, const uint8_t value)
{
return addField(DATA_TYPES::PRSNC_SENS, sensorChannel, value);
}
const uint8_t addTemperature(const uint8_t sensorChannel, const float value)
{
return addField(DATA_TYPES::TEMP_SENS, sensorChannel, value);
}
const uint8_t addHumidity(const uint8_t sensorChannel, const float value)
{
return addField(DATA_TYPES::HUM_SENS, sensorChannel, value);
}
const uint8_t addAccelerometer(const uint8_t sensorChannel, const float x, const float y, const float z)
{
return addField(DATA_TYPES::ACCRM_SENS, sensorChannel, x, y, z);
}
const uint8_t addBarometer(const uint8_t sensorChannel, const float value)
{
return addField(DATA_TYPES::BARO_SENS, sensorChannel, value);
}
const uint8_t addGyroscope(const uint8_t sensorChannel, const float x, const float y, const float z)
{
return addField(DATA_TYPES::GYRO_SENS, sensorChannel, x, y, z);
}
const uint8_t addGPSLocation(uint8_t sensorChannel, const float lat, const float lon, const float alt)
{
return addField(DATA_TYPES::GPS_LOC, sensorChannel, lat, lon, alt);
}
private:
uint8_t buffer[MaxSize];
size_t operationalSize;
size_t currentIndex;
const static inline int32_t round_and_cast(const float value)
{
if (value > 0)
{
return static_cast<int32_t>(value + 0.5f);
}
else
{
return static_cast<int32_t>(value - 0.5f);
}
}
const static inline int16_t round_and_cast_int16(const float value)
{
if (value > 0)
{
return static_cast<int16_t>(value + 0.5f);
}
else
{
return static_cast<int16_t>(value - 0.5f);
}
}
const bool checkCapacity(const size_t dataSize)
{
return currentIndex + dataSize <= operationalSize;
}
void appendHeader(const DATA_TYPES dataType, const uint8_t sensorChannel)
{
buffer[currentIndex++] = static_cast<uint8_t>(dataType);
buffer[currentIndex++] = sensorChannel;
}
template <typename T>
void appendData(const T data)
{
memcpyAVR(&buffer[currentIndex], &data, sizeof(T));
currentIndex += sizeof(T);
}
const uint8_t addFieldImpl(const DATA_TYPES dataType, const uint8_t sensorChannel, const uint8_t value)
{
if (!checkCapacity(3)) {
return 0;
}
appendHeader(dataType, sensorChannel);
buffer[currentIndex++] = value;
return currentIndex;
}
const uint8_t addFieldImpl(const DATA_TYPES dataType, const uint8_t sensorChannel, const uint16_t value)
{
if (!checkCapacity(4)) {
return 0;
}
appendHeader(dataType, sensorChannel);
appendData(value);
return currentIndex;
}
const uint8_t addFieldImpl(const DATA_TYPES dataType, const uint8_t sensorChannel, const float value)
{
const uint16_t resolution = FLOATING_DATA_RESOLUTION(dataType);
int16_t scaledValue = round_and_cast_int16(value * resolution);
if (!checkCapacity(4)) {
return 0;
}
appendHeader(dataType, sensorChannel);
appendData(scaledValue);
return currentIndex;
}
const uint8_t addFieldImpl(const DATA_TYPES dataType, const uint8_t sensorChannel,
const float first, const float second, const float third)
{
const size_t totalBytes = getDataTypeSize(dataType) + 2;
if (!checkCapacity(totalBytes))
return 0;
appendHeader(dataType, sensorChannel);
if (dataType == DATA_TYPES::GPS_LOC)
{
// Special handling for GPS data
appendData(round_and_cast(first * FLOATING_DATA_RESOLUTION(dataType)));
appendData(round_and_cast(second * FLOATING_DATA_RESOLUTION(dataType)));
appendData(round_and_cast(third * (FLOATING_DATA_RESOLUTION(dataType) / 100)));
}
else
{
// Generic handling for other types requiring three floats
appendData(round_and_cast_int16(first * FLOATING_DATA_RESOLUTION(dataType)));
appendData(round_and_cast_int16(second * FLOATING_DATA_RESOLUTION(dataType)));
appendData(round_and_cast_int16(third * FLOATING_DATA_RESOLUTION(dataType)));
}
return currentIndex;
}
template <typename... Args>
const uint8_t addField(const DATA_TYPES dataType, const uint8_t sensorChannel, Args... args)
{
return addFieldImpl(dataType, sensorChannel, args...);
}
static inline void memcpyAVR(void *dest, const void *src, const size_t n)
{
uint8_t *cdest = static_cast<uint8_t*>(dest);
const uint8_t *csrc = static_cast<const uint8_t*>(src);
for (size_t i = 0; i < n; i++)
{
cdest[i] = csrc[i];
}
}
}; // End of class CayenneLPP.
} // End of Namespace PAYLOAD_ENCODER.
#endif // CAYENNE_LPP_HPP