Subversion Repositories Projects

Rev

Rev 1539 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1539 - 1
package dongfang.mkt.serial;
2
 
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.io.OutputStream;
6
 
7
import dongfang.mkt.frames.AllDisplaysResponseFrame;
8
import dongfang.mkt.frames.AnalogDebugLabelResponseFrame;
9
import dongfang.mkt.frames.AttitudeDataResponseFrame;
10
import dongfang.mkt.frames.ChangeParameterSetResponseFrame;
11
import dongfang.mkt.frames.ConfirmFrame;
12
import dongfang.mkt.frames.DebugResponseFrame;
13
import dongfang.mkt.frames.MotorTestResponseFrame;
1559 - 14
import dongfang.mkt.frames.OSDDataResponseFrame;
15
import dongfang.mkt.frames.OSDDataResponseFrame.GPSDistanceAndBearing;
16
import dongfang.mkt.frames.OSDDataResponseFrame.GPSPosition;
17
import dongfang.mkt.frames.ReadExternalControlResponseFrame;
1539 - 18
import dongfang.mkt.frames.ResponseFrame;
19
import dongfang.mkt.frames.SetCompassHeadingResponseFrame;
20
import dongfang.mkt.frames.UniversalReadParamSetResponseFrame;
21
import dongfang.mkt.frames.UniversalWriteParamSetResponseFrame;
22
import dongfang.mkt.frames.VariablesResponseFrame;
23
import dongfang.mkt.frames.VersionResponseFrame;
24
 
