874 lines
25 KiB
C++
874 lines
25 KiB
C++
|
|
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2017, University in Hagen,
|
|
Faculty of Mathematics and Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
|
|
*/
|
|
|
|
#include "aisdecode.h"
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <set>
|
|
#include <stdlib.h>
|
|
#include <bitset>
|
|
#include <vector>
|
|
#include <assert.h>
|
|
#include <map>
|
|
#include <stdint.h>
|
|
#include <algorithm>
|
|
|
|
|
|
namespace aisdecode{
|
|
|
|
|
|
/*
|
|
1 Auxiliary functions
|
|
|
|
|
|
*/
|
|
|
|
const char chartbl[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"[\\]^- !\"#$%&`()*+,-./0123456789:;<=>?";
|
|
|
|
void trim(std::string& str, std::string whiteSpaces=" \r\n\t") {
|
|
std::string::size_type pos = str.find_last_not_of(whiteSpaces);
|
|
if(pos != std::string::npos) {
|
|
str.erase(pos + 1);
|
|
pos = str.find_first_not_of(whiteSpaces);
|
|
if(pos != std::string::npos){
|
|
str.erase(0, pos);
|
|
}
|
|
} else {
|
|
str.erase(str.begin(), str.end());
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
2 Implementation of class Message
|
|
|
|
*/
|
|
|
|
template<int size>
|
|
void Message<size>::setMessage(const std::string& _msg){
|
|
msg = _msg;
|
|
size_t ssize = getStringSize();
|
|
if(msg.size() < ssize){
|
|
std::cerr << "expected minimum size is " << ssize << std::endl;
|
|
std::cerr << "got message of length " << msg.length() << std::endl;
|
|
throw 1001;
|
|
}
|
|
createMsg();
|
|
}
|
|
|
|
|
|
template<int size>
|
|
void Message<size>::createMsg(){
|
|
int s = getStringSize();
|
|
for(int i=0;i<s;i++){
|
|
unsigned long c = msg[i];
|
|
c = c - '0';
|
|
if(c>40) c = c - 8;
|
|
message = (message << 6);
|
|
message |= std::bitset<size>((unsigned long)c);
|
|
}
|
|
}
|
|
|
|
|
|
template<int size>
|
|
std::string Message<size>::extractString(int start, int end) const{
|
|
std::bitset<size> b = ((message >> (size - (end+1) ) ));
|
|
int len = (end - start) +1;
|
|
assert(len % 6 == 0); // must be a multiple of 6
|
|
len = len / 6; // number of chars
|
|
std::string chars(len,'@');
|
|
static std::bitset<size> mask(std::string("111111"));
|
|
for(int i=0;i<len;i++){
|
|
unsigned char c = (char)((b & mask).to_ulong());
|
|
assert(c<0xf3);
|
|
chars[len-(i+1)] = chartbl[c];
|
|
b = (b >> 6);
|
|
}
|
|
std::replace(chars.begin(), chars.end(),'@',' ');
|
|
trim(chars);
|
|
return chars;
|
|
}
|
|
|
|
|
|
|
|
template<int size>
|
|
double Message<size>::computeLat(unsigned int rlat) const{
|
|
if(rlat == 0x3412140){ // special value for nbot available
|
|
return 91;
|
|
}
|
|
int lat = rlat;
|
|
if(rlat >= 0x4000000){
|
|
lat = 0x8000000 - rlat;
|
|
lat = -lat;
|
|
}
|
|
return lat/600000.0;
|
|
}
|
|
|
|
template<int size>
|
|
double Message<size>::computeLon(unsigned int rlon) const{
|
|
if(rlon == 0x6791AC0){ // special value
|
|
return 181;
|
|
}
|
|
int lon = rlon;
|
|
if(rlon >= 0x8000000){
|
|
lon = 0x10000000 - rlon;
|
|
lon = -lon;
|
|
}
|
|
return lon / 600000.0;
|
|
}
|
|
|
|
template<int size>
|
|
std::string Message<size>::decodeText(const std::string& text) const{
|
|
std::string text2(text.length(),'@');
|
|
for(size_t i=0;i<text.length();i++){
|
|
char c = text[i] - '0';
|
|
if(c>40) c = c-8;
|
|
text2[i] = chartbl[(int)c];
|
|
}
|
|
return text2;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
3 Implementation of MultiLineMessage
|
|
|
|
*/
|
|
|
|
MultiLineMessage::MultiLineMessage(int fragmentcount, int fragmentnumber,
|
|
const std::string& fragment,
|
|
int messageId, const std::string& rcc){
|
|
for(int i=0;i<fragmentcount;i++){
|
|
fragments.push_back("");
|
|
}
|
|
fragments[fragmentnumber-1] = fragment;
|
|
fragmentsAvailable = 1;
|
|
this->message_Id = messageId;
|
|
this->rcc = rcc;
|
|
}
|
|
|
|
void MultiLineMessage::add(int fragmentcount, int fragmentnumber,
|
|
const std::string& fragment,
|
|
int messageId, const std::string& rcc){
|
|
if( ((size_t) fragmentcount != fragments.size())
|
|
|| (fragmentnumber < 1)
|
|
|| ((size_t) fragmentnumber > fragments.size())
|
|
|| (fragments[fragmentnumber-1] !="")
|
|
|| (this->rcc != rcc) ){
|
|
throw 1002;
|
|
}
|
|
fragments[fragmentnumber-1] = fragment;
|
|
fragmentsAvailable++;
|
|
|
|
}
|
|
|
|
|
|
std::string MultiLineMessage::getMessage() const{
|
|
assert(isComplete());
|
|
std::stringstream ss;
|
|
for(size_t i=0;i<fragments.size();i++){
|
|
ss << fragments[i];
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
/*
|
|
4 Message1-3
|
|
|
|
*/
|
|
void Message1_3::print()const{
|
|
std::cout << "-----------------------------------------------" << std::endl;
|
|
std::cout << "messagetype " << messageType << std::endl;
|
|
std::cout << "repeatIndicator " << repeatIndicator << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "status " << status << std::endl;
|
|
std::cout << "rate of turn " << rot << std::endl;
|
|
std::cout << "speed over ground " << sog << std::endl;
|
|
std::cout << "accuracy " << accuracy << std::endl;
|
|
std::cout << "longitude " << longitude << std::endl;
|
|
std::cout << "latitude " << latitude << std::endl;
|
|
std::cout << "course over ground " << cog << std::endl;
|
|
std::cout << "heading " << heading << std::endl;
|
|
std::cout << "second " << second << std::endl;
|
|
std::cout << "maneuver " << maneuver << std::endl;
|
|
std::cout << "spare " << spare << std::endl;
|
|
std::cout << "raim " << raim << std::endl;
|
|
std::cout << "radio status " << rstatus << std::endl;
|
|
if(msg.length()>28){
|
|
std::cout << "more information available " << std::endl;
|
|
}
|
|
std::cout << "----------------------------------------------" << std::endl;
|
|
}
|
|
|
|
|
|
void Message1_3::extractInfos(){
|
|
messageType = extract(0,5);
|
|
repeatIndicator = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
status = extract(38,41);
|
|
rot = extract(42,49);
|
|
sog = extract(50,59);
|
|
accuracy = extract(60,60);
|
|
unsigned int lon = extract(61,88);
|
|
longitude = computeLon(lon);
|
|
unsigned int lat = extract(89,115);
|
|
latitude = computeLat(lat);
|
|
cog = extract(116,127);
|
|
heading = extract(128,136);
|
|
second = extract(137,142);
|
|
maneuver = extract(143,144);
|
|
spare = extract(145,147);
|
|
raim = extract(148,148);
|
|
rstatus = extract(149,167);
|
|
}
|
|
|
|
|
|
/*
|
|
4 Message4
|
|
|
|
*/
|
|
|
|
|
|
void Message4::print()const{
|
|
std::cout << "--------------------------------------------" << std::endl;
|
|
std::cout << "type " << type << std::endl;
|
|
std::cout << "repeat " << repeat << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "year " << year << std::endl;
|
|
std::cout << "month " << month << std::endl;
|
|
std::cout << "day " << day << std::endl;
|
|
std::cout << "hour " << hour << std::endl;
|
|
std::cout << "minute " << minute << std::endl;
|
|
std::cout << "second " << second << std::endl;
|
|
std::cout << "fix " << fix << std::endl;
|
|
std::cout << "longitude " << (longitude / 600000.0) << std::endl;
|
|
std::cout << "latitude " << (latitude / 600000.0) << std::endl;
|
|
std::cout << "epfd " << epfd << std::endl;
|
|
std::cout << "spare " << spare << std::endl;
|
|
std::cout << "raim " << raim << std::endl;
|
|
std::cout << "sotdma " << sotdma << std::endl;
|
|
if(msg.length()>28){
|
|
std::cout << "more information available " << std::endl;
|
|
}
|
|
std::cout << "--------------------------------------------" << std::endl;
|
|
}
|
|
|
|
void Message4::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
year = extract(38,51);
|
|
month = extract(52,55);
|
|
day = extract(56,60);
|
|
hour = extract(61,65);
|
|
minute = extract(66,71);
|
|
second = extract(72,77);
|
|
fix = extract(78,78);
|
|
longitude = computeLon(extract(79,106));
|
|
latitude = computeLat(extract(107,133));
|
|
epfd = extract(134,137);
|
|
spare = extract(138,147);
|
|
raim = extract(148,148);
|
|
sotdma = extract(149,167);
|
|
assert(type==4);
|
|
}
|
|
|
|
/*
|
|
5 Message5
|
|
|
|
*/
|
|
|
|
void Message5::print() const{
|
|
std::cout << "--------------------------------------" << std::endl;
|
|
std::cout << "type : " << type << std::endl;
|
|
std::cout << "repeat : " << repeat << std::endl;
|
|
std::cout << "mmsi :" << mmsi << std::endl;
|
|
std::cout << "ais_version " << ais_version << std::endl;
|
|
std::cout << "imo " << imo << std::endl;
|
|
std::cout << "callSign " << callSign << std::endl;
|
|
std::cout << "vesselName " << vesselName << std::endl;
|
|
std::cout << "shiptype " << shipType << std::endl;
|
|
std::cout << "dimToBow " << dimToBow << std::endl;
|
|
std::cout << "dimToStern " << dimToStern << std::endl;
|
|
std::cout << "dimToPort " << dimToPort << std::endl;
|
|
std::cout << "dimToStarboard" << dimToStarboard << std::endl;
|
|
std::cout << "epfd " << epfd << std::endl;
|
|
std::cout << "month " << month << std::endl;
|
|
std::cout << "day " << day << std::endl;
|
|
std::cout << "hour " << hour << std::endl;
|
|
std::cout << "minute " << minute << std::endl;
|
|
std::cout << "draught " << draught << std::endl;
|
|
std::cout << "destination " << destination << std::endl;
|
|
std::cout << "dte " << dte << std::endl;
|
|
std::cout << "--------------------------------------" << std::endl;
|
|
}
|
|
|
|
void Message5::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
ais_version = extract(38,39);
|
|
imo = extract(40,69);
|
|
callSign = extractString(70,111);
|
|
vesselName = extractString(112,231);
|
|
shipType = extract(232,239);
|
|
dimToBow = extract(240,248);
|
|
dimToStern = extract(249,257);
|
|
dimToPort = extract(258,263);
|
|
dimToStarboard = extract(264,269);
|
|
epfd = extract(270,273);
|
|
month = extract(274,277);
|
|
day = extract(278,282);
|
|
hour = extract(283,287);
|
|
minute = extract(288,293);
|
|
draught = extract(294,301);
|
|
destination = extractString(302,421);
|
|
dte = extract(422,422);
|
|
assert(type==5);
|
|
}
|
|
|
|
|
|
/*
|
|
6 Message9
|
|
|
|
*/
|
|
void Message9::print()const{
|
|
std::cout << "type " << type << std::endl;
|
|
std::cout << "repeat " << repeat << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "alt " << alt << std::endl;
|
|
std::cout << "sog " << sog << std::endl;
|
|
std::cout << "accuracy " << accuracy << std::endl;
|
|
std::cout << "longitude " << longitude << std::endl;
|
|
std::cout << "latitude " << latitude << std::endl;
|
|
std::cout << "cog " << cog << std::endl;
|
|
std::cout << "second " << second << std::endl;
|
|
std::cout << "reserved " << reserved << std::endl;
|
|
std::cout << "dte " << dte << std::endl;
|
|
std::cout << "assigned " << assigned << std::endl;
|
|
std::cout << "raim " << raim << std::endl;
|
|
std::cout << "radio " << radio << std::endl;
|
|
}
|
|
|
|
|
|
void Message9::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(30,37);
|
|
alt = extract(38,49);
|
|
sog = extract(50,59);
|
|
accuracy = extract(60,60);
|
|
longitude = computeLon(extract(61,88));
|
|
latitude = computeLat(extract(89,115));
|
|
cog = extract(116,127);
|
|
second = extract(128,133);
|
|
reserved = extract(134,141);
|
|
dte = extract(142,142);
|
|
assigned = extract(146,146);
|
|
raim = extract(147,147);
|
|
radio = extract(148,167);
|
|
assert(type==9);
|
|
}
|
|
|
|
/*
|
|
8 Message12
|
|
|
|
*/
|
|
void Message12::print()const{
|
|
std::cout << "-----------------------------------" << std::endl;
|
|
std::cout << "type " << type << std::endl;
|
|
std::cout << "repeat " << repeat << std::endl;
|
|
std::cout << "source " << source_mmsi << std::endl;
|
|
std::cout << "sequence number " << sequence_number << std::endl;
|
|
std::cout << "dest " <<dest_mmsi << std::endl;
|
|
std::cout << "retransmit " << retransmit << std::endl;
|
|
std::cout << "text " << text << std::endl;
|
|
std::cout << "-----------------------------------" << std::endl;
|
|
}
|
|
|
|
void Message12::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
source_mmsi = extract(8,37);
|
|
sequence_number = extract(38,39);
|
|
dest_mmsi = extract(40,69);
|
|
retransmit = extract(70,70);
|
|
text = decodeText(omsg.substr(12));
|
|
assert(type==12);
|
|
}
|
|
|
|
|
|
/*
|
|
9 Message14
|
|
|
|
*/
|
|
|
|
void Message14::print()const{
|
|
std::cout << "---------------------------------" << std::endl;
|
|
std::cout << " type " << type << std::endl;
|
|
std::cout << " repeat " << repeat << std::endl;
|
|
std::cout << " mmsi " << mmsi << std::endl;
|
|
std::cout << " text " << text << std::endl;
|
|
std::cout << "---------------------------------" << std::endl;
|
|
}
|
|
|
|
void Message14::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
//std::cout << "tbit = " << tbit << std::endl;
|
|
text = extractString(40,1007-2);
|
|
int textlength = omsg.length() - 8;
|
|
text = text.substr(0,textlength);
|
|
assert(type==14);
|
|
}
|
|
|
|
|
|
/*
|
|
10 Message18
|
|
|
|
*/
|
|
|
|
void Message18::print()const{
|
|
std::cout << "type " << type << std::endl;
|
|
std::cout << "repeat " << repeat << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "reserved1 " << reserved1 << std::endl;
|
|
std::cout << "sog " << sog << std::endl;
|
|
std::cout << "accuracy " << accuracy << std::endl;
|
|
std::cout << "longitude " << longitude << std::endl;
|
|
std::cout << "latitude " << latitude << std::endl;
|
|
std::cout << "cog " << cog << std::endl;
|
|
std::cout << "heading " << heading << std::endl;
|
|
std::cout << "second " << second << std::endl;
|
|
std::cout << "reserved2 " << reserved2 << std::endl;
|
|
std::cout << "cs " << cs << std::endl;
|
|
std::cout << "display " << display << std::endl;
|
|
std::cout << "dsc " << dsc << std::endl;
|
|
std::cout << "band " << band << std::endl;
|
|
std::cout << "msg22 " << msg22 << std::endl;
|
|
std::cout << "assigned " << assigned << std::endl;
|
|
std::cout << "raim " << raim << std::endl;
|
|
std::cout << "radio " << radio << std::endl;
|
|
}
|
|
|
|
|
|
void Message18::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
reserved1 = extract(38,45);
|
|
sog = extract(46,55);
|
|
accuracy = extract(56,56);
|
|
longitude = computeLon(extract(57,84));
|
|
latitude = computeLat(extract(85,111));
|
|
cog = extract(112,123);
|
|
heading = extract(124,132);
|
|
second = extract(133,138);
|
|
reserved2 = extract(139,140);
|
|
cs = extract(141,141);
|
|
display = extract(142,142);
|
|
dsc = extract(143,143);
|
|
band = extract(144,144);
|
|
msg22 = extract(145,145);
|
|
assigned = extract(146,146);
|
|
raim = extract(147,147);
|
|
radio = extract(148,167);
|
|
assert(type==18);
|
|
}
|
|
|
|
|
|
/*
|
|
11 Message19
|
|
|
|
*/
|
|
|
|
void Message19::print()const{
|
|
std::cout << "type" << type << std::endl;
|
|
std::cout << "repeat" << repeat << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "reserved " << reserved << std::endl;
|
|
std::cout << "sog " << sog << std::endl;
|
|
std::cout << "accuracy " << accuracy << std::endl;
|
|
std::cout << "longitude " << longitude << std::endl;
|
|
std::cout << "latitude " << latitude << std::endl;
|
|
std::cout << "cog " << cog << std::endl;
|
|
std::cout << "heading " << heading << std::endl;
|
|
std::cout << "second " << second << std::endl;
|
|
std::cout << "reserved2 " << reserved2 << std::endl;
|
|
std::cout << "name " << name << std::endl;
|
|
std::cout << "shiptype " << shiptype << std::endl;
|
|
std::cout << "dimToBow " << dimToBow << std::endl;
|
|
std::cout << "dimToStern " << dimToStern << std::endl;
|
|
std::cout << "dimToPort " << dimToPort << std::endl;
|
|
std::cout << "dimToStarboard " << dimToStarboard << std::endl;
|
|
std::cout << "epfd " << epfd << std::endl;
|
|
std::cout << "raim " << raim << std::endl;
|
|
std::cout << "dte " << dte << std::endl;
|
|
std::cout << "assigned " << assigned << std::endl;
|
|
}
|
|
|
|
void Message19::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
reserved = extract(38,45);
|
|
sog = extract(46,55);
|
|
accuracy = extract(56,56);
|
|
longitude = computeLon(extract(57,84));
|
|
latitude = computeLat(extract(85,111));
|
|
cog = extract(112,123);
|
|
heading = extract(124,132);
|
|
second = extract(133,138);
|
|
reserved2 = extract(139,142);
|
|
name = extractString(143,262);
|
|
shiptype = extract(263,270);
|
|
dimToBow = extract(271,279);
|
|
dimToStern = extract(280,288);
|
|
dimToPort = extract(289,294);
|
|
dimToStarboard = extract(295,300);
|
|
epfd = extract(301,304);
|
|
raim = extract(305,305);
|
|
dte = extract(306,306);
|
|
assigned = extract(307,307);
|
|
assert(type==19);
|
|
}
|
|
|
|
/*
|
|
13 Message24
|
|
|
|
*/
|
|
void Message24::print()const{
|
|
std::cout << "type " << type << std::endl;
|
|
std::cout << "repeat " << repeat << std::endl;
|
|
std::cout << "mmsi " << mmsi << std::endl;
|
|
std::cout << "partno " << partno << std::endl;
|
|
std::cout << "shipsname " << shipsname << std::endl;
|
|
std::cout << "shiptype " << shiptype << std::endl;
|
|
std::cout << "vendorid " << vendorid << std::endl;
|
|
std::cout << "model " << model << std::endl;
|
|
std::cout << "serial " << serial << std::endl;
|
|
std::cout << "callsign " << callsign << std::endl;
|
|
std::cout << "dimToBow " << dimToBow << std::endl;
|
|
std::cout << "dimToStern " << dimToStern << std::endl;
|
|
std::cout << "dimToPort " << dimToPort << std::endl;
|
|
std::cout << "dimToStarboard " << dimToStarboard << std::endl;
|
|
std::cout << "mothership_mmsi " << mothership_mmsi << std::endl;
|
|
}
|
|
|
|
void Message24::extractInfos(){
|
|
type = extract(0,5);
|
|
repeat = extract(6,7);
|
|
mmsi = extract(8,37);
|
|
partno = extract(38,39);
|
|
shipsname = extractString(40,159);
|
|
shiptype = extract(40,47);
|
|
vendorid = extract(48,65);
|
|
model = extract(66,69);
|
|
serial = extract(70,89);
|
|
callsign = extractString(90,131);
|
|
dimToBow = extract(132,140);
|
|
dimToStern = extract(141,149);
|
|
dimToPort = extract(150,155);
|
|
dimToStarboard = extract(156,161);
|
|
mothership_mmsi = extract(132,161);
|
|
assert(type==24);
|
|
}
|
|
|
|
|
|
/*
|
|
20 class aisdecoder
|
|
|
|
*/
|
|
|
|
aisdecoder::aisdecoder(const std::string& filename) {
|
|
in.open(filename.c_str(),std::ios::in);
|
|
buffer = 0;
|
|
if(in){
|
|
const int FILE_BUFFER_SIZE = 10485760;
|
|
buffer = new char[FILE_BUFFER_SIZE];
|
|
in.rdbuf()->pubsetbuf(buffer, FILE_BUFFER_SIZE);
|
|
}
|
|
}
|
|
|
|
MessageBase* aisdecoder::getNextMessage(){
|
|
while(!in.eof() && in.good()){
|
|
getline(in,line);
|
|
MessageBase* msg = 0;
|
|
try{
|
|
msg = decodeLine(line,0);
|
|
} catch(...){
|
|
std::cerr << "Exception during decoding line " << line << std::endl;
|
|
}
|
|
if(msg){
|
|
return msg;
|
|
}
|
|
}
|
|
try{
|
|
in.close();
|
|
} catch(...) {}
|
|
return 0;
|
|
}
|
|
|
|
MessageBase* aisdecoder::getNextMessage(const int type){
|
|
while(!in.eof() && in.good()){
|
|
getline(in,line);
|
|
MessageBase* msg = 0;
|
|
try{
|
|
msg = decodeLine(line,type);
|
|
} catch(...){
|
|
std::cerr << "Exception during decoding line " << line << std::endl;
|
|
}
|
|
if(msg){
|
|
return msg;
|
|
}
|
|
}
|
|
try{
|
|
in.close();
|
|
} catch(...) {}
|
|
return 0;
|
|
}
|
|
|
|
|
|
MessageBase* aisdecoder::decodeLine(const std::string& line, const int type){
|
|
if(line.size()==0){ // ignore empty lines
|
|
return 0;
|
|
}
|
|
size_t pos = line.find(",");
|
|
if(pos==std::string::npos){
|
|
std::cerr << "invalid line format, no comma inside" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
std::string talker = line.substr(0,pos);
|
|
if(talker.length()==6 && talker[0]=='!' && talker.substr(3,2)=="VD"){
|
|
return decodevdms(line, type);
|
|
} else if(talker=="$PVOL"){
|
|
return 0; // heartbeat message, ignore
|
|
} else {
|
|
std::cerr << "unknown talker: " << talker << std::endl;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
MessageBase* aisdecoder::decodevdms(const std::string& line, const int type){
|
|
std::string talker = line.substr(1,2);
|
|
size_t pos1 = 0;
|
|
size_t pos2 = line.find(",");
|
|
std::string tmp;
|
|
if(!getNextPart(line,pos1,pos2,tmp)){
|
|
std::cerr << "cannot extract framecount" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
int fragmentcount = str2int(tmp);
|
|
if(!getNextPart(line,pos1,pos2,tmp)){
|
|
std::cerr << "cannot extract frame number in line '"
|
|
<< line << "'" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
int fragmentnumber = str2int(tmp);
|
|
if(!getNextPart(line,pos1,pos2,tmp)){
|
|
std::cerr << "cannot extract message id" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
int messageId = str2int(tmp);
|
|
if(!getNextPart(line,pos1,pos2,tmp)){
|
|
std::cerr << "cannot extract radio channel code" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
std::string rcc = tmp;
|
|
if(!getNextPart(line,pos1,pos2,tmp)){
|
|
std::cerr << "cannot extract message " << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
std::string msg = tmp;
|
|
if(msg.length()<1){
|
|
return 0;
|
|
}
|
|
// extract type and filter out if type not fits
|
|
int t = msg[0] - '0';
|
|
if(t>40) t -= 8;
|
|
if(type>0 && t!=type){
|
|
return 0;
|
|
}
|
|
|
|
|
|
pos1 = pos2;
|
|
pos1++;
|
|
pos2 = line.find(",",pos1);
|
|
std::string fill = pos2==std::string::npos
|
|
? line.substr(pos1, std::string::npos)
|
|
: line.substr(pos1, pos2-pos1);
|
|
|
|
if(fill.size()!=4){
|
|
std::cerr << "invalid length of fill" << std::endl;
|
|
std::cerr << "fill is " << fill << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
if( fill[1] != '*'){
|
|
std::cerr << "missing '*' in last field" << std::endl;
|
|
std::cerr << "line is " << line << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
int check = atoi(("0x"+fill.substr(2)).c_str());
|
|
|
|
std::string rest = pos2 == std::string::npos
|
|
? line.substr(pos1,std::string::npos)
|
|
: "";
|
|
|
|
return decodeLine(talker, fragmentcount, fragmentnumber, messageId, rcc,
|
|
msg, fill[0]-'0', check, rest);
|
|
}
|
|
|
|
MessageBase* aisdecoder::decodeLine(std::string& talker,
|
|
int fragmentcount,
|
|
int fragmentnumber,
|
|
int messageId,
|
|
std::string& rcc,
|
|
std::string& msg,
|
|
int fill,
|
|
int check,
|
|
std::string& rest){
|
|
if(fragmentcount > 1){
|
|
if(incompleteMessages.find(messageId)==incompleteMessages.end()){
|
|
MultiLineMessage mlm(fragmentcount, fragmentnumber, msg, messageId,rcc);
|
|
incompleteMessages[messageId] = mlm;
|
|
} else {
|
|
try{
|
|
incompleteMessages[messageId].add(fragmentcount, fragmentnumber,
|
|
msg, messageId,rcc);
|
|
} catch(int err){
|
|
incompleteMessages.erase(messageId);
|
|
MultiLineMessage mlm(fragmentcount, fragmentnumber, msg,
|
|
messageId,rcc);
|
|
incompleteMessages[messageId] = mlm;
|
|
}
|
|
}
|
|
MultiLineMessage mlm = incompleteMessages[messageId];
|
|
if(mlm.isComplete()){
|
|
incompleteMessages.erase(messageId);
|
|
return decode(mlm);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if(msg.length() < 1){
|
|
std::cerr << "empty message" << std::endl;
|
|
return 0;
|
|
}
|
|
int messagenumber = msg[0] - 48;
|
|
if(messagenumber > 40){
|
|
messagenumber = messagenumber - 8;
|
|
}
|
|
if(messagenumber <1 || messagenumber > 27){
|
|
std::cerr << "invalid message number " << messagenumber << std::endl;
|
|
return 0;
|
|
}
|
|
return decode(messagenumber, msg);
|
|
}
|
|
|
|
|
|
MessageBase* aisdecoder::decode(const MultiLineMessage& mlm){
|
|
assert(mlm.isComplete());
|
|
std::string msg = mlm.getMessage();
|
|
if(msg.size()<1){
|
|
std::cerr << "found empty multi line message";
|
|
return 0;
|
|
}
|
|
int messagenumber = msg[0] - 48;
|
|
if(messagenumber > 40){
|
|
messagenumber = messagenumber - 8;
|
|
}
|
|
return decode(messagenumber,msg);
|
|
}
|
|
|
|
|
|
MessageBase* aisdecoder::decode(const int messagenumber,
|
|
const std::string& msg) {
|
|
try{
|
|
switch(messagenumber){
|
|
case 1:
|
|
case 2:
|
|
case 3: return new Message1_3(msg);
|
|
case 4: return new Message4(msg);
|
|
case 5: return new Message5(msg);
|
|
case 9: return new Message9(msg);
|
|
case 12: return new Message12(msg);
|
|
case 14: return new Message14(msg);
|
|
case 18: return new Message18(msg);
|
|
case 19: return new Message19(msg);
|
|
case 24: return new Message24(msg);
|
|
default: std::cerr << "aisdecoder: message type " << messagenumber
|
|
<< "not implemented yet" << std::endl;
|
|
return 0;
|
|
}
|
|
} catch(int ex){
|
|
std::cerr << "exception during processing message " << messagenumber
|
|
<< std::endl;
|
|
std::cerr << "message is " << msg << std::endl;
|
|
std::cerr << "message's length : " << msg.length() << std::endl;
|
|
std::cerr << "Exception is " << ex << std::endl;
|
|
return 0;
|
|
} catch(...){
|
|
std::cerr << " unknown exception during processing message "
|
|
<< messagenumber << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool aisdecoder::getNextPart(const std::string& line, size_t& pos1,
|
|
size_t&pos2, std::string& result){
|
|
pos1 = pos2;
|
|
pos1++;
|
|
pos2 = line.find(",",pos1);
|
|
if(pos2==std::string::npos){
|
|
result = "";
|
|
return false;
|
|
}
|
|
result = line.substr(pos1, pos2-pos1);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
} // end of namespace
|
|
|