/* * GPS telemetry using standard RTTY 5N1.5 170 45.45 sender * for the HopeRF rfm69hcw * on a ProMini 3.3 * Charles Webb * KC1ENN@arrl.net * * with thanks to Ted Van Slyck * * Written by Ted Van Slyck www.openrcdesign.com * Feel free to use for personal non commercial use * use at your own risk, no warranties. It probably has errors of some kind. * * -- Fixed the only error in Ted's most excellent code to fix an issue with shifted characters as noted below - cwebb */ #include #include #include #define MODULATION 0x60 //#define radioPower 0x50 // -2 dBm //#define radioPower 0x52 // 0 dBm //#define radioPower 0x55 // 3 dBm #define radioPower 0x58 // 6 dBm //#define radioPower 0x5B // 9 dBm //#define radioPower 0x5E // 12 dBm //#define radioPower 0x7F // 17 dBm #define ssPin 10 // SS //#define ssPin 8 // adafruit feather M0 #define rstPin 9 // reset pin //#define rstPin 4 // adafruit feather M0 #define myShift 3 // 3 x 61 Hz = 181 Hz ~ 170 Hz #define myDelay 1 // delay in seconds between loops #define myFrequency 433200000 // 70cm //#define myFrequency 915000000 // 33cm char mytext[80]; String myCallSign = "CALLSIGN/B"; String myString = ""; int myStringLen = 0; int current_state; int previous_state; int send_shift; float baud = 45.45; float bit_time = 1000/baud;; float stop_bit_time = bit_time * 2; int index = 0; uint32_t myMark; uint32_t mySpace; unsigned int count=0; char mycount = 0; int myHour, myMinute, mySecond, myAlt, mySpd, mySat; double myLat, myLng; // For stats that happen every 5 seconds unsigned long last = 0UL; TinyGPSPlus gps; SoftwareSerial ss(6,7); // Tx Rx void setup(){ Serial.begin(9600); ss.begin(9600); pinMode(ssPin, OUTPUT); pinMode(rstPin, OUTPUT); setupSPI(); delay(1000); resetRFM69(); // a good thing to use and necessary if using boards with level shifters delay(1000); setupRFM69(); } void loop (){ count++; fetchGPS(); buildString(); transmitData(); delay (myDelay * 1000); // delay between transmit cycle } //ends void loop void txString(String dataString) { Serial.println(dataString); // print to Serial Monitor myString = dataString; myStringLen = myString.length(); transmitData(); } void buildString() { myString = myCallSign; myString += " COUNT " + String(count); myString += " TIME " + String(myHour) + "/" + String(myMinute) + "/" + String(mySecond); myString += " LAT " + String(myLat,7) + " LNG " + String(myLng,7); myString += " ALT " + String(myAlt) + " SPD " + String(mySpd) + " SAT " + String(mySat); myString += "..."; myString.toUpperCase(); myStringLen = myString.length(); Serial.print("I am sending: "); Serial.println(myString); } void fetchGPS() { myHour = gps.time.hour(); myMinute = gps.time.minute(); mySecond = gps.time.second(); myLat = gps.location.lat(); myLng = gps.location.lng(); myAlt = gps.altitude.feet(); mySpd = gps.speed.mph(); mySat = gps.satellites.value(); smartDelay(1000); } void setupRFM69() { writeReg(0x01,0x84); // set RegOpMode to Sequencer On Listen Off Standby = 0x04 writeReg(0x02,MODULATION); // RegDataModul = Continuous mode w/0 synthesizer FSK No Shaping = 0x60 setFrequency(myFrequency); getMark(myFrequency); getSpace(myFrequency); writeReg(0x26,0x07); // CLK off to save power writeReg(0x01, 0x0C); // set to TX mode writeReg(0x11,radioPower); // 0x9F PA0 On only, 0x5F or 0x41 // Pa1On 0x40 to 0x5F ????? Was 0x70 } void resetRFM69() { digitalWrite(rstPin, HIGH); delay(100); digitalWrite(rstPin, LOW); delay(100); } void getMark(uint32_t freqHz) { freqHz /= 61; // divide down by FSTEP to get FRF myMark = freqHz; } void getSpace(uint32_t freqHz) { freqHz /= 61; // divide down by FSTEP to get FRF mySpace = freqHz - 3; } void printReg(byte data){ Serial.print("Register "); Serial.print(data); Serial.print(" = "); Serial.println(readReg(data), HEX); } void writeReg(uint8_t addr, uint8_t value) { digitalWrite(ssPin,LOW); SPI.transfer(addr | 0x80); SPI.transfer(value); digitalWrite(ssPin, HIGH); } uint8_t readReg(uint8_t addr) { digitalWrite(ssPin, LOW); SPI.transfer(addr & 0x7F); uint8_t regval = SPI.transfer(0); digitalWrite(ssPin, HIGH); return regval; } void setupSPI() { SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); } void setFrequency(uint32_t freqHz){ // Setup the frequency freqHz /= 61; // resolution is 61 Hz so divide it it down and mask it out writeReg(0x07, freqHz >> 16); // Frequency MSB writeReg(0x08, freqHz >> 8); // Frequency Middle Byte writeReg(0x09, freqHz); // Frequency LSB } // Tim's code here ///////////////////////////////////////////// void transmitData(){ for (index = 0; index < myStringLen; index++) { check_current_state(myString[index]) ; compare_state(); send_shift_sig(); lookup_send(myString, index); } } void check_current_state(char val) { if (isalpha(val)) current_state = 0; // is a letter else current_state = 1; // is a number } void compare_state() { //compares states and sends letter shifts if (current_state == previous_state) { send_shift = 0; } else { send_shift = 1; previous_state = current_state; } } void send_shift_sig() { // shifts between letter and number ????? if (send_shift == 1) { if (current_state == 0) { letter_shift(); } else { figure_shift(); } // what is a figure ????? } if (current_state == 1) { // My addition figure_shift(); // my addition } } void lookup_send(String checkletter, int indexofstring) { if (checkletter[indexofstring] == 'A' || checkletter[indexofstring] == '-'){//11000 start_bit(); markF(); markF(); spaceF(); spaceF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'B' || checkletter[indexofstring] == '?') { //10011 start_bit(); markF(); spaceF(); spaceF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'C' || checkletter[indexofstring] == ':') { //01110 start_bit(); spaceF(); markF(); markF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'D') { //10010 WRU? will program later start_bit(); markF(); spaceF(); spaceF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'E' || checkletter[indexofstring] == '3') { //10000 start_bit(); markF(); spaceF(); spaceF(); spaceF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'F' || checkletter[indexofstring] == '!') { //10110 start_bit(); markF(); spaceF(); markF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'G' || checkletter[indexofstring] == '&') { //01011 start_bit(); spaceF(); markF(); spaceF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'H' || checkletter[indexofstring] == '#') { //00101 start_bit(); spaceF(); spaceF(); markF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'I' || checkletter[indexofstring] == '8') { //01100 start_bit(); spaceF(); markF(); markF(); spaceF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'J') { //11010 should send a ' as well, but errors start_bit(); markF(); markF(); spaceF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'K' || checkletter[indexofstring] == '(') { //11110 start_bit(); markF(); markF(); markF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'L' || checkletter[indexofstring] == ')') { //01001 start_bit(); spaceF(); markF(); spaceF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'M' || checkletter[indexofstring] == '.') { //00111 start_bit(); spaceF(); spaceF(); markF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'N' || checkletter[indexofstring] == ',') { //00110 start_bit(); spaceF(); spaceF(); markF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'O' || checkletter[indexofstring] == '9') { //00011 start_bit(); spaceF(); spaceF(); spaceF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'P' || checkletter[indexofstring] == '0') { //01101 start_bit(); spaceF(); markF(); markF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'Q' || checkletter[indexofstring] == '1') { //11101 start_bit(); markF(); markF(); markF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'R' || checkletter[indexofstring] == '4') { //01010 start_bit(); spaceF(); markF(); spaceF(); markF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'S') { //10100 should do Bell? start_bit(); markF(); spaceF(); markF(); spaceF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'T' || checkletter[indexofstring] == '5') { //00001 start_bit(); spaceF(); spaceF(); spaceF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'U' || checkletter[indexofstring] == '7') { //11100 start_bit(); markF(); markF(); markF(); spaceF(); spaceF(); stop_bit(); } else if (checkletter[indexofstring] == 'V' || checkletter[indexofstring] == ';') { //01111 start_bit(); spaceF(); markF(); markF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'W' || checkletter[indexofstring] == '2') { //11001 start_bit(); markF(); markF(); spaceF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'X' || checkletter[indexofstring] == '/') { //10111 start_bit(); markF(); spaceF(); markF(); markF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'Y' || checkletter[indexofstring] == '6') { //10101 start_bit(); markF(); spaceF(); markF(); spaceF(); markF(); stop_bit(); } else if (checkletter[indexofstring] == 'Z' || checkletter[indexofstring] == '"') { //10001 start_bit(); markF(); spaceF(); spaceF(); spaceF(); markF(); stop_bit(); } else if ( (checkletter[indexofstring] == ' ')) {//this seems to properly send a space 00100. for a new line i think i need 01000 start_bit(); spaceF(); spaceF(); markF(); spaceF(); spaceF(); stop_bit(); } else { //if no valid characters are provided a ? is returned for that character figure_shift(); start_bit(); markF(); spaceF(); spaceF(); markF(); markF(); stop_bit(); } } void start_bit() { writeReg(0x09,mySpace); // my addition delay(bit_time); } void markF() { writeReg(0x09,myMark); // my addition delay(bit_time); } void spaceF() { writeReg(0x09,mySpace); // my addition delay(bit_time); } void stop_bit() { writeReg(0x09,myMark); // my addition delay(stop_bit_time); } void figure_shift() { // switch to figures ???? Numbers ????? //switch to figures start_bit(); //11011 markF(); markF(); spaceF(); markF(); markF(); //stop bit stop_bit(); } void letter_shift() { //switch to letters start_bit(); //11011 markF(); markF(); markF(); markF(); markF(); //stop bit stop_bit(); } // This custom version of delay() ensures that the gps object is being "fed". static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (ss.available()) gps.encode(ss.read()); } while (millis() - start < ms); } // //Written by Ted Van Slyck www.openrcdesign.com //Feel free to use for personal non commercial use //use at your own risk, no warranties. It probably has errors of some kind. //this program has an issue with finishing a string on a non space. perhaps i should program it to send a new line or a space at the end of all strings regardless? this MIGHT be an issue with how droidRTTY interperets too... //Also, i think i should make it send a letter or a figure shift each time it commences a string.