Star Trek control panel

February 5, 2017

This is one of those things that starts out as ridiculous but just might work.  We’re putting in a door at our hackerspace, a pocket door, so obviously it has to be pneumatic.  I was asked how to control this door, and I had one answer: Star Trek Electronic Door Chime Think Geek wants $30, Ebay wants $28, the cheapest is Amazon at $25 and free shipping.  I ordered one right away with the intention of converting it for use as our door controller.

looks unmolested, doesn’t it?

I knew I would have to do three things:

  1. make the sounds triggerable on command
  2. take the inputs from the button and switch separate from their original use
  3. control that LED
  4. (optional) do something cool with that translucent bit at the top, maybe an RGB LED?

Let’s investigate the guts.

brb learning kicad

Unfortunately I did not take a picture before tearing into it, so here’s my recreation.  Top left, board with a single LED.  Below that is a board with a single membrane switch and that passes through the LED wires.  To the far left are two PIR sensors.  Out the bottom is the connection to the battery box. The right side has the speaker and volume switch.  The top right has the front slider switch.  The middle of the board has the switch to select which PIR sensor will activate the sound.

I didn’t really go into this with a plan, but step by step I made this sound board sing and dance.  The first thing was to pin out the PIR sensors:

didn’t use their own copper traces….

PIR sensors:
s1=blue=common
d1=orange=normally open (3.61v)
g1=green=normally closed (0v)
s2=white=common
d2=purple=normally open (3.61v)
g2=grey=normally closed (0v)

That’s that.  I found that I could replace one with a microswitch and activate the circuit, perfect! I had to tweak the timings once I got it hooked into the microcontroller but I could control them digitally, good enough!

not PIR, this is the new microswitch

Next was the front switch board:

switch board
7=0v
up=woosh
7-8
center=none
7-9
bottom=red alert
7-10

That’s fortunate, there’s one common and three different things to be pulled down in succession.  I decided to use the trick of defining a pin as an input to make it floating, which worked great.  For inputs I used three separate pins with pullups to detect which was being pulled low.

Last was the LED and button boards:

LED board
1=led positive (4.4v, floating battery)
2=led ground (current limiting resistor inline, switched)
resistor removed and shorted over

button board
1 – 6
2 – 3
4 – 5 button
5=4.38v (floating input)
4=0v

The decode here is that the LED gets tied high, there is a SMT resistor on the main board, and the ground is switched.  The button is on pin 5 and pin 4 is ground, so all I have to do is pull that low to activate it with a microcontroller.  I really don’t like how that LED is wired so I removed the resistor on the board, jumpered over it, and wired the switched pin (3 on the board) to an input on the microcontroller (pulled up).  I then wired the LED to ground and one of my GPIO through a 100 ohm resistor I added.  The button also got wired to me as an input.

Here’s the story so far:

Outputs:

  1. LED
  2. simulate front switch
  3. simulate front button
  4. simulate PIR sensor

Inputs:

  1. sound board output for LED
  2. front switch
  3. front button
  4. extra button from me (to trigger as if it was a PIR sensor)

power circuit

In this configuration I could essentially man-in-the-middle the entire board, but I had one limitation.  The red alert is supposed to be a burglar alarm for a cubicle (just like the hail is supposed to be a doorbell) and thus cannot be stopped mid cycle.  I decided the best way to fix this was to wire a couple of transistors so that I could drop power to the whole board and thus kill any sound mid-play.  This is a very crude solution, but seeing as my music box is literally 2 epoxy blob chips, I’m going to just call this good enough as well.

The jumper near the label R19 is mine (for that resistor I removed) and the pin the PIR chip out put is actually pin 2, right under that white dot

Now I have even more control over the board than I did to start with, I have written code that would simulate an unmodified board (no PIR though) and augment it with the ability to interrupt the sound being played.  If you really really wanted to you could take the PIR sensor in as analog and output it as PWM and maybe it would work.  I didn’t bother because this device has 2 PIR sensors and a switch on the back to choose between left, right, or both to activate the sound.  If you want a PIR sensor, just leave one in and connect the arduino in place of the other.  You can even switch between them to preserve as much original functionality as possible.

as wired in final assemble

