/* ORion: OpenRelief Ion Chamber Radiation Detector - http://openrelief.org Copyright: 2012 Andrew Back 2011 James Coliz (Pachube/Cosm Ethercard example) 2011 Rufus Cable (Nanode MAC addr chip code) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #define JFET A0 // Nanode pin connected to JFET source #define METER 3 // Nanode pin connected to moving coil meter (not used at present) #define HOLD_LOW 300 // Time in ms to hold the JFET source low #define READ_DELAY 500 // Time in ms between taking voltage readings // Set the Cosm feed ID and API key #define FEED "60745" #define APIKEY "secretkey" typedef byte bytes6_t[6]; int voltageDrift; byte mymac[6]; // Static IP configuration to use if no DHCP found static byte static_ip[] = { 0,0,0,0 }; static byte static_gw[] = { 0,0,0,0 }; static byte static_dns[] = { 0,0,0,0 }; char website[] PROGMEM = "api.cosm.com"; byte Ethernet::buffer[500]; uint32_t timer; Stash stash; void printf_begin(void); void read_MAC(byte*); void measure_drift(int); void setup() { Serial.begin(9600); printf_begin(); printf_P(PSTR("OpenRelief Ion Chamber Radiation Detector v0.1\n\r")); read_MAC(mymac); // Fetch the MAC address printf_P(PSTR("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n\r"), mymac[0], mymac[1], mymac[2], mymac[3], mymac[4], mymac[5] ); if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) printf_P(PSTR( "Failed to access Ethernet controller\n\r")); if (!ether.dhcpSetup()) { printf_P(PSTR("DHCP failed, using static configuration\n\r")); ether.staticSetup(static_ip, static_gw); ether.copyIp(ether.dnsip, static_dns); } ether.printIp("IP: ", ether.myip); ether.printIp("GW: ", ether.gwip); ether.printIp("DNS: ", ether.dnsip); if (!ether.dnsLookup(website)) printf_P(PSTR("DNS failed\n\r")); ether.printIp("SRV: ", ether.hisip); } void loop() { if(Stash::freeCount()<5){ // reset EtherCard stash if running low Stash::initMap(56); } voltageDrift = measure_drift(); printf_P(PSTR("Level: ")); Serial.println(voltageDrift); ether.packetLoop(ether.packetReceive()); if (millis() > timer) { timer = millis() + 10000; printf_P(PSTR("Posting to Cosm feed...\n\r")); // generate two fake values as payload - by using a separate stash, // we can determine the size of the generated message ahead of time byte sd = stash.create(); stash.print("radiation,"); stash.println((word) voltageDrift); stash.save(); // generate the header with payload - note that the stash size is used, // and that a "stash descriptor" is passed in as argument using "$H" Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n" "Host: $F" "\r\n" "X-ApiKey: $F" "\r\n" "Content-Length: $D" "\r\n" "\r\n" "$H"), website, PSTR(FEED), website, PSTR(APIKEY), stash.size(), sd); // send the packet - this also releases all stash buffers once done ether.tcpSend(); } } // Functions below here int serial_putc( char c, FILE * ) { Serial.write( c ); return c; } void printf_begin(void) { fdevopen( &serial_putc, 0 ); } // Measure JFET gate voltage drift over a fixed period int measure_drift() { pinMode(JFET, OUTPUT); // Hold JFET gate low for a period digitalWrite(JFET, LOW); delay(HOLD_LOW); pinMode(JFET, INPUT); // Prepare to read JFET gate voltage int v1 = analogRead(JFET); // Take first reading delay(READ_DELAY); // Wait int v2 = analogRead(JFET); // Take a second reading return (v2 - v1); // Calculate drift } // Nanode_MAC // Rufus Cable, June 2011 (threebytesfull) // Sample code to read the MAC address from the 11AA02E48 on the // back of the Nanode V5 board. // This code is hacky and basic - it doesn't check for bus errors // and will probably fail horribly if it's interrupted. It's best // run in setup() - fetch the MAC address once and keep it. After // the address is fetched, it puts the chip back in standby mode // in which it apparently only consumes 1uA. // Feel free to reuse this code - suggestions for improvement are // welcome! :) // http://ww1.microchip.com/downloads/en/DeviceDoc/DS-22067H.pdf // http://ww1.microchip.com/downloads/en/devicedoc/22122a.pdf // Nanode has UNI/O SCIO on PD7 #define D7_ON _BV(7) #define D7_OFF (~D7_ON) #define SCIO_HIGH PORTD |= D7_ON #define SCIO_LOW PORTD &= D7_OFF #define SCIO_OUTPUT DDRD |= D7_ON #define SCIO_INPUT DDRD &= D7_OFF #define SCIO_READ ((PIND & D7_ON) != 0) #define WAIT_QUARTER_BIT delayMicroseconds(9); #define WAIT_HALF_BIT delayMicroseconds(20); #define NOP PORTD &= 0xff // Fixed Timings // standby pulse time (600us+) #define UNIO_TSTBY_US 600 // start header setup time (10us+) #define UNIO_TSS_US 10 // start header low pulse (5us+) #define UNIO_THDR_US 6 // SCIO Manipulation macros #define BIT0 SCIO_HIGH;WAIT_HALF_BIT;SCIO_LOW;WAIT_HALF_BIT; #define BIT1 SCIO_LOW;WAIT_HALF_BIT;SCIO_HIGH;WAIT_HALF_BIT; // 11AA02E48 defines #define DEVICE_ADDRESS 0xA0 #define READ_INSTRUCTION 0x03 // Where on the chip is the MAC address located? #define CHIP_ADDRESS 0xFA inline bool unio_readBit() { SCIO_INPUT; WAIT_QUARTER_BIT; bool value1 = SCIO_READ; WAIT_HALF_BIT; bool value2 = SCIO_READ; WAIT_QUARTER_BIT; return (value2 && !value1); } void unio_standby() { SCIO_OUTPUT; SCIO_HIGH; delayMicroseconds(UNIO_TSTBY_US); } void unio_sendByte(byte data) { SCIO_OUTPUT; for (int i=0; i<8; i++) { if (data & 0x80) { BIT1; } else { BIT0; } data <<= 1; } // MAK BIT1; // SAK? /*bool sak =*/ unio_readBit(); } void unio_readBytes(byte *addr, int length) { for (int i=0; i> 8); unio_sendByte(CHIP_ADDRESS & 0xff); // read 6 bytes unio_readBytes(mac_address, 6); // back to standby unio_standby(); // interrupts ok now sei(); }