renormalized line endings
This commit is contained in:
@ -1,230 +1,230 @@
|
||||
#include "../globalfunctions/AsciiConverter.h"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
template<typename T>
|
||||
ReturnValue_t AsciiConverter::scanAsciiDecimalNumber(const uint8_t** dataPtr,
|
||||
uint8_t len, T* value) {
|
||||
if (len > std::numeric_limits<T>().digits10) {
|
||||
return TOO_LONG_FOR_TARGET_TYPE;
|
||||
}
|
||||
|
||||
double temp;
|
||||
|
||||
ReturnValue_t result = scanAsciiDecimalNumber_(dataPtr, len, &temp);
|
||||
|
||||
*value = temp;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::scanAsciiHexByte(const uint8_t** dataPtr,
|
||||
uint8_t* value) {
|
||||
int8_t tmp;
|
||||
|
||||
tmp = convertHexChar(*dataPtr);
|
||||
(*dataPtr)++;
|
||||
if (tmp == -1) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
if (tmp == -2) {
|
||||
tmp = 0;
|
||||
}
|
||||
|
||||
*value = tmp << 4;
|
||||
|
||||
tmp = convertHexChar(*dataPtr);
|
||||
(*dataPtr)++;
|
||||
if (tmp == -1) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
if (tmp != -2) {
|
||||
*value += tmp;
|
||||
} else {
|
||||
*value = *value >> 4;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::scanAsciiDecimalNumber_(uint8_t const ** dataPtr,
|
||||
uint8_t len, double* value) {
|
||||
|
||||
uint8_t const *ptr = *dataPtr;
|
||||
int8_t sign = 1;
|
||||
float decimal = 0;
|
||||
bool abort = false;
|
||||
|
||||
*value = 0;
|
||||
|
||||
//ignore leading space
|
||||
ptr = clearSpace(ptr, len);
|
||||
|
||||
while ((ptr - *dataPtr < len) && !abort) {
|
||||
switch (*ptr) {
|
||||
case '+':
|
||||
sign = 1;
|
||||
break;
|
||||
case '-':
|
||||
sign = -1;
|
||||
break;
|
||||
case '.':
|
||||
decimal = 1;
|
||||
break;
|
||||
case ' ':
|
||||
case 0x0d:
|
||||
case 0x0a:
|
||||
//ignore trailing space
|
||||
ptr = clearSpace(ptr, len - (ptr - *dataPtr)) - 1; //before aborting the loop, ptr will be incremented
|
||||
abort = true;
|
||||
break;
|
||||
default:
|
||||
if ((*ptr < 0x30) || (*ptr > 0x39)) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
*value = *value * 10 + (*ptr - 0x30);
|
||||
if (decimal > 0) {
|
||||
decimal *= 10;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (decimal == 0) {
|
||||
decimal = 1;
|
||||
}
|
||||
|
||||
*value = *value / (decimal) * sign;
|
||||
|
||||
*dataPtr = ptr;
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printFloat(uint8_t* buffer, uint32_t bufferLength,
|
||||
float value, uint8_t decimalPlaces, uint32_t *printedSize) {
|
||||
*printedSize = 0;
|
||||
uint32_t streamposition = 0, integerSize;
|
||||
bool negative = (value < 0);
|
||||
int32_t digits = bufferLength - decimalPlaces - 1;
|
||||
if (digits <= 0) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
if (negative) {
|
||||
digits -= 1;
|
||||
buffer[streamposition++] = '-';
|
||||
value = -value;
|
||||
}
|
||||
float maximumNumber = pow(10, digits);
|
||||
if (value >= maximumNumber) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
//print the numbers before the decimal point;
|
||||
ReturnValue_t result = printInteger(buffer + streamposition,
|
||||
bufferLength - streamposition - decimalPlaces - 1, value,
|
||||
&integerSize);
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
streamposition += integerSize;
|
||||
//The decimal Point
|
||||
buffer[streamposition++] = '.';
|
||||
|
||||
//Print the decimals
|
||||
uint32_t integerValue = value;
|
||||
value -= integerValue;
|
||||
value = value * pow(10, decimalPlaces);
|
||||
result = printInteger(buffer + streamposition, decimalPlaces, round(value),
|
||||
&integerSize, true);
|
||||
*printedSize = integerSize + streamposition;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printInteger(uint8_t* buffer,
|
||||
uint32_t bufferLength, uint32_t value, uint32_t *printedSize,
|
||||
bool leadingZeros) {
|
||||
*printedSize = 0;
|
||||
if (bufferLength == 0) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
uint32_t maximumNumber = -1;
|
||||
if (bufferLength < 10) {
|
||||
maximumNumber = pow(10, bufferLength);
|
||||
if (value >= maximumNumber) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
maximumNumber /= 10;
|
||||
} else {
|
||||
if (!(value <= maximumNumber)) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
maximumNumber = 1000000000;
|
||||
}
|
||||
if (!leadingZeros && (value == 0)) {
|
||||
buffer[(*printedSize)++] = '0';
|
||||
return RETURN_OK;
|
||||
}
|
||||
while (maximumNumber >= 1) {
|
||||
uint8_t number = value / maximumNumber;
|
||||
value = value - (number * maximumNumber);
|
||||
if (!leadingZeros && number == 0) {
|
||||
maximumNumber /= 10;
|
||||
} else {
|
||||
leadingZeros = true;
|
||||
buffer[(*printedSize)++] = '0' + number;
|
||||
maximumNumber /= 10;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printSignedInteger(uint8_t* buffer,
|
||||
uint32_t bufferLength, int32_t value, uint32_t *printedSize) {
|
||||
bool negative = false;
|
||||
if ((bufferLength > 0) && (value < 0)) {
|
||||
*buffer++ = '-';
|
||||
bufferLength--;
|
||||
value = -value;
|
||||
negative = true;
|
||||
}
|
||||
ReturnValue_t result = printInteger(buffer, bufferLength, value,
|
||||
printedSize);
|
||||
if (negative) {
|
||||
(*printedSize)++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int8_t AsciiConverter::convertHexChar(const uint8_t* character) {
|
||||
if ((*character > 0x60) && (*character < 0x67)) {
|
||||
return *character - 0x61 + 10;
|
||||
} else if ((*character > 0x40) && (*character < 0x47)) {
|
||||
return *character - 0x41 + 10;
|
||||
} else if ((*character > 0x2F) && (*character < 0x3A)) {
|
||||
return *character - 0x30;
|
||||
} else if (*character == ' ') {
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<float>(
|
||||
const uint8_t** dataPtr, uint8_t len, float* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<uint8_t>(
|
||||
const uint8_t** dataPtr, uint8_t len, uint8_t* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<uint16_t>(
|
||||
const uint8_t** dataPtr, uint8_t len, uint16_t* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<double>(
|
||||
const uint8_t** dataPtr, uint8_t len, double* value);
|
||||
|
||||
const uint8_t* AsciiConverter::clearSpace(const uint8_t* data, uint8_t len) {
|
||||
while (len > 0) {
|
||||
if ((*data != ' ') && (*data != 0x0a) && (*data != 0x0d)) {
|
||||
return data;
|
||||
}
|
||||
data++;
|
||||
len--;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#include "../globalfunctions/AsciiConverter.h"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
template<typename T>
|
||||
ReturnValue_t AsciiConverter::scanAsciiDecimalNumber(const uint8_t** dataPtr,
|
||||
uint8_t len, T* value) {
|
||||
if (len > std::numeric_limits<T>().digits10) {
|
||||
return TOO_LONG_FOR_TARGET_TYPE;
|
||||
}
|
||||
|
||||
double temp;
|
||||
|
||||
ReturnValue_t result = scanAsciiDecimalNumber_(dataPtr, len, &temp);
|
||||
|
||||
*value = temp;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::scanAsciiHexByte(const uint8_t** dataPtr,
|
||||
uint8_t* value) {
|
||||
int8_t tmp;
|
||||
|
||||
tmp = convertHexChar(*dataPtr);
|
||||
(*dataPtr)++;
|
||||
if (tmp == -1) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
if (tmp == -2) {
|
||||
tmp = 0;
|
||||
}
|
||||
|
||||
*value = tmp << 4;
|
||||
|
||||
tmp = convertHexChar(*dataPtr);
|
||||
(*dataPtr)++;
|
||||
if (tmp == -1) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
if (tmp != -2) {
|
||||
*value += tmp;
|
||||
} else {
|
||||
*value = *value >> 4;
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::scanAsciiDecimalNumber_(uint8_t const ** dataPtr,
|
||||
uint8_t len, double* value) {
|
||||
|
||||
uint8_t const *ptr = *dataPtr;
|
||||
int8_t sign = 1;
|
||||
float decimal = 0;
|
||||
bool abort = false;
|
||||
|
||||
*value = 0;
|
||||
|
||||
//ignore leading space
|
||||
ptr = clearSpace(ptr, len);
|
||||
|
||||
while ((ptr - *dataPtr < len) && !abort) {
|
||||
switch (*ptr) {
|
||||
case '+':
|
||||
sign = 1;
|
||||
break;
|
||||
case '-':
|
||||
sign = -1;
|
||||
break;
|
||||
case '.':
|
||||
decimal = 1;
|
||||
break;
|
||||
case ' ':
|
||||
case 0x0d:
|
||||
case 0x0a:
|
||||
//ignore trailing space
|
||||
ptr = clearSpace(ptr, len - (ptr - *dataPtr)) - 1; //before aborting the loop, ptr will be incremented
|
||||
abort = true;
|
||||
break;
|
||||
default:
|
||||
if ((*ptr < 0x30) || (*ptr > 0x39)) {
|
||||
return INVALID_CHARACTERS;
|
||||
}
|
||||
*value = *value * 10 + (*ptr - 0x30);
|
||||
if (decimal > 0) {
|
||||
decimal *= 10;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (decimal == 0) {
|
||||
decimal = 1;
|
||||
}
|
||||
|
||||
*value = *value / (decimal) * sign;
|
||||
|
||||
*dataPtr = ptr;
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printFloat(uint8_t* buffer, uint32_t bufferLength,
|
||||
float value, uint8_t decimalPlaces, uint32_t *printedSize) {
|
||||
*printedSize = 0;
|
||||
uint32_t streamposition = 0, integerSize;
|
||||
bool negative = (value < 0);
|
||||
int32_t digits = bufferLength - decimalPlaces - 1;
|
||||
if (digits <= 0) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
if (negative) {
|
||||
digits -= 1;
|
||||
buffer[streamposition++] = '-';
|
||||
value = -value;
|
||||
}
|
||||
float maximumNumber = pow(10, digits);
|
||||
if (value >= maximumNumber) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
//print the numbers before the decimal point;
|
||||
ReturnValue_t result = printInteger(buffer + streamposition,
|
||||
bufferLength - streamposition - decimalPlaces - 1, value,
|
||||
&integerSize);
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
streamposition += integerSize;
|
||||
//The decimal Point
|
||||
buffer[streamposition++] = '.';
|
||||
|
||||
//Print the decimals
|
||||
uint32_t integerValue = value;
|
||||
value -= integerValue;
|
||||
value = value * pow(10, decimalPlaces);
|
||||
result = printInteger(buffer + streamposition, decimalPlaces, round(value),
|
||||
&integerSize, true);
|
||||
*printedSize = integerSize + streamposition;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printInteger(uint8_t* buffer,
|
||||
uint32_t bufferLength, uint32_t value, uint32_t *printedSize,
|
||||
bool leadingZeros) {
|
||||
*printedSize = 0;
|
||||
if (bufferLength == 0) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
uint32_t maximumNumber = -1;
|
||||
if (bufferLength < 10) {
|
||||
maximumNumber = pow(10, bufferLength);
|
||||
if (value >= maximumNumber) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
maximumNumber /= 10;
|
||||
} else {
|
||||
if (!(value <= maximumNumber)) {
|
||||
return BUFFER_TOO_SMALL;
|
||||
}
|
||||
maximumNumber = 1000000000;
|
||||
}
|
||||
if (!leadingZeros && (value == 0)) {
|
||||
buffer[(*printedSize)++] = '0';
|
||||
return RETURN_OK;
|
||||
}
|
||||
while (maximumNumber >= 1) {
|
||||
uint8_t number = value / maximumNumber;
|
||||
value = value - (number * maximumNumber);
|
||||
if (!leadingZeros && number == 0) {
|
||||
maximumNumber /= 10;
|
||||
} else {
|
||||
leadingZeros = true;
|
||||
buffer[(*printedSize)++] = '0' + number;
|
||||
maximumNumber /= 10;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AsciiConverter::printSignedInteger(uint8_t* buffer,
|
||||
uint32_t bufferLength, int32_t value, uint32_t *printedSize) {
|
||||
bool negative = false;
|
||||
if ((bufferLength > 0) && (value < 0)) {
|
||||
*buffer++ = '-';
|
||||
bufferLength--;
|
||||
value = -value;
|
||||
negative = true;
|
||||
}
|
||||
ReturnValue_t result = printInteger(buffer, bufferLength, value,
|
||||
printedSize);
|
||||
if (negative) {
|
||||
(*printedSize)++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int8_t AsciiConverter::convertHexChar(const uint8_t* character) {
|
||||
if ((*character > 0x60) && (*character < 0x67)) {
|
||||
return *character - 0x61 + 10;
|
||||
} else if ((*character > 0x40) && (*character < 0x47)) {
|
||||
return *character - 0x41 + 10;
|
||||
} else if ((*character > 0x2F) && (*character < 0x3A)) {
|
||||
return *character - 0x30;
|
||||
} else if (*character == ' ') {
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<float>(
|
||||
const uint8_t** dataPtr, uint8_t len, float* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<uint8_t>(
|
||||
const uint8_t** dataPtr, uint8_t len, uint8_t* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<uint16_t>(
|
||||
const uint8_t** dataPtr, uint8_t len, uint16_t* value);
|
||||
template ReturnValue_t AsciiConverter::scanAsciiDecimalNumber<double>(
|
||||
const uint8_t** dataPtr, uint8_t len, double* value);
|
||||
|
||||
const uint8_t* AsciiConverter::clearSpace(const uint8_t* data, uint8_t len) {
|
||||
while (len > 0) {
|
||||
if ((*data != ' ') && (*data != 0x0a) && (*data != 0x0d)) {
|
||||
return data;
|
||||
}
|
||||
data++;
|
||||
len--;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
@ -1,39 +1,39 @@
|
||||
#ifndef ASCIICONVERTER_H_
|
||||
#define ASCIICONVERTER_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
class AsciiConverter: public HasReturnvaluesIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::ASCII_CONVERTER;
|
||||
static const ReturnValue_t TOO_LONG_FOR_TARGET_TYPE = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t INVALID_CHARACTERS = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t BUFFER_TOO_SMALL = MAKE_RETURN_CODE(0x3);
|
||||
|
||||
template<typename T>
|
||||
static ReturnValue_t scanAsciiDecimalNumber(const uint8_t **dataPtr,
|
||||
uint8_t len, T *value);
|
||||
|
||||
static ReturnValue_t scanAsciiHexByte(const uint8_t **dataPtr,
|
||||
uint8_t *value);
|
||||
|
||||
static ReturnValue_t printFloat(uint8_t *buffer, uint32_t bufferLength,
|
||||
float value, uint8_t decimalPlaces, uint32_t *printedSize);
|
||||
|
||||
static ReturnValue_t printInteger(uint8_t *buffer, uint32_t bufferLength,
|
||||
uint32_t value, uint32_t *printedSize, bool leadingZeros = false);
|
||||
|
||||
static ReturnValue_t printSignedInteger(uint8_t *buffer,
|
||||
uint32_t bufferLength, int32_t value, uint32_t *printedSize);
|
||||
|
||||
private:
|
||||
AsciiConverter();
|
||||
static ReturnValue_t scanAsciiDecimalNumber_(const uint8_t **dataPtr,
|
||||
uint8_t len, double *value);
|
||||
|
||||
static int8_t convertHexChar(const uint8_t *character);
|
||||
|
||||
static const uint8_t *clearSpace(const uint8_t *data, uint8_t len);
|
||||
};
|
||||
|
||||
#endif /* ASCIICONVERTER_H_ */
|
||||
#ifndef ASCIICONVERTER_H_
|
||||
#define ASCIICONVERTER_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
class AsciiConverter: public HasReturnvaluesIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::ASCII_CONVERTER;
|
||||
static const ReturnValue_t TOO_LONG_FOR_TARGET_TYPE = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t INVALID_CHARACTERS = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t BUFFER_TOO_SMALL = MAKE_RETURN_CODE(0x3);
|
||||
|
||||
template<typename T>
|
||||
static ReturnValue_t scanAsciiDecimalNumber(const uint8_t **dataPtr,
|
||||
uint8_t len, T *value);
|
||||
|
||||
static ReturnValue_t scanAsciiHexByte(const uint8_t **dataPtr,
|
||||
uint8_t *value);
|
||||
|
||||
static ReturnValue_t printFloat(uint8_t *buffer, uint32_t bufferLength,
|
||||
float value, uint8_t decimalPlaces, uint32_t *printedSize);
|
||||
|
||||
static ReturnValue_t printInteger(uint8_t *buffer, uint32_t bufferLength,
|
||||
uint32_t value, uint32_t *printedSize, bool leadingZeros = false);
|
||||
|
||||
static ReturnValue_t printSignedInteger(uint8_t *buffer,
|
||||
uint32_t bufferLength, int32_t value, uint32_t *printedSize);
|
||||
|
||||
private:
|
||||
AsciiConverter();
|
||||
static ReturnValue_t scanAsciiDecimalNumber_(const uint8_t **dataPtr,
|
||||
uint8_t len, double *value);
|
||||
|
||||
static int8_t convertHexChar(const uint8_t *character);
|
||||
|
||||
static const uint8_t *clearSpace(const uint8_t *data, uint8_t len);
|
||||
};
|
||||
|
||||
#endif /* ASCIICONVERTER_H_ */
|
||||
|
@ -1,139 +1,139 @@
|
||||
#include "../globalfunctions/CRC.h"
|
||||
#include <math.h>
|
||||
|
||||
const uint16_t CRC::crc16ccitt_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
|
||||
// CRC implementation
|
||||
uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)input;
|
||||
unsigned int tbl_idx;
|
||||
|
||||
while (length--) {
|
||||
tbl_idx = ((startingCrc >> 8) ^ *data) & 0xff;
|
||||
startingCrc = (crc16ccitt_table[tbl_idx] ^ (startingCrc << 8)) & 0xffff;
|
||||
|
||||
data++;
|
||||
}
|
||||
return startingCrc & 0xffff;
|
||||
|
||||
//The part below is not used!
|
||||
// bool temr[16];
|
||||
// bool xor_out[16];
|
||||
// bool r[16];
|
||||
// bool d[8];
|
||||
// uint16_t crc_value = 0;
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++) {
|
||||
// temr[i] = false;
|
||||
// xor_out[i] = false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// r[i] = true; // initialize with 0xFFFF
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int j=0; j<length ;j++)
|
||||
// {
|
||||
//
|
||||
// for (int i=0; i<8 ;i++)
|
||||
// if ((input[j] & 1<<i) == 1<<i)
|
||||
// d[7-i]=true; // reverse input data
|
||||
// else
|
||||
// d[7-i]=false; // reverse input data
|
||||
//
|
||||
//
|
||||
//
|
||||
// temr[0] = d[4] ^ d[0];
|
||||
// temr[1] = d[5] ^ d[1];
|
||||
// temr[2] = d[6] ^ d[2];
|
||||
// temr[3] = d[7] ^ d[3];
|
||||
// temr[4] = r[12] ^ r[8];
|
||||
// temr[5] = r[13] ^ r[9];
|
||||
// temr[6] = r[14] ^ r[10];
|
||||
// temr[7] = r[15] ^ r[11];
|
||||
// temr[8] = d[4] ^ r[12];
|
||||
// temr[9] = d[5] ^ r[13];
|
||||
// temr[10] = d[6] ^ r[14];
|
||||
// temr[11] = d[7] ^ r[15];
|
||||
// temr[12] = temr[0] ^ temr[4];
|
||||
// temr[13] = temr[1] ^ temr[5];
|
||||
// temr[14] = temr[2] ^ temr[6];
|
||||
// temr[15] = temr[3] ^ temr[7];
|
||||
//
|
||||
//
|
||||
// xor_out[0] = temr[12];
|
||||
// xor_out[1] = temr[13];
|
||||
// xor_out[2] = temr[14];
|
||||
// xor_out[3] = temr[15];
|
||||
// xor_out[4] = temr[8];
|
||||
// xor_out[5] = temr[9] ^ temr[12];
|
||||
// xor_out[6] = temr[10] ^ temr[13];
|
||||
// xor_out[7] = temr[11] ^ temr[14];
|
||||
// xor_out[8] = temr[15] ^ r[0];
|
||||
// xor_out[9] = temr[8] ^ r[1];
|
||||
// xor_out[10] = temr[9] ^ r[2];
|
||||
// xor_out[11] = temr[10] ^ r[3];
|
||||
// xor_out[12] = temr[11] ^ temr[12] ^ r[4];
|
||||
// xor_out[13] = temr[13] ^ r[5];
|
||||
// xor_out[14] = temr[14] ^ r[6];
|
||||
// xor_out[15] = temr[15] ^ r[7];
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// r[i]= xor_out[i] ;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// if (xor_out[i] == true)
|
||||
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before Final XOR
|
||||
// }
|
||||
//
|
||||
// crc_value = 0;// for debug mode
|
||||
// return (crc_value);
|
||||
|
||||
} /* Calculate_CRC() */
|
||||
|
||||
|
||||
#include "../globalfunctions/CRC.h"
|
||||
#include <math.h>
|
||||
|
||||
const uint16_t CRC::crc16ccitt_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
|
||||
// CRC implementation
|
||||
uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)input;
|
||||
unsigned int tbl_idx;
|
||||
|
||||
while (length--) {
|
||||
tbl_idx = ((startingCrc >> 8) ^ *data) & 0xff;
|
||||
startingCrc = (crc16ccitt_table[tbl_idx] ^ (startingCrc << 8)) & 0xffff;
|
||||
|
||||
data++;
|
||||
}
|
||||
return startingCrc & 0xffff;
|
||||
|
||||
//The part below is not used!
|
||||
// bool temr[16];
|
||||
// bool xor_out[16];
|
||||
// bool r[16];
|
||||
// bool d[8];
|
||||
// uint16_t crc_value = 0;
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++) {
|
||||
// temr[i] = false;
|
||||
// xor_out[i] = false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// r[i] = true; // initialize with 0xFFFF
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int j=0; j<length ;j++)
|
||||
// {
|
||||
//
|
||||
// for (int i=0; i<8 ;i++)
|
||||
// if ((input[j] & 1<<i) == 1<<i)
|
||||
// d[7-i]=true; // reverse input data
|
||||
// else
|
||||
// d[7-i]=false; // reverse input data
|
||||
//
|
||||
//
|
||||
//
|
||||
// temr[0] = d[4] ^ d[0];
|
||||
// temr[1] = d[5] ^ d[1];
|
||||
// temr[2] = d[6] ^ d[2];
|
||||
// temr[3] = d[7] ^ d[3];
|
||||
// temr[4] = r[12] ^ r[8];
|
||||
// temr[5] = r[13] ^ r[9];
|
||||
// temr[6] = r[14] ^ r[10];
|
||||
// temr[7] = r[15] ^ r[11];
|
||||
// temr[8] = d[4] ^ r[12];
|
||||
// temr[9] = d[5] ^ r[13];
|
||||
// temr[10] = d[6] ^ r[14];
|
||||
// temr[11] = d[7] ^ r[15];
|
||||
// temr[12] = temr[0] ^ temr[4];
|
||||
// temr[13] = temr[1] ^ temr[5];
|
||||
// temr[14] = temr[2] ^ temr[6];
|
||||
// temr[15] = temr[3] ^ temr[7];
|
||||
//
|
||||
//
|
||||
// xor_out[0] = temr[12];
|
||||
// xor_out[1] = temr[13];
|
||||
// xor_out[2] = temr[14];
|
||||
// xor_out[3] = temr[15];
|
||||
// xor_out[4] = temr[8];
|
||||
// xor_out[5] = temr[9] ^ temr[12];
|
||||
// xor_out[6] = temr[10] ^ temr[13];
|
||||
// xor_out[7] = temr[11] ^ temr[14];
|
||||
// xor_out[8] = temr[15] ^ r[0];
|
||||
// xor_out[9] = temr[8] ^ r[1];
|
||||
// xor_out[10] = temr[9] ^ r[2];
|
||||
// xor_out[11] = temr[10] ^ r[3];
|
||||
// xor_out[12] = temr[11] ^ temr[12] ^ r[4];
|
||||
// xor_out[13] = temr[13] ^ r[5];
|
||||
// xor_out[14] = temr[14] ^ r[6];
|
||||
// xor_out[15] = temr[15] ^ r[7];
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// r[i]= xor_out[i] ;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// if (xor_out[i] == true)
|
||||
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before Final XOR
|
||||
// }
|
||||
//
|
||||
// crc_value = 0;// for debug mode
|
||||
// return (crc_value);
|
||||
|
||||
} /* Calculate_CRC() */
|
||||
|
||||
|
||||
|
@ -1,124 +1,124 @@
|
||||
#include "../globalfunctions/DleEncoder.h"
|
||||
|
||||
DleEncoder::DleEncoder() {}
|
||||
|
||||
DleEncoder::~DleEncoder() {}
|
||||
|
||||
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
|
||||
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
|
||||
size_t* encodedLen, bool addStxEtx) {
|
||||
if (maxDestLen < 2) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
size_t encodedIndex = 0, sourceIndex = 0;
|
||||
uint8_t nextByte;
|
||||
if (addStxEtx) {
|
||||
destStream[0] = STX_CHAR;
|
||||
++encodedIndex;
|
||||
}
|
||||
|
||||
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
|
||||
{
|
||||
nextByte = sourceStream[sourceIndex];
|
||||
// STX, ETX and CR characters in the stream need to be escaped with DLE
|
||||
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
|
||||
if (encodedIndex + 1 >= maxDestLen) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
++encodedIndex;
|
||||
/* Escaped byte will be actual byte + 0x40. This prevents
|
||||
* STX, ETX, and carriage return characters from appearing
|
||||
* in the encoded data stream at all, so when polling an
|
||||
* encoded stream, the transmission can be stopped at ETX.
|
||||
* 0x40 was chosen at random with special requirements:
|
||||
* - Prevent going from one control char to another
|
||||
* - Prevent overflow for common characters */
|
||||
destStream[encodedIndex] = nextByte + 0x40;
|
||||
}
|
||||
}
|
||||
// DLE characters are simply escaped with DLE.
|
||||
else if (nextByte == DLE_CHAR) {
|
||||
if (encodedIndex + 1 >= maxDestLen) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
++encodedIndex;
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = nextByte;
|
||||
}
|
||||
++encodedIndex;
|
||||
++sourceIndex;
|
||||
}
|
||||
|
||||
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
|
||||
if (addStxEtx) {
|
||||
destStream[encodedIndex] = ETX_CHAR;
|
||||
++encodedIndex;
|
||||
}
|
||||
*encodedLen = encodedIndex;
|
||||
return RETURN_OK;
|
||||
}
|
||||
else {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
|
||||
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
|
||||
size_t maxDestStreamlen, size_t *decodedLen) {
|
||||
size_t encodedIndex = 0, decodedIndex = 0;
|
||||
uint8_t nextByte;
|
||||
if (*sourceStream != STX_CHAR) {
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
++encodedIndex;
|
||||
|
||||
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
|
||||
&& (sourceStream[encodedIndex] != ETX_CHAR)
|
||||
&& (sourceStream[encodedIndex] != STX_CHAR)) {
|
||||
if (sourceStream[encodedIndex] == DLE_CHAR) {
|
||||
nextByte = sourceStream[encodedIndex + 1];
|
||||
// The next byte is a DLE character that was escaped by another
|
||||
// DLE character, so we can write it to the destination stream.
|
||||
if (nextByte == DLE_CHAR) {
|
||||
destStream[decodedIndex] = nextByte;
|
||||
}
|
||||
else {
|
||||
/* The next byte is a STX, DTX or 0x0D character which
|
||||
* was escaped by a DLE character. The actual byte was
|
||||
* also encoded by adding + 0x40 to preven having control chars,
|
||||
* in the stream at all, so we convert it back. */
|
||||
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
|
||||
destStream[decodedIndex] = nextByte - 0x40;
|
||||
}
|
||||
else {
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
}
|
||||
++encodedIndex;
|
||||
}
|
||||
else {
|
||||
destStream[decodedIndex] = sourceStream[encodedIndex];
|
||||
}
|
||||
|
||||
++encodedIndex;
|
||||
++decodedIndex;
|
||||
}
|
||||
|
||||
if (sourceStream[encodedIndex] != ETX_CHAR) {
|
||||
*readLen = ++encodedIndex;
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
else {
|
||||
*readLen = ++encodedIndex;
|
||||
*decodedLen = decodedIndex;
|
||||
return RETURN_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#include "../globalfunctions/DleEncoder.h"
|
||||
|
||||
DleEncoder::DleEncoder() {}
|
||||
|
||||
DleEncoder::~DleEncoder() {}
|
||||
|
||||
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
|
||||
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
|
||||
size_t* encodedLen, bool addStxEtx) {
|
||||
if (maxDestLen < 2) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
size_t encodedIndex = 0, sourceIndex = 0;
|
||||
uint8_t nextByte;
|
||||
if (addStxEtx) {
|
||||
destStream[0] = STX_CHAR;
|
||||
++encodedIndex;
|
||||
}
|
||||
|
||||
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
|
||||
{
|
||||
nextByte = sourceStream[sourceIndex];
|
||||
// STX, ETX and CR characters in the stream need to be escaped with DLE
|
||||
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
|
||||
if (encodedIndex + 1 >= maxDestLen) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
++encodedIndex;
|
||||
/* Escaped byte will be actual byte + 0x40. This prevents
|
||||
* STX, ETX, and carriage return characters from appearing
|
||||
* in the encoded data stream at all, so when polling an
|
||||
* encoded stream, the transmission can be stopped at ETX.
|
||||
* 0x40 was chosen at random with special requirements:
|
||||
* - Prevent going from one control char to another
|
||||
* - Prevent overflow for common characters */
|
||||
destStream[encodedIndex] = nextByte + 0x40;
|
||||
}
|
||||
}
|
||||
// DLE characters are simply escaped with DLE.
|
||||
else if (nextByte == DLE_CHAR) {
|
||||
if (encodedIndex + 1 >= maxDestLen) {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
++encodedIndex;
|
||||
destStream[encodedIndex] = DLE_CHAR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
destStream[encodedIndex] = nextByte;
|
||||
}
|
||||
++encodedIndex;
|
||||
++sourceIndex;
|
||||
}
|
||||
|
||||
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
|
||||
if (addStxEtx) {
|
||||
destStream[encodedIndex] = ETX_CHAR;
|
||||
++encodedIndex;
|
||||
}
|
||||
*encodedLen = encodedIndex;
|
||||
return RETURN_OK;
|
||||
}
|
||||
else {
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
|
||||
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
|
||||
size_t maxDestStreamlen, size_t *decodedLen) {
|
||||
size_t encodedIndex = 0, decodedIndex = 0;
|
||||
uint8_t nextByte;
|
||||
if (*sourceStream != STX_CHAR) {
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
++encodedIndex;
|
||||
|
||||
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
|
||||
&& (sourceStream[encodedIndex] != ETX_CHAR)
|
||||
&& (sourceStream[encodedIndex] != STX_CHAR)) {
|
||||
if (sourceStream[encodedIndex] == DLE_CHAR) {
|
||||
nextByte = sourceStream[encodedIndex + 1];
|
||||
// The next byte is a DLE character that was escaped by another
|
||||
// DLE character, so we can write it to the destination stream.
|
||||
if (nextByte == DLE_CHAR) {
|
||||
destStream[decodedIndex] = nextByte;
|
||||
}
|
||||
else {
|
||||
/* The next byte is a STX, DTX or 0x0D character which
|
||||
* was escaped by a DLE character. The actual byte was
|
||||
* also encoded by adding + 0x40 to preven having control chars,
|
||||
* in the stream at all, so we convert it back. */
|
||||
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
|
||||
destStream[decodedIndex] = nextByte - 0x40;
|
||||
}
|
||||
else {
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
}
|
||||
++encodedIndex;
|
||||
}
|
||||
else {
|
||||
destStream[decodedIndex] = sourceStream[encodedIndex];
|
||||
}
|
||||
|
||||
++encodedIndex;
|
||||
++decodedIndex;
|
||||
}
|
||||
|
||||
if (sourceStream[encodedIndex] != ETX_CHAR) {
|
||||
*readLen = ++encodedIndex;
|
||||
return DECODING_ERROR;
|
||||
}
|
||||
else {
|
||||
*readLen = ++encodedIndex;
|
||||
*decodedLen = decodedIndex;
|
||||
return RETURN_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,79 +1,79 @@
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
|
||||
* decode arbitrary data with ASCII control characters
|
||||
* @details
|
||||
* List of control codes:
|
||||
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
|
||||
*
|
||||
* This encoder can be used to achieve a basic transport layer when using
|
||||
* char based transmission systems.
|
||||
* The passed source strean is converted into a encoded stream by adding
|
||||
* a STX marker at the start of the stream and an ETX marker at the end of
|
||||
* the stream. Any STX, ETX, DLE and CR occurences in the source stream are
|
||||
* escaped by a DLE character. The encoder also replaces escaped control chars
|
||||
* by another char, so STX, ETX and CR should not appear anywhere in the actual
|
||||
* encoded data stream.
|
||||
*
|
||||
* When using a strictly char based reception of packets enoded with DLE,
|
||||
* STX can be used to notify a reader that actual data will start to arrive
|
||||
* while ETX can be used to notify the reader that the data has ended.
|
||||
*/
|
||||
class DleEncoder: public HasReturnvaluesIF {
|
||||
private:
|
||||
DleEncoder();
|
||||
virtual ~DleEncoder();
|
||||
|
||||
public:
|
||||
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
|
||||
static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
|
||||
static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
|
||||
|
||||
//! Start Of Text character. First character is encoded stream
|
||||
static constexpr uint8_t STX_CHAR = 0x02;
|
||||
//! End Of Text character. Last character in encoded stream
|
||||
static constexpr uint8_t ETX_CHAR = 0x03;
|
||||
//! Data Link Escape character. Used to escape STX, ETX and DLE occurences
|
||||
//! in the source stream.
|
||||
static constexpr uint8_t DLE_CHAR = 0x10;
|
||||
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
|
||||
|
||||
/**
|
||||
* Encodes the give data stream by preceding it with the STX marker
|
||||
* and ending it with an ETX marker. STX, ETX and DLE characters inside
|
||||
* the stream are escaped by DLE characters and also replaced by adding
|
||||
* 0x40 (which is reverted in the decoing process).
|
||||
* @param sourceStream
|
||||
* @param sourceLen
|
||||
* @param destStream
|
||||
* @param maxDestLen
|
||||
* @param encodedLen
|
||||
* @param addStxEtx
|
||||
* Adding STX and ETX can be omitted, if they are added manually.
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
|
||||
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
|
||||
bool addStxEtx = true);
|
||||
|
||||
/**
|
||||
* Converts an encoded stream back.
|
||||
* @param sourceStream
|
||||
* @param sourceStreamLen
|
||||
* @param readLen
|
||||
* @param destStream
|
||||
* @param maxDestStreamlen
|
||||
* @param decodedLen
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t decode(const uint8_t *sourceStream,
|
||||
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
|
||||
size_t maxDestStreamlen, size_t *decodedLen);
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
|
||||
* decode arbitrary data with ASCII control characters
|
||||
* @details
|
||||
* List of control codes:
|
||||
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
|
||||
*
|
||||
* This encoder can be used to achieve a basic transport layer when using
|
||||
* char based transmission systems.
|
||||
* The passed source strean is converted into a encoded stream by adding
|
||||
* a STX marker at the start of the stream and an ETX marker at the end of
|
||||
* the stream. Any STX, ETX, DLE and CR occurences in the source stream are
|
||||
* escaped by a DLE character. The encoder also replaces escaped control chars
|
||||
* by another char, so STX, ETX and CR should not appear anywhere in the actual
|
||||
* encoded data stream.
|
||||
*
|
||||
* When using a strictly char based reception of packets enoded with DLE,
|
||||
* STX can be used to notify a reader that actual data will start to arrive
|
||||
* while ETX can be used to notify the reader that the data has ended.
|
||||
*/
|
||||
class DleEncoder: public HasReturnvaluesIF {
|
||||
private:
|
||||
DleEncoder();
|
||||
virtual ~DleEncoder();
|
||||
|
||||
public:
|
||||
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
|
||||
static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
|
||||
static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
|
||||
|
||||
//! Start Of Text character. First character is encoded stream
|
||||
static constexpr uint8_t STX_CHAR = 0x02;
|
||||
//! End Of Text character. Last character in encoded stream
|
||||
static constexpr uint8_t ETX_CHAR = 0x03;
|
||||
//! Data Link Escape character. Used to escape STX, ETX and DLE occurences
|
||||
//! in the source stream.
|
||||
static constexpr uint8_t DLE_CHAR = 0x10;
|
||||
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
|
||||
|
||||
/**
|
||||
* Encodes the give data stream by preceding it with the STX marker
|
||||
* and ending it with an ETX marker. STX, ETX and DLE characters inside
|
||||
* the stream are escaped by DLE characters and also replaced by adding
|
||||
* 0x40 (which is reverted in the decoing process).
|
||||
* @param sourceStream
|
||||
* @param sourceLen
|
||||
* @param destStream
|
||||
* @param maxDestLen
|
||||
* @param encodedLen
|
||||
* @param addStxEtx
|
||||
* Adding STX and ETX can be omitted, if they are added manually.
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
|
||||
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
|
||||
bool addStxEtx = true);
|
||||
|
||||
/**
|
||||
* Converts an encoded stream back.
|
||||
* @param sourceStream
|
||||
* @param sourceStreamLen
|
||||
* @param readLen
|
||||
* @param destStream
|
||||
* @param maxDestStreamlen
|
||||
* @param decodedLen
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t decode(const uint8_t *sourceStream,
|
||||
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
|
||||
size_t maxDestStreamlen, size_t *decodedLen);
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */
|
||||
|
@ -1,181 +1,181 @@
|
||||
#include "../globalfunctions/Type.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
|
||||
Type::Type() :
|
||||
actualType(UNKNOWN_TYPE) {
|
||||
}
|
||||
|
||||
Type::Type(ActualType_t actualType) :
|
||||
actualType(actualType) {
|
||||
}
|
||||
|
||||
Type::Type(const Type& type) :
|
||||
actualType(type.actualType) {
|
||||
}
|
||||
|
||||
Type& Type::operator =(Type rhs) {
|
||||
this->actualType = rhs.actualType;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type& Type::operator =(ActualType_t actualType) {
|
||||
this->actualType = actualType;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type::operator Type::ActualType_t() const {
|
||||
return actualType;
|
||||
}
|
||||
|
||||
bool Type::operator ==(const Type& rhs) {
|
||||
return this->actualType == rhs.actualType;
|
||||
}
|
||||
|
||||
bool Type::operator !=(const Type& rhs) {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
uint8_t Type::getSize() const {
|
||||
switch (actualType) {
|
||||
case UINT8_T:
|
||||
return sizeof(uint8_t);
|
||||
case INT8_T:
|
||||
return sizeof(int8_t);
|
||||
case UINT16_T:
|
||||
return sizeof(uint16_t);
|
||||
case INT16_T:
|
||||
return sizeof(int16_t);
|
||||
case UINT32_T:
|
||||
return sizeof(uint32_t);
|
||||
case INT32_T:
|
||||
return sizeof(int32_t);
|
||||
case FLOAT:
|
||||
return sizeof(float);
|
||||
case DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t Type::serialize(uint8_t** buffer, size_t* size,
|
||||
size_t maxSize, Endianness streamEndianness) const {
|
||||
uint8_t ptc;
|
||||
uint8_t pfc;
|
||||
ReturnValue_t result = getPtcPfc(&ptc, &pfc);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::serialize(&ptc, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::serialize(&pfc, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
size_t Type::getSerializedSize() const {
|
||||
uint8_t dontcare = 0;
|
||||
return 2 * SerializeAdapter::getSerializedSize(&dontcare);
|
||||
}
|
||||
|
||||
ReturnValue_t Type::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
uint8_t ptc;
|
||||
uint8_t pfc;
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(&ptc, buffer,
|
||||
size, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::deSerialize(&pfc, buffer, size,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
actualType = getActualType(ptc, pfc);
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Type::getPtcPfc(uint8_t* ptc, uint8_t* pfc) const {
|
||||
switch (actualType) {
|
||||
case UINT8_T:
|
||||
*ptc = 3;
|
||||
*pfc = 4;
|
||||
break;
|
||||
case INT8_T:
|
||||
*ptc = 4;
|
||||
*pfc = 4;
|
||||
break;
|
||||
case UINT16_T:
|
||||
*ptc = 3;
|
||||
*pfc = 12;
|
||||
break;
|
||||
case INT16_T:
|
||||
*ptc = 4;
|
||||
*pfc = 12;
|
||||
break;
|
||||
case UINT32_T:
|
||||
*ptc = 3;
|
||||
*pfc = 14;
|
||||
break;
|
||||
case INT32_T:
|
||||
*ptc = 4;
|
||||
*pfc = 14;
|
||||
break;
|
||||
case FLOAT:
|
||||
*ptc = 5;
|
||||
*pfc = 1;
|
||||
break;
|
||||
case DOUBLE:
|
||||
*ptc = 5;
|
||||
*pfc = 2;
|
||||
break;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
Type::ActualType_t Type::getActualType(uint8_t ptc, uint8_t pfc) {
|
||||
switch (ptc) {
|
||||
case 3:
|
||||
switch (pfc) {
|
||||
case 4:
|
||||
return UINT8_T;
|
||||
case 12:
|
||||
return UINT16_T;
|
||||
case 14:
|
||||
return UINT32_T;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (pfc) {
|
||||
case 4:
|
||||
return INT8_T;
|
||||
case 12:
|
||||
return INT16_T;
|
||||
case 14:
|
||||
return INT32_T;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (pfc) {
|
||||
case 1:
|
||||
return FLOAT;
|
||||
case 2:
|
||||
return DOUBLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return UNKNOWN_TYPE;
|
||||
}
|
||||
#include "../globalfunctions/Type.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
|
||||
Type::Type() :
|
||||
actualType(UNKNOWN_TYPE) {
|
||||
}
|
||||
|
||||
Type::Type(ActualType_t actualType) :
|
||||
actualType(actualType) {
|
||||
}
|
||||
|
||||
Type::Type(const Type& type) :
|
||||
actualType(type.actualType) {
|
||||
}
|
||||
|
||||
Type& Type::operator =(Type rhs) {
|
||||
this->actualType = rhs.actualType;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type& Type::operator =(ActualType_t actualType) {
|
||||
this->actualType = actualType;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type::operator Type::ActualType_t() const {
|
||||
return actualType;
|
||||
}
|
||||
|
||||
bool Type::operator ==(const Type& rhs) {
|
||||
return this->actualType == rhs.actualType;
|
||||
}
|
||||
|
||||
bool Type::operator !=(const Type& rhs) {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
uint8_t Type::getSize() const {
|
||||
switch (actualType) {
|
||||
case UINT8_T:
|
||||
return sizeof(uint8_t);
|
||||
case INT8_T:
|
||||
return sizeof(int8_t);
|
||||
case UINT16_T:
|
||||
return sizeof(uint16_t);
|
||||
case INT16_T:
|
||||
return sizeof(int16_t);
|
||||
case UINT32_T:
|
||||
return sizeof(uint32_t);
|
||||
case INT32_T:
|
||||
return sizeof(int32_t);
|
||||
case FLOAT:
|
||||
return sizeof(float);
|
||||
case DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t Type::serialize(uint8_t** buffer, size_t* size,
|
||||
size_t maxSize, Endianness streamEndianness) const {
|
||||
uint8_t ptc;
|
||||
uint8_t pfc;
|
||||
ReturnValue_t result = getPtcPfc(&ptc, &pfc);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::serialize(&ptc, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::serialize(&pfc, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
size_t Type::getSerializedSize() const {
|
||||
uint8_t dontcare = 0;
|
||||
return 2 * SerializeAdapter::getSerializedSize(&dontcare);
|
||||
}
|
||||
|
||||
ReturnValue_t Type::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
uint8_t ptc;
|
||||
uint8_t pfc;
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(&ptc, buffer,
|
||||
size, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::deSerialize(&pfc, buffer, size,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
actualType = getActualType(ptc, pfc);
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Type::getPtcPfc(uint8_t* ptc, uint8_t* pfc) const {
|
||||
switch (actualType) {
|
||||
case UINT8_T:
|
||||
*ptc = 3;
|
||||
*pfc = 4;
|
||||
break;
|
||||
case INT8_T:
|
||||
*ptc = 4;
|
||||
*pfc = 4;
|
||||
break;
|
||||
case UINT16_T:
|
||||
*ptc = 3;
|
||||
*pfc = 12;
|
||||
break;
|
||||
case INT16_T:
|
||||
*ptc = 4;
|
||||
*pfc = 12;
|
||||
break;
|
||||
case UINT32_T:
|
||||
*ptc = 3;
|
||||
*pfc = 14;
|
||||
break;
|
||||
case INT32_T:
|
||||
*ptc = 4;
|
||||
*pfc = 14;
|
||||
break;
|
||||
case FLOAT:
|
||||
*ptc = 5;
|
||||
*pfc = 1;
|
||||
break;
|
||||
case DOUBLE:
|
||||
*ptc = 5;
|
||||
*pfc = 2;
|
||||
break;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
Type::ActualType_t Type::getActualType(uint8_t ptc, uint8_t pfc) {
|
||||
switch (ptc) {
|
||||
case 3:
|
||||
switch (pfc) {
|
||||
case 4:
|
||||
return UINT8_T;
|
||||
case 12:
|
||||
return UINT16_T;
|
||||
case 14:
|
||||
return UINT32_T;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (pfc) {
|
||||
case 4:
|
||||
return INT8_T;
|
||||
case 12:
|
||||
return INT16_T;
|
||||
case 14:
|
||||
return INT32_T;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (pfc) {
|
||||
case 1:
|
||||
return FLOAT;
|
||||
case 2:
|
||||
return DOUBLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return UNKNOWN_TYPE;
|
||||
}
|
||||
|
@ -1,94 +1,94 @@
|
||||
#ifndef TYPE_H_
|
||||
#define TYPE_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief Type definition for CCSDS or ECSS.
|
||||
*/
|
||||
class Type: public SerializeIF {
|
||||
public:
|
||||
enum ActualType_t {
|
||||
UINT8_T,
|
||||
INT8_T,
|
||||
UINT16_T,
|
||||
INT16_T,
|
||||
UINT32_T,
|
||||
INT32_T,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
UNKNOWN_TYPE
|
||||
};
|
||||
|
||||
Type();
|
||||
|
||||
Type(ActualType_t actualType);
|
||||
|
||||
Type(const Type &type);
|
||||
|
||||
Type& operator=(Type rhs);
|
||||
|
||||
Type& operator=(ActualType_t actualType);
|
||||
|
||||
operator ActualType_t() const;
|
||||
|
||||
bool operator==(const Type &rhs);
|
||||
bool operator!=(const Type &rhs);
|
||||
|
||||
uint8_t getSize() const;
|
||||
|
||||
ReturnValue_t getPtcPfc(uint8_t *ptc, uint8_t *pfc) const;
|
||||
|
||||
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
|
||||
size_t maxSize, Endianness streamEndianness) const override;
|
||||
|
||||
virtual size_t getSerializedSize() const override;
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
ActualType_t actualType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PodTypeConversion {
|
||||
static const Type::ActualType_t type = Type::UNKNOWN_TYPE;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint8_t> {
|
||||
static const Type::ActualType_t type = Type::UINT8_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint16_t> {
|
||||
static const Type::ActualType_t type = Type::UINT16_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint32_t> {
|
||||
static const Type::ActualType_t type = Type::UINT32_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int8_t> {
|
||||
static const Type::ActualType_t type = Type::INT8_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int16_t> {
|
||||
static const Type::ActualType_t type = Type::INT16_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int32_t> {
|
||||
static const Type::ActualType_t type = Type::INT32_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<float> {
|
||||
static const Type::ActualType_t type = Type::FLOAT;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<double> {
|
||||
static const Type::ActualType_t type = Type::DOUBLE;
|
||||
};
|
||||
|
||||
#endif /* TYPE_H_ */
|
||||
#ifndef TYPE_H_
|
||||
#define TYPE_H_
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief Type definition for CCSDS or ECSS.
|
||||
*/
|
||||
class Type: public SerializeIF {
|
||||
public:
|
||||
enum ActualType_t {
|
||||
UINT8_T,
|
||||
INT8_T,
|
||||
UINT16_T,
|
||||
INT16_T,
|
||||
UINT32_T,
|
||||
INT32_T,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
UNKNOWN_TYPE
|
||||
};
|
||||
|
||||
Type();
|
||||
|
||||
Type(ActualType_t actualType);
|
||||
|
||||
Type(const Type &type);
|
||||
|
||||
Type& operator=(Type rhs);
|
||||
|
||||
Type& operator=(ActualType_t actualType);
|
||||
|
||||
operator ActualType_t() const;
|
||||
|
||||
bool operator==(const Type &rhs);
|
||||
bool operator!=(const Type &rhs);
|
||||
|
||||
uint8_t getSize() const;
|
||||
|
||||
ReturnValue_t getPtcPfc(uint8_t *ptc, uint8_t *pfc) const;
|
||||
|
||||
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
|
||||
size_t maxSize, Endianness streamEndianness) const override;
|
||||
|
||||
virtual size_t getSerializedSize() const override;
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
ActualType_t actualType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PodTypeConversion {
|
||||
static const Type::ActualType_t type = Type::UNKNOWN_TYPE;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint8_t> {
|
||||
static const Type::ActualType_t type = Type::UINT8_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint16_t> {
|
||||
static const Type::ActualType_t type = Type::UINT16_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<uint32_t> {
|
||||
static const Type::ActualType_t type = Type::UINT32_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int8_t> {
|
||||
static const Type::ActualType_t type = Type::INT8_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int16_t> {
|
||||
static const Type::ActualType_t type = Type::INT16_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<int32_t> {
|
||||
static const Type::ActualType_t type = Type::INT32_T;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<float> {
|
||||
static const Type::ActualType_t type = Type::FLOAT;
|
||||
};
|
||||
template<>
|
||||
struct PodTypeConversion<double> {
|
||||
static const Type::ActualType_t type = Type::DOUBLE;
|
||||
};
|
||||
|
||||
#endif /* TYPE_H_ */
|
||||
|
@ -1,61 +1,61 @@
|
||||
#include "../globalfunctions/arrayprinter.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include <bitset>
|
||||
|
||||
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
|
||||
bool printInfo, size_t maxCharPerLine) {
|
||||
if(printInfo) {
|
||||
sif::info << "Printing data with size " << size << ": ";
|
||||
}
|
||||
sif::info << "[";
|
||||
if(type == OutputType::HEX) {
|
||||
arrayprinter::printHex(data, size, maxCharPerLine);
|
||||
}
|
||||
else if (type == OutputType::DEC) {
|
||||
arrayprinter::printDec(data, size, maxCharPerLine);
|
||||
}
|
||||
else if(type == OutputType::BIN) {
|
||||
arrayprinter::printBin(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
void arrayprinter::printHex(const uint8_t *data, size_t size,
|
||||
size_t maxCharPerLine) {
|
||||
sif::info << std::hex;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << "0x" << static_cast<int>(data[i]);
|
||||
if(i < size - 1){
|
||||
sif::info << " , ";
|
||||
if(i > 0 and i % maxCharPerLine == 0) {
|
||||
sif::info << "\r\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sif::info << std::dec;
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
|
||||
void arrayprinter::printDec(const uint8_t *data, size_t size,
|
||||
size_t maxCharPerLine) {
|
||||
sif::info << std::dec;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << static_cast<int>(data[i]);
|
||||
if(i < size - 1){
|
||||
sif::info << " , ";
|
||||
if(i > 0 and i % maxCharPerLine == 0) {
|
||||
sif::info << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
|
||||
void arrayprinter::printBin(const uint8_t *data, size_t size) {
|
||||
sif::info << "\n" << std::flush;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << "Byte " << i + 1 << ": 0b"<<
|
||||
std::bitset<8>(data[i]) << ",\n" << std::flush;
|
||||
}
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
#include "../globalfunctions/arrayprinter.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include <bitset>
|
||||
|
||||
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
|
||||
bool printInfo, size_t maxCharPerLine) {
|
||||
if(printInfo) {
|
||||
sif::info << "Printing data with size " << size << ": ";
|
||||
}
|
||||
sif::info << "[";
|
||||
if(type == OutputType::HEX) {
|
||||
arrayprinter::printHex(data, size, maxCharPerLine);
|
||||
}
|
||||
else if (type == OutputType::DEC) {
|
||||
arrayprinter::printDec(data, size, maxCharPerLine);
|
||||
}
|
||||
else if(type == OutputType::BIN) {
|
||||
arrayprinter::printBin(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
void arrayprinter::printHex(const uint8_t *data, size_t size,
|
||||
size_t maxCharPerLine) {
|
||||
sif::info << std::hex;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << "0x" << static_cast<int>(data[i]);
|
||||
if(i < size - 1){
|
||||
sif::info << " , ";
|
||||
if(i > 0 and i % maxCharPerLine == 0) {
|
||||
sif::info << "\r\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sif::info << std::dec;
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
|
||||
void arrayprinter::printDec(const uint8_t *data, size_t size,
|
||||
size_t maxCharPerLine) {
|
||||
sif::info << std::dec;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << static_cast<int>(data[i]);
|
||||
if(i < size - 1){
|
||||
sif::info << " , ";
|
||||
if(i > 0 and i % maxCharPerLine == 0) {
|
||||
sif::info << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
|
||||
void arrayprinter::printBin(const uint8_t *data, size_t size) {
|
||||
sif::info << "\n" << std::flush;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sif::info << "Byte " << i + 1 << ": 0b"<<
|
||||
std::bitset<8>(data[i]) << ",\n" << std::flush;
|
||||
}
|
||||
sif::info << "]" << std::endl;
|
||||
}
|
||||
|
@ -1,41 +1,41 @@
|
||||
#ifndef BINARYMATCHER_H_
|
||||
#define BINARYMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
|
||||
template<typename T>
|
||||
class BinaryMatcher: public MatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T mask, matchField;
|
||||
|
||||
BinaryMatcher() :
|
||||
inverted(false), mask(0), matchField(0) {
|
||||
}
|
||||
|
||||
BinaryMatcher(T mask, T match, bool inverted = false) :
|
||||
inverted(inverted), mask(mask), matchField(match) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return ~doMatch(input, mask, matchField);
|
||||
} else {
|
||||
return doMatch(input, mask, matchField);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool doMatch(T input, T mask, T match) {
|
||||
match = match & mask;
|
||||
input = input & mask;
|
||||
if (input == match) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BINARYMATCHER_H_ */
|
||||
#ifndef BINARYMATCHER_H_
|
||||
#define BINARYMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
|
||||
template<typename T>
|
||||
class BinaryMatcher: public MatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T mask, matchField;
|
||||
|
||||
BinaryMatcher() :
|
||||
inverted(false), mask(0), matchField(0) {
|
||||
}
|
||||
|
||||
BinaryMatcher(T mask, T match, bool inverted = false) :
|
||||
inverted(inverted), mask(mask), matchField(match) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return ~doMatch(input, mask, matchField);
|
||||
} else {
|
||||
return doMatch(input, mask, matchField);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool doMatch(T input, T mask, T match) {
|
||||
match = match & mask;
|
||||
input = input & mask;
|
||||
if (input == match) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BINARYMATCHER_H_ */
|
||||
|
@ -1,50 +1,50 @@
|
||||
#ifndef DECIMALMATCHER_H_
|
||||
#define DECIMALMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
|
||||
template<typename T>
|
||||
class DecimalMatcher: public MatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T mask, matchField;
|
||||
|
||||
DecimalMatcher() :
|
||||
inverted(false), mask(0), matchField(0) {
|
||||
}
|
||||
|
||||
DecimalMatcher(T mask, T match, bool inverted = false) :
|
||||
inverted(inverted), mask(mask), matchField(match) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return ~doMatch(input, mask, matchField);
|
||||
} else {
|
||||
return doMatch(input, mask, matchField);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool doMatch(T input, T mask, T match) {
|
||||
T decimal = 1, remainderMask, remainderMatch, remainderInput;
|
||||
|
||||
while (mask != 0) {
|
||||
remainderMask = mask % (decimal * 10);
|
||||
remainderMatch = match % (decimal * 10);
|
||||
remainderInput = input % (decimal * 10);
|
||||
if (remainderMask != 0) {
|
||||
if (remainderMatch != remainderInput) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mask -= remainderMask;
|
||||
match -= remainderMatch;
|
||||
input -= remainderInput;
|
||||
decimal *= 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DECIMALMATCHER_H_ */
|
||||
#ifndef DECIMALMATCHER_H_
|
||||
#define DECIMALMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
|
||||
template<typename T>
|
||||
class DecimalMatcher: public MatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T mask, matchField;
|
||||
|
||||
DecimalMatcher() :
|
||||
inverted(false), mask(0), matchField(0) {
|
||||
}
|
||||
|
||||
DecimalMatcher(T mask, T match, bool inverted = false) :
|
||||
inverted(inverted), mask(mask), matchField(match) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return ~doMatch(input, mask, matchField);
|
||||
} else {
|
||||
return doMatch(input, mask, matchField);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool doMatch(T input, T mask, T match) {
|
||||
T decimal = 1, remainderMask, remainderMatch, remainderInput;
|
||||
|
||||
while (mask != 0) {
|
||||
remainderMask = mask % (decimal * 10);
|
||||
remainderMatch = match % (decimal * 10);
|
||||
remainderInput = input % (decimal * 10);
|
||||
if (remainderMask != 0) {
|
||||
if (remainderMatch != remainderInput) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mask -= remainderMask;
|
||||
match -= remainderMatch;
|
||||
input -= remainderInput;
|
||||
decimal *= 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DECIMALMATCHER_H_ */
|
||||
|
@ -1,216 +1,216 @@
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_
|
||||
|
||||
#include "../../container/BinaryTree.h"
|
||||
#include "../../globalfunctions/matching/SerializeableMatcherIF.h"
|
||||
#include "../../serialize/SerializeAdapter.h"
|
||||
|
||||
template<typename T>
|
||||
class MatchTree: public SerializeableMatcherIF<T>, public BinaryTree<
|
||||
SerializeableMatcherIF<T>> {
|
||||
public:
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::MATCH_TREE_CLASS;
|
||||
static const ReturnValue_t TOO_DETAILED_REQUEST = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t TOO_GENERAL_REQUEST = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t NO_MATCH = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(4);
|
||||
static const ReturnValue_t NEW_NODE_CREATED = MAKE_RETURN_CODE(5);
|
||||
|
||||
typedef typename BinaryTree<SerializeableMatcherIF<T>>::iterator iterator;
|
||||
typedef BinaryNode<SerializeableMatcherIF<T>> Node;
|
||||
static const bool AND = true; //LEFT
|
||||
static const bool OR = false; //RIGHT
|
||||
MatchTree(BinaryNode<SerializeableMatcherIF<T>>* root,
|
||||
uint8_t maxDepth = -1) :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(root), maxDepth(maxDepth) {
|
||||
}
|
||||
MatchTree(iterator root, uint8_t maxDepth = -1) :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(
|
||||
maxDepth) {
|
||||
}
|
||||
MatchTree() :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {
|
||||
}
|
||||
virtual ~MatchTree() {
|
||||
}
|
||||
virtual bool match(T number) {
|
||||
return matchesTree(number);
|
||||
}
|
||||
bool matchesTree(T number) {
|
||||
iterator iter = this->begin();
|
||||
if (iter == this->end()) {
|
||||
return false;
|
||||
}
|
||||
return matchSubtree(iter, number);
|
||||
}
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
||||
size_t maxSize, SerializeIF::Endianness streamEndianness) const override {
|
||||
iterator iter = this->begin();
|
||||
uint8_t count = this->countRight(iter);
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
||||
buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (iter == this->end()) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
result = iter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
result = temp.serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
iter = iter.right();
|
||||
while (iter != this->end()) {
|
||||
result = iter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
result = temp.serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
iter = iter.right();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t getSerializedSize() const override {
|
||||
//Analogous to serialize!
|
||||
uint32_t size = 1; //One for count
|
||||
iterator iter = this->begin();
|
||||
if (iter == this->end()) {
|
||||
return size;
|
||||
}
|
||||
//Count object itself
|
||||
size += iter->getSerializedSize();
|
||||
//Handle everything below on AND side
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
size += temp.getSerializedSize();
|
||||
}
|
||||
//Handle everything on OR side
|
||||
iter = iter.right();
|
||||
//Iterate over every object on the OR branch
|
||||
while (iter != this->end()) {
|
||||
size += iter->getSerializedSize();
|
||||
if (maxDepth > 0) {
|
||||
//If we are allowed to go deeper, handle AND elements.
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
size += temp.getSerializedSize();
|
||||
}
|
||||
iter = iter.right();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool isOnAndBranch(iterator position) {
|
||||
if ((position == this->end()) || (position.up() == this->end())) {
|
||||
return false;
|
||||
}
|
||||
if (position.up().left() == position) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//SHOULDDO: What to do if insertion/deletion fails. Throw event?
|
||||
ReturnValue_t removeElementAndAllChildren(iterator position) {
|
||||
auto children = this->erase(position);
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if (children.first != this->end()) {
|
||||
result = removeElementAndAllChildren(children.first);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (children.second != this->end()) {
|
||||
result = removeElementAndAllChildren(children.second);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
//Delete element itself.
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
ReturnValue_t removeElementAndReconnectChildren(iterator position) {
|
||||
if (position == this->end()) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
//Delete everything from the AND branch.
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if (position.left() != this->end()) {
|
||||
result = removeElementAndAllChildren(position.left());
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (position.right() != this->end()) {
|
||||
//There's something at the OR branch, reconnect to parent.
|
||||
if (isOnAndBranch(position)) {
|
||||
//Either one hierarchy up AND branch...
|
||||
this->insert(AND, position.up(), position.right().element);
|
||||
} else {
|
||||
//or on another OR'ed element (or install new root node).
|
||||
this->insert(OR, position.up(), position.right().element);
|
||||
}
|
||||
} else {
|
||||
if (isOnAndBranch(position)) {
|
||||
//Recursively delete parent node as well, because it is not expected to be there anymore.
|
||||
return removeElementAndReconnectChildren(position.up());
|
||||
} else {
|
||||
//simply delete self.
|
||||
this->erase(position);
|
||||
}
|
||||
|
||||
}
|
||||
//Delete element itself.
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
virtual ReturnValue_t cleanUpElement(iterator position) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
bool matchSubtree(iterator iter, T number) {
|
||||
bool isMatch = iter->match(number);
|
||||
if (isMatch) {
|
||||
if (iter.left() == this->end()) {
|
||||
return true;
|
||||
}
|
||||
isMatch = matchSubtree(iter.left(), number);
|
||||
if (isMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (iter.right() == this->end()) {
|
||||
return false;
|
||||
}
|
||||
return matchSubtree(iter.right(), number);
|
||||
}
|
||||
private:
|
||||
uint8_t maxDepth;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ */
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_
|
||||
|
||||
#include "../../container/BinaryTree.h"
|
||||
#include "../../globalfunctions/matching/SerializeableMatcherIF.h"
|
||||
#include "../../serialize/SerializeAdapter.h"
|
||||
|
||||
template<typename T>
|
||||
class MatchTree: public SerializeableMatcherIF<T>, public BinaryTree<
|
||||
SerializeableMatcherIF<T>> {
|
||||
public:
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::MATCH_TREE_CLASS;
|
||||
static const ReturnValue_t TOO_DETAILED_REQUEST = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t TOO_GENERAL_REQUEST = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t NO_MATCH = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(4);
|
||||
static const ReturnValue_t NEW_NODE_CREATED = MAKE_RETURN_CODE(5);
|
||||
|
||||
typedef typename BinaryTree<SerializeableMatcherIF<T>>::iterator iterator;
|
||||
typedef BinaryNode<SerializeableMatcherIF<T>> Node;
|
||||
static const bool AND = true; //LEFT
|
||||
static const bool OR = false; //RIGHT
|
||||
MatchTree(BinaryNode<SerializeableMatcherIF<T>>* root,
|
||||
uint8_t maxDepth = -1) :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(root), maxDepth(maxDepth) {
|
||||
}
|
||||
MatchTree(iterator root, uint8_t maxDepth = -1) :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(
|
||||
maxDepth) {
|
||||
}
|
||||
MatchTree() :
|
||||
BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {
|
||||
}
|
||||
virtual ~MatchTree() {
|
||||
}
|
||||
virtual bool match(T number) {
|
||||
return matchesTree(number);
|
||||
}
|
||||
bool matchesTree(T number) {
|
||||
iterator iter = this->begin();
|
||||
if (iter == this->end()) {
|
||||
return false;
|
||||
}
|
||||
return matchSubtree(iter, number);
|
||||
}
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
||||
size_t maxSize, SerializeIF::Endianness streamEndianness) const override {
|
||||
iterator iter = this->begin();
|
||||
uint8_t count = this->countRight(iter);
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
||||
buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (iter == this->end()) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
result = iter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
result = temp.serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
iter = iter.right();
|
||||
while (iter != this->end()) {
|
||||
result = iter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
result = temp.serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
iter = iter.right();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t getSerializedSize() const override {
|
||||
//Analogous to serialize!
|
||||
uint32_t size = 1; //One for count
|
||||
iterator iter = this->begin();
|
||||
if (iter == this->end()) {
|
||||
return size;
|
||||
}
|
||||
//Count object itself
|
||||
size += iter->getSerializedSize();
|
||||
//Handle everything below on AND side
|
||||
if (maxDepth > 0) {
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
size += temp.getSerializedSize();
|
||||
}
|
||||
//Handle everything on OR side
|
||||
iter = iter.right();
|
||||
//Iterate over every object on the OR branch
|
||||
while (iter != this->end()) {
|
||||
size += iter->getSerializedSize();
|
||||
if (maxDepth > 0) {
|
||||
//If we are allowed to go deeper, handle AND elements.
|
||||
MatchTree<T> temp(iter.left(), maxDepth - 1);
|
||||
size += temp.getSerializedSize();
|
||||
}
|
||||
iter = iter.right();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool isOnAndBranch(iterator position) {
|
||||
if ((position == this->end()) || (position.up() == this->end())) {
|
||||
return false;
|
||||
}
|
||||
if (position.up().left() == position) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//SHOULDDO: What to do if insertion/deletion fails. Throw event?
|
||||
ReturnValue_t removeElementAndAllChildren(iterator position) {
|
||||
auto children = this->erase(position);
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if (children.first != this->end()) {
|
||||
result = removeElementAndAllChildren(children.first);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (children.second != this->end()) {
|
||||
result = removeElementAndAllChildren(children.second);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
//Delete element itself.
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
ReturnValue_t removeElementAndReconnectChildren(iterator position) {
|
||||
if (position == this->end()) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
//Delete everything from the AND branch.
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
if (position.left() != this->end()) {
|
||||
result = removeElementAndAllChildren(position.left());
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (position.right() != this->end()) {
|
||||
//There's something at the OR branch, reconnect to parent.
|
||||
if (isOnAndBranch(position)) {
|
||||
//Either one hierarchy up AND branch...
|
||||
this->insert(AND, position.up(), position.right().element);
|
||||
} else {
|
||||
//or on another OR'ed element (or install new root node).
|
||||
this->insert(OR, position.up(), position.right().element);
|
||||
}
|
||||
} else {
|
||||
if (isOnAndBranch(position)) {
|
||||
//Recursively delete parent node as well, because it is not expected to be there anymore.
|
||||
return removeElementAndReconnectChildren(position.up());
|
||||
} else {
|
||||
//simply delete self.
|
||||
this->erase(position);
|
||||
}
|
||||
|
||||
}
|
||||
//Delete element itself.
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
virtual ReturnValue_t cleanUpElement(iterator position) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
bool matchSubtree(iterator iter, T number) {
|
||||
bool isMatch = iter->match(number);
|
||||
if (isMatch) {
|
||||
if (iter.left() == this->end()) {
|
||||
return true;
|
||||
}
|
||||
isMatch = matchSubtree(iter.left(), number);
|
||||
if (isMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (iter.right() == this->end()) {
|
||||
return false;
|
||||
}
|
||||
return matchSubtree(iter.right(), number);
|
||||
}
|
||||
private:
|
||||
uint8_t maxDepth;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_MATCHTREE_H_ */
|
||||
|
@ -1,70 +1,70 @@
|
||||
#ifndef RANGEMATCHER_H_
|
||||
#define RANGEMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/SerializeableMatcherIF.h"
|
||||
#include "../../serialize/SerializeAdapter.h"
|
||||
|
||||
template<typename T>
|
||||
class RangeMatcher: public SerializeableMatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T lowerBound;
|
||||
T upperBound;
|
||||
|
||||
RangeMatcher() :
|
||||
inverted(true), lowerBound(1), upperBound(0) {
|
||||
}
|
||||
RangeMatcher(T lowerBound, T upperBound, bool inverted = false) :
|
||||
inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return !doMatch(input);
|
||||
} else {
|
||||
return doMatch(input);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override {
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&lowerBound, buffer,
|
||||
size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&upperBound, buffer, size,
|
||||
maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return SerializeAdapter::serialize(&inverted, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
}
|
||||
|
||||
size_t getSerializedSize() const override {
|
||||
return sizeof(lowerBound) + sizeof(upperBound) + sizeof(bool);
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) override {
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(&lowerBound,
|
||||
buffer, size, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&upperBound, buffer, size,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return SerializeAdapter::deSerialize(&inverted, buffer, size,
|
||||
streamEndianness);
|
||||
}
|
||||
protected:
|
||||
bool doMatch(T input) {
|
||||
return (input >= lowerBound) && (input <= upperBound);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RANGEMATCHER_H_ */
|
||||
#ifndef RANGEMATCHER_H_
|
||||
#define RANGEMATCHER_H_
|
||||
|
||||
#include "../../globalfunctions/matching/SerializeableMatcherIF.h"
|
||||
#include "../../serialize/SerializeAdapter.h"
|
||||
|
||||
template<typename T>
|
||||
class RangeMatcher: public SerializeableMatcherIF<T> {
|
||||
public:
|
||||
bool inverted;
|
||||
T lowerBound;
|
||||
T upperBound;
|
||||
|
||||
RangeMatcher() :
|
||||
inverted(true), lowerBound(1), upperBound(0) {
|
||||
}
|
||||
RangeMatcher(T lowerBound, T upperBound, bool inverted = false) :
|
||||
inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {
|
||||
}
|
||||
|
||||
bool match(T input) {
|
||||
if (inverted) {
|
||||
return !doMatch(input);
|
||||
} else {
|
||||
return doMatch(input);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override {
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&lowerBound, buffer,
|
||||
size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&upperBound, buffer, size,
|
||||
maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return SerializeAdapter::serialize(&inverted, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
}
|
||||
|
||||
size_t getSerializedSize() const override {
|
||||
return sizeof(lowerBound) + sizeof(upperBound) + sizeof(bool);
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) override {
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(&lowerBound,
|
||||
buffer, size, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&upperBound, buffer, size,
|
||||
streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return SerializeAdapter::deSerialize(&inverted, buffer, size,
|
||||
streamEndianness);
|
||||
}
|
||||
protected:
|
||||
bool doMatch(T input) {
|
||||
return (input >= lowerBound) && (input <= upperBound);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RANGEMATCHER_H_ */
|
||||
|
@ -1,13 +1,13 @@
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
|
||||
template<typename T>
|
||||
class SerializeableMatcherIF : public MatcherIF<T>, public SerializeIF {
|
||||
public:
|
||||
virtual ~SerializeableMatcherIF() {}
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ */
|
||||
#ifndef FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_
|
||||
#define FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_
|
||||
|
||||
#include "../../globalfunctions/matching/MatcherIF.h"
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
|
||||
template<typename T>
|
||||
class SerializeableMatcherIF : public MatcherIF<T>, public SerializeIF {
|
||||
public:
|
||||
virtual ~SerializeableMatcherIF() {}
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_GLOBALFUNCTIONS_MATCHING_SERIALIZEABLEMATCHERIF_H_ */
|
||||
|
@ -1,156 +1,156 @@
|
||||
#include "QuaternionOperations.h"
|
||||
#include "../../globalfunctions/math/VectorOperations.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
QuaternionOperations::~QuaternionOperations() {
|
||||
}
|
||||
|
||||
void QuaternionOperations::multiply(const double* q1, const double* q2,
|
||||
double* q) {
|
||||
double out[4];
|
||||
|
||||
out[0] = q1[3] * q2[0] + q1[2] * q2[1] - q1[1] * q2[2] + q1[0] * q2[3];
|
||||
out[1] = -q1[2] * q2[0] + q1[3] * q2[1] + q1[0] * q2[2] + q1[1] * q2[3];
|
||||
out[2] = q1[1] * q2[0] - q1[0] * q2[1] + q1[3] * q2[2] + q1[2] * q2[3];
|
||||
out[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3];
|
||||
|
||||
memcpy(q, out, 4 * sizeof(*q));
|
||||
}
|
||||
|
||||
void QuaternionOperations::toDcm(const double* quaternion, double dcm[][3]) {
|
||||
dcm[0][0] = 2
|
||||
* (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[0][1] = 2
|
||||
* (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]);
|
||||
dcm[0][2] = 2
|
||||
* (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]);
|
||||
|
||||
dcm[1][0] = 2
|
||||
* (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]);
|
||||
dcm[1][1] = 2
|
||||
* (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[1][2] = 2
|
||||
* (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]);
|
||||
|
||||
dcm[2][0] = 2
|
||||
* (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]);
|
||||
dcm[2][1] = 2
|
||||
* (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]);
|
||||
dcm[2][2] = 2
|
||||
* (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
}
|
||||
|
||||
void QuaternionOperations::inverse(const double* quaternion,
|
||||
double* inverseQuaternion) {
|
||||
memcpy(inverseQuaternion, quaternion, 4 * sizeof(*quaternion));
|
||||
VectorOperations<double>::mulScalar(inverseQuaternion, -1,
|
||||
inverseQuaternion, 3);
|
||||
}
|
||||
|
||||
QuaternionOperations::QuaternionOperations() {
|
||||
|
||||
}
|
||||
|
||||
void QuaternionOperations::normalize(const double* quaternion,
|
||||
double* unitQuaternion) {
|
||||
VectorOperations<double>::normalize(quaternion, unitQuaternion, 4);
|
||||
}
|
||||
|
||||
float QuaternionOperations::norm(const double* quaternion) {
|
||||
return VectorOperations<double>::norm(quaternion, 4);
|
||||
}
|
||||
|
||||
void QuaternionOperations::fromDcm(const double dcm[][3], double* quaternion,
|
||||
uint8_t *index) {
|
||||
|
||||
double a[4];
|
||||
|
||||
a[0] = 1 + dcm[0][0] - dcm[1][1] - dcm[2][2];
|
||||
a[1] = 1 - dcm[0][0] + dcm[1][1] - dcm[2][2];
|
||||
a[2] = 1 - dcm[0][0] - dcm[1][1] + dcm[2][2];
|
||||
a[3] = 1 + dcm[0][0] + dcm[1][1] + dcm[2][2];
|
||||
|
||||
uint8_t maxAIndex = 0;
|
||||
|
||||
VectorOperations<double>::maxValue(a, 4, &maxAIndex);
|
||||
|
||||
if (index != 0) {
|
||||
*index = maxAIndex;
|
||||
}
|
||||
|
||||
switch (maxAIndex) {
|
||||
case 0:
|
||||
quaternion[0] = 0.5 * sqrt(a[0]);
|
||||
quaternion[1] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[0]));
|
||||
quaternion[2] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[0]));
|
||||
quaternion[3] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[0]));
|
||||
break;
|
||||
case 1:
|
||||
quaternion[0] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[1]));
|
||||
quaternion[1] = 0.5 * sqrt(a[1]);
|
||||
quaternion[2] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[1]));
|
||||
quaternion[3] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[1]));
|
||||
break;
|
||||
case 2:
|
||||
quaternion[0] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[2]));
|
||||
quaternion[1] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[2]));
|
||||
quaternion[2] = 0.5 * sqrt(a[2]);
|
||||
quaternion[3] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[2]));
|
||||
break;
|
||||
case 3:
|
||||
quaternion[0] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[3]));
|
||||
quaternion[1] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[3]));
|
||||
quaternion[2] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[3]));
|
||||
quaternion[3] = 0.5 * sqrt(a[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QuaternionOperations::toDcm(const double* quaternion, float dcm[][3]) {
|
||||
dcm[0][0] = 2
|
||||
* (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[0][1] = 2
|
||||
* (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]);
|
||||
dcm[0][2] = 2
|
||||
* (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]);
|
||||
|
||||
dcm[1][0] = 2
|
||||
* (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]);
|
||||
dcm[1][1] = 2
|
||||
* (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[1][2] = 2
|
||||
* (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]);
|
||||
|
||||
dcm[2][0] = 2
|
||||
* (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]);
|
||||
dcm[2][1] = 2
|
||||
* (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]);
|
||||
dcm[2][2] = 2
|
||||
* (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
}
|
||||
|
||||
void QuaternionOperations::normalize(double* quaternion) {
|
||||
normalize(quaternion, quaternion);
|
||||
}
|
||||
|
||||
double QuaternionOperations::getAngle(const double* quaternion, bool abs) {
|
||||
if (quaternion[3] >= 0) {
|
||||
return 2 * acos(quaternion[3]);
|
||||
} else {
|
||||
if (abs) {
|
||||
return 2 * acos(-quaternion[3]);
|
||||
} else {
|
||||
return -2 * acos(-quaternion[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "QuaternionOperations.h"
|
||||
#include "../../globalfunctions/math/VectorOperations.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
QuaternionOperations::~QuaternionOperations() {
|
||||
}
|
||||
|
||||
void QuaternionOperations::multiply(const double* q1, const double* q2,
|
||||
double* q) {
|
||||
double out[4];
|
||||
|
||||
out[0] = q1[3] * q2[0] + q1[2] * q2[1] - q1[1] * q2[2] + q1[0] * q2[3];
|
||||
out[1] = -q1[2] * q2[0] + q1[3] * q2[1] + q1[0] * q2[2] + q1[1] * q2[3];
|
||||
out[2] = q1[1] * q2[0] - q1[0] * q2[1] + q1[3] * q2[2] + q1[2] * q2[3];
|
||||
out[3] = -q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] + q1[3] * q2[3];
|
||||
|
||||
memcpy(q, out, 4 * sizeof(*q));
|
||||
}
|
||||
|
||||
void QuaternionOperations::toDcm(const double* quaternion, double dcm[][3]) {
|
||||
dcm[0][0] = 2
|
||||
* (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[0][1] = 2
|
||||
* (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]);
|
||||
dcm[0][2] = 2
|
||||
* (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]);
|
||||
|
||||
dcm[1][0] = 2
|
||||
* (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]);
|
||||
dcm[1][1] = 2
|
||||
* (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[1][2] = 2
|
||||
* (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]);
|
||||
|
||||
dcm[2][0] = 2
|
||||
* (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]);
|
||||
dcm[2][1] = 2
|
||||
* (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]);
|
||||
dcm[2][2] = 2
|
||||
* (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
}
|
||||
|
||||
void QuaternionOperations::inverse(const double* quaternion,
|
||||
double* inverseQuaternion) {
|
||||
memcpy(inverseQuaternion, quaternion, 4 * sizeof(*quaternion));
|
||||
VectorOperations<double>::mulScalar(inverseQuaternion, -1,
|
||||
inverseQuaternion, 3);
|
||||
}
|
||||
|
||||
QuaternionOperations::QuaternionOperations() {
|
||||
|
||||
}
|
||||
|
||||
void QuaternionOperations::normalize(const double* quaternion,
|
||||
double* unitQuaternion) {
|
||||
VectorOperations<double>::normalize(quaternion, unitQuaternion, 4);
|
||||
}
|
||||
|
||||
float QuaternionOperations::norm(const double* quaternion) {
|
||||
return VectorOperations<double>::norm(quaternion, 4);
|
||||
}
|
||||
|
||||
void QuaternionOperations::fromDcm(const double dcm[][3], double* quaternion,
|
||||
uint8_t *index) {
|
||||
|
||||
double a[4];
|
||||
|
||||
a[0] = 1 + dcm[0][0] - dcm[1][1] - dcm[2][2];
|
||||
a[1] = 1 - dcm[0][0] + dcm[1][1] - dcm[2][2];
|
||||
a[2] = 1 - dcm[0][0] - dcm[1][1] + dcm[2][2];
|
||||
a[3] = 1 + dcm[0][0] + dcm[1][1] + dcm[2][2];
|
||||
|
||||
uint8_t maxAIndex = 0;
|
||||
|
||||
VectorOperations<double>::maxValue(a, 4, &maxAIndex);
|
||||
|
||||
if (index != 0) {
|
||||
*index = maxAIndex;
|
||||
}
|
||||
|
||||
switch (maxAIndex) {
|
||||
case 0:
|
||||
quaternion[0] = 0.5 * sqrt(a[0]);
|
||||
quaternion[1] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[0]));
|
||||
quaternion[2] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[0]));
|
||||
quaternion[3] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[0]));
|
||||
break;
|
||||
case 1:
|
||||
quaternion[0] = (dcm[0][1] + dcm[1][0]) / (2 * sqrt(a[1]));
|
||||
quaternion[1] = 0.5 * sqrt(a[1]);
|
||||
quaternion[2] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[1]));
|
||||
quaternion[3] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[1]));
|
||||
break;
|
||||
case 2:
|
||||
quaternion[0] = (dcm[0][2] + dcm[2][0]) / (2 * sqrt(a[2]));
|
||||
quaternion[1] = (dcm[1][2] + dcm[2][1]) / (2 * sqrt(a[2]));
|
||||
quaternion[2] = 0.5 * sqrt(a[2]);
|
||||
quaternion[3] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[2]));
|
||||
break;
|
||||
case 3:
|
||||
quaternion[0] = (dcm[1][2] - dcm[2][1]) / (2 * sqrt(a[3]));
|
||||
quaternion[1] = (dcm[2][0] - dcm[0][2]) / (2 * sqrt(a[3]));
|
||||
quaternion[2] = (dcm[0][1] - dcm[1][0]) / (2 * sqrt(a[3]));
|
||||
quaternion[3] = 0.5 * sqrt(a[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QuaternionOperations::toDcm(const double* quaternion, float dcm[][3]) {
|
||||
dcm[0][0] = 2
|
||||
* (quaternion[0] * quaternion[0] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[0][1] = 2
|
||||
* (quaternion[0] * quaternion[1] + quaternion[2] * quaternion[3]);
|
||||
dcm[0][2] = 2
|
||||
* (quaternion[0] * quaternion[2] - quaternion[1] * quaternion[3]);
|
||||
|
||||
dcm[1][0] = 2
|
||||
* (quaternion[0] * quaternion[1] - quaternion[2] * quaternion[3]);
|
||||
dcm[1][1] = 2
|
||||
* (quaternion[1] * quaternion[1] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
dcm[1][2] = 2
|
||||
* (quaternion[1] * quaternion[2] + quaternion[0] * quaternion[3]);
|
||||
|
||||
dcm[2][0] = 2
|
||||
* (quaternion[0] * quaternion[2] + quaternion[1] * quaternion[3]);
|
||||
dcm[2][1] = 2
|
||||
* (quaternion[1] * quaternion[2] - quaternion[0] * quaternion[3]);
|
||||
dcm[2][2] = 2
|
||||
* (quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3])
|
||||
- 1;
|
||||
}
|
||||
|
||||
void QuaternionOperations::normalize(double* quaternion) {
|
||||
normalize(quaternion, quaternion);
|
||||
}
|
||||
|
||||
double QuaternionOperations::getAngle(const double* quaternion, bool abs) {
|
||||
if (quaternion[3] >= 0) {
|
||||
return 2 * acos(quaternion[3]);
|
||||
} else {
|
||||
if (abs) {
|
||||
return 2 * acos(-quaternion[3]);
|
||||
} else {
|
||||
return -2 * acos(-quaternion[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,99 +1,99 @@
|
||||
#include "timevalOperations.h"
|
||||
|
||||
timeval& operator+=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator+(timeval lhs, const timeval& rhs) {
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval& operator-=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum -= rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator-(timeval lhs, const timeval& rhs) {
|
||||
lhs -= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
double operator/(const timeval& lhs, const timeval& rhs) {
|
||||
double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 / rhs64;
|
||||
}
|
||||
|
||||
timeval& operator/=(timeval& lhs, double scalar) {
|
||||
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
product /= scalar;
|
||||
lhs.tv_sec = product / 1000000;
|
||||
lhs.tv_usec = product - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator/(timeval lhs, double scalar) {
|
||||
lhs /= scalar;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval& operator*=(timeval& lhs, double scalar) {
|
||||
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
product *= scalar;
|
||||
lhs.tv_sec = product / 1000000;
|
||||
lhs.tv_usec = product - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator*(timeval lhs, double scalar) {
|
||||
lhs *= scalar;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator*(double scalar, timeval rhs) {
|
||||
rhs *= scalar;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
bool operator==(const timeval& lhs, const timeval& rhs) {
|
||||
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 == rhs64;
|
||||
}
|
||||
bool operator!=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
bool operator<(const timeval& lhs, const timeval& rhs) {
|
||||
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 < rhs64;
|
||||
}
|
||||
bool operator>(const timeval& lhs, const timeval& rhs) {
|
||||
return operator<(rhs, lhs);
|
||||
}
|
||||
bool operator<=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator>(lhs, rhs);
|
||||
}
|
||||
bool operator>=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator<(lhs, rhs);
|
||||
}
|
||||
|
||||
double timevalOperations::toDouble(const timeval timeval) {
|
||||
double result = timeval.tv_sec * 1000000. + timeval.tv_usec;
|
||||
return result / 1000000.;
|
||||
}
|
||||
|
||||
timeval timevalOperations::toTimeval(const double seconds) {
|
||||
timeval tval;
|
||||
tval.tv_sec = seconds;
|
||||
tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6);
|
||||
return tval;
|
||||
}
|
||||
#include "timevalOperations.h"
|
||||
|
||||
timeval& operator+=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator+(timeval lhs, const timeval& rhs) {
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval& operator-=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum -= rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator-(timeval lhs, const timeval& rhs) {
|
||||
lhs -= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
double operator/(const timeval& lhs, const timeval& rhs) {
|
||||
double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 / rhs64;
|
||||
}
|
||||
|
||||
timeval& operator/=(timeval& lhs, double scalar) {
|
||||
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
product /= scalar;
|
||||
lhs.tv_sec = product / 1000000;
|
||||
lhs.tv_usec = product - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator/(timeval lhs, double scalar) {
|
||||
lhs /= scalar;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval& operator*=(timeval& lhs, double scalar) {
|
||||
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
product *= scalar;
|
||||
lhs.tv_sec = product / 1000000;
|
||||
lhs.tv_usec = product - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator*(timeval lhs, double scalar) {
|
||||
lhs *= scalar;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
timeval operator*(double scalar, timeval rhs) {
|
||||
rhs *= scalar;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
bool operator==(const timeval& lhs, const timeval& rhs) {
|
||||
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 == rhs64;
|
||||
}
|
||||
bool operator!=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
bool operator<(const timeval& lhs, const timeval& rhs) {
|
||||
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
return lhs64 < rhs64;
|
||||
}
|
||||
bool operator>(const timeval& lhs, const timeval& rhs) {
|
||||
return operator<(rhs, lhs);
|
||||
}
|
||||
bool operator<=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator>(lhs, rhs);
|
||||
}
|
||||
bool operator>=(const timeval& lhs, const timeval& rhs) {
|
||||
return !operator<(lhs, rhs);
|
||||
}
|
||||
|
||||
double timevalOperations::toDouble(const timeval timeval) {
|
||||
double result = timeval.tv_sec * 1000000. + timeval.tv_usec;
|
||||
return result / 1000000.;
|
||||
}
|
||||
|
||||
timeval timevalOperations::toTimeval(const double seconds) {
|
||||
timeval tval;
|
||||
tval.tv_sec = seconds;
|
||||
tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6);
|
||||
return tval;
|
||||
}
|
||||
|
Reference in New Issue
Block a user