Somewhere along the line I thought I broke my code for simulating the PIR sensor (spoiler: don’t #define the same variable twice and expect it to work).  My remedy for this was to look into the TM2291 chip connected to the horrorshow of capacitors and resistors.  This chip turned out to be a dedicated PIR sensor reader chip.  Most of you won’t have ever dealt with this because you but modules that have something that does this onboard, but this device had 2 PIR sensors MUXed into one driver chip… I did not want to decode that.  I found an example circuit and picked the pin I thought must be the output to the sound chip.  After I desoldered the chip and connected in place of it everything worked (no it didn’t. but it was around this time I found my code bug).  Now I could also be rid of that switch on the back of the PCB.

polarity marked, it’s important

With the switch desoldered I had room to just about fit my FTDI header out the back.  One important thing: the RAW and the Vin on the FTDI header are not as connected as you might think, which led to some head scratching from me.  Here is the final layout as I have it now.

kicad’s going slowly

The diode is so the batteries don’t get charged from the ftdi header (but it can still power the unit).  The switch at the top is mine for triggering things instead of the PIR (glued where the PIR was).  You can see the NPN/PNP circuit I mentioned before to kill power to the board (and the power for that coming from the FTDI input, not any other pin on the pro mini).  The LED has a new resistor, and the button boards now go to the pro mini.  The arduino has a bunch of control lines running to the original board, but the volume switch was left alone.  This literally shorts out a series resistor with the speaker, I didn’t think it was important to make that variable.  You can see how I now have central control of all the inputs and outputs, which was the plan all along.

removed parts (and all the shitty wire)

The code I think this will be running in production is the command based one I uploaded here.  It’s overly modularized, but it works well.  Another hint: 8Mhz does not divide equally to give close enough to 115200 baud for input, even though the output comes through readable.  That’s a fuckin’ pain to diagnose.  I used 9600 this one time, as you can see.  My functions:

WOOSH does exactly that, plays that sound.
ALERT does the same as WOOSH, except it will be left in alert mode so the LED will blink
HAIL plays the hail sound
NONE sets the virtual switch to no sound, but can be used to cancel the blinking without playing a sound
KILL kills the current playing audio
ON turns the LED on
OFF turns the LED off
PASS passes through the LED state from the board, useful in alert standby mode or to see the blinking while playing the red alert sound
BLINK sets the board to red alert mode, does not trigger sound, LED blinks slowly
SWITCH returns the state of the front switch (0, 1, or 2)

The button on the front and the new button on the side asynchronously send 3 or 4 out serial, but they are debounced and only do it once per press.

That square board is mounted 180* off, and I cut the post/glued in the speaker to accommodate it.  Completely un-needed.

That’s it, I’m done, it works.  I anticipate this (maybe two) being serially linked to an ESP8266 (it wants 4.5 to 5v power, but 3.3v serial is fine) which will run the solenoids, read pressures, and talk MQTT.  If I’m really hurting for pins I can make the second one respond to different commands, make it talk different numbers, and hook them in parallel with a couple diodes, but that’s silly…

the code is here.

the rest of the pictures are here.

mini-sucker (gravity sucker)

February 5, 2017

This past weekend (this post has been in the queue for a while…) there was the Ferndale Pig and Whiskey Festival.  I spend a lot of time at i3Detroit and was convinced to help out at this event. We have a large device aptly named the moneysucker as it consists mostly of a water cooler bottle, a shop-vac and a long tube.  That particular one is triggered by a non-contact mains switch and has a spiral of lights running up the tube.  Over the years that has been made sturdier and nicer, but now it’s hard to move and impossible to shrink without essentially breaking it and rebuilding it after.  The one I built is a sucker in name only; it is a water cooler jug, an arduino, a neopixel strip, and an IR presence sensor.

The first version I built used an arduino pro mini, but that died just as we were supposed to leave for the event.  My best guess is the little SOT23-5 linear regulator on the chinese knock-off board was not up to the task of stepping 12 volts down to 5 (even though I was not powering anything but the ir sensor and arduino with it).  The fix was to replace it with a full-size real-deal arduino, no expense was spared (although it wasn’t my expense).  The IR sensor had the LEDs pointed straight out, and I decided that I’d rather have them mounted at a right angle to make the board mounting easier.  That was a bit of a mistake.  Those LEDs are very sensitive.  All the sensor is is a comparator and a potentiometer to set the bias, so the level it triggers at can be set (theoretically a distance).  When I unmounted the LEDs the alignment became somewhat of an issue.  If I were to do it again I would convert the sensor to a beam break sensor, and heatshrink around the 5mm LED body to keep directionality.  This would invert my signal, but the pin change interrupt does not care.  The pin change interrupt is indifferent to your small mortal worries.

The code was a modified version of the adafruit strandtest.ino example expanded to the length of strip I was using.  I chose a default state I liked (the rainbow and rainbowCycle subroutines) and one I liked for the instance of having money inserted (theaterChase, white) and pulled out the rest of the calls.  The interrupt is triggered on a pin state change  so no mater what I use for a sensor (reflective, beam break, etc…) it will trigger a blinking state.  The theaterChase subroutine was also tweaked to be more intense and shorter.  The delay passed in the subroutine call was shortened from 50 to 20,  and the number of cycles was shortened to 3 instead of 10.

the code is here.

the rest of the pictures are here.

serialderp – completely non-autonomous arduino robot

August 11, 2016

This is an extension of the pervious robot, derpderp.  A friend wanted something to use for makerfaire Detroit to show off a bluetooth attached armband.  That sensor interfaces with python on a raspberry pi 3, and since I have some experience making python controlled robot platforms I volunteered to help.

The code I wrote just conflates the original derpderp code (which I use to drive the robot) with the wheelchair robot code that I use as a framework.  The additional things are setting the servo angle (what used to be the lidar platform), turning the light on and off (added to the lidar platform), and getting the temperature and humidity from an onboard sensor.  When making this change I found that the battery wasn’t working so I dug up the charger.  Then I found it wasn’t charging… so I tore apart the charger and bypassed the fuse.  It still wasn’t charging so I tore apart the battery and bypassed the fuse.  Then it finally worked, but that battery was so anemic anyway I decided to upgrade it.

The original battery was a 9.6v 500mAh battery, I replaced it with a lithium jump pack.  I had bought this jump pack for my car with an unreliable battery (which I eventually replaced) and somehow ended up running it over in my driveway.  I don’t even remember taking it out of my car and the next day it’s in pieces on the driveway.  After looking it over it still looks intact.  The plastic is shattered and the box that goes between the battery and the jumper cable clips has been crushed and the open frame relays inside will never function again.  That box, as far as I can tell, has a microcontroller in it that just supervises the closing of a bunch of little parallel relays to connect the care battery in parallel with the lithium pack (no protection whatsoever).  To me that means that I now have a connector and cable that will give me an unregulated voltage that I am glad to use for my motor power.  The charger board for the jump pack has a variable dc-dc on it to make different voltages, a usb port, and a flashlight.  I took the flashlight off and drove it at about 20mA with a resistor and a FET off the regulated 5V I’m making on the robot.  That’s the headlamp on the robot and it’s steerable with the servo as well as PWMable.  The control board is now only useful as a charger for the bare lithium pack as the battery voltage is not passed through it before hitting my robot.

The commands are:

sCmd.addCommand(“HUM”, humCMD); //no args

sCmd.addCommand(“LIGHT”, lightCMD); //0 – 255

sCmd.addCommand(“TEMP”, tempCMD); // if ‘1’ then F, if ‘0’ then C

sCmd.addCommand(“TURN”, turnCMD); // sets turn -1000 to 1000

sCmd.addCommand(“SPEED”, speedCMD); // sets speed -1000 to 1000

sCmd.addCommand(“ANGLE”, angleCMD); // sets angle of servo, 20 to 160

That’s a fairly easily controlled robot.  I don’t know exactly how the project went because I was on vacation for the week leading up to makerfaire, but there were some problems sending the commands from a raspberry pi (and I still don’t know why, it was over USB).

code is here.

pics are here.

autonomous version is here.

derpderp – Autonomous arduino-based robot

July 15, 2016

Here is yet another autonomous little robot that rolls around avoiding walls, this one was also made for a hackathon much like the venerable wheelchair robot.  The difference here is that insistence that code be developed on an SBC slowed development to the point that many features had to be dropped.  The point of this robot is to venture into unknown territory and send back sensor readings (distance, temperature, humidity, light level, barometric pressure) so you don’t have to go in blind.  The need for autonomy come from us not having a camera with which we could drive the robot.  The goals as best as I can remember:

  • autonomous exploring (drive forward, avoid walls)
  • wireless telemetry
  • large array of sensors
  • manual over-ride
  • make duck noises

The only things that got implemented out of these were the first two.  I put a lot of effort into making the only touchscreen we had (a SainSmart 2.8 inch TFT LCD) work as a UI for telemetry and control but was no able to make it work.  I still cannot even after buying the adapter for the arduino mega.  Usually I’m able to get around shitty documentation by digging through the code of the libraries, but this one beat me.

The large number of sensors… We had a BH1750 Digital Light Sensor, never got it to work.  We had a BMP180 Barometric Pressure/Temperature/Altitude Sensor, didn’t have time to make it work.  An HC-SR04 ultrasonic sensor, also never made it do anything.  A DHT22, the simplest sensor we could have installed… nope.  So, we had absolutely no sensor readings but it had a bunch of stuff plugged in so it looked impressive.

The actual navigation was done using a LIDAR Lite, which is a really cool i2c lidar sensor.  This was borrowed from a FIRST team and unfortunately no longer resides with the robot.  I thought about getting another one, but it’s just too expensive to put on a robot that I actually have no use for.  The chassis was the absolute biggest, most expensive RC car that walmart had to offer.. a New Bright 1:10 Radio Control Ford Raptor Truck, Black/Green.  No, I wasn’t much impressed either.  For a chassis this had loose ball joints, an anemic little lithium battery pack, and a motor that was rather poorly geared for torque.  But if the chassis was perfect then we’d have no fun accounting for it later.  The motor control comes from a Sparkfun Ludus Protoshield (which I got in a ding/dent deal and is not labeled like that on mine).  The control is just two-bit direction and a pwm line for speed.

Sparkfun ProtoCAT board

Being in the IEEE lab at MTU we had the advantage of a 3d printer.  They may have taken away the band saw and drill press because someone took off the safety switches and didn’t either restore them or hide them well enough, but we could still make small plastic parts over the course of several hours.  We made a bracket to hold the LIDAR to the servo and cut up a chunk of an old computer case to affix the servo to the chassis.  Now we had a chassis with enough sensor to let it move.  You may notice this is the exact same setup as the wheelchair robot with the exception that it’s smaller and much lower power.  When you have a hammer and all that…  It should not surprise you that the same person wrote the code for that as this one.

The wireless part was going to be a whole custom interface between two esp8266s to allow for touch-screen control and telemetry… Well, when it came right down to it I flashed the wonderful ESP-Bridge firmware to an esp8266 and clamped that onto the serial port of the arduino uno.  That worked for a very short while and then stopped.  I then replaced the esp8266, put a voltage divider on the rx pin, flashed it again and then it kept working… oops.  This theoretically gave manual control and some sensor data, but in fact it just gave updates from within the code.  That meant a constant stream of almost nonsense that looked pretty impressive to the lay-person.

The duck sounds were actually going to be quacks made by a speak-n-spell I found at goodwill, but hacking that never actually happened.  That may be an upcoming post, because using one of those for a speech synth has always been a plan of mine.

The battery was the same one that came with the RC car, a 500mah 9.6v lithium pack with charger.  Really anemic for this use but it worked for the little while we needed it to.  I upgraded that with a later revision.  The bus power is provided by a little 3A adjustable dc-dc regulator from ebay that got set to 5V and had the POT glued down.  This is much better than the linear regulator that would just dump 50% of the power from our tiny battery as heat.

The code is here

The pictures are here

the hackathon post is here

Amazon Dash Button Re-Hack!

July 14, 2016

So, we just got through Amazon Prime Day.  That means I got myself a handful of amazon dash buttons for $0.99 each.  How could I resist, I could do some coding in a new toolchain and architecture I’m not familiar with… ok no.  All I intended to do with these was to use the software-only hack that allows you to capture the button presses and pipe that through to my mqtt server.  Amazon decided to thwart me just a bit.

As noted in this wonderful teardown there’s a new kid on the block for amazon dash buttons (JK29LP).  The old one (JK76PL) had an stm32, the new one is an atmel.  I would normally like this, but no one else has blazed a trail for me yet so I’ll fall back to being lazy.  The new amazon dash buttons no longer broadcast the message that the original hack picks up, but I tweaked it and am back in business (although from the blink pattern you can tell what revision button you have).  There’s a new program someone wrote to have a windows daemon that runs a program or script whenever a button is pushed, and it even works on the new buttons.  But it only works on windows and I just won’t have that.

I based my work on the original code from a number of different places used for different purposes.  My modification is using the dash button to send out a message on a given topic on a given mqtt server (in my case it’s localhost).  I thought that if the windows program used the ip addresses that the router gave leases to then I could get the MAC addresses by checking the leases in my router.  If I had only been smart enough to remove this line:

if pkt[ARP].psrc == ‘0.0.0.0’: # ARP Probe

I would have seen the buttons being pressed.

from scapy.all import *
import os

def arp_display(pkt):
if pkt[ARP].op == 1: #who-has (request)
if pkt[ARP].hwsrc == ‘f0:27:2d:ef:a8:a2′: # ARP Probe
print “ARP Probe from: snuggle 1 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m snuggle1”)
if pkt[ARP].hwsrc == ’74:75:48:6f:3b:b7′: # ARP Probe
print “ARP Probe from: snuggle 2 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m snuggle2”)
if pkt[ARP].hwsrc == ’44:65:0d:78:94:12′: # ARP Probe
print “ARP Probe from: glad 1 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m glad1”)
if pkt[ARP].hwsrc == ’44:65:0d:c6:e5:21’: # ARP Probe
print “ARP Probe from: glad 2 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m glad2”)
if pkt[ARP].hwsrc == ‘0c:47:c9:7c:55:20’: # ARP Probe
print “ARP Probe from: redbull 1 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m redbull1”)
if pkt[ARP].hwsrc == ‘0c:47:c9:ed:9c:46′: # ARP Probe
print “ARP Probe from: redbull 2 ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m redbull2”)
if pkt[ARP].hwsrc == ’44:65:0d:4d:a6:0b’: # ARP Probe
print “ARP Probe from: burt’s bees ” + pkt[ARP].psrc
os.system(“mosquitto_pub -h localhost -t displayTopic -m bees1″)

