Subversion Repositories FlightCtrl

Compare Revisions

Ignore whitespace Rev 193 → Rev 208

/branches/ligi_j2me/README
1,47 → 1,76
/*********************************************************************************************************************************
* *
* Project to Communicate via J2ME and Bluetooth with the FlightCtrl of the MikroKopter Project (www.mikrokopter.de ) *
* *
* Author: Marcus -LiGi- Bueschleb *
* Project-Start: 9/2007 *
* Version: 0.11 *
* Mailto: ligi@smart4mobile.de *
* Licence: Creative Commons / Non Commercial / Share Alike ( http://creativecommons.org/licenses/by-nc-sa/2.0/de/) *
* Big Up: Holger&Ingo *
* ChangeLog: *
* 0.01 - initial Version ( initialize connection / main Thread with reading data from MK) *
* 0.02 - reconnect after connection loss ( e.g. switching on/off ) *
* 0.03 - added send_command ( with CRC ) *
* 0.04 - added decode64 to decode 'pseudo' BASE64 *
* 0.05 - added get_version *
* 0.06 - added parsing of DebugData *
* 0.07 - Code-(Doc&&Cleanup) && initial svn commit *
* 0.08 - Initial README / ToDo List *
* 0.09 - implemented BTScanner for detecting BT-Devices ( No hard mac anymore for first public bin) *
* 0.10 - initial MKMinimalMidlet / Canvas *
* 0.11 - 1st public binary ( JAR/JAD) *
* 0.12 - measure Uptime ( like that word for MK being in Air ;-) *
* 0.14 - measure idling mixture *
* 0.15 - Fixed Nokia Problem 2 instead of 2.0 .. *
* *
*********************************************************************************************************************************/
/*************************************************************************************************
*
* Project to Communicate via J2ME and Bluetooth with a MikroKopter (www.mikrokopter.de )
*
*
* Author: Marcus -LiGi- Bueschleb
* Project-Start: 9/2007
* Version: 0.17
* Mailto: ligi@smart4mobile.de
*
* Licence: http://creativecommons.org/licenses/by-nc-sa/2.0/de/
* (Creative Commons / Non Commercial / Share Alike)
* Big Up: Holger&Ingo
*
* ChangeLog:
* 0.01 - initial Version ( initialize connection / main Thread with reading data from MK)
* 0.02 - reconnect after connection loss ( e.g. switching on/off )
* 0.03 - added send_command ( with CRC )
* 0.04 - added decode64 to decode 'pseudo' BASE64
* 0.05 - added get_version
* 0.06 - added parsing of DebugData
* 0.07 - Code-(Doc&&Cleanup) && initial svn commit
* 0.08 - Initial README / ToDo List
* 0.09 - implemented BTScanner for detecting BT-Devices (No hard mac anymore for first public bin)
* 0.10 - initial MKMinimalMidlet / Canvas
* 0.11 - 1st public binary ( JAR/JAD)
* 0.12 - measure Uptime ( like that word for MK being in Air ;-)
* 0.14 - measure idling mixture
* 0.15 - Fixed Nokia Problem 2 instead of 2.0 ..
* 0.16 - LCD implementation & polishing code on serveral places
* 0.17 - Quit via * | Rescan via #
* 0.18 - Remember URL ( bt-mac ) on quit
*
* Online Link to this Document:
* http://mikrocontroller.cco-ev.de/mikroviewvc/FlightCtrl/branches/ligi_j2me/README?view=markup
*
*************************************************************************************************/
 
Install:
If u know how to handle JAR/JADs take the ones from the bin directory. If u dont visit http://www.getjar.com/products/12587/MKMiniMidlet
- If u know how to handle JAR/JADs take the ones from the bin directory.
- If u dont visit http://www.getjar.com/products/12587/MKMiniMidlet
 
Compile:
- download and install ANT
- you need to download SUNs Wireless Toolkit(WTK) - set the path to it in build.xml
- install some tools to fullfill Compile-Dependencys ( see below )
- Set the path to WTK it in build.xml
- execute $> ant build
- the JAR and JAD will appear in build/bin when success
* see http://forum.mikrokopter.de/topic-post15829.html#post15829 for Hints on Compiling on Windows
 
