Subversion Repositories Projects

Rev

Go to most recent revision | Details | 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;
14
import dongfang.mkt.frames.ResponseFrame;
15
import dongfang.mkt.frames.SetCompassHeadingResponseFrame;
16
import dongfang.mkt.frames.UniversalReadParamSetResponseFrame;
17
import dongfang.mkt.frames.UniversalWriteParamSetResponseFrame;
18
import dongfang.mkt.frames.VariablesResponseFrame;
19
import dongfang.mkt.frames.VersionResponseFrame;
20
import dongfang.mkt.main.UniversalConfigurator;
21
 
22
public class MKInputStream extends InputStream {
23
        int readByteCnt;
24
        class MKDataInputStream {
25
                int[] inbuf = new int[4];
26
                int[] outbuf = new int[3];
27
                int outbufptr = outbuf.length; // reset to "buffer empty"
28
 
29
                private boolean decode() throws IOException {
30
                        for (int i = 0; i < 4; i++) {
31
                                int raw = MKInputStream.this.readByte();
32
                                int in = raw - '=';
33
                                if (in < 0 || in > 63)
34
                                        return false;
35
                                        // throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");
36
                                inbuf[i] = in;
37
                                readByteCnt++;
38
                        }
39
                        outbuf[0] = (inbuf[0] << 2) | (inbuf[1] >>> 4);
40
                        outbuf[1] = ((inbuf[1] & 0x0f) << 4) | (inbuf[2] >>> 2);
41
                        outbuf[2] = ((inbuf[2] & 0x03) << 6) | inbuf[3];
42
                        outbufptr = 0;
43
                        return true;
44
                }
45
 
46
                public void reset() {
47
                        outbufptr = outbuf.length; // reset to "buffer empty"
48
                }
49
 
50
                public int readByte() throws IOException {
51
                        if (outbufptr > 2 && !decode())
52
                                        throw new IOException("Out of range data received where frame data expected. Probably the frame was shorter than expected (" + readByteCnt + ")!");            
53
                        return outbuf[outbufptr++];
54
                }
55
 
56
                public int readWord() throws IOException {
57
                        int byte2 = readByte();
58
                        int byte1 = readByte();
59
                        return (byte1 << 8) | byte2;
60
                }
61
 
62
                public int readSignedWord() throws IOException {
63
                        int word = readWord();
64
                        if (word > 32767)
65
                                word = word - 65536;
66
                        return word;
67
                }
68
 
69
                public int[] readBytes(int length) throws IOException {
70
                        int[] result = new int[length];
71
                        for (int i = 0; i < length; i++) {
72
                                result[i] = readByte();
73
                        }
74
                        return result;
75
                }
76
 
77
                public int[] readWords(int length) throws IOException {
78
                        int[] result = new int[length];
79
                        for (int i = 0; i < length; i++) {
80
                                result[i] = readWord();
81
                        }
82
                        return result;
83
                }
84
 
85
                public char[] readChars(int length) throws IOException {
86
                        char[] result = new char[length];
87
                        for (int i = 0; i < length; i++) {
88
                                // Here, a 1:1 mapping between byte values and char codes is assumed.
89
                                // That means we're assuming ISO-8859-1 (= the first 256 code points
90
                                // of Unicode, which Java uses for chars)
91
                                result[i] = (char) readByte();
92
                        }
93
                        return result;
94
                }
95
        }
96
 
97
        MKDataInputStream dis = new MKDataInputStream();
98
        OutputStream nonPacketSpillway = null; //System.err;
99
 
100
        final InputStream is;
101
        int crc;
102
 
103
        public MKInputStream(InputStream is) {
104
                this.is = is;
105
        }
106
 
107
        @Override
108
        public int read() throws IOException {
109
                int i;
110
                while ((i=is.read()) == -1);
111
                // System.out.print("Received: " + i + " (as char: " + (char)i + ")\n");
112
                return i;
113
        }
114
 
115
        public int readByte() throws IOException {
116
                int _byte = read();
117
                if (_byte < 0)
118
                        throw new IOException("End of Stream!");
119
                crc += _byte;
120
                return _byte;
121
        }
122
 
123
        public MKDataInputStream getBase64InputStream() {
124
                return dis;
125
        }
126
 
127
        public ResponseFrame getNextFrame() throws IOException {
128
                int c;
129
                while ((c = read()) != '#') {
130
                        // throw it on some scrap-text buffer.
131
                        if (nonPacketSpillway != null)
132
                                nonPacketSpillway.write(c);
133
                }
134
                crc = '#';
135
                dis.reset();
136
                int address = readByte() - 'a';
137
                int iid = readByte();
138
                readByteCnt = 0;
139
                //RESPONSE_IDS id = getResponseType(iid);
140
                ResponseFrame result;
141
                switch (iid) {
142
                case 'A': {
143
                        AnalogDebugLabelResponseFrame f = new AnalogDebugLabelResponseFrame(address);
144
                        f.setChannel(getBase64InputStream().readByte());
145
                        f.setLabel(getBase64InputStream().readChars(16));
146
                        result = f;
147
                        break;
148
                }
149
                case 'B': {
150
                        ConfirmFrame f = new ConfirmFrame(address);
151
                        f.setFrameNum(getBase64InputStream().readByte());
152
                        result = f;
153
                        break;
154
                }
155
                case 'C': {
156
                        AttitudeDataResponseFrame f = new AttitudeDataResponseFrame(address);
157
                        f.setPitch(getBase64InputStream().readSignedWord());
158
                        f.setRoll(getBase64InputStream().readSignedWord());
159
                        f.setHeading(getBase64InputStream().readSignedWord());
160
                        f.setExpansion(getBase64InputStream().readBytes(8));
161
                        result = f;
162
                        break;
163
                }
164
                case 'D': {
165
                        DebugResponseFrame f = new DebugResponseFrame(address);
166
                        for (int i=0; i<2; i++)
167
                                f.setDigital(i, getBase64InputStream().readByte());
168
                        for (int i=0; i<32; i++)
169
                                f.setAnalog(i, getBase64InputStream().readSignedWord());
170
                        result = f;
171
                        break;
172
                }
173
                case 'F': {
174
                        ChangeParameterSetResponseFrame f = new ChangeParameterSetResponseFrame(address);
175
                        f.setParameterSetNumber(getBase64InputStream().readByte());
176
                        result = f;
177
                        break;
178
                }
179
                case 'H': {
180
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
181
                        f.setLine(getBase64InputStream().readByte());
182
                        //f.setMaxItem(getDataInputStream().readByte());
183
                        f.setText(getBase64InputStream().readChars(20));
184
                        result = f;
185
                        break;
186
                }
187
                case 'L': {
188
                        AllDisplaysResponseFrame f = new AllDisplaysResponseFrame(address);
189
                        f.setItem(getBase64InputStream().readByte());
190
                        // f.setMaxItem(getDataInputStream().readByte());
191
                        f.setText(getBase64InputStream().readChars(80));
192
                        result = f;
193
                        break;
194
                }
195
                case 'S': {
196
                        UniversalWriteParamSetResponseFrame f = new UniversalWriteParamSetResponseFrame(address);
197
                        f.setParameterSetNumber(getBase64InputStream().readByte());
198
                        result = f;
199
                        break;
200
                }
201
                case 'T': {
202
                        MotorTestResponseFrame f = new MotorTestResponseFrame(address);
203
                        result = f;
204
                        break;
205
                }
206
                /*
207
                 * We have a collision with the 'x' token: Also used for VariablesRequest.
208
                case 'x': {
209
                        LoopbackTestResponseFrame f = new LoopbackTestResponseFrame(address);
210
                        f.setByte(getDataInputStream().readByte());
211
                        f.setWord(getDataInputStream().readWord());
212
                        f.setChararray(getDataInputStream().readChars(8));
213
                        result = f;
214
                        break;
215
                }
216
            */
217
                case 'V': {
218
                        VersionResponseFrame f = new VersionResponseFrame(address);
219
                        f.setSWMajor(getBase64InputStream().readByte());
220
                        f.setSWMinor(getBase64InputStream().readByte());
221
                        f.setProtoMajor(getBase64InputStream().readByte());
222
                        f.setProtoMinor(getBase64InputStream().readByte());
223
                        f.setSWPatch(getBase64InputStream().readByte());
224
                        f.setHardwareErrors(getBase64InputStream().readBytes(5));
225
                        result = f;
226
                        break;
227
                }
228
 
229
                // This is my own creation. The ID collides with the waypoint one of FC.
230
                case 'X': {
231
                        VariablesResponseFrame f = new VariablesResponseFrame(address);
232
                        f.setVariables(getBase64InputStream().readWords(8));
233
                        result = f;
234
                        break;
235
                }
236
                case 'w': {
237
                        SetCompassHeadingResponseFrame f = new SetCompassHeadingResponseFrame(address);
238
                        // do stuff.
239
                        /*
240
                        ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
241
                        ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
242
                        ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
243
                        ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
244
                        ToMk3Mag.CalState = compassCalState;
245
                        */
246
                        // Waste 8 bytes to make CRC match.
247
                        getBase64InputStream().readBytes(8);
248
                        result = f;
249
                        break;
250
                }
251
                case 'Q':
252
                        UniversalReadParamSetResponseFrame f = new UniversalReadParamSetResponseFrame(address);
253
                        f.setConfigurationSetNumber(getBase64InputStream().readByte());
254
                        f.setConfigurationVersion(getBase64InputStream().readByte());
255
                        int length = getBase64InputStream().readByte();
256
                        f.setData(getBase64InputStream().readBytes(length));
257
                        result = f;
258
                        break;
259
                default:
260
                        result = null;
261
                }
262
 
263
                int receivedCRC = (read() - '=') << 6;
264
                receivedCRC += (read() - '=');
265
                crc %= 4096;
266
                if (receivedCRC != crc) {
267
                        /// System.err.println("Expected CRC: " + crc + ", got CRC: " + receivedCRC);
268
                        throw new IOException("CRC mismatch! Calculated crc: " + (int)crc + "; received check crc: " + receivedCRC + ", difference: " + Math.abs(crc - receivedCRC));
269
                }
270
                if (read() != '\r') {
271
                        throw new IOException("CR at end of frame missing");
272
                }
273
 
274
                return result;
275
        }
276
}