There are several key pieces of information displayed and there are some subtleties. This is a list of the data displayed and a key to try to understand it.
int IntDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, UINT Mask, BOOL APRS)
{
UCHAR * ptr;
int n;
MESSAGE * ADJBUFFER;
UINT Work;
UCHAR CTL;
BOOL PF = 0;
char CRCHAR[3] = " ";
char PFCHAR[3] = " ";
int Port;
int MSGFLAG = 0; //CR and V1 flags
char * Output = buffer;
int HH, MM, SS;
char TR = 'R';
char From[10], To[10];
BOOL Info = 0;
BOOL FRMRFLAG = 0;
int MsgLen = msg->LENGTH;
// GET THE CONTROL BYTE, TO SEE IF THIS FRAME IS TO BE DISPLAYED
n = 8; // MAX DIGIS
ptr = &msg->ORIGIN[6]; // End of Address bit
while ((*ptr & 1) == 0)
{
// MORE TO COME
ptr += 7;
n--;
if (n == 0)
{
return 0; // Corrupt - no end of address bit
}
}
// Reached End of digis
Work = (UINT)&msg->ORIGIN[6];
ptr -= Work; // ptr is now length of digis
MsgLen -= (UINT)ptr;
Work = (UINT)msg;
ptr += Work;
ADJBUFFER = (MESSAGE * )ptr; // ADJBUFFER points to CTL, etc. allowing for digis
CTL = ADJBUFFER->CTL;
if (CTL & PFBIT)
PF = TRUE;
CTL &= ~PFBIT;
if (MUIONLY)
if (CTL != 3)
return 0;
if ((CTL & 1) == 0 || CTL == FRMR || CTL == 3)
{
}
else
{
if (MCOM == 0)
return 0; // Dont do control
}
Port = msg->PORT;
if (Port & 0x80)
{
if (MTX == 0)
return 0; // TRANSMITTED FRAME - SEE IF MTX ON
TR = 'T';
}
Port &= 0x7F;
if (((1 << (Port - 1)) & Mask) == 0) // Check MMASK
return 0;
Stamp = Stamp % 86400; // Secs
HH = Stamp / 3600;
Stamp -= HH * 3600;
MM = Stamp / 60;
SS = Stamp - MM * 60;
Output += sprintf(Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR);
From[ConvFromAX25(msg->ORIGIN, From)] = 0;
To[ConvFromAX25(msg->DEST, To)] = 0;
Output += sprintf(Output, "%s>%s", From, To);
// Display any Digi-Peaters
n = 8; // Max number of digi-peaters
ptr = &msg->ORIGIN[6]; // End of Address bit
while ((*ptr & 1) == 0)
{
// MORE TO COME
From[ConvFromAX25(ptr + 1, From)] = 0;
Output += sprintf(Output, ",%s", From);
ptr += 7;
n--;
if (n == 0)
break;
// See if digi actioned - put a * on last actioned
if (*ptr & 0x80)
{
if (*ptr & 1) // if last address, must need *
*(Output++) = '*';
else
if ((ptr[7] & 0x80) == 0) // Repeased by next?
*(Output++) = '*'; // No, so need *
}
}
Output += sprintf(Output, " Port=%d ", Port);
// Set up CR and PF
CRCHAR[0] = 0;
PFCHAR[0] = 0;
if (msg->DEST[6] & 0x80)
{
if (msg->ORIGIN[6] & 0x80) // Both set, assume V1
MSGFLAG |= VER1;
else
{
MSGFLAG |= CMDBIT;
CRCHAR[0] = ' ';
CRCHAR[1] = 'C';
if (PF) // If FP set
{
PFCHAR[0] = ' ';
PFCHAR[1] = 'P';
}
}
}
else
{
if (msg->ORIGIN[6] & 0x80) // Only Origin Set
{
MSGFLAG |= RESP;
CRCHAR[0] = ' ';
CRCHAR[1] = 'R';
if (PF) // If FP set
{
PFCHAR[0] = ' ';
PFCHAR[1] = 'F';
}
}
else
MSGFLAG |= VER1; // Neither, assume V1
}
if ((CTL & 1) == 0) // I frame
{
int NS = (CTL >> 1) & 7; // ISOLATE RECEIVED N(S)
int NR = (CTL >> 5) & 7;
Info = 1;
Output += sprintf(Output, "", CRCHAR, PFCHAR, NS, NR);
}
else if (CTL == 3)
{
// Un-numbered Information Frame
Output += sprintf(Output, "", CRCHAR);
Info = 1;
}
else if (CTL & 2)
{
// UN Numbered
char SUP[5] = "??";
switch (CTL)
{
case SABM:
strcpy(SUP, "C");
break;
case DISC:
strcpy(SUP, "D");
break;
case DM:
strcpy(SUP, "DM");
break;
case UA:
strcpy(SUP, "UA");
break;
case FRMR:
strcpy(SUP, "FRMR");
FRMRFLAG = 1;
break;
}
Output += sprintf(Output, "<%s%s%s>", SUP, CRCHAR, PFCHAR);
}
else
{
// Super
int NR = (CTL >> 5) & 7;
char SUP[4] = "??";
switch (CTL & 0x0F)
{
case RR:
strcpy(SUP, "RR");
break;
case RNR:
strcpy(SUP, "RNR");
break;
case REJ:
strcpy(SUP, "REJ");
break;
}
Output += sprintf(Output, "<%s%s%s R%d>", SUP, CRCHAR, PFCHAR, NR);
}
if (FRMRFLAG)
Output += sprintf(Output, " %02X %02X %02X", ADJBUFFER->PID, ADJBUFFER->L2DATA[0], ADJBUFFER->L2DATA[1]);
if (Info)
{
// We have an info frame
switch (ADJBUFFER->PID)
{
case 0xF0: // Normal Data
{
char Infofield[257];
char * ptr1 = Infofield;
char * ptr2 = ADJBUFFER->L2DATA;
UCHAR C;
int len;
MsgLen = MsgLen - 23;
if (MsgLen < 0 || MsgLen > 257)
return 0; // Duff
while (MsgLen--)
{
C = *(ptr2++);
if (APRS)
*(ptr1++) = C; // MIC-E needs all chars
else
{
// Convert to printable
C &= 0x7F;
if (C == 13 || C == 10 || C > 31)
*(ptr1++) = C;
}
}
len = ptr1 - Infofield;
Output[0] = ':';
Output[1] = 13;
memcpy(&Output[2], Infofield, len);
Output += (len + 2);
break;
}
case NETROM_PID:
Output = DISPLAY_NETROM(ADJBUFFER, Output, MsgLen);
break;
case IP_PID:
Output += sprintf(Output, " \r");
Output = DISPLAYIPDATAGRAM((IPMSG *)&ADJBUFFER->L2DATA[0], Output, MsgLen);
break;
case ARP_PID:
Output = DISPLAYARPDATAGRAM(&ADJBUFFER->L2DATA[0], Output);
break;
case 8: // Fragmented IP
Output += sprintf(Output, "");
break;
}
}
if (Output[-1] != 13)
Output += sprintf(Output, "\r");
return Output - buffer;
}
// Display NET/ROM data
char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
{
char Alias[7]= "";
char Dest[10];
char Node[10];
UCHAR TTL, Index, ID, TXNO, RXNO, OpCode, Flags, Window;
UCHAR * ptr = &ADJBUFFER->L2DATA[0];
if (ADJBUFFER->L2DATA[0] == NODES_SIG)
{
// Display NODES
// If an INP3 RIF (type <> UI) decode as such
if (ADJBUFFER->CTL != 3) // UI
return DisplayINP3RIF(&ADJBUFFER->L2DATA[1], Output, MsgLen - 24);
memcpy(Alias, ++ptr, 6);
ptr += 6;
Output += sprintf(Output, " NODES broadcast from %s\r", Alias);
MsgLen -= 30; //Header, mnemonic and signature length
while(MsgLen > 20) // Entries are 21 bytes
{
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
memcpy(Alias, ptr, 6);
ptr +=6;
strlop(Alias, ' ');
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
Output += sprintf(Output, " %s:%s via %s qlty=%d\r", Alias, Dest, Node, ptr[0]);
ptr++;
MsgLen -= 21;
}
return Output;
}
// Display normal NET/ROM transmissions
Output += sprintf(Output, " NET/ROM\r ", Alias);
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
TTL = *(ptr++);
Index = *(ptr++);
ID = *(ptr++);
TXNO = *(ptr++);
RXNO = *(ptr++);
OpCode = Flags = *(ptr++);
OpCode &= 15; // Remove Flags
Output += sprintf(Output, "%s to %s ttl %d cct=%02X%02X ", Dest, Node, TTL, Index, ID );
MsgLen -= 20;
switch (OpCode)
{
case L4CREQ:
Window = *(ptr++);
Dest[ConvFromAX25(ptr, Dest)] = 0;
ptr +=7;
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
Output += sprintf(Output, " w=%d %s at %s", Window, Dest, Node);
if (MsgLen > 38) // BPQ Extended Params
{
short Timeout = (SHORT)*ptr;
Output += sprintf(Output, " t/o %d", Timeout);
}
return Output;
case L4CACK:
if (Flags & L4BUSY) // BUSY RETURNED
return Output + sprintf(Output, " - BUSY");
return Output + sprintf(Output, " w=%d my cct=%02X%02X", ptr[1], TXNO, RXNO);
case L4DREQ:
return Output + sprintf(Output, " ");
case L4DACK:
return Output + sprintf(Output, " ");
case L4INFO:
{
char Infofield[257];
char * ptr1 = Infofield;
UCHAR C;
int len;
Output += sprintf(Output, " ", TXNO, RXNO);
if (Flags & L4BUSY)
*(Output++) = 'B';
if (Flags & L4NAK)
*(Output++) = 'N';
if (Flags & L4MORE)
*(Output++) = 'M';
MsgLen = MsgLen - 23;
if (MsgLen < 0 || MsgLen > 257)
return Output; // Duff
while (MsgLen--)
{
C = *(ptr++);
// Convert to printable
C &= 0x7F;
if (C == 13 || C == 10 || C > 31)
*(ptr1++) = C;
}
len = ptr1 - Infofield;
Output[0] = ':';
Output[1] = 13;
memcpy(&Output[2], Infofield, len);
Output += (len + 2);
}
return Output;
case L4IACK:
Output += sprintf(Output, " ", RXNO);
if (Flags & L4BUSY)
*(Output++) = 'B';
if (Flags & L4NAK)
*(Output++) = 'N';
if (Flags & L4MORE)
*(Output++) = 'M';
return Output;
case 0:
// OPcode zero is used for several things
if (Index == 0x0c && ID == 0x0c) // IP
{
// Output = L3IP(Output);
return Output;
}
if (Index == 0 && ID == 1) // NRR
{
Output += sprintf(Output, " \r");
MsgLen -= 23;
while (MsgLen > 6)
{
Dest[ConvFromAX25(ptr, Dest)] = 0;
if (ptr[7] & 0x80)
Output += sprintf(Output, "%s* ", Dest);
else
Output += sprintf(Output, "%s ", Dest);
ptr +=8;
MsgLen -= 8;
}
return Output;
}
}
Output += sprintf(Output, " ??\?>");
return Output;
}