Dependencys:
The Phone needs the Bluetooth API and MIDP 2.0 .
The MK needs a Bluetooth-Modul - http://mikrokopter.de/ucwiki/F2M03GXA?action=show
Run:
- The Phone needs the Bluetooth API and MIDP 2.0 .
- The MK needs a Bluetooth-Modul - http://mikrokopter.de/ucwiki/F2M03GXA?action=show
Compile:
- WTK ( 2.2 proven to work - please test with newer )
- Obfuscator (e.g. Proguard from http://sourceforge.net/project/showfiles.php?group_id=54750
) when willing to obfuscate
- ANT
Usage:
KEY 1..X to select device
KEY UP to go Page up in MK-LCD
KEY DOWN to go Page up in MK-LCD
KEY # to Rescan
KEY * to Quit
 
Tested on:
SE - K800i
 
Nokia 6234
Nokia N80 ( Font is too Big - but API worx)
6230i ( without copter )
N95 ( without copter )
ToDo:
- Proxying to TCP/IP ( GPRS / UMTS / WLAN ( e.g. N80) .. )
- measure DebugSets per Second
/branches/ligi_j2me/bin/midp2_minimal/MKMiniMidlet.jad
1,7 → 1,7
MIDlet-Jar-URL: MKMiniMidlet.jar
MIDlet-Jar-Size: 6665
MIDlet-Jar-Size: 8234
MIDlet-Name: MKMiniMidlet
MIDlet-Vendor: LiGi
MIDlet-Version: 0.15
MIDlet-Version: 0.18
MIDlet-1: MKMiniMidlet, , MKMiniMidlet
MIDletX-No-Command: true
/branches/ligi_j2me/bin/midp2_minimal/MKMiniMidlet.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/ligi_j2me/build.xml
23,7 → 23,7
manifest="${build_dir}/bin/MANIFEST.MF"
name="${project_name}"
vendor="LiGi"
version="0.15">
version="0.18">
<attribute name="MIDletX-No-Command" value="true"/>
 
<midlet name="${project_name}" class="${project_name}" />
/branches/ligi_j2me/src/BTSearcher.java
28,20 → 28,37
 
public final int MAX_DEVICES=10;
 
public RemoteDevice[] remote_devices;
 
public int remote_device_count=0;
public String[] remote_device_name;
public String[] remote_device_mac;
 
 
public void search_again()
{
try
{
remote_device_count=0;
searching=true;
m_DscrAgent.startInquiry(DiscoveryAgent.GIAC,this);
}
catch (BluetoothStateException ex)
{
error=true;
err_log+="Problem in searching the blue tooth devices\n" + ex;
}
 
}
 
public BTSearcher()
{
 
remote_devices=new RemoteDevice[MAX_DEVICES];
remote_device_name=new String[MAX_DEVICES];
remote_device_mac=new String[MAX_DEVICES];
 
remote_device_count=0;
 
try
{
//First get the local device and obtain the discovery agent.
48,7 → 65,6
m_LclDevice = LocalDevice.getLocalDevice();
m_DscrAgent= m_LclDevice.getDiscoveryAgent();
m_DscrAgent.startInquiry(DiscoveryAgent.GIAC,this);
}
catch (BluetoothStateException ex)
{
56,24 → 72,13
err_log+="Problem in searching the blue tooth devices\n" + ex;
}
search_again();
}
 
 
public void inquiryCompleted(int transID) {
 
try {
for(int i=0;i<remote_device_count;i++)
{
remote_device_name[i]=remote_devices[i].getFriendlyName(true);
remote_device_mac[i]=remote_devices[i].getBluetoothAddress();
 
}
}
catch (Exception e)
{
err_log+="Problem in searching the blue tooth devices";
}
searching=false;
}
 
85,7 → 90,9
{
if (remote_device_count!=(MAX_DEVICES-1))
{
remote_devices[remote_device_count]=btDevice;
 
remote_device_name[remote_device_count]=btDevice.getFriendlyName(true);
remote_device_mac[remote_device_count]=btDevice.getBluetoothAddress();
remote_device_count++;
}
}
/branches/ligi_j2me/src/MKCommunicator.java
37,8 → 37,9
public int version_major=-1;
public int version_minor=-1;
public int version_compatible=-1;
 
public MKLCD LCD;
 
public long connection_start_time=-1;
 
52,12 → 53,16
String p_msg="--";
public String msg="BT_INIT";
 
