-
Notifications
You must be signed in to change notification settings - Fork 9
Open
Description
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:
api.call("Add", {
"typeName": "TextMessage",
"entity": {
"device": {"id":"b2"}, // Replace with device ID that should receive the data
"messageContent": {
"contentType": "MimeContent",
"channelNumber": 1,
"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'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:
public class ThirdParty {
private static final int DEVICE_ID = 4208; // Used in methods sendHandshakeConfirmation and BuildHandshakeMessage
// Some other code ...
// State machine to handle the third party protocol - See case SEND_CONFIRMATION
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: {
sendHandshakeConfirmation(); // Added this (see below)
// Could also use this without flags:
// byte[] abMessage = BuildHandshakeMessage();
// 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();
}
}
}
// Some other code ...
// Wrote this to send a confirmation with the flags as stated in the documentation
public void sendHandshakeConfirmation() {
byte[] handshakeMessage = BuildHandshakeConfirmationMessage();
Log.d(TAG, "Sending Handshake Confirmation: " + Arrays.toString(handshakeMessage));
mAccessoryControl.write(handshakeMessage);
}
private byte[] BuildHandshakeConfirmationMessage() {
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;
}
// Some other code ...
// I also tried this method without the flags that uses existing BuildMessage method
// Assemble the handshake message with the device ID - could be called in
private byte[] BuildHandshakeMessage() {
byte[] abDeviceId = new byte[]{
(byte) (DEVICE_ID & 0xFF),
(byte) ((DEVICE_ID >> 8) & 0xFF),
0x00, 0x00 // Placeholder for any additional data
};
return BuildMessage(MESSAGE_CONFIRMATION, abDeviceId);
}
}
My procedure:
- I press Run in the Geotab Runner, the message displayed in the console is Done:b54, Done:b55 (number increasing for each call).
- I watch for any raw bytes coming to my Android device inside the RxMessage method in ThirdParty.java, but nothing gets printed.
Example:
public void RxMessage(byte[] abData) {
Log.d(TAG, "RxMessage: abData.length:" + abData.length + ", abData:" + Arrays.toString(abData));
// Other code ....
}
How to make this work? Am I missing something?
Metadata
Metadata
Assignees
Labels
No labels