Skip to content

Instantly share code, notes, and snippets.

@Luit
Last active August 29, 2015 14:16
Show Gist options
  • Save Luit/bb867481931139fc9c5e to your computer and use it in GitHub Desktop.
Save Luit/bb867481931139fc9c5e to your computer and use it in GitHub Desktop.
// kinda smart ergonomic Desk, or kseD for short, is a project to make my
// no-frills ergonomic desk a bit more special.
/*
Serial commands:
E <upper> <lower>
Read value from EEPROM (might disappear once testing is done)
G <upper> <lower>
Move to position (upper << 8 | lower)
I
Identify (triggers `kseD` update)
M <pos>
Move to stored position <pos>
P
Get position update
S <pos> <upper> <lower>
Store position (upper << 8 | lower) to <pos>
T
Show current target
X <user>
Switch user to <user>. User 0xFF means switching to normal mode.
Z
Zero the kseD (should be issued with desk in lowest position)
Serial updates:
C <size> <uid0> <uid1> ... <uid{size-1}>
New card detected
E <data>
Data from EEPROM (response to E command)
k 's' 'e' 'D' <version>
Response to I command
P <upper> <lower>
Position (upper << 8 | lower) reached (unsollicited means stored in EEPROM)
T <upper> <lower>
Current target is (upper << 8 | lower)
*/
#include <SPI.h>
#include <EEPROM.h>
#include <MFRC522.h>
#define KSED_VERSION 0x02
#define EEPROM_POSITION 0x000 // 2 bytes
#define EEPROM_CURRENT_USER 0x002 // 1 byte
#define EEPROM_CURRENT_POS 0x003 // 1 byte
#define EEPROM_USERS_OFFSET 0x100 // 768 bytes in 0x100 - 0x3FF (1K EEPROM)
#define EEPROM_MAX_USERS 192 // 768 bytes at 4 bytes per user
#define EEPROM_USER_LENGTH 4 // 2 bytes per position, 2 positions
#define ENCODER_PIN1 2 // Needs interrupt
#define ENCODER_PIN2 3 // Needs interrupt
#define RFID_RST_PIN 9
#define RFID_SS_PIN 10
#define UP_PIN 6
#define DOWN_PIN 5
volatile bool nfc = false;
volatile uint8_t lastEncoded = 0;
volatile uint16_t position;
volatile uint16_t sentPosition;
volatile uint32_t sentMs = 0;
volatile uint16_t target = 0; // 0 = no movement
volatile bool targetUp = false; // Direction of target at time of set
volatile uint8_t uidByte[10];
volatile uint8_t uidSize = 0;
MFRC522 mfrc522(RFID_SS_PIN, RFID_RST_PIN);
void setup() {
position = EEPROM.read(EEPROM_POSITION);
if (position == 255<<8) {
position = 0x10;
// First time run, probably.
EEPROM.write(EEPROM_POSITION, 0x10);
EEPROM.write(EEPROM_POSITION+1, 0x00);
EEPROM.write(EEPROM_CURRENT_USER, 0xFF);
EEPROM.write(EEPROM_CURRENT_POS, 0x00);
}
position <<= 8;
position |= EEPROM.read(EEPROM_POSITION+1);
sentPosition = position;
pinMode(UP_PIN, OUTPUT);
pinMode(DOWN_PIN, OUTPUT);
digitalWrite(UP_PIN, LOW);
digitalWrite(DOWN_PIN, LOW);
// Initialize rotary encoder
pinMode(ENCODER_PIN1, INPUT);
pinMode(ENCODER_PIN2, INPUT);
digitalWrite(ENCODER_PIN1, HIGH); //turn pullup resistor on
digitalWrite(ENCODER_PIN2, HIGH); //turn pullup resistor on
//call updateEncoder() when any high/low changed seen
//on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
Serial1.begin (9600, SERIAL_8N1);
while (!Serial1);
// Enable SPI and activate RFID reader
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
if (v == 0x91 || v == 0x92) {
nfc = true; // RFID chip found
// Enhance range of RFID reader
mfrc522.PCD_AntennaOff();
mfrc522.PCD_SetAntennaGain(0xff);
mfrc522.PCD_AntennaOn();
}
}
void serialWrite(byte b) {
Serial1.write(b);
}
void serialFlush() {
Serial1.flush();
}
byte serialRead() {
while (Serial1.available() < 1);
return Serial1.read();
}
void storePosition(bool now) {
if (sentPosition == position) {
sentMs = 0;
return;
}
if (!now && sentMs == 0) {
sentMs = millis();
return;
}
uint32_t ms = millis();
if (now || ms < sentMs || (ms - sentMs) > 30000) {
sentPosition = position;
sentMs = 0;
// Store (and autosend) at most every 30 seconds (so we'll probably
// store once every move)
EEPROM.write(EEPROM_POSITION, sentPosition >> 8);
EEPROM.write(EEPROM_POSITION+1, sentPosition & 0xFF);
serialWrite('P');
serialWrite((sentPosition>>8)&0xFF);
serialWrite(sentPosition&0xFF);
serialFlush();
}
}
void loop(){
storePosition(false);
if (target == 0) {
digitalWrite(UP_PIN, LOW);
digitalWrite(DOWN_PIN, LOW);
} else {
if (target > position) {
if (targetUp) {
digitalWrite(UP_PIN, HIGH);
digitalWrite(DOWN_PIN, LOW);
} else {
target = 0;
}
} else if (target < position) {
if (targetUp) {
target = 0;
} else {
digitalWrite(UP_PIN, LOW);
digitalWrite(DOWN_PIN, HIGH);
}
} else {
digitalWrite(UP_PIN, LOW);
digitalWrite(DOWN_PIN, LOW);
}
}
if (Serial1.available() > 0) {
uint8_t u8_0, u8_1, u8_2, u8_3;
uint16_t u16_0, u16_1;
byte cmd = serialRead();
switch (cmd) {
case 'E':
u16_0 = ((uint16_t) serialRead()) << 8;
u16_0 |= (uint16_t) serialRead();
serialWrite('e');
serialWrite(EEPROM.read(u16_0));
serialFlush();
break;
case 'G':
target = (((uint16_t) serialRead()) << 8) | ((uint16_t) serialRead());
if (EEPROM.read(EEPROM_CURRENT_POS) != 255)
EEPROM.write(EEPROM_CURRENT_POS, 255);
targetUp = false;
if (target > position)
targetUp = true;
if (target == position)
target = 0;
break;
case 'I':
serialWrite('k');
serialWrite('s');
serialWrite('e');
serialWrite('D');
serialWrite(KSED_VERSION);
serialFlush();
break;
case 'M':
u8_0 = serialRead();
if (u8_0 > 2) break; // TODO: configure number of stored positions?
u16_0 = EEPROM.read(EEPROM_CURRENT_USER);
if (u16_0 == 255) break;
u16_0 = EEPROM_USERS_OFFSET + (u16_0 * EEPROM_USER_LENGTH);
u16_1 = EEPROM.read(u16_0 + (u8_0*2));
if (u16_1 == 255) break;
target = u16_1 << 8;
target |= EEPROM.read(u16_0 + (u8_0*2) + 1);
targetUp = false;
if (target > position)
targetUp = true;
if (target == position)
target = 0;
break;
EEPROM.write(EEPROM_CURRENT_POS, u8_0);
break;
case 'P':
u16_0 = position;
serialWrite('p');
serialWrite(u16_0>>8);
serialWrite(u16_0&0xFF);
serialFlush();
break;
case 'S':
u8_0 = serialRead(); // pos
u8_1 = serialRead(); // upper
u8_2 = serialRead(); // lower
u8_3 = EEPROM.read(EEPROM_CURRENT_USER);
if (u8_0 > 2) break; // TODO: configure number of stored positions?
if (u8_3 == 255) break;
u16_0 = EEPROM_USERS_OFFSET + (u8_3*EEPROM_USER_LENGTH) + u8_0;
EEPROM.write(u16_0, u8_1);
EEPROM.write(u16_0+1, u8_2);
break;
case 'T':
serialWrite('t');
serialWrite(target>>8);
serialWrite(target&0xFF);
serialFlush();
break;
case 'X':
u16_0 = serialRead();
EEPROM.write(EEPROM_CURRENT_USER, u16_0);
u16_0 = EEPROM_USERS_OFFSET + (u16_0*EEPROM_USER_LENGTH);
u8_0 = EEPROM.read(EEPROM_CURRENT_POS);
if (u8_0 == 255) break;
u16_0 += u8_0 * 2; // TODO: configure number of stored positions?
u16_1 = EEPROM.read(u16_0);
if (u16_1 == 255) break;
target = (u16_1 << 8) | EEPROM.read(u16_0 + 1);
targetUp = false;
if (target > position)
targetUp = true;
if (target == position)
target = 0;
break;
break;
case 'Z':
target = 0x0000;
position = 0x1000;
// sentPosition = 0x1000;
// EEPROM.write(EEPROM_POSITION, 0x10);
// EEPROM.write(EEPROM_POSITION+1, 0x00);
// sentMs = 0;
storePosition(true);
break;
}
}
if (nfc && mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
if (mfrc522.uid.size <= 10) {
if (uidSize != mfrc522.uid.size)
uidSize = mfrc522.uid.size;
for (int i = 0; i < uidSize; i++) {
uidByte[i] = mfrc522.uid.uidByte[i];
}
serialWrite('C');
serialWrite(uidSize);
for (int i = 0; i < uidSize; i++) {
serialWrite(uidByte[i]);
}
}
mfrc522.PICC_HaltA();
serialFlush();
}
}
void updateEncoder(){
uint8_t MSB = digitalRead(ENCODER_PIN1); // MSB = most significant bit
uint8_t LSB = digitalRead(ENCODER_PIN2); // LSB = least significant bit
uint8_t encoded = (MSB << 1) |LSB; // converting the 2 pin value to single number
uint8_t sum = (lastEncoded << 2) | encoded; // adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) position ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) position --;
lastEncoded = encoded; //store this value for next time
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment