Wowwee Light Strike Laser Tag Hacking/Creating your own device

Hi,

i am currently in the process to create my own Light Strike Toy Gun with an Arduino.

Here you can find more information from the manufacturer:

Basically it is a cheap Laser Tag System for up to four groups of people with a few accessories to make the game more interesting. It is really fun to play, but the toy guns are for kids and therefore they are too small for adult hands (and a Star Trek Phaser version would look really cool :wink: ).

The system is working with cheap ir leds and ir receivers.

I found a few posts and some source code from people who hacked that system about two years ago. Sadly some people didn't get the source code running from those sites as these sources rely on a customised irremote library (also from two years ago).

My current progress is that i can submit ir codes to trigger a hit on another toy gun/target with a specific weapon and team id. However my code is triggered via the serial connection from the pc. I really struggle with button debouncing and casualness (e.g. pulse a led while executing the ir submission code or getting a hit while fireing).

The intention for this post is to get the people who try to create their own toy gun or try to expand the system with additional devices together and solve common problems.

My code is based on the research from these two sites:
http://www.meatandnetworking.com/projects/hacking-at-the-light-strike-laser-tag-game/

So basically i didn't do anything great. Those people did the difficulty research and implemented the first version.

I think both sketches rely on an old verion of the irremote library. I modified the current version, so you don't have to use a two year old library.

I will upload the library in the next days (after i had a look at their licence). Also i will upload a few pictures of my prototype gun and my own sourcecode.

I hope that someone is interested in this, so i'll sty motivated :).

Cheers

FYI: IRLib is a more modern re-write of IRremote & has lots more features.

Did you check out the "miles tag" forum via google, lots of good info there.

Wow thank you, i wasn't aware that there is a new IR Lib available. It looks like it should be easy to adapt the send code from IRRemote to IRLib.

Also i didn't found the miles tag forum with google (propably because i searched explicitly for light strike).

Thanks for the information.

2nd result

Oh sorry, i think that was a misunderstanding. I meant i didn't found the miles tag forum as i was searching for a light strike hack. But thanks anyway for the link.

Hi regnets,

i did some reversal on the lightstrike protocol. the links you mentioned aren’t that good now, but are a good start. we (some students from germany) are creating a wiki for our project: building an arduino based lightstrike jacket (which will show the remaining life, etc)

the current state is, all signals coming from the assault strikers are completely reverse engineered. its 31/32 bits.
a raspberry pi is currently working as infrared receiver/sender and can interact with the guns through lirc.

we can use send signals of the ITS and other components like the enemy scanner :wink:

We’ll start our wiki within 2-3 days, if you like to join us that would be great!

https://lightstrike.is-awesome.com is the (currently blank) page.

Hi,

i did also some work :).

Currently my plan is to create a system based on this site:

Additional i want be compatible to light strike and miles tag, so that i can play with my weapons in different system.

I want to create the same receiver as you can see at the linked website.

However the guy from the website isn’t responding, so we can’t use his code.

Here is my example code for using the irlib to send the ir signals:

include <IRLib.h>

IRsend blaster;

//const String teamName[]       = { "Blue", "Red", "Yellow", "Green" };
const unsigned long teamCode[]  = { 0x07000000, 0x04000000, 0x05000000, 0x06000000 };

/*
const String weaponName[] = {"  P.Laser", "P.Stealth", "  P.Pulse", "  P.Sonic",
                            "     Bomb", "    Medic", "  R.Laser", "R.Stealth",
                            "  R.Pulse", "   R.Rail", "  R.Sonic", "   Sentry",
                            "    Optic", "Refractor", "AutoStrik", " Launcher",
                            " TimeBomb", "Trip-Mine"
                           };
*/
const unsigned int weaponCode[] = {     0x0102,     0x0202,     0x0303,     0x0406,
                                       0x0E18,     0x0800,     0x0502,     0x0602,
                                       0x0703,     0x0806,     0x0908,     0x0F08,
                                       0x0A0C,     0x0B12,     0x0C03,     0x0D06,
                                       0x0E18,     0x0E18
                                 };
                                 

