maandag 28 februari 2011

My first Arduino project - part 4

Checking the SD card

First I'll check whether the SD part of the Data Logging shield is working alright. This is described on this page.

The output I got was the following:

type any character to start


init time: 350


Card type: SD2


Manufacturer ID: 2
OEM ID: TM
Product: SD02G
Version: 4.8
Serial number: 371219368
Manufacturing date: 11/2009


cardSize: 3842048 (512 byte blocks)
flashEraseSize: 128 blocks
eraseSingleBlock: true


part,boot,type,start,length
1,0,6,137,3841911
2,0,0,0,0
3,0,0,0,0
4,0,0,0,0


Volume is FAT16
blocksPerCluster: 64
clusterCount: 60022
fatStartBlock: 138
fatCount: 2
blocksPerFat: 235
rootDirStart: 608
dataStartBlock: 640


type any character to start

To make the test work I had to put the baud rate to 9600 and I had to disconnect the connections to pin 0 of the Arduino (and the 5V line) to the RFID reader.  I've noticed that I have to disconnect the RFID reader each time I need to upload a sketch.  I'm currently still looking how to connect the RFID reader to something else than Digital pin 0 (which is also the RX pin used to transfer sketches to the Arduino).

But luckely my SD card seems to be OK :-)

The uses for the SD card

One way to use the SD card is to add a log entry each the time a token is read (one that's different than the previous one).

The second use for the SD card would be to keep track of all allowed users on the SD card.  Not only the token gets logged when read, it also gets checked against a list of tokens that are allowed access.  Only when access is allowed, the green LED should light up (simulating the door lock unlocking). 

Logging access

This blog will only cover writing a log entry to a log file whenever a valid token is read.  Validating the read token will be dealt with in my next blog entry.

I manually created 2 directories on the SD-card, the 'logs' and 'admin' directories.

The 'logs' directory which will keep track of all the access log files. Eventually a new file should be created per day, this will allow easier cleanup of the log files.

The 'admin' directory will contain a commas separated value list of all members with there corresponding RFID token (members.csv). I will also keep track of subscription information in a file called 'subscript.csv'.  A last file I need is the 'loginfo.txt' which will keep track of the last log date and the number of days after the subscription ends before somebody is no longer allowed to access the weight room.

I have been going through the example code and copied whatever I needed to make my arduino log every valid token to the 'log.csv' file within the 'logs' directory. The one 'log.csv' file is temporary before working out how to rotate the log files.


#include <SdFat.h>
#include <Wire.h>
#include <RTClib.h>


int LED = 7;
int RFID_ENABLE = 2;
int CODE_SIZE = 10;
int ARRAY_SIZE = 11;


int bytesRead = 0;
char lastReadRFID[11];
char code[11];


//The RTC related object
RTC_DS1307 RTC;


//The SD card related objects
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile accessLogDir;
SdFile adminDir;
SdFile logFile;




//===================================================================================
// SETUP METHOD
//===================================================================================
void setup() { 
  
  Serial.begin(2400);     // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
  Wire.begin();
  RTC.begin();
  pinMode(RFID_ENABLE,OUTPUT);   // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin 
  pinMode(LED, OUTPUT);   // Set digital pin 13 as OUTPUT to connect it to LED
  activateRFID();
  // initialize the SD card at SPI_FULL_SPEED for best performance.
  // try SPI_HALF_SPEED if bus errors occur.
  if (!card.init(SPI_FULL_SPEED)) Serial.println("card.init failed");


  // initialize a FAT volume
  if (!volume.init(&card)) Serial.println("volume.init failed");


  // open the root directory
  if (!root.openRoot(&volume)) Serial.println("openRoot failed");


  //open the logDir
  char logDirName[] = "logs";
  if (!accessLogDir.open(&root, logDirName, O_RDONLY)) {
    Serial.println("figure out error while opening logs and admin dir");
  }
  //open the admin
  char adminDirName[] = "admin";
  adminDir.open(&root, adminDirName, O_RDONLY);
  
}  


//===================================================================================
// MAIN APP LOOP
//===================================================================================
void loop() {
  openLogFile();
  if (!adminDir.isOpen()) {
    Serial.println ("admin dir not opened");
  }
  activateRFID();
  readRFID();
  if (bytesRead == CODE_SIZE) {
    deActivateRFID();
    handleReadRFID();
  }
  closeLogFile();
//  accessLogDir.close();
//  adminDir.close();
}


//===================================================================================
// close the log file
//===================================================================================
void closeLogFile() {
  logFile.close();
}


//===================================================================================
// opens the log file
//===================================================================================
void openLogFile() {
  if (!accessLogDir.isOpen()) {
    Serial.println ("access log dir not opened");
  } else {
    char name[] = "log.csv";
    logFile.open(&accessLogDir, name, O_CREAT | O_WRITE | O_APPEND);
    if (!logFile.isOpen()) {
      Serial.println ("file not opened");
    }
  }
}


//===================================================================================
// handle the read RFID tag
//===================================================================================
void handleReadRFID(){
//  if (code != lastReadRFID ) {
  if (codesAreDifferent() ) {
    Serial.print(RTC.now().year(), DEC);
    Serial.print('/');
    Serial.print(RTC.now().month(), DEC);
    Serial.print('/');
    Serial.print(RTC.now().day(), DEC);
    Serial.print(' ');
    Serial.print(RTC.now().hour(), DEC);
    Serial.print(':');
    Serial.print(RTC.now().minute(), DEC);
    Serial.print(':');
    Serial.print(RTC.now().second(), DEC);
    Serial.print("TAG code is: ");       // possibly a good TAG 
    Serial.print(code);                  // print the TAG code 
    Serial.print(" while old tag is ");  // print the TAG code 
    Serial.println(lastReadRFID);        // print the TAG code 
    //write to log file
    if (logFile.isOpen()) {
      logFile.print(RTC.now().year(), DEC);
      logFile.print('/');
      logFile.print(RTC.now().month(), DEC);
      logFile.print('/');
      logFile.print(RTC.now().day(), DEC);
      logFile.print(' ');
      logFile.print(RTC.now().hour(), DEC);
      logFile.print(':');
      logFile.print(RTC.now().minute(), DEC);
      logFile.print(':');
      logFile.print(RTC.now().second(), DEC);
      logFile.print(",");       // possibly a good TAG 
      logFile.println(code);                  // print the TAG code 
    }


    //
    deActivateRFID();
    digitalWrite(LED, HIGH);             // Switch on the LED
    delay(2000);                         // wait for 2 seconds
    setLastReadRFID();
    digitalWrite(LED, LOW);              // Switch off the LED
  } else {
    Serial.print("new (");               // possibly a good TAG 
    Serial.print(code);                  // print the TAG code 
    Serial.print(") equals new (");      // print the TAG code 
    Serial.print(lastReadRFID);          // print the TAG code 
    Serial.println(")");                 // print the TAG code 
  }
}


//===================================================================================
// checks wether the current code is different from the previously read code
//===================================================================================
boolean codesAreDifferent(){
  for (int i = 0; i < CODE_SIZE; i++) {
    if (code[i] != lastReadRFID[i]) {
      return true;
    }
  }
  return false;
}
  
//===================================================================================
// Activate the RFID reader
//===================================================================================
void activateRFID() {
    digitalWrite(RFID_ENABLE, LOW);// Activate the RFID reader
}
  
//===================================================================================
// DeActivate the RFID reader
//===================================================================================
void deActivateRFID() {
    digitalWrite(RFID_ENABLE, HIGH);// Deactivate the RFID reader
}
  
//===================================================================================
// read the code from the RFID reader
//===================================================================================
void readRFID(){
  bytesRead = 0;
  int val = 0;
    
  if(Serial.available() > 0) {          // if data available from reader 
    if((val = Serial.read()) == CODE_SIZE) {   // check for header 
      while(bytesRead<10) {              // read 10 digit code 
        if( Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          }
          code[bytesRead] = val;         // add the digit           
          bytesRead++;                   // ready to read next digit  
        } 
      } 
    }
  }
}


//===================================================================================
// set the lastReadRFID code
//===================================================================================
void setLastReadRFID(){
  for (int i = 0; i < CODE_SIZE; i++) {
    lastReadRFID[i] = code[i];        // copy the content of the last read RFID code into lastReadRFID
  }
  lastReadRFID[10] = 0;
  code[10] = 0;
}



Stats
compiler
Binary sketch size: 15736 bytes (of a 30720 byte maximum)
So I'm passing half of my capacity, let's see what I can still add.

knowledge
Seems like my knowledge of C (or my lack of it) is becoming a slight bottleneck.

zondag 20 februari 2011

My first Arduino project - part 3

Now it's time to start making use of the Adafruit Data Logger shield functionalities

Initialize the shield
So before using the shield I needed to set the time on the data logger shield.  This page describes how this can be done.

To get the sketches working as described in the explanation, I just added the RTC library, toghether with the SD library to my Arduino environment.  I added a libraries directory to the default sketchbook.  I downloaded the adafruit-RTClib-72fc1a4.tar.gz and sdfatlib20101010.zip file and unpacked them in the libraries directory.  The following shows what I did to make these libraries accessible to my Arduino IDE:


