|
7 | 7 | /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/621
|
8 | 8 | /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
|
9 | 9 | /// @see http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
|
| 10 | +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1538 (Checksum) |
10 | 11 |
|
11 | 12 | #include "ir_Samsung.h"
|
12 | 13 | #include <algorithm>
|
@@ -290,46 +291,61 @@ void IRSamsungAc::stateReset(const bool forcepower, const bool initialPower) {
|
290 | 291 | /// Set up hardware to be able to send a message.
|
291 | 292 | void IRSamsungAc::begin(void) { _irsend.begin(); }
|
292 | 293 |
|
293 |
| -/// Calculate the checksum for a given state. |
294 |
| -/// @param[in] state The array to calc the checksum of. |
295 |
| -/// @param[in] length The length/size of the array. |
| 294 | +/// Get the existing checksum for a given state section. |
| 295 | +/// @param[in] section The array to extract the checksum from. |
| 296 | +/// @return The existing checksum value. |
| 297 | +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1538#issuecomment-894645947 |
| 298 | +uint8_t IRSamsungAc::getSectionChecksum(const uint8_t *section) { |
| 299 | + return ((GETBITS8(*(section + 2), kLowNibble, kNibbleSize) << kNibbleSize) + |
| 300 | + GETBITS8(*(section + 1), kHighNibble, kNibbleSize)); |
| 301 | +} |
| 302 | + |
| 303 | +/// Calculate the checksum for a given state section. |
| 304 | +/// @param[in] section The array to calc the checksum of. |
296 | 305 | /// @return The calculated checksum value.
|
297 |
| -uint8_t IRSamsungAc::calcChecksum(const uint8_t state[], |
298 |
| - const uint16_t length) { |
| 306 | +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1538#issuecomment-894645947 |
| 307 | +uint8_t IRSamsungAc::calcSectionChecksum(const uint8_t *section) { |
299 | 308 | uint8_t sum = 0;
|
300 |
| - // Safety check so we don't go outside the array. |
301 |
| - if (length < 7) return 255; |
302 |
| - // Shamelessly inspired by: |
303 |
| - // https://github.com/adafruit/Raw-IR-decoder-for-Arduino/pull/3/files |
304 |
| - // Count most of the '1' bits after the checksum location. |
305 |
| - sum += countBits(state[length - 7], 8); |
306 |
| - sum -= countBits(GETBITS8(state[length - 6], kLowNibble, kNibbleSize), 8); |
307 |
| - sum += countBits(GETBITS8(state[length - 5], 1, 7), 8); |
308 |
| - sum += countBits(state + length - 4, 3); |
309 |
| - return GETBITS8(28 - sum, kLowNibble, kNibbleSize); |
| 309 | + |
| 310 | + sum += countBits(*section, 8); // Include the entire first byte |
| 311 | + // The lower half of the second byte. |
| 312 | + sum += countBits(GETBITS8(*(section + 1), kLowNibble, kNibbleSize), 8); |
| 313 | + // The upper half of the third byte. |
| 314 | + sum += countBits(GETBITS8(*(section + 2), kHighNibble, kNibbleSize), 8); |
| 315 | + // The next 4 bytes. |
| 316 | + sum += countBits(section + 3, 4); |
| 317 | + // Bitwise invert the result. |
| 318 | + return sum ^ UINT8_MAX; |
310 | 319 | }
|
311 | 320 |
|
312 | 321 | /// Verify the checksum is valid for a given state.
|
313 | 322 | /// @param[in] state The array to verify the checksum of.
|
314 | 323 | /// @param[in] length The length/size of the array.
|
315 | 324 | /// @return true, if the state has a valid checksum. Otherwise, false.
|
316 | 325 | bool IRSamsungAc::validChecksum(const uint8_t state[], const uint16_t length) {
|
317 |
| - if (length < kSamsungAcStateLength) |
318 |
| - return true; // No checksum to compare with. Assume okay. |
319 |
| - uint8_t offset = 0; |
320 |
| - if (length >= kSamsungAcExtendedStateLength) offset = 7; |
321 |
| - return (GETBITS8(state[length - 6], kHighNibble, kNibbleSize) == |
322 |
| - IRSamsungAc::calcChecksum(state, length)) && |
323 |
| - (GETBITS8(state[length - (13 + offset)], kHighNibble, kNibbleSize) == |
324 |
| - IRSamsungAc::calcChecksum(state, length - (7 + offset))); |
| 326 | + bool result = true; |
| 327 | + const uint16_t maxlength = |
| 328 | + (length > kSamsungAcExtendedStateLength) ? kSamsungAcExtendedStateLength |
| 329 | + : length; |
| 330 | + for (uint16_t offset = 0; |
| 331 | + offset + kSamsungAcSectionLength <= maxlength; |
| 332 | + offset += kSamsungAcSectionLength) |
| 333 | + result &= (getSectionChecksum(state + offset) == |
| 334 | + calcSectionChecksum(state + offset)); |
| 335 | + return result; |
325 | 336 | }
|
326 | 337 |
|
327 | 338 | /// Update the checksum for the internal state.
|
328 |
| -/// @param[in] length The length/size of the internal array to checksum. |
329 |
| -void IRSamsungAc::checksum(uint16_t length) { |
330 |
| - if (length < 13) return; |
331 |
| - _.Sum2 = calcChecksum(_.raw, length); |
332 |
| - _.Sum1 = calcChecksum(_.raw, length - 7); |
| 339 | +void IRSamsungAc::checksum(void) { |
| 340 | + uint8_t sectionsum = calcSectionChecksum(_.raw); |
| 341 | + _.Sum1Upper = GETBITS8(sectionsum, kHighNibble, kNibbleSize); |
| 342 | + _.Sum1Lower = GETBITS8(sectionsum, kLowNibble, kNibbleSize); |
| 343 | + sectionsum = calcSectionChecksum(_.raw + kSamsungAcSectionLength); |
| 344 | + _.Sum2Upper = GETBITS8(sectionsum, kHighNibble, kNibbleSize); |
| 345 | + _.Sum2Lower = GETBITS8(sectionsum, kLowNibble, kNibbleSize); |
| 346 | + sectionsum = calcSectionChecksum(_.raw + kSamsungAcSectionLength * 2); |
| 347 | + _.Sum3Upper = GETBITS8(sectionsum, kHighNibble, kNibbleSize); |
| 348 | + _.Sum3Lower = GETBITS8(sectionsum, kLowNibble, kNibbleSize); |
333 | 349 | }
|
334 | 350 |
|
335 | 351 | #if SEND_SAMSUNG_AC
|
|
0 commit comments