Skip to content

Instantly share code, notes, and snippets.

@jamescoxon
Created April 26, 2014 08:36
Show Gist options
  • Select an option

  • Save jamescoxon/11314983 to your computer and use it in GitHub Desktop.

Select an option

Save jamescoxon/11314983 to your computer and use it in GitHub Desktop.
/*
UKHASnet rf69_repeater code
based on rf22_client.pde/ino from the RF22 library
*/
#include <SPI.h>
//You'll need to use the RFM69 library from the UKHASnet repo
#include <RFM69.h>
#include <RFM69Config.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
//*************Node ID Setup ****************/
char id[] = "BALL"; //Please register your node on the UKHASnet website
int node_type = 4; //0 = gateway, 1 = repeater voltage, 2 = bridge (not implemented), 3 = low power node (please set battery thresholds), 4 = balloon
char location_string[] = "51.498,-0.0527";
//*************Pin Setup ****************/
int batt_pin = 0; //ADC 0 - measure battery voltage
int charge_pin = 1; //ADC 1 - measure solar voltage
//*************Misc Setup ****************/
byte num_repeats = '5'; //The number of hops the message will make before stopping
int battV_threshold = 1000; // ADC reading which below will stop listening and only tx
int slow_freq_threshold = 800; // ADC reading which below will reduce frequency of tx to conserve power
int n, battV = 0, chargeV = 0, packet_len, delay_length = 50, count = 0, tx_trigger = 0, num_counts = 1, rx_packets = 0;
byte data_count = 97; // 'a'
char data_temp[64], string_end[] = "]";
int navmode = 9, GPSerror = 1;
uint8_t buf[80]; //GPS receive buffer
int32_t lat = 12345, lon = 6789, alt = 0;
uint8_t lock = 0, sats = 0;
volatile int f_timer=0;
// Singleton instance of the radio
RFM69 rf69;
void setupRFM69(){
if(!rf69.init()){
//Serial.println("RFM69 Failed");
}
else{
//Serial.println("RFM69 Booted");
}
attachInterrupt(0, interrupt_function, RISING);
delay(100);
}
void interrupt_function(){
rf69.isr0();
/* set the flag. */
f_timer = 2;
}
ISR(TIMER1_COMPA_vect)
{
/* set the flag. */
f_timer = 1;
}
int gen_Data(){
//**** Internal Temperature (RFM69) ******
//byte intTemp = rf69.readTemperature(-1); // -1 = user cal factor, adjust for correct ambient
byte intTemp = 0;
//**** RSSI ******
uint8_t rssi = rf69.lastRssi();
if(node_type == 0 || data_count == 97){
//For Gateway (no sensors attached)
// Location is hard coded
n=sprintf(data_temp, "%c%cL%sT%dR%d[%s]", num_repeats, data_count, location_string, intTemp, rssi, id);
}
else if(node_type == 4){
//**** GPS Data ******
//noInterrupts();
//if(checkNAV() != 6){
// setupGPS();
// }
//gps_check_lock();
//delay(1000);
//gps_get_time();
n=sprintf(data_temp, "%c%cL%ld,%ld[%s]", num_repeats, data_count, lat, lon, id);
}
Serial.print(data_temp); Serial.print (" "); Serial.println(n);
return n;
}
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(6));
delay(1000);
setupGPS();
setupRFM69();
delay(1000);
packet_len = gen_Data();
//Serial.print("tx: "); Serial.println((char*)data);
send_data();
timer_setup();
}
void loop()
{
delay(100);
if (f_timer == 2){
detected_data();
f_timer = 0;
}
else if(f_timer == 1 && tx_trigger == 0)
{
if (count > num_counts){
transmit_time();
count = 0;
}
else{
//gps_get_position();
//gps_check_lock();
Serial.print(sats);
Serial.print(" ");
Serial.println(GPSerror);
alt = alt / 1000;
delay(1000);
count++;
Serial.println(rf69.spiRead(RFM69_REG_07_FRF_MSB));
}
f_timer = 0;
}
}
void timer_setup(){
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to desired timer count:
OCR1A = 15624;
// turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS12);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
sei(); // enable global interrupts
}
void transmit_time()
{
//**** Packet Tx Count ******
//using a byte to keep track of transmit count
// its meant to roll over
data_count++;
//'a' packet is only sent on the first transmission so we need to move it along
// when we roll over.
// 98 = 'b' up to 122 = 'z'
if(data_count > 122){
data_count = 98; //'b'
}
packet_len = gen_Data();
send_data();
}
void send_data(){
tx_trigger = 1;
rf69.send((byte*)data_temp, packet_len);
delay(delay_length);
tx_trigger = 0;
Serial.println("Transmitted");
}
void detected_data()
{
// Listen for data
uint8_t buf_radio[64];
uint8_t len = sizeof(buf_radio);
rf69.recv(buf_radio, &len);
// Need to take the recieved buffer and decode it and add a reference
for (int i=0; i<len; i++) {
if (buf_radio[i] == ']') {
//Print the string
buf_radio[i+1] = '\0';
Serial.print("rx: "); Serial.println((char*)buf_radio);
rx_packets++;
if (buf_radio[0] > '0'){
//Reduce the repeat value
buf_radio[0] = buf_radio[0] - 1;
//Now add , and end line and let string functions do the rest
buf_radio[i] = ',';
buf_radio[i+1] = '\0';
strcpy(data_temp, (char*)buf_radio); //first copy buf to data (bytes to char)
if(strstr(data_temp, id) == 0){
strcat(data_temp, id); //add ID
strcat(data_temp, string_end); //add ending
packet_len = strlen(data_temp);
//random delay to try and avoid packet collision
delay(random(50, 500));
//Serial.print("Repeat data: "); Serial.println((char*)data_temp);
send_data();
break;
}
else {
break;
}
}
else {
break;
}
}
}
}
//************Other Functions*****************
//Function to poll the NAV5 status of a Ublox GPS module (5/6)
//Sends a UBX command (requires the function sendUBX()) and waits 1 seconds
// for a reply from the module. It then isolates the byte which contains
// the information regarding the NAV5 mode,
// 0 = Pedestrian mode (default, will not work above 12km)
// 6 = Airborne 1G (works up to 50km altitude)
//Adapted by jcoxon from getUBX_ACK() from the example code on UKHAS wiki
// http://wiki.ukhas.org.uk/guides:falcom_fsa03
boolean checkNAV(){
uint8_t getNAV5[] = { 0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, 0x2A, 0x84 }; //Poll NAV5 status
Serial.flush();
sendUBX(getNAV5, 8);
gps_get_data();
navmode = buf[8];
if (navmode == 6){
return true;
}
else{
return false;
}
}
// Send a byte array of UBX protocol to the GPS
void sendUBX(uint8_t *MSG, uint8_t len) {
for(int i=0; i<len; i++) {
Serial.write(MSG[i]);
}
//Serial.println();
}
/**
* Calculate a UBX checksum using 8-bit Fletcher (RFC1145)
*/
void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka,
uint8_t* ckb)
{
*cka = 0;
*ckb = 0;
for( uint8_t i = 0; i < len; i++ )
{
*cka += *data;
*ckb += *cka;
data++;
}
}
/**
* Verify the checksum for the given data and length.
*/
bool _gps_verify_checksum(uint8_t* data, uint8_t len)
{
uint8_t a, b;
gps_ubx_checksum(data, len, &a, &b);
if( a != *(data + len) || b != *(data + len + 1))
return false;
else
return true;
}
/**
* Get data from GPS, times out after 1 second.
*/
void gps_get_data()
{
int i = 0;
unsigned long startTime = millis();
while (1) {
// Make sure data is available to read
if (Serial.available()) {
buf[i] = Serial.read();
i++;
}
// Timeout if no valid response in 1 seconds
if (millis() - startTime > 1000) {
break;
}
}
}
/**
* Check the navigation status to determine the quality of the
* fix currently held by the receiver with a NAV-STATUS message.
*/
void gps_check_lock()
{
GPSerror = 0;
Serial.flush();
// Construct the request to the GPS
uint8_t request[8] = {0xB5, 0x62, 0x01, 0x06, 0x00, 0x00,
0x07, 0x16};
sendUBX(request, 8);
// Get the message back from the GPS
gps_get_data();
// Verify the sync and header bits
if( buf[0] != 0xB5 || buf[1] != 0x62 ) {
GPSerror = 11;
}
if( buf[2] != 0x01 || buf[3] != 0x06 ) {
GPSerror = 12;
}
// Check 60 bytes minus SYNC and CHECKSUM (4 bytes)
if( !_gps_verify_checksum(&buf[2], 56) ) {
GPSerror = 13;
}
if(GPSerror == 0){
// Return the value if GPSfixOK is set in 'flags'
if( buf[17] & 0x01 )
lock = buf[16];
else
lock = 0;
sats = buf[53];
}
else {
lock = 0;
}
}
/**
* Poll the GPS for a position message then extract the useful
* information from it - POSLLH.
*/
void gps_get_position()
{
GPSerror = 0;
Serial.flush();
// Request a NAV-POSLLH message from the GPS
uint8_t request[8] = {0xB5, 0x62, 0x01, 0x02, 0x00, 0x00, 0x03,
0x0A};
sendUBX(request, 8);
// Get the message back from the GPS
gps_get_data();
// Verify the sync and header bits
if( buf[0] != 0xB5 || buf[1] != 0x62 )
GPSerror = 21;
if( buf[2] != 0x01 || buf[3] != 0x02 )
GPSerror = 22;
if( !_gps_verify_checksum(&buf[2], 32) ) {
GPSerror = 23;
}
if(GPSerror == 0) {
// 4 bytes of longitude (1e-7)
lon = (int32_t)buf[10] | (int32_t)buf[11] << 8 |
(int32_t)buf[12] << 16 | (int32_t)buf[13] << 24;
//lon /= 1000;
// 4 bytes of latitude (1e-7)
lat = (int32_t)buf[14] | (int32_t)buf[15] << 8 |
(int32_t)buf[16] << 16 | (int32_t)buf[17] << 24;
//lat /= 1000;
// 4 bytes of altitude above MSL (mm)
alt = (int32_t)buf[22] | (int32_t)buf[23] << 8 |
(int32_t)buf[24] << 16 | (int32_t)buf[25] << 24;
alt /= 1000;
}
}
void setupGPS() {
//Turning off all GPS NMEA strings apart on the uBlox module
// Taken from Project Swift (rather than the old way of sending ascii text)
uint8_t setNMEAoff[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xA9};
sendUBX(setNMEAoff, sizeof(setNMEAoff)/sizeof(uint8_t));
delay(500);
// Check and set the navigation mode (Airborne, 1G)
uint8_t setNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC};
sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t));
delay(500);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment