//#define ONEWIRE #define RFM69 #define SERIALDEBUG //#ifdef ESP8266 // ESP8266 based platform //#ifdef AVR // AVR based platform #ifdef RFM69 #include #include byte rfm_txpower = 20; float rfm_freq_trim = 0.068f; int16_t lastrssi; #define RFMRESET_PORT PORTB #define RFMRESET_DDR DDRB #define RFMRESET_PIN _BV(1) #endif #ifdef ONEWIRE #include #include #endif char NODE_NAME[9] = "OSTEST"; // null-terminated string, max 8 bytes, A-z0-9 uint8_t NODE_NAME_LEN = strlen(NODE_NAME); char HOPS = '9'; // '0'-'9' uint16_t BROADCAST_INTERVAL = 15; float LATITUDE = NAN; float LONGITUDE = NAN; float ALTITUDE = NAN; const byte BUFFERSIZE = 128; const byte PAYLOADSIZE = 64; double vsense_offset = 0.74d; // Seems like it depends on current usage. Jumps to 0.76V double vsense_mult = 15.227d; // const uint32_t baudrate = 9600; // The code in this sketch assumes clock speed of 8MHz (eg. the internal oscilator) #ifdef ONEWIRE const int OWPIN = 9; // 1-wire bus connected on pin 9 const int DSRES = 12; // 12-bit temperature resolution OneWire onewire(OWPIN); DallasTemperature dstemp(&onewire); DeviceAddress dsaddr; #endif typedef enum packet_source_t { SOURCE_UNKNOWN, SOURCE_SELF, SOURCE_SERIAL, SOURCE_WIFI, SOURCE_LAN, SOURCE_RFM, SOURCE_NRF24 } packet_source_t; packet_source_t packet_source; typedef enum gps_lock_t { GPS_LOCK_UNKNOWN, GPS_LOCK_NO, GPS_LOCK_2D, GPS_LOCK_3D } gps_lock_t; gps_lock_t gps_lock = GPS_LOCK_UNKNOWN; /* ------------------------------------------------------------------------- */ byte cpu_div = 1; void CPU_8MHz() { /* cli(); CLKPR = 0b10000000; CLKPR = 0b00000000; // Clock divider: 1 cpu_div = 1; sei(); // USART0 - http://wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=1&u2xmode=1 UCSR0A = UCSR0A | 0b00000010; // Enable double speed UBRR0 = 0x0067; // 9600bps */ } void CPU_4MHz() { /* cli(); CLKPR = 0b10000000; CLKPR = 0b00000001; // Clock divider: 2 cpu_div = 2; sei(); // USART0 UCSR0A = UCSR0A | 0b00000010; // Enable double speed UBRR0 = 0x0033; // 9600bps */ } void CPU_2MHz() { /* cli(); CLKPR = 0b10000000; CLKPR = 0b00000010; // Clock divider: 4 cpu_div = 4; sei(); // USART0 UCSR0A = UCSR0A | 0b00000010; // Enable double speed UBRR0 = 0x0019; // 9600bps */ } void CPU_1MHz() { /* cli(); CLKPR = 0b10000000; CLKPR = 0b00000011; // Clock divider: 8 cpu_div = 8; sei(); // USART0 UCSR0A = UCSR0A | 0b00000010; // Enable double speed UBRR0 = 0x000C; // 9600bps */ } void setCPUDIV(byte div) { switch (div) { case 1: CPU_8MHz(); break; case 2: CPU_4MHz(); break; case 4: CPU_2MHz(); break; case 8: CPU_1MHz(); break; } } void sleep(unsigned long d) { delay(d / cpu_div); } unsigned long timer_lastgps = 0; bool timer_lastgps_enabled = false; byte databuf[BUFFERSIZE]; byte dataptr = 0; unsigned long packet_count = 0; byte sequence = 0; /* ------------------------------------------------------------------------- */ // TODO: make all functions respect BUFFERSIZE. void resetData() { dataptr = 0; } // Add \0 terminated string, excluding \0 void addString(char *value) { int i = 0; while (value[i]) { if (dataptr < BUFFERSIZE) { databuf[dataptr++] = value[i++]; } } } char _floatbuf[16]; void addFloat(double value, byte precission = 2, bool strip=true) { dtostrf(value, 1, precission, _floatbuf); if (precission and strip) { byte e; for (byte i=0;i<16;i++) { if (!_floatbuf[i]) { e = i-1; break; } } for (byte i=e; i; i--) { if (_floatbuf[i] == '0') { _floatbuf[i] = 0; } else if (_floatbuf[i] == '.') { _floatbuf[i] = 0; break; } else { break; } } } addString(_floatbuf); } void addCharArray(char *value, byte len) { /* Add char array to the output data buffer (databuf) */ for (byte i=0; i> 24 & 0xff; databuf[dataptr++] = value >> 16 & 0xff; databuf[dataptr++] = value >> 8 & 0xff; databuf[dataptr++] = value & 0xff; } void addWord(word value) { // word, int, unsigned int databuf[dataptr++] = value >> 8 & 0xff; databuf[dataptr++] = value & 0xff; } void addByte(byte value) { // byte, char, unsigned char databuf[dataptr++] = value; } /* ------------------------------------------------------------------------- */ #ifdef RFM69 void rfm69_reset() { RFMRESET_DDR |= RFMRESET_PIN; RFMRESET_PORT |= RFMRESET_PIN; delay(100); RFMRESET_PORT &= ~(RFMRESET_PIN); while(rf69_init() != RFM_OK) { delay(100); } } uint8_t freqbuf[3]; long _freq; void rfm69_set_frequency(float freqMHz) { _freq = (long)(((freqMHz + rfm_freq_trim) * 1000000) / 61.04f); // 32MHz / 2^19 = 61.04 Hz freqbuf[0] = (_freq >> 16) & 0xff; freqbuf[1] = (_freq >> 8) & 0xff; freqbuf[2] = _freq & 0xff; #ifdef HAVE_HWSERIAL0 Serial.print(F("Setting frequency to: ")); Serial.print(freqMHz, DEC); Serial.print(F("MHz = 0x")); Serial.println(_freq, HEX); Serial.flush(); _rf69_burst_write(RFM69_REG_07_FRF_MSB, freqbuf, 3); _rf69_burst_read(RFM69_REG_07_FRF_MSB, freqbuf, 3); _freq = (freqbuf[0] << 16) | (freqbuf[1] << 8) | freqbuf[2]; Serial.print(F("Frequency was set to: ")); Serial.print((float)_freq / 1000000 * 61.04f, DEC); Serial.print(F("MHz = 0x")); Serial.println(_freq, HEX); Serial.flush(); #endif } #endif void setup() { CPU_8MHz(); #ifdef HAVE_HWSERIAL0 Serial.begin(9600); Serial.print(F("\nUKHASnet: Oddstr13's atmega328 battery node ")); Serial.println(NODE_NAME); Serial.flush(); #endif #ifdef ONEWIRE #ifdef HAVE_HWSERIAL0 Serial.println(F("Scanning 1-wire bus...")); #endif dstemp.begin(); dstemp.setResolution(12); #ifdef HAVE_HWSERIAL0 Serial.print(F("1-wire devices: ")); Serial.print(dstemp.getDeviceCount(), DEC); Serial.println(); Serial.print(F("1-wire parasite: ")); Serial.println(dstemp.isParasitePowerMode()); Serial.flush(); #endif if (!dstemp.getAddress(dsaddr, 0)) { #ifdef HAVE_HWSERIAL0 Serial.println("WARNING: 1-wire: Unable to find temperature device"); Serial.flush(); #endif } #endif #ifdef RFM69 rfm69_reset(); for (uint8_t i = 0; CONFIG[i][0] != 255; i++) { Serial.print("Setting "); Serial.print(CONFIG[i][0], HEX); Serial.print(" = "); Serial.println(CONFIG[i][1], HEX); } rf69_set_mode(RFM69_MODE_RX); //rf69_SetLnaMode(RF_TESTLNA_SENSITIVE); // NotImplemented #ifdef HAVE_HWSERIAL0 Serial.println(F("Radio started.")); dump_rfm69_registers(); Serial.flush(); rfm69_set_frequency(869.5f); #endif #endif #ifdef HAVE_HWSERIAL0 // UBRR0 = 0x0033; CPU_1MHz(); Serial.println(F("Serial test at 1MHz clock speed.")); Serial.flush(); CPU_2MHz(); Serial.println(F("Serial test at 2MHz clock speed.")); Serial.flush(); CPU_4MHz(); Serial.println(F("Serial test at 4MHz clock speed.")); Serial.flush(); CPU_8MHz(); Serial.println(F("Serial test at 8MHz clock speed.")); Serial.flush(); #endif CPU_1MHz(); } double voltage = 0; double readVCC() { voltage = getVCCVoltage(); #ifdef RFM69 if (voltage < 2.5) { rfm_txpower = 10; } else { rfm_txpower = 20; } #endif return voltage; } void bumpSequence() { sequence++; sequence %= 26; if (!sequence) { // 'a' should only be sendt on boot. sequence++; } } void sendOwn() { resetData(); addByte(HOPS); addByte(sequence+97); addByte('V'); addFloat(readVCC()); //addByte(','); //addFloat(getBatteryVoltage()); addByte('T'); addFloat(getChipTemp()); #ifdef ONEWIRE if (voltage > 2.75) { double temp = getDSTemp(); if (temp != 85) { addByte(','); addFloat(getDSTemp(), 3); } } #endif #ifdef RFM69 addByte('R'); addFloat((lastrssi / 2.0f) * -1); #endif switch (sequence) { case 1: // Location break; case 2: // Mode addString("Z0"); break; /*case 3: // Comment addString(":no sleep"); break;*/ } addByte('['); addString(NODE_NAME); addByte(']'); send(); bumpSequence(); } void addLocation() { } void sendPositionStatus() { resetData(); addByte(HOPS); addByte(sequence+97); switch (gps_lock) { case GPS_LOCK_UNKNOWN: addString(":GPS Disconnected"); break; case GPS_LOCK_NO: addString(":No GPS lock"); break; case GPS_LOCK_2D: addByte('L'); addFloat(LATITUDE, 5); addByte(','); addFloat(LONGITUDE, 5); addString(":2D GPS Lock"); break; case GPS_LOCK_3D: addByte('L'); addFloat(LATITUDE, 5); addByte(','); addFloat(LONGITUDE, 5); addByte(','); addFloat(ALTITUDE, 1); addString(":3D GPS Lock"); break; } addByte('['); addString(NODE_NAME); addByte(']'); send(); bumpSequence(); } uint8_t path_start, path_end; bool has_repeated; //rfm_status_t rf69_receive(rfm_reg_t* buf, rfm_reg_t* len, int16_t* lastrssi, // bool* rfm_packet_waiting); // typedef enum packet_source_t { SOURCE_UNKNOWN, SOURCE_SELF, SOURCE_SERIAL, SOURCE_WIFI, SOURCE_LAN, SOURCE_RFM, SOURCE_NRF24 } packet_source_t; bool packet_received; // packet_source_t packet_source; void handleUKHASNETPacket() { Serial.println("handleUKHASNETPacket"); path_start = 0; path_end = 0; has_repeated = false; for (uint8_t i=0; i= '0') { dataptr = path_end; addByte(','); addCharArray(NODE_NAME, NODE_NAME_LEN); addByte(']'); send(); } } uint8_t c_find(uint8_t start, char sep, uint8_t count) { uint8_t pos = start; for (uint8_t i=0; i < count; i++) { while (databuf[pos++] != sep) {} } return pos; } uint8_t c_find(uint8_t start, char sep) { return c_find(start, sep, 1); } uint8_t c_find(char sep, uint8_t count) { return c_find(0, sep, count); } uint8_t c_find(char sep) { return c_find(0, sep, 1); } bool s_cmp(char* a, char* b, uint8_t count) { for (uint8_t i=0;i= '0' and buf[i] <= '9') { _f_mult *= 10; } } float res = 0; for (uint8_t i=0; i= '0' and buf[i] <= '9') { res += (buf[i] - 48) * _f_mult; _f_mult /= 10; } } if (_neg) { res *= -1; } //Serial.println(res); return res; } float parse_float(char* buf) { return parse_float(buf, strlen(buf)); } uint8_t _gpspos; float _gpsfloat; char _gpsbuf[17]; gps_lock_t _gps_oldstatus = GPS_LOCK_UNKNOWN; void handleGPSString() { if (s_cmp((char*)databuf, "$GPGSA")) { timer_lastgps = millis(); timer_lastgps_enabled = true; _gpspos = c_find(',', 2); s_sub((char*)databuf, _gpsbuf, _gpspos, c_find(_gpspos, ',')-1); //Serial.println(_gpsbuf); switch (_gpsbuf[0]) { case '1': gps_lock = GPS_LOCK_NO; break; case '2': gps_lock = GPS_LOCK_2D; break; case '3': gps_lock = GPS_LOCK_3D; break; default: gps_lock = GPS_LOCK_UNKNOWN; } // $GPGGA,123710.00,6240.76823,N,01001.78175,E,1,06,1.16,613.9,M,40.5,M,,*52 } else if (s_cmp((char*)databuf, "$GPGGA")) { timer_lastgps = millis(); timer_lastgps_enabled = true; if (gps_lock == GPS_LOCK_2D or gps_lock == GPS_LOCK_3D) { _gpspos = c_find(',', 2); LATITUDE = (databuf[_gpspos] - 48) * 10; LATITUDE += databuf[_gpspos + 1] - 48; s_sub((char*)databuf, _gpsbuf, _gpspos+2, c_find(_gpspos, ',')-1); _gpsfloat = parse_float(_gpsbuf); LATITUDE += _gpsfloat / 60; // TODO: Handle N/S _gpspos = c_find(',', 3); s_sub((char*)databuf, _gpsbuf, _gpspos, c_find(_gpspos, ',')-1); if (_gpsbuf[0] == 'S') { LATITUDE *= -1; } Serial.print("Latitude: "); Serial.println(LATITUDE); _gpspos = c_find(',', 4); LONGITUDE = parse_float((char*)&databuf[_gpspos], 3); //LONGITUDE = (databuf[_gpspos + 1] - 48) * 10; //LONGITUDE += databuf[_gpspos + 2] - 48; s_sub((char*)databuf, _gpsbuf, _gpspos+3, c_find(_gpspos, ',')-1); _gpsfloat = parse_float(_gpsbuf); LONGITUDE += _gpsfloat / 60; // TODO: Handle N/S _gpspos = c_find(',', 5); s_sub((char*)databuf, _gpsbuf, _gpspos, c_find(_gpspos, ',')-1); if (_gpsbuf[0] == 'W') { LONGITUDE *= -1; } Serial.print("Longitude: "); Serial.println(LONGITUDE); } if (gps_lock == GPS_LOCK_3D) { _gpspos = c_find(',', 9); ALTITUDE = parse_float((char*)&databuf[_gpspos], c_find(_gpspos, ',')-1-_gpspos); Serial.print("Altitude: "); Serial.println(ALTITUDE); } if (_gps_oldstatus != gps_lock) { sendPositionStatus(); } _gps_oldstatus = gps_lock; } } void handlePacket() { Serial.print("handlePacket "); Serial.write(databuf[0]); Serial.write(databuf[1]); //Serial.write(databuf[dataptr]); Serial.println(); if (databuf[0] >= '0' and databuf[0] <= '9' and databuf[1] >= 'a' and databuf[1] <= 'z') { handleUKHASNETPacket(); } else if (s_cmp((char*)databuf, "$GP")) { if (packet_source == SOURCE_SERIAL) { handleGPSString(); } } } void handleRX() { #ifdef RFM69 rf69_receive(databuf, &dataptr, &lastrssi, &packet_received); if (packet_received) { packet_source = SOURCE_RFM; Serial.println(packet_received); handlePacket(); } #endif #ifdef SERIALDEBUG if (Serial.available()) { dataptr = Serial.readBytesUntil('\n', databuf, BUFFERSIZE); packet_source = SOURCE_SERIAL; handlePacket(); } #endif } /* ------------------------------------------------------------------------- */ const unsigned long MAXULONG = 0xffffffff; unsigned long now; unsigned long getTimeSince(unsigned long ___start) { unsigned long interval; now = millis(); if (___start > now) { interval = MAXULONG - ___start + now; } else { interval = now - ___start; } return interval; } /* ------------------------------------------------------------------------- */ unsigned long timer_sendown = 0; //millis(); void loop() { handleRX(); if (timer_lastgps_enabled and getTimeSince(timer_lastgps) >= 15000) { gps_lock = GPS_LOCK_UNKNOWN; sendPositionStatus(); timer_lastgps_enabled = false; } if (getTimeSince(timer_sendown) >= (BROADCAST_INTERVAL * 1000)) { timer_sendown = millis(); sendOwn(); } // sleep(1000); // sleep(60000); } void send() { #ifdef HAVE_HWSERIAL0 for (int i=0;i