void setup() {

}

void loop() {
 delay(2000);
 sendLightStrike(teamCode[0] + weaponCode[0]);

}

void sendLightStrike(unsigned long data) {
 #define LIGHT_STRIKE_DATA_LENGTH    32
 #define LIGHT_STRIKE_HEADER_MARK  6750
 #define LIGHT_STRIKE_HEADER_SPACE    0
 #define LIGHT_STRIKE_MARK_ONE      900
 #define LIGHT_STRIKE_MARK_ZERO     900
 #define LIGHT_STRIKE_SPACE_ONE    3700
 #define LIGHT_STRIKE_SPACE_ZERO    900
 #define LIGHT_STRIKE_KHZ            38
 #define LIGHT_STRIKE_USE_STOP     true
 #define LIGHT_STRIKE_MAX_EXTENT      0
 
 blaster.sendGeneric(data, 
                     LIGHT_STRIKE_DATA_LENGTH, 
                     LIGHT_STRIKE_HEADER_MARK, 
                     LIGHT_STRIKE_HEADER_SPACE, 
                     LIGHT_STRIKE_MARK_ONE, 
                     LIGHT_STRIKE_MARK_ZERO, 
                     LIGHT_STRIKE_SPACE_ONE, 
                     LIGHT_STRIKE_SPACE_ZERO, 
                     LIGHT_STRIKE_KHZ, 
                     LIGHT_STRIKE_USE_STOP, 
                     LIGHT_STRIKE_MAX_EXTENT);
}

However i can’t receive any data with a TSOP31238 and irlib… i always get the result 0.

The receiver seems to work, i can get a dump of the ir signal.

I tried the following code:

#include <IRLib.h>

IRrecv My_Receiver(2);

IRdecode My_Decoder;

void setup()
{
 Serial.begin(9600);
 My_Receiver.enableIRIn();
}

void loop() {
#define LIGHT_STRIKE_DATA_LENGTH    32
#define LIGHT_STRIKE_HEADER_MARK  6750
#define LIGHT_STRIKE_HEADER_SPACE    0
#define LIGHT_STRIKE_MARK_ONE      900
#define LIGHT_STRIKE_MARK_ZERO     900
#define LIGHT_STRIKE_SPACE_ONE    3700
#define LIGHT_STRIKE_SPACE_ZERO    900

 if (My_Receiver.GetResults(&My_Decoder)) {
   My_Decoder.decodeGeneric(LIGHT_STRIKE_DATA_LENGTH, LIGHT_STRIKE_HEADER_MARK, LIGHT_STRIKE_HEADER_SPACE, LIGHT_STRIKE_MARK_ONE, LIGHT_STRIKE_MARK_ZERO, LIGHT_STRIKE_SPACE_ONE, LIGHT_STRIKE_SPACE_ZERO);
   Serial.println(My_Decoder.value);

   My_Receiver.resume();
 }
}

OK, i found an error in my program, i suspected that the raw count length is the same as the bit length. That assumption were wrong. I changed the raw length from 32 to 66 however i still get no result.

Then i added some debugging code to the generic decode method in the irlib.cpp file.

Now i see that there is an error with the DATA_SPACE at offset but i don’t understand why.

I will attach the arduino code and the changed irlib function, maybe someone can give me a clue whats going on. Also i’ll add the dump results.

Arduino Code

#include <IRLib.h>

IRrecv My_Receiver(2);

IRdecode My_Decoder;

void setup()
{
  Serial.begin(9600);
  My_Receiver.enableIRIn();
}

