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


#define X2C_int32
#define X2C_index32
#ifndef aprstext_H_
#include "aprstext.h"
#endif
#define aprstext_C_
#ifndef aprsdecode_H_
#include "aprsdecode.h"
#endif
#ifndef aprspos_H_
#include "aprspos.h"
#endif
#ifndef aprsstr_H_
#include "aprsstr.h"
#endif
#ifndef osi_H_
#include "osi.h"
#endif
#include <osic.h>
#ifndef maptool_H_
#include "maptool.h"
#endif
#ifndef useri_H_
#include "useri.h"
#endif

/* aprs tracks on osm map by oe5dxl */
/*FROM osi IMPORT WrInt, WrStrLn; */
#define aprstext_PI 3.1415926535898


extern void aprstext_strcp(char from[], uint32_t from_len,
                uint32_t p, uint32_t l, char to[],
                uint32_t to_len)
{
   uint32_t i;
   i = 0UL;
   while (l>0UL && i<=to_len-1) {
      to[i] = from[p];
      ++i;
      ++p;
      --l;
   }
   if (i<=to_len-1) to[i] = 0;
} /* end strcp() */

#define aprstext_DAY 86400


extern void aprstext_DateLocToStr(uint32_t time0, char s[],
                uint32_t s_len)
/* append (+localtime) to time */
{
   uint32_t lo;
   char h[10];
   lo = useri_localtime();
   if (time0+86400UL<aprsdecode_realtime) {
      aprsstr_DateToStr(time0+lo, s, s_len);
   }
   else aprsstr_TimeToStr((time0+lo)%86400UL, s, s_len);
   if (lo) {
      aprsstr_IntToStr((int32_t)lo/3600L, 0UL, h, 10ul);
      aprsstr_Append(s, s_len, "(", 2ul);
      aprsstr_Append(s, s_len, h, 10ul);
      aprsstr_Append(s, s_len, ")", 2ul);
   }
} /* end DateLocToStr() */


static char IsBulletin(const struct aprsdecode_DAT dat)
{
   return ((dat.type==aprsdecode_MSG && dat.msgto[0UL]=='B')
                && dat.msgto[1UL]=='L') && dat.msgto[2UL]=='N';
} /* end IsBulletin() */


extern void aprstext_logfndate(uint32_t time0, char fn[],
                uint32_t fn_len)
/* replace %d by date */
{
   int32_t p;
   char s[16];
   p = aprsstr_InStr(fn, fn_len, "%d", 3ul);
   if (p>=0L && p+2L==(int32_t)aprsstr_Length(fn, fn_len)) {
      aprsstr_DateToStr(time0, s, 16ul);
      fn[p] = s[0U];
      ++p;
      fn[p] = s[1U];
      ++p;
      fn[p] = s[2U];
      ++p;
      fn[p] = s[3U];
      ++p;
      fn[p] = s[5U];
      ++p;
      fn[p] = s[6U];
      ++p;
      fn[p] = s[8U];
      ++p;
      fn[p] = s[9U];
      ++p;
      fn[p] = 0;
   }
} /* end logfndate() */


extern float aprstext_FtoC(float tempf)
{
   return X2C_DIVR(tempf-32.0f,1.8f);
} /* end FtoC() */


extern float aprstext_CtoF(float tempc)
{
   return tempc*1.8f+32.0f;
} /* end CtoF() */


extern char aprstext_isacall(char s[], uint32_t s_len)
{
   uint32_t p;
   uint32_t lit;
   uint32_t num0;
   char c1;
   p = 0UL;
   num0 = 0UL;
   lit = 0UL;
   for (;;) {
      c1 = s[p];
      if ((uint8_t)c1>='0' && (uint8_t)c1<='9') ++num0;
      else if ((uint8_t)c1>='A' && (uint8_t)c1<='Z') ++lit;
      else break;
      ++p;
      if (p>5UL) break;
   }
   if ((lit<2UL || num0==0UL) || num0>2UL) return 0;
   if (s[p]=='-') {
      ++p;
      if (s[p]=='1') {
         ++p;
         if ((uint8_t)s[p]>='0' && (uint8_t)s[p]<='5') ++p;
      }
      else {
         if ((uint8_t)s[p]<'1' || (uint8_t)s[p]>'9') return 0;
         ++p;
      }
   }
   return p>s_len-1 || s[p]==0;
} /* end isacall() */


extern void aprstext_sievert2str(float v, char s[], uint32_t s_len)
{
   if (v<1.E-6f) {
      aprsstr_FixToStr(v*1.E+9f+0.5f, 0UL, s, s_len);
      aprsstr_Append(s, s_len, "n", 2ul);
   }
   else if (v<0.001f) {
      aprsstr_FixToStr(v*1.E+6f+0.005f, 2UL, s, s_len);
      aprsstr_Append(s, s_len, "u", 2ul);
   }
   else {
      aprsstr_FixToStr(v*1000.0f+0.005f, 2UL, s, s_len);
      aprsstr_Append(s, s_len, "m", 2ul);
   }
   aprsstr_Append(s, s_len, "Sv/h", 5ul);
} /* end sievert2str() */


static void Errtxt(char s[], uint32_t s_len, aprsdecode_pFRAMEHIST pf,
                aprsdecode_pFRAMEHIST frame)
{
   char hh[100];
   char h[100];
   uint32_t l;
   uint8_t e;
   if (frame) {
      e = frame->nodraw;
      if ((frame->vardat && frame->vardat->lastref)
                && !aprspos_posvalid(frame->vardat->pos)) e |= 0x40U;
      h[0U] = 0;
      if ((0x1U & e)) aprsstr_Append(h, 100ul, "DIST,", 6ul);
      if ((0x2U & e)) aprsstr_Append(h, 100ul, "SPIKE,", 7ul);
      if ((0x4U & e)) aprsstr_Append(h, 100ul, "SYMBOL,", 8ul);
      if ((0x10U & e)) aprsstr_Append(h, 100ul, "SPEED,", 7ul);
      if ((0x40U & e)) aprsstr_Append(h, 100ul, "NOPOS,", 7ul);
      if ((0x8U & e)) {
         aprsstr_Append(h, 100ul, "DUPE,", 6ul);
         if (pf) {
            aprsstr_IntToStr((int32_t)aprsdecode_finddup(pf, frame), 0UL,
                hh, 100ul);
            aprsstr_Append(h, 100ul, hh, 100ul);
            aprsstr_Append(h, 100ul, "s,", 3ul);
         }
      }
      if ((0x20U & e)) aprsstr_Append(h, 100ul, "SEG,", 5ul);
      l = aprsstr_Length(h, 100ul);
      if (l>0UL) {
         h[l-1UL] = 0;
         aprsstr_Append(h, 100ul, "]\376", 3ul);
         aprsstr_Append(s, s_len, "\370[", 3ul);
         aprsstr_Append(s, s_len, h, 100ul);
      }
   }
} /* end Errtxt() */


static char Hex(uint32_t d)
{
   d = d&15UL;
   if (d>9UL) d += 7UL;
   return (char)(d+48UL);
} /* end Hex() */


extern void aprstext_Apphex(char s[], uint32_t s_len, char h[],
                uint32_t h_len)
{
   uint32_t j;
   uint32_t i;
   i = 0UL;
   j = aprsstr_Length(s, s_len);
   while ((i<=h_len-1 && h[i]) && j+10UL<s_len-1) {
      if (h[i]!='\015') {
         if ((uint8_t)h[i]<' ' || (uint8_t)h[i]>='\177') {
            s[j] = '\371';
            ++j;
            s[j] = '<';
            ++j;
            s[j] = Hex((uint32_t)(uint8_t)h[i]/16UL);
            ++j;
            s[j] = Hex((uint32_t)(uint8_t)h[i]);
            ++j;
            s[j] = '>';
            ++j;
            s[j] = '\376';
         }
         else s[j] = h[i];
         ++j;
      }
      ++i;
   }
   s[j] = 0;
} /* end Apphex() */

#define aprstext_TAB "\012 "


static void rfdist(aprsdecode_pVARDAT v, char h[], uint32_t h_len)
{
   aprsdecode_MONCALL digi;
   aprsdecode_pOPHIST ig;
   char s[32];
   struct aprsdecode_VARDAT * anonym;
   { /* with */
      struct aprsdecode_VARDAT * anonym = v;
      if (anonym->igatelen==0U || !aprspos_posvalid(anonym->pos)) return;
      aprstext_strcp(anonym->raw, 500ul, (uint32_t)anonym->igatepos,
                (uint32_t)anonym->igatelen, digi, 9ul);
      ig = aprsdecode_ophist0;
      while (ig && X2C_STRCMP(ig->call,9u,digi,9u)) ig = ig->next;
      if (ig==0 || !aprspos_posvalid(ig->lastpos)) return;
      aprsstr_Append(h, h_len, " Igate:", 8ul);
      aprsstr_Append(h, h_len, digi, 9ul);
      aprsstr_Append(h, h_len, "(", 2ul);
      aprsstr_FixToStr(aprspos_distance(ig->lastpos, anonym->pos), 4UL, s,
                32ul);
      aprsstr_Append(h, h_len, s, 32ul);
      aprsstr_Append(h, h_len, "km)", 4ul);
   }
} /* end rfdist() */


