/*
 * dxlAPRS toolchain
 *
 * Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */


#define X2C_int32
#define X2C_index32
#ifndef aprspos_H_
#include "aprspos.h"
#endif
#define aprspos_C_
#ifndef osi_H_
#include "osi.h"
#endif
#include <osic.h>



/* get aprs position by OE5DXL */
/*CONST arccos=acos; */
/*      arctan=atan; */
/*      power=pow; */

extern float aprspos_rad0(float w)
{
   return w*1.7453292519444E-2f;
} /* end rad() */


extern char aprspos_posvalid(struct aprspos_POSITION pos)
{
   return pos.lat!=0.0f || pos.long0!=0.0f;
} /* end posvalid() */


extern float aprspos_distance(struct aprspos_POSITION home,
                struct aprspos_POSITION dist)
{
   float y;
   float x;
   x = (float)fabs(dist.long0-home.long0);
   y = (float)fabs(dist.lat-home.lat);
   if (x==0.0f && y==0.0f) return 0.0f;
   else if (x+y<0.04f) {
      /* near */
      x = x*osic_cos((home.lat+dist.lat)*0.5f);
      return 6370.0f*osic_sqrt(x*x+y*y);
   }
   else {
      /* far */
      if (x>6.283185307f) x = 6.283185307f-x;
      x = osic_sin(dist.lat)*osic_sin(home.lat)+osic_cos(dist.lat)
                *osic_cos(home.lat)*osic_cos(x);
      if ((float)fabs(x)>=1.0f) return 0.0f;
      return 6370.0f*osic_arccos(x);
   }
   return 0;
} /* end distance() */


extern float aprspos_azimuth(struct aprspos_POSITION home,
                struct aprspos_POSITION dist)
{
   float ldiff;
   float h;
   ldiff = dist.long0-home.long0;
   if ((ldiff==0.0f || osic_cos(home.lat)==0.0f) || osic_cos(dist.lat)==0.0f)
                 {
      if (home.lat<=dist.lat) return 0.0f;
      else return 180.0f;
   }
   else {
      h = 5.729577951472E+1f*osic_arctan(osic_cos(home.lat)
                *(X2C_DIVR(osic_tan(home.lat)*osic_cos(ldiff)
                -osic_tan(dist.lat),osic_sin(ldiff))));
      if (ldiff<0.0f) return h+270.0f;
      else return h+90.0f;
   }
   return 0;
} /* end azimuth() */


static char dig(float * s, char c, float mul)
{
   if (c==' ') return 1;
   /* ambiguity */
   if ((uint8_t)c<'0' || (uint8_t)c>'9') return 0;
   *s = *s+(float)((uint32_t)(uint8_t)c-48UL)*mul;
   return 1;
} /* end dig() */


static char r91(float * s, char c, float mul)
{
   if ((uint8_t)c<'!' || (uint8_t)c>'|') return 0;
   *s = *s+(float)((uint32_t)(uint8_t)c-33UL)*mul;
   return 1;
} /* end r91() */


static char mic(float * s, char c, float mul)
{
   uint32_t n;
   if ((uint8_t)c>='0' && (uint8_t)c<='9') {
      n = (uint32_t)(uint8_t)c-48UL;
   }
   else if ((uint8_t)c>='A' && (uint8_t)c<='J') {
      n = (uint32_t)(uint8_t)c-65UL;
   }
   else if ((c=='K' || c=='L') || c=='Z') n = 0UL;
   else if ((uint8_t)c>='P' && (uint8_t)c<='Y') {
      n = (uint32_t)(uint8_t)c-80UL;
   }
   else return 0;
   *s = *s+(float)n*mul;
   return 1;
} /* end mic() */


static char bit5(char c)
{
   return ((uint32_t)(uint8_t)c/32UL&1) || c=='L';
} /* end bit5() */
/* L is wildcard */


static void komma(char buf[], uint32_t buf_len, uint32_t * p)
{
   for (;;) {
      if (*p+20UL>=buf_len-1 || (uint8_t)buf[*p]<' ') return;
      if (buf[*p]==',') break;
      ++*p;
   }
   ++*p;
} /* end komma() */


static char ns(char c)
{
   c = X2C_CAP(c);
   return c=='N' || c=='S';
} /* end ns() */


static char ew(char c)
{
   c = X2C_CAP(c);
   return c=='E' || c=='W';
} /* end ew() */


static char dig3(char buf[], uint32_t buf_len, uint32_t * s,
                uint32_t * p)
{
   uint32_t i;
   char c;
   *s = 0UL;
   if ((buf[*p]==' ' && buf[*p+1UL]==' ')
                && buf[*p+2UL]==' ' || (buf[*p]=='.' && buf[*p+1UL]=='.')
                && buf[*p+2UL]=='.') {
      *p += 3UL;
      return 1;
   }
   for (i = 0UL; i<=2UL; i++) {
      c = buf[*p];
      ++*p;
      if ((uint8_t)c<'0' || (uint8_t)c>'9') return 0;
      *s = ( *s*10UL+(uint32_t)(uint8_t)c)-48UL;
   } /* end for */
   return 1;
} /* end dig3() */


static char dig6(const char b[], uint32_t b_len, float * s,
                uint32_t p)
{
   uint32_t i;
   char c;
   char sig;
   *s = 0.0f;
   if (b[p]=='-') {
      sig = 1;
      i = 1UL;
   }
   else {
      sig = 0;
      i = 0UL;
   }
   do {
      c = b[p+i];
      if ((uint8_t)c<'0' || (uint8_t)c>'9') return 0;
      *s =  *s*10.0f+(float)((uint32_t)(uint8_t)c-48UL);
      ++i;
   } while (i<6UL);
   if (sig) *s = -*s;
   return 1;
} /* end dig6() */


static char Mapsym(char c)
{
   if ((uint8_t)c>='a' && (uint8_t)c<='j') {
      c = (char)((uint32_t)(uint8_t)c-49UL);
   }
   return c;
} /* end Mapsym() */

typedef uint32_t CHSET[4];

#define aprspos_DAO10 2.9088820865741E-7
/* additional digit in lat/log */

#define aprspos_DAO91 3.1997702952315E-8
/* additional 0..90 * 1.1 digits */

#define aprspos_RND 1.454441043287E-6

static CHSET _cnst1 = {0x00000000UL,0x00000080UL,0x00000000UL,0x00000001UL};
static CHSET _cnst0 = {0x00000000UL,0x40000000UL,0x20000000UL,0x00000000UL};
static CHSET _cnst = {0x20000000UL,0x40000080UL,0x20100000UL,0x00000001UL};

extern void aprspos_GetPos(struct aprspos_POSITION * pos, uint32_t * speed,
                 uint32_t * course, int32_t * altitude, char * symb,
                char * symbt, char buf[], uint32_t buf_len,
                uint32_t micedest, uint32_t payload, char coment[],
                uint32_t coment_len, char * postyp)
{
   uint32_t compos;
   uint32_t clen;
   uint32_t na;
   uint32_t nc;
   uint32_t n;
   uint32_t len;
   uint32_t i;
   char manucode;
   char gpst;
   char c;
   char nornd;
   char ok0;
   float scl;
   float sc;
   len = payload;
   nornd = 0;
   while (len<buf_len-1 && (uint8_t)buf[len]>'\015') ++len;
   coment[0UL] = 0;
   manucode = 0;
   compos = payload;
   c = buf[payload];
   if ((payload+8UL<len && micedest>0UL) && (((c=='\034' || c=='\035')
                || c=='\'') || c=='`')) {
      /* mic-e */
      pos->lat = 0.0f;
      i = micedest;
      ok0 = 1;
      if (!mic(&pos->lat, buf[i], 1.7453292519444E-1f)) ok0 = 0;
      ++i;
      if (!mic(&pos->lat, buf[i], 1.7453292519444E-2f)) ok0 = 0;
      ++i;
      if (!mic(&pos->lat, buf[i], 2.9088820865741E-3f)) ok0 = 0;
      ++i;
      if (!mic(&pos->lat, buf[i], 2.9088820865741E-4f)) ok0 = 0;
      ++i;
      if (!mic(&pos->lat, buf[i], 2.9088820865741E-5f)) ok0 = 0;
      ++i;
      if (!mic(&pos->lat, buf[i], 2.9088820865741E-6f)) ok0 = 0;
      /*    IF ok & (pos.lat<>0.0) THEN pos.lat:=pos.lat+0.005/60.0*RAD END;
                   (* rounding *)  */
      if (bit5(buf[micedest+3UL])) pos->lat = -pos->lat;
      n = (uint32_t)(uint8_t)buf[payload+1UL]; /* long degrees */
      if (n>=28UL && n<=127UL) {
         n -= 28UL;
         if (!bit5(buf[micedest+4UL])) n += 100UL;
         if (n>=180UL && n<=189UL) n -= 80UL;
         else if (n>=190UL && n<=199UL) n -= 190UL;
      }
      else ok0 = 0;
      pos->long0 = (float)n*1.7453292519444E-2f;
      n = (uint32_t)(uint8_t)buf[payload+2UL]; /* long min */
      if (n>=28UL && n<=127UL) {
         n -= 28UL;
         if (n>=60UL) n -= 60UL;
      }
      else ok0 = 0;
      pos->long0 = pos->long0+(float)n*2.9088820865741E-4f;
      n = (uint32_t)(uint8_t)buf[payload+3UL]; /* long min/100 */
      if (n>=28UL && n<=127UL) {
         pos->long0 = pos->long0+(float)(n-28UL)*2.9088820865741E-6f;
      }
      else ok0 = 0;
      /*    IF ok & (pos.long<>0.0)
                THEN pos.long:=pos.long+0.005/60.0*RAD END;
                (* rounding *) */
      if (!bit5(buf[micedest+5UL])) pos->long0 = -pos->long0;
      *speed = 0UL;
      *course = 0UL;
      if (ok0) {
         n = (uint32_t)(uint8_t)buf[payload+4UL];
         if (n>=28UL && n<=127UL) *speed = (n-28UL)*10UL;
         else ok0 = 0;
         n = (uint32_t)(uint8_t)buf[payload+5UL];
         if (n>=28UL && n<=127UL) {
            n -= 28UL;
            *speed += n/10UL;
            *course = (n%10UL)*100UL;
         }
         else ok0 = 0;
         n = (uint32_t)(uint8_t)buf[payload+6UL];
         if (n>=28UL && n<=127UL) {
            n -= 28UL;
            *course += n;
            if (*speed>=800UL) *speed -= 800UL;
            if (*course>=400UL) *course -= 400UL;
            if (*course>=360UL) ok0 = 0;
         }
         else {
            /*        INC(course);
                  (* compatible to 1..360 system *) */
            ok0 = 0;
         }
         *symb = buf[payload+7UL];
         *symbt = buf[payload+8UL];
      }
      compos = payload+9UL;
      i = payload+9UL;
      manucode = buf[i];
      if (!X2C_INL((int32_t)(uint8_t)manucode,128,_cnst)) {
         manucode = 0; /* no manufacturer code */
      }
      if (buf[i+3UL]=='}' || manucode && buf[i+4UL]=='}') {
         /* altitude in meters +10000 */
         if (buf[i+3UL]!='}' && manucode) ++i;
         sc = 0.0f;
         if ((r91(&sc, buf[i], 8281.0f) && r91(&sc, buf[i+1UL],
                91.0f)) && r91(&sc, buf[i+2UL], 1.0f)) {
            *altitude = (int32_t)(uint32_t)X2C_TRUNCC(sc,0UL,
                X2C_max_longcard)-10000L;
            compos = i+4UL;
         }
         else ok0 = 0;
      }
      *postyp = 'm';
   }
   else if (c=='$' && payload+30UL<buf_len-1) {
      /* gps 4806.9409,N,01134.6219,E */
      ok0 = 0;
      if (buf[payload+1UL]=='G' && buf[payload+2UL]=='P') {
         i = payload+7UL;
         gpst = buf[payload+5UL];
         if ((buf[payload+3UL]=='G' && buf[payload+4UL]=='G') && gpst=='A') {
            komma(buf, buf_len, &i);
            ok0 = 1;
         }
         else if ((buf[payload+3UL]=='R' && buf[payload+4UL]=='M')
                && gpst=='C') {
            komma(buf, buf_len, &i);
            komma(buf, buf_len, &i);
            ok0 = 1;
         }
         else if ((buf[payload+3UL]=='G' && buf[payload+4UL]=='L')
                && gpst=='L') ok0 = 1;
         pos->lat = 0.0f;
         if (!dig(&pos->lat, buf[i], 1.7453292519444E-1f)) ok0 = 0;
         ++i;
         if (!dig(&pos->lat, buf[i], 1.7453292519444E-2f)) ok0 = 0;
         ++i;
         if (!dig(&pos->lat, buf[i], 2.9088820865741E-3f)) ok0 = 0;
         ++i;
         if (!dig(&pos->lat, buf[i], 2.9088820865741E-4f)) ok0 = 0;
         i += 2UL;
         if (!dig(&pos->lat, buf[i], 2.9088820865741E-5f)) ok0 = 0;
         ++i;
         if (!dig(&pos->lat, buf[i], 2.9088820865741E-6f)) ok0 = 0;
         sc = 2.9088820865741E-7f;
         while (i<len && dig(&pos->lat, buf[i+1UL], sc)) {
            sc = sc*0.1f;
            ++i;
            nornd = 1;
         }
         komma(buf, buf_len, &i);
         if (buf[i]=='S') pos->lat = -pos->lat;
         komma(buf, buf_len, &i);
         pos->long0 = 0.0f;
         if (!dig(&pos->long0, buf[i], 1.7453292519444f)) ok0 = 0;
         ++i;
         if (!dig(&pos->long0, buf[i], 1.7453292519444E-1f)) ok0 = 0;
         ++i;
         if (!dig(&pos->long0, buf[i], 1.7453292519444E-2f)) ok0 = 0;
         ++i;
         if (!dig(&pos->long0, buf[i], 2.9088820865741E-3f)) ok0 = 0;
         ++i;
         if (!dig(&pos->long0, buf[i], 2.9088820865741E-4f)) ok0 = 0;
         i += 2UL;
         if (!dig(&pos->long0, buf[i], 2.9088820865741E-5f)) ok0 = 0;
         ++i;
         if (!dig(&pos->long0, buf[i], 2.9088820865741E-6f)) ok0 = 0;
         sc = 2.9088820865741E-7f;
         while (i<len && dig(&pos->long0, buf[i+1UL], sc)) {
            sc = sc*0.1f;
            ++i;
            nornd = 1;
         }
         komma(buf, buf_len, &i);
         if (buf[i]=='W') pos->long0 = -pos->long0;
         if (gpst=='C') {
            /* speed and course */
            komma(buf, buf_len, &i);
            sc = 0.0f;
            for (;;) {
               sc = sc*10.0f;
               if ((i>=len || sc>1.E+6f) || !dig(&sc, buf[i], 0.1f)) {
                  break;
               }
               ++i;
            }
            *speed = (uint32_t)X2C_TRUNCC(X2C_DIVR(sc,1.852f)+0.5f,0UL,
                X2C_max_longcard);
            komma(buf, buf_len, &i);
            sc = 0.0f;
            for (;;) {
               sc = sc*10.0f;
               if ((i>=len || sc>360.0f) || !dig(&sc, buf[i], 0.1f)) break;
               ++i;
            }
            *course = (uint32_t)X2C_TRUNCC(sc,0UL,X2C_max_longcard);
            if (i>len) ok0 = 0;
         }
         else if (gpst=='A') {
            /* altitude */
            komma(buf, buf_len, &i);
            komma(buf, buf_len, &i);
            komma(buf, buf_len, &i);
            komma(buf, buf_len, &i);
            sc = 0.0f;
            c = buf[i];
            if (c=='-') ++i;
            for (;;) {
               sc = sc*10.0f;
               if ((i>=len || sc>1.E+6f) || !dig(&sc, buf[i], 0.1f)) break;
               ++i;
            }
            komma(buf, buf_len, &i);
            if (c=='-') sc = -sc;
            if (buf[i]=='M') {
               *altitude = (int32_t)X2C_TRUNCI(sc,X2C_min_longint,
                X2C_max_longint);
            }
         }
         while (i<len && buf[i]!='*') ++i;
         if (i+3UL<len) compos = i+3UL;
         else compos = len;
         *postyp = 'g';
      }
   }
   else {
      /* !4915.10N/01402.20E& */
      /* xnnnn.nnNxnnnnn.nnEx */
      ok0 = 0;
      pos->lat = 0.0f;
      pos->long0 = 0.0f;
      i = 0UL;
      if (buf[payload]=='!' || buf[payload]=='=') i = payload+1UL;
      else if ((buf[payload]=='/' || buf[payload]=='@')
                && ((buf[payload+7UL]=='z' || buf[payload+7UL]=='h')
                || buf[payload+7UL]=='/')) i = payload+8UL;
      else if (buf[payload]==';') i = payload+18UL;
      else if (buf[payload]==')') {
         /* skip item */
         i = payload+4UL;
         while ((i<len && buf[i]!='!') && buf[i]!='_') ++i;
         ++i;
      }
      if (i>0UL) {
         if ((uint8_t)buf[i]>='0' && (uint8_t)buf[i]<='9') {
            if ((((i+17UL<=len && buf[i+4UL]=='.') && buf[i+14UL]=='.')
                && ns(buf[i+7UL])) && ew(buf[i+17UL])) {
               /* not compressed */
               ok0 = 1;
               if (!dig(&pos->lat, buf[i], 1.7453292519444E-1f)) ok0 = 0;
               ++i;
               if (!dig(&pos->lat, buf[i], 1.7453292519444E-2f)) ok0 = 0;
               ++i;
               if (!dig(&pos->lat, buf[i], 2.9088820865741E-3f)) ok0 = 0;
               if ((uint8_t)buf[i]>='6') ok0 = 0;
               ++i;
               if (!dig(&pos->lat, buf[i], 2.9088820865741E-4f)) ok0 = 0;
               i += 2UL;
               if (!dig(&pos->lat, buf[i], 2.9088820865741E-5f)) ok0 = 0;
               ++i;
               if (!dig(&pos->lat, buf[i], 2.9088820865741E-6f)) ok0 = 0;
               ++i;
               if (X2C_CAP(buf[i])=='S') pos->lat = -pos->lat;
               else if (X2C_CAP(buf[i])!='N') ok0 = 0;
               ++i;
               *symbt = buf[i];
               ++i;
               if (!dig(&pos->long0, buf[i], 1.7453292519444f)) {
                  ok0 = 0;
               }
               ++i;
               if (!dig(&pos->long0, buf[i], 1.7453292519444E-1f)) ok0 = 0;
               ++i;
               if (!dig(&pos->long0, buf[i], 1.7453292519444E-2f)) ok0 = 0;
               ++i;
               if (!dig(&pos->long0, buf[i], 2.9088820865741E-3f)) ok0 = 0;
               if ((uint8_t)buf[i]>='6') ok0 = 0;
               ++i;
               if (!dig(&pos->long0, buf[i], 2.9088820865741E-4f)) ok0 = 0;
               i += 2UL;
               if (!dig(&pos->long0, buf[i], 2.9088820865741E-5f)) ok0 = 0;
               ++i;
               if (!dig(&pos->long0, buf[i], 2.9088820865741E-6f)) ok0 = 0;
               ++i;
               if (X2C_CAP(buf[i])=='W') pos->long0 = -pos->long0;
               else if (X2C_CAP(buf[i])!='E') ok0 = 0;
               ++i;
               *symb = buf[i];
               ++i;
               compos = i;
               *postyp = 'g';
               if (i+7UL<=len) {
                  if (dig3(buf, buf_len, &nc, &i)) *course = nc;
                  else *course = 0UL;
                  /* area obj */
                  if (*symbt=='\\' && *symb=='l') {
                     /* area symbol */
                     c = buf[i];
                     if (c=='/' || c=='1') {
                        ++i;
                        if (dig3(buf, buf_len, &n, &i)) {
                           if (c=='1') {
                              n += 1000UL; /* Tyy/Cxx or Tyy1Cxx */
                           }
                           if (n<=1599UL) {
                              /* Tyy15xx max 5 */
                              *speed = n;
                              compos = i;
                              *postyp = 'A';
                           }
                        }
                     }
                  }
                  else if (buf[i]=='/') {
                     /* area obj */
                     /* ccc/sss */
                     ++i;
                     if (dig3(buf, buf_len, &n, &i)) {
                        *speed = n;
                        compos = i;
                     }
                  }
               }
            }
         }
         else if (i+11UL+2UL*(uint32_t)(buf[i+10UL]!=' ')<=len) {
            /* compressed pos*/
            ok0 = 1;
            *symbt = Mapsym(buf[i]);
            ++i;
            if (!r91(&pos->lat, buf[i], 7.53571E+5f)) ok0 = 0;
            ++i;
            if (!r91(&pos->lat, buf[i], 8281.0f)) ok0 = 0;
            ++i;
            if (!r91(&pos->lat, buf[i], 91.0f)) ok0 = 0;
            ++i;
            if (!r91(&pos->lat, buf[i], 1.0f)) ok0 = 0;
            pos->lat = 1.57079632675f-pos->lat*4.5818065764596E-8f;
            ++i;
            if (!r91(&pos->long0, buf[i], 7.53571E+5f)) ok0 = 0;
            ++i;
            if (!r91(&pos->long0, buf[i], 8281.0f)) ok0 = 0;
            ++i;
            if (!r91(&pos->long0, buf[i], 91.0f)) ok0 = 0;
            ++i;
            if (!r91(&pos->long0, buf[i], 1.0f)) ok0 = 0;
            pos->long0 = pos->long0*9.1636131529192E-8f-3.1415926535f;
            *symb = buf[i+1UL];
            if (ok0) {
               if (buf[i+2UL]=='}') {
               }
               else if (((uint32_t)(uint8_t)buf[i+4UL]/8UL&3UL)==2UL) {
                  /* radio range */
                  /* T byte says GGA so we have altitude */
                  na = (uint32_t)(uint8_t)buf[i+2UL];
                /* sc is altitude */
                  n = (uint32_t)(uint8_t)buf[i+3UL];
                  if (((na>=33UL && na<=127UL) && n>=33UL) && n<=127UL) {
                     *altitude = (int32_t)(uint32_t)
                X2C_TRUNCC(0.3048f*osic_power(1.002f,
                (float)(((na-33UL)*91UL+n)-33UL)),0UL,X2C_max_longcard);
                /* in feet */
                  }
               }
               else {
                  n = (uint32_t)(uint8_t)buf[i+2UL]; /* speed course */
                  if (n>=33UL && n<=127UL) {
                     n -= 33UL;
                     if (n<=89UL) {
                        *course = n*4UL;
                        n = (uint32_t)(uint8_t)buf[i+3UL];
                        if (n>=33UL && n<=127UL) {
                           *speed = (uint32_t)X2C_TRUNCC(osic_power(1.08f,
                (float)(n-33UL)),0UL,X2C_max_longcard);
                        }
                     }
                  }
               }
               compos = i+5UL;
               nornd = 1;
            }
            *postyp = 'c';
         }
      }
   }
   i = compos;
   clen = 0UL;
   while (clen<coment_len-1 && i<len) {
      coment[clen] = buf[i];
      ++i;
      ++clen;
   }
   if ((clen>0UL && X2C_INL((int32_t)(uint8_t)manucode,128,
                _cnst0)) && coment[clen-1UL]=='=') --clen;
   else if (clen>1UL && X2C_INL((int32_t)(uint8_t)manucode,128,_cnst1)) {
      clen -= 2UL; /* remove maufacturer code */
   }
   coment[clen] = 0;
   if (clen>0UL) {
      i = 0UL; /* look for altitude in comment /A= */
      for (;;) {
         if (i+9UL>clen) break;
         if (((coment[i]=='/' && coment[i+1UL]=='A') && coment[i+2UL]=='=')
                && dig6(coment, coment_len, &sc, i+3UL)) {
            *altitude = (int32_t)X2C_TRUNCI(sc*0.3048f,X2C_min_longint,
                X2C_max_longint);
            while (i+9UL<=clen) {
               coment[i] = coment[i+9UL]; /* delete altitude */
               ++i;
            }
            clen -= 9UL;
            break;
         }
         ++i;
      }
      if (clen>=5UL && (pos->long0!=0.0f || pos->lat!=0.0f)) {
         i = clen-5UL; /* look for !DAO! precision extension backward */
         n = 0UL; /* count "|" to know if inside mice-telemetry */
         for (;;) {
            if (coment[i]=='!' && coment[i+4UL]=='!') {
               c = coment[i+1UL];
               sc = 0.0f;
               scl = 0.0f;
               if ((((uint8_t)c>='A' && (uint8_t)c<='Z') && dig(&sc,
                coment[i+2UL], 2.9088820865741E-7f)) && dig(&scl,
                coment[i+3UL], 2.9088820865741E-7f) || (((uint8_t)c>='a' && (uint8_t)c<='z') && r91(&sc,
                 coment[i+2UL], 3.1997702952315E-8f)) && r91(&scl,
                coment[i+3UL], 3.1997702952315E-8f)) {
                  if (pos->lat<0.0f) pos->lat = pos->lat-sc;
                  else pos->lat = pos->lat+sc;
                  if (pos->long0<0.0f) pos->long0 = pos->long0-scl;
                  else pos->long0 = pos->long0+scl;
                  nornd = 1;
                  if (!(n&1)) {
                     /* if not possibly inside mice-telemetrty del DAO */
                     while (i+5UL<=clen) {
                        coment[i] = coment[i+5UL]; /* delete DAO */
                        ++i;
                     }
                     clen -= 5UL;
                  }
               }
               if ((uint8_t)*postyp>0) *postyp = X2C_CAP(*postyp);
               break;
            }
            if (coment[i+4UL]=='|') ++n;
            if (i==0UL) break;
            --i;
         }
      }
   }
   if (ok0 && !nornd) {
      /* rounding */
      if (pos->lat<0.0f) pos->lat = pos->lat-1.454441043287E-6f;
      else if (pos->lat>0.0f) pos->lat = pos->lat+1.454441043287E-6f;
      if (pos->long0<0.0f) pos->long0 = pos->long0-1.454441043287E-6f;
      else if (pos->long0>0.0f) pos->long0 = pos->long0+1.454441043287E-6f;
   }
   ok0 = ((ok0 && (pos->long0!=0.0f || pos->lat!=0.0f)) && (float)
                fabs(pos->long0)<3.1415926535f) && (float)fabs(pos->lat)
                <1.57079632675f;
   if (!ok0) {
      pos->long0 = 0.0f;
      pos->lat = 0.0f;
   }
} /* end GetPos() */