void loop() {
#define LIGHT_STRIKE_RAW_LENGTH     66
#define LIGHT_STRIKE_HEADER_MARK  6750
#define LIGHT_STRIKE_HEADER_SPACE    0  
#define LIGHT_STRIKE_MARK_ONE      900
#define LIGHT_STRIKE_MARK_ZERO     900
#define LIGHT_STRIKE_SPACE_ONE    3700
#define LIGHT_STRIKE_SPACE_ZERO    900


  if (My_Receiver.GetResults(&My_Decoder)) {
    My_Decoder.decodeGeneric(LIGHT_STRIKE_RAW_LENGTH, LIGHT_STRIKE_HEADER_MARK, LIGHT_STRIKE_HEADER_SPACE, LIGHT_STRIKE_MARK_ONE, LIGHT_STRIKE_MARK_ZERO, LIGHT_STRIKE_SPACE_ONE, LIGHT_STRIKE_SPACE_ZERO);
    My_Decoder.DumpResults();
    Serial.print("Decoder Result: ");
    Serial.println(My_Decoder.value);
    My_Receiver.resume();
  }
}

IRLib DecodeGeneric Function

bool IRdecodeBase::decodeGeneric(unsigned char Raw_Count, unsigned int Head_Mark, unsigned int Head_Space, 
                                 unsigned int Mark_One, unsigned int Mark_Zero, unsigned int Space_One, unsigned int Space_Zero) {
// If raw samples count or head mark are zero then don't perform these tests.
// Some protocols need to do custom header work.
  unsigned long data = 0;  unsigned char Max; offset=1;
  if (Raw_Count) {
     if (rawlen != Raw_Count) {
       Serial.println(rawlen);
       Serial.println("RAW_COUNT_ERROR");
       return RAW_COUNT_ERROR;
      }
  }
  if(!IgnoreHeader) {
    if (Head_Mark) {
	     if (!MATCH(rawbuf[offset],Head_Mark)) {
        Serial.println(rawbuf[offset]);
        Serial.println(offset);
        Serial.println("HEADER_MARK_ERROR");
        return HEADER_MARK_ERROR(Head_Mark);
       }
	  }
  }
  offset++;
  if (Head_Space) {
    if (!MATCH(rawbuf[offset],Head_Space))  {
        Serial.println(rawbuf[offset]);
        Serial.println(offset);
        Serial.println("HEADER_SPACE_ERROR");
        return HEADER_SPACE_ERROR(Head_Space);
    }
  }

  if (Mark_One) {//Length of a mark indicates data "0" or "1". Space_Zero is ignored.
    offset=2;//skip initial gap plus header Mark.
    Max=rawlen;
    while (offset < Max) {
      if (!MATCH(rawbuf[offset], Space_One))  {
        Serial.println(rawbuf[offset]);
        Serial.println(offset);
        Serial.println("DATA_SPACE_ERROR");
        return DATA_SPACE_ERROR(Space_One);
      }
      offset++;
      if (MATCH(rawbuf[offset], Mark_One)) {
        data = (data << 1) | 1;
      } 
      else if (MATCH(rawbuf[offset], Mark_Zero)) {
        data <<= 1;
      } 
      else return DATA_MARK_ERROR(Mark_Zero);
      offset++;
    }
    bits = (offset - 1) / 2;
  }
  else {//Mark_One was 0 therefore length of a space indicates data "0" or "1".
    Max=rawlen-1; //ignore stop bit
    offset=3;//skip initial gap plus two header items
    while (offset < Max) {
      if (!MATCH (rawbuf[offset],Mark_Zero)) {
        Serial.println(rawbuf[offset]);
        Serial.println(offset);
        Serial.println("DATA_MARK_ERROR");
        return DATA_MARK_ERROR(Mark_Zero);
      } 
      offset++;
      if (MATCH(rawbuf[offset],Space_One)) {
        data = (data << 1) | 1;
      } 
      else if (MATCH (rawbuf[offset],Space_Zero)) {
        data <<= 1;
      } 
      else {
        Serial.println(rawbuf[offset]);
        Serial.println(offset);
        Serial.println("DATA_SPACE_ERROR");
        return DATA_SPACE_ERROR(Space_Zero);
      } 
      offset++;
    }
    bits = (offset - 1) / 2 -1;//didn't encode stop bit
  }
  // Success
  value = data;
  return true;
}

