RgbCctPacketFormatter.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <RgbCctPacketFormatter.h>
  2. #define V2_OFFSET(byte, key, jumpStart) ( \
  3. V2_OFFSETS[byte-1][key%4] \
  4. + \
  5. ((jumpStart > 0 && key >= jumpStart && key <= jumpStart+0x80) ? 0x80 : 0) \
  6. )
  7. uint8_t const RgbCctPacketFormatter::V2_OFFSETS[][4] = {
  8. { 0x45, 0x1F, 0x14, 0x5C },
  9. { 0xAB, 0x49, 0x63, 0x91 },
  10. { 0x2D, 0x1F, 0x4A, 0xEB },
  11. { 0xAF, 0x03, 0x1D, 0xF3 },
  12. { 0x5A, 0x22, 0x30, 0x11 },
  13. { 0x04, 0xD8, 0x71, 0x42 },
  14. { 0xAF, 0x04, 0xDD, 0x07 },
  15. { 0xE1, 0x93, 0xB8, 0xE4 }
  16. };
  17. uint8_t const RgbCctPacketFormatter::BYTE_JUMP_STARTS[] = {
  18. 0, // key byte doesn't get shifted
  19. 0x54, 0x54, 0x14, 0x54,
  20. 0, // argument byte gets different shifts for different commands
  21. 0x54, 0x54,
  22. 0 // checksum isn't shifted
  23. };
  24. uint8_t const RgbCctPacketFormatter::ARG_JUMP_STARTS[] = {
  25. 0, // no command with id = 0
  26. 0x14, // on
  27. 0x14, // color
  28. 0x14, // kelvin
  29. 0x54, // brightness, saturation
  30. 0x14 // mode
  31. };
  32. void RgbCctPacketFormatter::reset() {
  33. size_t packetPtr = 0;
  34. packet[packetPtr++] = 0x00;
  35. packet[packetPtr++] = 0x20;
  36. packet[packetPtr++] = deviceId >> 8;
  37. packet[packetPtr++] = deviceId & 0xFF;
  38. packet[packetPtr++] = 0;
  39. packet[packetPtr++] = 0;
  40. packet[packetPtr++] = sequenceNum++;
  41. packet[packetPtr++] = groupId;
  42. packet[packetPtr++] = 0;
  43. }
  44. void RgbCctPacketFormatter::command(uint8_t command, uint8_t arg) {
  45. packet[RGB_CCT_COMMAND_INDEX] = command;
  46. packet[RGB_CCT_ARGUMENT_INDEX] = arg;
  47. }
  48. void RgbCctPacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
  49. command(RGB_CCT_ON, 0xC0 + groupId + (status == OFF ? 5 : 0));
  50. }
  51. void RgbCctPacketFormatter::updateBrightness(uint8_t brightness) {
  52. command(RGB_CCT_BRIGHTNESS, 0x4F + brightness);
  53. }
  54. void RgbCctPacketFormatter::updateHue(uint16_t value) {
  55. const int16_t remappedColor = (value + 20) % 360;
  56. updateColorRaw(rescale(remappedColor, 255, 360));
  57. }
  58. void RgbCctPacketFormatter::updateColorRaw(uint8_t value) {
  59. command(RGB_CCT_COLOR, 0x15 + value);
  60. }
  61. void RgbCctPacketFormatter::updateTemperature(uint8_t value) {
  62. command(RGB_CCT_KELVIN, (0x4C + value)*2);
  63. }
  64. void RgbCctPacketFormatter::updateSaturation(uint8_t value) {
  65. command(RGB_CCT_SATURATION, value - 0x33);
  66. }
  67. void RgbCctPacketFormatter::updateColorWhite() {
  68. updateTemperature(0);
  69. }
  70. uint8_t* RgbCctPacketFormatter::buildPacket() {
  71. encodeV2Packet(packet);
  72. return packet;
  73. }
  74. uint8_t RgbCctPacketFormatter::xorKey(uint8_t key) {
  75. // Generate most significant nibble
  76. const uint8_t shift = (key & 0x0F) < 0x04 ? 0 : 1;
  77. const uint8_t x = (((key & 0xF0) >> 4) + shift + 6) % 8;
  78. const uint8_t msn = (((4 + x) ^ 1) & 0x0F) << 4;
  79. // Generate least significant nibble
  80. const uint8_t lsn = ((((key & 0xF) + 4)^2) & 0x0F);
  81. return ( msn | lsn );
  82. }
  83. uint8_t RgbCctPacketFormatter::decodeByte(uint8_t byte, uint8_t s1, uint8_t xorKey, uint8_t s2) {
  84. uint8_t value = byte - s2;
  85. value = value ^ xorKey;
  86. value = value - s1;
  87. return value;
  88. }
  89. uint8_t RgbCctPacketFormatter::encodeByte(uint8_t byte, uint8_t s1, uint8_t xorKey, uint8_t s2) {
  90. uint8_t value = (byte + s1) % 0x100;
  91. value = value ^ xorKey;
  92. value = (value + s2) % 0x100;
  93. return value;
  94. }
  95. void RgbCctPacketFormatter::decodeV2Packet(uint8_t *packet) {
  96. uint8_t key = xorKey(packet[0]);
  97. for (size_t i = 1; i <= 8; i++) {
  98. if (i != 5) {
  99. packet[i] = decodeByte(packet[i], 0, key, V2_OFFSET(i, packet[0], BYTE_JUMP_STARTS[i]));
  100. }
  101. }
  102. packet[5] = decodeByte(packet[5], 0, key, V2_OFFSET(5, packet[0], ARG_JUMP_STARTS[packet[4]]));
  103. }
  104. void RgbCctPacketFormatter::encodeV2Packet(uint8_t *packet) {
  105. uint8_t key = xorKey(packet[0]);
  106. uint8_t sum = key;
  107. uint8_t command = packet[4];
  108. size_t ptr = 0;
  109. for (size_t i = 1; i <= 7; i++) {
  110. sum += packet[i];
  111. if (i != 5) {
  112. packet[i] = encodeByte(packet[i], 0, key, V2_OFFSET(i, packet[0], BYTE_JUMP_STARTS[i]));
  113. }
  114. }
  115. packet[5] = encodeByte(packet[5], 0, key, V2_OFFSET(5, packet[0], ARG_JUMP_STARTS[command]));
  116. packet[8] = encodeByte(sum, 2, key, V2_OFFSET(8, packet[0], 0));
  117. }
  118. void RgbCctPacketFormatter::format(uint8_t const* packet, char* buffer) {
  119. buffer += sprintf(buffer, "Raw packet: ");
  120. for (int i = 0; i < packetLength; i++) {
  121. buffer += sprintf(buffer, "%02X ", packet[i]);
  122. }
  123. uint8_t decodedPacket[packetLength];
  124. memcpy(decodedPacket, packet, packetLength);
  125. decodeV2Packet(decodedPacket);
  126. buffer += sprintf(buffer, "\n\nDecoded:\n");
  127. buffer += sprintf(buffer, "Key : %02X\n", decodedPacket[0]);
  128. buffer += sprintf(buffer, "b1 : %02X\n", decodedPacket[1]);
  129. buffer += sprintf(buffer, "ID : %02X%02X\n", decodedPacket[2], decodedPacket[3]);
  130. buffer += sprintf(buffer, "Command : %02X\n", decodedPacket[4]);
  131. buffer += sprintf(buffer, "Argument : %02X\n", decodedPacket[5]);
  132. buffer += sprintf(buffer, "Sequence : %02X\n", decodedPacket[6]);
  133. buffer += sprintf(buffer, "Group : %02X\n", decodedPacket[7]);
  134. buffer += sprintf(buffer, "Checksum : %02X", decodedPacket[8]);
  135. }