Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
164 | ligi | 1 | /********************************************************************************************************************************* |
2 | * * |
||
3 | * Abstaction Layer to Communicate via J2ME and Bluetooth with the FlightCtrl of the MikroKopter Project (www.mikrokopter.de ) * |
||
4 | * * |
||
5 | * Author: Marcus -LiGi- Bueschleb * |
||
6 | * Project-Start: 9/2007 * |
||
7 | * Version: 0.07 * |
||
8 | * Mailto: ligi@smart4mobile.de * |
||
9 | * Licence: Creative Commons / Non Commercial * |
||
10 | * Big Up: Holger&Ingo * |
||
11 | * ChangeLog: * |
||
12 | * 0.01 - initial Version ( initialize connection / main Thread with reading data from MK) * |
||
13 | * 0.02 - reconnect after connection loss ( e.g. switching on/off ) * |
||
14 | * 0.03 - added send_command ( with CRC ) * |
||
15 | * 0.04 - added decode64 to decode 'pseudo' BASE64 * |
||
16 | * 0.05 - added get_version * |
||
17 | * 0.06 - added parsing of DebugData * |
||
18 | * 0.07 - Code-(Doc&&Cleanup) && initial svn commit * |
||
19 | * * |
||
20 | *********************************************************************************************************************************/ |
||
21 | |||
22 | import javax.microedition.io.*; |
||
23 | import java.io.*; |
||
24 | |||
25 | public class MKCommunicator |
||
26 | implements Runnable |
||
27 | { |
||
28 | /***************** Section: public Attributes **********************************************/ |
||
29 | public boolean connected=false; // flag for the connection state |
||
30 | public boolean fatal=false; // flag which is set when an error is so fatal that reconnecting won't be tried - e.g. unknown version number. |
||
31 | |||
32 | |||
33 | public String mk_url=""; // buffer the url which is given in the constuctor for reconnectin purposes |
||
34 | |||
35 | |||
36 | |||
37 | // version Info from Flight Control |
||
38 | public int version_major=-1; |
||
39 | public int version_minor=-1; |
||
40 | public int version_compatible=-1; |
||
41 | |||
42 | |||
43 | |||
44 | |||
45 | /****************** Section: private Attributes **********************************************/ |
||
46 | private javax.microedition.io.StreamConnection connection; |
||
47 | private java.io.InputStream reader; |
||
48 | private java.io.OutputStream writer; |
||
49 | |||
50 | |||
51 | // temp - to be removed |
||
52 | String p_msg="--"; |
||
53 | public String msg="BT_INIT"; |
||
54 | |||
55 | int data_count=0; |
||
56 | |||
57 | |||
58 | /****************** Section: public Methods ************************************************/ |
||
59 | public MKCommunicator(String url) // Constructor with URL string e.g. "btspp://XXXXXXXXXXXX:1" - the X-Part is the MAC-Adress of the Bluetooth-Device connected to the Fligth-Control |
||
60 | { |
||
61 | mk_url=url; // remember URL for connecting / reconnecting later |
||
62 | new Thread( this ).start(); // fire up main Thread |
||
63 | } |
||
64 | |||
65 | |||
66 | /****************** Section: private Methods ************************************************/ |
||
67 | private void connect() |
||
68 | { |
||
69 | try{ |
||
70 | connection = (StreamConnection) Connector.open(mk_url, Connector.READ_WRITE); |
||
71 | reader=connection.openInputStream(); |
||
72 | writer=connection.openOutputStream(); |
||
73 | connected=true; // if we get here everything seems to be OK |
||
74 | } |
||
75 | catch (Exception ex) |
||
76 | { |
||
77 | // TODO difference fatal errors from those which will lead to reconnection |
||
78 | msg="Problem connecting" + "\n" + ex; |
||
79 | } |
||
80 | |||
81 | get_version(); |
||
82 | } |
||
83 | |||
84 | |||
85 | |||
86 | public int[] Decode64(int[] in_arr, int offset,int len) |
||
87 | { |
||
88 | int ptrIn=offset; |
||
89 | int a,b,c,d,x,y,z; |
||
90 | int ptr=0; |
||
91 | |||
92 | int[] out_arr=new int[len]; |
||
93 | |||
94 | while(len!=0) |
||
95 | { |
||
96 | a = in_arr[ptrIn++] - '='; |
||
97 | b = in_arr[ptrIn++] - '='; |
||
98 | c = in_arr[ptrIn++] - '='; |
||
99 | d = in_arr[ptrIn++] - '='; |
||
100 | //if(ptrIn > max - 2) break; // nicht mehr Daten verarbeiten, als empfangen wurden |
||
101 | |||
102 | x = (a << 2) | (b >> 4); |
||
103 | y = ((b & 0x0f) << 4) | (c >> 2); |
||
104 | z = ((c & 0x03) << 6) | d; |
||
105 | |||
106 | if((len--)!=0) out_arr[ptr++] = x; else break; |
||
107 | if((len--)!=0) out_arr[ptr++] = y; else break; |
||
108 | if((len--)!=0) out_arr[ptr++] = z; else break; |
||
109 | } |
||
110 | |||
111 | return out_arr; |
||
112 | |||
113 | } |
||
114 | |||
115 | |||
116 | // send a version Request to the FC - the reply to this request will be processed in process_data when it arrives |
||
117 | public void get_version() |
||
118 | { |
||
119 | send_command(0,'v',new int[0]); |
||
120 | } |
||
121 | |||
122 | // send command to FC ( add crc and pack into pseudo Base64 |
||
123 | public void send_command(int modul,char cmd,int[] params) |
||
124 | { |
||
125 | char[] send_buff=new char[5 + (params.length/3 + (params.length%3==0?0:1) )*4]; // 5=1*start_char+1*addr+1*cmd+2*crc |
||
126 | send_buff[0]='#'; |
||
127 | send_buff[1]=(char)modul; |
||
128 | send_buff[2]=cmd; |
||
129 | |||
130 | try |
||
131 | { |
||
132 | int tmp_crc=0; |
||
133 | for ( int tmp_i=0; tmp_i<send_buff.length;tmp_i++) |
||
134 | { |
||
135 | tmp_crc+=(int)send_buff[tmp_i]; |
||
136 | writer.write(send_buff[tmp_i]); |
||
137 | } |
||
138 | tmp_crc%=4096; |
||
139 | writer.write( (char)(tmp_crc/64 + '=')); |
||
140 | writer.write( (char)(tmp_crc%64 + '=')); |
||
141 | writer.write('\r'); |
||
142 | writer.flush(); |
||
143 | } |
||
144 | catch (Exception e) |
||
145 | { // problem sending data to FC |
||
146 | } |
||
147 | |||
148 | } |
||
149 | |||
150 | MKDebugData debug_data; |
||
151 | public void process_data(int[] data,int len) |
||
152 | { |
||
153 | int[] decoded_data; |
||
154 | |||
155 | switch((char)data[2]) |
||
156 | { |
||
157 | |||
158 | case 'D': // debug Data |
||
159 | decoded_data=Decode64(data,3,50); |
||
160 | debug_data=new MKDebugData(decoded_data); |
||
161 | msg="Got Debug Data s:" + debug_data.sekunden + "zy:"+debug_data.zyklen + "ze:" + debug_data.zeit + connected + ">" + data_count; |
||
162 | for (int ff=0;ff<8;ff++) |
||
163 | msg+="\n d:" + (ff*2+1) + " " + debug_data.analog[ff*2] + " d2:" + (ff*2+2) + " " + debug_data.analog[ff*2+1] ; |
||
164 | |||
165 | break; |
||
166 | |||
167 | case 'V': // Version Info |
||
168 | decoded_data=Decode64(data,3,6); |
||
169 | version_major=decoded_data[0]; |
||
170 | version_minor=decoded_data[1]; |
||
171 | version_compatible=decoded_data[2]; |
||
172 | |||
173 | break; |
||
174 | |||
175 | default: |
||
176 | break; |
||
177 | |||
178 | } |
||
179 | |||
180 | |||
181 | msg+=p_msg; |
||
182 | msg+="OK"; |
||
183 | data_count++; |
||
184 | |||
185 | } |
||
186 | |||
187 | // Thread to recieve data from Connection |
||
188 | public void run() |
||
189 | { |
||
190 | int[] data_set=new int[150]; |
||
191 | int input; |
||
192 | int pos=0; |
||
193 | msg+="!!run started!!"; |
||
194 | while(true) |
||
195 | { |
||
196 | if (!connected) |
||
197 | connect(); |
||
198 | else |
||
199 | try{ |
||
200 | pos=0; |
||
201 | input=0; |
||
202 | // recieve data-set |
||
203 | while ((input != 13)) // &&(input!=-1)) |
||
204 | { |
||
205 | input = reader.read() ; |
||
206 | if (input==-1) throw new Exception("test"); |
||
207 | data_set[pos]=input; |
||
208 | pos++; |
||
209 | |||
210 | } |
||
211 | process_data(data_set,pos); |
||
212 | |||
213 | } |
||
214 | catch (Exception ex) |
||
215 | { |
||
216 | msg="Problem reading from MK"; |
||
217 | // close the connection |
||
218 | try{ reader.close(); connection.close(); } |
||
219 | catch (Exception inner_ex) { } |
||
220 | connected=false; |
||
221 | } |
||
222 | |||
223 | // sleep a bit to get someting more done |
||
224 | try { Thread.sleep(50); } |
||
225 | catch (Exception e) { } |
||
226 | |||
227 | } // while |
||
228 | |||
229 | |||
230 | } // run() |
||
231 | |||
232 | |||
233 | } |