IR DumpResults/Output

900
2
DATA_SPACE_ERROR
Decoded Unknown(0): Value:0 (0 bits)
Raw samples(66): Gap:52784
  Head: m6600  s900
0:m800 s900	1:m750 s900		 2:m750 s900	3:m800 s900		 
4:m750 s3400	5:m800 s3350		 6:m800 s3400	7:m750 s900		 
8:m800 s900	9:m750 s900		 10:m750 s900	11:m750 s950		 
12:m750 s900	13:m750 s900		 14:m800 s900	15:m750 s900		 

16:m800 s900	17:m750 s900		 18:m800 s850	19:m800 s900		 
20:m750 s3400	21:m750 s900		 22:m800 s3400	23:m750 s900		 
24:m800 s900	25:m750 s900		 26:m800 s850	27:m800 s900		 
28:m750 s900	29:m800 s3350		 30:m800 s900	31:m750
Extent=75000
Mark  min:750	 max:800
Space min:850	 max:3400

Decoder Result: 0

OK, i found a working decoder for the Light Strike IR Commands, but i don’t get the difference between the working code and the generic function with the correct parms.

long IRrecv::decodeLS(decode_results *results) {
  long data = 0;
  /*if (irparams.rawlen < 2 * SONY_BITS + 2) {
    return ERR;
  }*/
  int offset = 1; // Skip first space
  // Initial mark
  if (!MATCH_MARK(results->rawbuf[offset], LS_HDR_MARK)) {
    return ERR;
  }
  offset++;

  // Initial space  
  if (!MATCH_SPACE(results->rawbuf[offset], LS_HDR_SPACE)) {
    return ERR;
  }
  offset++;
  for (int i = 0; i < 31; i++) {
    if (!MATCH_MARK(results->rawbuf[offset], LS_BIT_MARK)) {
      Serial.println("Err");
      return ERR;
    }
    offset++;
    if (MATCH_SPACE(results->rawbuf[offset], LS_ONE_SPACE)) {
      data = (data << 1) | 1;
    } 
    else if (MATCH_SPACE(results->rawbuf[offset], LS_ZERO_SPACE)) {
      data <<= 1;
    } 
    else {
      Serial.print("Err: ");
      Serial.println(i);

      return ERR;
    }
    offset++;
  }

  // Success
  results->bits = (offset - 1) / 2;
  /*if (results->bits < 12) {
    results->bits = 0;
    return ERR;
  }*/
  results->value = data;
  results->decode_type = LS;
  return DECODED;
}

The code is from this github repository:
https://github.com/LightStrikePlusPlus/LightStrikeDecode/blob/master/IRremote/IRremote.cpp

Could please someone enlighten me?

OK, i found my mistake. I should have read the manual of the decodeGeneric function :).

I just needed to set the mark_one parameter to zero, so that the decodeGeneric method would use the else branch of the method.

I find this really counter intuitive, but cyborg5 won’t accept currently pull request for his irlib library.

