Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 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
 *
7
 * see README for further Infos
8
 *
9
 *
10
 *******************************************************************************************************************************/
11
 
12
import javax.microedition.io.*;
13
import java.io.*;
14
 
15
public class MKCommunicator
16
   implements Runnable
17
{
18
    /***************** Section: public Attributes **********************************************/
19
    public boolean connected=false; // flag for the connection state
20
    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.
21
 
22
 
23
    public String mk_url=""; // buffer the url which is given in the constuctor for reconnectin purposes
24
 
25
    public MKLCD LCD;
26
    public MKVersion version;
27
    public MKDebugData debug_data;
28
    public MKParamsParser params;
29
    public MKWatchDog watchdog;
30
    public MKProxy proxy=null;
31
 
32
    public long connection_start_time=-1;
33
 
34
 
35
    /****************** Section: private Attributes **********************************************/
36
    private javax.microedition.io.StreamConnection connection;
37
    private java.io.InputStream reader;    
38
    private java.io.OutputStream writer;    
39
 
40
 
41
    // temp - to be removed
42
    String p_msg="--";
43
    public String msg="BT_INIT";
44
 
45
    public int debug_data_count=0;
46
    public int version_data_count=0;
47
    public int other_data_count=0;
48
    public int lcd_data_count=0;
49
    public int params_data_count=0;
50
 
51
 
52
 
53
    String name;
54
    DUBwise root;
55
 
56
    /******************  Section: public Methods ************************************************/
57
    public MKCommunicator(DUBwise root_)  
58
    {
59
        root=root_;
60
        version=new MKVersion();
61
        debug_data=new MKDebugData();
62
        params=new MKParamsParser();
63
        LCD= new MKLCD(this);
64
        watchdog=new MKWatchDog(this);
65
        new Thread( this ).start(); // fire up main Thread 
66
    }
67
 
68
 
69
    public void do_proxy(String proxy_url)
70
    {
71
        proxy=new MKProxy(proxy_url);
72
    }
73
 
74
    //  URL string: "btspp://XXXXXXXXXXXX:1" - the X-Part is the MAC-Adress of the Bluetooth-Device connected to the Fligth-Control
75
    public void connect_to(String _url,String _name)
76
    {
77
        mk_url=_url; // remember URL for connecting / reconnecting later
78
        name=_name;
79
        force_disconnect=false;
80
        connected=false;
81
    }
82
 
83
    /******************  Section: private Methods ************************************************/
84
    private void connect()
85
    {
59 ligi 86
        System.out.println("trying to connect to" + mk_url);
4 ligi 87
        try{
59 ligi 88
                connection = (StreamConnection) Connector.open(mk_url);
89
                // old call
90
                // connection = (StreamConnection) Connector.open(mk_url, Connector.READ_WRITE);
4 ligi 91
                reader=connection.openInputStream();
92
                writer=connection.openOutputStream();
93
 
94
                connection_start_time=System.currentTimeMillis();
95
                connected=true; // if we get here everything seems to be OK
96
                get_version();
97
                lcd_data_count=0;
98
                debug_data_count=0;
99
                version_data_count=0;
100
 
101
 
102
           }
103
        catch (Exception ex)
104
            {
105
                // TODO difference fatal errors from those which will lead to reconnection
106
                msg="Problem connecting" + "\n" + ex;
59 ligi 107
                System.out.println("problem connecting " + ex);
4 ligi 108
            }  
109
 
110
 
111
 
112
    }
113
 
114
 
115
 
116
    public int[] Decode64(int[] in_arr, int offset,int len)
117
    {
118
        int ptrIn=offset;      
119
        int a,b,c,d,x,y,z;
120
        int ptr=0;
121
 
122
        int[] out_arr=new int[len];
123
 
124
        while(len!=0)
125
            {
126
                a = in_arr[ptrIn++] - '=';
127
                b = in_arr[ptrIn++] - '=';
128
                c = in_arr[ptrIn++] - '=';
129
                d = in_arr[ptrIn++] - '=';
130
                //if(ptrIn > max - 2) break;     // nicht mehr Daten verarbeiten, als empfangen wurden
131
 
132
                x = (a << 2) | (b >> 4);
133
                y = ((b & 0x0f) << 4) | (c >> 2);
134
                z = ((c & 0x03) << 6) | d;
135
 
136
                if((len--)!=0) out_arr[ptr++] = x; else break;
137
                if((len--)!=0) out_arr[ptr++] = y; else break;
138
                if((len--)!=0) out_arr[ptr++] = z; else break;
139
            }
140
 
141
        return out_arr;
142
 
143
    }
144
 
145
    // FC - Function Mappers
146
 
147
    // send a version Request to the FC - the reply to this request will be processed in process_data when it arrives
148
    public void get_version()
149
    {
150
        send_command(0,'v',new int[0]);
151
    }
152
 
153
    // send a MotorTest request - params are the speed for each Motor
154
    public void motor_test(int[] params)
155
    {
156
        send_command(0,'t',params);
157
    }
158
 
159
    public void send_keys(int[] params)
160
    {
161
        send_command(0,'k',params);
162
    }
163
 
164
    // get params
165
    public void get_params(int id)
166
    {
167
        int[] params=new int[1];
168
        params[0]=id;
169
 
170
        while(sending)
171
            {try { Thread.sleep(50); }
172
            catch (Exception e)  {   }
173
            }
174
 
175
        send_command(0,'q',params);
176
    }
177
 
178
 
179
    public void get_debug_name(int id)
180
    {
181
        int[] params=new int[1];
182
        params[0]=id;
183
 
184
        while(sending)
185
            {try { Thread.sleep(50); }
186
            catch (Exception e)  {   }
187
            }
188
 
189
        send_command(0,'a',params);
190
    }
191
 
192
 
193
 
194
 
195
   public void trigger_LCD(int key)
196
    {
197
        if (sending) return;
198
 
199
 
200
        int[] params=new int[3];
201
        params[0]=key;
202
        params[1]=0;
203
        params[2]=0;
204
 
205
        send_command(0,'h',params);
206
 
207
    }
208
 
209
 
210
    public void write_params()
211
    {
212
        while(sending)
213
            {try { Thread.sleep(50); }
214
            catch (Exception e)  {   }
215
            }
216
 
217
        send_command(0,(char)('l'+params.act_paramset),params.field[params.act_paramset]);
218
    }
219
 
220
 
221
    boolean sending=false;
222
 
223
    // send command to FC ( add crc and pack into pseudo Base64
224
    public void send_command(int modul,char cmd,int[] params)
225
    {
226
        sending=true;
227
        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
228
        send_buff[0]='#';
229
        send_buff[1]=(char)modul;
230
        send_buff[2]=cmd;
231
 
232
        for(int param_pos=0;param_pos<(params.length/3 + (params.length%3==0?0:1)) ;param_pos++)
233
            {
234
                int a = (param_pos*3<params.length)?params[param_pos*3]:0;
235
                int b = ((param_pos*3+1)<params.length)?params[param_pos*3+1]:0;
236
                int c = ((param_pos*3+2)<params.length)?params[param_pos*3+2]:0;
237
 
238
                send_buff[3+param_pos*4] =  (char)((a >> 2)+'=' );
239
                send_buff[3+param_pos*4+1] = (char)('=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4)));
240
                send_buff[3+param_pos*4+2] = (char)('=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6)));
241
                send_buff[3+param_pos*4+3] = (char)('=' + ( c & 0x3f));
242
 
243
                //send_buff[3+foo]='=';
244
            }
245
 
246
/*      for(int foo=0;foo<(params.length/3 + (params.length%3==0?0:1) )*4;foo++)
247
            {
248
                int a = (foo<params.length) params[foo];
249
                int a = params[foo];
250
 
251
                //send_buff[3+foo]='=';
252
            }
253
*/
254
        try
255
            {
256
                int tmp_crc=0;
257
                for ( int tmp_i=0; tmp_i<send_buff.length;tmp_i++)
258
                    {
259
                        tmp_crc+=(int)send_buff[tmp_i];
260
                        writer.write(send_buff[tmp_i]);
261
                    }
262
                tmp_crc%=4096;
263
                writer.write( (char)(tmp_crc/64 + '='));
264
                writer.write( (char)(tmp_crc%64 + '='));
265
                writer.write('\r');
266
                writer.flush();
267
            }
268
        catch (Exception e)
269
            { // problem sending data to FC
270
            }
271
 
272
        sending=false;
273
    }
274
 
275
 
276
    public void process_data(int[] data,int len)
277
    {
278
        int[] decoded_data;
279
 
280
 
281
        switch((char)data[2])
282
            {
283
 
284
            case 'D': // debug Data
285
                debug_data_count++;
286
                debug_data.set_by_mk_data(Decode64(data,3,len-3),version);
287
                break;
288
 
289
            case 'A': // debug Data Names
290
                //debug_data_count++;
291
                debug_data.set_names_by_mk_data(data[1]-'0',Decode64(data,3,len-3));
292
                break;
293
 
294
            case 'V': // Version Info
295
                version_data_count++;
296
                version.set_by_mk_data(Decode64(data,3,6));
297
                break;
298
 
299
            case '0':
300
            case '1':
301
            case '2':
302
            case '3':
303
                LCD.handle_lcd_data(Decode64(data,3,20),data[2]-(int)'0');
304
                lcd_data_count++;
305
                break;
306
 
307
            case 'L':
308
            case 'M':
309
            case 'N':
310
            case 'O':
311
            case 'P':
312
                params.set_by_mk_data((int)(data[2]-'L'),Decode64(data,3,len-3),version);
313
                params_data_count++;
314
                break;
315
 
316
            default:
317
                other_data_count++;
318
                break;
319
 
320
            }
321
 
322
 
323
 
324
 
325
    }
326
 
327
    String o_msg="";
328
 
329
    public boolean force_disconnect=true;
330
 
331
    public void close_connections(boolean force)
332
    {
70 ligi 333
        if ((!force)&&root.canvas.do_vibra) root.vibrate(500);
4 ligi 334
        force_disconnect=force;
335
        try{ reader.close(); }
336
        catch (Exception inner_ex) { }
337
 
338
        try{ writer.close(); }
339
        catch (Exception inner_ex) { }
340
 
341
        try{ connection.close(); }
342
        catch (Exception inner_ex) { }
343
 
344
        connected=false;
345
    }
346
 
347
    // Thread to recieve data from Connection
348
    public void run()
349
    {
350
        int[] data_set=new int[150];
351
        int input;
352
        int pos=0;
353
        msg+="!!run started!!";
354
        while(true)
355
            {
356
            if (!connected)
357
                {
358
                   if (!force_disconnect) connect();
359
                }
360
            else
361
                try{
362
 
363
                    pos=0;
364
                    input=0;
365
                    // recieve data-set
366
                    while ((input != 13)) // &&(input!=-1))
367
                       {
368
 
369
                           input = reader.read() ;
370
                           if (proxy!=null)
371
                               proxy.writer.write(input);
372
                           if (input==-1) throw new Exception("test");
373
                           data_set[pos]=input;
374
                           pos++;
375
 
376
                       }
377
 
378
                           if (proxy!=null)
379
                               {
380
                                proxy.writer.write('\r');
381
                                proxy.writer.write('\n');
382
                                proxy.writer.flush();
383
                               }
384
 
385
                    process_data(data_set,pos);
386
 
387
                   }
388
        catch (Exception ex)
389
            {
390
                msg="Problem reading from MK";
391
                // close the connection 
392
                close_connections(false);
393
 
394
 
395
            }  
396
 
397
            // sleep a bit to get someting more done
398
            try { Thread.sleep(50); }
399
            catch (Exception e)  {   }
400
 
401
            } // while
402
 
403
 
404
    } // run()
405
 
406
 
407
}