static void objitem(char s[], uint32_t s_len,
                struct aprsdecode_DAT * dat)
{
   if (dat->type==aprsdecode_OBJ || dat->type==aprsdecode_ITEM) {
      aprsstr_Append(s, s_len, "\012 ", 3ul);
      if (dat->objkill=='1') aprsstr_Append(s, s_len, "Killed ", 8ul);
      if (dat->type==aprsdecode_OBJ && (uint8_t)dat->areasymb.typ>='0') {
         if ((uint8_t)dat->areasymb.typ>='5') {
            aprsstr_Append(s, s_len, "filled ", 8ul);
         }
         switch (((uint32_t)(uint8_t)dat->areasymb.typ-48UL)%5UL) {
         case 0UL:
            aprsstr_Append(s, s_len, "Circle", 7ul);
            break;
         case 1UL:
            aprsstr_Append(s, s_len, "Line", 5ul);
            break;
         case 2UL:
            aprsstr_Append(s, s_len, "Ellipse", 8ul);
            break;
         case 3UL:
            aprsstr_Append(s, s_len, "Triangle", 9ul);
            break;
         case 4UL:
            aprsstr_Append(s, s_len, "Box", 4ul);
            break;
         } /* end switch */
         aprsstr_Append(s, s_len, " Area ", 7ul);
      }
      if (dat->multiline.size>0UL) {
         aprsstr_Append(s, s_len, "Multiline ", 11ul);
      }
      if (dat->type==aprsdecode_OBJ) {
         aprsstr_Append(s, s_len, "Object from:", 13ul);
      }
      else aprsstr_Append(s, s_len, "Item from:", 11ul);
      aprstext_Apphex(s, s_len, dat->objectfrom, 9ul);
   }
} /* end objitem() */


