This is a simple library for parsing AIS (Automatic Identification System) record.
- You can parse each sentence which start with "!AIVDM" or "!AIVDO" to AisRecord instance
- Repeat sentences can be parsed
- The implemented AisRecords as it now stands are below
- Position Report Class A (type 1, 2, 3)
- Static and Voyage Related Data (type 5)
- Standard Class B CS Position Report (type 18)
- Static Data Report (type 24)
- You can create your custom AisParser for unimplemented type
Add dependency to your project.
For Gradle as an example, add the snippet like below to build.gradle.
// if it were needed
repositories {
jcenter()
}
dependencies {
compile 'com.kokufu.nmea.ais:ais-parser:0.1'
}To parse AIS record, instantiate AisParser and call AisParser#parse(String) for each line.
The simplest example is shown below.
AisParser aisParser = new AisParser();
BufferedReader reader = null;
try {
// InputStream (is) must be set and initialized before
reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
try {
AisRecord record = (AisRecord) aisParser.parse(line);
if (record != null) {
// Notify record is updated
// callback.onRecordUpdated(record);
}
} catch (NoParserException e) {
// Do nothing
} catch (InvalidDataFormatException e) (
// Do something
}
}
} catch (IOException e) {
// Do something
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// Do something
}
}You can cast the each AisRecord instance to the specific class like below.
void onRecordUpdated(AisRecord record) {
if (record instanceof AisPositionReportClassARecord) {
AisPositionReportClassARecord r = (AisPositionReportClassARecord) record;
mSpeedOverGround = r.getSpeedOverGround();
mPositionAccuracy = r.getPositionAccuracy();
mLongitude = r.getLongitude();
mLatitude = r.getLatitude();
mCourseOverGround = r.getCourseOverGround();
mTrueHeading = r.getTrueHeading();
mTimeStamp = r.getTimeStamp();
} else if (record instanceof AisPositionReportClassBRecord) {
AisPositionReportClassBRecord r = (AisPositionReportClassBRecord) record;
mSpeedOverGround = r.getSpeedOverGround();
mPositionAccuracy = r.getPositionAccuracy();
mLongitude = r.getLongitude();
mLatitude = r.getLatitude();
mCourseOverGround = r.getCourseOverGround();
mTrueHeading = r.getTrueHeading();
mTimeStamp = r.getTimeStamp();
} else if (record instanceof AisStaticAndVoyageRelatedDataRecord) {
AisStaticAndVoyageRelatedDataRecord r = (AisStaticAndVoyageRelatedDataRecord) record;
mName = r.getName();
mDimensionToBow = r.getDimensionToBow();
mDimensionToStern = r.getDimensionToStern();
mDimensionToPort = r.getDimensionToPort();
mDimensionToStarboard = r.getDimensionToStarboard();
mDestination = r.getDestination();
} else if (record instanceof AisStaticDataReportRecord) {
AisStaticDataReportRecord r = (AisStaticDataReportRecord) record;
if (r.getPartType() == AisStaticDataReportRecord.PartType.A) {
mName = r.getName();
} else if (r.getPartType() == AisStaticDataReportRecord.PartType.B) {
mDimensionToBow = r.getDimensionToBow();
mDimensionToStern = r.getDimensionToStern();
mDimensionToPort = r.getDimensionToPort();
mDimensionToStarboard = r.getDimensionToStarboard();
}
}
}If you want to parse the record which has not been implemented yet,
you can create a subclass of AisRecord and set it as custom record.
Below is an example to set "Base Station Report" record known as "Type 4."
AisParser aisParser = new AisParser();
// You must create BaseStationReportRecord class before
BaseStationReportRecord r = new BaseStationReportRecord();
// Set the record as custom record whose type is 4
aisParser.setCustomRecord(4, r);
// Call aisParser.parse(String) for each lineTo implement "Base Station Report",
only you have to do is create Segments array and the getter method like below.
It's better to see the real implementation of AisRecord like AisStaticAndVoyageRelatedDataRecord.
public class BaseStationReportRecord extends AisRecord {
private final Segment[] mSegments = {
new Segment(38, 78, SegmentConverters.TO_FULL_CALENDAR), // Time
new Segment(78, 79, SegmentConverters.TO_UNSIGNED_INT), // Accuracy
// ellipsis
};
public int getAccuracy() {
return (int) mSegments[1].getValue();
}
// ellipsis
}When the new record works fine, please make a pull request ;-)