Subversion Repositories Projects

Rev

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

Rev Author Line No. Line
1563 - 1
package dongfang.mkt.comm;
2
 
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.io.OutputStream;
6
 
7
import dongfang.mkt.datatype.GPSBearingAndRange;
8
import dongfang.mkt.datatype.GPSPosition;
9
import dongfang.mkt.frames.AllDisplaysResponseFrame;
10
import dongfang.mkt.frames.AnalogDebugLabelResponseFrame;
11
import dongfang.mkt.frames.AttitudeDataResponseFrame;
12
import dongfang.mkt.frames.ChangeParameterSetResponseFrame;
13
import dongfang.mkt.frames.CompassHeadingResponseFrame;
14
import dongfang.mkt.frames.ConfirmFrame;
1695 - 15
import dongfang.mkt.frames.DCMMatrixResponseFrame;
1563 - 16
import dongfang.mkt.frames.DebugResponseFrame;
17
import dongfang.mkt.frames.MotorTestResponseFrame;
18
import dongfang.mkt.frames.OSDDataResponseFrame;
19
import dongfang.mkt.frames.ReadExternalControlResponseFrame;
1611 - 20
import dongfang.mkt.frames.ReadIMUConfigurationResponseFrame;
1688 - 21
import dongfang.mkt.frames.ReadMotorMixerResponseFrame;
1690 - 22
import dongfang.mkt.frames.ReadParamSetResponseFrame;
23
import dongfang.mkt.frames.ReadRCChannelsResponseFrame;
24
import dongfang.mkt.frames.ReadVariablesResponseFrame;
1563 - 25
import dongfang.mkt.frames.ResponseFrame;
26
import dongfang.mkt.frames.SetCompassHeadingResponseFrame;
1690 - 27
import dongfang.mkt.frames.VersionResponseFrame;
1611 - 28
import dongfang.mkt.frames.WriteIMUConfigurationResponseFrame;
1688 - 29
import dongfang.mkt.frames.WriteMotorMixerResponseFrame;
1611 - 30
import dongfang.mkt.frames.WriteParamSetResponseFrame;
1563 - 31
 