#define aprspos_SYMT1 "BBBCBDBEBFBGBHBIBJBKBLBMBNBOBPP0P1P2P3P4P5P6P7P8P9MRMS\
MTMUMVMWMXPAPBPCPDPEPFPGPHPIPJPKPLPMPNPOPPPQPRPSPTPUPVPWPXPYPZHSHTHUHVHWHXLAL\
BLCLDLELFLGLHLILJLKLLLMLNLOLPLQLRLSLTLULVLWLXLYLZJ1J2J3J4"

#define aprspos_SYMT2 "OBOCODOEOFOGOHOIOJOKOLOMONOOOPA0A1A2A3A4A5A6A7A8A9NRNS\
NTNUNVNWNXAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARASATAUAVAWAXAYAZDSDTDUDVDWDXSAS\
BSCSDSESFSGSHSISJSKSLSMSNSOSPSQSRSSSTSUSVSWSXSYSZQ1Q2Q3Q4"

#define aprspos_LEN 94


extern void aprspos_GetSym(char d[], uint32_t d_len, char * symb,
                char * symt)
/* symbol out of destination call */
{
   uint32_t n;
   if (((d[0UL]=='G' && d[1UL]=='P') && d[2UL]=='S')
                && (d[3UL]=='C' || d[3UL]=='E')) {
      if ((((uint8_t)d[4UL]>='0' && (uint8_t)d[4UL]<='9') && (uint8_t)
                d[5UL]>='0') && (uint8_t)d[5UL]<='9') {
         n = (((uint32_t)(uint8_t)d[4UL]-48UL)*10UL+(uint32_t)
                (uint8_t)d[5UL])-48UL;
         if (n>=1UL && n<=94UL) {
            *symb = (char)(32UL+n);
            if (d[3UL]=='C') *symt = '/';
            else *symt = '\\';
         }
      }
   }
   else if (((d[0UL]=='G' && d[1UL]=='P')
                && d[2UL]=='S' || (d[0UL]=='S' && d[1UL]=='P')
                && d[2UL]=='C') || (d[0UL]=='S' && d[1UL]=='Y')
                && d[2UL]=='M') {
      if (d[3UL]==0) {
         *symb = '/';
         *symt = '/';
      }
      else {
         n = 0UL;
         for (;;) {
            if (n>=94UL) break;
            if (d[3UL]=="BBBCBDBEBFBGBHBIBJBKBLBMBNBOBPP0P1P2P3P4P5P6P7P8P9MR\
MSMTMUMVMWMXPAPBPCPDPEPFPGPHPIPJPKPLPMPNPOPPPQPRPSPTPUPVPWPXPYPZHSHTHUHVHWHXL\
ALBLCLDLELFLGLHLILJLKLLLMLNLOLPLQLRLSLTLULVLWLXLYLZJ1J2J3J4"[n*2UL] && d[4UL]
                =="BBBCBDBEBFBGBHBIBJBKBLBMBNBOBPP0P1P2P3P4P5P6P7P8P9MRMSMTMU\
MVMWMXPAPBPCPDPEPFPGPHPIPJPKPLPMPNPOPPPQPRPSPTPUPVPWPXPYPZHSHTHUHVHWHXLALBLCL\
DLELFLGLHLILJLKLLLMLNLOLPLQLRLSLTLULVLWLXLYLZJ1J2J3J4"[n*2UL+1UL]) {
               *symb = (char)(33UL+n);
               *symt = '/';
               break;
            }
            if (d[3UL]=="OBOCODOEOFOGOHOIOJOKOLOMONOOOPA0A1A2A3A4A5A6A7A8A9NR\
NSNTNUNVNWNXAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARASATAUAVAWAXAYAZDSDTDUDVDWDXS\
ASBSCSDSESFSGSHSISJSKSLSMSNSOSPSQSRSSSTSUSVSWSXSYSZQ1Q2Q3Q4"[n*2UL] && d[4UL]
                =="OBOCODOEOFOGOHOIOJOKOLOMONOOOPA0A1A2A3A4A5A6A7A8A9NRNSNTNU\
NVNWNXAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARASATAUAVAWAXAYAZDSDTDUDVDWDXSASBSCS\
DSESFSGSHSISJSKSLSMSNSOSPSQSRSSSTSUSVSWSXSYSZQ1Q2Q3Q4"[n*2UL+1UL]) {
               *symb = (char)(33UL+n);
               *symt = '\\';
               if ((uint8_t)d[5UL]>='0' && (uint8_t)
                d[5UL]<='9' || (uint8_t)d[5UL]>='A' && (uint8_t)
                d[5UL]<='Z') *symt = d[5UL];
               break;
            }
            ++n;
         }
      }
   }
} /* end GetSym() */


extern void aprspos_BEGIN(void)
{
   static int aprspos_init = 0;
   if (aprspos_init) return;
   aprspos_init = 1;
   osi_BEGIN();
}

