Skip to content

Commit

Permalink
SBS1 TCP server for outputting ADS positional information to third-party
Browse files Browse the repository at this point in the history
applications
  • Loading branch information
jontio committed Mar 3, 2016
1 parent f89229f commit 4f23cd2
Show file tree
Hide file tree
Showing 13 changed files with 436 additions and 90 deletions.
8 changes: 6 additions & 2 deletions JAERO/JAERO.pro
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ SOURCES += main.cpp\
../kiss_fft130/kiss_fastfir.c \
burstoqpskdemodulator.cpp \
audioburstoqpskdemodulator.cpp \
arincparse.cpp
arincparse.cpp \
tcpserver.cpp \
sbs1.cpp

HEADERS += mainwindow.h \
coarsefreqestimate.h \
Expand Down Expand Up @@ -77,7 +79,9 @@ HEADERS += mainwindow.h \
../kiss_fft130/kiss_fastfir.h \
burstoqpskdemodulator.h \
audioburstoqpskdemodulator.h \
arincparse.h
arincparse.h \
tcpserver.h \
sbs1.h

FORMS += mainwindow.ui \
gui_classes/settingsdialog.ui \
Expand Down
78 changes: 51 additions & 27 deletions JAERO/arincparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@ qint32 ArincParse::extractqint32(QByteArray &ba,int lsbyteoffset,int bitoffset,i


//returns true if something for the user to read. need to check what is valid on return
bool ArincParse::parseDownlinkmessage(QString &msg)
bool ArincParse::parseDownlinkmessage(ACARSItem &acarsitem)//QString &msg)
{
//qDebug()<<msg;
//qDebug()<<acarsitem.message;

arincmessage.clear();
arincmessage.downlink=true;
arincmessage.downlink=acarsitem.downlink;
downlinkheader.clear();

if(!acarsitem.downlink)return false;
if(acarsitem.nonacars)return false;

//ref 622. 4.3.3 and 745

Expand All @@ -61,25 +63,24 @@ bool ArincParse::parseDownlinkmessage(QString &msg)

//deal with header stuff
//ref 620 & 618
if(msg.size()<10)return false;
if(acarsitem.message.size()<10)return false;
char Originator=-1;
Originator=msg.at(0).toLatin1();
Originator=acarsitem.message.at(0).toLatin1();
downlinkheader.OriginatorString=MetaEnumMessageSourcesIDS.valueToKey(Originator);//the name of the device on the plane that sent the message if anyone is interested
bool ok;
downlinkheader.MessageNumber=msg.mid(1,2).toInt(&ok);
downlinkheader.MessageNumber=acarsitem.message.mid(1,2).toInt(&ok);
if(!ok)return false;
downlinkheader.BlockSequenceCharacter=msg.at(3).toLatin1();
downlinkheader.flightid=msg.mid(4,6);//unsually flight # but not allways
downlinkheader.BlockSequenceCharacter=acarsitem.message.at(3).toLatin1();
downlinkheader.flightid=acarsitem.message.mid(4,6);//unsually flight # but not allways
//remove zero padding in flight id
QRegExp rx("^[A-Z]*(0*)");
int pos = rx.indexIn(downlinkheader.flightid);
if(pos!=-1)downlinkheader.flightid.remove(rx.pos(1),rx.cap(1).size());
rx.setPattern("^[A-Z]*[0-9]*$");
if((downlinkheader.flightid.size()<2)||(!downlinkheader.flightid.contains(rx)))downlinkheader.flightid.clear();//not a flight #
if((downlinkheader.flightid.size()<3)||!downlinkheader.flightid[0].isLetter())downlinkheader.flightid.clear();//lets say not a flight #
downlinkheader.valid=true;

//deal with application section
QStringList sections=msg.split('/');
QStringList sections=acarsitem.message.split('/');
if(sections.size()!=2)return true;

//split up into components as strings
Expand All @@ -97,13 +98,13 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
QString ctraddr=MFI_ctraddr;
if(MFI_ctraddr.contains(' '))//incase MFI is present (H1 label rather than the MFI label) happens when ACARS peripheral created message rather than by an ACARS [C]MU
{
MFI=MFI_ctraddr.section(' ',0,0);
ctraddr=MFI_ctraddr.section(' ',1);
}
arincmessage.IMI=IMI_tailno_appmessage_CRC.left(3);
arincmessage.tailno=IMI_tailno_appmessage_CRC.mid(3,7);
QString appmessage=IMI_tailno_appmessage_CRC.mid(3+7,IMI_tailno_appmessage_CRC.size()-3-7-4);
QString CRC=IMI_tailno_appmessage_CRC.right(4);
MFI=MFI_ctraddr.section(' ',0,0);// eg B6 if there. its not there in this example as the ACARS header would have come with a B6 in the ACARS label
ctraddr=MFI_ctraddr.section(' ',1);// eg AKLCDYA
} else MFI=acarsitem.LABEL;// eg B6
arincmessage.IMI=IMI_tailno_appmessage_CRC.left(3);//eg ADS
arincmessage.tailno=IMI_tailno_appmessage_CRC.mid(3,7);//eg .N705DN
QString appmessage=IMI_tailno_appmessage_CRC.mid(3+7,IMI_tailno_appmessage_CRC.size()-3-7-4);//eg 07EEE19454DAC7D010D21D0DEEEC44556208024029F0588C71D7884D000E13B90F00000F12C1A280001029305F10
QString CRC=IMI_tailno_appmessage_CRC.right(4);//eg 19F4

//qDebug()<<MFI;
//qDebug()<<ctraddr;
Expand All @@ -122,16 +123,20 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
QByteArray adsmessage=arincmessage.IMI.toLatin1()+arincmessage.tailno.toLatin1()+appmessage_bytes;
int crc_calc=crc16.calcusingbytesotherendines(adsmessage.data(),adsmessage.size());

//remove . in reg
arincmessage.tailno.remove('.');

//fail if crc no good
if(crc_rec!=crc_calc)
{
// qDebug()<<"Application CRC failed"<<crc_rec<<crc_calc;
//qDebug()<<"Application CRC failed"<<crc_rec<<crc_calc;
return false;
}
arincmessage.valid=true;

//switch on IMI
bool fail=false;

switch(MetaEnumIMI.keysToValue(arincmessage.IMI.toLatin1()))
{
case ADS:
Expand Down Expand Up @@ -191,8 +196,8 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
//Temperature (arcinc 745 seems to make a mistake with their egampe on this one)
double temperature=((double)extractqint32(appmessage_bytes,i-1+5,1,12,true))*temperature_scaller;

if(truewinddirection_isvalid)arincmessage.info+=middlespacer+((QString)"Wind speed = %1 knots. True wind direction = %2 deg. Temperature = %3 deg C.\n").arg(windspeed).arg(qRound(truewinddirection)).arg(temperature);
else arincmessage.info+=middlespacer+((QString)"Wind speed = %1 knots. Temperature = %2 deg C.\n").arg(windspeed).arg(temperature);
if(truewinddirection_isvalid)arincmessage.info+=middlespacer+((QString)"Wind speed = %1 knots. True wind direction = %2 deg. Temperature = %3 deg C.\n").arg(qRound(windspeed)).arg(qRound(truewinddirection)).arg(temperature);
else arincmessage.info+=middlespacer+((QString)"Wind speed = %1 knots. Temperature = %2 deg C.\n").arg(qRound(windspeed)).arg(temperature);


i+=5;//goto next message
Expand All @@ -212,8 +217,8 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
//Vertical rate
double verticalrate=((double)extractqint32(appmessage_bytes,i-1+6,2,12,true))*verticalrate_scaller;

if(trueheading_isvalid)arincmessage.info+=middlespacer+((QString)"True heading = %1 deg. Mach speed = %2 Vertical rate = %3 fpm.\n").arg(qRound(trueheading)).arg(machspeed).arg(verticalrate);
else arincmessage.info+=middlespacer+((QString)"Mach speed = %1 Vertical rate = %2 fpm.\n").arg(machspeed).arg(verticalrate);
if(trueheading_isvalid)arincmessage.info+=middlespacer+((QString)"True heading = %1 deg. Mach speed = %2 Vertical rate = %3 fpm.\n").arg(qRound(trueheading)).arg(qRound(machspeed*100.0)/100.0).arg(verticalrate);
else arincmessage.info+=middlespacer+((QString)"Mach speed = %1 Vertical rate = %2 fpm.\n").arg(qRound(machspeed*100.0)/100.0).arg(verticalrate);


i+=6;//goto next message
Expand All @@ -234,8 +239,18 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
//Vertical rate
double verticalrate=((double)extractqint32(appmessage_bytes,i-1+6,2,12,true))*verticalrate_scaller;

if(truetrack_isvalid)arincmessage.info+=middlespacer+((QString)"True Track = %1 deg. Ground speed = %2 knots. Vertical rate = %3 fpm.\n").arg(qRound(truetrack)).arg(groundspeed).arg(verticalrate);
else arincmessage.info+=middlespacer+((QString)"Ground speed = %1 knots. Vertical rate = %2 fpm.\n").arg(groundspeed).arg(verticalrate);
if(truetrack_isvalid)arincmessage.info+=middlespacer+((QString)"True Track = %1 deg. Ground speed = %2 knots. Vertical rate = %3 fpm.\n").arg(qRound(truetrack)).arg(qRound(groundspeed)).arg(verticalrate);
else arincmessage.info+=middlespacer+((QString)"Ground speed = %1 knots. Vertical rate = %2 fpm.\n").arg(qRound(groundspeed)).arg(verticalrate);

//send earth reference group to anyone who cares
adownlinkearthreferencegroup.AESID=acarsitem.isuitem.AESID;
adownlinkearthreferencegroup.downlinkheader=downlinkheader;
adownlinkearthreferencegroup.truetrack=truetrack;
adownlinkearthreferencegroup.truetrack_isvalid=truetrack_isvalid;
adownlinkearthreferencegroup.groundspeed=groundspeed;
adownlinkearthreferencegroup.verticalrate=verticalrate;
emit DownlinkEarthReferenceGroupSignal(adownlinkearthreferencegroup);


i+=6;//goto next message
break;
Expand Down Expand Up @@ -304,10 +319,19 @@ bool ArincParse::parseDownlinkmessage(QString &msg)
//FOM
int FOM=((uchar)appmessage_bytes.at(i-1+11))&0x1F;



arincmessage.info+=middlespacer+((QString)"Lat = %1 Long = %2 Alt = %3 feet. Time past the hour = %4 FOM = %5\n").arg(latitude).arg(longitude).arg(altitude).arg(ts_str).arg((((QString)"%1").arg(FOM,2, 16, QChar('0'))).toUpper());

//send a report to anyone who cares
adownlinkbasicreportgroup.AESID=acarsitem.isuitem.AESID;
adownlinkbasicreportgroup.downlinkheader=downlinkheader;
adownlinkbasicreportgroup.messagetype=(ADSDownlinkMessages)appmessage_bytes.at(i);
adownlinkbasicreportgroup.latitude=latitude;
adownlinkbasicreportgroup.longitude=longitude;
adownlinkbasicreportgroup.altitude=altitude;
adownlinkbasicreportgroup.time_stamp=time_stamp;
adownlinkbasicreportgroup.FOM=FOM;
emit DownlinkBasicReportGroupSignal(adownlinkbasicreportgroup);

i+=11;//goto next message
break;
}
Expand Down
125 changes: 87 additions & 38 deletions JAERO/arincparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@
#include <QBitArray>
#include <QtMath>


#define lat_scaller 0.000171661376953125
#define long_scaller 0.000171661376953125
#define alt_scaller 4.0
#define time_scaller 0.125
#define truetrack_scaller 0.087890625
#define trueheading_scaller 0.087890625
#define groundspeed_scaller 0.5
#define machspeed_scaller 0.0005
#define verticalrate_scaller 16
#define windspeed_scaller 0.5
#define truewinddirection_scaller 0.703125
#define temperature_scaller 0.25
#define distance_scaller 0.125

struct DownlinkHeader
{
Expand Down Expand Up @@ -44,52 +56,82 @@ struct ArincMessage
}
};

typedef enum ADSDownlinkMessages {
Acknowledgement=3,
Negative_Acknowledgement=4,
Noncompliance_Notification=5,
Cancel_Emergency_Mode=6,
Basic_Report=7,
Emergency_Basic_Report=9,
Lateral_Deviation_Change_Event=10,
Flight_Identification_Group=12,
Predicted_Route_Group=13,
Earth_Reference_Group=14,
Air_Reference_Group=15,
Meteorological_Group=16,
Airframe_Identification_Group=17,
Vertical_Rate_Change_Event=18,
Altitude_Range_Event=19,
Waypoint_Change_Event=20,
Intermediate_Projected_Intent_Group=22,
Fixed_Projected_Intent_Group=23
} ADSDownlinkMessages;


struct DownlinkBasicReportGroup
{
//Message type
ADSDownlinkMessages messagetype;
//AES
quint32 AESID;
//Downlink header
DownlinkHeader downlinkheader;
//Lat
double latitude;
//Long
double longitude;
//Alt
double altitude;
//Time stamp
double time_stamp;
//FOM
int FOM;
};

struct DownlinkEarthReferenceGroup
{
//AES
quint32 AESID;
//Downlink header
DownlinkHeader downlinkheader;
//True track is valid
bool truetrack_isvalid;
//True track
double truetrack;
//Ground speed
double groundspeed;
//Vertical rate
double verticalrate;
};


