Problem adding another entry

I've got this code which is a infra-red decoder which reads an input IR sig and transcodes it to something else.

/*
 * IRTrans: receive and transcode IR signals 
 * 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 resistor and visible LED can be connected to STATUS_PIN to provide status.
 *
 * The logic is:
 * If a valid IR code in a lookup table is received
 * a corresonding different IR is transmitted
 * otherwise send the original code
 *
 * Version 0.1 September, 2011
 * Copyright 2011 Simon Walters based on code copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = 4;
//int BUTTON_PIN = 12;
int STATUS_PIN = 2;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

const int lRows = 19;
const int lCols = 6;
const char* lookupTable[lRows][lCols] = {
  {
    "SONT", "338", "SONY", "A8B47","20", "Red->PWR"  }  ,
  {
    "SONT", "F38", "SONY","42B47","20","Blue->Home"  }  ,
  {
    "SONT", "538", "SONY","BCB47","20","Sel->Sel"  }  ,
  {
    "SONT", "490", "SONY","9CB47","20","Up->Up"  }  ,
  {
    "SONT", "C90", "SONY","5CB47","20","Down->Down"  }  ,
  {
    "NEC", "1DE2B946", "SONY","DCB47","20","Left->Left"  }  ,
  {
    "SONT", "290", "SONY","3CB47","20","Right->Right"  }  ,
  {
    "SONT", "B38", "SONY","A8B47","20","Green->PWR"  }  ,
  {
    "SONT", "5E25", "SONY","58B47","20","Play->Play"  }  ,
  {
    "SONT", "738", "SONY","98B47","20","Yellow->Pause"  }  ,
  {
    "NEC", "1D8000FF", "SONY","D8B47","20","Rew->Rew"  }  ,
  {
    "NEC", "1DE2F00F", "SONY","38B47","20","FF->FF"  }  ,
  {
    "NEC", "1D8033CC", "SONY","98B47","20","Stop->Pause"  }  ,
  {
    "SONT", "1D0", "SONY","18B47","20","Backup->Stop"  }  ,
  {
    "NEC", "1DE2D926", "NEC","1D00D926","32","VolUp->AVVolUp"  }  ,
  {
    "NEC", "1DE259A6", "NEC","1D0059A6","32","VolDwn->AVVolDwn"  }  ,
  {
    "SONT", "A50", "NEC","20DFD02F","32","Help->TvAV"  }  ,
  {
    "SONT", "A90", "NEC","20DF10EF","32","Pwr->TvPwr"  }  ,
  {
    "SONT", "90", "NEC","20DF00FF","32","ChUp->ChUp"  }
};
unsigned long valueLTable[lRows][lCols];


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

  for (int checkRows =0;checkRows<lRows;checkRows++) {
    Serial.println(lookupTable[checkRows][1]);
    String outCode = lookupTable[checkRows][3];
    Serial.println(outCode);
    unsigned long decCode = 0;
    unsigned long multiplier = 1;
    for (int i=0;i<outCode.length();i++) {
      int chr = (int)outCode.charAt(outCode.length()-i-1);
      if (chr < 58) {
        decCode += (chr-48) * multiplier;
      } 
      else {
        decCode += (chr-55) * multiplier;
      }
      multiplier *= 16;
      Serial.println(decCode,HEX);
    }
    valueLTable[checkRows][3]=decCode;


    outCode = lookupTable[checkRows][4];
    Serial.println(outCode);
    decCode = 0;
    int chr = (int)outCode.charAt(1);
    decCode += (chr-48);
    chr = (int)outCode.charAt(0);
    decCode += (chr-48)*10;

    valueLTable[checkRows][4]=decCode;
    Serial.println(valueLTable[checkRows][3]);

    Serial.println(valueLTable[checkRows][4]);

    if (lookupTable[checkRows][2] == "SONY") {
      valueLTable[checkRows][2] = SONY;
    }
    if (lookupTable[checkRows][2] == "NEC") {
      valueLTable[checkRows][2] = NEC;
    }
    Serial.println(valueLTable[checkRows][2]);

  }



}

// Storage for the recorded code
int codeType = -1; // The type of code
unsigned long codeValue; // The code value if not raw
unsigned int rawCodes[RAWBUF]; // The durations if raw
int codeLen; // The length of the code
int toggle = 0; // The RC5/6 toggle state

// Stores the code for later playback
// Most of this code is just logging
void storeCode(decode_results *results) {
  codeType = results->decode_type;
  int count = results->rawlen;
  if (codeType == UNKNOWN) {
    Serial.println("Received unknown code, saving as raw");
    codeLen = results->rawlen - 1;
    // To store raw codes:
    // Drop first value (gap)
    // Convert from ticks to microseconds
    // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
    for (int i = 1; i <= codeLen; i++) {
      if (i % 2) {
        // Mark
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
        Serial.print(" m");
      } 
      else {
        // Space
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
        Serial.print(" s");
      }
      Serial.print(rawCodes[i - 1], DEC);
    }
    Serial.println("");
  }
  else {
    if (codeType == NEC) {
      Serial.print("Received NEC: ");
      if (results->value == REPEAT) {
        // Don't record a NEC repeat value as that's useless.
        Serial.println("repeat; ignoring.");
        return;
      }
    } 
    else if (codeType == SONY) {
      Serial.print("Received SONY: ");
    } 
    else if (codeType == RC5) {
      Serial.print("Received RC5: ");
    } 
    else if (codeType == RC6) {
      Serial.print("Received RC6: ");
    } 
    else {
      Serial.print("Unexpected codeType ");
      Serial.print(codeType, DEC);
      Serial.println("");
    }
    Serial.println(results->value, HEX);
    codeValue = results->value;
    codeLen = results->bits;
    //    Serial.println(codeLen);
  }
}

void sendCode(int repeat) {
  if (codeType == NEC) {
    if (repeat) {
      //      irsend.sendNEC(REPEAT, codeLen);
      //      Serial.println("Sent NEC repeat");
    } 
    else {
      Serial.print("Sent NEC ");
      Serial.println(codeValue, HEX);
      irsend.sendNEC(codeValue, codeLen);
      //      for (int i=1;i<=2;i++) {
      codeValue =0xFFFFFFFF;
      Serial.print("Sent NEC Repeat Code");
      Serial.println(codeValue, HEX);
      //      }
    }
  } 
  else if (codeType == SONY) {
    for (int i=1;i<=3;i++) {
      irsend.sendSony(codeValue, codeLen);
      Serial.print("Sent Sony ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == RC5 || codeType == RC6) {
    if (!repeat) {
      // Flip the toggle bit for a new button press
      toggle = 1 - toggle;
    }
    // Put the toggle bit into the code to send
    codeValue = codeValue & ~(1 << (codeLen - 1));
    codeValue = codeValue | (toggle << (codeLen - 1));
    if (codeType == RC5) {
      Serial.print("Sent RC5 ");
      Serial.println(codeValue, HEX);
      irsend.sendRC5(codeValue, codeLen);
    } 
    else {
      irsend.sendRC6(codeValue, codeLen);
      Serial.print("Sent RC6 ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == UNKNOWN /* i.e. raw */) {
    // Assume 38 KHz
    irsend.sendRaw(rawCodes, codeLen, 38);
    Serial.println("Sent raw");
  }
}


