Advertisement
stanleyseow

MicroAPRS.cpp

Dec 9th, 2014
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.71 KB | None | 0 0
  1. /**
  2.  * MicroAPRS Library, Modified by DB1NTO
  3.  * Source: ArgentRadioShield Library
  4.  * Copyright 2012 Leigh L. Klotz, Jr. WA5ZNU
  5.  * Released under dual license:
  6.  * MIT License http://www.opensource.org/licenses/mit-license
  7.  * LGPL 3.0: http://www.gnu.org/licenses/lgpl-3.0.txt
  8.  */
  9.  
  10. #include "Arduino.h"
  11. #include "Stream.h"
  12. #include <MicroAPRS.h>
  13.  
  14. MicroAPRS::MicroAPRS(Stream *s) {
  15.   stream = s;
  16.   defaultDestination="APOTW1";
  17. }
  18.  
  19. void MicroAPRS::setCall(char *call) {
  20.   stream->print("c");
  21.   stream->print(call);
  22.   stream->print("\r\n");
  23.   awaitResponse("1");
  24. }
  25.  
  26.  
  27.  
  28. void MicroAPRS::sendPacket(char *message) {
  29.   sendPacket(defaultDestination, message);
  30.   stream->print("!");
  31.   stream->print(message);
  32.   stream->print("\r\n");
  33.   delay(50 * strlen(message));
  34. }
  35.  
  36. void MicroAPRS::sendPacket(char *destination, char *message) {
  37.   stream->print("!");
  38.   stream->print(destination);
  39.   stream->print(":");
  40.   stream->print(message);
  41.   stream->print("\r\n");
  42.   delay(50 * strlen(message));
  43.   delay(50 * strlen(destination));
  44. }
  45.  
  46.  
  47. void MicroAPRS::awaitResponse(char *response) {
  48.   while (available() > 0) {  
  49.     char inbyte = stream->read();
  50.     if (inbyte == response[0]) return;
  51.   }
  52. }
  53.  
  54. int MicroAPRS::read() {
  55.   return stream->read();
  56. }
  57.  
  58. int MicroAPRS::available() {
  59.   return stream->available();
  60. }
  61.  
  62. void MicroAPRS::setDefaultDestination(char *destination) {
  63.   defaultDestination = destination;
  64. }
  65.  
  66.  
  67.  
  68. boolean MicroAPRS::decode_posit(char *packet, char **pcall, char *ptype, char **pposit, long *plon, long *plat, char **pmsgTo, char **pmsg, char *pmsgID) {
  69.   char *callsignBegin = packet+5;
  70.   *callsignBegin++ = 0;
  71.   char *callsignEnd = strchr(callsignBegin, ']');
  72.   if (callsignEnd == NULL || callsignEnd-callsignBegin > 16)
  73.     return false;
  74.   *callsignEnd = 0;
  75.   char *call = callsignBegin;
  76.   char *destination = callsignEnd+8;
  77.   char *payload_begin = strchr(destination, ':')+1;
  78.   if (payload_begin == NULL)
  79.     return false;
  80.   *payload_begin++ = 0;
  81.   // Type is !, =, @, /, ', `.  
  82.   // We only decode positions.
  83.   char type = *payload_begin;
  84.   payload_begin++;
  85.   *pcall = call;
  86.   *ptype = type;
  87.  
  88.   char *posit = payload_begin;
  89.   {
  90.     if (type == '/' || type == '@') {
  91.       // no compression, but starts with time
  92.       // advanced past type and fall through to pretend '/' and '@' are just '!'
  93.       // advance past "195537h" or '052139z'
  94.       posit += 6;
  95.       // call N5CV packet type / 3721.40N/12204.64W
  96.       posit++;
  97.       posit[19] = 0;
  98.       type = '!';
  99.     }
  100.  
  101.     if (type == '`' || type == '\'') {
  102.       // MIC-E compression
  103.       if (! decode_mic_e(destination, posit, plat, plon))
  104.     return false;
  105.     } else if (type == ':') {
  106.         //Message
  107.         char *msgToEnd = strchr(payload_begin, ':');
  108.         *msgToEnd++ = 0;
  109.         char *msgTo = payload_begin;
  110.        
  111.         char *msgEnd = strchr(msgToEnd, '{');
  112.         char *msg = msgToEnd++;
  113.         *msgEnd++ = 0;
  114.        
  115.         char msgID = *msgEnd++;
  116.        
  117.         *pmsgTo = msgTo;
  118.         *pmsg = msg;
  119.         *pmsgID = msgID;
  120.        
  121.        
  122.     } else if (type == '!' || type == '=') {
  123.     // No compression or base91 compression
  124.     // call KC6SSM-5 packet type ! 3754.15NI12216.92W&
  125.     // call N6MON-9 packet type ! 3741.84N/12202.85W
  126.     // call KC6SSM-9 packet type ! 3739.29N/12205.34W>
  127.  
  128.     // either !/ or !\ and 12 more characters
  129.     // or ![0-9] and 17 more characters
  130.     // if there is a space that terminates it
  131.     // otherwise terminate at 18 chars or eol, whichever is first
  132.     // terminated by space or EOL (length "3741.84N/12202.85W")
  133.     char sym1 = *posit;
  134.     char sym2 = ' ';
  135.     if (sym1 == '/' || sym1 == '\\') {
  136.       // Base91 Compressed
  137.       posit[13] = 0;
  138.       decode91(posit, plat, plon, &sym2);
  139.     } else  if (posit[1] >= '0' && posit[1] <= '9') {
  140.       posit[18] = 0;
  141.       decode_latlon(posit, plat, plon, &sym2);
  142.     } else {
  143.       return false;
  144.     }
  145.     } else {
  146.       return false;
  147.     }
  148.   }
  149.   *pposit = posit;
  150.   return true;
  151. }
  152.  
  153.  
  154.  
  155. void MicroAPRS::decode91(char *data, long *plat, long *plon, char *sym2) {
  156.   // *sym1 = data[0];
  157.   long lon = 0;
  158.   long lat = 0;
  159.   {
  160.     for (byte i = 1; i < 5; i++) {
  161.       lat = lat*91 + (data[i]-33);
  162.     }
  163.   }
  164.   {
  165.     for (byte i = 5; i < 9; i++) {
  166.       lon = lon*91 + (data[i]-33);
  167.     }
  168.   }
  169.  
  170.   *plat = 90e6 - ((lat * 1e7) + 5) / 3809260;
  171.   *plon = -180e6 + ((lon * 1e7) + 5) / 1904630;
  172.   *sym2 = data[9];
  173. }
  174.  
  175. #define DIGIT(x) (x-'0')
  176. void MicroAPRS::decode_latlon(char *data, long *plat, long *plon, char *sym2) {
  177.   {
  178.     // 3741.84N/12202.85W
  179.     // 37 41.84N -> 37.69733 -> 3,769,733 ; (+ 3e7 7e6 (/ 4e7 60) (/ 1e6 60) (/ 8e5 60) (/ 4e4 60))
  180.     // 122 02.85W -> -122.04750  -> -12,204,750
  181.     long lat = DIGIT(*data++) * 1e7;
  182.     lat += DIGIT(*data++) * 1e6;
  183.     lat += DIGIT(*data++) * 1e7 / 60;
  184.     lat += DIGIT(*data++) * 1e6 / 60;
  185.     data++;         // '.'
  186.     lat += DIGIT(*data++) * 1e5 / 60;
  187.     lat += DIGIT(*data++) * 1e4 / 60;
  188.     if (*data++=='S') lat = -lat;
  189.     *plat = lat;
  190.   }
  191.   *sym2 = *data++;
  192.   {
  193.     long lon = DIGIT(*data++) * 1e8;
  194.     lon += DIGIT(*data++) * 1e7;
  195.     lon += DIGIT(*data++) * 1e6;
  196.     lon += DIGIT(*data++) * 1e7 / 60;
  197.     lon += DIGIT(*data++) * 1e6 / 60;
  198.     data++;         // '.'
  199.     lon += DIGIT(*data++) * 1e5 / 60;
  200.     lon += DIGIT(*data++) * 1e4 / 60;
  201.     if (*data++=='W') lon = -lon;
  202.     *plon = lon;
  203.   }
  204. }
  205.  
  206. boolean MicroAPRS::decode_mic_e(char *destination, char *posit, long *plat, long *plon) {
  207.   char *lastdash = strchr(destination, '-');
  208.   if (lastdash != NULL) {
  209.     *lastdash = 0;
  210.   }
  211.   if (strlen(destination) != 6) return false;
  212.        
  213.   // latitude
  214.   {
  215.     int d = ((miceChar(destination[0])) * 10) + (miceChar(destination[1]));
  216.     int m = ((miceChar(destination[2])) * 10) + (miceChar(destination[3]));
  217.     int s = ((miceChar(destination[4])) * 10) + (miceChar(destination[5]));
  218.     long lat = (d*1000000) + (m*1000000 / 60) + (s*1000000 / 6000);
  219.  
  220.     if (! (miceFlag(destination[3])))
  221.       lat = -lat;
  222.  
  223.     *plat = lat;
  224.   }
  225.    
  226.   // longitude
  227.   {
  228.     int d = posit[0] - 28;
  229.     int m = posit[1] - 28;
  230.     int s = posit[2] - 28;
  231.  
  232.     if (d < 0 || d > 99 || m < 0 || m > 99 || s < 0 || s > 99) return false;
  233.  
  234.     if (miceFlag(destination[4])) d += 100;
  235.  
  236.     if (d >= 190) d -= 190;
  237.     else if (d >= 180) d -= 80;
  238.     if (m >= 60) m -= 60;
  239.  
  240.     long lon = (d*1000000) + (m*1000000 / 60) + (s*1000000 / 6000);
  241.  
  242.     if (miceFlag(destination[5]))
  243.       lon = - lon;
  244.     *plon = lon;
  245.   }
  246.   return true;
  247. }
  248.  
  249. // From Chris K6DBG
  250. int MicroAPRS::miceChar(char c) {
  251.   c -= 0x30;                   // adjust to be 0 based
  252.   if (c == 0x1c) { c = 0x0a; }      // change 'L' to space
  253.   if (c > 0x10 && c <= 0x1b) { c--; }       // Decrement A-K
  254.   if ((c & 0x0f) == 0x0a) { c &= 0xf0; }    // convert space to 0
  255.   return (c & 0xf);
  256. }
  257.  
  258. boolean MicroAPRS::miceFlag(char c) {
  259.   return (c > 0x50);
  260. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement