This blog post does not relate to one of my own achievements. But I came across the this article and I found it inspirational.
woensdag 21 december 2011
vrijdag 16 december 2011
PC case overhaul
Now that I have my brand new, home made 19" rack; I'm moving the internals of my old pc to a new 19" rack mountable case.
Before starting the move, I backed up all the data that was on the PC. Yes, I didn't forget :-)
First I put my two patients on the operating table :-) .
As I'm having software RAID configured I needed to be sure to reconnect the drives in the same order as before. So I labeled the drives according to the connectors on the mother board.
Then I took a pic of the back of the PC to have an idea of how everything was setup before the move. I also took some further pictures of the connectors inside the PC.
Once I was assured that I had enough pictures, I disconnected all cables from the mother board. Once disconnected I moved the mother board to the new case, followed by the power supply.
One neat thing about the new case is that it contains sleds for the hard drives making mounting the drives much more easier
After reconnecting everything, I booted the machine and everything seems to run fine.
As a finishing touch I tried addeinga some blue CCFL's I ordered on ebay some time ago. Unfortunately one of the two was broken (either in transport or during one of my moves :-) ). So I added the remaining CCFL to the case. I'm still not sure how exactly I'm going to mount it, but below pictures give an idea how it might look.
Still some work to do, but, looking good so far.
Before starting the move, I backed up all the data that was on the PC. Yes, I didn't forget :-)
First I put my two patients on the operating table :-) .
As I'm having software RAID configured I needed to be sure to reconnect the drives in the same order as before. So I labeled the drives according to the connectors on the mother board.
Then I took a pic of the back of the PC to have an idea of how everything was setup before the move. I also took some further pictures of the connectors inside the PC.
Once I was assured that I had enough pictures, I disconnected all cables from the mother board. Once disconnected I moved the mother board to the new case, followed by the power supply.
One neat thing about the new case is that it contains sleds for the hard drives making mounting the drives much more easier
After reconnecting everything, I booted the machine and everything seems to run fine.
As a finishing touch I tried addeinga some blue CCFL's I ordered on ebay some time ago. Unfortunately one of the two was broken (either in transport or during one of my moves :-) ). So I added the remaining CCFL to the case. I'm still not sure how exactly I'm going to mount it, but below pictures give an idea how it might look.
Still some work to do, but, looking good so far.
zondag 20 november 2011
Garage Storage
My latest creation, a custom built garage storage. I helped build this for a friend of mine. It's nearly finished but I'll see if I can update the pics when it is completely finished.
I designed this using google SketchUp.
One side hosts the washing machine and the cloths dryer. The other side, at the bottom has some narrow storage next to what will become a shoe rack. On top there is some bigger storage foreseen, at this time it's still missing some boards though. To maximize the storage space, I indented the closet to 'embed' the light switches.
I choose to use multiplex (18mm thick) as it would make the whole storage solution much sturdier and stronger than using MDF.
Hopefully my next post will be about something non-wood shop related or people start thinking I'm a carpenter or something similar.
I designed this using google SketchUp.
One side hosts the washing machine and the cloths dryer. The other side, at the bottom has some narrow storage next to what will become a shoe rack. On top there is some bigger storage foreseen, at this time it's still missing some boards though. To maximize the storage space, I indented the closet to 'embed' the light switches.
I choose to use multiplex (18mm thick) as it would make the whole storage solution much sturdier and stronger than using MDF.
Hopefully my next post will be about something non-wood shop related or people start thinking I'm a carpenter or something similar.
donderdag 10 november 2011
DIY 19" server rack
A while ago I purchased Sun Fire V480. As this is a 19" mountable server case, I went looking online for cheap (preferably Sun microsystems) 19"server cabinets/racks. However this search remained unfruitfull. Either the cabinets or racks were too big to handle or too expensive to buy or ship. So I decided to make one myself.
I set out to make this rack in wood which is cheap and lightweight. After reading an article in Make magazine I even attempted to not use any metal material. After creating the sides the ol'fashioned way I eventually decided that using 'modern' materials like vises and angle irons would be much quicker and productive :-)
So after constructing the rack I attached 2 12U rack strips I bought via e-bay to the rack. As a test I mounted a network switch in my home made rack.
I added some wheels to the rack, to make it more movable. Afterwards I slid in the Sun Fire V480 an an empty rack mountable case (in the future I'll move the contents of my desktop to this case).
Before mounting the wheels I added two beams to the rack to prevent it from tipping forward too much,making it safer for me to slide out a server.
I set out to make this rack in wood which is cheap and lightweight. After reading an article in Make magazine I even attempted to not use any metal material. After creating the sides the ol'fashioned way I eventually decided that using 'modern' materials like vises and angle irons would be much quicker and productive :-)
So after constructing the rack I attached 2 12U rack strips I bought via e-bay to the rack. As a test I mounted a network switch in my home made rack.
I added some wheels to the rack, to make it more movable. Afterwards I slid in the Sun Fire V480 an an empty rack mountable case (in the future I'll move the contents of my desktop to this case).
Before mounting the wheels I added two beams to the rack to prevent it from tipping forward too much,making it safer for me to slide out a server.
dinsdag 26 juli 2011
Arduino RFID project talk tape lost
Just got informed by one of the organizers of newline conference of the whitespace hackerspace that they can't find back the recording of my talk Bringing logic to a gym.
BUMMER
So I guess that I should have brought my own recording material.
BUMMER
So I guess that I should have brought my own recording material.
zondag 24 juli 2011
Standing desk - part 2
So what to do with your old desk when you made yourself a new standing desk? Throw it away?
Nope,
just put a board underneath it,
add some wheels,
throw some file cabinets on the board,
put your tools on the cabinets
and TADA!!!!!!
a small work bench that you roll out whenever you need some extra space and you don't want to clutter up your standing desk :-D
Nope,
just put a board underneath it,
add some wheels,
throw some file cabinets on the board,
put your tools on the cabinets
and TADA!!!!!!
a small work bench that you roll out whenever you need some extra space and you don't want to clutter up your standing desk :-D
donderdag 21 juli 2011
Standing desk - part 1
Just finished the base version of my standing desk. It still needs some finishing touches and I still have to throw my gear back onto the desk. But here are some shots of my new *achum* work of art.
The base is mostly made up of some 2by4s and some angle iron and the top is a door I had laying around.
It's dimensions: Height 105cm, Depth 78cm & Width 200cm
Follow up of this blog post is here.
The base is mostly made up of some 2by4s and some angle iron and the top is a door I had laying around.
It's dimensions: Height 105cm, Depth 78cm & Width 200cm
Follow up of this blog post is here.
zondag 29 mei 2011
Ongoing work
Hello all
I'm currently over my head in work and preparing for my exam japanese, so I have been unable to find time to blog about anything. However these are the projects that are currently ongoing/just started and for which you can expect some posts in a week or two:
I'm still waiting for some people to post the talk I gave about my Arduino project at Newline on youtube, so I can share it with you.
So, I hope to be blogging again soon.
I'm currently over my head in work and preparing for my exam japanese, so I have been unable to find time to blog about anything. However these are the projects that are currently ongoing/just started and for which you can expect some posts in a week or two:
- My Arduino security system project (I recently got an arduino Mega so I can expand my project a bit)
- A standing desk project from a door I had laying around from my house renovation
- A 19" 12U server rack made from two-by-fours
- An attempt for a home made aluminium pan and skillet organizer
- A small solar energy harvesting project
I'm still waiting for some people to post the talk I gave about my Arduino project at Newline on youtube, so I can share it with you.
So, I hope to be blogging again soon.
donderdag 31 maart 2011
My first Arduino project - part 7
I have currently split up the logic in two parts:
- one sketch contains the logic for the RFID reader, checking the administrative data on the SD card and logging to the SD card
- a second sketch to manage the content of the SD card (work ongoing for the moment)
These two sketches are uploaded to my github account.
I needed to split up the logic over two sketches as I ran into problems while trying to keep everything in one sketch. My Arduino seemed to grind to a halt when I started to call some of the data management logic that I already implemented. In the future I'll attempt putting all the logic back in one sketch, but for now I'll try to keep the development up to speed as much as possible
I haven't posted in a while as I was preparing to talk about my project on the newline event at the whitespace hackerspace in ghent. You can find my presentation, in openoffice format, in the doc directory on my github repository.
In the coming week I hope to complete the data management sketch. I'll keep you posted
vrijdag 18 maart 2011
My first Arduino project - part 6
Using NewSoftSerial
Until now, each time I had to upload the latest sofware to the Arduino I had to disconnect the RFID reader as it used the RX pin. Using NewSoftSerial library I can emulate RX and TX on other pins. So I use digital pin 8 & 9 to do this. Pin 9 is not really used as no data is send to the RFID reader, but the NewSoftSerial constructor only seems to take both RX and TX.
This change is also needed as I am going to try and interface the arduino with my laptop using USB.
You can download this latest version from my github repository:
git://github.com/NAVNi-stuff/arduino-rfid-datalog.git
Until now, each time I had to upload the latest sofware to the Arduino I had to disconnect the RFID reader as it used the RX pin. Using NewSoftSerial library I can emulate RX and TX on other pins. So I use digital pin 8 & 9 to do this. Pin 9 is not really used as no data is send to the RFID reader, but the NewSoftSerial constructor only seems to take both RX and TX.
This change is also needed as I am going to try and interface the arduino with my laptop using USB.
You can download this latest version from my github repository:
git://github.com/NAVNi-stuff/arduino-rfid-datalog.git
Stats
compiler
Binary sketch size: 20692 bytes (of a 30720 byte maximum)
pins
Currently I'm using digital pins 2, 7, 8, (9), 10, 11, 12, 13; analog pins 4 and 5 and the 5V pin.
So 6 digital pins left and a few analog pins
woensdag 16 maart 2011
My first Arduino project - github repository
Just a quick blog. From now on, the code for this project will be hosted on github.
Check it out at:
git://github.com/NAVNi-stuff/arduino-rfid-datalog.git
This will be a lot easier than copy-pasting my code and will make my blog post a bit more concise.
Have fun
Check it out at:
git://github.com/NAVNi-stuff/arduino-rfid-datalog.git
This will be a lot easier than copy-pasting my code and will make my blog post a bit more concise.
Have fun
zaterdag 12 maart 2011
My first Arduino project - part 5
It has been a while since my last post. But in the mean time I added up some changes my Arduino project.
Dated log files
I added some code changes to make log entries end up in a log file specific for that day. This might make manual lookup and cleanup a bit easier.
Validating RFID token
Dated log files
I added some code changes to make log entries end up in a log file specific for that day. This might make manual lookup and cleanup a bit easier.
For validating the RFID token that was read, I wanted to have an 'allowed.csv' file in the admin directory. This is different from what I logged in the previous blog post. I want to reduce the number of files used in this setup. In this way I hope the number of file I/O operations gets limited as much as possible.
The content for this 'allowed.csv' should be generated on the PC that will manage this system and/or should get managed via command through a serial connection to the Arduino (this is a problem I will tackle in a future blog post).
The structure of the 'allowed.csv' file will be the following:
RFID code,end date, start date,first name,last name,buffer date,,
- RFID code: the code of the RFID token to which the following information applies
- end and start date: keeps track of the current subscription of a user.
- first and last name: foreseen to provide a nicer output in the future.
- buffer date: is the end time of the user's subscription + a buffer e.g. one week, to allow the user to pay his or her new subscription without being locked out from the gym. Currently the Arduino sketch does not yet take this buffer into accout.
This is my latest code containing the dated log files and validating the RFID tokens against the content of the allowed.csv file:
#include <SdFat.h>
#include <Wire.h>
#include <RTClib.h>
int DOOR = 7;
int RFID_ENABLE = 2;
int CODE_SIZE = 10;
int ARRAY_SIZE = 11;
char DATE_SEPARATOR = '/';
char TIME_SEPARATOR = ':';
char DATE_AND_TIME_SEPARATOR = '-';
char CSV_SEPARATOR = ',';
int bytesRead = 0;
char lastReadRFID[] = "0000000000";
char code[] = "0000000000";
DateTime lastTimeStamp;
int elementIdx = 0;
String tokenCode = "";
String endDateStr = "";
String tmpString = "";
boolean equalsReadToken = false;
char tmpChar;
int converted = 0;
char allowedFileName[] = "allowed.csv";
int csvSeparatorCount;
String logFileName;
//The RTC related object
RTC_DS1307 RTC;
DateTime now;
//The SD card related objects
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile accessLogDir;
SdFile adminDir;
SdFile logFile;
SdFile allowedFile;
//===================================================================================
// 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(DOOR, OUTPUT); // Set digital pin 13 as OUTPUT to connect it to door opener
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() {
now = RTC.now();
activateRFID();
readRFID();
if (bytesRead == CODE_SIZE) {
deActivateRFID();
handleReadRFID();
}
}
//===================================================================================
// 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[13];
name[12] = '\0';
constructLogFileName();
logFileName.toCharArray(name,13);
logFile.open(&accessLogDir, name, O_CREAT | O_WRITE | O_APPEND);
if (!logFile.isOpen()) {
Serial.print("Unable to open log file ");
Serial.println(name);
}
}
}
//===================================================================================
// construct the correct file name, containing the time stamp, for the log file of today
//===================================================================================
void constructLogFileName() {
logFileName = String(now.year());
int month = now.month();
if (month < 10) {
logFileName += 0;
}
logFileName += month;
int day = now.day();
if (day < 10) {
logFileName += 0;
}
logFileName += day;
logFileName += ".csv";
}
//===================================================================================
// handle the read RFID tag
//===================================================================================
void handleReadRFID(){
if (codesAreDifferent(now) ) {
openLogFile();
if (userIsAllowed()) { //if rfid token allowed
logAccessToSerial(true); //log to serial out
logAccessToLogFile(true);//write to log file
digitalWrite(DOOR, HIGH); // unlock the door
delay(2000); // wait for 2 seconds
setLastReadRFID();
digitalWrite(DOOR, LOW); // lock the door
}
else {
logAccessToSerial(false); //log to serial out
logAccessToLogFile(false); //log not allowed user to log file
delay(2000); // wait for 2 seconds
}
closeLogFile();
}
}
//===================================================================================
// logs the access to the log file
//===================================================================================
void logAccessToLogFile(boolean isAccessAllowed) {
if (logFile.isOpen()) {
if (!isAccessAllowed) {
logFile.print("NOT ALLOWED - ");
}
logFile.print(now.year(), DEC);
logFile.print(DATE_SEPARATOR);
logFile.print(now.month(), DEC);
logFile.print(DATE_SEPARATOR);
logFile.print(now.day(), DEC);
logFile.print(DATE_AND_TIME_SEPARATOR);
logFile.print(now.hour(), DEC);
logFile.print(TIME_SEPARATOR);
logFile.print(now.minute(), DEC);
logFile.print(TIME_SEPARATOR);
logFile.print(now.second(), DEC);
logFile.print(CSV_SEPARATOR); // possibly a good TAG
logFile.println(code); // print the TAG code
}
else {
Serial.println("Unable to write to the log file on the SD card.");
}
}
//===================================================================================
// logs the access to serial output
//===================================================================================
void logAccessToSerial(boolean wasAllowed) {
Serial.print(now.year(), DEC);
Serial.print(DATE_SEPARATOR);
Serial.print(now.month(), DEC);
Serial.print(DATE_SEPARATOR);
Serial.print(now.day(), DEC);
Serial.print(DATE_AND_TIME_SEPARATOR);
Serial.print(now.hour(), DEC);
Serial.print(TIME_SEPARATOR);
Serial.print(now.minute(), DEC);
Serial.print(TIME_SEPARATOR);
Serial.print(now.second(), DEC);
Serial.print(" RFID code "); // possibly a good TAG
Serial.print(code); // print the TAG code
Serial.print(" -> access ");
if (wasAllowed) {
Serial.println("GRANTED");
} else {
Serial.println("DENIED");
}
}
//===================================================================================
// checks whether the read RFID token is of a user that is still allowed access
//===================================================================================
boolean userIsAllowed() {
if (adminDir.isOpen()) {
allowedFile.open(&adminDir, allowedFileName, O_RDONLY);
if (allowedFile.isOpen()) {
equalsReadToken = false;
int16_t c;
while ((c = allowedFile.read()) > 0){
if ((char)c == CSV_SEPARATOR) {
switch(elementIdx) {
case 0:
if (tmpString.equals(String(code))) {
equalsReadToken = true;
Serial.print("token ");
Serial.print(tmpString);
Serial.println(" found in allowed file");
} else {
equalsReadToken = false;
}
break;
case 1:
if (equalsReadToken == true) {
Serial.print("evaluate against date: ");
Serial.println(tmpString);
if (equalsReadToken) {//only check the end date for the corresponding entry for the read RFID code
if(isNowBeforeEndDate(tmpString)) {
return true;
}
}
}
break;
}
tmpString = "";
csvSeparatorCount++;
if (csvSeparatorCount == 2) {
csvSeparatorCount = 0;
elementIdx = 0;
} else {
elementIdx++;
}
} else {
csvSeparatorCount = 0;
if (((char)c != '\n')&&((char)c !='\r')) { //prevent newline chars to end up in tmpString
tmpString += (char)c; //accumulate the chars to eventually hold the contents of one element
}
}
}
allowedFile.close();
} else {
Serial.println("allowed file is not open");
}
} else {
Serial.println("admin dir is not open");
}
return false;
}
//===================================================================================
// checks whether current time has passed the given subscription end date
//===================================================================================
boolean isNowBeforeEndDate(String endDateString) {
if (((int)now.year()) < getInteger(endDateString.substring(0,4))) {
return true;
} else if (((int)now.year()) == getInteger(endDateString.substring(0,4))) {
if (((int)now.month()) < getInteger(endDateString.substring(5,7))) {
return true;
} else if (((int)now.month()) == getInteger(endDateString.substring(5,7))){
if (((int)now.day()) <= getInteger(endDateString.substring(8))) {
return true;
}
}
}
return false;
}
int getInteger(String intAsString) {
converted = 0;
for (int i = 0; i < intAsString.length(); i++) {
converted *= 10;
tmpChar = intAsString.charAt(i);
converted += (tmpChar - '0');//convert from ascii char to corresponding int
}
return converted;
}
//===================================================================================
// checks wether the current code is different from the previously read code
//===================================================================================
boolean codesAreDifferent(DateTime now){
for (int i = 0; i < CODE_SIZE; i++) {
if (code[i] != lastReadRFID[i]) {
lastTimeStamp = now;
return true;
}
else {//if more than one minute has passed same token can be reused
if ((lastTimeStamp.year() <= now.year())
&& (lastTimeStamp.month() <= now.month())
&& (lastTimeStamp.day() <= now.day())
&& (lastTimeStamp.hour() <= now.hour())
&& (lastTimeStamp.minute() < now.minute())) {
lastTimeStamp = now;
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 still need to do some more testing and debugging, but here is some example output (all dates are in format yyyy/mm/dd):
Stats
compiler
Binary sketch size: 18684 bytes (of a 30720 byte maximum)
#include <SdFat.h>
#include <Wire.h>
#include <RTClib.h>
int DOOR = 7;
int RFID_ENABLE = 2;
int CODE_SIZE = 10;
int ARRAY_SIZE = 11;
char DATE_SEPARATOR = '/';
char TIME_SEPARATOR = ':';
char DATE_AND_TIME_SEPARATOR = '-';
char CSV_SEPARATOR = ',';
int bytesRead = 0;
char lastReadRFID[] = "0000000000";
char code[] = "0000000000";
DateTime lastTimeStamp;
int elementIdx = 0;
String tokenCode = "";
String endDateStr = "";
String tmpString = "";
boolean equalsReadToken = false;
char tmpChar;
int converted = 0;
char allowedFileName[] = "allowed.csv";
int csvSeparatorCount;
String logFileName;
//The RTC related object
RTC_DS1307 RTC;
DateTime now;
//The SD card related objects
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile accessLogDir;
SdFile adminDir;
SdFile logFile;
SdFile allowedFile;
//===================================================================================
// 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(DOOR, OUTPUT); // Set digital pin 13 as OUTPUT to connect it to door opener
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() {
now = RTC.now();
activateRFID();
readRFID();
if (bytesRead == CODE_SIZE) {
deActivateRFID();
handleReadRFID();
}
}
//===================================================================================
// 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[13];
name[12] = '\0';
constructLogFileName();
logFileName.toCharArray(name,13);
logFile.open(&accessLogDir, name, O_CREAT | O_WRITE | O_APPEND);
if (!logFile.isOpen()) {
Serial.print("Unable to open log file ");
Serial.println(name);
}
}
}
//===================================================================================
// construct the correct file name, containing the time stamp, for the log file of today
//===================================================================================
void constructLogFileName() {
logFileName = String(now.year());
int month = now.month();
if (month < 10) {
logFileName += 0;
}
logFileName += month;
int day = now.day();
if (day < 10) {
logFileName += 0;
}
logFileName += day;
logFileName += ".csv";
}
//===================================================================================
// handle the read RFID tag
//===================================================================================
void handleReadRFID(){
if (codesAreDifferent(now) ) {
openLogFile();
if (userIsAllowed()) { //if rfid token allowed
logAccessToSerial(true); //log to serial out
logAccessToLogFile(true);//write to log file
digitalWrite(DOOR, HIGH); // unlock the door
delay(2000); // wait for 2 seconds
setLastReadRFID();
digitalWrite(DOOR, LOW); // lock the door
}
else {
logAccessToSerial(false); //log to serial out
logAccessToLogFile(false); //log not allowed user to log file
delay(2000); // wait for 2 seconds
}
closeLogFile();
}
}
//===================================================================================
// logs the access to the log file
//===================================================================================
void logAccessToLogFile(boolean isAccessAllowed) {
if (logFile.isOpen()) {
if (!isAccessAllowed) {
logFile.print("NOT ALLOWED - ");
}
logFile.print(now.year(), DEC);
logFile.print(DATE_SEPARATOR);
logFile.print(now.month(), DEC);
logFile.print(DATE_SEPARATOR);
logFile.print(now.day(), DEC);
logFile.print(DATE_AND_TIME_SEPARATOR);
logFile.print(now.hour(), DEC);
logFile.print(TIME_SEPARATOR);
logFile.print(now.minute(), DEC);
logFile.print(TIME_SEPARATOR);
logFile.print(now.second(), DEC);
logFile.print(CSV_SEPARATOR); // possibly a good TAG
logFile.println(code); // print the TAG code
}
else {
Serial.println("Unable to write to the log file on the SD card.");
}
}
//===================================================================================
// logs the access to serial output
//===================================================================================
void logAccessToSerial(boolean wasAllowed) {
Serial.print(now.year(), DEC);
Serial.print(DATE_SEPARATOR);
Serial.print(now.month(), DEC);
Serial.print(DATE_SEPARATOR);
Serial.print(now.day(), DEC);
Serial.print(DATE_AND_TIME_SEPARATOR);
Serial.print(now.hour(), DEC);
Serial.print(TIME_SEPARATOR);
Serial.print(now.minute(), DEC);
Serial.print(TIME_SEPARATOR);
Serial.print(now.second(), DEC);
Serial.print(" RFID code "); // possibly a good TAG
Serial.print(code); // print the TAG code
Serial.print(" -> access ");
if (wasAllowed) {
Serial.println("GRANTED");
} else {
Serial.println("DENIED");
}
}
//===================================================================================
// checks whether the read RFID token is of a user that is still allowed access
//===================================================================================
boolean userIsAllowed() {
if (adminDir.isOpen()) {
allowedFile.open(&adminDir, allowedFileName, O_RDONLY);
if (allowedFile.isOpen()) {
equalsReadToken = false;
int16_t c;
while ((c = allowedFile.read()) > 0){
if ((char)c == CSV_SEPARATOR) {
switch(elementIdx) {
case 0:
if (tmpString.equals(String(code))) {
equalsReadToken = true;
Serial.print("token ");
Serial.print(tmpString);
Serial.println(" found in allowed file");
} else {
equalsReadToken = false;
}
break;
case 1:
if (equalsReadToken == true) {
Serial.print("evaluate against date: ");
Serial.println(tmpString);
if (equalsReadToken) {//only check the end date for the corresponding entry for the read RFID code
if(isNowBeforeEndDate(tmpString)) {
return true;
}
}
}
break;
}
tmpString = "";
csvSeparatorCount++;
if (csvSeparatorCount == 2) {
csvSeparatorCount = 0;
elementIdx = 0;
} else {
elementIdx++;
}
} else {
csvSeparatorCount = 0;
if (((char)c != '\n')&&((char)c !='\r')) { //prevent newline chars to end up in tmpString
tmpString += (char)c; //accumulate the chars to eventually hold the contents of one element
}
}
}
allowedFile.close();
} else {
Serial.println("allowed file is not open");
}
} else {
Serial.println("admin dir is not open");
}
return false;
}
//===================================================================================
// checks whether current time has passed the given subscription end date
//===================================================================================
boolean isNowBeforeEndDate(String endDateString) {
if (((int)now.year()) < getInteger(endDateString.substring(0,4))) {
return true;
} else if (((int)now.year()) == getInteger(endDateString.substring(0,4))) {
if (((int)now.month()) < getInteger(endDateString.substring(5,7))) {
return true;
} else if (((int)now.month()) == getInteger(endDateString.substring(5,7))){
if (((int)now.day()) <= getInteger(endDateString.substring(8))) {
return true;
}
}
}
return false;
}
int getInteger(String intAsString) {
converted = 0;
for (int i = 0; i < intAsString.length(); i++) {
converted *= 10;
tmpChar = intAsString.charAt(i);
converted += (tmpChar - '0');//convert from ascii char to corresponding int
}
return converted;
}
//===================================================================================
// checks wether the current code is different from the previously read code
//===================================================================================
boolean codesAreDifferent(DateTime now){
for (int i = 0; i < CODE_SIZE; i++) {
if (code[i] != lastReadRFID[i]) {
lastTimeStamp = now;
return true;
}
else {//if more than one minute has passed same token can be reused
if ((lastTimeStamp.year() <= now.year())
&& (lastTimeStamp.month() <= now.month())
&& (lastTimeStamp.day() <= now.day())
&& (lastTimeStamp.hour() <= now.hour())
&& (lastTimeStamp.minute() < now.minute())) {
lastTimeStamp = now;
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 still need to do some more testing and debugging, but here is some example output (all dates are in format yyyy/mm/dd):
2011/3/12-17:25:7 RFID code 31003290D2 -> access DENIED
2011/3/12-17:25:9 RFID code 31003290D2 -> access DENIED
2011/3/12-17:25:12 RFID code 310032A667 -> access DENIED
2011/3/12-17:25:21 RFID code 3D0073C215 -> access DENIED
token 3D00750CA8 found in allowed file
evaluate against date: 2011/04/03
2011/3/12-17:25:27 RFID code 3D00750CA8 -> access GRANTED
2011/3/12-17:25:33 RFID code 3D001E0A78 -> access DENIED
token 3D001E0A78 found in allowed file
evaluate against date: 2011/12/03
2011/3/12-17:25:35 RFID code 3D001E0A78 -> access GRANTED
token 3D0073E5DC found in allowed file
evaluate against date: 2011/01/04
2011/3/12-17:25:42 RFID code 3D0073E5DC -> access DENIED
token 310031B7D9 found in allowed file
evaluate against date: 2011/05/10
2011/3/12-17:25:53 RFID code 310031B7D9 -> access GRANTED
The first 4 lines of the above output shows how3 tokens are read by the RFID reader that are not listed in the allowed.csv file. Somehow one token gets read in twice, which is still not the end of the world.
The following entries show tags that are read who are in the allowed.csv file. All these, except the token with id '3D0073E5DC' have an end date in the future. All these are thus granted access (except for token with id '3D0073E5DC').
What's next?
Well one of the first things on my to-do list is the see if I can make use of softserial to read the RFID tokens. This would allow me to reflash my arduino without having to disconnect the RFID reader each time.
Next to this I will also investigate whether I can still attach an LCD to the arduino to output some info regarding the user that wants access to the gym.
And thirdly, this functionality is very basic. I would hate if the users of this system would have to extract the RFID card each time subsctiption info needs to be changed. So I'll see if the user can manipulate the subscription data via an USB connection.
And last but not least, I'm gonna start looking for a place to host my code. My blog post tends to get too long because I copy paste all my code in here.
So, I'm not short of work :-)
Stats
compiler
Binary sketch size: 18684 bytes (of a 30720 byte maximum)
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
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
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.