libicsneo/communication/packet/i2cpacket.cpp

83 lines
3.9 KiB
C++

#include "icsneo/communication/packet/i2cpacket.h"
namespace icsneo
{
std::shared_ptr<Message> HardwareI2CPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream)
{
auto msg = std::make_shared<I2CMessage>();
const I2CHeader* packet = reinterpret_cast<const I2CHeader*>(bytestream.data());
const size_t numPayloadBytes = packet->length;
const size_t numControlBytes = packet->CoreMiniBitsI2C.CBLen;
const size_t numDataBytes = numPayloadBytes - numControlBytes;
if( (numPayloadBytes == 0) || (numDataBytes > I2CMaxLength) ||
(sizeof(I2CHeader) != (bytestream.size() - numPayloadBytes)) )
{ return nullptr; }
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->address = (packet->CoreMiniBitsI2C.ID & 0x3FFu);
msg->deviceMode = static_cast<I2CMessage::DeviceMode>(packet->CoreMiniBitsI2C.CT);
msg->direction = static_cast<I2CMessage::Direction>(packet->CoreMiniBitsI2C.DIR);
msg->isExtendedID = static_cast<bool>(packet->CoreMiniBitsI2C.EID & 0x01u);
msg->isTXMsg = static_cast<bool>(packet->CoreMiniBitsI2C.TXMsg & 0x01u);
msg->txTimeout = static_cast<bool>(packet->CoreMiniBitsI2C.TXTimeout & 0x01u);
msg->txNack = static_cast<bool>(packet->CoreMiniBitsI2C.TXNack & 0x01u);
msg->txAborted = static_cast<bool>(packet->CoreMiniBitsI2C.TXAborted & 0x01u);
msg->txLostArb = static_cast<bool>(packet->CoreMiniBitsI2C.TXLostArb & 0x01u);
msg->txError = static_cast<bool>(packet->CoreMiniBitsI2C.TXError & 0x01u);
//We don't care about 0xTRB0Dx in this case...
//copy 0xTRB0STAT even though we likely won't use it either
msg->stats = packet->stats;
msg->timestamp = (packet->timestamp & (0x7FFFFFFFFFFFFFFFull));
//The device will combine the 'control' bytes and data bytes into one payload
//The control bytes will always come before the data
auto cbStart = bytestream.begin() + sizeof(I2CHeader);
auto dataStart = cbStart + numControlBytes;
std::copy(cbStart, dataStart, std::back_inserter(msg->controlBytes));
std::copy(dataStart, bytestream.end(), std::back_inserter(msg->dataBytes));
return msg;
}
bool HardwareI2CPacket::EncodeFromMessage(const I2CMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t numControlBytes = message.controlBytes.size();
const size_t numDataBytes = message.dataBytes.size();
if(I2CMaxLength < numDataBytes)
{
report(APIEvent::Type::I2CMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
if(message.controlBytes.empty() || message.dataBytes.empty())
{
//You'll need to provide a target R/W register in controlBytes
//alternatively, you're expecting to read without providing a dataBytes payload
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
bytestream.push_back(static_cast<uint8_t>(numControlBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numControlBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(numDataBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numDataBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>((message.stats) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(message.stats & 0xFFu));
if(message.isExtendedID)
{
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(((message.address) >> 8) & 0x03u) | 0x04u);
} else {
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(0x00u));
}
if(I2CMessage::Direction::Read == message.direction)
{ bytestream.back() |= static_cast<uint8_t>(0x10u); }
std::copy(message.controlBytes.begin(), message.controlBytes.end(), std::back_inserter(bytestream));
std::copy(message.dataBytes.begin(), message.dataBytes.end(), std::back_inserter(bytestream));
return true;
}
}