View Javadoc
1   package au.gov.amsa.ais.message;
2   
3   import static au.gov.amsa.ais.AisMessageType.POSITION_REPORT_ASSIGNED;
4   import static au.gov.amsa.ais.AisMessageType.POSITION_REPORT_SCHEDULED;
5   import static au.gov.amsa.ais.AisMessageType.POSITION_REPORT_SPECIAL;
6   
7   import au.gov.amsa.ais.AisExtractor;
8   import au.gov.amsa.ais.AisExtractorFactory;
9   import au.gov.amsa.ais.AisParseException;
10  import au.gov.amsa.ais.Communications;
11  import au.gov.amsa.ais.HasCommunications;
12  import au.gov.amsa.ais.Util;
13  
14  /**
15   * Decoder for AIS message types 1, 2,3 (Class A position reports).
16   * 
17   * @author dxm
18   * 
19   */
20  public class AisPositionA implements AisPosition, HasCommunications {
21  
22      private static final Integer TRUE_HEADING_NOT_AVAILABLE = 511;
23      private static final Integer COG_NOT_AVAILABLE = 3600;
24      private static final Integer SOG_NOT_AVAILABLE = 1023;
25      private static final Integer ROT_NOT_AVAILABLE = -128;
26      private static final Integer LONGITUDE_NOT_AVAILABLE = 181 * 600000; // 108600000;
27      private static final Integer LATITUDE_NOT_AVAILABLE = 91 * 600000; // 54600000;
28      private final AisExtractor extractor;
29      private final String source;
30      private final int messageId;
31      private final int mmsi;
32      private final Double longitude;
33      private final Double latitude;
34  
35      public AisPositionA(String message, String source, int padBits) {
36          this(Util.getAisExtractorFactory(), message, source, padBits);
37      }
38  
39      public AisPositionA(String message, int padBits) {
40          this(Util.getAisExtractorFactory(), message, null, padBits);
41      }
42  
43      public AisPositionA(AisExtractorFactory factory, String message, String source, int padBits) {
44          this.source = source;
45          this.extractor = factory.create(message, 137, padBits);
46          messageId = extractor.getMessageId();
47          Util.checkMessageId(messageId, POSITION_REPORT_SCHEDULED, POSITION_REPORT_ASSIGNED,
48                  POSITION_REPORT_SPECIAL);
49          mmsi = extractor.getValue(8, 38);
50          longitude = extractLongitude(extractor);
51          latitude = extractLatitude(extractor);
52      }
53  
54      static Integer extractTrueHeading(AisExtractor extractor) {
55          try {
56              int val = extractor.getValue(128, 137);
57              if (val == TRUE_HEADING_NOT_AVAILABLE)
58                  return null;
59              else if (val > 359) {
60                  // have seen 404, might be corrupted message
61                  return null;
62              } else
63                  return val;
64          } catch (AisParseException e) {
65              return null;
66          }
67      }
68  
69      static Double extractCourseOverGround(AisExtractor extractor) {
70          try {
71              int val = extractor.getValue(116, 128);
72              if (val == COG_NOT_AVAILABLE || val >= 3600)
73                  return null;
74              else
75                  return val / 10.0;
76          } catch (AisParseException e) {
77              return null;
78          }
79      }
80  
81      static Double extractSpeedOverGround(AisExtractor extractor) {
82          try {
83              int val = extractor.getValue(50, 60);
84              if (val == SOG_NOT_AVAILABLE)
85                  return null;
86              else
87                  return val / 10.0;
88          } catch (AisParseException e) {
89              return null;
90          }
91      }
92  
93      static Integer extractRateOfTurn(AisExtractor extractor) {
94          try {
95              byte val = (byte) extractor.getSignedValue(42, 50);
96              if (val == ROT_NOT_AVAILABLE)
97                  return null;
98              else
99                  return (int) val;
100         } catch (AisParseException e) {
101             return null;
102         }
103     }
104 
105     static Double extractLongitude(AisExtractor extractor) {
106         try {
107             int val = extractor.getSignedValue(61, 89);
108             if (val == LONGITUDE_NOT_AVAILABLE) {
109                 return null;
110             } else {
111                 Util.checkLong(val / 600000.0);
112                 return val / 600000.0;
113             }
114         } catch (AisParseException e) {
115             return null;
116         }
117     }
118 
119     static Double extractLatitude(AisExtractor extractor) {
120 
121         try {
122             int val = extractor.getSignedValue(89, 116);
123             if (val == LATITUDE_NOT_AVAILABLE) {
124                 return null;
125             } else {
126                 Util.checkLat(val / 600000.0);
127                 return val / 600000.0;
128             }
129         } catch (AisParseException e) {
130             return null;
131         }
132     }
133 
134     @Override
135     public int getMessageId() {
136         return messageId;
137     }
138 
139     @Override
140     public int getRepeatIndicator() {
141         return extractor.getValue(6, 8);
142     }
143 
144     @Override
145     public int getMmsi() {
146         return mmsi;
147     }
148 
149     public NavigationalStatus getNavigationalStatus() {
150         return NavigationalStatus.values()[extractor.getValue(38, 42)];
151     }
152 
153     public Integer getRateOfTurn() {
154         return extractRateOfTurn(extractor);
155     }
156 
157     @Override
158     public Double getSpeedOverGroundKnots() {
159         return extractSpeedOverGround(extractor);
160     }
161 
162     @Override
163     public boolean isHighAccuracyPosition() {
164         return Util.areEqual(extractor.getValue(60, 61), 1);
165     }
166 
167     @Override
168     public Double getLongitude() {
169         return longitude;
170     }
171 
172     @Override
173     public Double getLatitude() {
174         return latitude;
175     }
176 
177     @Override
178     public Double getCourseOverGround() {
179         return extractCourseOverGround(extractor);
180     }
181 
182     @Override
183     public Integer getTrueHeading() {
184         return extractTrueHeading(extractor);
185     }
186 
187     @Override
188     public int getTimeSecondsOnly() {
189         return extractor.getValue(137, 143);
190     }
191 
192     public int getSpecialManoeuvreIndicator() {
193         return extractor.getValue(143, 145);
194     }
195 
196     public int getSpare() {
197         return extractor.getValue(145, 148);
198     }
199 
200     @Override
201     public boolean isUsingRAIM() {
202         return Util.areEqual(extractor.getValue(148, 149), 1);
203     }
204 
205     @Override
206     public Communications getCommunications() {
207         return new Communications(extractor, 149);
208     }
209 
210     @Override
211     public String getSource() {
212         return source;
213     }
214 
215     @Override
216     public String toString() {
217         StringBuilder builder = new StringBuilder();
218         builder.append("AisPositionA [source=");
219         builder.append(source);
220         builder.append(", messageId=");
221         builder.append(messageId);
222         builder.append(", repeatIndicator=");
223         builder.append(getRepeatIndicator());
224         builder.append(", mmsi=");
225         builder.append(mmsi);
226         builder.append(", navigationalStatus=");
227         builder.append(getNavigationalStatus());
228         builder.append(", rateOfTurn=");
229         builder.append(getRateOfTurn());
230         builder.append(", speedOverGroundKnots=");
231         builder.append(getSpeedOverGroundKnots());
232         builder.append(", isHighAccuracyPosition=");
233         builder.append(isHighAccuracyPosition());
234         builder.append(", longitude=");
235         builder.append(longitude);
236         builder.append(", latitude=");
237         builder.append(latitude);
238         builder.append(", courseOverGround=");
239         builder.append(getCourseOverGround());
240         builder.append(", trueHeading=");
241         builder.append(getTrueHeading());
242         builder.append(", timeSecondsOnly=");
243         builder.append(getTimeSecondsOnly());
244         builder.append(", specialManoeuvreIndicator=");
245         builder.append(getSpecialManoeuvreIndicator());
246         builder.append(", spare=");
247         builder.append(getSpare());
248         builder.append(", isUsingRAIM=");
249         builder.append(isUsingRAIM());
250         builder.append(", communications=");
251         builder.append(getCommunications());
252         builder.append("]");
253         return builder.toString();
254     }
255 
256 }