rossoreed

Nanode Pachube with Watchdog

Apr 16th, 2012
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.41 KB | None | 0 0
  1. // Simple demo for feeding some random data to Pachube.
  2. // Based on pachube.pde 2011-07-08 <jcw@equi4.com>
  3. // Created by <maniacbug@ymail.com>
  4.  
  5. // This has been tested with EtherCard rev 7752
  6. #include <EtherCard.h>
  7. #include <CmdMessenger.h>
  8. #include <Base64.h>
  9. #include <Streaming.h>
  10. #include <avr/wdt.h>
  11.  
  12. // change these settings to match your own setup
  13. #define FEED    "34843"
  14. #define APIKEY  "JHhghggffgfgg6rF5rfdtrtfytY"
  15.  
  16. // On Nanode, this will get the MAC from the 11AA02E48 chip
  17. byte mymac[6];
  18.  
  19. // Static IP configuration to use if no DHCP found
  20. // Change these to match your site setup
  21. static byte static_ip[] = { 192,168,1,91 };
  22. static byte static_gw[] = { 192,168,1,1 };
  23. static byte static_dns[] = { 192,168,1,99 };
  24.  
  25. char website[] PROGMEM = "api.pachube.com";
  26. char field_separator = ',';
  27. char command_separator = ';';
  28.  
  29. int mcount, tvalue, sd1, sd1a, sd2, sd2a;
  30. double sd6, sd7;
  31. float sd3, sd4, sd5, sd8=0.0;  //floats because data is to ? decimal places
  32. int tol=5;  //update frequency tolerance, either up or down 5Watts triggers an update
  33. //------------------------------------------------------------
  34. // Timing Variables
  35. //------------------------------------------------------------
  36. unsigned long timerDelay=840000UL;  // Updates Pachube every 14 mins max to prevent freezing
  37. unsigned long LEDDelay=500;
  38. unsigned long prevMillis=0UL;
  39.  
  40. byte Ethernet::buffer[512];
  41. uint32_t timer;
  42. Stash stash;
  43.  
  44. void printf_begin(void);
  45. void read_MAC(byte*);
  46.  
  47. //------------Command Messenger------------------//
  48.  
  49. // Attach a new CmdMessenger object to the default Serial port
  50. CmdMessenger cmdMessenger = CmdMessenger(Serial, field_separator, command_separator);
  51.  
  52. enum
  53. {
  54.   kCOMM_ERROR    = 000, // Lets Arduino report serial port comm error back to the PC (only works for some comm errors)
  55.   kACK           = 001, // Arduino acknowledges cmd was received
  56.   kARDUINO_READY = 002, // After opening the comm port, send this cmd 02 from PC to check arduino is ready
  57.   kERR           = 003, // Arduino reports badly formatted cmd, or cmd not recognised
  58.  
  59.   kSEND_CMDS_END, // Mustnt delete this line
  60. };
  61.  
  62. messengerCallbackFunction messengerCallbacks[] =
  63. {
  64.   Arduino_msg,            // 004 in this example
  65.   NULL
  66. };
  67.  
  68. void Arduino_msg()
  69. {
  70.   cmdMessenger.sendCmd(kACK,"command recieved");
  71.   mcount = 0;
  72.   while ( cmdMessenger.available() )
  73.   {
  74.     char buf[350] = { '\0' };
  75.     cmdMessenger.copyString(buf, 350);
  76.  
  77.     mcount = mcount+1 ;
  78.     tvalue = atoi(buf);
  79.     if (mcount == 1) {
  80.      sd1 = (tvalue); }
  81.       else if (mcount == 2) {
  82.        sd2 = (tvalue); }
  83.         else if (mcount == 3) {
  84.          sd3 = (tvalue); }
  85.           else if (mcount == 4) {
  86.            sd4 = (tvalue); }
  87.             else if (mcount == 5) {
  88.              sd5 = (tvalue); }
  89.               else if (mcount == 6) {
  90.                sd6 = (tvalue); }
  91.                 else if (mcount == 7) {
  92.                  sd7 = (tvalue); }
  93.                   else if (mcount == 8) {
  94.                    sd8 = (tvalue); }
  95.     if(buf[0])
  96.       cmdMessenger.sendCmd(kACK, buf);
  97.    }
  98. }
  99.  
  100. void arduino_ready()
  101. {
  102.   // In response to ping. We just send a throw-away Acknowledgement to say "im alive"
  103.   cmdMessenger.sendCmd(kACK,"Arduino ready");
  104. }
  105.  
  106. void unknownCmd()
  107. {
  108.   // Default response for unknown commands and corrupt messages
  109.   cmdMessenger.sendCmd(kERR,"Unknown command");
  110. }
  111.  
  112. void attach_callbacks(messengerCallbackFunction* callbacks)
  113. {
  114.   int i = 0;
  115.   int offset = kSEND_CMDS_END;
  116.   while(callbacks[i])
  117.   {
  118.     cmdMessenger.attach(offset+i, callbacks[i]);
  119.     i++;
  120.   }
  121. }
  122. //end of CmdMessenger code
  123.  
  124. void setup () {
  125.   pinMode(6, OUTPUT);  //Onboard LED
  126.  
  127.   Serial.begin(9600);
  128.  
  129.   printf_begin();
  130.   printf_P(PSTR("\nEtherCard/examples/nanode_pachube\n\r"));
  131.  
  132.   // Fetch the MAC address -- Nanode-specific
  133.   read_MAC(mymac);
  134.  
  135.   printf_P(PSTR("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n\r"),
  136.       mymac[0],
  137.       mymac[1],
  138.       mymac[2],
  139.       mymac[3],
  140.       mymac[4],
  141.       mymac[5]
  142.   );
  143.  
  144.   if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
  145.     printf_P(PSTR( "Failed to access Ethernet controller\n\r"));
  146.   if (!ether.dhcpSetup())
  147.   {
  148.     printf_P(PSTR("DHCP failed, using static configuration\n\r"));
  149.     ether.staticSetup(static_ip, static_gw);
  150.     ether.copyIp(ether.dnsip, static_dns);
  151.   }
  152.  
  153.   ether.printIp("IP:  ", ether.myip);
  154.   ether.printIp("GW:  ", ether.gwip);  
  155.   ether.printIp("DNS: ", ether.dnsip);  
  156.  
  157.   if (!ether.dnsLookup(website))
  158.     printf_P(PSTR("DNS failed\n\r"));
  159.    
  160.   ether.printIp("SRV: ", ether.hisip);
  161.  
  162.   //----------Start of CmdMessenger----------//
  163.   cmdMessenger.print_LF_CR();   // Make output more readable whilst debugging in Arduino Serial Monitor
  164.   cmdMessenger.attach(kARDUINO_READY, arduino_ready);
  165.   cmdMessenger.attach(unknownCmd);
  166.   attach_callbacks(messengerCallbacks);
  167.   arduino_ready();
  168.   //----------End of CmdMessenger----------//
  169.  
  170.   wdt_enable(WDTO_8S);  //Set up the watchdog timer. If it isn't reset every 8 seconds, the arduino will reset
  171. }
  172.  
  173. void loop () {  
  174.   wdt_reset();  //Reset the watchdog
  175.    
  176.   //check if timer has reset (after 49 days...)
  177.   if (prevMillis > millis()) {
  178.     prevMillis = 0;  }
  179.  
  180.   cmdMessenger.feedinSerialData(); //CmdMessenger
  181.  
  182.   ether.packetLoop(ether.packetReceive());
  183.  
  184.   //------------------------------
  185.   // SEND DATA TO PACHUBE  
  186.   //------------------------------
  187.  
  188.   // blink onboard LED to show IF statement is true (Pin 6 on Nanode)
  189.   if ((millis() - prevMillis) > (LEDDelay)) {
  190.     digitalWrite(6, HIGH); } // turns LED off
  191.  
  192.   // check if new data has arrived...
  193.     if ((sd1 >(sd1a + tol)) || (sd1 <(sd1a - tol)) || (sd2 >(sd2a + tol)) || (sd2 <(sd2a - tol)) || ((millis() - prevMillis) > (timerDelay)))  {  
  194.     digitalWrite(6, LOW); //turns onboard LED on if IF statement true
  195.      
  196.     // reset the indicators to current values
  197.     sd1a = sd1;
  198.     sd2a = sd2;
  199.     prevMillis=millis();
  200.        
  201.     printf_P(PSTR("Sending...\n\r"));
  202.  
  203.     byte sd = stash.create();
  204.     stash.print("sd1,");
  205.     stash.println((word) sd1);
  206.     stash.print("sd2,");
  207.     stash.println((word) sd2);
  208.     stash.print("sd3,");
  209.     stash.println((word) sd3 / 1000.0, 3);
  210.     stash.print("sd4,");
  211.     stash.println((word) sd4 / 1000.0, 3);
  212.     stash.print("sd5,");
  213.     stash.println((word) sd5 / 1000.0, 3);
  214.     stash.print("sd6,");
  215.     stash.println((word) sd6);
  216.     stash.print("sd7,");
  217.     stash.println((word) sd7);
  218.     stash.print("sd8,");
  219.     stash.println((sd8 / 100.0) - 50.0);
  220.     //stash.println((word) sd8);
  221.     stash.save();
  222.    
  223.     // generate the header with payload - note that the stash size is used,
  224.     // and that a "stash descriptor" is passed in as argument using "$H"
  225.     Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n"
  226.                         "Host: $F" "\r\n"
  227.                         "X-PachubeApiKey: $F" "\r\n"
  228.                         "Content-Length: $D" "\r\n"
  229.                         "\r\n"
  230.                         "$H"),
  231.             website, PSTR(FEED), website, PSTR(APIKEY), stash.size(), sd);
  232.  
  233.     // send the packet - this also releases all stash buffers once done
  234.     ether.tcpSend();
  235.    
  236.     //Watchdog reboot every hour
  237.     if (millis() > 3600000L) {
  238.     delay (10000); }
  239.   }
  240. }
  241.  
  242. int serial_putc( char c, FILE * )
  243. {
  244.   Serial.write( c );
  245.   return c;
  246. }
  247.  
  248. void printf_begin(void)
  249. {
  250.   fdevopen( &serial_putc, 0 );
  251. }
  252.  
  253. // Nanode_MAC
  254. // Rufus Cable, June 2011 (threebytesfull)
  255.  
  256. // Sample code to read the MAC address from the 11AA02E48 on the
  257. // back of the Nanode V5 board.
  258.  
  259. // This code is hacky and basic - it doesn't check for bus errors
  260. // and will probably fail horribly if it's interrupted. It's best
  261. // run in setup() - fetch the MAC address once and keep it. After
  262. // the address is fetched, it puts the chip back in standby mode
  263. // in which it apparently only consumes 1uA.
  264.  
  265. // Feel free to reuse this code - suggestions for improvement are
  266. // welcome! :)
  267.  
  268. // http://ww1.microchip.com/downloads/en/DeviceDoc/DS-22067H.pdf
  269. // http://ww1.microchip.com/downloads/en/devicedoc/22122a.pdf
  270.  
  271. // Nanode has UNI/O SCIO on PD7
  272.  
  273. #define D7_ON  _BV(7)
  274. #define D7_OFF (~D7_ON)
  275.  
  276. #define SCIO_HIGH PORTD |= D7_ON
  277. #define SCIO_LOW  PORTD &= D7_OFF
  278.  
  279. #define SCIO_OUTPUT DDRD |= D7_ON
  280. #define SCIO_INPUT  DDRD &= D7_OFF
  281.  
  282. #define SCIO_READ ((PIND & D7_ON) != 0)
  283.  
  284. #define WAIT_QUARTER_BIT delayMicroseconds(9);
  285. #define WAIT_HALF_BIT delayMicroseconds(20);
  286.  
  287. #define NOP PORTD &= 0xff
  288.  
  289. // Fixed Timings
  290. // standby pulse time (600us+)
  291. #define UNIO_TSTBY_US 600
  292. // start header setup time (10us+)
  293. #define UNIO_TSS_US 10
  294. // start header low pulse (5us+)
  295. #define UNIO_THDR_US 6
  296.  
  297. // SCIO Manipulation macros
  298. #define BIT0 SCIO_HIGH;WAIT_HALF_BIT;SCIO_LOW;WAIT_HALF_BIT;
  299. #define BIT1 SCIO_LOW;WAIT_HALF_BIT;SCIO_HIGH;WAIT_HALF_BIT;
  300.  
  301. // 11AA02E48 defines
  302. #define DEVICE_ADDRESS 0xA0
  303. #define READ_INSTRUCTION 0x03
  304.  
  305. // Where on the chip is the MAC address located?
  306. #define CHIP_ADDRESS 0xFA
  307.  
  308. inline bool unio_readBit()
  309. {
  310.   SCIO_INPUT;
  311.   WAIT_QUARTER_BIT;
  312.   bool value1 = SCIO_READ;
  313.   WAIT_HALF_BIT;
  314.   bool value2 = SCIO_READ;
  315.   WAIT_QUARTER_BIT;
  316.   return (value2 && !value1);
  317. }
  318.  
  319. void unio_standby() {
  320.  
  321.   SCIO_OUTPUT;
  322.   SCIO_HIGH;
  323.   delayMicroseconds(UNIO_TSTBY_US);
  324. }
  325.  
  326. void unio_sendByte(byte data) {
  327.  
  328.   SCIO_OUTPUT;
  329.   for (int i=0; i<8; i++) {
  330.     if (data & 0x80) {
  331.       BIT1;
  332.     } else {
  333.       BIT0;
  334.     }
  335.     data <<= 1;
  336.   }
  337.   // MAK
  338.   BIT1;
  339.   // SAK?
  340.   /*bool sak =*/ unio_readBit();
  341. }
  342.  
  343. void unio_readBytes(byte *addr, int length) {
  344.   for (int i=0; i<length; i++) {
  345.    
  346.     byte data = 0;
  347.     for (int b=0; b<8; b++) {
  348.       data = (data << 1) | (unio_readBit() ? 1 : 0);
  349.     }
  350.     SCIO_OUTPUT;
  351.     if (i==length-1) {
  352.       BIT0; // NoMAK
  353.     } else {
  354.       BIT1; // MAK
  355.     }
  356.     /*bool sak =*/ unio_readBit();
  357.     addr[i] = data;
  358.   }
  359. }
  360.  
  361. void unio_start_header() {
  362.   SCIO_LOW;
  363.   delayMicroseconds(UNIO_THDR_US);
  364.   unio_sendByte(B01010101);
  365. }
  366.  
  367. void read_MAC(byte* mac_address) {
  368.  
  369.   // no interrupts!
  370.   cli();
  371.  
  372.   // standby
  373.   unio_standby();
  374.  
  375.   // start header
  376.   unio_start_header();
  377.  
  378.   unio_sendByte(DEVICE_ADDRESS);
  379.   unio_sendByte(READ_INSTRUCTION);
  380.   unio_sendByte(CHIP_ADDRESS >> 8);
  381.   unio_sendByte(CHIP_ADDRESS & 0xff);
  382.  
  383.   // read 6 bytes
  384.   unio_readBytes(mac_address, 6);
  385.  
  386.   // back to standby
  387.   unio_standby();
  388.  
  389.   // interrupts ok now
  390.   sei();
  391. }
  392.  
  393. // vim:ai:cin:sts=2 sw=2 ft=cpp
Add Comment
Please, Sign In to add comment