Posts Tagged ‘code’

DSC alarm system installer codes and user access codes

Monday, February 15th, 2016

My new habitat came protected by a DSC alarm system. The system consists of a keypad, model RFK5501 in my case, and a control panel, PC1616 for me. The model number of the keypad is hidden in very tiny text on the top edge of the keypad. The control panel is the hub of the alarm system and is located within a metal box within an interior wall. I had to open the metal enclosure to find the model number of the control panel.

To change most settings one needs a user access code. For the PC1616, there are 48 user access codes numbered 01 through 48. Other models have more codes. Access code 40 is the master code. This code can be used to change all other codes. To change a user access code, one would enter *5[master code][code #][new code]. So, for example, if the master code is 1234 and one wants to add a second code (01) as 5678, one would enter *5 1234 01 5678. To change the master code to 5678, the sequence is *5 1234 40 5678. In the sequence, after each accepted entry, the keypad will emit three beeps. When an entry is rejected, it will sound one long beep. When finished, pressing # until the ready light comes back on and the screen blanks will return the keypad to normal operation.

Changing the master code is one important level of security, but there is an even more privileged code with which a person could compromise the DSC security system. This code is the installer code. With the installer code, it is possible to change the master code and all other settings. New systems come with a default installer code programmed, 5555 in the case of the PC1616. If the installer hasn't changed the installer code, it's a good idea to change it since it potentially allows anyone to have control over your security system. DIY'ers should change the code regardless to prevent unwanted access from even the installer.

The installer code is changed by entering the installer programming via the *8 command. The complete sequence is *8[current installer code]006[new installer code]. For example, the following sequence sets the default installer code (5555) to 1234: *8 5555 006 1234. Then the # key is pressed until the keypad returns to normal operation. In the case of entering the installer code, an accepted code is signaled by six short beeps instead of three.

If the new installer code is forgotten, the code can be reset to the default code following a hardware reset procedure at the control panel. For maximum security, there is an installer lockout feature that will prevent the hardware reset from resetting the installer code. If the installer code is unknown and the installer lockout is enabled, the only solution to regain complete control of the system is to replace the control panel with a new panel in factory default condition.

An improved key-reader library for the SainSmart LCD Keypad Shield (for Arduino)

Monday, August 5th, 2013

The LCD Keypad shield from SainSmart is a bargain. For ~$8 (and free shipping, at the time of this post) you get 32 character (16×2) blue/white LCD panel with a built-in keypad with 5 momentary switches. This provides a quick solution for interaction with Arduino projects. To control the LCD part of the shield, one can use the Arduino supplied LiquidCrystal library (included with Arduino IDE). In the Key_Grab demo (v. 0.2) on the SainSmart website is included a library, DFR_Key, for reading which keys are pressed on the keypad. However, the library is not written well. This post describes both the problem and the solution.

First, a little background is necessary about how the keypad signals a key is pressed. Only a single analog-in pin is used and the shield uses a voltage divider to send a voltage that corresponds to a given key. To detect a key, one has only to read the voltage at the analog pin and determine if it falls within a certain range. For example, a voltage of 0 to 0.7 V signals the UP key was pressed. The DFR_Key library contains a getKey() function that does this and returns an integer from 0 to 5 that represents the key pressed (0 is supposed to mean no key, but as written means the last key was just released).

You’d expect that when you call getKey() it would read the voltage at the pin, figure out what key that represented, and send back the integer representing the particular key. So really, it should just be translating the voltage to an integer from 0 to 5 (none, select, left, up, down, right, respectively). But, there is some “extra functionality” the library provides that is the problem. Here’s how the logic of the getKey() function works:

Has a minimum time passed since the last time I checked for a key press?

If not, do nothing – return no value at all!

If so, read the voltage at the pin. Is this voltage different than the voltage I read the last time I checked for a keypress?

If not, return -1.

If they’re different, it means a key was pressed right? Determine which key was pressed and return an integer from 0 to 5 representing that key.

The first bit of “extra functionality” is what the library refers to as the refreshRate. The idea is that you don’t want to check for a key press too quickly, else the function might return that the key is being held down when in fact it’s just a normal press. This makes some sense if you simply dump a getKey() call in your Arduino sketch’s loop() function. You would then check the returned value to see if it actually did a key press. If it decided enough time hadn’t pass it would return….oh wait! It doesn’t return anything in this case. That’s not appropriate behavior. When the program says getKey(), it should expect a key code sent back. Therefore, it should be the job of the programmer to only call getKey() at appropriate intervals (say every 100 ms).

That brings up the next problem. There are five keys on the keypad. Add in an extra code for “no key being pressed” and you get the six integers from 0 to 5. Perfectly reasonable. So what’s this -1 return value for? The library defines the alias SAMPLE_WAIT for this value (as opposed to NO_KEY, and UP_KEY, etc.). I’m not sure what the meaning was supposed to be, but this value is returned when the getKey() function determines that the key being pressed is the same as the key that was detected upon the last call to getKey(). At first, it would seem to be letting you know that the last key pressed is being held down. But 1: you don’t know what the last key pressed was, unless you’re tracking it yourself. And 2: that may not even be true – if you make two getKey() calls 60 s apart, whose to say whether the key was being held the whole time; all we know is that the same key was pressed as last time. So it’s telling us the same key was pressed as before and according to point 1, I’m keeping track of what that key was. If it had just returned the actual key code, I could have figured this out for myself by comparing it to my stored value of the last key pressed.

Now to the final problem. If you follow the logic stated above carefully, you’ll see that to determine if the same key was pressed, the getKey() function compares the voltage read at the analog pin to the voltage it read last time it detected a key was pressed. But the voltage does not directly correspond to a given key – a key press can be signaled by a range of voltages. For example, assume on the first call to getKey() it reads a value of 200 mV. That corresponds to the UP_KEY and it returns 3. On the next call to getKey() assume it reads a value of 205 mV. The user is pressing the up key again (or holding it down) but the voltage is slightly different. The getKey() function compares the new value, 205 mV, to the old value, 200 mV, and thinks a new key is being pressed. So instead of returning -1 for “same key is being pressed” it returns 3 for “up key is being pressed”.

Actually, this should be the behavior! Upon every call, the getKey() function should just return an integer representing the key that is being pressed at the time the call is made. But because the authors meant for it to return -1 when there was no change in the key being pressed, and meant for it to be called on every loop() iteration, the Key_Grab demo flickers the screen like crazy. Actually, it works fine when the UNO board is removed from all sources of noise and interference. But put it next to a piece of electronics (e.g. your computer) and the noise causes the voltage supplied to the analog pin to fluctuate, new key presses to be registered, and the demo to update the screen on every loop() iteration. It’s the constant updating that causes the flicker which makes it appear as though you got ripped off $10.

How can we fix this mess? Actually, the fixes are simple and actually reduce the code in the library.

  1. Remove all of the logic relating to the “refreshRate”. The programmer will be forced to decide how often to call getKey().
  2. Remove the comparison of the current key press to the previous key press. The programmer can decide if the user is pressing the same key by recording the last pressed key.

Here is the derived library which I’ve called LCD_Keypad_Reader.cpp (feel free to rename). The original SainSmart DFR_Key library didn’t come with a license so I’m not putting one on this derived work either. I don’t really care what you do with this code, but it’s possible that SainSmart could impose some kind of limitations.

#include "Arduino.h" 
#include "LCD_Keypad_Reader.h" 

static int DEFAULT_KEY_PIN = 0;  
static int DEFAULT_THRESHOLD = 5; 

// The Sainsmart keypad uses a voltage divider to deliver a voltage  
// between 0 and 5 V that corresponds to the key being pressed in  
// order to use only a single input pin. The values below are from 0 to  
// 1023 because the Arduino uses a 10 bit resolution. 
static int UPKEY_ARV = 144; // 0.720 V, that's read "analogue read value" 
static int DOWNKEY_ARV = 329; // 1.645 V 
static int LEFTKEY_ARV = 505; // 2.525 V 
static int RIGHTKEY_ARV = 0; // 0 V 
static int SELKEY_ARV = 742; // 3.710 V 
static int NOKEY_ARV = 1023; // 5.115 V 

LCD_Keypad_Reader::LCD_Keypad_Reader() 
{     
  _keyPin = DEFAULT_KEY_PIN; 
  _threshold = DEFAULT_THRESHOLD; 
  _curInput = NO_KEY; 
  _curKey = NO_KEY; 
} 

int LCD_Keypad_Reader::getKey() 
{ 
  _curInput =  analogRead(_keyPin); 
  _curKey = categorizeKey(_curInput); 
  return _curKey; 
} 

int LCD_Keypad_Reader::categorizeKey(int analogKeyValue){ 
  int categorizedKeyValue = 0; 

  if (analogKeyValue > UPKEY_ARV - _threshold && analogKeyValue < UPKEY_ARV + _threshold ){ 
      categorizedKeyValue = UP_KEY; 
  } 
  else if (analogKeyValue > DOWNKEY_ARV - _threshold && analogKeyValue < DOWNKEY_ARV + _threshold ){ 
      categorizedKeyValue = DOWN_KEY; 
  } 
  else if (analogKeyValue > RIGHTKEY_ARV - _threshold && analogKeyValue < RIGHTKEY_ARV + _threshold ){ 
      categorizedKeyValue = RIGHT_KEY; 
  } 
  else if (analogKeyValue > LEFTKEY_ARV - _threshold && analogKeyValue < LEFTKEY_ARV + _threshold ){  
      categorizedKeyValue = LEFT_KEY; 
  } 
  else if (analogKeyValue > SELKEY_ARV - _threshold && analogKeyValue < SELKEY_ARV + _threshold ){ 
      categorizedKeyValue = SELECT_KEY; 
  } 
  else{ 
    categorizedKeyValue = NO_KEY; 
  } 

  return categorizedKeyValue; 
}

And here is the header file, LCD_Keypad_Reader.h

#ifndef LCD_Keypad_Reader_h 
#define LCD_Keypad_Reader_h 

#include "Arduino.h" 

#define SAMPLE_WAIT -1 
#define NO_KEY 0 
#define UP_KEY 3 
#define DOWN_KEY 4 
#define LEFT_KEY 2 
#define RIGHT_KEY 5 
#define SELECT_KEY 1 

class LCD_Keypad_Reader 
{ 
  public: 
    LCD_Keypad_Reader(); 
    int getKey(); 
    int categorizeKey(int); 
  private: 
    int _keyPin; 
    int _threshold; 
    int _curInput; 
    int _curKey; 
}; 

#endif