|
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