extern void aprstext_decode(char s[], uint32_t s_len,
                aprsdecode_pFRAMEHIST pf0, aprsdecode_pFRAMEHIST pf,
                aprsdecode_pVARDAT oldvar, uint32_t odate,
                char decoded, struct aprsdecode_DAT * dat)
{
   char h[512];
   char colalt;
   char nl;
   int32_t ret;
   int32_t og;
   uint32_t tn;
   float resol;
   char tmp;
   if (pf->time0>0UL) {
      s[0UL] = '\367';
      s[1UL] = 0;
      aprstext_DateLocToStr(pf->time0, h, 512ul);
      aprsstr_Append(s, s_len, h, 512ul);
      aprsstr_Append(s, s_len, ":\376", 3ul);
   }
   else s[0UL] = 0;
   ret = aprsdecode_Decode(pf->vardat->raw, 500ul, dat);
   if (decoded) {
      aprstext_Apphex(s, s_len, dat->symcall, 9ul);
      og = X2C_max_longint;
      if (!aprspos_posvalid(dat->pos)) dat->pos = pf->vardat->pos;
      if (aprspos_posvalid(dat->pos)) {
         aprstext_postostr(dat->pos, '3', h, 512ul);
         aprsstr_Append(s, s_len, " \367", 3ul);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, "\376 (", 4ul);
         maptool_postoloc(h, 512ul, dat->pos);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, ") ", 3ul);
         og = (int32_t)X2C_TRUNCI(maptool_getsrtm(dat->pos, 0UL, &resol),
                X2C_min_longint,X2C_max_longint);
      }
      nl = 1;
      if ((uint8_t)dat->symt>' ' && (uint8_t)dat->sym>' ') {
         aprsstr_Append(s, s_len, "\012 ", 3ul);
         nl = 0;
         aprsstr_Append(s, s_len, "\375", 2ul);
         /*      Append(s, "Sym:"); */
         aprstext_Apphex(s, s_len, (char *) &dat->symt, 1u/1u);
         aprstext_Apphex(s, s_len, (char *) &dat->sym, 1u/1u);
      }
      if (dat->speed<X2C_max_longcard) {
         if (nl) {
            aprsstr_Append(s, s_len, "\012 ", 3ul);
            nl = 0;
         }
         else aprsstr_Append(s, s_len, " \367", 3ul);
         if (dat->sym=='_') {
            aprsstr_FixToStr((float)dat->speed*1.609f, 2UL, h, 512ul);
         }
         else aprsstr_FixToStr((float)dat->speed*1.852f, 0UL, h, 512ul);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, "km/h\376", 6ul);
         if (dat->course>0UL) {
            aprsstr_Append(s, s_len, " dir:", 6ul);
            aprsstr_IntToStr((int32_t)(dat->course%360UL), 1UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "deg", 4ul);
         }
      }
      if (dat->altitude<X2C_max_longint) {
         if (nl) {
            aprsstr_Append(s, s_len, "\012 ", 3ul);
            nl = 0;
         }
         else aprsstr_Append(s, s_len, " ", 2ul);
         colalt = useri_conf2int(useri_fALTMIN, 0UL, -10000L, 100000L,
                -10000L)<=dat->altitude;
         if (colalt) aprsstr_Append(s, s_len, "\367", 2ul);
         aprsstr_Append(s, s_len, "NN:", 4ul);
         aprsstr_IntToStr(dat->altitude, 1UL, h, 512ul);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, "m", 2ul);
         if (colalt) aprsstr_Append(s, s_len, "\376", 2ul);
         if (og<30000L) {
            aprsstr_Append(s, s_len, " OG:", 5ul);
            aprsstr_IntToStr(dat->altitude-og, 1UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "m", 2ul);
         }
      }
      rfdist(pf->vardat, s, s_len);
      if ((oldvar && aprspos_posvalid(oldvar->pos))
                && aprspos_posvalid(dat->pos)) {
         if (nl) {
            aprsstr_Append(s, s_len, "\012 ", 3ul);
            nl = 0;
         }
         else aprsstr_Append(s, s_len, " ", 2ul);
         aprsstr_Append(s, s_len, "moved:", 7ul);
         aprsstr_FixToStr(aprspos_distance(oldvar->pos, dat->pos), 4UL, h,
                512ul);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, "km", 3ul);
      }
      if (odate>0UL && pf->time0>=odate) {
         if (nl) {
            aprsstr_Append(s, s_len, "\012 ", 3ul);
            nl = 0;
         }
         else aprsstr_Append(s, s_len, " ", 2ul);
         aprsstr_Append(s, s_len, "since ", 7ul);
         aprsstr_IntToStr((int32_t)(pf->time0-odate), 1UL, h, 512ul);
         aprsstr_Append(s, s_len, h, 512ul);
         aprsstr_Append(s, s_len, "s", 2ul);
      }
      if (dat->type!=aprsdecode_MSG) Errtxt(s, s_len, pf0, pf);
      nl = 1;
      if (dat->wx.storm==aprsdecode_WXNORMAL) {
         if (dat->type==aprsdecode_OBJ || dat->type==aprsdecode_ITEM) {
            objitem(s, s_len, dat);
         }
         if (dat->wx.gust!=1.E+6f) {
            nl = 0;
            aprsstr_Append(s, s_len, "\012 Gust:", 8ul);
            aprsstr_FixToStr(dat->wx.gust*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km/h", 5ul);
         }
         if (dat->wx.temp!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Temp:", 7ul);
            aprsstr_FixToStr(aprstext_FtoC(dat->wx.temp), 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "C", 2ul);
         }
         if (dat->wx.hygro!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Hum:", 6ul);
            aprsstr_IntToStr((int32_t)X2C_TRUNCI(dat->wx.hygro+0.5f,
                X2C_min_longint,X2C_max_longint), 1UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "%", 2ul);
         }
         if (dat->wx.baro!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Baro:", 7ul);
            aprsstr_FixToStr(dat->wx.baro*0.1f+0.05f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "hPa", 4ul);
         }
         if (dat->wx.rain1!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Rain1h:", 9ul);
            aprsstr_FixToStr(dat->wx.rain1*0.254f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "mm", 3ul);
         }
         if (dat->wx.rain24!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Rain24h:", 10ul);
            aprsstr_FixToStr(dat->wx.rain24*0.254f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "mm", 3ul);
         }
         if (dat->wx.raintoday!=1.E+6f) {
            if (nl) {
               aprsstr_Append(s, s_len, "\012 ", 3ul);
               nl = 0;
            }
            aprsstr_Append(s, s_len, " Rain00:", 9ul);
            aprsstr_FixToStr(dat->wx.raintoday*0.254f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "mm", 3ul);
         }
         if (dat->wx.lum!=1.E+6f) {
            if (nl) aprsstr_Append(s, s_len, "\012 ", 3ul);
            aprsstr_Append(s, s_len, " Luminosity:", 13ul);
            aprsstr_FixToStr(dat->wx.lum+0.5f, 0UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "W", 2ul);
         }
         if (dat->wx.sievert!=1.E+6f) {
            if (nl) aprsstr_Append(s, s_len, "\012 ", 3ul);
            aprsstr_Append(s, s_len, " Radiation:", 12ul);
            aprstext_sievert2str(dat->wx.sievert, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
         }
      }
      else if (dat->wx.storm>aprsdecode_WXNORMAL) {
         if (dat->type==aprsdecode_OBJ || dat->type==aprsdecode_ITEM) {
            objitem(s, s_len, dat);
         }
         nl = 0;
         aprsstr_Append(s, s_len, "\012 ", 3ul);
         if (dat->wx.storm==aprsdecode_WXTS) {
            aprsstr_Append(s, s_len, "Tropical Storm", 15ul);
         }
         else if (dat->wx.storm==aprsdecode_WXHC) {
            aprsstr_Append(s, s_len, "Hurricane", 10ul);
         }
         else if (dat->wx.storm==aprsdecode_WXTD) {
            aprsstr_Append(s, s_len, "Tropical Depression", 20ul);
         }
         nl = 0;
         if (dat->wx.gust!=1.E+6f) {
            aprsstr_Append(s, s_len, " Gust:", 7ul);
            aprsstr_FixToStr(dat->wx.gust*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km/h", 5ul);
         }
         if (dat->wx.sustaind!=0.0f) {
            aprsstr_Append(s, s_len, " Sustaind Speed:", 17ul);
            aprsstr_FixToStr(dat->wx.sustaind*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km/h", 5ul);
         }
         if (dat->wx.baro!=1.E+6f) {
            aprsstr_Append(s, s_len, " Baro:", 7ul);
            aprsstr_FixToStr(dat->wx.baro, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "hPa", 4ul);
         }
         if (dat->wx.radiushurr!=0.0f) {
            aprsstr_Append(s, s_len, " Radius Hurricane Winds:", 25ul);
            aprsstr_FixToStr(dat->wx.radiushurr*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km", 3ul);
         }
         if (dat->wx.radiusstorm!=0.0f) {
            aprsstr_Append(s, s_len, " Storm Winds:", 14ul);
            aprsstr_FixToStr(dat->wx.radiusstorm*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km", 3ul);
         }
         if (dat->wx.wholegale!=0.0f) {
            aprsstr_Append(s, s_len, " Whole gale:", 13ul);
            aprsstr_FixToStr(dat->wx.wholegale*1.609f, 2UL, h, 512ul);
            aprsstr_Append(s, s_len, h, 512ul);
            aprsstr_Append(s, s_len, "km", 3ul);
         }
      }
      else if (dat->type==aprsdecode_MSG) {
         aprsstr_Append(s, s_len, "\012  Msg To:", 11ul);
         aprstext_Apphex(s, s_len, dat->msgto, 9ul);
         if (dat->msgtext[0UL]) {
            aprsstr_Append(s, s_len, " Text:[", 8ul);
            aprstext_Apphex(s, s_len, dat->msgtext, 67ul);
            aprsstr_Append(s, s_len, "]", 2ul);
         }
         if (dat->acktext[0UL]) {
            aprsstr_Append(s, s_len, " Ack:[", 7ul);
            aprstext_Apphex(s, s_len, dat->acktext, 5ul);
            aprsstr_Append(s, s_len, "]", 2ul);
         }
         if (dat->ackrej==aprsdecode_MSGREJ) {
            aprsstr_Append(s, s_len, " Reject", 8ul);
         }
      }
      else if (dat->type==aprsdecode_OBJ || dat->type==aprsdecode_ITEM) {
         objitem(s, s_len, dat);
      }
      if (dat->type!=aprsdecode_MSG && dat->comment0[0UL]) {
         if (dat->type==aprsdecode_TELE) {
            aprsstr_Append(s, s_len, "\012 Telemetry: [", 15ul);
         }
         else aprsstr_Append(s, s_len, "\012 Comment: [", 13ul);
         aprstext_Apphex(s, s_len, dat->comment0, 256ul);
         aprsstr_Append(s, s_len, "]", 2ul);
      }
      if (dat->tlmvalues[0UL]) {
         aprsstr_Append(s, s_len, "\012  Mic-e Telemetry Seq:", 24ul);
         ret = 0L;
         for (;;) {
            if (dat->tlmvalues[ret]) {
               if (ret!=6L) {
                  aprsstr_IntToStr((int32_t)(dat->tlmvalues[ret]-1U), 1UL,
                h, 512ul);
                  aprsstr_Append(s, s_len, h, 512ul);
               }
               else {
                  tn = (uint32_t)(dat->tlmvalues[ret]-1U);
                  if (tn>=256UL) tn = (tn&8191UL)+8192UL;
                  else tn = (tn&255UL)+256UL;
                  while (tn>1UL) {
                     aprsstr_Append(s, s_len,
                (char *)(tmp = (char)((uint32_t)(char)(tn&1)
                +48UL),&tmp), 1u/1u);
                     tn = tn/2UL;
                  }
               }
            }
            ++ret;
            if (ret>6L) break;
            aprsstr_Append(s, s_len, ",", 2ul);
         }
      }
      aprsstr_Append(s, s_len, "\012 ", 3ul);
   }
   aprsstr_Append(s, s_len, "[", 2ul);
   aprstext_Apphex(s, s_len, pf->vardat->raw, 500ul);
   aprsstr_Append(s, s_len, "]", 2ul);
   if (!decoded) Errtxt(s, s_len, pf0, pf);
} /* end decode() */


extern void aprstext_decodelistline(char s[], uint32_t s_len,
                char text[], uint32_t text_len, uint32_t time0)
{
   uint32_t i;
   struct aprsdecode_DAT dat;
   struct aprsdecode_FRAMEHIST f;
   struct aprsdecode_VARDAT vardat;
   X2C_PCOPY((void **)&text,text_len);
   i = 0UL;
   while ((i<=text_len-1 && text[i]) && text[i]!='[') ++i;
   if (i>text_len-1 || text[i]==0) i = 0UL;
   aprsstr_Delstr(text, text_len, 0UL, i+1UL); /* remove port/time[ */
   i = aprsstr_Length(text, text_len);
   if (i>1UL) {
      text[i-1UL] = 0; /* remove ] */
      memset((char *) &vardat,(char)0,
                sizeof(struct aprsdecode_VARDAT));
      aprsstr_Assign(vardat.raw, 500ul, text, text_len);
      memset((char *) &f,(char)0,
                sizeof(struct aprsdecode_FRAMEHIST));
      f.vardat = &vardat;
      f.time0 = time0;
      aprstext_decode(s, s_len, 0, &f, 0, 0UL, 1, &dat);
   }
   X2C_PFREE(text);
} /* end decodelistline() */


extern void aprstext_setmark1(struct aprspos_POSITION pos,
                char overwrite, int32_t alt, uint32_t timestamp)
{
   if ((overwrite || !aprspos_posvalid(aprsdecode_click.markpos))
                || aprsdecode_click.marktime) {
      aprsdecode_click.markpos = pos;
      if (overwrite) aprsdecode_click.marktime = 0UL;
      else aprsdecode_click.marktime = aprsdecode_realtime;
      aprsdecode_click.markalti = alt;
      aprsdecode_click.markpost = timestamp;
   }
} /* end setmark1() */


extern void aprstext_setmarkalti(aprsdecode_pFRAMEHIST pf,
                aprsdecode_pOPHIST op, char overwrite)
{
   struct aprsdecode_DAT dat;
   int32_t alt;
   struct aprspos_POSITION pos;
   uint32_t t;
   aprsdecode_posinval(&pos);
   alt = X2C_max_longint;
   t = aprsdecode_realtime;
   if (pf && aprsdecode_Decode(pf->vardat->raw, 500ul, &dat)==0L) {
      if (dat.altitude>-10000L) alt = dat.altitude;
      pos = dat.pos;
      t = pf->time0;
   }
   else if (op && op->lastinftyp<100U) {
      alt = (int32_t)op->lasttempalt+22768L;
   }
   if (!aprspos_posvalid(pos) && op) pos = op->lastpos;
   aprstext_setmark1(pos, overwrite, alt, t);
} /* end setmarkalti() */


extern void aprstext_optext(uint32_t typ,
                struct aprsdecode_CLICKOBJECT * obj, char * last,
                char s[], uint32_t s_len)
{
   aprsdecode_pOPHIST op;
   aprsdecode_pFRAMEHIST pfe;
   aprsdecode_pFRAMEHIST pf1;
   aprsdecode_pFRAMEHIST pf;
   uint32_t cn;
   uint32_t cx;
   char ss[1000];
   struct aprsdecode_DAT dat;
   /*    islast:BOOLEAN; */
   op = obj->opf;
   pf = obj->pff0;
   if (pf==0 && op) pf = op->frames;
   s[0UL] = 0;
   /*  islast:=last; */
   *last = 0;
   if (op && pf) {
      if (typ==2UL) {
         /* find last raw frame */
         pf = op->frames;
         if (pf) {
            while (pf->next) pf = pf->next;
            obj->pff0 = pf;
         }
      }
      else if (typ==1UL) {
         /* next frame */
         pf1 = pf;
         do {
            if (pf->next==0) pf = op->frames;
            else pf = pf->next;
         } while (!((!aprsdecode_lums.errorstep || pf1==pf) || (pf->nodraw&~0x40U)!=0U));
         /*      IF pf^.next<>NIL THEN pf:=pf^.next ELSE pf:=op^.frames END;
                */
         if (pf) {
            obj->pff0 = pf;
            obj->pff = pf;
            obj->typf = aprsdecode_tTRACK; /* set "track found" */
         }
      }
      else if (typ==0UL) {
         /* back to last frame */
         pf1 = pf;
         pfe = pf;
         do {
            if (!aprsdecode_lums.errorstep || (pfe->nodraw&~0x40U)!=0U) {
               pf = pfe;
            }
            if (pfe->next==0) pfe = op->frames;
            else pfe = pfe->next;
         } while (pfe!=pf1);
         obj->pff0 = pf;
         obj->pff = pf;
         obj->typf = aprsdecode_tTRACK; /* set "track found" */
      }
      /*    IF ((typ=1) OR (typ=0)) & lums.errorstep & (pf=pf1)
                THEN Assign(s, "no more errors found"); */
      if ((aprsdecode_lums.errorstep && pf) && (pf->nodraw&~0x40U)==0U) {
         aprsstr_Assign(s, s_len, "Show errors mode: no (more) errors found",
                 41ul);
      }
      else if (pf) {
         cn = 0UL;
         cx = 0UL;
         pfe = 0;
         pf1 = op->frames;
         while (pf1) {
            ++cn;
            if (pf1==pf) cx = cn;
            if (pf1->next==pf) pfe = pf1;
            pf1 = pf1->next;
         }
         aprsstr_IntToStr((int32_t)cx, 0UL, s, s_len);
         aprsstr_Append(s, s_len, "/", 2ul);
         aprsstr_IntToStr((int32_t)cn, 0UL, ss, 1000ul);
         aprsstr_Append(s, s_len, ss, 1000ul);
         aprsstr_Append(s, s_len, " ", 2ul);
         if (pfe==0) {
            aprstext_decode(ss, 1000ul, op->frames, pf, 0, 0UL, 1, &dat);
         }
         else {
            aprstext_decode(ss, 1000ul, op->frames, pf, pfe->vardat,
                pfe->time0, 1, &dat);
         }
         aprsstr_Append(s, s_len, ss, 1000ul);
         *last = pf->next==0;
      }
   }
} /* end optext() */


extern aprsdecode_pOPHIST aprstext_oppo(aprsdecode_MONCALL opcall)
/* find pointer to call */
{
   aprsdecode_pOPHIST op;
   if (opcall[0UL]==0) return 0;
   op = aprsdecode_ophist0;
   while (op && X2C_STRCMP(op->call,9u,opcall,9u)) op = op->next;
   return op;
} /* end oppo() */


extern void aprstext_listop(char decoded)
{
   aprsdecode_pOPHIST op;
   aprsdecode_pFRAMEHIST pf;
   aprsdecode_pVARDAT oldv;
   uint32_t oldt;
   char s[1000];
   struct aprsdecode_DAT dat;
   op = aprsdecode_click.table[aprsdecode_click.selected].opf;
   if (op) {
      pf = op->frames;
      oldv = 0;
      oldt = 0UL;
      while (pf) {
         aprstext_decode(s, 1000ul, op->frames, pf, oldv, oldt, decoded,
                &dat);
         if (aprspos_posvalid(pf->vardat->pos)) oldv = pf->vardat;
         oldt = pf->time0;
         aprsstr_Append(s, 1000ul, "\012", 2ul);
         if (decoded) aprsstr_Append(s, 1000ul, "\012", 2ul);
         useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos, pf->time0);
         pf = pf->next;
      }
   }
} /* end listop() */


extern void aprstext_listin(char r[], uint32_t r_len, char port,
                char dir, char decoded, int32_t quali,
                int32_t txd, int32_t level)
{
   char s2[1000];
   char s1[1000];
   char s[1000];
   struct aprsdecode_VARDAT vard;
   struct aprsdecode_FRAMEHIST pf;
   uint32_t j;
   uint32_t i;
   struct aprsdecode_DAT dat;
   memset((char *) &vard,(char)0,sizeof(struct aprsdecode_VARDAT));
   i = 0UL;
   j = 0UL;
   while ((i<499UL && i<=r_len-1) && r[i]) {
      if (r[i]!='\015' && r[i]!='\012') j = i;
      vard.raw[i] = r[i];
      ++i;
   }
   vard.raw[j+1UL] = 0;
   memset((char *) &pf,(char)0,sizeof(struct aprsdecode_FRAMEHIST));
   pf.vardat = &vard;
   aprstext_decode(s, 1000ul, 0, &pf, 0, 0UL, decoded, &dat);
   if (decoded) {
      s1[0U] = '\012';
      s1[1U] = port;
      s1[2U] = 0;
   }
   else {
      s1[0U] = port;
      s1[1U] = 0;
   }
   if (dir=='<') aprsstr_Append(s1, 1000ul, "\370<\376", 4ul);
   else aprsstr_Append(s1, 1000ul, (char *) &dir, 1u/1u);
   if (txd>0L || quali>0L) {
      aprsstr_Append(s1, 1000ul, "(", 2ul);
      if (txd>0L) aprsstr_IntToStr(txd, 3UL, s2, 1000ul);
      else strncpy(s2,"   ",1000u);
      aprsstr_Append(s1, 1000ul, s2, 1000ul);
      aprsstr_Append(s1, 1000ul, "/", 2ul);
      if (level) aprsstr_IntToStr(level, 3UL, s2, 1000ul);
      else strncpy(s2,"   ",1000u);
      aprsstr_Append(s1, 1000ul, s2, 1000ul);
      aprsstr_Append(s1, 1000ul, "/", 2ul);
      if (quali>0L) aprsstr_IntToStr(quali, 2UL, s2, 1000ul);
      else strncpy(s2,"  ",1000u);
      aprsstr_Append(s1, 1000ul, s2, 1000ul);
      aprsstr_Append(s1, 1000ul, ")", 2ul);
   }
   aprsstr_Append(s1, 1000ul, s, 1000ul);
   useri_wrstrmon(s1, 1000ul, dat.pos);
} /* end listin() */

#define aprstext_TRIVIAL 3.1397174254317E-6
/* 20m */


extern void aprstext_listtyps(char typ, char decod,
                char oneop[], uint32_t oneop_len)
{
   aprsdecode_pOPHIST op;
   aprsdecode_pFRAMEHIST pf;
   char s[1000];
   char lasttext[101];
   char lastto[101];
   struct aprsdecode_DAT dat;
   X2C_PCOPY((void **)&oneop,oneop_len);
   op = aprsdecode_ophist0;
   while (op) {
      pf = op->frames;
      if (typ=='N') {
         /* no pos */
         if (pf && !aprspos_posvalid(op->lastpos)) {
            while (pf->next) pf = pf->next;
            aprstext_decode(s, 1000ul, 0, pf, 0, 0UL, decod, &dat);
            if (decod) aprsstr_Append(s, 1000ul, "\012\012", 3ul);
            else aprsstr_Append(s, 1000ul, "\012", 2ul);
            useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos,
                pf->time0);
         }
      }
      else if (typ=='D') {
         /* moveing stations */
         if (pf && (op->margin0.lat>op->margin1.lat+3.1397174254317E-6f || op->margin0.long0+3.1397174254317E-6f<op->margin1.long0)
                ) {
            while (pf->next) pf = pf->next;
            aprstext_decode(s, 1000ul, 0, pf, 0, 0UL, decod, &dat);
            if (decod) aprsstr_Append(s, 1000ul, "\012\012", 3ul);
            else aprsstr_Append(s, 1000ul, "\012", 2ul);
            useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos,
                pf->time0);
         }
      }
      else if (typ=='W') {
         if (pf) {
            while (pf->next) pf = pf->next;
            aprstext_decode(s, 1000ul, 0, pf, 0, 0UL, decod, &dat);
            /*        IF (dat.symt="/") & (dat.sym="_") */
            /*        OR (op^.temptime+SHOWTEMPWIND>systime)
                & (op^.lastinftyp>=100) */
            /*        & (op^.lasttempalt>=-99) & (op^.lasttempalt<=99)
                THEN */
            if (dat.symt=='/' && dat.sym=='_') {
               if (decod) aprsstr_Append(s, 1000ul, "\012\012", 3ul);
               else aprsstr_Append(s, 1000ul, "\012", 2ul);
               useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos,
                pf->time0);
            }
         }
      }
      else if (typ=='M' || typ=='B' && (oneop[0UL]==0 || X2C_STRCMP(oneop,
                oneop_len,op->call,9u)==0)) {
         /* bulletins messages */
         lastto[0U] = 0;
         lasttext[0U] = 0;
         while (pf) {
            if (((((((pf->vardat->lastref==pf && aprsdecode_Decode(pf->vardat->raw,
                 500ul, &dat)>=0L) && (typ=='M' || typ=='B')) && dat.type==aprsdecode_MSG) && X2C_STRCMP(dat.symcall,
                9u,dat.msgto,9u)) && dat.msgtext[0UL]) && (typ=='B')==IsBulletin(dat)) && ((oneop[0UL]==0 || X2C_STRCMP(oneop,
                oneop_len,op->call,9u)==0) || X2C_STRCMP(oneop,oneop_len,
                dat.msgto,9u)==0)) {
               if (!(aprsstr_StrCmp(lastto, 101ul, dat.msgto,
                9ul) && aprsstr_StrCmp(lasttext, 101ul, dat.msgtext, 67ul))) {
                  aprstext_DateLocToStr(pf->time0, s, 1000ul);
                  aprsstr_Append(s, 1000ul, " ", 2ul);
                  aprsstr_Append(s, 1000ul, dat.symcall, 9ul);
                  aprsstr_Append(s, 1000ul, ">", 2ul);
                  aprsstr_Append(s, 1000ul, dat.msgto, 9ul);
                  aprsstr_Append(s, 1000ul, ":[", 3ul);
                  aprstext_Apphex(s, 1000ul, dat.msgtext, 67ul);
                  aprsstr_Append(s, 1000ul, "]", 2ul);
                  if (dat.acktext[0UL]) {
                     aprstext_Apphex(s, 1000ul, " Ack[", 6ul);
                     aprsstr_Append(s, 1000ul, dat.acktext, 5ul);
                     aprsstr_Append(s, 1000ul, "]", 2ul);
                  }
                  aprsstr_Append(s, 1000ul, "\012", 2ul);
                  useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos,
                pf->time0);
                  aprsstr_Assign(lastto, 101ul, dat.msgto, 9ul);
                  aprsstr_Assign(lasttext, 101ul, dat.msgtext, 67ul);
               }
            }
            pf = pf->next;
         }
      }
      else if (typ=='O') {
         /*
             ELSIF ((typ="M") OR (typ="B")) & ((oneop[0]=0C)
                OR (oneop=op^.call)) THEN (* bulletins messages *)
               lastto[0]:=0C;
               lasttext[0]:=0C;
         
               WHILE pf<>NIL DO
                 IF (pf^.vardat^.lastref=pf) & (Decode(pf^.vardat^.raw,
                dat)>=0) THEN
                   IF (typ="M") OR (typ="B") THEN
                     IF (dat.type=MSG) & (dat.symcall<>dat.msgto)
                & (dat.msgtext[0]<>0C) THEN
                       IF (typ="B")=IsBulletin(dat) THEN 
                         IF NOT (StrCmp(lastto, dat.msgto) & StrCmp(lasttext,
                 dat.msgtext)) THEN 
                           DateLocToStr(pf^.time, s); Append(s, " ");
                           Append(s, dat.symcall); Append(s, ">");
                           Append(s, dat.msgto); Append(s, ":[");
                           Apphex(s, dat.msgtext); Append(s, "]");
                           IF dat.acktext[0]<>0C THEN 
                             Apphex(s, " Ack[");Append(s, dat.acktext);
                Append(s, "]");
                           END;
                           Append(s, LF);
                           wrstrlist(s, dat.symcall, pf^.vardat^.pos,
                pf^.time);
         
         <* IF WITHSTDOUT THEN *>
                           WrStr(s);
         <* END *>
                           Assign(lastto, dat.msgto);
                           Assign(lasttext, dat.msgtext);
                         END;
                       END;
                     END;
                   END;  
                 END;
                 pf:=pf^.next;
               END;
         */
         if (pf) {
            while (pf->next) pf = pf->next;
            aprstext_decode(s, 1000ul, 0, pf, 0, 0UL, decod, &dat);
            if ((dat.type==aprsdecode_OBJ || dat.type==aprsdecode_ITEM)
                && (oneop[0UL]==0 || X2C_STRCMP(oneop,oneop_len,
                dat.objectfrom,9u)==0)) {
               if (decod) {
                  aprsstr_Append(s, 1000ul, "\012\012", 3ul);
                  useri_wrstrlist(s, 1000ul, dat.symcall, pf->vardat->pos,
                pf->time0);
               }
               else {
                  aprsstr_Append(s, 1000ul, "\012", 2ul);
                  useri_wrstrlist(s, 1000ul, dat.objectfrom, pf->vardat->pos,
                 pf->time0);
               }
            }
         }
      }
      op = op->next;
   }
   X2C_PFREE(oneop);
} /* end listtyps() */

