-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to send messages from MyGeotab to External device #5
Comments
Additional information with logs for 3 cases:
Modified ThirdParty.javaI modified the ThirdParty.java a bit to test all 3 cases. I created two methods to test cases 2 and 3: BuildHandshakeConfirmationMessageWithFlags and BuildHandshakeMessageWithoutFlags. Full modified ThirdParty.java file content: /*****************************************************************************
*
* Copyright (C) 2017, Geotab Inc.
*
******************************************************************************
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
package com.geotab.AOA;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.geotab.ioxproto.IoxMessaging;
import com.google.protobuf.InvalidProtocolBufferException;
public class ThirdParty {
private static final String TAG = ThirdParty.class.getSimpleName(); // Used for error logging
private static final HOSData mHOSdata = new HOSData();
private static final byte MESSAGE_HANDSHAKE = 1;
private static final byte MESSAGE_ACK = 2;
private static final byte MESSAGE_GO_DEVICE_DATA = 0x21;
private static final byte PROTOBUF_DATA_FROM_GO = 0x26;
private static final byte MESSAGE_CONFIRMATION = (byte) 0x81;
private static final byte CUSTOM_IOX = (byte) 0x1D;
private static final byte MESSAGE_STATUS_DATA = (byte) 0x80;
private static final byte TP_FREE_FORMAT_DATA = (byte) 0x82;
private static final byte TP_DEVICE_INFO_RECEIVED = (byte) 0x83;
private static final byte TP_HOS_ACK = (byte) 0x84;
static final byte PROTOBUF_DATA_TO_GO = (byte) 0x8c;
private static final byte MESSAGE_SYNC = 0x55;
private static final byte[] HOS_ENHANCED_ID_WITH_ACK = new byte[]{0x2D, 0x10, 0x00, 0x00}; //
// private static final byte[] HOS_ENHANCED_ID_WITH_ACK = new byte[]{0x60, 0x10, 0x00, 0x00};
// private static final int DEVICE_ID = 4141; // device ID that works
private static final int DEVICE_ID = 4208; // this device ID does not work
static final ThirdPartyMessage[] THIRD_PARTY_MESSAGE_DEFINEs = new ThirdPartyMessage[]
{
new ThirdPartyMessage("-BYPASS-", (byte) 0, null),
new ThirdPartyMessage("STATUS: OUTSIDE TEMPERATURE", MESSAGE_STATUS_DATA, new byte[]{0x35, 0x00}), // 53
new ThirdPartyMessage("STATUS: ENGINE WARNING LIGHT", MESSAGE_STATUS_DATA, new byte[]{0x24, 0x00}), // 36
new ThirdPartyMessage("STATUS: PARK BRAKE", MESSAGE_STATUS_DATA, new byte[]{0x31, 0x00}), // 49
new ThirdPartyMessage("FREE FORMAT", TP_FREE_FORMAT_DATA, null),
new ThirdPartyMessage("DEVICE INFO", TP_DEVICE_INFO_RECEIVED, null),
new ThirdPartyMessage("HOS ACK", TP_HOS_ACK, null),
new ThirdPartyMessage("PROTOBUF PUB/SUB", PROTOBUF_DATA_TO_GO, null),
};
private final Lock mLock = new ReentrantLock();
private final Condition mEvent = mLock.newCondition();
private byte[] mabMessage;
private boolean mfAckReceived, mfHandshakeReceived, mfMessageToSend;
private AccessoryControl mAccessoryControl;
private StateMachine mStateMachine;
private final Handler mHandler;
private IOXListener mIOXListener;
public enum State {
SEND_SYNC, WAIT_FOR_HANDSHAKE, SEND_CONFIRMATION, PRE_IDLE, IDLE, WAIT_FOR_ACK
}
// Constructor
public ThirdParty(AccessoryControl accessory, Context context, IOXListener ioxListener) {
mfHandshakeReceived = false;
mfAckReceived = false;
mfMessageToSend = false;
mAccessoryControl = accessory;
mHandler = new Handler(context.getMainLooper());
mIOXListener = ioxListener;
mStateMachine = new StateMachine();
new Thread(mStateMachine).start(); // Run as a separate thread
}
// State machine to handle the third party protocol
private class StateMachine implements Runnable {
private State eState = State.SEND_SYNC;
private AtomicBoolean fRunning = new AtomicBoolean(true);
public void run() {
Log.i(TAG, "Third party SM started");
while (fRunning.get()) {
mLock.lock(); // The lock is needed for await and atomic access to flags/buffers
try {
notifyStateChanged(eState);
switch (eState) {
case SEND_SYNC: {
byte[] abMessage = new byte[]{MESSAGE_SYNC};
mAccessoryControl.write(abMessage);
eState = State.WAIT_FOR_HANDSHAKE;
Log.d("THIRD_PARTY", "SEND_SYNC");
break;
}
case WAIT_FOR_HANDSHAKE: {
// Waits for the handshake message or resends sync every 1s
mEvent.await(1000, TimeUnit.MILLISECONDS);
if (mfHandshakeReceived) {
eState = State.SEND_CONFIRMATION;
} else {
eState = State.SEND_SYNC;
}
break;
}
case SEND_CONFIRMATION: {
/// Test with HOS_ENHANCED_ID_WITH_ACK
// byte[] abMessage = BuildMessage(MESSAGE_CONFIRMATION, HOS_ENHANCED_ID_WITH_ACK); // Uncomment this
/// Test with flags
// byte[] abMessage = BuildHandshakeConfirmationMessageWithFlags(); // Uncomment this
/// Test without flags
byte[] abMessage = BuildHandshakeMessageWithoutFlags(); // Uncomment this
Log.d(TAG, "SEND_CONFIRMATION: abMessage.length:" + abMessage.length + ", abMessage:" + Arrays.toString(abMessage));
mAccessoryControl.write(abMessage);
eState = State.PRE_IDLE;
break;
}
case PRE_IDLE: {
mfHandshakeReceived = false;
mfAckReceived = false;
mfMessageToSend = false;
eState = State.IDLE;
break;
}
case IDLE: {
// Sleep and wait for a handshake or a message to send
mEvent.await();
if (mfHandshakeReceived) {
eState = State.SEND_CONFIRMATION;
} else if (mfMessageToSend) {
mAccessoryControl.write(mabMessage);
eState = State.WAIT_FOR_ACK;
}
break;
}
case WAIT_FOR_ACK: {
// Wait for the ack or reset after 5s
mEvent.await(5000, TimeUnit.MILLISECONDS);
if (mfAckReceived) {
eState = State.PRE_IDLE;
} else {
eState = State.SEND_SYNC;
}
break;
}
default: {
eState = State.SEND_SYNC;
break;
}
}
} catch (InterruptedException e) {
Log.w(TAG, "Exception during await", e);
} finally {
mLock.unlock();
}
}
}
// Stop the thread
public void close() {
Log.i(TAG, "Shutting down third party SM");
mLock.lock();
try {
fRunning.set(false);
mfHandshakeReceived = false;
mfAckReceived = false;
mfMessageToSend = false;
mEvent.signal();
} finally {
mLock.unlock();
}
}
}
// Signal the state machine to stop
public void close() {
if (mStateMachine != null)
mStateMachine.close();
}
// Encapsulate a message to be sent
public void TxMessage(byte bType, byte[] abData) {
Log.d(TAG, "TxMessage:" + bType + ", abData.length:" + abData.length);
mLock.lock();
try {
mabMessage = BuildMessage(bType, abData);
Log.d(TAG, "TxMessage: mabMessage.length:" + mabMessage.length + ", mabMessage:" + Arrays.toString(mabMessage));
mfMessageToSend = true;
mEvent.signal();
} finally {
mLock.unlock();
}
}
// Checks if a received message matches the expected third party format
public void RxMessage(byte[] abData) {
Log.d(TAG, "RxMessage: abData.length:" + abData.length + ", abData:" + Arrays.toString(abData));
// Check length
if (abData == null || abData.length < 6) {
Log.e(TAG, "RxMessage: Bad Data length!");
return;
}
// Check structure
byte bSTX = abData[0];
byte bLength = abData[2];
byte bETX = abData[abData.length - 1];
if (bSTX != 0x02 || bETX != 0x03) {
Log.e(TAG, "RxMessage: Bad Data format!");
return;
}
// Check checksum
byte[] abChecksum = new byte[]{abData[abData.length - 3], abData[abData.length - 2]};
byte[] abCalcChecksum = CalcChecksum(abData, bLength + 3);
if (!Arrays.equals(abChecksum, abCalcChecksum)) {
Log.e(TAG, "RxMessage: Bad Data Checksum!");
return;
}
byte bType = abData[1];
switch (bType) {
case MESSAGE_HANDSHAKE:
mLock.lock();
try {
mfHandshakeReceived = true;
mEvent.signal();
} finally {
mLock.unlock();
}
break;
case MESSAGE_ACK:
mLock.lock();
try {
mfAckReceived = true;
mEvent.signal();
} finally {
mLock.unlock();
}
break;
case MESSAGE_GO_DEVICE_DATA:
ExtractHOSData(abData);
byte[] abAck = new byte[]{};
mabMessage = BuildMessage(TP_HOS_ACK, abAck);
mAccessoryControl.write(mabMessage);
break;
case PROTOBUF_DATA_FROM_GO:
try {
byte[] mDate = new byte[abData.length - 6];
System.arraycopy(abData, 3, mDate, 0, mDate.length);
IoxMessaging.IoxFromGo ioxFromGoMsg = IoxMessaging.IoxFromGo.parseFrom(mDate);
Log.d(TAG, "RxMessage: PROTOBUF_DATA_FROM_GO MsgCase:"
+ ioxFromGoMsg.getMsgCase());
if (mIOXListener != null && mHandler != null) {
mHandler.post(() -> {
mIOXListener.onIOXReceived(ioxFromGoMsg);
});
}
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "RxMessage: Failed to decode the protobuf data\n"
+ e.getMessage());
}
break;
// Case some other message type
default:
Log.d(TAG, "RxMessage: Unknown message type: " + bType);
break;
}
}
// Assemble a third party message
private byte[] BuildMessage(byte bType, byte[] abData) {
byte[] abMessage = new byte[abData.length + 6];
abMessage[0] = 0x02;
abMessage[1] = bType;
abMessage[2] = (byte) abData.length;
System.arraycopy(abData, 0, abMessage, 3, abData.length);
int iLengthUpToChecksum = abData.length + 3;
byte[] abCalcChecksum = CalcChecksum(abMessage, iLengthUpToChecksum);
System.arraycopy(abCalcChecksum, 0, abMessage, iLengthUpToChecksum, 2);
abMessage[abMessage.length - 1] = 0x03;
return abMessage;
}
private byte[] BuildHandshakeConfirmationMessageWithFlags() {
byte[] abMessage = new byte[10];
// Start of Text
abMessage[0] = 0x02;
// Message Type
abMessage[1] = MESSAGE_CONFIRMATION;
// Message Body Length
abMessage[2] = 4;
// External Device ID (little-endian)
abMessage[3] = (byte) (DEVICE_ID & 0xFF);
abMessage[4] = (byte) ((DEVICE_ID >> 8) & 0xFF);
// Flags
byte flags = 0x06; // Handshake ACK = 1, Binary data wrapping = 1, Self-powered = 0
abMessage[5] = flags;
// Checksum (Fletcher's checksum)
byte[] abChecksum = CalcChecksum(abMessage, 6);
abMessage[6] = abChecksum[0];
abMessage[7] = abChecksum[1];
// End of Text
abMessage[8] = 0x03;
return abMessage;
}
// Assemble the handshake message with device ID and without flags
private byte[] BuildHandshakeMessageWithoutFlags(){
byte[] abDeviceId = new byte[]{
(byte) ((DEVICE_ID >> 8) & 0xFF),
(byte) (DEVICE_ID & 0xFF),
0x00, 0x00
};
return BuildMessage(MESSAGE_CONFIRMATION, abDeviceId);
}
// Calculate the Fletcher's checksum over the given bytes
private byte[] CalcChecksum(byte[] abData, int iLength) {
byte[] abChecksum = new byte[]{0x00, 0x00};
for (int i = 0; i < iLength; i++) {
abChecksum[0] += abData[i];
abChecksum[1] += abChecksum[0];
}
return abChecksum;
}
public void ExtractHOSData(byte[] abData) {
synchronized (mHOSdata) {
Log.d("NewTest", "ExtractHOSData: " + abData.length);
ByteBuffer abConvert;
byte[] abDateTime = new byte[4];
System.arraycopy(abData, 3, abDateTime, 0, abDateTime.length);
abConvert = ByteBuffer.wrap(abDateTime).order(java.nio.ByteOrder.LITTLE_ENDIAN);
int iDateTime = abConvert.getInt();
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
c.clear();
c.set(2002, Calendar.JANUARY, 1); // (Units given in seconds since Jan 1, 2002)
c.add(Calendar.SECOND, iDateTime);
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.US);
mHOSdata.sDateTime = dataFormat.format(c.getTime());
byte[] abLatitude = new byte[4];
System.arraycopy(abData, 7, abLatitude, 0, abLatitude.length);
abConvert = ByteBuffer.wrap(abLatitude).order(java.nio.ByteOrder.LITTLE_ENDIAN);
int iLatitude = abConvert.getInt();
mHOSdata.Latitude = (float) iLatitude / 10000000; // (Units given in 10^-7)
byte[] abLogitude = new byte[4];
System.arraycopy(abData, 11, abLogitude, 0, abLogitude.length);
abConvert = ByteBuffer.wrap(abLogitude).order(java.nio.ByteOrder.LITTLE_ENDIAN);
int iLogitude = abConvert.getInt();
mHOSdata.Longitude = (float) iLogitude / 10000000; // (Units given in 10^-7)
mHOSdata.iRoadSpeed = abData[15];
byte[] abPRM = new byte[2];
System.arraycopy(abData, 16, abPRM, 0, abPRM.length);
abConvert = ByteBuffer.wrap(abPRM).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iRPM = abConvert.getShort();
mHOSdata.iRPM /= 4; // Convert to RPM (Units given in 0.25)
byte[] abOdometer = new byte[4];
System.arraycopy(abData, 18, abOdometer, 0, abOdometer.length);
abConvert = ByteBuffer.wrap(abOdometer).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iOdometer = abConvert.getInt(); // (Units given in 0.1/km)
byte bStatus = abData[22];
mHOSdata.sStatus = "";
if ((bStatus & (1 << 0)) != 0)
mHOSdata.sStatus += "GPS Latched | ";
else
mHOSdata.sStatus += "GPS Invalid | ";
if ((bStatus & (1 << 1)) != 0)
mHOSdata.sStatus += "IGN on | ";
else
mHOSdata.sStatus += "IGN off | ";
if ((bStatus & (1 << 2)) != 0)
mHOSdata.sStatus += "Engine Data | ";
else
mHOSdata.sStatus += "No Engine Data | ";
if ((bStatus & (1 << 3)) != 0)
mHOSdata.sStatus += "Date/Time Valid | ";
else
mHOSdata.sStatus += "Date/Time Invalid | ";
if ((bStatus & (1 << 4)) != 0)
mHOSdata.sStatus += "Speed From Engine | ";
else
mHOSdata.sStatus += "Speed From GPS | ";
if ((bStatus & (1 << 5)) != 0)
mHOSdata.sStatus += "Distance From Engine | ";
else
mHOSdata.sStatus += "Distance From GPS | ";
byte[] abTripOdometer = new byte[4];
System.arraycopy(abData, 23, abTripOdometer, 0, abTripOdometer.length);
abConvert = ByteBuffer.wrap(abTripOdometer).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iTripOdometer = abConvert.getInt(); // (Units given in 0.1/km)
byte[] abEngineHours = new byte[4];
System.arraycopy(abData, 27, abEngineHours, 0, abEngineHours.length);
abConvert = ByteBuffer.wrap(abEngineHours).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iEngineHours = abConvert.getInt(); // Already in units of 0.1h
byte[] abTripDuration = new byte[4];
System.arraycopy(abData, 31, abTripDuration, 0, abTripDuration.length);
abConvert = ByteBuffer.wrap(abTripDuration).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iTripDuration = abConvert.getInt(); // Units of seconds
byte[] abVehicleId = new byte[4];
System.arraycopy(abData, 35, abVehicleId, 0, abVehicleId.length);
abConvert = ByteBuffer.wrap(abVehicleId).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iVehicleId = abConvert.getInt();
byte[] abDriverId = new byte[4];
System.arraycopy(abData, 39, abDriverId, 0, abDriverId.length);
abConvert = ByteBuffer.wrap(abDriverId).order(java.nio.ByteOrder.LITTLE_ENDIAN);
mHOSdata.iDriverId = abConvert.getInt();
}
updateHOSTextFromThread();
}
public synchronized HOSData getHOSData() {
return mHOSdata;
}
// Update text on the UI thread from another thread
private void updateHOSTextFromThread() {
HOSData dataHOS = getHOSData();
if (mHandler != null && mIOXListener != null) {
mHandler.post(() -> mIOXListener.onUpdateHOSText(dataHOS));
}
}
private void showStatusMsg(final String msg) {
Log.i(TAG, msg);
if (mHandler != null && mIOXListener != null) {
mHandler.post(() -> mIOXListener.onStatusUpdate(msg));
}
}
private void notifyStateChanged(ThirdParty.State state) {
Log.i(TAG, "notifyStateChanged " + state.name());
if (mHandler != null && mIOXListener != null) {
mHandler.post(() -> mIOXListener.onIOXStateChanged(state));
}
}
} LogsLogs for case 1: 2024-08-01 08:45:37.240 12918-12963 ThirdParty com.geotab.AOA I Third party SM started
2024-08-01 08:45:37.241 12918-12963 ThirdParty com.geotab.AOA I notifyStateChanged SEND_SYNC
2024-08-01 08:45:37.245 12918-12963 ThirdParty com.geotab.AOA I notifyStateChanged WAIT_FOR_HANDSHAKE
2024-08-01 08:45:37.246 12918-12964 ThirdParty com.geotab.AOA D RxMessage: abData.length:58, abData:[2, 33, 52, 12, 51, 122, 42, 0, -110, 59, 27, 0, 93, -97, 8, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 71, 65, 85, 54, 66, 69, 85, 69, 80, 50, 90, 50, 118, -40, 3]
2024-08-01 08:45:37.353 12918-12964 ThirdParty com.geotab.AOA D RxMessage: abData.length:6, abData:[2, 1, 0, 3, 8, 3]
2024-08-01 08:45:37.355 12918-12963 ThirdParty com.geotab.AOA I notifyStateChanged SEND_CONFIRMATION
2024-08-01 08:45:37.362 12918-12963 ThirdParty com.geotab.AOA D SEND_CONFIRMATION: abMessage.length:10, abMessage:[2, -127, 4, 45, 16, 0, 0, -60, 12, 3]
2024-08-01 08:45:37.363 12918-12963 ThirdParty com.geotab.AOA I notifyStateChanged PRE_IDLE
2024-08-01 08:45:37.366 12918-12963 ThirdParty com.geotab.AOA I notifyStateChanged IDLE
2024-08-01 08:45:39.377 12918-12964 ThirdParty com.geotab.AOA D RxMessage: abData.length:58, abData:[2, 33, 52, 19, 51, 122, 42, 0, -110, 59, 27, 0, 93, -97, 8, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 71, 65, 85, 54, 66, 69, 85, 69, 80, 50, 90, 50, -124, -20, 3]
2024-08-01 08:45:41.376 12918-12964 ThirdParty com.geotab.AOA D RxMessage: abData.length:58, abData:[2, 33, 52, 21, 51, 122, 42, 0, -110, 59, 27, 0, 93, -97, 8, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 71, 65, 85, 54, 66, 69, 85, 69, 80, 50, 90, 50, -120, -124, 3] HOS data is being receved as expected.
2024-08-01 08:47:40.879 13622-13672 ThirdParty com.geotab.AOA I Third party SM started
2024-08-01 08:47:40.879 13622-13672 ThirdParty com.geotab.AOA I notifyStateChanged SEND_SYNC
2024-08-01 08:47:40.882 13622-13672 ThirdParty com.geotab.AOA I notifyStateChanged WAIT_FOR_HANDSHAKE
2024-08-01 08:47:40.883 13622-13673 ThirdParty com.geotab.AOA D RxMessage: abData.length:6, abData:[2, 1, 0, 3, 8, 3]
2024-08-01 08:47:40.884 13622-13672 ThirdParty com.geotab.AOA I notifyStateChanged SEND_CONFIRMATION
2024-08-01 08:47:40.885 13622-13672 ThirdParty com.geotab.AOA D SEND_CONFIRMATION: abMessage.length:10, abMessage:[2, -127, 4, 112, 16, 6, 13, 23, 3, 0]
2024-08-01 08:47:40.886 13622-13672 ThirdParty com.geotab.AOA I notifyStateChanged PRE_IDLE
2024-08-01 08:47:40.886 13622-13672 ThirdParty com.geotab.AOA I notifyStateChanged IDLE
2024-08-01 08:48:23.408 13622-13673 ThirdParty com.geotab.AOA I Shutting down third party SM No data is being received from the device after the confirmation sent from the Android device. I tried sending the Runner's data, but nothing was logged.
2024-08-01 08:51:33.701 15060-15107 ThirdParty com.geotab.AOA I Third party SM started
2024-08-01 08:51:33.701 15060-15107 ThirdParty com.geotab.AOA I notifyStateChanged SEND_SYNC
2024-08-01 08:51:33.702 15060-15107 ThirdParty com.geotab.AOA I notifyStateChanged WAIT_FOR_HANDSHAKE
2024-08-01 08:51:33.704 15060-15108 ThirdParty com.geotab.AOA D RxMessage: abData.length:6, abData:[2, 1, 0, 3, 8, 3]
2024-08-01 08:51:33.706 15060-15107 ThirdParty com.geotab.AOA I notifyStateChanged SEND_CONFIRMATION
2024-08-01 08:51:33.707 15060-15107 ThirdParty com.geotab.AOA D SEND_CONFIRMATION: abMessage.length:10, abMessage:[2, -127, 4, 16, 112, 0, 0, 7, -72, 3]
2024-08-01 08:51:33.708 15060-15107 ThirdParty com.geotab.AOA I notifyStateChanged PRE_IDLE
2024-08-01 08:51:33.709 15060-15107 ThirdParty com.geotab.AOA I notifyStateChanged IDLE
2024-08-01 08:57:32.009 15060-15060 ThirdParty com.geotab.AOA I Shutting down third party SM Same as case 2 - no data is being received from the device after the confirmation sent from the Android device. I tried sending the Runner's data, but nothing was logged. For cases 2 and 3 I used this API call to get data from the Runner to external Android device: api.call("Add", {
"typeName": "TextMessage",
"entity": {
"device": {"id":"b1"}, // Replace with device ID that should receive the data
"messageContent": {
"contentType": "MimeContent",
"channelNumber": 5,
"mimeType": "text", // Can be changed to any free format text value
"binaryDataPacketDelay": "00:00:03.0000000", // Applies a configurable delay of up to 5 seconds in between each sequenced message of a multimessage MIME payload
"data": "SGVsbG8gV29ybGQ=" // Replace with your data encoded in base64
},
"isDirectionToVehicle": true,
"messageSize": 235 // If unspecified defaults to 235. Max of 1000.
},
}, function(result) {
console.log("Done: ", result);
}, function(e) {
console.error("Failed:", e);
}); |
I'd like to send messages from MyGeotab Runner to the external Android device connected to the Geotab GO device with the USB cable.
I use this API call with the Runner:
I'm using your example code, where I only changed the Device ID to a number between 4200 and 4299 based on your documentation.
My ThirdParty.java code:
My procedure:
Example:
How to make this work? Am I missing something?
The text was updated successfully, but these errors were encountered: