SHARE
TWEET

main

a guest Oct 16th, 2015 74 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. /* LED Patter
  3. * red,green,red,green  -> i give you 10 sec to connect to me, before I start
  4. * red on, green on -> I'm trying to connect to my server
  5. * UPDATE MODE
  6. * red and green blink simultainous -> I'm ready for an update
  7. * MACS MODE (status can be combined)
  8. * red blinking -> no connection to the MACS Server
  9. * red solid -> card rejected
  10. * green blinking -> connected to the MACS Server
  11. * green solid -> card accepted
  12. */
  13.  
  14. // This #include statement was automatically added by the Particle IDE.
  15. #include "wifi_login.h"
  16. #include "rest_client.h"
  17. #include "led.h"
  18. #include "application.h"
  19. #include "stdint.h"
  20.  
  21. /**
  22. * Declaring the variables.
  23. */
  24. // hardware
  25. #define MAX_JUMPER_PIN 6 // 2^(6+1)-1=127
  26.  
  27. #define RELAY_PIN D3
  28. #define RED_LED_PIN D4
  29. #define GREEN_LED_PIN D6
  30. #define DB_LED_AND_UPDATE_PIN D0
  31. #define TAG_IN_RANGE_INPUT D1
  32.  
  33. // storage
  34. #define MAX_KEYS 200 // max number of keys
  35. #define TAGSTRINGSIZE 5 // tag length
  36.  
  37. // macros
  38. #define RELAY_CONNECTED 1
  39. #define RELAY_DISCONNECTED 0
  40.  
  41. #define LOG_RELAY_CONNECTED 1
  42. #define LOG_RELAY_DISCONNECTED 2
  43. #define LOG_LOGIN_REJECTED 3
  44.  
  45. // debug
  46. #define DEBUG_JKW
  47.  
  48. // settings
  49. #define DB_UPDATE_TIME 10*60 // seconds between two auto updates from the server
  50. #define MIN_UPDATE_TIME 30 // seconds between two database request, to avoid flooding, remember this has to be smaller then db_update_time
  51. #define RED_LED_DELAY 1000 // ms
  52. #define GREEN_LED_DELAY 1000 // ms
  53. #define DB_LED_DELAY 1000 // ms
  54. #define SEC_WAIT_BOOTUP 5 // 5sec of led toggling to show that we are starting
  55.  
  56. // network
  57. //#define HOSTNAME "52.24.157.229"
  58. //#define HOSTPORT 80
  59. //#define HOSTNAME "192.168.1.84"
  60. //#define HOSTPORT 90
  61. //#define HOSTNAME "192.168.1.76"
  62. //#define HOSTPORT 80
  63. //#define HOSTNAME "192.168.42.1"
  64. uint8_t HOSTNAME[]={192,168,188,23};
  65. #define HOSTPORT 80
  66.  
  67.  
  68. uint8_t keys_available=0;
  69. uint32_t keys[MAX_KEYS];
  70.  
  71. uint8_t currentTagBuf[TAGSTRINGSIZE];
  72. uint8_t currentTagIndex=0;
  73. uint32_t currentTag=-1;
  74.  
  75. uint8_t current_relay_state=RELAY_DISCONNECTED;
  76. uint8_t id=-1; //255, my own id
  77. uint8_t tagInRange=0;
  78. uint32_t last_key_update=0;
  79. uint32_t relay_open_timestamp=0;
  80.  
  81.  
  82. LED db_led(DB_LED_AND_UPDATE_PIN,DB_LED_DELAY,1,1); // weak + inverse
  83. LED red_led(RED_LED_PIN,RED_LED_DELAY,0,0);
  84. LED green_led(GREEN_LED_PIN,GREEN_LED_DELAY,0,0);
  85.  
  86. //SYSTEM_MODE(SEMI_AUTOMATIC); // do not connect on your own
  87.  
  88. // http server
  89. RestClient client = RestClient(HOSTNAME);
  90.  
  91.  
  92. void setup() {
  93.     for(uint8_t i=10; i<=MAX_JUMPER_PIN+10; i++){   // A0..7 is 10..17, used to read my ID
  94.        pinMode(i,INPUT_PULLUP);
  95.     }
  96.     pinMode(RELAY_PIN,OUTPUT);          // driver for the relay
  97.     pinMode(TAG_IN_RANGE_INPUT,INPUT);
  98.     // the db led is a weak and inverterted LED on the same pin as the update_input, this will set the pin to input_pullup anyway //pinMode(DB_LED_AND_UPDATE_PIN,INPUT_PULLUP);
  99.    
  100.     Serial.begin(9600);
  101.     Serial1.begin(9600);
  102.  
  103.     // start sequence, to remind user to set mode
  104.     for(uint i=0;i<SEC_WAIT_BOOTUP;i++){
  105.         Serial.print(i+1);
  106.         Serial.print("/");
  107.         Serial.println(5);
  108.         delay(250);
  109.         red_led.on();
  110.         green_led.off();
  111.        
  112.         delay(250);
  113.         red_led.off();
  114.         green_led.on();
  115.        
  116.         delay(250);
  117.         red_led.on();
  118.         green_led.off();
  119.        
  120.         delay(250);
  121.         red_led.off();
  122.         green_led.on();
  123.     }
  124.     red_led.off();
  125.     green_led.off();
  126.    
  127.    
  128.     // read mode to starting with
  129.     if(digitalRead(DB_LED_AND_UPDATE_PIN)){
  130.         Serial.println("Connect to MACS system");
  131.         red_led.on();
  132.         green_led.on();
  133.        
  134.         set_macs_login();
  135.         WiFi.connect();
  136.        
  137.         uint8_t i=0;
  138.         uint8_t j=0;
  139.         Serial.println("---- Enable Wifi ---------");
  140.         while(i<20){
  141.             if(j!=millis()/1000){
  142.                 j=millis()/1000;
  143.                 i++;
  144.                 Serial.print("try ");
  145.                 Serial.print(i);
  146.                 Serial.println("/20 to reach macs wifi");
  147.                 if(WiFi.ready()){
  148.                     Serial.println("WiFi connected, here we go!");
  149.                     break;
  150.                 }
  151.             }
  152.             delay(200);
  153.         }
  154.         Serial.println("---- Get Update ---------");
  155.        
  156.         if(!update_ids()){
  157.             red_led.blink();
  158.             green_led.off();
  159.             read_EEPROM();
  160.         } else {
  161.             green_led.blink();
  162.             red_led.off();
  163.         }
  164.    
  165.     } else {
  166.         red_led.on();
  167.         green_led.on();
  168.         db_led.on();
  169.         Serial.println("Connect to cloud");
  170.         set_update_login();
  171.         Particle.connect();
  172.         uint8_t i=0;
  173.         uint8_t connected=0;
  174.         // stay in update mode forever
  175.         while(1){
  176.             if(i!=millis()/1000){
  177.                 Serial.print(i);
  178.                 Serial.print(": ");
  179.                 if(Particle.connected()){
  180.                     // as soon as we are connected, swtich to blink mode to make it visible
  181.                     if(!connected){
  182.                         red_led.blink();
  183.                         green_led.blink();
  184.                         db_led.blink();
  185.                         connected=1;
  186.                     }
  187.                    
  188.                     // keep blinking
  189.                     red_led.check();
  190.                     green_led.check();
  191.                     db_led.check();
  192.                     Serial.println("Photon connected");
  193.                    
  194.                 } else {
  195.                     Serial.println("Photon NOT connected");
  196.                     // constant on == not yet connected
  197.                     red_led.on();
  198.                     green_led.on();
  199.                     db_led.on();
  200.                 }
  201.                 i=millis()/1000;
  202.             }
  203.             delay(200); // don't go to high as blink will look odd
  204.         }
  205.     }
  206.    
  207.    
  208. }
  209.  
  210.  
  211. // woop woop main loop
  212. void loop() {
  213.     // check if we found a tag
  214.     if(tag_found(currentTagBuf,&currentTag)){
  215.         // if we found a tag, test it
  216.         // if it works close relay,
  217.         // if not - ask the server for an update and try again
  218.         uint8_t tries=2; // two tries to check the card
  219.         while(tries){
  220.             // compares known keys, returns true if key is known
  221.             if(access_test(currentTag)){
  222.                 relay(RELAY_CONNECTED);
  223.                 tries=0;
  224.                 green_led.on();
  225.                 // last because it takes long
  226.                 create_report(LOG_RELAY_CONNECTED,currentTag,0);
  227.             } else {
  228.                 // if we have a card that is not known to be valid we should maybe check our database
  229.                 if(tries>1){
  230.            
  231.                     #ifdef DEBUG_JKW
  232.                     Serial.println("Key not valid, requesting update from server");
  233.                     #endif
  234.                    
  235.                     update_ids();
  236.                    
  237.                     #ifdef DEBUG_JKW
  238.                     if(tries>0){
  239.                         Serial.println("Trying once more if key is valid now");
  240.                     };
  241.                     #endif
  242.                     tries-=1;
  243.                 } else {
  244.                     #ifdef DEBUG_JKW
  245.                     Serial.println("key still not valid. :P");
  246.                     #endif
  247.                     tries=0;  
  248.                     red_led.on();
  249.                     // last because it takes long
  250.                     create_report(LOG_LOGIN_REJECTED,currentTag,0);
  251.                 }
  252.             }
  253.         }
  254.     }
  255.    
  256.    
  257.     // card moved away
  258.     if(digitalRead(TAG_IN_RANGE_INPUT)==0 && currentTag!=-1){
  259.         // open the relay as soon as the tag is gone
  260.         if(current_relay_state==RELAY_CONNECTED){
  261.             uint32_t open_time_sec=relay(RELAY_DISCONNECTED);
  262.             green_led.resume();
  263.             // last because it takes long
  264.             create_report(LOG_RELAY_DISCONNECTED,currentTag,open_time_sec);
  265.         } else {
  266.             red_led.resume();    
  267.         }
  268.        
  269.         currentTag=-1;      // reset current user
  270.         currentTagIndex=0;  // reset index counter for incoming bytes
  271.        
  272.     }
  273.    
  274.     // time based update the storage from the server (every 10 min?)
  275.     if(last_key_update+DB_UPDATE_TIME<(millis()/1000)){
  276.         update_ids();
  277.     }
  278.    
  279.     // see if we should switch off the leds by now
  280.     db_led.check();
  281.     red_led.check();
  282.     green_led.check();
  283. }
  284.  
  285.  
  286.  
  287. // callen from main loop as soon as a tag has been found to test if it matches one of the saved keys
  288. bool access_test(uint32_t tag){
  289.     #ifdef DEBUG_JKW
  290.     Serial.print("Tag ");
  291.     Serial.print(tag);
  292.     Serial.print(" found. Checking database (");
  293.     Serial.print(keys_available);
  294.     Serial.print(") for matching key");
  295.     Serial.println("==============");
  296.     #endif
  297.    
  298.     for(uint8_t i=0;i<MAX_KEYS && i<keys_available; i++){
  299.  
  300.         #ifdef DEBUG_JKW
  301.         Serial.print(i+1);
  302.         Serial.print(" / ");
  303.         Serial.print(keys_available);
  304.         Serial.print(" Compare current read tag ");
  305.         Serial.print(tag);
  306.         Serial.print(" to stored key ");
  307.         Serial.print(keys[i]);
  308.         Serial.println("");
  309.         #endif
  310.        
  311.         if(keys[i]==tag){
  312.  
  313.     #ifdef DEBUG_JKW
  314.     Serial.println("Key valid, closing relay");
  315.     #endif
  316.    
  317.             return true;
  318.         }
  319.     }
  320.  
  321.     #ifdef DEBUG_JKW
  322.     Serial.println("==============");
  323.     #endif
  324.    
  325.     return false;
  326. }
  327.  
  328. // hardware controll, writing to the pin and log times
  329. uint32_t relay(int8_t input){
  330.     if(input==1){
  331.         #ifdef DEBUG_JKW
  332.         Serial.println("Connecting relay!");
  333.         #endif
  334.        
  335.         //digitalWrite(RELAY_PIN,HIGH);
  336.         current_relay_state=RELAY_CONNECTED;
  337.         relay_open_timestamp=millis()/1000;
  338.     } else {
  339.         #ifdef DEBUG_JKW
  340.         Serial.println("Disconnecting relay!");
  341.         #endif
  342.        
  343.         //digitalWrite(RELAY_PIN,LOW);
  344.         current_relay_state=RELAY_DISCONNECTED;
  345.         return ((millis()/1000) - relay_open_timestamp);
  346.     }
  347. }
  348.  
  349.  
  350. // returns true if tag found, does the UART handling
  351. bool tag_found(uint8_t *buf,uint32_t *tag){
  352.     uint8_t temp;
  353.    
  354.     while(Serial1.available()){
  355.         //tag_read_led.on_dalayed(); // switch on the LED for one sec, no off needed
  356.         temp=Serial1.read();
  357.         buf[currentTagIndex]=temp;
  358.         currentTagIndex=(currentTagIndex+1)%TAGSTRINGSIZE;
  359.        
  360.         if(currentTagIndex==0){
  361.             return validate_tag(buf,tag);
  362.         };
  363.     }
  364.     return false;
  365. }
  366.  
  367.  
  368. // just check if the data are corrumpeted or equal the checksum
  369. // and convert them to the correct oriented unsigned long
  370. bool validate_tag(uint8_t *buf,uint32_t *tag){
  371.     uint8_t expected=0;
  372.     for(uint8_t i=0;i<TAGSTRINGSIZE-1;i++){
  373.         expected^=buf[i];
  374.     }
  375.     //Serial.println("comparing");
  376.     if(expected==buf[TAGSTRINGSIZE-1]){
  377.         // checksum correct, flip data around to get the uint32_t
  378.         for(uint8_t i=0;i<TAGSTRINGSIZE-1;i++){
  379.             *tag=(*tag<<8)+buf[i];
  380.         };
  381.         return true;
  382.     }
  383.     //Serial.println("invalid checksum detected");
  384.     return false;
  385. }
  386.  
  387.  
  388. bool read_EEPROM(){
  389.     Serial.println("-- This is EEPROM read --");
  390.     uint8_t temp;
  391.     uint16_t num_keys=0;
  392.     uint16_t num_keys_check=0;
  393.    
  394.     temp=EEPROM.read(2044);
  395.     num_keys=temp<<8;
  396.     temp=EEPROM.read(2045);
  397.     num_keys+=temp;
  398.     Serial.print("# of keys =");
  399.     Serial.println(num_keys);
  400.    
  401.    
  402.     temp=EEPROM.read(2046);
  403.     num_keys_check=temp<<8;
  404.     temp=EEPROM.read(2047);
  405.     num_keys_check+=temp;
  406.     Serial.print("# of keys+1 =");
  407.     Serial.println(num_keys_check);
  408.    
  409.     if(num_keys_check==num_keys+1){
  410.         keys_available=num_keys;
  411.         for(uint8_t i=0;i<num_keys;i++){
  412.             temp=EEPROM.read(i*4+0);
  413.             keys[i]=temp<<24;
  414.             temp=EEPROM.read(i*4+1);
  415.             keys[i]+=temp<<16;
  416.             temp=EEPROM.read(i*4+2);
  417.             keys[i]+=temp<<8;
  418.             temp=EEPROM.read(i*4+3);
  419.             keys[i]+=temp;
  420.            
  421.             #ifdef DEBUG_JKW
  422.             Serial.print("Read key ");
  423.             Serial.print(i);
  424.             Serial.print("=");
  425.             Serial.print(keys[i]);
  426.             Serial.println(" from eeprom");
  427.             #endif
  428.         }
  429.     }
  430.     Serial.println("-- End of EEPROM read --");
  431. }
  432.  
  433. // sends a request to the amazon server, this server should be later changed to
  434. // be the local Raspberry pi. It will call the get_my_id() function
  435. // return true if http request was ok
  436. // false if not - you might want to set a LED if it returns false
  437. bool update_ids(){
  438.     // avoid flooding
  439.     if(last_key_update+MIN_UPDATE_TIME>millis()/1000 && last_key_update>0){
  440.         #ifdef DEBUG_JKW
  441.         Serial.println("db read blocked, too frequent");
  442.         #endif
  443.        
  444.         return false;
  445.     }
  446.     last_key_update=millis()/1000;
  447.     db_led.on(); // turn the led on
  448.    
  449.     // request data
  450.     uint32_t now=millis();
  451.     String response;
  452.     String url="/m2m.php?mach_nr="+String(get_my_id());
  453.     int statusCode = client.get(url, &response);
  454.    
  455.     #ifdef DEBUG_JKW
  456.     Serial.print("db request took ");
  457.     Serial.print(millis()-now);
  458.     Serial.println(" ms");
  459.     #endif
  460.    
  461.    
  462.     // check status
  463.     if(statusCode!=200){
  464.         db_led.off(); // turn the led off
  465.        
  466.         #ifdef DEBUG_JKW
  467.         Serial.println("No response from server");
  468.         #endif
  469.        
  470.         return false;
  471.     }
  472.  
  473.     // check length
  474.     if(response.length()==0){
  475.         db_led.off(); // turn the led off
  476.        
  477.         #ifdef DEBUG_JKW
  478.         Serial.println("Empty response");
  479.         #endif
  480.     }
  481.  
  482.     // clear all existing keys and then, import keys from request
  483.     keys_available=0;
  484.     uint8_t current_key=0;
  485.     for(uint8_t i=0;i<sizeof(keys)/sizeof(keys[0]);i++){
  486.         keys[i]=0;
  487.     }
  488.  
  489.     for(uint8_t i=0;i<response.length();i++){
  490.         Serial.print(response.charAt(i));
  491.  
  492.         if(response.charAt(i)==','){
  493.             if(current_key<MAX_KEYS){
  494.                
  495.                 #ifdef DEBUG_JKW
  496.                 /*
  497.                 Serial.print("Write key ");
  498.                 Serial.print(current_key);
  499.                 Serial.print("=");
  500.                 Serial.print(keys[current_key]);
  501.                 Serial.println(" to eeprom");
  502.                 */
  503.                 #endif
  504.                
  505.                 // store to EEPROM
  506.                 EEPROM.update(current_key*4+0, (keys[current_key]>>24)&0xff);
  507.                 EEPROM.update(current_key*4+1, (keys[current_key]>>16)&0xff);
  508.                 EEPROM.update(current_key*4+2, (keys[current_key]>>8)&0xff);
  509.                 EEPROM.update(current_key*4+3, (keys[current_key])&0xff);
  510.            
  511.                 current_key++;
  512.             }
  513.         } else if(response.charAt(i)>='0' && response.charAt(i)<='9') { // zahl
  514.             keys[current_key]=keys[current_key]*10+(response.charAt(i)-'0');
  515.         }
  516.     }
  517.    
  518.    
  519.     // csv does not end with a ',', therefore we have to add +1
  520.     keys_available=current_key;
  521.     EEPROM.update(2044,(keys_available>>8)&0xff);
  522.     EEPROM.update(2045,(keys_available)&0xff);
  523.    
  524.     // checksum
  525.     EEPROM.update(2046,((keys_available+1)>>8)&0xff);
  526.     EEPROM.update(2047,((keys_available+1))&0xff);
  527.    
  528.     #ifdef DEBUG_JKW
  529.     Serial.print("Total received keys for my id(");
  530.     Serial.print(get_my_id());
  531.     Serial.print("):");
  532.     Serial.println(keys_available);
  533.     for(uint8_t i=0;i<keys_available;i++){
  534.         Serial.print("Valid Database Key Nr ");
  535.         Serial.print(i+1);
  536.         Serial.print(": ");
  537.         Serial.print(keys[i]);
  538.         Serial.println("");
  539.     };
  540.     #endif
  541.    
  542.     db_led.off(); // turn the led off
  543.     return true;
  544. }
  545.  
  546.  
  547. // create a log entry on the server for the action performed
  548. void create_report(uint8_t event,uint32_t badge,uint32_t extrainfo){
  549.    
  550.     //db_led.on(); // turn the led on
  551.     String request_path;
  552.     if(event==LOG_RELAY_CONNECTED){
  553.         request_path = "/history.php?logme&badge="+String(badge)+"&mach_nr="+String(get_my_id())+"&event=Unlocked";
  554.     } else if(event==LOG_LOGIN_REJECTED){
  555.         request_path = "/history.php?logme&badge="+String(badge)+"&mach_nr="+String(get_my_id())+"&event=Rejected";
  556.     } else if(event==LOG_RELAY_DISCONNECTED){
  557.         request_path = "/history.php?logme&badge="+String(badge)+"&mach_nr="+String(get_my_id())+"&event=Locked&timeopen="+String(extrainfo);
  558.     } else {
  559.         return;
  560.     }
  561.    
  562.     #ifdef DEBUG_JKW
  563.     Serial.print("calling:");
  564.     Serial.println(request_path);
  565.     #endif
  566.    
  567.     uint32_t now=millis();
  568.     String response;
  569.     int statusCode = client.get(request_path, &response);
  570.    
  571.     #ifdef DEBUG_JKW
  572.     Serial.print("db request took ");
  573.     Serial.print(millis()-now);
  574.     Serial.println(" ms");
  575.     #endif
  576.    
  577.     //db_led.off(); // turn the led off
  578. }
  579.  
  580. // shall later on read the device jumper and return that number
  581. // will only do the interation with the pins once for performance
  582. uint8_t get_my_id(){
  583.     if(id==(uint8_t)-1){
  584.         id=0;
  585.        
  586.         #ifdef DEBUG_JKW
  587.         Serial.print("ID never set, reading");
  588.         #endif
  589.        
  590.         for(uint8_t i=10+MAX_JUMPER_PIN; i>=10; i--){   // A0..7 is 10..17
  591.             id=id<<1;
  592.             if(!digitalRead(i)){
  593.                 id++;
  594.             };
  595.         }
  596.        
  597.         #ifdef DEBUG_JKW
  598.         Serial.print("id for this device as ");
  599.         Serial.println(id);
  600.         #endif
  601.        
  602.     }
  603.     return id;
  604. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top