Problems with 4-digit key code

Hi all

I found a piece of code on this thread http://arduino.cc/forum/index.php/topic,48847.0.html that looked like just what I wanted but I can’t get the ‘check correct sequence’ part to work (I’m assuming that it’s working ok up to the error messages).

Here’s what I have (the part that is throwing the error - I can post the full sketch if needed, it’s not huge):

// To check the code is correct

char secret[4] = { ‘6’,‘7’,‘8’,‘9’};
byte cnt=0;
for (byte ix=0; ix<sizeof(secret); ix++) {
if (codearray[(charindex-sizeof(secret)+ix)%sizeof(codearray)] == secret[ix]) cnt++;
}

if (cnt == sizeof(secret)) {
digitalWrite(greenLed, HIGH); // set Green LED ON
delay(250); // wait for 0.25 seconds
digitalWrite(greenLed, LOW); // set Green LED OFF
}

else {
if (codeTries == 0) {
digitalWrite(redLed, LOW); // set Red LED ON
delay(250); // wait for 0.25 seconds
digitalWrite(redLed, HIGH); // set Red LED OFF
}
codeTries = codeTries - 1
}

The error messages that are produced are:

_4DigitWIP:52: error: expected unqualified-id before ‘for’
_4DigitWIP:52: error: expected constructor, destructor, or type conversion before ‘<’ token
_4DigitWIP:52: error: expected constructor, destructor, or type conversion before ‘++’ token
_4DigitWIP:56: error: expected unqualified-id before ‘if’
_4DigitWIP:62: error: expected unqualified-id before ‘else’

Can somebody help me out and explain what “expected unqualified-id” and “expected constructor, destructor, or type conversion” mean in simple terms? I have tried searching for answers but didn’t find anything helpful.

Basically it is supposed to check that the code entered from the keypad matches the “secret code” and allows three attempts (I set ’ int codeTries = 2; ’ at the beginning) to get it right before going to the “Failed” state where it flashes the Red LED. Each attempt should flash the Green LED - the two LEDs are supposed to be ‘reversed’ before anybody picks up on it and I have declared them at the begiining of the code.

The error messages are extremely unhelpful for us newbies. Somebody ought to write a guide “Arduino Error Messages Explained” - I’d pay good money for that just at the moment (less than a week from getting my Uno and having no previous programming experience)…

Thanks

Duncan

You need to post the whole sketch - looks like you may have code outside of functions.

If you want to see an alternative key code script, if you go here: http://www.arduinoevilgenius.com and download all the sketches in the zip file on the downloads tab, there are examples for two keycode locks. One also allows you to change the secret code, which it stores in EEPROM.

It does not do the three guesses thing though.

Thanks guys…

The complete sketch so far is:

#include <Keypad.h>

// set pin numbers:
const int redLed = 12; // the number of the Red LED pin
const int greenLed = 13; // the number of the Green LED pin

// set keypad:
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{‘1’,‘2’,‘3’},
{‘4’,‘5’,‘6’},
{‘7’,‘8’,‘9’},
{’*’,‘0’,’#’}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
Serial.begin(9600);
int RedledState = HIGH; //initial status for the Red LED
int GreenledState = LOW; //initial status for the Green LED
int codeTries = 2; //allow three attempts to get the correct code
long previousMillis = 0; // will store last time LED was updated
long interval = 500; // on time for LED blink (milliseconds)

}

char codearray[4]; // This is the array used to store the keys pressed, it has only for numbers
int charindex = 0; // This specifies the location in the array

void keyArray()
{
char key = keypad.getKey(); // Get the key pressed from the keypad
while (key == NO_KEY){
key = keypad.getKey();}
if (key != NO_KEY){
codearray[charindex] = key; // This stores a value in the array if a key was pressed
charindex = (charindex +1) % sizeof(codearray);
Serial.println(codearray[charindex],BYTE);}
}

void loop(){
keyArray();
}

// To check the code is correct

char secret[4] = { ‘6’,‘7’,‘8’,‘9’};
byte cnt=0;
for (byte ix=0; ix<sizeof(secret); ix++) {
if (codearray[(charindex-sizeof(secret)+ix)%sizeof(codearray)] == secret[ix]) cnt++;
}

if (cnt == sizeof(secret)) {
digitalWrite(greenLed, HIGH); // set Green LED ON
delay(250); // wait for 0.25 seconds
digitalWrite(greenLed, LOW); // set Green LED OFF
}

else {
if (codeTries == 0) {
digitalWrite(redLed, LOW); // set Red LED ON
delay(250); // wait for 0.25 seconds
digitalWrite(redLed, HIGH); // set Red LED OFF
}
codeTries = – codeTries
}

Be gentle with me - the Uno only arrived 4 days ago and I’m nudging 60 years old (dogs and tricks, etc…)

Thanks

Awol nailed it. Here's your problem:

void loop(){
keyArray();
}

All that code after that point which looks like you intended it to be in loop, isn't. Take that closing brace & move it down

Si

Thanks for the 'heads up' on the "Evil Genius" code examples. The door lock one is far more compact code-wise than what I had and (apart from the solenoid pin not being declared as a digital output in the code on the site - thought I had a dead Uno) it works well.

I just need to work out how it actually works (maybe I should buy the book or is there something more useful at my stage?) and find a way of implementing the three attempts and re-setting the thing after a timeout - it would soon burn the solenoid out as it is...

The ability to change the code is very useful.

It does seem to 'exercise' the LEDS at boot-up which is a problem for my intended application (I'm triggering a microprocessor in something else). Is this fundamental behaviour with Arduino or is it a function of this code (I'm too new to know) - can it be avoided somehow?

Although I'll base what I'm doing on this new code, I still wouldn't mind knowing what I did wrong in mine and what the error messages were actually telling me as part of the learning process.

Thanks

You can't have executable code outside of a function, so the compiler is only looking for things that look like declarations (functions, classes, stricts, simple data types) The error messages are not that obvious.

Wildbill

Thanks.

I’d ‘kind of’ homed in on that but hadn’t got as far as working out what exactly was wrong and what I needed to do.

Is it just me as a newbie (or even just me) or do other people find the error messages almost completely unfathomable? I think AWOL has just gone part way to answering that!!!

Duncan

The compiler is good and tries to make sense of what it sees, but it can only do this in the context of what it [u]expects[/u] to see at that particular time.

It would be a little like if someone spoke English words to you, but with German sentence structure.

Just remember that functional code has to be...in a function!

AWOL

I know the language problems of Spanish and Catalan vs English and they’re bad enough!!!

As if to highlight the problem further…

I added two lines to the working code so that the solenoid output would only be active for 250mS and it all fell over! The two additional lines are in red below…

// Project 27 Keypad door lock

#include <Keypad.h>
#include <EEPROM.h>

char* secretCode = “1234”;
int position = 0;
boolean locked = true;

const byte rows = 4;
const byte cols = 3;
char keys[rows][cols] = {
{‘1’,‘2’,‘3’},
{‘4’,‘5’,‘6’},
{‘7’,‘8’,‘9’},
{’*’,‘0’,’#’}
};
byte rowPins[rows] = {5, 4, 3, 2};
byte colPins[cols] = {8, 7, 6};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);

int redPin = 12;
int greenPin = 13;
int solenoidPin = 10;

void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(solenoidPin, OUTPUT);
loadCode();
flash();
updateOutputs();
}

void loop()
{
char key = keypad.getKey();
if (key == ‘*’ && ! locked)
{
// unlocked and * pressed so change code
position = 0;
getNewCode();
updateOutputs();
}
if (key == ‘#’)
{
locked = true;
position = 0;
updateOutputs();
}
if (key == secretCode[position])
{
position ++;
}
if (position == 4)
{
locked = false;
updateOutputs();
}
delay(100);
}

void updateOutputs()
{
if (locked)
{
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, LOW);
digitalWrite(solenoidPin, HIGH);
}
else
{
digitalWrite(redPin, LOW);
digitalWrite(greenPin, HIGH);
digitalWrite(solenoidPin, LOW);
delay(250);
digitalWrite(solenoidPin, High);
}
}

