Skip to content

Commit e826653

Browse files
committed
LTTO (Lazertag) protocol decoder
Decodes LTTO lazertag protocol. See wiki.lazerswarm.com for details on how to use.
1 parent 47aadf5 commit e826653

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

ir_LTTO.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
Written by rmick (www.bushandbeyond.com.au) Oct 2017
3+
4+
LTTO means Lazer Tag Team Ops. It is a brand of Lazertag that started life in 2004, from a toy dev company called 'Shoot The Moon'.
5+
It was was originally sold under the Tiger brand, then later under Nerf and Hasbro.
6+
7+
The range of taggers supported by this library includes;
8+
LTTO/Deluxe
9+
IRT-2X drone
10+
LTX/Phoenix
11+
TMB
12+
LTAR
13+
14+
The protocol uses a 38kHz carrier with a 1mS Mark and 2mS Space bits. The Header consists of a 3mS Mark, followed by a 3mS or 6mS Space.
15+
16+
This decoder would not have been possible without the help of many people, inlcuding Riley McArdle, TagFerret & Ryan Bales.
17+
18+
For more information on the protocol and how to use it, please visit
19+
20+
https://wiki.lazerswarm.com/wiki/Main_Page
21+
22+
or ask to join the Lazertag Modders group on Facebook.
23+
https://www.facebook.com/groups/LazerTagModders/
24+
*/
25+
26+
#include "IRremote.h"
27+
#include "IRremoteInt.h"
28+
29+
//==============================================================================
30+
// L TTTTT TTTTT OOO
31+
// L T T O O
32+
// L T T O O
33+
// L T T O O
34+
// LLLLL T T OOO
35+
//==============================================================================
36+
37+
#define BITS 32 // The number of bits in the command
38+
39+
#define HDR_MARK 3000 // The length of the Header:Mark
40+
#define HDR_SPACE 6000 // The length of the Header:Space
41+
#define TAG_SYNC 3000 // The lenght of the Sync signal for a Tag:Mark
42+
#define BEACON_SYNC 6000 // The length of the Sync signal for a Beacon:Mark
43+
44+
#define ZERO_BIT 1000 // The length of a Bit:Mark for 0's
45+
#define ONE_BIT 2000 // The length of a Bit:Mark for 1's
46+
#define BIT_SPACE 2000 // The length of a Bit:Space
47+
#define LONG_PAUSE 25000 // The length between packets.
48+
49+
//+=============================================================================
50+
//
51+
#if SEND_LTTO
52+
void IRsend::sendLTTO (unsigned long data, int nbits, bool beacon)
53+
{
54+
// Set IR carrier frequency
55+
enableIROut(38);
56+
57+
// Header
58+
mark (HDR_MARK); //PreSync
59+
space(HDR_SPACE); //PreSync Pause
60+
61+
//Sync
62+
if (beacon) mark(BEACON_SYNC);
63+
else mark(TAG_SYNC);
64+
65+
// Data
66+
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
67+
if (data & mask) {
68+
space(BIT_SPACE);
69+
mark (ONE_BIT);
70+
} else {
71+
space(BIT_SPACE);
72+
mark (ZERO_BIT);
73+
}
74+
}
75+
76+
// Footer
77+
space(LONG_PAUSE);
78+
space(0); // Always end with the LED off
79+
}
80+
#endif
81+
82+
//+=============================================================================
83+
//
84+
#if DECODE_LTTO
85+
bool IRrecv::decodeLTTO(decode_results *results)
86+
{
87+
unsigned long data = 0; // Somewhere to build our code
88+
int offset = 0; // The IF(_GAP) statement sets the Skip the Gap reading
89+
int headerSize = 2; // Number of bits for the header, altered by IF(_GAP) to 4
90+
int tagLength = 16;
91+
int beaconLength = 12;
92+
results->bits = 0;
93+
// Check initial Mark+Space match
94+
if (_GAP > 7000)
95+
{
96+
// The library default for _GAP is 5000, which means the 6000uS Space is seen as a new packet,
97+
// therefore the initial 3000uS Mark gets lost, so ignore it unless _GAP > 7000.
98+
headerSize = 4; // allow for the 2 extra bits in the packet.
99+
tagLength = 18; // allow for the 2 extra bits in the packet.
100+
beaconLength = 14; // allow for the 2 extra bits in the packet.
101+
offset++; // Skip the Gap reading
102+
if (!MATCH_MARK(results->rawbuf[offset++], HDR_MARK)) return false;
103+
}
104+
if (!MATCH_SPACE(results->rawbuf[offset++], HDR_SPACE)) return false ;
105+
106+
107+
// Check the Sync Type
108+
if (MATCH_MARK(results->rawbuf[offset], TAG_SYNC))
109+
{
110+
if (results->rawlen < tagLength) return false;
111+
results->address = 3000; //TYPE_LAZERTAG_TAG;
112+
}
113+
else if (MATCH_MARK(results->rawbuf[offset], BEACON_SYNC))
114+
{
115+
if (results->rawlen < beaconLength) return false;
116+
results->address = 6000; //TYPE_LAZERTAG_BEACON;
117+
}
118+
else return false;
119+
offset++;
120+
121+
// Read the bits in
122+
for (int i = 0; i < ((results->rawlen-headerSize)/2); i++)
123+
{
124+
// Each bit looks like: SPACE + MARK_1 -> 1
125+
// or : SPACE + MARK_0 -> 0
126+
127+
if (!MATCH_SPACE(results->rawbuf[offset++], BIT_SPACE)) return false;
128+
129+
// IR data is big-endian, so we shuffle it in from the right:
130+
if (MATCH_MARK(results->rawbuf[offset], ONE_BIT))
131+
{
132+
data = (data << 1) | 1;
133+
results->bits++;
134+
}
135+
else if (MATCH_MARK(results->rawbuf[offset], ZERO_BIT))
136+
{
137+
data = (data << 1) | 0;
138+
results->bits++;
139+
}
140+
offset++;
141+
}
142+
143+
// Success
144+
results->value = data;
145+
results->decode_type = LTTO;
146+
147+
//Serial.print("\n\nSuccess = LTTO");
148+
149+
return true;
150+
}
151+
#endif

0 commit comments

Comments
 (0)