/* @file TopoDroidComm.java
*
* @author marco corvi
* @date nov 2011
*
* @brief TopoDroid-DistoX BlueTooth communication
* --------------------------------------------------------
* Copyright This sowftare is distributed under GPL-3.0 or later
* See the file COPYING.
* --------------------------------------------------------
*/
package com.topodroid.DistoX;
import java.util.List;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.widget.Toast;
import android.util.Log;
public class TopoDroidComm
{
protected TopoDroidApp mApp;
protected String mAddress;
protected DistoXProtocol mProtocol;
protected boolean mCalibMode; //!< whether the device is in calib-mode
protected boolean mBTConnected;
protected static final byte CALIB_BIT = (byte)0x08;
public byte[] mCoeff;
// -----------------------------------------------------------
protected int nReadPackets;
protected boolean doWork = true;
public boolean isConnected() { return mBTConnected; }
// public void stopDoWork( ) { doWork = false; }
protected class RfcommThread extends Thread
{
private DistoXProtocol mProto;
private int toRead; // number of packet to read
// private ILister mLister;
private Handler mLister; // FIXME LISTER
private long mLastShotId; // last shot id
void cancelWork()
{
if ( mProto != null ) mProto.mMaxTimeout = 0;
doWork = false;
}
/**
* @param protocol communication protocol
* @param to_read number of data to read (use -1 to read forever until timeout or an exception)
*/
public RfcommThread( DistoXProtocol protocol, int to_read, Handler /* ILister */ lister ) // FIXME LISTER
{
nReadPackets = 0; // reset nr of read packets
toRead = to_read;
mProto = protocol;
mLister = lister;
// mLastShotId = 0;
// TDLog.Log( TDLog.LOG_COMM, "RFcommThread cstr ToRead " + toRead );
}
public void run()
{
boolean hasG = false;
doWork = true;
// TDLog.Log( TDLog.LOG_COMM, "RFcomm thread running ... to_read " + toRead );
while ( doWork && nReadPackets != toRead ) {
// TDLog.Log( TDLog.LOG_COMM, "RFcomm loop: read " + nReadPackets + " to-read " + toRead );
int res = mProto.readPacket( toRead >= 0 );
// TDLog.Log( TDLog.LOG_COMM, "RFcomm readPacket returns " + res );
if ( res == DistoXProtocol.DISTOX_PACKET_NONE ) {
if ( toRead == -1 ) {
doWork = false;
} else {
try {
// TDLog.Log( TDLog.LOG_COMM, "RFcomm sleeping 1000 " );
Thread.sleep( TDSetting.mWaitConn );
} catch (InterruptedException e) {
// TDLog.Log( TDLog.LOG_COMM, "RFcomm thread sleep interrupt");
}
}
} else if ( res == DistoXProtocol.DISTOX_ERR_OFF ) {
TDLog.Error( "RFcomm readPacket returns ERR_OFF " );
// if ( TDSetting.mCommType == 1 && TDSetting.mAutoReconnect ) { // FIXME ACL_DISCONNECT
// mApp.mDataDownloader.setConnected( false );
// mApp.notifyStatus();
// closeSocket( );
// mApp.notifyDisconnected();
// }
doWork = false;
} else if ( res == DistoXProtocol.DISTOX_PACKET_DATA ) {
++nReadPackets;
double d = mProto.mDistance;
double b = mProto.mBearing;
double c = mProto.mClino;
double r = mProto.mRoll;
long extend = TDAzimuth.computeLegExtend( b ); // FIXME-EXTEND
TDLog.Log( TDLog.LOG_DISTOX, "DATA PACKET " + d + " " + b + " " + c );
// NOTE type=0 shot is DistoX-type
mLastShotId = mApp.mData.insertShot( mApp.mSID, -1L, d, b, c, r, extend, 0, true );
if ( mLister != null ) { // FIXME LISTER sendMessage with mLastShotId only
Message msg = mLister.obtainMessage( ListerHandler.LISTER_UPDATE );
Bundle bundle = new Bundle();
bundle.putLong( ListerHandler.LISTER_DATA_BLOCK_ID, mLastShotId );
msg.setData(bundle);
mLister.sendMessage(msg);
if ( mApp.distoType() == Device.DISTO_A3 && TDSetting.mWaitData > 10 ) {
try {
Thread.sleep( TDSetting.mWaitData ); // slowdown
} catch ( InterruptedException e ) { }
}
}
// if ( mLister != null ) {
// DistoXDBlock blk = new DistoXDBlock( );
// blk.setId( mLastShotId, mApp.mSID );
// blk.mLength = (float)d;
// blk.mBearing = (float)b;
// blk.mClino = (float)c;
// blk.mRoll = (float)r;
// mLister.updateBlockList( blk );
// }
} else if ( res == DistoXProtocol.DISTOX_PACKET_G ) {
// TDLog.Log( TDLog.LOG_DISTOX, "G PACKET" );
++nReadPackets;
hasG = true;
} else if ( res == DistoXProtocol.DISTOX_PACKET_M ) {
// TDLog.Log( TDLog.LOG_DISTOX, "M PACKET" );
++nReadPackets;
// get G and M from mProto and save them to store
TDLog.Log( TDLog.LOG_PROTO, "save G " + mProto.mGX + " " + mProto.mGY + " " + mProto.mGZ +
" M " + mProto.mMX + " " + mProto.mMY + " " + mProto.mMZ );
mApp.mDData.insertGM( mApp.mCID, mProto.mGX, mProto.mGY, mProto.mGZ, mProto.mMX, mProto.mMY, mProto.mMZ );
if ( ! hasG ) {
TDLog.Error( "data without G packet " + nReadPackets );
TopoDroidApp.mActivity.runOnUiThread( new Runnable() {
public void run() {
Toast toast = Toast.makeText(mApp, "data without G: " + nReadPackets, Toast.LENGTH_SHORT );
toast.getView().setBackgroundColor( 0xff993333 );
toast.show();
}
} );
}
hasG = false;
} else if ( res == DistoXProtocol.DISTOX_PACKET_REPLY ) {
byte[] addr = mProto.getAddress();
byte[] reply = mProto.getReply();
String result = String.format("%02x %02x %02x %02x at %02x%02x",
reply[0], reply[1], reply[2], reply[3], addr[1], addr[0] );
TDLog.Log( TDLog.LOG_DISTOX, "REPLY PACKET: " + result );
if ( addr[0] == (byte)0x00 && addr[1] == (byte)0x80 ) { // 0x8000
// TDLog.Log( TDLog.LOG_DISTOX, "toggle reply" );
// if ( (reply[0] & CALIB_BIT) == 0 ) {
// mProto.sendCommand( (byte)0x31 ); // TOGGLE CALIB ON
// } else {
// mProto.sendCommand( (byte)0x30 ); // TOGGLE CALIB OFF
// }
} else if ( ( addr[1] & (byte)0x80) == (byte)0x80 ) { // REPLY TO READ/WRITE-CALIBs
// TDLog.Log( TDLog.LOG_DISTOX, "write reply" );
// mProto.setWrittenCalib( true );
} else if ( addr[0] == 0x20 && addr[1] == (byte)0xC0 ) { // C020 READ HEAD-TAIL
// TDLog.Log( TDLog.LOG_DISTOX, "read head-tail reply");
// mHead = (int)( reply[0] | ( (int)(reply[1]) << 8 ) );
// mTail = (int)( reply[2] | ( (int)(reply[3]) << 8 ) );
}
} else if ( res == DistoXProtocol.DISTOX_PACKET_VECTOR ) {
// ++nReadPackets; // vector packet do not count
double acc = mProto.mAcceleration;
double mag = mProto.mMagnetic;
double dip = mProto.mDip;
double roll = mProto.mRoll;
TDLog.Log( TDLog.LOG_DISTOX, "VECTOR PACKET " + mLastShotId + " " + acc + " " + mag + " " + dip + " " + roll );
if ( mApp.distoType() == Device.DISTO_X310 ) {
mApp.mData.updateShotAMDR( mLastShotId, mApp.mSID, acc, mag, dip, roll, true );
if ( TDSetting.mWaitData > 10 ) {
try {
Thread.sleep( TDSetting.mWaitData ); // slowdown
} catch ( InterruptedException e ) { }
}
}
}
}
// TDLog.Log( TDLog.LOG_COMM, "RFcomm thread run() exiting");
mRfcommThread = null;
// FIXME_COMM
// mApp.notifyConnState( );
}
};
protected RfcommThread mRfcommThread;
TopoDroidComm( TopoDroidApp app )
{
mApp = app;
mProtocol = null;
mAddress = null;
mRfcommThread = null;
mCalibMode = false;
mBTConnected = false;
// TDLog.Log( TDLog.LOG_COMM, "TopoDroid Comm cstr");
}
public void resume()
{
// if ( mRfcommThread != null ) { mRfcommThread.resume(); }
}
public void suspend()
{
// if ( mRfcommThread != null ) { mRfcommThread.suspend(); }
}
protected void cancelRfcommThread()
{
// TDLog.Log( TDLog.LOG_COMM, "VD comm cancel Rfcomm thread");
if ( mRfcommThread != null ) {
// TDLog.Log( TDLog.LOG_COMM, "cancel Rfcomm thread: thread is active");
mRfcommThread.cancelWork();
try {
mRfcommThread.join();
} catch ( InterruptedException e ) {
// TDLog.Error( "cancel thread interrupt " + e.getMessage() );
} finally {
// TDLog.Log( TDLog.LOG_COMM, "cancel Rfcomm thread: nulling thread");
mRfcommThread = null;
}
} else {
// TDLog.Log( TDLog.LOG_COMM, "cancel Rfcomm thread: no thread");
}
}
// --------------------------------------------------------
// PROTOCOL
protected void closeProtocol()
{
// TDLog.Log( TDLog.LOG_COMM, "VD comm close protocol");
// if ( mProtocol != null ) mProtocol.closeIOstreams();
mProtocol = null;
}
protected boolean startRfcommThread( int to_read, Handler /* ILister */ lister )
{
return false;
}
public void disconnectRemoteDevice( )
{
// TDLog.Log( TDLog.LOG_COMM, "disconnect remote device ");
cancelRfcommThread();
closeProtocol();
}
protected boolean checkRfcommThreadNull( String msg ) { return ( mRfcommThread == null ); }
protected boolean sendCommand( int cmd )
{
// TDLog.Log( TDLog.LOG_COMM, "VD comm send cmd " + cmd );
boolean ret = false;
if ( mProtocol != null ) {
for (int k=0; k<3 && ! ret; ++k ) { // try three times
ret |= mProtocol.sendCommand( (byte)cmd );
// TDLog.Log( TDLog.LOG_COMM, "sendCommand " + cmd + " " + k + "-ret " + ret );
try {
Thread.sleep( TDSetting.mWaitCommand );
} catch ( InterruptedException e ) {
}
}
}
return ret;
}
public void setX310Laser( String address, int what, Handler /* ILister */ lister ) { }
public boolean toggleCalibMode( String address, int type ) { return false; }
public boolean writeCoeff( String address, byte[] coeff ) { return false; }
public boolean readCoeff( String address, byte[] coeff ) { return false; }
public String readHeadTail( String address, int[] head_tail ) { return null; }
public int readX310Memory( String address, int from, int to, List< MemoryOctet > memory ) { return -1; }
public int readA3Memory( String address, int from, int to, List< MemoryOctet > memory ) { return -1; }
byte[] readMemory( String address, int addr ) { return null; }
public int swapHotBit( String address, int from, int to ) { return -1; }
// ------------------------------------------------------------------------------------
// CONTINUOUS DATA DOWNLOAD
public boolean connectDevice( String address, Handler /* ILister */ lister )
{
return false;
}
public void disconnect() { }
// -------------------------------------------------------------------------------------
// ON-DEMAND DATA DOWNLOAD
public int downloadData( String address, Handler /* ILister */ lister )
{
return -1;
}
// ====================================================================================
// FIRMWARE
public int dumpFirmware( String address, String filepath ) { return 0; }
public int uploadFirmware( String address, String filepath ) { return 0; }
};