esp32_ethernet_milight_hub/lib/MiLight/V2PacketFormatter.cpp

144 lines
4.3 KiB
C++

#include <V2PacketFormatter.h>
#include <V2RFEncoding.h>
#define GROUP_COMMAND_ARG(status, groupId, numGroups) ( groupId + (status == OFF ? (numGroups + 1) : 0) )
V2PacketFormatter::V2PacketFormatter(const MiLightRemoteType deviceType, uint8_t protocolId, uint8_t numGroups)
: PacketFormatter(deviceType, 9),
protocolId(protocolId),
numGroups(numGroups)
{ }
bool V2PacketFormatter::canHandle(const uint8_t *packet, const size_t packetLen) {
uint8_t packetCopy[V2_PACKET_LEN];
memcpy(packetCopy, packet, V2_PACKET_LEN);
V2RFEncoding::decodeV2Packet(packetCopy);
#ifdef DEBUG_PRINTF
Serial.printf_P(PSTR("Testing whether formater for ID %d can handle packet: with protocol ID %d...\n"), protocolId, packetCopy[V2_PROTOCOL_ID_INDEX]);
#endif
return packetCopy[V2_PROTOCOL_ID_INDEX] == protocolId;
}
void V2PacketFormatter::initializePacket(uint8_t* packet) {
size_t packetPtr = 0;
// Always encode with 0x00 key. No utility in varying it.
packet[packetPtr++] = 0x00;
packet[packetPtr++] = protocolId;
packet[packetPtr++] = deviceId >> 8;
packet[packetPtr++] = deviceId & 0xFF;
packet[packetPtr++] = 0;
packet[packetPtr++] = 0;
packet[packetPtr++] = sequenceNum++;
packet[packetPtr++] = groupId;
packet[packetPtr++] = 0;
}
void V2PacketFormatter::command(uint8_t command, uint8_t arg) {
pushPacket();
if (held) {
command |= 0x80;
}
currentPacket[V2_COMMAND_INDEX] = command;
currentPacket[V2_ARGUMENT_INDEX] = arg;
}
void V2PacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
command(0x01, GROUP_COMMAND_ARG(status, groupId, numGroups));
}
void V2PacketFormatter::unpair() {
for (size_t i = 0; i < 5; i++) {
updateStatus(ON, 0);
}
}
void V2PacketFormatter::finalizePacket(uint8_t* packet) {
V2RFEncoding::encodeV2Packet(packet);
}
void V2PacketFormatter::format(uint8_t const* packet, char* buffer) {
buffer += sprintf_P(buffer, PSTR("Raw packet: "));
for (size_t i = 0; i < packetLength; i++) {
buffer += sprintf_P(buffer, PSTR("%02X "), packet[i]);
}
uint8_t decodedPacket[packetLength];
memcpy(decodedPacket, packet, packetLength);
V2RFEncoding::decodeV2Packet(decodedPacket);
buffer += sprintf_P(buffer, PSTR("\n\nDecoded:\n"));
buffer += sprintf_P(buffer, PSTR("Key : %02X\n"), decodedPacket[0]);
buffer += sprintf_P(buffer, PSTR("b1 : %02X\n"), decodedPacket[1]);
buffer += sprintf_P(buffer, PSTR("ID : %02X%02X\n"), decodedPacket[2], decodedPacket[3]);
buffer += sprintf_P(buffer, PSTR("Command : %02X\n"), decodedPacket[4]);
buffer += sprintf_P(buffer, PSTR("Argument : %02X\n"), decodedPacket[5]);
buffer += sprintf_P(buffer, PSTR("Sequence : %02X\n"), decodedPacket[6]);
buffer += sprintf_P(buffer, PSTR("Group : %02X\n"), decodedPacket[7]);
buffer += sprintf_P(buffer, PSTR("Checksum : %02X"), decodedPacket[8]);
}
uint8_t V2PacketFormatter::groupCommandArg(MiLightStatus status, uint8_t groupId) {
return GROUP_COMMAND_ARG(status, groupId, numGroups);
}
// helper method to return a bulb to the prior state
void V2PacketFormatter::switchMode(const GroupState& currentState, BulbMode desiredMode) {
// revert back to the prior mode
switch (desiredMode) {
case BulbMode::BULB_MODE_COLOR:
updateHue(currentState.getHue());
break;
case BulbMode::BULB_MODE_NIGHT:
enableNightMode();
break;
case BulbMode::BULB_MODE_SCENE:
updateMode(currentState.getMode());
break;
case BulbMode::BULB_MODE_WHITE:
updateColorWhite();
break;
default:
Serial.printf_P(PSTR("V2PacketFormatter::switchMode: Request to switch to unknown mode %d\n"), desiredMode);
break;
}
}
uint8_t V2PacketFormatter::tov2scale(uint8_t value, uint8_t endValue, uint8_t interval, bool reverse) {
if (reverse) {
value = 100 - value;
}
return (value * interval) + endValue;
}
uint8_t V2PacketFormatter::fromv2scale(uint8_t value, uint8_t endValue, uint8_t interval, bool reverse, uint8_t buffer) {
value -= endValue;
// Deal with underflow
if (value >= (0xFF - buffer)) {
value = 0;
}
value /= interval;
if (reverse) {
value = 100 - value;
}
if (value > 100) {
// overflow
if (value <= (100 + buffer)) {
value = 100;
// underflow (value is unsigned)
} else {
value = 0;
}
}
return value;
}