25
public class MKInputStream extends InputStream {
26
        int readByteCnt;
27
        class MKDataInputStream {
28
                int[] inbuf = new int[4];
29
                int[] outbuf = new int[3];
30
                int outbufptr = outbuf.length; // reset to "buffer empty"
31
 
32
                private boolean decode() throws IOException {
33
                        for (int i = 0; i < 4; i++) {
34
                                int raw = MKInputStream.this.readByte();
35
                                int in = raw - '=';
36
                                if (in < 0 || in > 63)
37
                                        return false;
38
                                        // throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");
39
                                inbuf[i] = in;
40
                                readByteCnt++;
41
                        }
42
                        outbuf[0] = (inbuf[0] << 2) | (inbuf[1] >>> 4);
43
                        outbuf[1] = ((inbuf[1] & 0x0f) << 4) | (inbuf[2] >>> 2);
44
                        outbuf[2] = ((inbuf[2] & 0x03) << 6) | inbuf[3];
45
                        outbufptr = 0;
46
                        return true;
47
                }
48
 
49
                public void reset() {
50
                        outbufptr = outbuf.length; // reset to "buffer empty"
51
                }
52
 
53
                public int readByte() throws IOException {
54
                        if (outbufptr > 2 && !decode())
55
                                        throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");            
56
                        return outbuf[outbufptr++];
57
                }
58
 
1559 - 59
                public int readSignedByte() throws IOException {
60
                        byte result = (byte)readByte();
61
                        return result;
62
                }
63
 
1539 - 64
                public int readWord() throws IOException {
1559 - 65
                        int byte0 = readByte();
1539 - 66
                        int byte1 = readByte();
1559 - 67
                        return (byte1 << 8) | byte0;
1539 - 68
                }
69
 
70
                public int readSignedWord() throws IOException {
71
                        int word = readWord();
72
                        if (word > 32767)
73
                                word = word - 65536;
74
                        return word;
75
                }
1559 - 76
 
77
                public int readSignedDWord() throws IOException {
78
                        int byte0 = readByte();
79
                        int byte1 = readByte();
80
                        int byte2 = readByte();
81
                        int byte3 = readByte();
82
                        return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
83
                }
1539 - 84
 
85
                public int[] readBytes(int length) throws IOException {
86
                        int[] result = new int[length];
87
                        for (int i = 0; i < length; i++) {
88
                                result[i] = readByte();
89
                        }
90
                        return result;
91
                }
92
 
93
                public int[] readWords(int length) throws IOException {
94
                        int[] result = new int[length];
95
                        for (int i = 0; i < length; i++) {
96
                                result[i] = readWord();
97
                        }
98
                        return result;
99
                }
100
 
101
                public char[] readChars(int length) throws IOException {
102
                        char[] result = new char[length];
103
                        for (int i = 0; i < length; i++) {
104
                                // Here, a 1:1 mapping between byte values and char codes is assumed.
105
                                // That means we're assuming ISO-8859-1 (= the first 256 code points
106
                                // of Unicode, which Java uses for chars)
107
                                result[i] = (char) readByte();
108
                        }
109
                        return result;
110
                }
111
        }
112
 
1559 - 113
        MKDataInputStream base64InputStream = new MKDataInputStream();
1539 - 114
        OutputStream nonPacketSpillway = null; //System.err;
115
 
116
        final InputStream is;
117
        int crc;
118
 
119
        public MKInputStream(InputStream is) {
120
                this.is = is;
121
        }
122
 
123
        @Override
124
        public int read() throws IOException {
125
                int i;
126
                while ((i=is.read()) == -1);
127
                // System.out.print("Received: " + i + " (as char: " + (char)i + ")\n");
128
                return i;
129
        }
130
 
131
        public int readByte() throws IOException {
132
                int _byte = read();
133
                if (_byte < 0)
134
                        throw new IOException("End of Stream!");
135
                crc += _byte;
136
                return _byte;
137
        }
138
 
139
        public MKDataInputStream getBase64InputStream() {
1559 - 140
                return base64InputStream;
1539 - 141
        }
142
 
143
        public ResponseFrame getNextFrame() throws IOException {
144
                int c;
145
                while ((c = read()) != '#') {
146
                        // throw it on some scrap-text buffer.
147
                        if (nonPacketSpillway != null)
148
                                nonPacketSpillway.write(c);
149
                }
150
                crc = '#';
1559 - 151
                base64InputStream.reset();
1539 - 152
                int address = readByte() - 'a';
153
                int iid = readByte();
154
                readByteCnt = 0;
155
                //RESPONSE_IDS id = getResponseType(iid);
156
                ResponseFrame result;
157
                switch (iid) {
158
                case 'A': {
159
                        AnalogDebugLabelResponseFrame f = new AnalogDebugLabelResponseFrame(address);
1559 - 160
                        f.setChannel(base64InputStream.readByte());
161
                        f.setLabel(base64InputStream.readChars(16));
1539 - 162
                        result = f;
163
                        break;
164
                }
165
                case 'B': {
166
                        ConfirmFrame f = new ConfirmFrame(address);
1559 - 167
                        f.setFrameNum(base64InputStream.readByte());
1539 - 168
                        result = f;
169
                        break;
170
                }
171
                case 'C': {
172
                        AttitudeDataResponseFrame f = new AttitudeDataResponseFrame(address);
1559 - 173
                        f.setPitch(base64InputStream.readSignedWord());
174
                        f.setRoll(base64InputStream.readSignedWord());
175
                        f.setHeading(base64InputStream.readSignedWord());
176
                        f.setExpansion(base64InputStream.readBytes(8));
1539 - 177
                        result = f;
178
                        break;
179
                }
180
                case 'D': {
181
                        DebugResponseFrame f = new DebugResponseFrame(address);
182
                        for (int i=0; i<2; i++)
1559 - 183
                                f.setDigital(i, base64InputStream.readByte());
1539 - 184
                        for (int i=0; i<32; i++)
1559 - 185
                                f.setAnalog(i, base64InputStream.readSignedWord());
1539 - 186
                        result = f;
187
                        break;
188
                }
189
                case 'F': {
190
                        ChangeParameterSetResponseFrame f = new ChangeParameterSetResponseFrame(address);
1559 - 191
                        f.setParameterSetNumber(base64InputStream.readByte());
1539 - 192
                        result = f;
193
                        break;
194
                }
1559 - 195
                case 'G': {
196
                        ReadExternalControlResponseFrame f = new ReadExternalControlResponseFrame(address);
197
                        f.setDigital(base64InputStream.readBytes(2));
198
                        f.setRemoteButtons(base64InputStream.readByte());
199
                        f.setPitch(base64InputStream.readByte());
200
                        f.setRoll(base64InputStream.readByte());
201
                        f.setYaw(base64InputStream.readByte());
202
                        f.setThrottle(base64InputStream.readByte());
203
                        f.setHeight(base64InputStream.readByte());
204
                        f.setCommand(base64InputStream.readByte());
205
                        f.setFrameNum(base64InputStream.readByte());
206
                        f.setArgument(base64InputStream.readByte());
207
                        result = f;
208
                        break;
209
                }
1539 - 210
                case 'H': {
211
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
1559 - 212
                        f.setLine(base64InputStream.readByte());
1539 - 213
                        //f.setMaxItem(getDataInputStream().readByte());
1559 - 214
                        f.setText(base64InputStream.readChars(20));
1539 - 215
                        result = f;
216
                        break;
217
                }
218
                case 'L': {
219
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
1559 - 220
                        f.setItem(base64InputStream.readByte());
1539 - 221
                        // f.setMaxItem(getDataInputStream().readByte());
1559 - 222
                        f.setText(base64InputStream.readChars(80));
1539 - 223
                        result = f;
224
                        break;
225
                }
1559 - 226
                case 'O': {
227
                        OSDDataResponseFrame f = new OSDDataResponseFrame(address);
228
                        f.setVersion(base64InputStream.readByte());
229
 
230
                        GPSPosition pos = new GPSPosition();
231
                        pos.setLongitude(base64InputStream.readSignedDWord());
232
                        pos.setLatitude(base64InputStream.readSignedDWord());
233
                        pos.setAltitude(base64InputStream.readSignedDWord());
234
                        pos.setStatus(base64InputStream.readByte());
235
                        f.setCurrentPosition(pos);
236
 
237
                        pos = new GPSPosition();
238
                        pos.setLongitude(base64InputStream.readSignedDWord());
239
                        pos.setLatitude(base64InputStream.readSignedDWord());
240
                        pos.setAltitude(base64InputStream.readSignedDWord());
241
                        pos.setStatus(base64InputStream.readByte());
242
                        f.setTargetPosition(pos);
243
 
244
                        GPSDistanceAndBearing rnb = new GPSDistanceAndBearing();
245
                        rnb.setDistance(base64InputStream.readWord());
246
                        rnb.setBearing(base64InputStream.readSignedWord());
247
                        f.setCurrentToTarget(rnb);
248
 
249
                        pos = new GPSPosition();
250
                        pos.setLongitude(base64InputStream.readSignedDWord());
251
                        pos.setLatitude(base64InputStream.readSignedDWord());
252
                        pos.setAltitude(base64InputStream.readSignedDWord());
253
                        pos.setStatus(base64InputStream.readByte());
254
                        f.setHomePosition(pos);
255
 
256
                        rnb = new GPSDistanceAndBearing();
257
                        rnb.setDistance(base64InputStream.readWord());
258
                        rnb.setBearing(base64InputStream.readSignedWord());
259
                        f.setCurrentToHome(rnb);
260
 
261
                        f.setWaypointIndex(base64InputStream.readByte());
262
                        f.setWaypointCount(base64InputStream.readByte());
263
                        f.setNumberOfSatellites(base64InputStream.readByte());
264
 
265
                        f.setHeightByPressure(base64InputStream.readSignedWord());
266
                        f.setVerticalVelocityByPressure(base64InputStream.readSignedWord());
267
                        f.setFlightTime(base64InputStream.readWord());
268
                        f.setBatteryVoltage(base64InputStream.readByte());
269
                        f.setGroundSpeed(base64InputStream.readWord());
270
 
271
                        f.setHeading(base64InputStream.readSignedWord());
272
                        f.setCompassHeading(base64InputStream.readSignedWord());
273
 
274
                        f.setPitchAngle(base64InputStream.readSignedByte());
275
                        f.setRollAngle(base64InputStream.readSignedByte());
276
 
277
                        f.setRcQuality(base64InputStream.readByte());
278
                        f.setFcFlags(base64InputStream.readByte());
279
                        f.setNcFlags(base64InputStream.readByte());
280
                        f.setErrorCode(base64InputStream.readByte());
281
                        f.setOperatingRadius(base64InputStream.readByte());
282
 
283
                        f.setVerticalVelocityByGPS(base64InputStream.readSignedWord());
284
                        f.setTargetLoiterTime(base64InputStream.readByte());
285
                        f.setFcFlags2(base64InputStream.readByte());
286
                        f.setSetpointForAltitude(base64InputStream.readSignedWord());
287
                        f.setThrottle(base64InputStream.readByte());
288
                        f.setCurrent(base64InputStream.readWord());
289
                        f.setCapacityUsed(base64InputStream.readWord());
290
                        result = f;
291
                        break;
292
}
1539 - 293
                case 'S': {
294
                        UniversalWriteParamSetResponseFrame f = new UniversalWriteParamSetResponseFrame(address);
1559 - 295
                        f.setParameterSetNumber(base64InputStream.readByte());
1539 - 296
                        result = f;
297
                        break;
298
                }
299
                case 'T': {
300
                        MotorTestResponseFrame f = new MotorTestResponseFrame(address);
301
                        result = f;
302
                        break;
303
                }
304
                /*
305
                 * We have a collision with the 'x' token: Also used for VariablesRequest.
306
                case 'x': {
307
                        LoopbackTestResponseFrame f = new LoopbackTestResponseFrame(address);
308
                        f.setByte(getDataInputStream().readByte());
309
                        f.setWord(getDataInputStream().readWord());
310
                        f.setChararray(getDataInputStream().readChars(8));
311
                        result = f;
312
                        break;
313
                }
314
            */
315
                case 'V': {
316
                        VersionResponseFrame f = new VersionResponseFrame(address);
1559 - 317
                        f.setSWMajor(base64InputStream.readByte());
318
                        f.setSWMinor(base64InputStream.readByte());
319
                        f.setProtoMajor(base64InputStream.readByte());
320
                        f.setProtoMinor(base64InputStream.readByte());
321
                        f.setSWPatch(base64InputStream.readByte());
322
                        f.setHardwareErrors(base64InputStream.readBytes(5));
1539 - 323
                        result = f;
324
                        break;
325
                }
326
 
327
                // This is my own creation. The ID collides with the waypoint one of FC.
328
                case 'X': {
329
                        VariablesResponseFrame f = new VariablesResponseFrame(address);
1559 - 330
                        f.setVariables(base64InputStream.readWords(8));
1539 - 331
                        result = f;
332
                        break;
333
                }
334
                case 'w': {
335
                        SetCompassHeadingResponseFrame f = new SetCompassHeadingResponseFrame(address);
336
                        // do stuff.
337
                        /*
338
                        ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
339
                        ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
340
                        ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
341
                        ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
342
                        ToMk3Mag.CalState = compassCalState;
343
                        */
344
                        // Waste 8 bytes to make CRC match.
1559 - 345
                        base64InputStream.readBytes(8);
1539 - 346
                        result = f;
347
                        break;
348
                }
349
                case 'Q':
350
                        UniversalReadParamSetResponseFrame f = new UniversalReadParamSetResponseFrame(address);
1559 - 351
                        f.setConfigurationSetNumber(base64InputStream.readByte());
352
                        f.setConfigurationVersion(base64InputStream.readByte());
353
                        int length = base64InputStream.readByte();
354
                        f.setData(base64InputStream.readBytes(length));
1539 - 355
                        result = f;
356
                        break;
357
                default:
358
                        result = null;
359
                }
360
 
361
                int receivedCRC = (read() - '=') << 6;
362
                receivedCRC += (read() - '=');
363
                crc %= 4096;
364
                if (receivedCRC != crc) {
365
                        /// System.err.println("Expected CRC: " + crc + ", got CRC: " + receivedCRC);
366
                        throw new IOException("CRC mismatch! Calculated crc: " + (int)crc + "; received check crc: " + receivedCRC + ", difference: " + Math.abs(crc - receivedCRC));
367
                }
368
                if (read() != '\r') {
369
                        throw new IOException("CR at end of frame missing");
370
                }
371
 
372
                return result;
373
        }
374
}