class ArincParse : public QObject
{
#define lat_scaller 0.000171661376953125
#define long_scaller 0.000171661376953125
#define alt_scaller 4.0
#define time_scaller 0.125
#define truetrack_scaller 0.087890625
#define trueheading_scaller 0.087890625
#define groundspeed_scaller 0.5
#define machspeed_scaller 0.0005
#define verticalrate_scaller 16
#define windspeed_scaller 0.5
#define truewinddirection_scaller 0.703125
#define temperature_scaller 0.25
#define distance_scaller 0.125
Q_OBJECT
Q_ENUMS(IMIEnum)
Q_ENUMS(MessageSourcesIDS)
public:
enum IMIEnum {

typedef enum IMIEnum {
ADS,
AT1,
DR1,
CC1
} IMIEnum;
enum ADSDownlinkMessages {
Acknowledgement=3,
Negative_Acknowledgement=4,
Noncompliance_Notification=5,
Cancel_Emergency_Mode=6,
Basic_Report=7,
Emergency_Basic_Report=9,
Lateral_Deviation_Change_Event=10,
Flight_Identification_Group=12,
Predicted_Route_Group=13,
Earth_Reference_Group=14,
Air_Reference_Group=15,
Meteorological_Group=16,
Airframe_Identification_Group=17,
Vertical_Rate_Change_Event=18,
Altitude_Range_Event=19,
Waypoint_Change_Event=20,
Intermediate_Projected_Intent_Group=22,
Fixed_Projected_Intent_Group=23
} ADSDownlinkMessages;
enum MessageSourcesIDS {



typedef enum MessageSourcesIDS {
CFDIU='C',
DFDAU='D',
FMC='F',
Expand All @@ -111,14 +153,17 @@ class ArincParse : public QObject
ATSU_ADSU='J',
HF_Data_Radio='T'
} MessageSourcesIDS;


explicit ArincParse(QObject *parent = 0);
bool parseDownlinkmessage(QString &msg);
bool parseDownlinkmessage(ACARSItem &acarsitem);//QString &msg);

ArincMessage arincmessage;
DownlinkHeader downlinkheader;

signals:

void DownlinkBasicReportGroupSignal(DownlinkBasicReportGroup &message);
void DownlinkEarthReferenceGroupSignal(DownlinkEarthReferenceGroup &message);
public slots:
private:
QBitArray &tobits(QByteArray &bytes);
Expand All @@ -129,6 +174,10 @@ public slots:
QBitArray bitarray;
qint32 extractqint32(QByteArray &ba, int lsbyteoffset, int bitoffset, int numberofbits, bool issigned);
QString middlespacer;
DownlinkBasicReportGroup adownlinkbasicreportgroup;
DownlinkEarthReferenceGroup adownlinkearthreferencegroup;
};



#endif // ARINCPARSE_H
2 changes: 1 addition & 1 deletion JAERO/gui_classes/planelog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ void PlaneLog::ACARSslot(ACARSItem &acarsitem)
message.replace("\n\n","\n");
if(message.right(1)=="\n")message.chop(1);
if(message.left(1)=="\n")message.remove(0,1);
if((!acarsitem.nonacars)&&(acarsitem.downlink))arincparser.parseDownlinkmessage(message);//if we are on a downlink then process downlink message
arincparser.parseDownlinkmessage(acarsitem);
message.replace('\n',"");//● instead of \n\t

QByteArray TAKstr;
Expand Down
Loading

0 comments on commit 4f23cd2

Please sign in to comment.