// =================================================================================================
// eModbus: Copyright 2020, 2021 by Michael Harwerth, Bert Melis and the contributors to eModbus
// MIT license - see license.md for details
// =================================================================================================
#include "CoilData.h"
#undef LOCAL_LOG_LEVEL
#include "Logging.h"
// Constructor: optional size in bits, optional initial value for all bits
// Maximum size is 2000 coils (=250 bytes)
CoilData::CoilData(uint16_t size, bool initValue) :
CDsize(0),
CDbyteSize(0),
CDbuffer(nullptr) {
// Limit the size to 2000 (Modbus rules)
if (size > 2000) size = 2000;
// Do we have a size?
if (size) {
// Calculate number of bytes needed
CDbyteSize = byteIndex(size - 1) + 1;
// Allocate and init buffer
CDbuffer = new uint8_t[CDbyteSize];
memset(CDbuffer, initValue ? 0xFF : 0, CDbyteSize);
if (initValue) {
CDbuffer[CDbyteSize - 1] &= CDfilter[bitIndex(size - 1)];
}
CDsize = size;
}
}
// Alternate constructor, taking a "1101..." bit image char array to init
CoilData::CoilData(const char *initVector) :
CDsize(0),
CDbyteSize(0),
CDbuffer(nullptr) {
// Init with bit image array.
setVector(initVector);
}
// Destructor: take care of cleaning up
CoilData::~CoilData() {
if (CDbuffer) {
delete CDbuffer;
}
}
// Assignment operator
CoilData& CoilData::operator=(const CoilData& m) {
// Avoid self-assignment
if (this == &m) return *this;
// Remove old data
if (CDbuffer) {
delete CDbuffer;
}
// Are coils in source?
if (m.CDsize > 0) {
// Yes. Allocate new buffer and copy data
CDbuffer = new uint8_t[m.CDbyteSize];
memcpy(CDbuffer, m.CDbuffer, m.CDbyteSize);
CDsize = m.CDsize;
CDbyteSize = m.CDbyteSize;
} else {
// No, leave buffer empty
CDsize = 0;
CDbyteSize = 0;
CDbuffer = nullptr;
}
return *this;
}
// Copy constructor
CoilData::CoilData(const CoilData& m) :
CDsize(0),
CDbyteSize(0),
CDbuffer(nullptr) {
// Has the source coils at all?
if (m.CDsize > 0) {
// Yes. Allocate new buffer and copy data
CDbuffer = new uint8_t[m.CDbyteSize];
memcpy(CDbuffer, m.CDbuffer, m.CDbyteSize);
CDsize = m.CDsize;
CDbyteSize = m.CDbyteSize;
}
}
#ifndef NO_MOVE
// Move constructor
CoilData::CoilData(CoilData&& m) {
// Copy all data
CDbuffer = m.CDbuffer;
CDsize = m.CDsize;
CDbyteSize = m.CDbyteSize;
// Then clear source
m.CDbuffer = nullptr;
m.CDsize = 0;
m.CDbyteSize = 0;
}
// Move assignment
CoilData& CoilData::operator=(CoilData&& m) {
// Remove buffer, if already allocated
if (CDbuffer) {
delete CDbuffer;
}
// Are there coils in the source at all?
if (m.CDsize > 0) {
// Yes. Copy over all data
CDbuffer = m.CDbuffer;
CDsize = m.CDsize;
CDbyteSize = m.CDbyteSize;
// Then clear source
m.CDbuffer = nullptr;
m.CDsize = 0;
m.CDbyteSize = 0;
} else {
// No, leave object empty.
CDbuffer = nullptr;
CDsize = 0;
CDbyteSize = 0;
}
return *this;
}
#endif
// Comparison operators
bool CoilData::operator==(const CoilData& m) {
// Self-compare is always true
if (this == &m) return true;
// Different sizes are never equal
if (CDsize != m.CDsize) return false;
// Compare the data
if (CDsize > 0 && memcmp(CDbuffer, m.CDbuffer, CDbyteSize)) return false;
return true;
}
// Inequality: invert the result of the equality comparison
bool CoilData::operator!=(const CoilData& m) {
return !(*this == m);
}
// Assignment of a bit image char array to re-init
CoilData& CoilData::operator=(const char *initVector) {
// setVector() may be unsuccessful - then data is deleted!
setVector(initVector);
return *this;
}
// If used as vector, return a complete slice
CoilData::operator vector const () {
// Create new vector to return
vector retval;
if (CDsize > 0) {
// Copy over all buffer content
retval.assign(CDbuffer, CDbuffer + CDbyteSize);
}
// return the copy (or an empty vector)
return retval;
}
// slice: return a CoilData object with coils shifted leftmost
// will return empty object if illegal parameters are detected
CoilData CoilData::slice(uint16_t start, uint16_t length) {
CoilData retval;
// Any slice of an empty coilset is an empty coilset ;)
if (CDsize == 0) return retval;
// If start is beyond the available coils, return empty slice
if (start > CDsize) return retval;
// length default is all up to the end
if (length == 0) length = CDsize - start;
// Does the requested slice fit in the buffer?
if ((start + length)