Skip to content

Instantly share code, notes, and snippets.

@jamescoxon
Created August 7, 2016 09:40
Show Gist options
  • Select an option

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

Select an option

Save jamescoxon/1662093161c996b6a73cf1958bb3f12c 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[] = "0,0,0";
//*************Pin Setup ****************/
int batt_pin = 5; //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 = 9, rx_packets = 0, reset_pin = A0, total_count = 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");
}
delay(100);
attachInterrupt(0, interrupt_function, RISING);
}
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){
//Stop stuff
SPI.end();
detachInterrupt(0);
//**** Battery Voltage ******
battV = analogRead(batt_pin);
//**** GPS Data ******
gps_check_nav();
if(navmode != 6){
setupGPS();
delay(2000);
}
gps_check_lock();
gps_get_position();
Serial.print(sats);
Serial.print(" ");
Serial.println(GPSerror);
n=sprintf(data_temp, "%c%cL%ld,%ld,%ldV%dX%d,%d,%d[%s]", num_repeats, data_count, lat, lon, alt, battV, rx_packets, navmode, sats, id);
//Reset Radio module
digitalWrite(HIGH, reset_pin);
delay(100);
digitalWrite(LOW, reset_pin);
delay(100);
setupRFM69();
delay(2000);
}
Serial.print(data_temp); Serial.print (" "); Serial.println(n);
return n;
}
void setup()
{
pinMode(reset_pin, OUTPUT);
digitalWrite(reset_pin, LOW);
Serial.begin(9600);
randomSeed(analogRead(6));
timer_setup();
delay(1000);
setupGPS();
setupRFM69();
delay(1000);
packet_len = gen_Data();
//Serial.print("tx: "); Serial.println((char*)data);
send_data();
}
void loop()
{
delay(1000);
Serial.println(rf69.spiRead(RFM69_REG_07_FRF_MSB));
if (f_timer == 2){
detected_data();
f_timer = 0;
}
if (total_count > 10){
transmit_time();
total_count = 0;
}
else{
total_count++;
}
}
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(){
rf69.send((byte*)data_temp, packet_len);
delay(delay_length);
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*****************
/**
* Verify that the uBlox 6 GPS receiver is set to the <1g airborne
* navigaion mode.
*/
uint8_t gps_check_nav(void)
{
GPSerror = 0;
Serial.flush();
uint8_t request[8] = {0xB5, 0x62, 0x06, 0x24, 0x00, 0x00,
0x2A, 0x84};
sendUBX(request, 8);
// Get the message back from the GPS
gps_get_data();
// Verify sync and header bytes
if( buf[0] != 0xB5 || buf[1] != 0x62 ){
GPSerror = 41;
}
if( buf[2] != 0x06 || buf[3] != 0x24 ){
GPSerror = 42;
}
// Check 40 bytes of message checksum
if( !_gps_verify_checksum(&buf[2], 40) ) {
GPSerror = 43;
}
// Return the navigation mode and let the caller analyse it
navmode = buf[8];
}
// 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;
}
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 gps_get_data()
{
f_timer = 0;
int i = 0;
while (f_timer == 0) {
// Make sure data is available to read
if (Serial.available()) {
buf[i] = Serial.read();
i++;
}
}
f_timer = 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;
}
}
/**
* 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;
}
}
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