mqtt-ir-remote/IRremoteESP8266/src/ir_Lasertag.cpp

125 lines
3.9 KiB
C++

// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
// LL AAA SSSSS EEEEEEE RRRRRR TTTTTTT AAA GGGG
// LL AAAAA SS EE RR RR TTT AAAAA GG GG
// LL AA AA SSSSS EEEEE RRRRRR TTT AA AA GG
// LL AAAAAAA SS EE RR RR TTT AAAAAAA GG GG
// LLLLLLL AA AA SSSSS EEEEEEE RR RR TTT AA AA GGGGGG
// Constants
#define MIN_LASERTAG_SAMPLES 13U
#define LASERTAG_TICK 333U
#define LASERTAG_MIN_GAP 100000UL // Completely made up amount.
#define LASERTAG_TOLERANCE 0U // Percentage error margin
#define LASERTAG_EXCESS 0U // See MARK_EXCESS
#define LASERTAG_DELTA 150U // Use instead of EXCESS and TOLERANCE.
const int16_t kSPACE = 1;
const int16_t kMARK = 0;
#if SEND_LASERTAG
// Send a Lasertag packet.
// This protocol is pretty much just raw Manchester encoding.
//
// Args:
// data: The message you wish to send.
// nbits: Bit size of the protocol you want to send.
// repeat: Nr. of extra times the data will be sent.
//
// Status: STABLE / Working.
//
void IRsend::sendLasertag(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (nbits > sizeof(data) * 8)
return; // We can't send something that big.
// Set 36kHz IR carrier frequency & a 1/4 (25%) duty cycle.
// NOTE: duty cycle is not confirmed. Just guessing based on RC5/6 protocols.
enableIROut(36, 25);
for (uint16_t i = 0; i <= repeat; i++) {
// Data
for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1)
if (data & mask) { // 1
space(LASERTAG_TICK); // 1 is space, then mark.
mark(LASERTAG_TICK);
} else { // 0
mark(LASERTAG_TICK); // 0 is mark, then space.
space(LASERTAG_TICK);
}
// Footer
space(LASERTAG_MIN_GAP);
}
}
#endif // SEND_LASERTAG
#if DECODE_LASERTAG
// Decode the supplied Lasertag message.
// This protocol is pretty much just raw Manchester encoding.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Appears to be working 90% of the time.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
// https://en.wikipedia.org/wiki/Manchester_code
bool IRrecv::decodeLasertag(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < MIN_LASERTAG_SAMPLES) return false;
// Compliance
if (strict && nbits != LASERTAG_BITS) return false;
uint16_t offset = OFFSET_START;
uint16_t used = 0;
uint64_t data = 0;
uint16_t actual_bits = 0;
// No Header
// Data
for (; offset <= results->rawlen; actual_bits++) {
int16_t levelA = getRClevel(results, &offset, &used, LASERTAG_TICK,
LASERTAG_TOLERANCE, LASERTAG_EXCESS,
LASERTAG_DELTA);
int16_t levelB = getRClevel(results, &offset, &used, LASERTAG_TICK,
LASERTAG_TOLERANCE, LASERTAG_EXCESS,
LASERTAG_DELTA);
if (levelA == kSPACE && levelB == kMARK) {
data = (data << 1) | 1; // 1
} else {
if (levelA == kMARK && levelB == kSPACE) {
data <<= 1; // 0
} else {
break;
}
}
}
// Footer (None)
// Compliance
if (actual_bits < nbits) return false; // Less data than we expected.
if (strict && actual_bits != LASERTAG_BITS) return false;
// Success
results->decode_type = LASERTAG;
results->value = data;
results->address = data & 0xF; // Unit
results->command = data >> 4; // Team
results->repeat = false;
results->bits = actual_bits;
return true;
}
#endif // DECODE_LASERTAG