public int data_count=0;
public int debug_data_count=0;
public int version_data_count=0;
public int other_data_count=0;
public int lcd_data_count=0;
 
 
/****************** Section: public Methods ************************************************/
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
{
 
debug_data=new MKDebugData();
mk_url=url; // remember URL for connecting / reconnecting later
 
76,6 → 81,7
connection_start_time=System.currentTimeMillis();
connected=true; // if we get here everything seems to be OK
get_version();
LCD= new MKLCD(this);
}
catch (Exception ex)
{
125,6 → 131,7
send_command(0,'v',new int[0]);
}
 
 
// send command to FC ( add crc and pack into pseudo Base64
public void send_command(int modul,char cmd,int[] params)
{
133,6 → 140,28
send_buff[1]=(char)modul;
send_buff[2]=cmd;
for(int param_pos=0;param_pos<(params.length/3 + (params.length%3==0?0:1)) ;param_pos++)
{
int a = (param_pos<params.length)?params[param_pos]:0;
int b = ((param_pos+1)<params.length)?params[param_pos+1]:0;
int c = ((param_pos+2)<params.length)?params[param_pos+2]:0;
 
send_buff[3+param_pos*4] = (char)((a >> 2)+'=' );
send_buff[3+param_pos*4+1] = (char)('=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4)));
send_buff[3+param_pos*4+2] = (char)('=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6)));
send_buff[3+param_pos*4+3] = (char)('=' + ( c & 0x3f));
 
//send_buff[3+foo]='=';
}
 
/* for(int foo=0;foo<(params.length/3 + (params.length%3==0?0:1) )*4;foo++)
{
int a = (foo<params.length) params[foo];
int a = params[foo];
//send_buff[3+foo]='=';
}
*/
try
{
int tmp_crc=0;
165,10 → 194,9
case 'D': // debug Data
decoded_data=Decode64(data,3,50);
debug_data=new MKDebugData(decoded_data);
msg="Got Debug Data s:" + debug_data.sekunden + "zy:"+debug_data.zyklen + "ze:" + debug_data.zeit + connected + ">" + data_count;
for (int ff=0;ff<8;ff++)
msg+="\n d:" + (ff*2+1) + " " + debug_data.analog[ff*2] + " d2:" + (ff*2+2) + " " + debug_data.analog[ff*2+1] ;
 
debug_data_count++;
break;
case 'V': // Version Info
176,24 → 204,53
version_major=decoded_data[0];
version_minor=decoded_data[1];
version_compatible=decoded_data[2];
version_data_count++;
break;
case '0':
case '1':
case '2':
case '3':
LCD.handle_lcd_data(Decode64(data,3,20),data[2]-(int)'0');
lcd_data_count++;
// decoded_data=
 
// if ((data[2]-(int)'0')!=3)
// get_LCD();
break;
 
default:
other_data_count++;
break;
 
}
 
 
msg+=p_msg;
msg+="OK";
data_count++;
 
}
 
String o_msg="";
 
public boolean force_disconnect=false;
 
public void close_connections()
{
force_disconnect=true;
try{ reader.close(); }
catch (Exception inner_ex) { }
 
try{ writer.close(); }
catch (Exception inner_ex) { }
try{ connection.close(); }
catch (Exception inner_ex) { }
connected=false;
}
 
// Thread to recieve data from Connection
public void run()
{
205,7 → 262,7
{
if (!connected)
{
connect();
if (!force_disconnect) connect();
}
else
try{
228,9 → 285,9
{
msg="Problem reading from MK";
// close the connection
try{ reader.close(); connection.close(); }
catch (Exception inner_ex) { }
connected=false;
close_connections();
 
 
}
// sleep a bit to get someting more done
/branches/ligi_j2me/src/MKDebugData.java
14,44 → 14,32
 
{
 
int[] digital;
int zyklen;
int zeit;
int sekunden;
int[] analog;
public int[] analog;
public int motor_complete=-1;
 
public MKDebugData()
private int i;
 
public int motor_val(int id) { return analog[12+id]; }
 
 
public MKDebugData()
{
digital=new int[13];
analog=new int[16];
int i;
for (i=0;i<13;i++)
digital[i]=-1;
zyklen=-1;
zeit= -1;
sekunden= -1;
 
for (i=0;i<16;i++)
analog[i]=-1;
 
}
 
public MKDebugData(int[] in_arr)
public MKDebugData(int[] in_arr) // MKVersion
{
digital=new int[13];
analog=new int[16];
int i;
for (i=0;i<13;i++)
digital[i]=in_arr[i];
zyklen= in_arr[13] << 8 | in_arr[14] ;
zeit= in_arr[14] << 8 | in_arr[15] ;
sekunden= in_arr[16] ;
 
analog=new int[32];
 
for (i=0;i<16;i++)
analog[i]=(in_arr[17+i*2]<<8) | in_arr[18+i*2];
 
motor_complete=motor_val(0)+motor_val(1)+motor_val(2)+motor_val(3);
}
 
 
/branches/ligi_j2me/src/MKMiniCanvas.java
10,6 → 10,7
*********************************************************************************************************************************/
 
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
 
public class MKMiniCanvas
extends Canvas
16,30 → 17,46
implements Runnable
{
 
int vibrating=0;
private BTSearcher bt_scanner;
private MKCommunicator mk=null;
private MKStatistics mk_stat=null;
private String err="";
private MKMiniMidlet root;
 
//BTAbstractor bt;
BTSearcher bt_scanner;
MKCommunicator mk=null;
MKStatistics mk_stat=null;
public MKMiniCanvas(MKMiniMidlet _root)
{
root=_root;
 
// data Section
// mk = new MKCommunicator("btspp://000BCE016B5B:1");
//connect_mk("btspp://000BCE016B4F:1");
 
public String err="";
try
{
RecordStore recStore = RecordStore.openRecordStore("bturl", true );
 
if (recStore.getNumRecords()==1)
{
byte[] recData = new byte[recStore.getRecordSize(1)];
int len = recStore.getRecord(1, recData, 0);
rescan=false;
connect_mk(new String(recData, 0, len));
}
}
catch (Exception e)
{
err+=e.toString();
}
 
public MKMiniCanvas()
{
if (mk==null) bt_scanner = new BTSearcher();
new Thread(this).start();
 
bt_scanner = new BTSearcher();
//////////////////////////////////////////////////////////////////////////////mk = new MKCommunicator("btspp://000BCE016B5B:1");
new Thread(this).start();
}
 
boolean quit=false;
boolean rescan=true;
 
 
/********************************************************** Thread ***********************************************************/
53,6 → 70,34
long sleeptime=0;
// ticked thing
if (quit)
{
try
{
RecordStore recStore = RecordStore.openRecordStore("bturl", true );
if (recStore.getNumRecords()==1)
recStore.deleteRecord(1);
byte[] rec = mk.mk_url.getBytes();
recStore.addRecord(rec, 0, rec.length);
 
}
catch (Exception e)
{
err+=e.toString();
}
 
root.quit();
}
if (rescan)
{
if (mk!=null) mk.close_connections();
mk=null;
bt_scanner.search_again();
}
 
rescan=false;
 
com.nokia.mid.ui.DeviceControl.setLights(0,100);
//bt.tick();
// every state has sth to do in tick section
84,6 → 129,8
 
// drawing section
public void paint(Graphics g) {
 
int spacer=(g.getFont().getHeight());
g.setColor(0xFFFFFF);
g.fillRect(0,0,this.getWidth(),this.getHeight());
g.setColor(0x000000);
96,7 → 143,7
{
g.drawString("Press key 0-"+(bt_scanner.remote_device_count-1) + " to continue" ,0,0,Graphics.TOP | Graphics.LEFT);
for (int i=0;i<bt_scanner.remote_device_count;i++)
g.drawString("#"+i+">" + bt_scanner.remote_device_name[i]+"("+bt_scanner.remote_device_mac[i]+")",0,15+15*i,Graphics.TOP | Graphics.LEFT);
g.drawString("#"+i+">" + bt_scanner.remote_device_name[i]+"("+bt_scanner.remote_device_mac[i]+")",0,spacer+spacer*i,Graphics.TOP | Graphics.LEFT);
}
}
103,12 → 150,15
else // MK is connected
{
int y_off=0;
int spacer=15;
g.drawString("#"+mk.data_count + "from:" + mk.mk_url,0,y_off,Graphics.TOP | Graphics.LEFT);
 
g.drawString("v"+mk.version_major+"."+mk.version_minor+"(d:"+mk.debug_data_count+ " l:" + mk.lcd_data_count+ " v:" + mk.version_data_count+" o:"+mk.other_data_count+")",0,y_off,Graphics.TOP | Graphics.LEFT);
 
y_off+=spacer;
g.drawString("v"+mk.version_major+"."+mk.version_minor,0,y_off,Graphics.TOP | Graphics.LEFT);
y_off+=spacer;
 
for ( int foo=0;foo<4;foo++)
{
g.drawString(mk.LCD.LCD_str[foo],0,y_off,Graphics.TOP | Graphics.LEFT);
y_off+=spacer;
}
try {
g.drawString("motor1:"+mk.debug_data.analog[12],0,y_off,Graphics.TOP | Graphics.LEFT);
y_off+=spacer;
126,6 → 176,8
g.drawString("time conn:" +((System.currentTimeMillis()- mk.connection_start_time)/1000)+"s" ,0,y_off,Graphics.TOP | Graphics.LEFT);
y_off+=spacer;
g.drawString("time motor>15:" +(mk_stat.motor_on_time/1000) +"s" ,0,y_off,Graphics.TOP | Graphics.LEFT);
y_off+=spacer;
g.drawString("time motor=15:" +(mk_stat.motor_stand_time/1000) +"s" ,0,y_off,Graphics.TOP | Graphics.LEFT);
}
 
}
132,6 → 184,12
}
 
private void connect_mk(String url)
{
mk = new MKCommunicator(url);
mk_stat= new MKStatistics(mk);
}
 
/*********************************************** input Section **********************************************/
// keys
public void keyPressed(int keyCode)
138,11 → 196,34
{
if ((mk==null)&&(keyCode >= this.KEY_NUM0) && (keyCode < this.KEY_NUM0+bt_scanner.remote_device_count))
{
mk = new MKCommunicator("btspp://"+bt_scanner.remote_device_mac[keyCode-this.KEY_NUM0] + ":1");
mk_stat= new MKStatistics(mk);
}
return;
connect_mk("btspp://"+bt_scanner.remote_device_mac[keyCode-this.KEY_NUM0] + ":1");
else
{
switch (keyCode)
{
case KEY_STAR:
mk.other_data_count=23;
quit=true;
break;
 
case KEY_POUND:
rescan=true;
break;
}
switch (getGameAction (keyCode))
{
case UP:
mk.LCD.LCD_PREVPAGE();
break;
case DOWN:
mk.LCD.LCD_NEXTPAGE();
break;
}
}
return;
}
 
/branches/ligi_j2me/src/MKMiniMidlet.java
26,7 → 26,7
 
if (loaded)return;
display = Display.getDisplay(this);
canvas=new MKMiniCanvas();
canvas=new MKMiniCanvas(this);
 
// fire up canvas
display.setCurrent(canvas);
/branches/ligi_j2me/src/MKStatistics.java
1,7 → 1,6
/*********************************************************************************************************************************
/**********************************************************************************************************************************
* Statistics from MK-Connection ( needed for 2. Thread and Readability of Code ) *
* *
* Some Statistics from MK-Connection ( needed for 2. Thread and Readability of Code ) *
* *
* Author: Marcus -LiGi- Bueschleb *
* Project-Start: 9/2007 *
* Version: 0.07 *
13,6 → 12,10
public class MKStatistics
implements Runnable
{
public long motor_on_time=-1;
public long motor_stand_time=-1;
public long motor_sum=-1;
 
MKCommunicator mk=null;
 
public MKStatistics(MKCommunicator _mk)
21,11 → 24,12
new Thread( this ).start(); // fire up main Thread
}
 
public long motor_on_time=-1;
 
 
long last_run_ms=-1;
 
private long last_run_ms=-1;
private long last_step=-1;
 
public void run()
{
while(true)
33,19 → 37,26
if (mk.connected)
{
last_step=System.currentTimeMillis()-last_run_ms;
 
if (last_run_ms!=-1)
{
if (mk.debug_data.analog[14]>15)
motor_on_time+=System.currentTimeMillis()-last_run_ms;
 
if (mk.debug_data.motor_complete>0)
motor_sum+=mk.debug_data.motor_complete;
if (mk.debug_data.motor_complete>60)
motor_on_time+=last_step;
if (mk.debug_data.motor_complete==60)
motor_stand_time+=last_step;
}
last_run_ms=System.currentTimeMillis();
}
else
{
last_run_ms=-1;
motor_on_time=-1;
motor_stand_time=-1;
}
try { Thread.sleep(500); }
catch (Exception e) { }