print sniff(prn=arp_display, filter=”arp”, store=0, count=0)

My code hardcodes the MAC addresses without checking for a 0.0.0.0 arp packet and prints out to the terminal and sends a mqtt command.  I run all this on my mqtt server pi and have it autostart just like the screen script.  Except not just like that because I want this one to run as root since I can’t do permissions worth a damn.  That would be here, and I’m still working on it.

I know this isn’t original as I see references to people removing that line, but I see no reference to the new dash button and this rock solid implementation of the year old python code.  That being said I also haven’t seen this tied to mqtt either, so that may be original.  NOTE: this triggers a notification on the amazon shopping app everytime a button that does not order a product is pressed.  This could be mitigated by blocking access to amazon’s servers for those buttons but I just sign out of the amazon shopping app (I could set them back up using a fake account, but it’s late).  I also like the thought of finding out how to respond to the buttons so they blink green when amazon responds, but I’m not willing to dig into that right now.

LED Cylon Painting

July 1, 2016

I was inspired by a large bag of red ‘tombstone’ LEDs to make a larson scanner.  These LEDs are exactly 0.1″ across which makes them perfect to stack side by side on perf board to get an arbitrarily long bargraph (but in a nicer form factor).  This was to be put in a box that originally held the receiver for an aftermarket wireless video game controller.  I designed and actually fitted the circuitry in there first.  The plan was to make that take serial commands (or serial over USB) and have it be an ROS peripheral  for an AI, or natural language processor, or just a roomba with some attitude.  Following this build I was watching an episode of Futurama called ‘The Honking’ which featured this distinguished gentleman:

