1 package au.gov.amsa.ais.message;
2
3 import au.gov.amsa.ais.AisExtractor;
4 import au.gov.amsa.ais.AisExtractorFactory;
5 import au.gov.amsa.ais.AisParseException;
6 import au.gov.amsa.ais.Util;
7
8 import static au.gov.amsa.ais.AisMessageType.POSITION_GPS;
9
10
11
12
13
14
15
16 public class AisPositionGPS implements AisPosition {
17
18 private static final Integer COG_NOT_AVAILABLE = 511;
19 private static final Integer SOG_NOT_AVAILABLE = 63;
20 private static final Integer LONGITUDE_NOT_AVAILABLE = 181 * 600;
21 private static final Integer LATITUDE_NOT_AVAILABLE = 91 * 600;
22 private final AisExtractor extractor;
23 private final String source;
24 private final int messageId;
25 private final int mmsi;
26 private final Double longitude;
27 private final Double latitude;
28
29 public AisPositionGPS(String message, String source, int padBits) {
30 this(Util.getAisExtractorFactory(), message, source, padBits);
31 }
32
33 public AisPositionGPS(String message, int padBits) {
34 this(message, null, padBits);
35 }
36
37 public AisPositionGPS(AisExtractorFactory factory, String message, String source, int padBits) {
38 this.source = source;
39 this.extractor = factory.create(message, 96, padBits);
40 messageId = extractor.getMessageId();
41 Util.checkMessageId(messageId, POSITION_GPS);
42 mmsi = extractor.getValue(8, 38);
43 longitude = extractLongitude(extractor);
44 latitude = extractLatitude(extractor);
45 }
46
47
48 static Double extractCourseOverGround(AisExtractor extractor) {
49 try {
50 int val = extractor.getValue(85, 94);
51 if (val == COG_NOT_AVAILABLE || val >= 360)
52 return null;
53 else
54 return val * 1.0;
55 } catch (AisParseException e) {
56 return null;
57 }
58 }
59
60 static Double extractSpeedOverGround(AisExtractor extractor) {
61 try {
62 int val = extractor.getValue(79, 85);
63 if (val == SOG_NOT_AVAILABLE)
64 return null;
65 else
66 return val * 1.0;
67 } catch (AisParseException e) {
68 return null;
69 }
70 }
71
72 static Double extractLongitude(AisExtractor extractor) {
73 try {
74 int val = extractor.getSignedValue(44, 62);
75 if (val == LONGITUDE_NOT_AVAILABLE) {
76 return null;
77 } else {
78 Util.checkLong(val / 600.0);
79 return val / 600.0;
80 }
81 } catch (AisParseException e) {
82 return null;
83 }
84 }
85
86 static Double extractLatitude(AisExtractor extractor) {
87
88 try {
89 int val = extractor.getSignedValue(62, 79);
90 if (val == LATITUDE_NOT_AVAILABLE) {
91 return null;
92 } else {
93 Util.checkLat(val / 600.0);
94 return val / 600.0;
95 }
96 } catch (AisParseException e) {
97 return null;
98 }
99 }
100
101 @Override
102 public int getMessageId() {
103 return messageId;
104 }
105
106 @Override
107 public int getRepeatIndicator() {
108 return extractor.getValue(6, 8);
109 }
110
111 @Override
112 public int getMmsi() {
113 return mmsi;
114 }
115
116 public NavigationalStatus getNavigationalStatus() { return NavigationalStatus.values()[extractor.getValue(40, 44)]; }
117
118 @Override
119 public Double getSpeedOverGroundKnots() {
120 return extractSpeedOverGround(extractor);
121 }
122
123 @Override
124 public boolean isHighAccuracyPosition() {
125 return Util.areEqual(extractor.getValue(38, 39), 1);
126 }
127
128 @Override
129 public Double getLongitude() {
130 return longitude;
131 }
132
133 @Override
134 public Double getLatitude() {
135 return latitude;
136 }
137
138 @Override
139 public Double getCourseOverGround() {
140 return extractCourseOverGround(extractor);
141 }
142
143 @Override
144 public Integer getTrueHeading() {
145 return null;
146 }
147
148 @Override
149 public int getTimeSecondsOnly() {
150 return 0;
151 }
152
153 public int getSpare() {
154 return extractor.getValue(95, 96);
155 }
156
157 @Override
158 public boolean isUsingRAIM() {
159 return Util.areEqual(extractor.getValue(39, 40), 1);
160 }
161
162 @Override
163 public String getSource() {
164 return source;
165 }
166
167 @Override
168 public String toString() {
169 StringBuilder builder = new StringBuilder();
170 builder.append("AisPositionGPS [source=");
171 builder.append(source);
172 builder.append(", messageId=");
173 builder.append(messageId);
174 builder.append(", repeatIndicator=");
175 builder.append(getRepeatIndicator());
176 builder.append(", mmsi=");
177 builder.append(mmsi);
178 builder.append(", navigationalStatus=");
179 builder.append(getNavigationalStatus());
180 builder.append(", speedOverGroundKnots=");
181 builder.append(getSpeedOverGroundKnots());
182 builder.append(", isHighAccuracyPosition=");
183 builder.append(isHighAccuracyPosition());
184 builder.append(", longitude=");
185 builder.append(longitude);
186 builder.append(", latitude=");
187 builder.append(latitude);
188 builder.append(", courseOverGround=");
189 builder.append(getCourseOverGround());
190 builder.append(", trueHeading=");
191 builder.append(getTrueHeading());
192 builder.append(", timeSecondsOnly=");
193 builder.append(getTimeSecondsOnly());
194 builder.append(", spare=");
195 builder.append(getSpare());
196 builder.append(", isUsingRAIM=");
197 builder.append(isUsingRAIM());
198 builder.append("]");
199 return builder.toString();
200 }
201
202 }