32
public class MKInputStream extends InputStream {
33
        int readByteCnt;
34
        class MKDataInputStream {
35
                int[] inbuf = new int[4];
36
                int[] outbuf = new int[3];
37
                int outbufptr = outbuf.length; // reset to "buffer empty"
38
 
39
                private boolean decode() throws IOException {
40
                        for (int i = 0; i < 4; i++) {
41
                                int raw = MKInputStream.this.readByte();
42
                                int in = raw - '=';
43
                                if (in < 0 || in > 63)
44
                                        return false;
45
                                        // throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");
46
                                inbuf[i] = in;
47
                                readByteCnt++;
48
                        }
49
                        outbuf[0] = (inbuf[0] << 2) | (inbuf[1] >>> 4);
50
                        outbuf[1] = ((inbuf[1] & 0x0f) << 4) | (inbuf[2] >>> 2);
51
                        outbuf[2] = ((inbuf[2] & 0x03) << 6) | inbuf[3];
52
                        outbufptr = 0;
53
                        return true;
54
                }
55
 
56
                public void reset() {
57
                        outbufptr = outbuf.length; // reset to "buffer empty"
58
                }
59
 
60
                public int readByte() throws IOException {
61
                        if (outbufptr > 2 && !decode())
62
                                        throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");            
63
                        return outbuf[outbufptr++];
64
                }
65
 
66
                public int readSignedByte() throws IOException {
67
                        byte result = (byte)readByte();
68
                        return result;
69
                }
70
 
71
                public int readWord() throws IOException {
72
                        int byte0 = readByte();
73
                        int byte1 = readByte();
74
                        return (byte1 << 8) | byte0;
75
                }
76
 
77
                public int readSignedWord() throws IOException {
78
                        int word = readWord();
79
                        if (word > 32767)
80
                                word = word - 65536;
81
                        return word;
82
                }
83
 
84
                public int readSignedDWord() throws IOException {
85
                        int byte0 = readByte();
86
                        int byte1 = readByte();
87
                        int byte2 = readByte();
88
                        int byte3 = readByte();
89
                        return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
90
                }
91
 
92
                public int[] readBytes(int length) throws IOException {
93
                        int[] result = new int[length];
94
                        for (int i = 0; i < length; i++) {
95
                                result[i] = readByte();
96
                        }
97
                        return result;
98
                }
99
 
100
                public int[] readWords(int length) throws IOException {
101
                        int[] result = new int[length];
102
                        for (int i = 0; i < length; i++) {
103
                                result[i] = readWord();
104
                        }
105
                        return result;
106
                }
107
 
108
                public int[] readSignedWords(int length) throws IOException {
109
                        int[] result = new int[length];
110
                        for (int i = 0; i < length; i++) {
111
                                result[i] = readSignedWord();
112
                        }
113
                        return result;
114
                }
115
 
116
                public char[] readChars(int length) throws IOException {
117
                        char[] result = new char[length];
118
                        for (int i = 0; i < length; i++) {
119
                                // Here, a 1:1 mapping between byte values and char codes is assumed.
120
                                // That means we're assuming ISO-8859-1 (= the first 256 code points
121
                                // of Unicode, which Java uses for chars)
122
                                result[i] = (char) readByte();
123
                        }
124
                        return result;
125
                }
1695 - 126
 
127
                public float readFloat() throws IOException {
128
                        int asInt = readByte() | (readByte()<<8) | (readByte()<<16) | (readByte()<<24);
129
                        return Float.intBitsToFloat(asInt);
130
                }
1563 - 131
 
1695 - 132
                public float[] readFloats(int length) throws IOException {
133
                        float[] result = new float[length];
134
                        for (int i = 0; i < length; i++) {
135
                                result[i] = readFloat();
136
                        }
137
                        return result;
138
                }
139
}
140
 
1563 - 141
        MKDataInputStream base64InputStream = new MKDataInputStream();
142
        OutputStream nonPacketSpillway = null; //System.err;
143
 
144
        final InputStream is;
145
        int crc;
146
 
147
        public MKInputStream(InputStream is) {
148
                this.is = is;
149
        }
150
 
151
        @Override
152
        public int read() throws IOException {
153
                int i;
154
                while ((i=is.read()) == -1);
155
                // System.out.print("Received: " + i + " (as char: " + (char)i + ")\n");
156
                return i;
157
        }
158
 
159
        public int readByte() throws IOException {
160
                int _byte = read();
161
                if (_byte < 0)
162
                        throw new IOException("End of Stream!");
163
                crc += _byte;
164
                return _byte;
165
        }
166
 
167
        public MKDataInputStream getBase64InputStream() {
168
                return base64InputStream;
169
        }
170
 
171
        public ResponseFrame getNextFrame() throws IOException {
172
                int c;
173
                while ((c = read()) != '#') {
174
                        // throw it on some scrap-text buffer.
175
                        if (nonPacketSpillway != null)
176
                                nonPacketSpillway.write(c);
177
                }
178
                crc = '#';
179
                base64InputStream.reset();
180
                int address = readByte() - 'a';
181
                int iid = readByte();
182
                readByteCnt = 0;
183
                //RESPONSE_IDS id = getResponseType(iid);
184
                ResponseFrame result;
185
//              System.out.println("Received a: " + (char)iid + " from " + address);
186
                switch (iid) {
187
                case 'A': {
188
                        AnalogDebugLabelResponseFrame f = new AnalogDebugLabelResponseFrame(address);
189
                        f.setChannel(base64InputStream.readByte());
190
                        f.setLabel(base64InputStream.readChars(16));
191
                        result = f;
192
                        break;
193
                }
194
                case 'B': {
195
                        ConfirmFrame f = new ConfirmFrame(address);
196
                        f.setFrameNum(base64InputStream.readByte());
197
                        result = f;
198
                        break;
199
                }
200
                case 'C': {
201
                        AttitudeDataResponseFrame f = new AttitudeDataResponseFrame(address);
1695 - 202
                        f.setAttitude(base64InputStream.readFloats(3));
203
                        f.setRates(base64InputStream.readFloats(3));
204
                        f.setAcc(base64InputStream.readFloats(3));
1563 - 205
                        result = f;
206
                        break;
207
                }
208
                case 'D': {
209
                        DebugResponseFrame f = new DebugResponseFrame(address);
210
                        for (int i=0; i<2; i++)
211
                                f.setDigital(i, base64InputStream.readByte());
212
                        for (int i=0; i<32; i++)
213
                                f.setAnalog(i, base64InputStream.readSignedWord());
214
                        result = f;
215
                        break;
216
                }
1695 - 217
                case 'E': {
218
                        DCMMatrixResponseFrame f= new DCMMatrixResponseFrame(address);
219
                        float[][] matrix = new float[3][];
220
                        for (int i=0; i<3; i++) {
221
                                float[] row = base64InputStream.readFloats(3);
222
                                matrix[i] = row;
223
                        }
224
                        f.setMatrix(matrix);
225
                        result = f;
226
                        break;
227
                }
1563 - 228
                case 'F': {
229
                        ChangeParameterSetResponseFrame f = new ChangeParameterSetResponseFrame(address);
230
                        f.setParameterSetNumber(base64InputStream.readByte());
231
                        result = f;
232
                        break;
233
                }
234
                case 'G': {
235
                        ReadExternalControlResponseFrame f = new ReadExternalControlResponseFrame(address);
236
                        f.setDigital(base64InputStream.readBytes(2));
237
                        f.setRemoteButtons(base64InputStream.readByte());
238
                        f.setPitch(base64InputStream.readByte());
239
                        f.setRoll(base64InputStream.readByte());
240
                        f.setYaw(base64InputStream.readByte());
241
                        f.setThrottle(base64InputStream.readByte());
242
                        f.setHeight(base64InputStream.readByte());
243
                        f.setCommand(base64InputStream.readByte());
244
                        f.setFrameNum(base64InputStream.readByte());
245
                        f.setArgument(base64InputStream.readByte());
246
                        result = f;
247
                        break;
248
                }
249
                case 'H': {
250
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
251
                        f.setLine(base64InputStream.readByte());
252
                        //f.setMaxItem(getDataInputStream().readByte());
253
                        f.setText(base64InputStream.readChars(20));
254
                        result = f;
255
                        break;
256
                }
1611 - 257
                case 'I': {
258
                        ReadIMUConfigurationResponseFrame f = new ReadIMUConfigurationResponseFrame(address);
259
                        f.setConfigurationVersion(base64InputStream.readByte());
260
                        int length = base64InputStream.readByte();
261
                        f.setConfigurationSetLength(length);
262
                        f.setData(base64InputStream.readBytes(length));
263
                        result = f;
264
                        break;
265
                }
266
                case 'J': {
267
                        WriteIMUConfigurationResponseFrame f = new WriteIMUConfigurationResponseFrame(address);
268
                        f.setWasAccepted(base64InputStream.readByte()==1);
269
                        result = f;
270
                        break;
271
                }
1563 - 272
                case 'k' : {
273
                        CompassHeadingResponseFrame f = new CompassHeadingResponseFrame(address);
274
                        base64InputStream.readSignedWords(2);
275
                        base64InputStream.readBytes(2);
276
                        base64InputStream.readByte();
277
                        base64InputStream.readByte();
278
                        result = f;
279
                        break;
280
                }
281
                case 'L': {
282
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
283
                        f.setItem(base64InputStream.readByte());
284
                        // f.setMaxItem(getDataInputStream().readByte());
285
                        f.setText(base64InputStream.readChars(80));
286
                        result = f;
287
                        break;
288
                }
1688 - 289
                case 'M': {
290
                        WriteMotorMixerResponseFrame f = new WriteMotorMixerResponseFrame(address);
291
                        f.setWasAccepted(base64InputStream.readByte() != 0);
1689 - 292
                        result = f;
293
                        break;
1688 - 294
                }
295
                case 'N': {
296
                        int numMotors = 12;
297
                        ReadMotorMixerResponseFrame f = new ReadMotorMixerResponseFrame();
298
                        f.setConfigurationVersion(base64InputStream.readByte());
299
                        int length = base64InputStream.readByte();
300
                        f.setDataLength(length);
1689 - 301
                        int testLength = 12; // the name is first!
302
                        char[] name = base64InputStream.readChars(12);
303
                        f.setName(name);
1688 - 304
                        int[][] matrix = new int[numMotors][];
305
                        for(int i=0; i<numMotors; i++) {
1689 - 306
                                int[] row = new int[5];
307
                                matrix[i] = row;
308
                                for(int j=0; j<5; j++) {
309
                                        row[j] = base64InputStream.readSignedByte();
1688 - 310
                                        testLength++;
311
                                }
312
                        }
313
 
314
                        if (length != testLength)
1689 - 315
                                throw new IOException("Length of motor mixer data was not as expected (" + testLength + " vs. " + length + ").");
1688 - 316
                        /*
317
                        int[] opposite = new int[numMotors];
318
                        for(int i=0; i<numMotors; i++) {
319
                                opposite[i] = base64InputStream.readByte();
320
                        }
321
                        */
322
                        f.setMatrix(matrix);
323
                        result = f;
1689 - 324
                        break;
1688 - 325
                }
1563 - 326
                case 'O': {
327
                        OSDDataResponseFrame f = new OSDDataResponseFrame(address);
328
                        f.setVersion(base64InputStream.readByte());
329
 
330
                        GPSPosition pos = new GPSPosition();
1565 - 331
                        pos.setLongitude(((double)base64InputStream.readSignedDWord())/1E7);
332
                        pos.setLatitude(((double)base64InputStream.readSignedDWord())/1E7);
333
                        pos.setAltitude(((double)base64InputStream.readSignedDWord())/1E3);
1563 - 334
                        pos.setStatus(base64InputStream.readByte());
335
                        f.setCurrentPosition(pos);
336
 
337
                        pos = new GPSPosition();
1565 - 338
                        pos.setLongitude(((double)base64InputStream.readSignedDWord())/1E7);
339
                        pos.setLatitude(((double)base64InputStream.readSignedDWord())/1E7);
340
                        pos.setAltitude(((double)base64InputStream.readSignedDWord())/1E3);
1563 - 341
                        pos.setStatus(base64InputStream.readByte());
342
                        f.setTargetPosition(pos);
343
 
344
                        GPSBearingAndRange rnb = new GPSBearingAndRange();
1565 - 345
                        rnb.setDistance(((double)base64InputStream.readWord())/10.0);
1563 - 346
                        rnb.setBearing(base64InputStream.readSignedWord());
347
                        f.setCurrentToTarget(rnb);
348
 
349
                        pos = new GPSPosition();
1565 - 350
                        pos.setLongitude(((double)base64InputStream.readSignedDWord())/1E7);
351
                        pos.setLatitude(((double)base64InputStream.readSignedDWord())/1E7);
352
                        pos.setAltitude(((double)base64InputStream.readSignedDWord())/1E3);
1563 - 353
                        pos.setStatus(base64InputStream.readByte());
354
                        f.setHomePosition(pos);
355
 
356
                        rnb = new GPSBearingAndRange();
1565 - 357
                        rnb.setDistance(((double)base64InputStream.readWord())/10.0);
1563 - 358
                        rnb.setBearing(base64InputStream.readSignedWord());
359
                        f.setCurrentToHome(rnb);
360
 
361
                        f.setWaypointIndex(base64InputStream.readByte());
362
                        f.setWaypointCount(base64InputStream.readByte());
363
                        f.setNumberOfSatellites(base64InputStream.readByte());
364
 
1565 - 365
                        // This stunt is a metric unit conversion: The height was supposed (H&I) to be in integral 5cm steps.
366
                        // However there is error factor in the measurement of 24% too much.
367
                        // h[m] = h[int] * 0.05 / 1.24 = h[int]
368
                        f._setHeightByPressure(((double)base64InputStream.readSignedWord()) * 0.05 / 1.24);
369
 
1568 - 370
                        f.setVerticalVelocityByPressure(((double)base64InputStream.readSignedWord()) * 0.05 / 1.24); // clueless!
1563 - 371
                        f.setFlightTime(base64InputStream.readWord());
372
                        f.setBatteryVoltage(base64InputStream.readByte());
1568 - 373
                        f.setGroundSpeed(((double)base64InputStream.readWord()) / 1E2);
1563 - 374
 
375
                        f.setDirectionOfFlight(base64InputStream.readSignedWord());
376
                        f.setCompassHeading(base64InputStream.readSignedWord());
377
 
378
                        f.setPitchAngle(base64InputStream.readSignedByte());
379
                        f.setRollAngle(base64InputStream.readSignedByte());
380
 
381
                        f.setRcQuality(base64InputStream.readByte());
382
                        f.setFcFlags(base64InputStream.readByte());
383
                        f.setNcFlags(base64InputStream.readByte());
384
                        f.setErrorCode(base64InputStream.readByte());
385
                        f.setOperatingRadius(base64InputStream.readByte());
386
 
1568 - 387
                        f.setVerticalVelocityByGPS(((double)base64InputStream.readSignedWord()) / 1E2);
1563 - 388
                        f.setTargetLoiterTime(base64InputStream.readByte());
389
                        f.setFcFlags2(base64InputStream.readByte());
1565 - 390
                        f.setSetpointForAltitude(((double)base64InputStream.readSignedWord()) * 0.05 / 1.24);
1563 - 391
                        f.setThrottle(base64InputStream.readByte());
392
                        f.setCurrent(base64InputStream.readWord());
393
                        f.setCapacityUsed(base64InputStream.readWord());
394
                        result = f;
395
                        break;
1690 - 396
                }
397
                case 'P': {
398
                        ReadRCChannelsResponseFrame f = new ReadRCChannelsResponseFrame(address);
399
                        int numberOfChannels = base64InputStream.readByte();
400
                        f.setNumberOfChannels(numberOfChannels);
401
                        f.setChannels(base64InputStream.readSignedWords(numberOfChannels));
402
                        result = f;
403
                        break;
404
                }
1563 - 405
                case 'S': {
1611 - 406
                        WriteParamSetResponseFrame f = new WriteParamSetResponseFrame(address);
1563 - 407
                        f.setParameterSetNumber(base64InputStream.readByte());
408
                        result = f;
409
                        break;
410
                }
411
                case 'T': {
412
                        MotorTestResponseFrame f = new MotorTestResponseFrame(address);
413
                        result = f;
414
                        break;
415
                }
416
                /*
417
                 * We have a collision with the 'x' token: Also used for VariablesRequest.
418
                case 'x': {
419
                        LoopbackTestResponseFrame f = new LoopbackTestResponseFrame(address);
420
                        f.setByte(getDataInputStream().readByte());
421
                        f.setWord(getDataInputStream().readWord());
422
                        f.setChararray(getDataInputStream().readChars(8));
423
                        result = f;
424
                        break;
425
                }
426
            */
427
                case 'V': {
428
                        VersionResponseFrame f = new VersionResponseFrame(address);
429
                        f.setSWMajor(base64InputStream.readByte());
430
                        f.setSWMinor(base64InputStream.readByte());
431
                        f.setProtoMajor(base64InputStream.readByte());
432
                        f.setProtoMinor(base64InputStream.readByte());
433
                        f.setSWPatch(base64InputStream.readByte());
434
                        f.setHardwareErrors(base64InputStream.readBytes(5));
435
                        result = f;
436
                        break;
437
                }
438
 
439
                // This is my own creation. The ID collides with the waypoint one of FC.
440
                case 'X': {
1688 - 441
                        ReadVariablesResponseFrame f = new ReadVariablesResponseFrame(address);
1631 - 442
                        f.setVariables(base64InputStream.readSignedWords(8));
1563 - 443
                        result = f;
444
                        break;
445
                }
446
                case 'w': {
447
                        SetCompassHeadingResponseFrame f = new SetCompassHeadingResponseFrame(address);
448
                        // do stuff.
449
                        /*
450
                        ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
451
                        ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
452
                        ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
453
                        ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
454
                        ToMk3Mag.CalState = compassCalState;
455
                        */
456
                        // Waste 8 bytes to make CRC match.
457
                        base64InputStream.readBytes(8);
458
                        result = f;
459
                        break;
460
                }
461
                case 'Q':
1611 - 462
                        ReadParamSetResponseFrame f = new ReadParamSetResponseFrame(address);
1563 - 463
                        f.setConfigurationSetNumber(base64InputStream.readByte());
464
                        f.setConfigurationVersion(base64InputStream.readByte());
465
                        int length = base64InputStream.readByte();
1601 - 466
                        f.setConfigurationSetLength(length);
1563 - 467
                        f.setData(base64InputStream.readBytes(length));
468
                        result = f;
469
                        break;
470
                default:
471
                        int count = 0;
1573 - 472
                        while(read() != '\r') {
1563 - 473
                                count++;
474
                        }
475
                        System.err.println("Unknown frame " + (char)iid + " received from " + address);
476
                        System.err.println("It appears to have " + (count-2) + " data bytes (encoded)");
477
                        System.err.println("(" + (count-2) * 6/8 + " data bytes decoded)");
478
                        result = null;
479
                }
480
 
481
                int receivedCRC = (read() - '=') << 6;
482
                receivedCRC += (read() - '=');
483
                crc %= 4096;
484
                if (receivedCRC != crc) {
485
                        /// System.err.println("Expected CRC: " + crc + ", got CRC: " + receivedCRC);
486
                        throw new IOException("CRC mismatch! Calculated crc: " + (int)crc + "; received check crc: " + receivedCRC + ", difference: " + Math.abs(crc - receivedCRC));
487
                }
488
                if (read() != '\r') {
489
                        throw new IOException("CR at end of frame missing");
490
                }
491
 
492
                return result;
493
        }
494
}