RgbCctPacketFormatter.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include <RgbCctPacketFormatter.h>
  2. #define V2_OFFSET(byte, key, jumpStart) ( \
  3. pgm_read_byte(&V2_OFFSETS[byte-1][key%4]) \
  4. + \
  5. ((jumpStart > 0 && key >= jumpStart && key <= jumpStart+0x80) ? 0x80 : 0) \
  6. )
  7. #define GROUP_COMMAND_ARG(status, groupId) ( groupId + (status == OFF ? 5 : 0) )
  8. uint8_t const RgbCctPacketFormatter::V2_OFFSETS[][4] = {
  9. { 0x45, 0x1F, 0x14, 0x5C }, // request type
  10. { 0x2B, 0xC9, 0xE3, 0x11 }, // id 1
  11. { 0x6D, 0x5F, 0x8A, 0x2B }, // id 2
  12. { 0xAF, 0x03, 0x1D, 0xF3 }, // command
  13. { 0x1A, 0xE2, 0xF0, 0xD1 }, // argument
  14. { 0x04, 0xD8, 0x71, 0x42 }, // sequence
  15. { 0xAF, 0x04, 0xDD, 0x07 }, // group
  16. { 0x61, 0x13, 0x38, 0x64 } // checksum
  17. };
  18. void RgbCctPacketFormatter::initializePacket(uint8_t* packet) {
  19. size_t packetPtr = 0;
  20. // Always encode with 0x00 key. No utility in varying it.
  21. packet[packetPtr++] = 0x00;
  22. packet[packetPtr++] = 0x20;
  23. packet[packetPtr++] = deviceId >> 8;
  24. packet[packetPtr++] = deviceId & 0xFF;
  25. packet[packetPtr++] = 0;
  26. packet[packetPtr++] = 0;
  27. packet[packetPtr++] = sequenceNum++;
  28. packet[packetPtr++] = groupId;
  29. packet[packetPtr++] = 0;
  30. }
  31. void RgbCctPacketFormatter::unpair() {
  32. for (size_t i = 0; i < 5; i++) {
  33. updateStatus(ON, 0);
  34. }
  35. }
  36. void RgbCctPacketFormatter::command(uint8_t command, uint8_t arg) {
  37. pushPacket();
  38. if (held) {
  39. command |= 0x80;
  40. }
  41. currentPacket[RGB_CCT_COMMAND_INDEX] = command;
  42. currentPacket[RGB_CCT_ARGUMENT_INDEX] = arg;
  43. }
  44. void RgbCctPacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
  45. command(RGB_CCT_ON, GROUP_COMMAND_ARG(status, groupId));
  46. }
  47. void RgbCctPacketFormatter::modeSpeedDown() {
  48. command(RGB_CCT_ON, RGB_CCT_MODE_SPEED_DOWN);
  49. }
  50. void RgbCctPacketFormatter::modeSpeedUp() {
  51. command(RGB_CCT_ON, RGB_CCT_MODE_SPEED_UP);
  52. }
  53. void RgbCctPacketFormatter::updateMode(uint8_t mode) {
  54. lastMode = mode;
  55. command(RGB_CCT_MODE, mode);
  56. }
  57. void RgbCctPacketFormatter::nextMode() {
  58. updateMode((lastMode+1)%RGB_CCT_NUM_MODES);
  59. }
  60. void RgbCctPacketFormatter::previousMode() {
  61. updateMode((lastMode-1)%RGB_CCT_NUM_MODES);
  62. }
  63. void RgbCctPacketFormatter::updateBrightness(uint8_t brightness) {
  64. command(RGB_CCT_BRIGHTNESS, 0x8F + brightness);
  65. }
  66. void RgbCctPacketFormatter::updateHue(uint16_t value) {
  67. uint8_t remapped = rescale(value, 255, 360);
  68. updateColorRaw(remapped);
  69. }
  70. void RgbCctPacketFormatter::updateColorRaw(uint8_t value) {
  71. command(RGB_CCT_COLOR, 0x5F + value);
  72. }
  73. void RgbCctPacketFormatter::updateTemperature(uint8_t value) {
  74. command(RGB_CCT_KELVIN, 0x94 - (value*2));
  75. }
  76. void RgbCctPacketFormatter::updateSaturation(uint8_t value) {
  77. uint8_t remapped = value + 0xD;
  78. command(RGB_CCT_SATURATION, remapped);
  79. }
  80. void RgbCctPacketFormatter::updateColorWhite() {
  81. updateTemperature(0);
  82. }
  83. void RgbCctPacketFormatter::enableNightMode() {
  84. uint8_t arg = GROUP_COMMAND_ARG(OFF, groupId);
  85. command(RGB_CCT_ON | 0x80, arg);
  86. }
  87. void RgbCctPacketFormatter::finalizePacket(uint8_t* packet) {
  88. encodeV2Packet(packet);
  89. }
  90. uint8_t RgbCctPacketFormatter::xorKey(uint8_t key) {
  91. // Generate most significant nibble
  92. const uint8_t shift = (key & 0x0F) < 0x04 ? 0 : 1;
  93. const uint8_t x = (((key & 0xF0) >> 4) + shift + 6) % 8;
  94. const uint8_t msn = (((4 + x) ^ 1) & 0x0F) << 4;
  95. // Generate least significant nibble
  96. const uint8_t lsn = ((((key & 0xF) + 4)^2) & 0x0F);
  97. return ( msn | lsn );
  98. }
  99. uint8_t RgbCctPacketFormatter::decodeByte(uint8_t byte, uint8_t s1, uint8_t xorKey, uint8_t s2) {
  100. uint8_t value = byte - s2;
  101. value = value ^ xorKey;
  102. value = value - s1;
  103. return value;
  104. }
  105. uint8_t RgbCctPacketFormatter::encodeByte(uint8_t byte, uint8_t s1, uint8_t xorKey, uint8_t s2) {
  106. uint8_t value = byte + s1;
  107. value = value ^ xorKey;
  108. value = value + s2;
  109. return value;
  110. }
  111. void RgbCctPacketFormatter::decodeV2Packet(uint8_t *packet) {
  112. uint8_t key = xorKey(packet[0]);
  113. for (size_t i = 1; i <= 8; i++) {
  114. packet[i] = decodeByte(packet[i], 0, key, V2_OFFSET(i, packet[0], V2_OFFSET_JUMP_START));
  115. }
  116. }
  117. void RgbCctPacketFormatter::encodeV2Packet(uint8_t *packet) {
  118. uint8_t key = xorKey(packet[0]);
  119. uint8_t sum = key;
  120. for (size_t i = 1; i <= 7; i++) {
  121. sum += packet[i];
  122. packet[i] = encodeByte(packet[i], 0, key, V2_OFFSET(i, packet[0], V2_OFFSET_JUMP_START));
  123. }
  124. packet[8] = encodeByte(sum, 2, key, V2_OFFSET(8, packet[0], 0));
  125. }
  126. void RgbCctPacketFormatter::format(uint8_t const* packet, char* buffer) {
  127. buffer += sprintf_P(buffer, PSTR("Raw packet: "));
  128. for (int i = 0; i < packetLength; i++) {
  129. buffer += sprintf_P(buffer, PSTR("%02X "), packet[i]);
  130. }
  131. uint8_t decodedPacket[packetLength];
  132. memcpy(decodedPacket, packet, packetLength);
  133. decodeV2Packet(decodedPacket);
  134. buffer += sprintf_P(buffer, PSTR("\n\nDecoded:\n"));
  135. buffer += sprintf_P(buffer, PSTR("Key : %02X\n"), decodedPacket[0]);
  136. buffer += sprintf_P(buffer, PSTR("b1 : %02X\n"), decodedPacket[1]);
  137. buffer += sprintf_P(buffer, PSTR("ID : %02X%02X\n"), decodedPacket[2], decodedPacket[3]);
  138. buffer += sprintf_P(buffer, PSTR("Command : %02X\n"), decodedPacket[4]);
  139. buffer += sprintf_P(buffer, PSTR("Argument : %02X\n"), decodedPacket[5]);
  140. buffer += sprintf_P(buffer, PSTR("Sequence : %02X\n"), decodedPacket[6]);
  141. buffer += sprintf_P(buffer, PSTR("Group : %02X\n"), decodedPacket[7]);
  142. buffer += sprintf_P(buffer, PSTR("Checksum : %02X"), decodedPacket[8]);
  143. }