someuser@somehost:~/sketchbook/libraries$ pwd
/home/someuser/sketchbook/libraries
someuser@somehost:~/sketchbook/libraries$ ls -la
total 20
drwxr-xr-x 5 someuser someuser 4096 2011-02-20 21:08 .
drwxr-xr-x 8 someuser someuser 4096 2011-02-20 18:54 ..
drwxrwxr-x 3 someuser someuser 4096 2010-07-30 04:36 adafruit-RTClib-72fc1a4
drwxr-xr-x 5 someuser someuser 4096 2011-02-20 18:22 sdfatlib20101010
someuser@somehost:~/sketchbook/libraries$ mv ./adafruit-RTClib-72fc1a4 ./RTClib
someuser@somehost:~/sketchbook/libraries$ mv ./sdfatlib20101010 ./sdfatlib
someuser@somehost:~/sketchbook/libraries$ ls -la
total 20
drwxr-xr-x 5 someuser someuser 4096 2011-02-20 21:08 .
drwxr-xr-x 8 someuser someuser 4096 2011-02-20 18:54 ..
drwxrwxr-x 3 someuser someuser 4096 2010-07-30 04:36 RTClib
drwxr-xr-x 5 someuser someuser 4096 2011-02-20 18:22 sdfatlib
someuser@somehost:~/sketchbook/libraries$ ls -al ./sdfatlib
total 288
drwxr-xr-x 5 someuser someuser   4096 2011-02-20 18:22 .
drwxr-xr-x 5 someuser someuser   4096 2011-02-20 21:08 ..
-rw-r--r-- 1 someuser someuser    558 2010-08-02 09:13 AF_GPS_Mega.txt
-rw-r--r-- 1 someuser someuser   4844 2010-10-10 08:34 changes.txt
drwxr-xr-x 2 someuser someuser   4096 2011-02-20 18:22 html
drwxr-xr-x 2 someuser someuser   4096 2011-02-20 18:22 makePinInclude
-rw-r--r-- 1 someuser someuser   6552 2010-08-13 05:34 readme.txt
drwxr-xr-x 3 someuser someuser   4096 2011-02-20 18:22 SdFat
-rw-r--r-- 1 someuser someuser 224229 2010-08-13 05:23 SdFat.pdf
-rw-r--r-- 1 someuser someuser  21428 2009-02-15 09:11 SdLevel.png
-rw-r--r-- 1 someuser someuser   1921 2010-08-13 05:20 troubleshooting.txt
someuser@somehost:~/sketchbook/libraries$ cp -a ./sdfatlib/SdFat ./
someuser@somehost:~/sketchbook/libraries$ rm -rf ./sdfatlib
someuser@somehost:~/sketchbook/libraries$ ls -la
total 20
drwxr-xr-x 5 someuser someuser 4096 2011-02-20 21:08 .
drwxr-xr-x 8 someuser someuser 4096 2011-02-20 18:54 ..
drwxrwxr-x 3 someuser someuser 4096 2010-07-30 04:36 RTClib
drwxr-xr-x 3 someuser someuser 4096 2011-02-20 18:22 SdFat


I unpacked these files in the libraries directory and renamed them so the resulting directory names (one for each lib) only contained letters and numbers (the arduino IDE doesn't seem to handle anything else very well).

Also, the SD sources are found in a subdirectory that needs to be copied into the libraries directory instead of the unpacked archive file.  So after restart of the arduino IDE, I could start using the libraries.

After the above changes you need to restart your Arduino IDE to have access to the libraries.

So now that the libraries are accessible from the IDE and my data logging shield's time is set, I can start using the RTC and SD functionalities.

RTC

I copied some code into the piece of the application that prints out the RFID token whenever a new token is read. The copied code (see below) however didn't work for me:

    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);

I adjusted the source to the following to make it work:

#include <Wire.h>
#include <RTClib.h>
...
RTC_DS1307 RTC;
...
    Serial.print(RTC.now().year(), DEC);

    Serial.print('/');
    Serial.print(RTC.now().month(), DEC);
    Serial.print('/');
    Serial.print(RTC.now().day(), DEC);
    Serial.print(' ');
    Serial.print(RTC.now().hour(), DEC);
    Serial.print(':');
    Serial.print(RTC.now().minute(), DEC);
    Serial.print(':');
    Serial.print(RTC.now().second(), DEC);

My C knowledge is very basic, so there might be a very good reason why the first code didn't work but the above changes work for me.

So now I got a time stamp displayed whenever a RFID token is read.  So, next I'll try to get the SD card involved in the application. But that will be for the next blog entry :-)

Stats
compiler
Binary sketch size: 6162 bytes (of a 30720 byte maximum)
So this still leaves me 24558 bytes of room.

vrijdag 11 februari 2011

My first Arduino project - part 2

Initial setup

I have put the Data logger shield onto the Arduino board and checked the pin usage of this shield on the shieldlist website.

Next I hooked up the Parallax RFID to the Arduino board via the connectors I soldered onto the data logger shield.  I based myself on the documentation found at the Arduino playground.  I did however modify the given examples to make sure the pins used by the parallax RFID reader did not interfere with the pins used by the data logger and I restructured the code a bit.

One additional component I added was a LED to indicate whether to door should get unlocked or not.

Current functionality

The code below allows reading and displaying RFID codes.  It will 'unlock the door' (power the LED) when an RFID code is read that is different from the last read RFID code. If the same RFID token is read several times in succession, it will only 'unlock the door' the first time it is read. Later I'll adjust to code to make sure this is time boxed. But first I'll see if I get the data logger working properly

The source code


int LED = 7;
int RFID_ENABLE = 2;
int CODE_SIZE = 10;
int ARRAY_SIZE = 11;


int bytesRead = 0;
char lastReadRFID[11];
char code[11];


//===================================================================================
// SETUP METHOD
//===================================================================================
void setup() { 
  
  Serial.begin(2400);     // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
  pinMode(RFID_ENABLE,OUTPUT);   // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin 
  pinMode(LED, OUTPUT);   // Set digital pin 13 as OUTPUT to connect it to LED
  activateRFID();
}  


//===================================================================================
// MAIN APP LOOP
//===================================================================================
void loop() { 
  activateRFID();
  readRFID();
  if (bytesRead == CODE_SIZE) {
    deActivateRFID();
    handleReadRFID();
  }
}


//===================================================================================
// handle the read RFID tag
//===================================================================================
void handleReadRFID(){
  if (codesAreDifferent() ) {
    Serial.print("TAG code is: ");       // possibly a good TAG 
    Serial.print(code);                  // print the TAG code 
    Serial.print(" while old tag is ");  // print the TAG code 
    Serial.println(lastReadRFID);        // print the TAG code 
    deActivateRFID();
    digitalWrite(LED, HIGH);             // Switch on the LED
    delay(2000);                         // wait for 2 seconds
    setLastReadRFID();
    digitalWrite(LED, LOW);              // Switch off the LED
  } else {
    Serial.print("new (");               // possibly a good TAG 
    Serial.print(code);                  // print the TAG code 
    Serial.print(") equals new (");      // print the TAG code 
    Serial.print(lastReadRFID);          // print the TAG code 
    Serial.println(")");                 // print the TAG code 
  }
}


//===================================================================================
// checks wether the current code is different from the previously read code
//===================================================================================
boolean codesAreDifferent(){
  for (int i = 0; i < CODE_SIZE; i++) {
    if (code[i] != lastReadRFID[i]) {
      return true;
    }
  }
  return false;
}
  
//===================================================================================
// Activate the RFID reader
//===================================================================================
void activateRFID() {
    digitalWrite(RFID_ENABLE, LOW);// Activate the RFID reader
}
  
//===================================================================================
// DeActivate the RFID reader
//===================================================================================
void deActivateRFID() {
    digitalWrite(RFID_ENABLE, HIGH);// Deactivate the RFID reader
}
  
//===================================================================================
// read the code from the RFID reader
//===================================================================================
void readRFID(){
  bytesRead = 0;
  int val = 0;
    
  if(Serial.available() > 0) {          // if data available from reader 
    if((val = Serial.read()) == CODE_SIZE) {   // check for header 
      while(bytesRead<10) {              // read 10 digit code 
        if( Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          }
          code[bytesRead] = val;         // add the digit           
          bytesRead++;                   // ready to read next digit  
        } 
      } 
    }
  }
}


//===================================================================================
// set the lastReadRFID code
//===================================================================================
void setLastReadRFID(){
  for (int i = 0; i < CODE_SIZE; i++) {
    lastReadRFID[i] = code[i];        // copy the content of the last read RFID code into lastReadRFID
  }
  lastReadRFID[10] = 0;
  code[10] = 0;
}





I'll see in the future if I can host this test code on a public repository somewhere

Stats
compiler
Binary sketch size: 3176 bytes (of a 30720 byte maximum)
So this still leaves me 27544 bytes room, I'll see what will be left after I implemented all data logger logic.

pins
Currently I'm using digital pins 0, 2, 7, 10, 11, 12, 13; analog pins 4 and 5 and the 5V pin.
So 6 digital pins left and a few analog pins