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