The quote goes:

BENDER
That painting, the eyes are watching me!

[Farnsworth walks towards a portrait of Commodore LXIV.]

FARNSWORTH
Hmm. It has motor eye sensors attached to motion detectors.

BENDER
So does my butt, but I don’t frame it and put it on the wall! Although…

Then he got an idea. An awful idea. The Grinch got a wonderful, Awful idea… What if one of those paintings could follow you and was of a regal looking Cylon.  I commissioned a friend at i3detroit to mane the painting (a replica of a famous painting, but with a modified head/helmet) and got to work on getting someone else to help with the motion detection.  Yeah, I farmed out the work but that’s because I like it here in embeded-land.

The openCV code to detect faces wasn’t hard, it came from a certain mustache example some of you may be familiar with.  The painting turned out beautifully, and went to makerfaire.  The problem was that the raspberry pi is not the fastest computer for video processing and the pi camera does not deal with changes in exposure well.  The face tracking was a failure, but I hope to try that again in the future with a more powerful board.

The hardware is just shift registers, LEDs, and a pro mini.  The code is simple, but it’s a good thing I put in an auto-scanner routine for operation without a computer.  The manual control can set any LED position on, and then resume scrolling on command.

The code is here.

The pictures are here.

OpenAccess eeprom functions

July 1, 2016

