Skip to content

Commit

Permalink
Improve Handshake Process with HELLO Message (#230)
Browse files Browse the repository at this point in the history
* Improve Handshake Process with HELLO Message

* tweaks

* tweaks

* NPE

* Tweaks:

Ensured only one active timeout by clearing all pending callbacks before scheduling a new one, preventing stale events from affecting the connection state.

* Increased timeout

* PR feedback

* PR feedback
  • Loading branch information
dkaukov authored Feb 15, 2025
1 parent 955e72b commit 03b804f
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public class RadioAudioService extends Service {
private static final byte COMMAND_DEBUG_WARN = 0x03;
private static final byte COMMAND_DEBUG_DEBUG = 0x04;
private static final byte COMMAND_DEBUG_TRACE = 0x05;
private static final byte COMMAND_HELLO = 0x06;

private final ESP32DataStreamParser esp32DataStreamParser = new ESP32DataStreamParser(this::handleParsedCommand);

Expand Down Expand Up @@ -209,6 +210,8 @@ public class RadioAudioService extends Service {
private String radioType = RADIO_MODULE_VHF;
private boolean radioModuleNotFound = false;
private boolean checkedFirmwareVersion = false;
private boolean gotHello = false;
private final Handler timeOutHandler = new Handler(Looper.getMainLooper());

// Safety constants
private static int RUNAWAY_TX_TIMEOUT_SEC = 180; // Stop runaway tx after 3 minutes
Expand Down Expand Up @@ -481,6 +484,8 @@ public void setChannelMemories(LiveData<List<ChannelMemory>> channelMemoriesLive
public interface RadioAudioServiceCallbacks {
public void radioMissing();
public void radioConnected();
public void hideSnackbar();
public void radioModuleHandshake();
public void radioModuleNotFound();
public void audioTrackCreated();
public void packetReceived(APRSPacket aprsPacket);
Expand Down Expand Up @@ -727,13 +732,13 @@ private String getTxFreq(String txFreq, int offset, int khz) {
if (offset == ChannelMemory.OFFSET_NONE) {
return txFreq;
} else {
Float freqFloat = Float.parseFloat(txFreq);
float freqFloat = Float.parseFloat(txFreq);
if (offset == ChannelMemory.OFFSET_UP) {
freqFloat += 0f + (khz / 1000f);
} else if (offset == ChannelMemory.OFFSET_DOWN){
freqFloat -= 0f + (khz / 1000f);
}
return makeSafeHamFreq(freqFloat.toString());
return makeSafeHamFreq(Float.toString(freqFloat));
}
}

Expand Down Expand Up @@ -864,6 +869,9 @@ private void findESP32Device() {
}
} else {
Log.d("DEBUG", "Found ESP32.");
if (callbacks != null) {
callbacks.hideSnackbar();
}
setupSerialConnection();
}
}
Expand Down Expand Up @@ -939,6 +947,9 @@ public void onNewData(byte[] data) {
@Override
public void onRunError(Exception e) {
Log.d("DEBUG", "Error reading from ESP32.");
if (audioTrack != null) {
audioTrack.stop();
}
connection.close();
try {
serialPort.close();
Expand All @@ -958,19 +969,17 @@ public void onRunError(Exception e) {
usbIoManager.setReadBufferCount(16*2);
usbIoManager.start();
checkedFirmwareVersion = false;
gotHello = false;

Log.d("DEBUG", "Connected to ESP32.");

// After a brief pause (to let it boot), do things with the ESP32 that we were waiting to do.
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (!checkedFirmwareVersion) {
checkFirmwareVersion();
}
timeOutHandler.removeCallbacksAndMessages(null);
timeOutHandler.postDelayed(() -> {
if (!gotHello) {
Log.d("DEBUG", "Error: No HELLO received from module.");
callbacks.missingFirmware();
setMode(MODE_BAD_FIRMWARE);
}
}, 3000);
}, 1000);
}

/**
Expand Down Expand Up @@ -1021,19 +1030,14 @@ private void checkFirmwareVersion() {

// If we don't hear back from the ESP32, it means the firmware is either not
// installed or it's somehow corrupt.
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (mode != MODE_STARTUP || radioModuleNotFound) {
return;
} else {
Log.d("DEBUG", "Error: Did not hear back from ESP32 after requesting its firmware version. Offering to flash.");
callbacks.missingFirmware();
setMode(MODE_BAD_FIRMWARE);
}
timeOutHandler.removeCallbacksAndMessages(null);
timeOutHandler.postDelayed(() -> {
if (mode == MODE_STARTUP && !checkedFirmwareVersion) {
Log.d("DEBUG", "Error: Did not hear back from ESP32 after requesting its firmware version. Offering to flash.");
callbacks.missingFirmware();
setMode(MODE_BAD_FIRMWARE);
}
}, 6000);
}, 60000);
}

private void initAfterESP32Connected() {
Expand Down Expand Up @@ -1461,6 +1465,16 @@ private void handleParsedCommand(byte cmd, byte[] param) {
Log.w("firmware", new String(param));
} else if (cmd == COMMAND_DEBUG_TRACE) {
Log.v("firmware", new String(param));
} else if (cmd == COMMAND_HELLO) {
gotHello = true;
if (audioTrack != null) {
audioTrack.stop();
restartAudioPrebuffer();
}
if (callbacks != null) {
callbacks.radioModuleHandshake();
}
checkFirmwareVersion();
} else {
Log.d("DEBUG", "Unknown cmd received from ESP32: 0x" + Integer.toHexString(cmd & 0xFF) +
" paramLen=" + param.length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ public void radioMissing() {

@Override
public void radioConnected() {
hideSnackbar();
applySettings();
findViewById(R.id.pttButton).setClickable(true);
}

@Override
public void hideSnackbar() {
if (usbSnackbar != null) {
usbSnackbar.dismiss();
usbSnackbar = null;
Expand All @@ -336,8 +343,12 @@ public void radioConnected() {
radioModuleNotFoundSnackbar.dismiss();
radioModuleNotFoundSnackbar = null;
}
applySettings();
findViewById(R.id.pttButton).setClickable(true);

}

@Override
public void radioModuleHandshake() {
showHandshakeSnackbar();
}

@Override
Expand Down Expand Up @@ -1726,6 +1737,21 @@ private void showUSBSnackbar() {
usbSnackbar.show();
}

private void showHandshakeSnackbar() {
CharSequence snackbarMsg = "Connecting to radio...";
usbSnackbar = Snackbar.make(this, findViewById(R.id.mainTopLevelLayout), snackbarMsg, Snackbar.LENGTH_INDEFINITE)
.setBackgroundTint(Color.rgb(20, 140, 0)).setActionTextColor(Color.WHITE).setTextColor(Color.WHITE)
.setAnchorView(findViewById(R.id.bottomNavigationView));

// Make the text of the snackbar larger.
TextView snackbarActionTextView = (TextView) usbSnackbar.getView().findViewById(com.google.android.material.R.id.snackbar_action);
snackbarActionTextView.setTextSize(20);
TextView snackbarTextView = (TextView) usbSnackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
snackbarTextView.setTextSize(20);

usbSnackbar.show();
}

private void showRadioModuleNotFoundSnackbar() {
CharSequence snackbarMsg = "Radio module not responding to ESP32, check PCB solder joints";
radioModuleNotFoundSnackbar = Snackbar.make(this, findViewById(R.id.mainTopLevelLayout), snackbarMsg, Snackbar.LENGTH_INDEFINITE)
Expand Down
1 change: 1 addition & 0 deletions microcontroller-src/kv4p_ht_esp32_wroom_32/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const byte COMMAND_DEBUG_ERROR = 0x02;
const byte COMMAND_DEBUG_WARN = 0x03;
const byte COMMAND_DEBUG_DEBUG = 0x04;
const byte COMMAND_DEBUG_TRACE = 0x05;
const byte COMMAND_HELLO = 0x06;

// Mode of the app, which is essentially a state machine
enum Mode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ void setup() {
squelched = (digitalRead(SQ_PIN) == HIGH);
setMode(MODE_STOPPED);
ledSetup();
sendCmdToAndroid(COMMAND_HELLO, NULL, 0);
_LOGI("Setup is finished");
}

Expand Down Expand Up @@ -314,7 +315,7 @@ void loop() {
while (result != 1) {
result = dra->handshake(); // Wait for module to start up
// Serial.println("handshake: " + String(result));

esp_task_wdt_reset();
if ((micros() - waitStart) > 2000000) { // Give the radio module 2 seconds max before giving up on it
radioModuleStatus = RADIO_MODULE_NOT_FOUND;
break;
Expand Down

0 comments on commit 03b804f

Please sign in to comment.