void getNewCode()
{
flash();
for (int i = 0; i < 4; i++ )
{
char key;
key = keypad.getKey();
while (key == 0)
{
key = keypad.getKey();
}
flash();
secretCode = key;

  • }*
  • saveCode();*
  • flash();flash();*
    }
    void loadCode()
    {
  • if (EEPROM.read(0) == 1)*
  • {*
  • secretCode[0] = EEPROM.read(1);*
  • secretCode[1] = EEPROM.read(2);*
  • secretCode[2] = EEPROM.read(3);*
  • secretCode[3] = EEPROM.read(4);*
  • }*
    }
    void saveCode()
    {
  • EEPROM.write(1, secretCode[0]);*
  • EEPROM.write(2, secretCode[1]);*
  • EEPROM.write(3, secretCode[2]);*
  • EEPROM.write(4, secretCode[3]);*
  • EEPROM.write(0, 1); *
    }
    void flash()
    {
  • digitalWrite(redPin, HIGH);*
  • digitalWrite(greenPin, HIGH); *
  • delay(500);*
  • digitalWrite(redPin, LOW);*
  • digitalWrite(greenPin, LOW); *
    }
    The error messages generated were:
    Project_27_keypad_lock.cpp: In function ‘void updateOutputs()’:
    Project_27_keypad_lock:77: error: ‘High’ was not declared in this scope
    Exception in thread “Thread-328” java.lang.ArrayIndexOutOfBoundsException: 3457
  • at processing.app.syntax.KeywordMap.getSegmentMapKey(Unknown Source)*
  • at processing.app.syntax.KeywordMap.lookup(Unknown Source)*
  • at processing.app.syntax.CTokenMarker.doKeyword(Unknown Source)*
  • at processing.app.syntax.CTokenMarker.markTokensImpl(Unknown Source)*
  • at processing.app.syntax.TokenMarker.markTokens(Unknown Source)*
  • at processing.app.syntax.JEditTextArea._offsetToX(Unknown Source)*
  • at processing.app.syntax.JEditTextArea.scrollTo(Unknown Source)*
  • at processing.app.syntax.JEditTextArea.scrollToCaret(Unknown Source)*
  • at processing.app.syntax.JEditTextArea.select(Unknown Source)*
  • at processing.app.Editor.statusError(Unknown Source)*
  • at processing.app.Editor$DefaultExportHandler.run(Unknown Source)*
  • at java.lang.Thread.run(Thread.java:619)*
    And all because I’d used lower case by mistake - change to upper case and it’s happy…
    I think you’d have to agree that’s a bit more than “English in a German sentence structure” :slight_smile:

"High" is not the same as "HIGH"

Duncan - obviously I'm going to recommend my own book ;)

This project is one of the more advanced ones in software terms. I start simple, work up to more advanced projects and try and explain how things work as I go.

I explain all the scripts in the book in a fair amount of detail.

This is going to sound really dumb...

I left the sketch running (not sure whether it was 'locked' or 'unlocked') while I went to make a coffee - now it's not responding to the unlock code...