#define aprstext_Z 48


static void degtostr(float d, char lat, char form,
                char s[], uint32_t s_len)
{
   uint32_t i;
   uint32_t n;
   if (s_len-1<11UL) {
      s[0UL] = 0;
      return;
   }
   if (form=='2') i = 7UL;
   else if (form=='3') i = 8UL;
   else i = 9UL;
   if (d<0.0f) {
      d = -d;
      if (lat) s[i] = 'S';
      else s[i+1UL] = 'W';
   }
   else if (lat) s[i] = 'N';
   else s[i+1UL] = 'E';
   i = (uint32_t)!lat;
   if (form=='2') {
      /* DDMM.MMNDDMM.MME */
      /*    n:=trunc(d*(6000*180/PI)+0.5); */
      n = aprsdecode_trunc(d*3.4377467707849E+5f);
      s[0UL] = (char)((n/600000UL)%10UL+48UL);
      s[i] = (char)((n/60000UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/6000UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/1000UL)%6UL+48UL);
      ++i;
      s[i] = (char)((n/100UL)%10UL+48UL);
      ++i;
      s[i] = '.';
      ++i;
      s[i] = (char)((n/10UL)%10UL+48UL);
      ++i;
      s[i] = (char)(n%10UL+48UL);
      ++i;
   }
   else if (form=='3') {
      /* DDMM.MMMNDDMM.MMME */
      n = aprsdecode_trunc(d*3.4377467707849E+6f+0.5f);
      s[0UL] = (char)((n/6000000UL)%10UL+48UL);
      s[i] = (char)((n/600000UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/60000UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/10000UL)%6UL+48UL);
      ++i;
      s[i] = (char)((n/1000UL)%10UL+48UL);
      ++i;
      s[i] = '.';
      ++i;
      s[i] = (char)((n/100UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/10UL)%10UL+48UL);
      ++i;
      s[i] = (char)(n%10UL+48UL);
      ++i;
   }
   else {
      /* DDMMSS */
      n = aprsdecode_trunc(d*2.062648062471E+5f+0.5f);
      s[0UL] = (char)((n/360000UL)%10UL+48UL);
      s[i] = (char)((n/36000UL)%10UL+48UL);
      ++i;
      s[i] = (char)((n/3600UL)%10UL+48UL);
      ++i;
      s[i] = '\177';
      ++i;
      s[i] = (char)((n/600UL)%6UL+48UL);
      ++i;
      s[i] = (char)((n/60UL)%10UL+48UL);
      ++i;
      s[i] = '\'';
      ++i;
      s[i] = (char)((n/10UL)%6UL+48UL);
      ++i;
      s[i] = (char)(n%10UL+48UL);
      ++i;
      s[i] = '\"';
      ++i;
   }
   ++i;
   s[i] = 0;
} /* end degtostr() */


extern void aprstext_postostr(struct aprspos_POSITION pos, char form,
                char s[], uint32_t s_len)
{
   char h[32];
   degtostr(pos.lat, 1, form, s, s_len);
   aprsstr_Append(s, s_len, "/", 2ul);
   degtostr(pos.long0, 0, form, h, 32ul);
   aprsstr_Append(s, s_len, h, 32ul);
} /* end postostr() */


static int32_t myround(float x)
{
   if (x>=0.0f) x = x+0.5f;
   else x = x-0.5f;
   return (int32_t)X2C_TRUNCI(x,X2C_min_longint,X2C_max_longint);
} /* end myround() */


extern void aprstext_measure(struct aprspos_POSITION pos0,
                struct aprspos_POSITION pos1, char s[], uint32_t s_len,
                 char sum)
{
   char h[32];
   if (aprspos_posvalid(pos0) && aprspos_posvalid(pos1)) {
      aprstext_postostr(pos1, '3', s, s_len);
      aprsstr_Append(s, s_len, " [", 3ul);
      maptool_postoloc(h, 32ul, pos1);
      aprsstr_Append(s, s_len, h, 32ul);
      aprsstr_Append(s, s_len, "] ", 3ul);
      aprsstr_FixToStr(aprspos_distance(pos0, pos1), 4UL, h, 32ul);
      aprsstr_Append(s, s_len, h, 32ul);
      aprsstr_Append(s, s_len, "km,", 4ul);
      aprsstr_IntToStr(myround(aprspos_azimuth(pos0, pos1)), 1UL, h, 32ul);
      aprsstr_Append(s, s_len, h, 32ul);
      aprsstr_Append(s, s_len, "deg to Marker", 14ul);
      if (sum) {
         if (aprsdecode_click.waysum==0.0f) aprsdecode_click.sumpos = pos0;
         aprsdecode_click.waysum = aprsdecode_click.waysum+aprspos_distance(aprsdecode_click.sumpos,
                 pos1);
         aprsdecode_click.sumpos = pos1;
         aprsstr_Append(s, s_len, " sum:", 6ul);
         aprsstr_FixToStr(aprsdecode_click.waysum, 4UL, h, 32ul);
         aprsstr_Append(s, s_len, h, 32ul);
         aprsstr_Append(s, s_len, "km", 3ul);
      }
   }
   else s[0UL] = 0;
} /* end measure() */


static uint32_t c(char * err, char ch)
{
   uint32_t n;
   if ((uint8_t)ch>='0') n = (uint32_t)(uint8_t)ch-48UL;
   else {
      n = 0UL;
      *err = 1;
   }
   if (n>9UL) *err = 1;
   return n;
} /* end c() */


extern void aprstext_degtopos(char s[], uint32_t s_len,
                struct aprspos_POSITION * pos)
/* DDMM.MMNDDDMM.MME */
{
   char err;
   uint32_t d;
   X2C_PCOPY((void **)&s,s_len);
   err = 0;
   d = c(&err, s[0UL])*60000UL+c(&err, s[1UL])*6000UL+c(&err,
                s[2UL])*1000UL+c(&err, s[3UL])*100UL+c(&err,
                s[5UL])*10UL+c(&err, s[6UL]);
   pos->lat = (float)d*2.9088820866572E-6f;
   if (pos->lat>=1.5707963267949f) err = 1;
   if (X2C_CAP(s[7UL])=='S') pos->lat = -pos->lat;
   else if (X2C_CAP(s[7UL])!='N') err = 1;
   d = c(&err, s[9UL])*600000UL+c(&err, s[10UL])*60000UL+c(&err,
                s[11UL])*6000UL+c(&err, s[12UL])*1000UL+c(&err,
                s[13UL])*100UL+c(&err, s[15UL])*10UL+c(&err, s[16UL]);
   pos->long0 = (float)d*2.9088820866572E-6f;
   if (pos->long0>=3.1415926535898f) err = 1;
   if (X2C_CAP(s[17UL])=='W') pos->long0 = -pos->long0;
   else if (X2C_CAP(s[17UL])!='E') err = 1;
   if (((uint8_t)s[2UL]>='6' || (uint8_t)s[12UL]>='6') || err) {
      aprsdecode_posinval(pos);
   }
   X2C_PFREE(s);
} /* end degtopos() */


static char c0(uint32_t * d, uint32_t * i, char s[],
                uint32_t s_len, uint32_t mul)
{
   uint32_t n;
   char ch;
   ch = s[*i];
   if (mul>0UL) {
      if ((uint8_t)ch>='0') n = (uint32_t)(uint8_t)ch-48UL;
      else return 0;
      if (n>9UL) return 0;
      *d += n*mul;
   }
   else if (ch!='.') return 0;
   ++*i;
   return 1;
} /* end c() */


extern void aprstext_deghtopos(char s[], uint32_t s_len,
                struct aprspos_POSITION * pos)
/* DDMM.MMMNDDDMM.MMME */
{
   char e;
   char err;
   uint32_t i;
   uint32_t d;
   X2C_PCOPY((void **)&s,s_len);
   err = 0;
   d = 0UL;
   i = 0UL;
   e = ((((((c0(&d, &i, s, s_len, 600000UL) && c0(&d, &i, s, s_len,
                60000UL)) && c0(&d, &i, s, s_len, 10000UL)) && c0(&d, &i, s,
                s_len, 1000UL)) && c0(&d, &i, s, s_len, 0UL)) && c0(&d, &i,
                s, s_len, 100UL)) && c0(&d, &i, s, s_len, 10UL)) && c0(&d,
                &i, s, s_len, 1UL);
   pos->lat = (float)d*2.9088820866572E-7f;
   if (pos->lat>=1.5707963267949f) err = 1;
   if (s[i]=='S') pos->lat = -pos->lat;
   else if (s[i]!='N') err = 1;
   i += 2UL;
   d = 0UL;
   e = (((((((c0(&d, &i, s, s_len, 6000000UL) && c0(&d, &i, s, s_len,
                600000UL)) && c0(&d, &i, s, s_len, 60000UL)) && c0(&d, &i, s,
                 s_len, 10000UL)) && c0(&d, &i, s, s_len, 1000UL)) && c0(&d,
                &i, s, s_len, 0UL)) && c0(&d, &i, s, s_len, 100UL)) && c0(&d,
                 &i, s, s_len, 10UL)) && c0(&d, &i, s, s_len, 1UL);
   pos->long0 = (float)d*2.9088820866572E-7f;
   if (pos->long0>=3.1415926535898f) err = 1;
   if (s[i]=='W') pos->long0 = -pos->long0;
   else if (s[i]!='E') err = 1;
   if (((uint8_t)s[2UL]>='6' || (uint8_t)s[13UL]>='6') || err) {
      aprsdecode_posinval(pos);
   }
   X2C_PFREE(s);
} /* end deghtopos() */


static void cleanposstr(char s[], uint32_t s_len)
{
   uint32_t i;
   i = 0UL;
   while (i<=s_len-1 && s[i]) {
      if ((s[i]==',' || s[i]=='/') || s[i]=='\\') s[i] = ' ';
      ++i;
   }
} /* end cleanposstr() */


extern void aprstext_degdeztopos(char s[], uint32_t s_len,
                struct aprspos_POSITION * pos)
/* lat long in float deg */
{
   float d;
   char h[31];
   X2C_PCOPY((void **)&s,s_len);
   cleanposstr(s, s_len);
   aprsstr_Extractword(s, s_len, h, 31ul);
   if (aprsstr_StrToFix(&d, h, 31ul)) {
      pos->lat = d*1.7453292519943E-2f;
      aprsstr_Extractword(s, s_len, h, 31ul);
      if (aprsstr_StrToFix(&d, h, 31ul)) {
         pos->long0 = d*1.7453292519943E-2f;
         if ((float)fabs(pos->long0)<3.1415926535898f && (float)
                fabs(pos->lat)<=1.484f) goto label;
      }
   }
   aprsdecode_posinval(pos);
   label:;
   X2C_PFREE(s);
} /* end degdeztopos() */


extern void aprstext_deganytopos(char s[], uint32_t s_len,
                struct aprspos_POSITION * pos)
/* lat long any format in float deg */
{
   X2C_PCOPY((void **)&s,s_len);
   aprstext_degtopos(s, s_len, pos); /* DDMM.MMNDDDMM.MME */
   if (!aprspos_posvalid(*pos)) aprstext_deghtopos(s, s_len, pos);
   if (!aprspos_posvalid(*pos)) aprstext_degdeztopos(s, s_len, pos);
   X2C_PFREE(s);
} /* end deganytopos() */


extern char aprstext_getmypos(struct aprspos_POSITION * pos)
{
   char s[51];
   useri_confstr(useri_fMYPOS, s, 51ul);
   aprstext_deganytopos(s, 51ul, pos);
   return aprspos_posvalid(*pos);
} /* end getmypos() */


static char num(int32_t n)
{
   return (char)(labs(n)%10L+48L);
} /* end num() */


static uint32_t dao91(uint32_t x)
/* 33 + radix91(xx/1.1) of dddmm.mmxx */
{
   return 33UL+(x*20UL+11UL)/22UL;
} /* end dao91() */


static void daostr(int32_t latd, int32_t longd, char s[],
                uint32_t s_len)
{
   s[0UL] = '!';
   s[1UL] = 'w';
   s[2UL] = (char)dao91((uint32_t)latd);
   s[3UL] = (char)dao91((uint32_t)longd);
   s[4UL] = '!';
   s[5UL] = 0;
} /* end daostr() */


static void micedest(int32_t lat, int32_t long0, char s[],
                uint32_t s_len)
{
   uint32_t nl;
   uint32_t nb;
   nl = (uint32_t)(labs(long0)/6000L);
   nb = (uint32_t)(labs(lat)/6000L);
   s[0UL] = (char)(80UL+nb/10UL);
   s[1UL] = (char)(80UL+nb%10UL);
   nb = (uint32_t)labs(lat)-nb*6000UL;
   s[2UL] = (char)(80UL+nb/1000UL);
   s[3UL] = (char)(48UL+32UL*(uint32_t)(lat>=0L)+(nb/100UL)%10UL);
   s[4UL] = (char)(48UL+32UL*(uint32_t)(nl<10UL || nl>=100UL)+(nb/10UL)
                %10UL);
   s[5UL] = (char)(48UL+32UL*(uint32_t)(long0<0L)+nb%10UL);
   s[6UL] = 0;
} /* end micedest() */


static void micedata(int32_t lat, int32_t long0, uint32_t knots,
                uint32_t dir, int32_t alt, char sym[],
                uint32_t sym_len, char s[], uint32_t s_len)
{
   uint32_t n;
   uint32_t nl;
   X2C_PCOPY((void **)&sym,sym_len);
   dir = dir%360UL;
   /*IF dir>0 THEN DEC(dir) END; */
   /*IF dir>359 THEN dir:=359 END; */
   if (knots>799UL) knots = 0UL;
   nl = (uint32_t)(labs(long0)/6000L);
   if (nl<10UL) s[0UL] = (char)(nl+118UL);
   else if (nl>=100UL) {
      if (nl<110UL) s[0UL] = (char)(nl+8UL);
      else s[0UL] = (char)(nl-72UL);
   }
   else s[0UL] = (char)(nl+28UL);
   nl = (uint32_t)labs(long0)-nl*6000UL; /* long min*100 */
   n = nl/100UL;
   if (n<10UL) n += 60UL;
   s[1UL] = (char)(n+28UL);
   s[2UL] = (char)(nl%100UL+28UL);
   s[3UL] = (char)(knots/10UL+28UL);
   s[4UL] = (char)(32UL+(knots%10UL)*10UL+dir/100UL);
   s[5UL] = (char)(28UL+dir%100UL);
   s[6UL] = sym[1UL];
   s[7UL] = sym[0UL];
   if (alt>-10000L) {
      n = (uint32_t)(alt+10000L);
      s[8UL] = (char)(33UL+(n/8281UL)%91UL);
      s[9UL] = (char)(33UL+(n/91UL)%91UL);
      s[10UL] = (char)(33UL+n%91UL);
      s[11UL] = '}';
      s[12UL] = 0;
   }
   else s[8UL] = 0;
   X2C_PFREE(sym);
} /* end micedata() */


static void alt2str(int32_t feet, char s[], uint32_t s_len)
{
   if (feet>-100000L) {
      s[0UL] = '/';
      s[1UL] = 'A';
      s[2UL] = '=';
      if (feet<0L) {
         feet = -feet;
         s[3UL] = '-';
      }
      else s[3UL] = num(feet/100000L);
      s[4UL] = num(feet/10000L);
      s[5UL] = num(feet/1000L);
      s[6UL] = num(feet/100L);
      s[7UL] = num(feet/10L);
      s[8UL] = num(feet);
      s[9UL] = 0;
   }
   else s[0UL] = 0;
} /* end alt2str() */


static void speeddir2str(int32_t knots, int32_t dir, char areaobj,
                 char s[], uint32_t s_len)
{
   if (areaobj || dir>0L && dir<=360L) {
      /*    IF dir=0 THEN dir:=360 END; */
      s[0UL] = num(dir/100L);
      s[1UL] = num(dir/10L);
      s[2UL] = num(dir);
   }
   else {
      s[0UL] = '.';
      s[1UL] = '.';
      s[2UL] = '.';
   }
   if (areaobj && knots>=1000L) s[3UL] = num(knots/1000L);
   else s[3UL] = '/';
   s[4UL] = num(knots/100L);
   s[5UL] = num(knots/10L);
   s[6UL] = num(knots);
   s[7UL] = 0;
} /* end speeddir2str() */


extern void aprstext_compressdata(struct aprspos_POSITION pos,
                uint32_t knots, uint32_t dir, int32_t feet,
                char sym[], uint32_t sym_len, char s[],
                uint32_t s_len)
{
   int32_t n;
   char h[201];
   X2C_PCOPY((void **)&sym,sym_len);
   pos.lat = pos.lat*5.7295779513082E+1f;
   pos.long0 = pos.long0*5.7295779513082E+1f;
   s[0UL] = sym[0UL];
   if (pos.lat<90.0f) {
      n = (int32_t)aprsdecode_trunc((90.0f-pos.lat)*3.80926E+5f);
   }
   else n = 0L;
   s[1UL] = (char)(33L+n/753571L);
   s[2UL] = (char)(33L+(n/8281L)%91L);
   s[3UL] = (char)(33L+(n/91L)%91L);
   s[4UL] = (char)(33L+n%91L);
   if (pos.long0>(-180.0f)) {
      n = (int32_t)aprsdecode_trunc((180.0f+pos.long0)*1.90463E+5f);
   }
   else n = 0L;
   s[5UL] = (char)(33L+n/753571L);
   s[6UL] = (char)(33L+(n/8281L)%91L);
   s[7UL] = (char)(33L+(n/91L)%91L);
   s[8UL] = (char)(33L+n%91L);
   s[9UL] = sym[1UL];
   if (knots>0UL) {
      if (dir>=360UL) dir = 0UL;
      s[10UL] = (char)(33UL+dir/4UL);
      s[11UL] = (char)(33UL+aprsdecode_trunc(osic_ln((float)
                (knots+1UL))*1.29935872129E+1f));
      s[12UL] = '_';
   }
   else if (feet>0L) {
      n = (int32_t)aprsdecode_trunc(osic_ln((float)feet)*500.5f+0.5f);
      if (n>=8281L) n = 8280L;
      s[10UL] = (char)(33L+n/91L);
      s[11UL] = (char)(33L+n%91L);
      s[12UL] = 'W';
   }
   else {
      s[10UL] = ' ';
      s[11UL] = ' ';
      s[12UL] = '_';
   }
   s[13UL] = 0;
   if (knots>0UL && feet>0L) {
      alt2str(feet, h, 201ul);
      aprsstr_Append(s, s_len, h, 201ul);
   }
   X2C_PFREE(sym);
} /* end compressdata() */

#define aprstext_Z0 48


static void deg2str(int32_t lat, int32_t long0, char s[],
                uint32_t s_len)
/* DDMM.MMNDDDMM.MME */
{
   if (lat<0L) {
      lat = -lat;
      s[7UL] = 'S';
   }
   else s[7UL] = 'N';
   if (long0<0L) {
      long0 = -long0;
      s[17UL] = 'W';
   }
   else s[17UL] = 'E';
   s[0UL] = (char)(lat/60000L+48L);
   s[1UL] = (char)((lat/6000L)%10L+48L);
   s[2UL] = (char)((lat/1000L)%6L+48L);
   s[3UL] = (char)((lat/100L)%10L+48L);
   s[4UL] = '.';
   s[5UL] = (char)((lat/10L)%10L+48L);
   s[6UL] = (char)(lat%10L+48L);
   s[9UL] = (char)(long0/600000L+48L);
   s[10UL] = (char)((long0/60000L)%10L+48L);
   s[11UL] = (char)((long0/6000L)%10L+48L);
   s[12UL] = (char)((long0/1000L)%6L+48L);
   s[13UL] = (char)((long0/100L)%10L+48L);
   s[14UL] = '.';
   s[15UL] = (char)((long0/10L)%10L+48L);
   s[16UL] = (char)(long0%10L+48L);
   s[18UL] = 0;
} /* end deg2str() */


static void getbeaconpos(struct aprspos_POSITION * pos, char * err)
{
   int32_t fd;
   int32_t len;
   char s[1001];
   useri_confstr(useri_fRBPOS, s, 1001ul);
   if (s[0U]==':') {
      /* get beacon position from file */
      aprsstr_Delstr(s, 1001ul, 0UL, 1UL);
      fd = osi_OpenRead(s, 1001ul);
      s[0U] = 0;
      if (osic_FdValid(fd)) {
         len = osi_RdBin(fd, (char *)s, 1001u/1u, 1000UL);
         if (len<1L) {
            len = 0L;
            useri_say("\012beacon position file not readable\012", 36ul,
                20UL, 'e');
         }
         else if (len>1000L) len = 1000L;
         s[len] = 0;
         osic_Close(fd);
      }
      else {
         useri_say("\012beacon position file not found\012", 33ul, 20UL,
                'e');
      }
   }
   if (s[0U]) {
      aprstext_deganytopos(s, 1001ul, pos);
      if (!aprspos_posvalid(*pos)) {
         useri_say("\012beacon: object/item position wrong\012", 37ul, 4UL,
                'e');
         *err = 1;
      }
   }
   else {
      useri_say("\012beacon: no object/item position\012", 34ul, 4UL, 'e');
      *err = 1;
      aprsdecode_posinval(pos);
   }
} /* end getbeaconpos() */


extern char aprstext_callwrong(char s[], uint32_t s_len)
{
   uint32_t i;
   i = 0UL;
   while (i<=s_len-1 && s[i]) {
      if ((uint8_t)s[i]<=' ' || (uint8_t)s[i]>='\177') return 1;
      ++i;
   }
   return i<3UL || i>9UL;
} /* end callwrong() */

#define aprstext_RAD 3.4377467707849E+7


extern void aprstext_encbeacon(char s[], uint32_t s_len,
                uint32_t * len)