So i created a irlib ‚Äúlite‚ÄĚ version which only consists of the decodeGeneric and sendGeneric function (the decodeGeneric function now accepts for mark_one the correct value. This saves me about 500 Byte ram and i don‚Äôt need the function for tv remote control.

Here is my current code base:

#include <IRLib.h>

#define LIGHT_STRIKE_DATA_LENGTH    32
#define LIGHT_STRIKE_RAW_LENGTH     66
#define LIGHT_STRIKE_HEADER_MARK  6750
#define LIGHT_STRIKE_HEADER_SPACE  900
#define LIGHT_STRIKE_MARK_ONE      900
#define LIGHT_STRIKE_MARK_ZERO     900
#define LIGHT_STRIKE_SPACE_ONE    3700
#define LIGHT_STRIKE_SPACE_ZERO    900
#define LIGHT_STRIKE_KHZ            38
#define LIGHT_STRIKE_USE_STOP     true
#define LIGHT_STRIKE_MAX_EXTENT      0

IRrecv receiver(2);
IRsend transmitter;
IRdecodeBase decoder;

const unsigned int teamCode[4] PROGMEM = {
  0x0700, //Blue
  0x0400, //Red
  0x0500, //Yellow
  0x0600  //Green
};

const unsigned int weaponCode[16] PROGMEM = {
  0x0102, //Pistol Laserstrike
  0x0202, //Pistol Stealthstrike
  0x0303, //Pistol Pulsestrike
  0x0406, //Pistol Sonicstrike
  0x0502, //Rifle Laserstrike
  0x0602, //Rifle Stealthstrike
  0x0703, //Rifle Pulsestrike
  0x0806, //Rifle Railstrike
  0x0908, //Rifle Sonicstrike
  0x0E18, //Bomb
  0x0A0C, //Optic
  0x0F08, //Sentry
  0x0B12, //Refractor
  0x0C03, //Auto Strike
  0x0D06, //Launcher
  0x0800  //Medic
};

const int weaponDamage[16] PROGMEM = {
  -10,  //Pistol Laserstrike
  -10,  //Pistol Stealthstrike
  -15,  //Pistol Pulsestrike
  -40,  //Pistol Sonicstrike
  -10,  //Rifle Laserstrike
  -10,  //Rifle Stealthstrike
  -15,  //Rifle Pulsestrike
  -30,  //Rifle Railstrike
  -40,  //Rifle Sonicstrike
  -120, //Bomb
  -60,  //Optic
  -40,  //Sentry
  -60,  //Refractor
  -15,  //Auto Strike
  -30,  //Launcher
  +40   //Medic
};

unsigned int myTeam = 0;
unsigned int myWeapon = 0;
unsigned long lastShot = 0;
const byte maxLife = 120;
byte currentLife = 120;

void setup() {
  receiver.enableIRIn();
  Serial.begin(9600);
  Serial.println(F("Ready"));
}

void loop() {
  if (currentLife > 0) {
    if (receiver.GetResults(&decoder)) {
      decoder.decodeGeneric(LIGHT_STRIKE_RAW_LENGTH, LIGHT_STRIKE_HEADER_MARK, LIGHT_STRIKE_HEADER_SPACE, LIGHT_STRIKE_MARK_ONE, LIGHT_STRIKE_MARK_ZERO, LIGHT_STRIKE_SPACE_ONE, LIGHT_STRIKE_SPACE_ZERO);
      lastShot = decoder.value;
      receiver.resume();
    }

    if (lastShot != 0) {
      displayShotMessage(lastShot);
      currentLife = currentLife - getWeaponDamage(getWeaponFromShot(lastShot));
      lastShot = 0;
    }
  }
}

String displayShotMessage(long shot) {
  Serial.print(F("Hit by Team "));
  Serial.print(getTeamName(getTeamFromShot(lastShot)));
  Serial.print(F(" with a "));
  Serial.print(getWeaponName(getWeaponFromShot(lastShot)));
  Serial.println(F("."));
}

void shot(int teamCode, int weaponCode) {
  transmitter.sendGeneric(teamCode + weaponCode,
                          LIGHT_STRIKE_DATA_LENGTH,
                          LIGHT_STRIKE_HEADER_MARK,
                          LIGHT_STRIKE_HEADER_SPACE,
                          LIGHT_STRIKE_MARK_ONE,
                          LIGHT_STRIKE_MARK_ZERO,
                          LIGHT_STRIKE_SPACE_ONE,
                          LIGHT_STRIKE_SPACE_ZERO,
                          LIGHT_STRIKE_KHZ,
                          LIGHT_STRIKE_USE_STOP,
                          LIGHT_STRIKE_MAX_EXTENT);
}

String getTeamName(unsigned int code) {
  switch (code) {
    case 0x0700:
      return F("Blue");
    case 0x0400:
      return F("Red");
    case 0x0500:
      return F("Yellow");
    case 0x0600:
      return F("Green");
  }
}

byte getWeaponDamage(unsigned int code) {
  for (byte i = 0; i < 16; i++) {
    if (code == weaponCode[i]) {
      return weaponDamage[i];
    }
  }
}

String getWeaponName(unsigned int code) {
  switch (code) {
    case 0x0102:
      return F("Pistol Laserstrike");
    case 0x0202:
      return F("Pistol Stealthstrike");
    case 0x0303:
      return F("Pistol Pulsestrike");
    case 0x0406:
      return F("Pistol Sonicstrike");
    case 0x0502:
      return F("Rifle Laserstrike");
    case 0x0602:
      return F("Rifle Stealthstrike");
    case 0x0703:
      return F("Rifle Pulsestrike");
    case 0x0806:
      return F("Rifle Railstrike");
    case 0x0908:
      return F("Rifle Sonicstrike");
    case 0x0E18:
      return F("Bomb");
    case 0x0A0C:
      return F("Optic");
    case 0x0F08:
      return F("Sentry");
    case 0x0B12:
      return F("Refractor");
    case 0x0C03:
      return F("Auto Strike");
    case 0x0D06:
      return F("Launcher");
    case 0x0800:
      return F("Medic");
  }
}

unsigned int getTeamFromShot(long shotValue) {
  return shotValue >> 16;
}

unsigned int getWeaponFromShot(long shotValue) {
  return shotValue;
}

If someone would like to get the strip down version of irlib, i glady share it, but ther is no option to attach something to my post.

here is a fully working lightstrike implementation for an arduino. It uses a non-manipulated IRremote library and is capable of receiving and sending lightstrike signals.
I identified the bits for teamcolor, weapon and damage in an earlier project and built a new game mode:

the targed lights up in the color of the team which did most damage. once a team made 96 damage it receives one heal impulse (like the ITS).

Have fun:

#include <IRremote.h>

int RECV_PIN = 4; //Infrared receiver connected

IRrecv irrecv(RECV_PIN); 

IRsend irsend; // Default Pin is 3 for IR sender

decode_results results;
// the ls_array is used to generate a infrared packet
unsigned int ls_array[33] = {0};

// just a team damage counter
unsigned int team_damange[8] = {0};


void setup()
{
  Serial.begin(9600);
  pinMode(9, OUTPUT); //BLUE LED connected
  pinMode(8, OUTPUT); //GREEN LED connected
  pinMode(7, OUTPUT); //RED LED connected


  // Start with a light show like the lightstrike target
  //RED
  setLightOn(4);
  delay(250);

  //YELLOW
  setLightOn(5);
  delay(250);

  //GREEN
  setLightOn(6);
  delay(250);

  //BLUE
  setLightOn(7);
  delay(250);

  //OFF
  setLightOff();


  irrecv.enableIRIn(); // Start the receiver

}

void loop() {
  if (irrecv.decode(&results)) {
    rawdump2ls_array(&results, ls_array);

    int team = getColorValue(ls_array);
    //Serial.println(getDamageValue(ls_array));
    //Serial.println(getWeaponValue(ls_array));

    if (team != 0) {
      team_damange[team] += getDamageValue(ls_array);
      setLightOff();
      delay(40);
      setLightOn(team);

      // Heal the team which first reached 96 Damage 
      // capture the flag ;)
      //
      for (int i = 4; i < 8; i++) {
        if (team_damange[i] >= 96) {
          setLightOff();
          delay(100);
          for(int j = 0; j <= 4; j++) {
            setLightOn(8);
            delay(1000);
            setLightOff();
            delay(250);
          }
          doLSheal(i);
          resetDamage();
        }
      }
    }

    delay(80);
    for (int i = 4; i < 8; i++) {
      Serial.print("Team ");
      Serial.print(i);
      Serial.print(": ");
      Serial.println(team_damange[i]);
    }
    


    irrecv.resume();
  }

  int bestTeam = 0;
  for (int i = 4; i < 8; i++) {
    if (team_damange[i] > team_damange[bestTeam]) {
      bestTeam = i;
    }
  }
  // Light up with the leading team color
  setLightOn(bestTeam);
  
}
void resetDamage() {
  for (int i = 4; i < 8; i++) {
    team_damange[i] = 0;
  }
}

void setLightOff() {
  digitalWrite(9, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(7, HIGH);
}

void doLSheal(int team) {
  doLSshot(8, 8, team);
}

void doLSshot(int team, int weapon, int damage) {
  //signed int raw[66] = {6700,           128,    , 64 ,    , 32 ,    , 16 ,    , 8  ,    , 4   ,    , 2  ,    , 1  ,    , 128,    , 64 ,    , 32 ,    , 16 ,    , 8  ,    , 4  ,    , 2  ,    , 1  , 128,    , 64 ,    , 32 ,    , 16 ,    , 8  ,    , 4  ,   , 2   ,    , 1 , 128,    , 64 ,    , 32 ,    , 16 ,    ,  8 ,    , 4  ,    , 2  ,    , 1   ,
  //signed int raw[66] = {   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,   11,  12,  13,  14  15  16   17   18   19   20    21   22   23   24   25   26   27   28   29   30   31   32   33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48   49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64
  unsigned int raw[66] = {6700, 800, 850, 850, 800, 850, 800, 850, 850, 800, 850, 850, 800, 850, 800, 850, 850, 850, 800, 850, 800, 850, 850, 850, 800, 850, 800, 850, 850, 800, 850, 850, 800, 850, 800, 850, 850, 850, 800, 850, 800, 850, 850, 850, 800, 850, 800, 3350, 850, 800, 850, 850, 800, 850, 800, 850, 850, 850, 800, 850, 800, 850, 850, 850, 800};

  int value = 16;
  for (int i = 4; i <= 8; i++) {
    if (team - value >= 0) {
      raw[(i * 2) - 1] = 3350;
      team -= value;
    }
    value = value / 2;
  }

  value = 16;
  for (int i = 20; i <= 24; i++) {
    if (weapon - value >= 0) {
      raw[(i * 2) - 1] = 3350;
      weapon -= value;
    }
    value = value / 2;
  }

  value = 16;
  for (int i = 28; i <= 32; i++) {
    if (damage - value >= 0) {
      raw[(i * 2) - 1] = 3350;
      damage -= value;
    }
    value = value / 2;
  }

  irsend.enableIROut(38);
  irsend.sendRaw(raw, 66, 32);
  irrecv.enableIRIn();
}

void setLightOn(int color) {
  if (color == 7) {
    //BLUE
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
  } else if (color == 6) {
    //GREEN
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
  } else if (color == 5) {
    //YELLOW
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
  } else if (color == 4) {
    //RED
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
  } else if (color == 8) {
    //MAGENTA
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
  }

}

int getColorValue(unsigned int ls_array[]) {
  return getLSValue(ls_array, 8, 6);
}

int getDamageValue(unsigned int ls_array[]) {
  return getLSValue(ls_array, 32, 28);
}

int getWeaponValue(unsigned int ls_array[]) {
  return getLSValue(ls_array, 24, 20);
}

int getLSValue(unsigned int ls_array[], int maxBit, int minBit) {
  int val = 0;
  int loopcount = 1;
  for (int i = maxBit; i >= minBit; i--) {
    val += ls_array[i] * loopcount;
    loopcount = loopcount * 2;
  }
  return val;
}

void rawdump2ls_array(decode_results *results, unsigned int ls_array[]) {
  int count = results->rawlen;

  if (count == 66) {
    for (int i = 0; i < count; i++) {
      if ((i % 2) == 0) {
        if ((int)results->rawbuf[i]*USECPERTICK > 3000) {
          ls_array[i / 2] = 1;
        } else {
          ls_array[i / 2] = 0;
        }
      }
    }
  }
}

im using this code on an arduino pro mini inside the target and added an ir led :wink:

k3mp

Hi k3mp,

Could you please tell me, how you identified the team color and the other stuff?

Thanks a lot.

Regards ardutob

Tried a PM, but thought I’d ask here - Regnets, any chance you could send me your updated IRLib file? I’ve been working on replicating the lesser functions (sound, etc.) for the LightStrike gear, and your code has formed a bit part of the base of what I’m working on. I appreciate any help!

Hi Hedningen,

i think you are already following me on github.

In the meantime i did a lot of work on the code and on the hardware.

Currently i am able to send and receive signals, display various information about your current gun on an 128x64 Oled I2C Display and flash some led as well as an laser diode.

Also there is a fritzing diagramm, some pictures, and a lot of information will follow.

At the moment i am working on sound output. How do you get some sound out of the arduino for cheap?

Here is the github repository for the laser tag sketch:

And here you can find the modified IRLib

Here is a picture of the screen, while the gun is turned on:

Cheers

regnets

First prototype is ready!

Added Pictures and current source code.

@regnets,

Amazing work.
I would like to do the same and have lots of problems with IRLib, too. Maybe you can help me ?

The wiring should be correct. I can send signals with the Panasonic_Old format and they are received and decoded correctly. Why Panasonic_Old ? Because my receiver needs 56kHz and that is the only built-in format with that frequency.

That being said I would like to create my own protocol. Which means using sendGeneric.

I created a lot of definitions for Marks and Spaces, read the IRLib code (for example Space_One=Head_Space for signals with Mark_One != 0 ).

Then I tried sending some data:
I'm sending only two bits. My tests include the values 2 (10) and 3 (11).
On the receiver side I can see that the protocol was transmitted correctly.
The receiver dumps have correct marks and spaces.
For a 3, which is two 1 bits, there are two marks of length Mark_One.
For a 2, which has the bits 1 and 0, there is a mark of length Mark_One and Mark_Zero.

Nevertheless the decoder is unable to create a value for the input.
I don't know why but decodeGeneric always returns false. And the value of the decoder stays 0.

I started searching on the internet and found your project. Amazing !

Your system is very impressive and you seem to have overcome the difficulties of IRLib.

In your code you have the following lines:

decoder.decodeGeneric(LIGHT_STRIKE_RAW_LENGTH, 
			 					  LIGHT_STRIKE_HEADER_MARK, 
							      LIGHT_STRIKE_HEADER_SPACE,
								  //For use with IRLib-Light 
								  //LIGHT_STRIKE_MARK_ZERO, 
								  //For use with Standard IRLib
								  0, 
								  LIGHT_STRIKE_MARK_ZERO, 
								  LIGHT_STRIKE_SPACE_ONE, 
								  LIGHT_STRIKE_SPACE_ZERO);

I'm afraid I don't understand this.
Since on the sending side, you are transmitting with LIGHT_STRIKE_MARK_ONE which is not zero.
You are passing different configurations to send and receive. And that fixes the behaviour of IRLib ?

Could you please explain this ?
Did you change other parts of the library or did you just remove the boilerplate code ?

I tried changing my code and passed 0 as MARK_ONE on the decoder side, too. But that didn't do anything.

I could install your IRLIB-light version, but before I do that I would like to understand what is happening.

Hi mintwurm,

thanks a lot.

You should be able to use any protocol. The khz just have to be same frequency on the sender and receiver site.

I tried to explain why you have to pass a zero for MARK_ZERO in the decodeGeneric method on github (see github.com).

However i can't remember it very well, it is too long ago, in the meantime there were just too many other issues and projects :D.

I didn't change a lot in the IRLib. I just removed every proprietary protocol so that the lib would be a bit smaller. For this project i need every byte on the arduino.

Currently there is a newer version of this sketch available on my local git repository however it is not working as intended (i got issues with the trigger and i am trying to get some audio out of the arduino).

If you got any other question, i will be happy to get you an answer.

Cheers

regnets