I reloaded the sketch to the Uno to reset the "secret code" to 1 2 3 4 (just in case I'd changed it to something really obscure) and it didn't throw any errors so I assume it uploaded ok but it still won't respond to 1234...

I tried uploading a different sketch (thinking that might 'clear memory' or something), then reloaded - still dead!

Anybody got any ideas?

Si - I didn't realise you were the "Evil Genius" (was I right that "pinMode(solenoidPin, OUTPUT);" was missing - or are there some things that are simply implied?). Of course I'll get your book. I did actually consider it when I ordered the Uno (I'd already got the Make one) but the finances wouldn't stretch far enough. I realise that it's a bit beyond "Blink" but I only got into 'the wonderful world of Arduino' as a result of somebody asking me if something could be done (I, like a fool, said "yes, probably, Arduino looks like the easiest way as it's so well supported") - now (when I can get the unlock working again) I only have to incorporate a countdown timer, the multiple tries and a serial 7-segment display and I'll be cooking with gas!!! I'm still very glad that I didn't dive into PIC though...

AWOL - I realised that High is not the same as HIGH once I'd read the code over a few times, hence "And all because I'd used lower case by mistake - change to upper case and it's happy...". I still think the error messages make the MS-Windows ones look [u]almost[/u] helpful though. There has to be scope for some genius (evil or otherwise) to come up with a guide to them - even if it's in the form of "expected unqualified-id before... Indicates that you have done something silly just before the indicated command (for, next..... whatever it applies to - this might be having a closing curly brace (}) in the middle of a void loop() or, ..." or "If you get something like 'High' was not declared in this scope, check the spelling and case High is not the same as HIGH - one is a variable and the other is a state" or something. Whether there is any easy way to explain "at processing.app.syntax.CTokenMarker.markTokensImpl(Unknown Source)" I wouldn't know.

All of these:

Exception in thread "Thread-328" java.lang.ArrayIndexOutOfBoundsException: 3457 at processing.app.syntax.KeywordMap.getSegmentMapKey(Unknown Source) at processing.app.syntax.KeywordMap.lookup(Unknown Source) at processing.app.syntax.CTokenMarker.doKeyword(Unknown Source) at processing.app.syntax.CTokenMarker.markTokensImpl(Unknown Source) at processing.app.syntax.TokenMarker.markTokens(Unknown Source) at processing.app.syntax.JEditTextArea._offsetToX(Unknown Source) at processing.app.syntax.JEditTextArea.scrollTo(Unknown Source) at processing.app.syntax.JEditTextArea.scrollToCaret(Unknown Source) at processing.app.syntax.JEditTextArea.select(Unknown Source) at processing.app.Editor.statusError(Unknown Source) at processing.app.Editor$DefaultExportHandler.run(Unknown Source) at java.lang.Thread.run(Thread.java:619)

are not C errors, but are a side-effect of Arduino making it easier for you to program.

As to why your board is dead? Well, how is your stuff wired? What buffers do you have for the solenoid and do you have current-limiters for the LEDs?

Here are a couple of things to remember about computers and compilers: I've heard computers described as totally obedient morons (in a Dick Francis novel of all things!) and it's very apposite in this case. The system isn't smart enough to look at 'High' and make the leap to Oh, I suppose he means 'HIGH' and even if it were, you wouldn't want it to start making such assumptions about your code, in case you were really using two variables distinguished only by case and had forgotten to declare one. Then debugging really would be an exciting exercise in AI. In this case, the compiler told you precisely where and what the problem was, albeit in a slightly cryptic way.

Next thing is a quote from an old compiler writing text book - "Even a fool can write a compiler for correct programs". The author went on to say that it is very very difficult to deal with all the mistakes people can make in their code. Compilers have improved over the years in this regard, sometimes they are able to make suggestions as to what is wrong, but in other cases, all you can rely on is that the compiler found a problem at this point in the code. That should usually be enough clue for you to find the problem, although it helps to recall that it may mean, the problem is on the previous line, but the compiler didn't notice the problem then. Missing semi-colons (among other things) can cause this one.

The upshot is, just look at the general location of the first error and use your superior human intellect to figure out what on earth the compiler is whining about ;) Don't bother even looking at the rest of the errors. Fix the first and recompile - many others will evaporate.

For cryptic read 'totally unintelligible and frightening' when you're just starting out - I realise it will become easier as I get the hang of it and, as you say, it does point you at the problem.

is it possible to show the line numbers within the sketch or is it only possible to move up and down and read the line number below the sketch? It took me quite a while to realise that it was the cursor line number there...

As to the "why your board is dead" - 'by 'eck Myrtle, I hope that's not the case!'... The circuit is wired on a prototype board (the spring-contacts in holes type) and nothing has moved - I've checked everything is 'as was'. I'm using a LED in place of the solenoid. All three LEDs have 470R current limiting resistors. Interconnects are flying leads with 'header pins' on each end.

The three outputs I'm using for the LEDs work fine from another sketch.

Are Arduinos prone to dying?

Could it be the EEPROM part as that's where the code seems to store the 'secret number' (that could explain why it can't get a match perhaps?). Is there a way I can test that? - read the stored 4-digit 'secret number' via serial monitor perhaps?

For cryptic read 'totally unintelligible and frightening' when you're just starting out

Yes, but be aware that you seem to have gone from "Sur le pont d'Avignon" to "A la recherche de temps perdus" without bothering to learn any of the intermediate steps.

Duncan, yes you were right about the missing line. Well spotted (see, you are learning) and thanks for letting me know.

I have updated the download on http://www.arduinoevilgenius.comnow and made a note for the next printing.

In my defence, the sketch works, because I control the solenoid using a transistor and digitalWriting a high to a pin in input mode actually turns on the built-in pullup resistor, which was enough to turn on the transistor. But you are correct, it should be set as an output explicitly.

Duncan, Its just dawned on me what your problem is.

It reads the secret code from EEPROM in the setup function.

Comment out the line:

loadCode();

in the setup function and then reload the sketch.

You can put the line back in again once you have reset the code.

This is explained in the book ;-)

Point taken AWOL but the case-sensitive thing would have been there if I'd typed "Blink" in rather than running the sketch from 'Examples' and the error message would have been equally as baffling at first sight - though probably easier to spot with only a few lines of code... I had read in the Make book about case sensitivity, I just didn't 'see' it in the code as being wrong because the word was right - lesson learned, and that's what it's all about.

Si - thank you, mention of dead Arduino was getting me worried. Not quite sure what's going on with this bit or what you meant by "You can put the line back in again once you have reset the code." - but it's sold me on the idea of getting the book, if I can persuade my daughter to buy me a birthday present this year!!!

Thanks guys

Duncan