-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Seraj Dhaliwal edited this page Nov 17, 2020
·
10 revisions
Why another parser? Reviewed a lot of outstanding parsers and learned a lot; only hang-up was either with conversion or parsing or older/incomplete message implementation. Not all of them had all message implemented, tag-block parsing, with NMEA 0183 TSA/VSI message linking to VDO/VDM was missing. Lots of good code is out there; full reference review is at the bottom of the page.
The focus is on simple maintenance and updates of the core parser.
- Excel Spread-sheet (MessagePayloadBlockFormatter.xlsx) is provided to show how the blocks were created to create classes in under 10-20 mins.
- Adding a sub-type message for Type 6 and Type 8 is simple using blocks.
- Adding / Parsing data blocks follows same methodology as sub-type messages.
- Adding NMEA 0183 messages is done using dynamic attributes; look at NMESMessageBase.java.
- Support messages with Tag-block and non-tag-blocks.
- Support messages with multiple fragments.
- Support linking NMEA 0183 TSA/VSI sentence with VDO/VDM messages.
- Support easy maintenance for updates when message specs are changed.
- Provide event based notifications for Complete, Error, or Update (ie: TSA/VSI).
- Support all ITU-R M.1371-5 Messages (1..27)
- Support all GNSS data reporting formats for Type 17 as per Recommendation ITU-R M.823 (partial; in work)
- Support all NMEA 0813 sentences (partial; in work)
- Support command line interface for file processing.
- Support network interface for multiple base station interface (in testing).
- Support connection recovery, logging, and auto-rotation for base station interface (in testing).
- Support live tracking for base station interface (in testing).
- Support all sub-type for Type 6 & Type 8 messages (partial; in work).
- Support encoding (planned).
- ElsuFoundation
- Commons-codec 1.12
- Moved processing to connectors - File and Socket
- Updated to use app.config vice command line arguments
- Running parser "java -jar AISParser.jar"
- Running local sender for socket testing "java -cp ./AISParser.jar elsu.parser.test.sender.SenderServer"
- process.threads is used to configure parse threads; if there is backlog or slow performance increasing it may help - not the thread count should not exceed system processing limitations.
- sender.xxx params are used by threaded sender to simulate base station sending messages
- activeList - comma separated list of active connectors
- file service is used by File Connector to read and parse the file
- net service is used by Socket Connector to connect to host/port and parse recieved data
<application>
...
<services>
<key name="processing.threads">20</key>
<!-- all/6, debug/5, info/4, warn/3, error/2, fatal/1, none/0 -->
<key name="processing.debug">none</key>
<key name="sender.port">31414</key>
<key name="sender.file">E:\development\opt\nbspace-mars\AISParser\references\test\003669771_20200825.log</key>
<key name="sender.interval">2</key>
<activeList>localfile</activeList>
<service name="localfile">
<attributes>
<key name="type">file</key>
<key name="filename">E:\development\opt\nbspace-mars\AISParser\references\test\003669771_20200825.log</key>
<key name="interval">2</key>
<key name="loop">false</key>
</attributes>
</service>
<service name="realtime">
<attributes>
<key name="type">net</key>
<key name="site.host">localhost</key>
<key name="site.port">31414</key>
<key name="monitor.noDataTimeout">2500</key>
<key name="monitor.idleTimeout">5000</key>
<key name="localStore.mask">%s_%s_%s.txt</key>
<key name="localStore.directory">services/data/</key>
<key name="log.rollover.frequency">5</key>
<key name="log.rollover.periodicity">MINUTE</key>
<key name="site.name">NAIS</key>
<key name="site.id">1004</key>
<!-- raw, matched, none (note logging will affect performance) -->
<key name="log.type">raw</key>
</attributes>
</service>
</services>
...
</application>
package elsu.parser;
import java.util.*;
import java.util.concurrent.TimeUnit;
import elsu.base.IAISEventListener;
import elsu.parser.connector.ConnectorBase;
import elsu.parser.connector.StreamFileConnector;
import elsu.parser.connector.StreamSocketConnector;
import elsu.sentence.SentenceBase;
import elsu.support.*;
public class AISParser implements IAISEventListener {
public AISParser(ConfigLoader config) throws Exception {
initialize(config);
for (ConnectorBase connector : this.connectors) {
connector.addListener(this);
}
for (ConnectorBase connector : this.connectors) {
connector.getWorkerPool().awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
}
private void initialize(ConfigLoader config) throws Exception {
try {
String debugLevel = config.getProperty("application.services.key.processing.debug").toString();
if (debugLevel.equals("debug")) {
SentenceBase.logLevel = 6;
} else if (debugLevel.equals("all")) {
SentenceBase.logLevel = 6;
} else if (debugLevel.equals("debug")) {
SentenceBase.logLevel = 5;
} else if (debugLevel.equals("info")) {
SentenceBase.logLevel = 4;
} else if (debugLevel.equals("warn")) {
SentenceBase.logLevel = 3;
} else if (debugLevel.equals("error")) {
SentenceBase.logLevel = 2;
} else if (debugLevel.equals("fatal")) {
SentenceBase.logLevel = 1;
} else if (debugLevel.equals("off")) {
SentenceBase.logLevel = 0;
}
} catch (Exception exi) {
System.out.println(getClass().getName() + ", initialize(), null, config item application.services.key.processing.debug not defined, debugLeve set to all");
}
String connectionList = config.getProperty("application.services.activeList").toString();
String[] connections = connectionList.split(",");
for (String connection : connections) {
if (config.getProperty("application.services.service." + connection + ".attributes.key.type").toString().equals("file")) {
connector = new StreamFileConnector(config, connection, "", 0);
} else {
connector = new StreamSocketConnector(config, connection, "", 0, "", "");
}
connector.start();
connectors.add(connector);
}
}
@Override
public void onAISError(Exception ex, Object o, String message) {
try {
if (SentenceBase.logLevel >= 2) {
System.out.println(getClass().toString() + ", " + "onAISError(), " + ex.getMessage() + ", " + o + ", " + message);
}
} catch (Exception exi) {
System.out.println(getClass().toString() + ", " + "onAISError(), " + "message error notification exception, " + exi.getMessage());
}
}
@Override
public void onAISComplete(Object o) {
try {
if (SentenceBase.logLevel >= 4) {
System.out.println(getClass().toString() + ", " + "onAISComplete(), " + "complete, " + o);
}
} catch (Exception exi) {
System.out.println(getClass().toString() + ", " + "onAISComplete(), " + "message complete notification exception, " + exi.getMessage());
}
}
@Override
public void onAISUpdate(Object o) {
try {
if (SentenceBase.logLevel >= 4) {
System.out.println(getClass().toString() + ", " + "onAISComplete(), " + "update, " + o);
}
} catch (Exception exi) {
System.out.println(getClass().toString() + ", " + "onAISError(), " + "message error notification exception, " + exi.getMessage());
}
}
public static void main(String[] args) throws Exception {
ConfigLoader config = null;
try {
config = new ConfigLoader("config/app.config", null);
} catch (Exception ex) {
throw new Exception("elsu.parser, " + "main(), " + "config resource not found: config/app.config");
}
System.out.println("elsu.parser, " + "main(), start, " + (new Date()));
try {
AISParser parser = new AISParser(config);
System.out.println("elsu.parser, " + "main(), complete, " + (new Date()));
} catch (Exception ex) {
System.out.println("elsu.parser, " + "main(), unknown, " + ex.getMessage());
}
}
ConnectorBase connector = null;
private ArrayList<ConnectorBase> connectors = new ArrayList<>();
}
- Use Socket Connector (see app.config realtime service)
- See AISStreams