Snippets

Simon Johnson MilesTag Gamebox V3 Simulator for Arduino

Created by Simon Johnson last modified
/*
 * MilesTag Gamebox V3 Simulator 
 * 
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * An IR LED must be connected to the output PWM pin 3.
 * A push button with pull-up resistor must be connected to the input BUTTON_PIN; 
 * this is the send button.
 * A visible LED can be connected to STATUS_PIN to provide status.
 *
 * The logic is:
 * On startup, retrieve the stored IR code value from the EEPROM.
 * If the button is pressed, send the IR code.
 * If an IR code is received, record it and save it to the EEPROM.
 *
 * Version 0.0.1 December, 2016
 * By Simon Johnson
 * http://redcrowdigital.com
 */

#include <IRremote.h>
#include <EEPROM.h>

int RECV_PIN = 5;
int BUTTON_PIN = 12;
int STATUS_PIN = 8;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

// Declare some globals to store our IR codes
unsigned long codesAmmo[16][2];
unsigned long codesMedic[16][2];
unsigned long codesFlag[16][2];
unsigned long codesHazard[16][2];
unsigned long codesTeamRespawn1[4][2];
unsigned long codesTeamRespawn2[4][2];
unsigned long codeRespawn[2][2];
unsigned long codeAmmo[2][2];

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(BUTTON_PIN, INPUT);
  pinMode(STATUS_PIN, OUTPUT);

  // On startup, set codeValue to whatever is in the EEPROM
  getCode();
  
  setCodeArray(codesAmmo, 11665640, 9044200, 16, 256, 256);
  setCodeArray(codesMedic, 11731176, 9109736, 16, 256, 256);
  setCodeArray(codesFlag, 11862248, 9175272, 16, 256, 256);
  setCodeArray(codesHazard, 12255464, 8782056, 16, 256, 256);
  // Codes for the 3 below here seem to change.
  setCodeArray(codesTeamRespawn1, 11994344, 8913128, 4, 65536, 256); // Sometimes the respawn input codes will differ by 1024.
  setCodeArray(codesTeamRespawn2, 11993320, 8913128, 4, 65536, 256); // So we use 2 separate arrays for them.
  setCodeArray(codeRespawn, 11927784, 8586472, 2, 1024, 0); // 2 possible inputs, 1024 apart.
  setCodeArray(codeAmmo, 12321000, 8586984, 2, 1024, 0); // 2 possible inputs, 1024 apart.
}
  
// Globals
unsigned long codeValue = -1; // The code value if not raw
int codeLen; // The length of the code

// Initialize a 2 dimensional array of IR code pairs
void setCodeArray(unsigned long array[][2], unsigned long inputStart, unsigned long outputStart, int len, long inputInterval, int outputInterval) {
  // loop over the array, setting the values
  for (int i = 0; i < len; i++) {
    array[i][0] = inputStart + (i * inputInterval);
    array[i][1] = outputStart + (i * outputInterval);
  }
}


// Stores the code for later playback
void storeCode(decode_results *results) {
  int codeType = -1; // The type of code
  codeType = results->decode_type;
  int count = results->rawlen;
  unsigned long actionCode = 0;
  if (codeType == SONY) {
      Serial.print("Received SONY: ");
      Serial.println(results->value, HEX);
      Serial.println(results->value);
      Serial.println(results->bits);
      actionCode = mapCode(results->value, results->bits);
      Serial.print("actionCode: ");
      Serial.println(actionCode);
      if (actionCode != 0) {
        saveCode(actionCode);
      }
  } else {
      Serial.print("Unexpected codeType ");
      Serial.print(codeType, DEC);
      Serial.println("");
  }
}

// Given an 'input' code, find and return its matching output code by searching our global arrays
unsigned long mapCode(long inputCode, int len) {
  Serial.print("inputCode: ");
  Serial.println(inputCode);
  unsigned long outputCode = 0;
  if (len == 24){
    outputCode = searchArray(codesAmmo, inputCode, 16);
  
    if (outputCode == 0) {
      outputCode = searchArray(codesMedic, inputCode, 16);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codesFlag, inputCode, 16);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codesHazard, inputCode, 16);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codesTeamRespawn1, inputCode, 4);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codesTeamRespawn2, inputCode, 4);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codeRespawn, inputCode, 2);
    }

    if (outputCode == 0) {
      outputCode = searchArray(codeAmmo, inputCode, 2);
    }
  }
  Serial.print("outputCode: ");
  Serial.println(outputCode);
  return outputCode;
}
  
// Search for something in an array and return its corresponding value 
unsigned long searchArray(unsigned long array[][2], unsigned long value, int len) {
  for (int i = 0; i < len; i++) {
    if (array[i][0] == value) {
      return array[i][1];
    }
  }
  return 0;
}

// Store code in the EEPROM
void saveCode(unsigned long code) {
  int eeAddress = 0;   //Location we want the data to be put.
  EEPROMWritelong(eeAddress, code);
  Serial.println(code);
  Serial.print("Code has been written to EEPROM address: ");
  Serial.println(eeAddress);
  // Also update the global
  codeValue = code;
}

// Retrieve a codeValue from the EEPROM
// Set the retrieved value as codeValue
void getCode() {
  unsigned long code = 0;   //Variable to store data read from EEPROM.
  int eeAddress = 0; //EEPROM address to start reading from
  //Get data from the EEPROM at position 'eeAddress'
  codeValue = EEPROMReadlong(eeAddress);
  Serial.print("Read code from EEPROM: ");
  Serial.println(codeValue);
}

//This function will write a 4 byte (32bit) long to the eeprom at
//the specified address to address + 3.
void EEPROMWritelong(int address, long value) {
  //Decomposition from a long to 4 bytes by using bitshift.
  //One = Most significant -> Four = Least significant byte
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}

//This function will return a 4 byte (32bit) long from the eeprom
//at the specified address to address + 3.
long EEPROMReadlong(long address) {
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);

  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

void sendCode(unsigned long code, int len) {
  irsend.sendSony(code, len);
  Serial.print("Sent Sony code: ");
  Serial.println(code);
}

long buttonTimer = 0;
long longPressTime = 4000;
boolean buttonActive = false;
boolean longPressActive = false;

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);
  if (buttonState == LOW) {
    if (buttonActive == false) {
      buttonActive = true;
      buttonTimer = millis();
    }
    if (millis() - buttonTimer > longPressTime) {
      if (longPressActive == false) {
        longPressActive = true;
        buttonTimer = millis();
        // do long press things
        Serial.println("Long press - Receive IR codes");      
        irrecv.enableIRIn(); // Re-enable receiver
      } else {
        Serial.println("2nd long press - Stop receiving IR codes");
        longPressActive = false;      
        buttonTimer = millis();
      }
    }
  } else {
    if (buttonActive == true) {
      if (longPressActive == false) {
        // short press logic
        Serial.println("Pressed, sending");
        digitalWrite(STATUS_PIN, HIGH);
        sendCode(codeValue, 24);
        digitalWrite(STATUS_PIN, LOW);
        delay(300); // Wait a bit between retransmissions
      }
      buttonActive = false;
    }
    if (longPressActive && irrecv.decode(&results)) {
      digitalWrite(STATUS_PIN, HIGH);
      storeCode(&results);
      irrecv.resume(); // resume receiver
      digitalWrite(STATUS_PIN, LOW);
    }
  }
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.