void loop() {


  if (irrecv.decode(&results)) {
    digitalWrite(STATUS_PIN, HIGH);
    Serial.println(" ");
    storeCode(&results);
    //    irrecv.resume(); // resume receiver
    digitalWrite(STATUS_PIN, LOW);
    delay(200); // Wait a bit before retransmissions
    //    Serial.println("Transcoding Start");
    //    Serial.println("rcvd code: ");
    //    Serial.println(codeValue);
    //    String sCodeValue = String(2576,HEX);
    //Serial.println(sCodeValue);
    String sCodeValue = String(codeValue,HEX).toUpperCase();
    //    Serial.println(sCodeValue);
    boolean transcode = false;
    for (int checkRows =0;checkRows<lRows;checkRows++) {
      //      Serial.println(lookupTable[checkRows][1]);
      if (sCodeValue == lookupTable[checkRows][1]) { 
        Serial.println("Found transcode");   
        digitalWrite(STATUS_PIN, HIGH);
        codeType = valueLTable[checkRows][2];
        codeValue = valueLTable[checkRows][3];
        codeLen = valueLTable[checkRows][4];
        sendCode(0);
        Serial.println(codeValue,HEX);
        Serial.println(lookupTable[checkRows][5]);
        digitalWrite(STATUS_PIN, LOW);
        transcode = true;
        delay(100); // Wait a bit between retransmissions
      }
    }
    if (!transcode) {
      //        Serial.println("Just repeat");
      //       delay(100); 
      //        sendCode(0);
    }
    irrecv.enableIRIn(); // Re-enable receiver
    irrecv.resume(); // resume receiver
  }
}

My problem is that the code is working fine but if I add one more entry to the lookup table it misbehaves :frowning:
I'd be very grateful if someone could test it out - you don't need and hardware as the fault manifests as a strange debug output from the serial com port.

To try and recreate the problem, load in the code (you'll need Ken Sheffiffs IRLibray) and monitor the serail port - you should see a debug list of the lookup table being output.

Now try and add in another entry to the lookup table (and increment lrows as well) and see what happens to the serial com output (it just outputs rubbish AFAIC) :frowning:

Any help greatfully received :slight_smile:

Simon

PS Ken's IR library available via http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html

regards

Simon

You are very short of memory. At the start of Setup, without adding another line, this function:

// this function will return the number of bytes currently free in RAM      
extern int  __bss_end; 
extern int  *__brkval; 
int freemem()
{ 
 int free_memory; 
 if((int)__brkval == 0) 
   free_memory = ((int)&free_memory) - ((int)&__bss_end); 
 else 
   free_memory = ((int)&free_memory) - ((int)__brkval); 
 return free_memory; 
}

Returns 98. That's not much to hold the stack and the String instances you're using, with their associated memory allocation calls. Adding another row pushes you over the edge into tricky bugs - having tweaked your code a bit and added a row, it crashed without ever running freemem. Since these strings are const, consider putting them in progmem.

@wildbill
Thanks :slight_smile:
While I was ordering an extra ATMega328P today, I was looking at the spec in the catalogue in the shop and suddenly realised that I'd forgotton that I don't have 1G or available RAM to program in :lol:

Time to remember/re-use the sort of techniques I used to employ on my 4K UK101 computer from 30 years ago :slight_smile:

regards
Simon

@wildbill

Since these strings are const, consider putting them in progmem.

Could you give an example/pointer to how to do this sort of thing please? :slight_smile:

Simon
[edit]PS I've modified my prog to work OK now by just modifying/trimming my array but would be interested how to get const data into progmem still for future reference[/edit] :slight_smile:

Here's the entry from the main site - it's quite comprehensive: PROGMEM - Arduino Reference