161 lines
5.2 KiB
C++
161 lines
5.2 KiB
C++
// Copyright 2013 mpflaga
|
|
// Copyright 2015 kitlaan
|
|
// Copyright 2017 Jason kendall, David Conran
|
|
|
|
#include "ir_Magiquest.h"
|
|
#include <algorithm>
|
|
#include "IRrecv.h"
|
|
#include "IRsend.h"
|
|
#include "IRutils.h"
|
|
|
|
#define IS_ZERO(m, s) (((m) * 100 / ((m) + (s))) <= MAGIQUEST_ZERO_RATIO)
|
|
#define IS_ONE(m, s) (((m) * 100 / ((m) + (s))) >= MAGIQUEST_ONE_RATIO)
|
|
|
|
// Strips taken from:
|
|
// https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp
|
|
// and
|
|
// https://github.com/mpflaga/Arduino-IRremote
|
|
|
|
// Source: https://github.com/mpflaga/Arduino-IRremote
|
|
|
|
#if SEND_MAGIQUEST
|
|
// Send a MagiQuest formatted message.
|
|
//
|
|
// Args:
|
|
// data: The contents of the message you want to send.
|
|
// nbits: The bit size of the message being sent.
|
|
// Typically MAGIQUEST_BITS.
|
|
// repeat: The number of times you want the message to be repeated.
|
|
//
|
|
// Status: Alpha / Should be working.
|
|
//
|
|
void IRsend::sendMagiQuest(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
|
sendGeneric(0, 0, // No Headers - Technically it's included in the data.
|
|
// i.e. 8 zeros.
|
|
MAGIQUEST_MARK_ONE, MAGIQUEST_SPACE_ONE,
|
|
MAGIQUEST_MARK_ZERO, MAGIQUEST_SPACE_ZERO,
|
|
0, // No footer mark.
|
|
MAGIQUEST_GAP,
|
|
data, nbits, 36, true, repeat, 50);
|
|
}
|
|
|
|
// Encode a MagiQuest wand_id, and a magnitude into a single 64bit value.
|
|
// (Only 48 bits of real data + 8 leading zero bits)
|
|
// This is suitable for calling sendMagiQuest() with.
|
|
// e.g. sendMagiQuest(encodeMagiQuest(wand_id, magnitude));
|
|
uint64_t IRsend::encodeMagiQuest(uint32_t wand_id, uint16_t magnitude) {
|
|
uint64_t result = 0;
|
|
result = wand_id;
|
|
result <<= 16;
|
|
result |= magnitude;
|
|
// Shouldn't be needed, but ensure top 8/16 bit are zero.
|
|
result &= 0xFFFFFFFFFFFFULL;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
// Source: https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp
|
|
|
|
#if DECODE_MAGIQUEST
|
|
// Decode the supplied MagiQuest message.
|
|
// MagiQuest protocol appears to be a header of 8 'zero' bits, followed
|
|
// by 32 bits of "wand ID" and finally 16 bits of "magnitude".
|
|
// Even though we describe this protocol as 56 bits, it really only has
|
|
// 48 bits of data that matter.
|
|
//
|
|
// In transmission order, 8 zeros + 32 wand_id + 16 magnitude.
|
|
//
|
|
// Args:
|
|
// results: Ptr to the data to decode and where to store the decode result.
|
|
// nbits: Nr. of bits to expect in the data portion, inc. the 8 bit header.
|
|
// Typically MAGIQUEST_BITS.
|
|
// strict: Flag to indicate if we strictly adhere to the specification.
|
|
// Returns:
|
|
// boolean: True if it can decode it, false if it can't.
|
|
//
|
|
// Status: Alpha / Should work.
|
|
//
|
|
// Ref:
|
|
// https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp
|
|
bool IRrecv::decodeMagiQuest(decode_results *results, uint16_t nbits,
|
|
bool strict) {
|
|
uint16_t bits = 0;
|
|
uint64_t data = 0;
|
|
uint16_t offset = OFFSET_START;
|
|
|
|
if (results->rawlen < (2 * MAGIQUEST_BITS)) {
|
|
DPRINT("Not enough bits to be Magiquest - Rawlen: ");
|
|
DPRINT(results->rawlen);
|
|
DPRINT(" Expected: ");
|
|
DPRINTLN((2 * MAGIQUEST_BITS));
|
|
return false;
|
|
}
|
|
|
|
// Compliance
|
|
if (strict && nbits != MAGIQUEST_BITS) return false;
|
|
|
|
// Of six wands as datapoints, so far they all start with 8 ZEROs.
|
|
// For example, here is the data from two wands
|
|
// 00000000 00100011 01001100 00100110 00000010 00000010 00010111
|
|
// 00000000 00100000 10001000 00110001 00000010 00000010 10110100
|
|
|
|
// Decode the (MARK + SPACE) bits
|
|
while (offset + 1 < results->rawlen && bits < nbits - 1) {
|
|
uint16_t mark = results->rawbuf[offset];
|
|
uint16_t space = results->rawbuf[offset + 1];
|
|
if (!matchMark(mark + space, MAGIQUEST_TOTAL_USEC)) {
|
|
DPRINT("Not enough time to be Magiquest - Mark: ");
|
|
DPRINT(mark);
|
|
DPRINT(" Space: ");
|
|
DPRINT(space);
|
|
DPRINT(" Total: ");
|
|
DPRINT(mark+space);
|
|
DPRINT("Expected: ");
|
|
DPRINTLN(MAGIQUEST_TOTAL_USEC);
|
|
return false;
|
|
}
|
|
|
|
if (IS_ZERO(mark, space)) data = (data << 1) | 0;
|
|
else if (IS_ONE( mark, space)) data = (data << 1) | 1;
|
|
else return false;
|
|
|
|
bits++;
|
|
offset += 2;
|
|
|
|
// Compliance
|
|
// The first 8 bits of this protocol are supposed to all be 0.
|
|
// Exit out early as it is never going to match.
|
|
if (strict && bits == 8 && data != 0) return false;
|
|
}
|
|
|
|
// Last bit is special as the protocol ends with a SPACE, not a MARK.
|
|
// Grab the last MARK bit, assuming a good SPACE after it
|
|
if (offset < results->rawlen) {
|
|
uint16_t mark = results->rawbuf[offset];
|
|
uint16_t space = (MAGIQUEST_TOTAL_USEC / RAWTICK) - mark;
|
|
|
|
if (IS_ZERO(mark, space)) data = (data << 1) | 0;
|
|
else if (IS_ONE( mark, space)) data = (data << 1) | 1;
|
|
else return false;
|
|
|
|
bits++;
|
|
}
|
|
|
|
if (bits != nbits) return false;
|
|
|
|
if (strict) {
|
|
// The top 8 bits of the 56 bits needs to be 0x00 to be valid.
|
|
// i.e. bits 56 to 49 are all zero.
|
|
if ((data >> (nbits - 8)) != 0) return false;
|
|
}
|
|
|
|
// Success
|
|
results->decode_type = MAGIQUEST;
|
|
results->bits = bits;
|
|
results->value = data;
|
|
results->address = data >> 16; // Wand ID
|
|
results->command = data & 0xFFFF; // Magnitude
|
|
return true;
|
|
}
|
|
#endif
|