/* assemble beacon string */
{
   char h[201];
   char symb[2];
   char postyp;
   char typ;
   char mull;
   char areaobj;
   char err;
   char dao;
   char bkn;
   struct aprspos_POSITION pos;
   int32_t i;
   int32_t longd;
   int32_t latd;
   int32_t long0;
   int32_t lat;
   int32_t alt;
   int32_t feet;
   int32_t knots;
   int32_t dir;
   uint32_t datastart;
   err = 0;
   *len = 16UL; /* ax.25 address + UI + PID */
   useri_confstr(useri_fRBTYP, s, s_len);
   typ = X2C_CAP(s[0UL]);
   bkn = (((typ!='O' && typ!='H') && typ!='P') && typ!='I') && typ!='J';
   useri_confstr(useri_fRBPOSTYP, (char *) &postyp, 1u/1u);
   useri_confstr(useri_fRBSYMB, symb, 2ul);
   areaobj = (typ=='O' && symb[0U]=='\\') && symb[1U]=='l';
   if (aprsstr_Length(symb, 2ul)!=2UL) {
      useri_say("\012no symbol\012", 12ul, 4UL, 'e');
      err = 1;
   }
   dao = postyp=='G' || postyp=='M';
   knots = useri_conf2int(useri_fRBSPEED, 0UL, 0L, 32767L, 0L);
   if (!areaobj) {
      knots = (int32_t)aprsdecode_trunc((float)
                knots*5.3995680345572E-1f+0.5f);
   }
   dir = useri_conf2int(useri_fRBDIR, 0UL, 0L, 1000L, 1000L);
   /*WrInt(dir, 9); WrStrLn("defdir"); */
   if (dir<1000L) {
      if (!areaobj) {
         if (dir>359L) {
            useri_say("\012beacon: Direction <360\012", 25ul, 20UL, 'e');
            err = 1;
         }
         else if (knots==0L) {
            useri_say("\012direction needs speed>0\012", 26ul, 20UL, 'e');
         }
         if (dir==0L) dir = 360L;
      }
   }
   else dir = 0L;
   alt = useri_conf2int(useri_fRBALT, 0UL, -10000L, 1000000L, -32768L);
   feet = (int32_t)aprsdecode_trunc((float)fabs(X2C_DIVR((float)alt,
                0.3048f)+0.5f));
   if (alt<0L) feet = -feet;
   useri_confstr(useri_fRBPORT, s, s_len); /* port */
   aprsstr_Append(s, s_len, ":", 2ul);
   aprsstr_IntToStr(useri_conf2int(useri_fRBTIME, 0UL, 0L, 32767L, 3600L),
                1UL, h, 201ul);
   aprsstr_Append(s, s_len, h, 201ul); /* repeat time */
   aprsstr_Append(s, s_len, ":", 2ul);
   if (bkn) {
      useri_confstr(useri_fRBNAME, h, 201ul);
      if ((uint8_t)h[0U]<=' ') {
         useri_say("\012no beacon call?\012", 18ul, 4UL, 'e');
      }
      if (useri_configon(useri_fMUSTBECALL) && !aprstext_isacall(h, 201ul)) {
         useri_say("\012not valid callsign as beacon sender?\012", 39ul,
                20UL, 'e');
      }
      aprsstr_Append(s, s_len, h, 201ul);
      if (aprstext_getmypos(&pos)) {
         if (!aprspos_posvalid(pos)) {
            useri_say("\012Net beacon position wrong\012", 28ul, 4UL, 'e');
            err = 1;
         }
      }
      else getbeaconpos(&pos, &err);
   }
   else {
      useri_confstr(useri_fMYCALL, h, 201ul);
      if ((uint8_t)h[0U]<=' ') {
         useri_say("\012object/item needs a Config/Online/My Call\012", 44ul,
                 4UL, 'e');
      }
      aprsstr_Append(s, s_len, h, 201ul);
      getbeaconpos(&pos, &err);
   }
   lat = (int32_t)aprsdecode_trunc((float)fabs(pos.lat)
                *3.4377467707849E+7f);
   long0 = (int32_t)aprsdecode_trunc((float)fabs(pos.long0)
                *3.4377467707849E+7f);
   latd = (int32_t)((uint32_t)lat%100UL);
   longd = (int32_t)((uint32_t)long0%100UL);
   if (dao) {
      lat -= latd;
      long0 -= longd;
   }
   lat = lat/100L;
   long0 = long0/100L;
   if (pos.lat<0.0f) lat = -lat;
   if (pos.long0<0.0f) {
      long0 = -long0;
   }
   aprsstr_Append(s, s_len, ">", 2ul);
   if (X2C_CAP(postyp)=='M') micedest(lat, long0, h, 201ul);
   else {
      useri_confstr(useri_fRBDEST, h, 201ul);
      if (h[0U]==0) strncpy(h,"APLM01",201u);
      i = aprsstr_InStr(h, 201ul, "-", 2ul);
      if (i>0L) aprsstr_Delstr(h, 201ul, (uint32_t)i, 201UL);
   }
   aprsstr_Append(s, s_len, h, 201ul);
   useri_confstr(useri_fRBPATH, h, 201ul);
   if ((uint8_t)h[0U]>' ') {
      if (h[0U]!='-') aprsstr_Append(s, s_len, ",", 2ul);
      aprsstr_Append(s, s_len, h, 201ul); /* dest ssid + via path */
      i = 0L;
      while (s[i]) {
         if (s[i]==',') *len += 7UL;
         ++i;
      }
   }
   aprsstr_Append(s, s_len, ":", 2ul); /* end of address */
   datastart = aprsstr_Length(s, s_len); /* rest of line for byte count */
   if (!bkn) {
      useri_confstr(useri_fRBNAME, h, 201ul);
      if ((uint8_t)h[0U]<=' ') {
         useri_say("\012no object/item name?\012", 23ul, 20UL, 'e');
         err = 1;
      }
      aprsstr_Append(h, 201ul, "         ", 10ul); /* fix size */
      h[9U] = 0;
      if ((typ=='O' || typ=='H') || typ=='P') {
         aprsstr_Append(s, s_len, ";", 2ul); /* object */
         aprsstr_Append(s, s_len, h, 201ul);
         if (typ=='P') aprsstr_Append(s, s_len, "_", 2ul);
         else aprsstr_Append(s, s_len, "*", 2ul);
         if (typ=='O') aprsstr_Append(s, s_len, "\\\\Zz", 5ul);
         else aprsstr_Append(s, s_len, "\\\\Hh", 5ul);
      }
      else {
         aprsstr_Append(s, s_len, ")", 2ul); /* item */
         i = 3L;
         while ((uint8_t)h[i]>' ') ++i;
         h[i] = 0; /* item size 3..9 */
         aprsstr_Append(s, s_len, h, 201ul);
         if (typ=='J') aprsstr_Append(s, s_len, "_", 2ul);
         else aprsstr_Append(s, s_len, "!", 2ul);
      }
   }
   else {
      if (X2C_CAP(postyp)=='M') strncpy(h,"`",201u);
      else strncpy(h,"=",201u);
      aprsstr_Append(s, s_len, h, 201ul); /* beacon protocol */
   }
   switch ((unsigned)X2C_CAP(postyp)) {
   case 'M':
      micedata(lat, long0, (uint32_t)knots, (uint32_t)dir, alt, symb,
                2ul, h, 201ul);
      aprsstr_Append(s, s_len, h, 201ul);
      break;
   case 'C':
      if (feet<0L && feet>-10000L) {
         useri_say("\012no negative altitude in compressed mode\012", 42ul,
                20UL, 'e');
         err = 1;
      }
      if ((uint8_t)symb[0U]>='a' && (uint8_t)symb[0U]<='j') {
         useri_say("\012overlay character a..j not in compressed mode\012",
                48ul, 20UL, 'e');
         err = 1;
      }
      if ((uint8_t)symb[0U]>='0' && (uint8_t)symb[0U]<='9') {
         symb[0U] = (char)((uint32_t)(uint8_t)symb[0U]+49UL);
      }
      aprstext_compressdata(pos, (uint32_t)knots, (uint32_t)dir, feet,
                symb, 2ul, h, 201ul);
      aprsstr_Append(s, s_len, h, 201ul);
      break;
   default:;
      deg2str(lat, long0, h, 201ul);
      h[8U] = symb[0U]; /* symbol */
      h[18U] = symb[1U];
      h[19U] = 0;
      aprsstr_Append(s, s_len, h, 201ul);
      if (knots>0L) {
         /* dir, speed */
         speeddir2str(knots, dir, areaobj, h, 201ul);
         aprsstr_Append(s, s_len, h, 201ul);
      }
      if (alt>-10000L) {
         alt2str(feet, h, 201ul);
         aprsstr_Append(s, s_len, h, 201ul);
      }
      break;
   } /* end switch */
   mull = aprsdecode_ismultiline(0);
   /*  IF mull THEN confappend(fRBCOMMENT, s) END;
                (* multiline: append dao at end *) */
   useri_confappend(useri_fRBCOMMENT, s, s_len);
   if (X2C_CAP(postyp)!='C' && (dao || mull)) {
      /* DAO */
      daostr(latd, longd, h, 201ul);
      aprsstr_Append(s, s_len, h, 201ul);
   }
   /*  IF NOT mull THEN confappend(fRBCOMMENT, s) END; */
   *len += aprsstr_Length(s, s_len)-datastart;
   if (err) s[0UL] = 0;
} /* end encbeacon() */


extern void aprstext_BEGIN(void)
{
   static int aprstext_init = 0;
   if (aprstext_init) return;
   aprstext_init = 1;
   useri_BEGIN();
   osi_BEGIN();
   maptool_BEGIN();
   aprsdecode_BEGIN();
   aprsstr_BEGIN();
   aprspos_BEGIN();
}