I defined a lot of commands about how to store and retrieve stuff from the onboard eeprom.  Here they are with hopefully enough explanation.

//EEPROM stuff
//if I have time I should figure out why it errors out reading over 512 entries (should get 2048)
int entry_size = 64;
byte hash[32];
//store card id (currently a long, might not need to be)
char name[31];
byte priv;
byte command[64]; //add time zone

Initialization stuff, and questions about my sanity.  I defined 64 bytes of ‘command’ data, but never got around to using it (I could have made the define byte command[entry_size]).  The length is because that’s the same amount of space I use for a given user (and I can just index +1 to get that index user) .  You can see that the hash is 32 bits, and I have one priv byte which leaves an arbitrary 31 bytes to store the human readable name while keeping a nice round 64 byte per entry number.  The intent was to use this space for nonvolatile things (which could be stored in the 2560’s eeprom, but I decided to make it so the micro-controller board is fungible.  The only part of that intent that remains is the comment that references a time zone.  It would be easy to add the ability to peek and poke that byte (er… signed whatever-the-hell it would have to be to be a time zone) and have the date retrieval function use that offset.

// dumps the command area of the EEPROM
void SCmd_read_CMD()//debug, dumps command memory
{
read_EE_command();//updates working memory from EEPROM
for (int i = 0; i < 64; i++)
{
Serial.print(command[i], HEX);
}
Serial.println();
}

The command area of the eeprom stores nonvolatile things, but I never defined what.  This function reads it all out into working memory and prints it out for the benefit of the person or script that requested it (this function is triggered by a serial command).

void read_EE_command()//populate working memory from EEPROM
{
//for(int i = 0;i<64;i++)
//{
// command[i] = 0;
//}
for(int i = 0;i<64;i++)
{
command[i] = EEPROM1024.read(i);
}
}

This is the function that actually reads the command section of the eeprom and puts it into working memory.  There is a commented out section that blanks the working memory first, I don’t think that needs to still be there.

void write_EE_cmd()//populate EEPROM from working memory
{
for(int i = 0;i<64;i++)
{
EEPROM1024.write(i,command[i]);
}
}

This writes the volatile command memory to long term storage, doing the opposite of the above function.

void blank_EE_cmd()//debug

{
for(int i = 0;i<64;i++)
{
command[i] = 0;
EEPROM1024.write(i,0);
}
}

When testing code I end up filling the eeprom and need to blank parts of it to test other code, this function probably need not live in a running system.  I would recommend putting in a bunch of debug stuff, but marking it as such so it can be removed later.

void read_EE_name(int index)
{
for(int i = 0;i<31;i++)
{
name[i] = 0;
}
for (int i = 0; i < 31; i++)
{
name[i] = EEPROM1024.read(i+((index+1) * entry_size));//keeps command byte unwritten
}
return;
}

This code reads the name at a given index to working memory.  This is a common part of this code, I move stuff to and from working memory in order to check on it, change it, and then put it back.  This keeps reads and writes to the memory to a minimum and there’s less of a chance that the memory will be saved in an undesirable state.

void read_EE_hash(int index)
{
//for(int i = 0;i<64;i++)
//{
// EEPROM1024.write(i,command[i]);
//}
index +=1;//keeps command byte unwritten
int start_address = (index) * entry_size;
int end_address = start_address + entry_size;

for (int i = 0; i < 32; i++)
{
hash[i] = EEPROM1024.read(((start_address) + 32)+i);
}
return;
}

This code reads a hash at a given index to working memory.  This code is framed a bit differently than the function above, but it accomplishes the same task.  This looks older and more complicated, and should probably be condensed to look like the name retrieval function.

void dump_EE(int start_address, int end_address)//debug
{
//byte data[64];
for (int address = start_address; address < end_address; address++)
{
char data;
data = EEPROM1024.read(address);
Serial.print(address);
Serial.print(” :”);
Serial.print(data, HEX);
Serial.print(” :”);
Serial.println(data);
}
//Serial.println(“DONE”);
return;
}

This is another debug statement to dump eeprom data.  I mostly store my data as ascii so it prints the hex and ascii.  This is how I checked up on the memory during development, and if the intent is to run this board as a dumb I/O terminal it could be useful to leave in or as a method of backing up all the raw data.  If there is a problem this could be helped in debugging it since it does not try to be smart and just gives you all the addresses you ask for.  As always there’s some cruft left from previous formatting of the data, I’d remove the first one but leave the second one as it would be nice to be able to uncomment that later if something starts locking up.

void serial_user_print(int index)//debug? if in final make serial prints logging
{
read_EE_name(index);
read_EE_priv(index);
read_EE_hash(index);
Serial.print(index,DEC);
Serial.print(“;”);
for (int j = 0; j < (sizeof(name)/sizeof(name[0])); j++)
{
if(name[j] != 0)
Serial.print(name[j]);
}
Serial.print(“;”);
Serial.print(priv,HEX);
Serial.print(“;”);
for (int j = 0; j < (sizeof(hash)/sizeof(hash[0])); j++)
{
Serial.print((char)hash[j]);
}
Serial.println();
}

This prints out all the information about a user at a given address.  A more verbose version could be written to decode the priv bits as well.  This is a smarter version of the dump function which gives one index’s user data in a concise format.  It is only sent to the serial port, not to the printer (as pointed out by the comment).

// removes the user with <hash>
//format: RMV_USRH;<hash>
void SCmd_remove_user_hash()
{
char *arg;
arg = SCmd.next();
remove_user_hash(arg);
Serial.println(“user removed”);
}
void remove_user_hash(char hashd[32])////////////////////////////////////////////////////////////////////////////////////////////////untested
{
for(int i = 0;i<num_users;i++)
{
boolean succeed = 1;
read_EE_hash(i);
for (int j = 0; j < (sizeof(hash)/sizeof(hash[0])); j++)
{
if(hash[j] != hashd[j])
{
succeed == 0;
j+=((sizeof(hash)/sizeof(hash[0])));//break
}
}
if(succeed)
{
remove_user(i);
Serial.println(“user removed”);
i+=num_users;//break
}
}
}

This is supposed to be a serial wrapper and the associated function to remove a user with a given hash.  It would search out a perfect match for a given hash then blow away the first user with that hash.  It looks like it actually prints “user removed” twice, once from each function which should be corrected (remove the first instance, leave the one in the internal function and make it log that to the printer as well as the serial port).  There is no output if the hash isn’t found (this should be corrected).  Notice how I break the loop? Classic me. Use at your own peril.

// removes the user with <name>
//format: RMV_USRN;<name>
void SCmd_remove_user_name()
{
char *arg;
arg = SCmd.next();
remove_user_name(arg);
Serial.println(“user removed”);
}
void remove_user_name(char named[31])///////////////////////////////////////////////////////////////////////////////////////////////untested
{
for(int i = 0;i<num_users;i++)
{
boolean succeed = 1;
read_EE_name(i);
for (int j = 0; j < (sizeof(name)/sizeof(name[0])); j++)
{
if((name[j] != 0 || named[j] != 0) && name[j] != named[j])
{
succeed == 0;
j+=((sizeof(name)/sizeof(name[0])));//break
}
}
if(succeed)
{
remove_user(i);
Serial.println(“user removed”);
i+=num_users;//break
}
}
}

This is supposed to be a serial wrapper and the associated function to remove a user with a given human readable name.  It would search out a perfect match for a given name, then blow away the first user with that hash.  It looks like it actually prints “user removed” twice, once from each function which should be corrected (remove the first instance, leave the one in the internal function and make it log that to the printer as well as the serial port).  There is no output if the hash isn’t found (this should be corrected).  Notice how I break the loop? Classic me. Use at your own peril.

// removes the user at <index>
//format: RMV_USR;<index>
void SCmd_remove_user()
{
char *arg;
arg = SCmd.next();
remove_user(atoi(arg));
Serial.println(“user removed”);
}
void remove_user(int i)
{
logging(logDate());
logging(” – “);
loggingln(“removing user”);
serial_user_print(i);
String name = “Free”;
byte priv= 0;
//gonna need to add a blank cardid ince that gets implemented
String hash = “00000000000000000000000000000000”;
write_EE(i, name, priv, hash);
logging(logDate());
logging(” – “);
loggingln(“user removed”);
}

This will remove a user at a given index, log it properly, blanking the hash, priv byte, and changing the name to ‘Free’.  This is the way I think it should be done, finding the user you want to delete by reading through the entries and deciding to eliminate it by index, the above functions were an attempt to automate that (which are a bit unfinished).  This sorta creates a sacred cow with that name, but I’m not worried about it.  I could also use “-1” but “Free” reads better when you dump the data.  Also, there’s no spellchecker in my IDE, so that comment typo was only found here in wordpress.

void populate_blank_users()//debug
{
for (int i = 0;i<num_users;i++)
remove_user(i);
}

Want to remove everyone? Probably do if you’re debugging a bunch.  This just loops through everyone and does that.

// adds a user at a given index
//format: ADD_USR;<index>;<name>;<priv byte>;<hash>
void SCmd_add_user()//rename to SCmd_add_user_index() once above function is done
{
char *arg;
arg = SCmd.next();
int index = atoi(arg);
arg = SCmd.next();
String name = arg;
arg = SCmd.next();
byte priv= atoi(arg);
arg = SCmd.next();
String hash = arg;
write_EE(index, name, priv, hash);
}

This adds a user to a given index, be warned you need the desired name, precalculated hash and priv byte to use this.  It’s mostly useful for restoring after a backup, although I could create a standalone tool to calculate those based on the card ID, PIN, and asking what privileges the user should have.  I already have those functions, they just need to be tweaked to reply to some user input.

//create a function like SCmd_add_user that adds a user at the first free index

I could have sworn I did this but I guess it’s left as an exercise for the reader.  It’s like the ‘search and destroy’ commands, but it’s a ‘search and implant’ which uses the functionality already in the user add functionality if you use they keypad to add the user.

// reads the user at <index>
//format: READ_USR;<index>
void SCmd_read_user()
{
char *arg;
arg = SCmd.next();
serial_user_print(atoi(arg));
//Serial.println(“DONE”);
}

This reads a user at a given index, this is a serial wrapper for a function already made modular for other reasons.

// dumps all users present
//format: DUMP_USR
void SCmd_dump_users()
{
for (int i=0;i<num_users;i++)
{
if(user_present(i))
{
Serial.println(i);
serial_user_print(i);
}
}
//Serial.println(“DONE”);
}

This dumps all present users (use the raw read if you want all the data).  This uses the user_present function, I thought that used the name being ‘Free’ but I just checked and it uses priv byte not equal to zero.  Whatever gets the job done, this actually returns whether the user can open the door and that effectively limits the other functions because I use the door open timer to allow for the triggering of the other functions.

void dump_all_EE() //debug stuff
{
for (int address = 0; address < 131072; address++)
{
char data;
data = EEPROM1024.read(address);
Serial.print(address);
Serial.print(” :”);
Serial.println(data, HEX);
Serial.print(address);
Serial.print(” :”);
Serial.println((char)data);
//Serial.print(” :”);
//Serial.println(data);
}
//Serial.println(“DONE”);
}

Dump all the eeprom!  Hardcoded endstop, don’t remember why but there it is.

void write_EE(int index, String name, byte priv, String hash)
{
index +=1;
char data[64] = {
};
for(int i = 0;i<31;i++)
{
if(name[i] == 0)
{
i+=31;//break
}
else
{
data[i] = name[i];
}
}
data[31] = priv;
for(int i = 0;i<32;i++)
{
data[i+32] = hash[i];
}

int start_address = (index) * entry_size;
int end_address = start_address + entry_size;

//Serial.println(“Writing data”);
for (int address = start_address; address < end_address; address++)
{
EEPROM1024.write(address, data[address % entry_size]);
}
//Serial.println();
}

Here is how I write the eeprom for a user index.  This is used when I dump working memory back to a user slot.  I have the serial wrapper for it, or it is called after adding a user.

This may seem like a lot, and you may not need much of it but I think it’s nice to have.  This is part of the OpenAccess project.

 

OpenAccess Exit button/relay

July 1, 2016

This has to do with the exit button/relay.  I call these functions from elsewhere, but basically it sets the timeout for activating the exit relay.  I also use this as a timeout to enter commands to the system (enter or leave modes, like adding users)

//exit button stuff
const int exit_button = 48; //digital pin the exit button is attached to
const int exit_relay = 0; //relay the door solenoid is on
const unsigned long exit_time = 3000; //time to keep the door open in thousandths of a second
boolean exiting = 0; //whether or not the door should be open (and timer running)
unsigned long exit_start_time = 0; //used for count down timer

That is the initialization; sets the button, relay, timeout, and two variables so it can let the rest of the code execute while it’s open.

void exit()
{
logging(logDate());
logging(” – “);
loggingln(“exit relay open”);
exiting = 1;
exit_start_time = current_time;
digitalWrite(relaysToPins[exit_relay], HIGH);
}

That starts the ‘exiting’ procedure, starts the timer rolling and opens the door.

void exit_timeout()
{
logging(logDate());
logging(” – “);
loggingln(“exit relay closed”);
LCD_default();
RFID_reset();
exiting = 0; //no longer in exiting mode
//exit_start_time = 0; //not needed
digitalWrite(relaysToPins[exit_relay], LOW); //close door
}

That stops the exit procedure, pretty simple really.

if (!digitalRead(exit_button)) //exit button pressed
{
//Serial.println(“exiting”);
exit();
}
//Serial.println(“past exiting”);

That checks to see if the exit button was pressed, and starts the exit procedure.

if (exiting)
{
if (current_time – exit_start_time > exit_time) //exit time out loop
{
exit_timeout();
}
}

That checks to see if the door should be re-locked (you can of course extend the timer with more code that backs up the start time to cheat this check)

That’s all there is to the exit button and exit relay code.  It can also be called like any other relay from the I/O section, but it operates on its own unlike the others.  This is part of the OpenAccess project.

OpenAccess Keypad functions

July 1, 2016

char keypad_matrix()

{
//Serial.println(“keypad_matrix”);
if(Serial3.available())
{
char result = Serial3.read();//Read key press
return result;
}
else
{
return ‘ ‘;//equivalent to -1, a null result
}
//delay(10);
}

This code polls for keypresses.  If it returns anything then the keypresses are acted on.  Stuff like this is why it is so important to keep the code looping and not blocking.  If there are multiple keypresses buffered this will grab one and leave the rest for next loop.

void enter_pin(char c)
{
//Serial.print(“Pin Button = “);
//Serial.println(reader2);
LCD_disp(“*”);
pin[digit] = c – ‘0’;//stores as numbers rather than characters
digit++;
}

Here is how a pin is incremented, it is one of the few places I do not overwrite the entire LCD line at once.

void backspace_pin()
{
pin[digit] = 15;
//Serial.println(“backspace”);
LCD_displn(” “,1);
LCD_displn(“Pin:”,1);
if(digit >0)
{
digit–;
pin[digit] = 15;
}
for (int i = 0;i<digit;i++)//repopulates asterisks
{
LCD_disp(“*”);
}
//for(int i=0;i<(sizeof(pin)/sizeof(pin[0]));i++)
//{
// Serial.print(pin[i]);
//}
}

Removing a digit is tricky, I have to set it to an impossible to type character and rewrite the line of asterisks because I don’t support arbitrary cursor positioning.

 

void clear_pin()
{
digit = 0;
for(int i=0;i<(sizeof(pin)/sizeof(pin[0]));i++)
{
pin[i] = 15;
}
}

Clearing a pin is easy, set back to unprintable.  These steps are done in the key taking process which is longer and in the main logic code.  This is part of the greater OpenAccess project.

OpenAccess LCD functions

July 1, 2016

Here is the set of variables related to the LCD, the backlight and contrast values are important.  ‘printname’ is not here for the LCD, it actually is used when returning strings over the serial port.  ‘transmit’ is what I use to send commands to the LCD.

//LCD stuff

int back_val = 255;
int cont_val = 90;
String transmit = “”;
String printname = “”;

This is my initializer for the LCD (the LCD is on Serial3), it sets the contrast and backlight value to the values in memory (could use the command bytes) so that whatever state the LCD is in, it gets set up right.

void LCD_init()
{
Serial3.begin(115200);
LCD_clear();

transmit = “CONTRAST;”;
transmit += cont_val;
Serial3.println(transmit);

transmit = “BACKLIGHT;”;
transmit += back_val;
Serial3.println(transmit);
}

These are the commands to display things on the LCD manually (like using the Serial print and println commands).  These are used internal to the code all the time, there are wrappers though that let them get used by the serial port commands.

void LCD_displn(String prints,int line)//displays on a given line, does not emulate CR LF
{
transmit = “DISPLN;”;
transmit += line;
transmit += “;”;
transmit += prints;
Serial3.println(transmit);
}
void LCD_disp(String prints)
{
transmit = “DISP;”;
transmit += prints;
Serial3.println(transmit);
}

These set the backlight and contrast from the serial console on the OpenAccess

// sets contrast
//format: CONTRAST;<analog value, 0-255 or nothing for default>
void SCmd_contrast()
{

transmit = “CONTRAST;”;
char *arg;
//Serial.println(“contrast”);
arg = SCmd.next();
if (arg != NULL)
{
transmit += arg;
}
else
{
transmit += cont_val;
}
Serial3.println(transmit);
}
// sets backlight
//format: BACKLIGHT;<analog value, 0-255 or nothing for default>
void SCmd_backlight()
{

transmit = “BACKLIGHT;”;
char *arg;
//Serial.println(“backlight”);
arg = SCmd.next();
if (arg != NULL)
{
transmit += arg;
}
else
{
transmit += back_val;
}
Serial3.println(transmit);
}

This is my clear command (it is a 2 line LCD)  This is modular so you can fill in your own code to clear whatever display you use:

inline void LCD_clear()
{
LCD_displn(” “,0);
LCD_displn(” “,1);
}

This is how you can manually overwrite the display from the console:

// uses display
//format: DISP;<0=line 1, 1=line 2 (or no argument to clear the display)>;<string (or no argument to clear the line)>
void SCmd_display()
{
char *arg;
arg = SCmd.next();
if (arg != NULL)
{
if (atoi(arg) == 0)
{
arg = SCmd.next();
if (arg != NULL)
{
LCD_displn(arg,0);
}
else
{
LCD_displn(” “,0);
}
}
else if (atoi(arg) == 1)
{
arg = SCmd.next();
if (arg != NULL)
{
LCD_displn(arg,1);
}
else
{
LCD_displn(” “,1);
}
}
}
else
{
LCD_clear();
}
}

 

This runs every loop that nothing interesting is happening and chooses the splash screen:

void LCD_default()
{
LCD_clear();
if(doorbell)
{
LCD_displn(“Welcome: press “,0);
LCD_displn(“\”#\” to enter “,1);
}
else if(doorhold)
{
LCD_displn(“Door held: press”,0);
LCD_displn(“\”#\” to enter “,1);
}
else
{
LCD_displn(“i3 Detroit “,0);
LCD_displn(“Hackerspace “,1);
}
}

That’s my LCD functions, you can see that I compartmentalized it a lot so it is easy to change the protocol or library of your display. This is part of the greater OpenAccess project.