diff --git a/index.html b/index.html
index ee7d984..23333ab 100644
--- a/index.html
+++ b/index.html
@@ -354,6 +354,52 @@
+
+
+
+ Configure Wi-Fi (optional)
+
+
+
+
+
+
+
PSK
+
+
{{ errors['psk'] }}
+
+
+
+
IP
+
+
{{ errors['ip'] }}
+
+
+
Netmask
+
+
{{ errors['netmask'] }}
+
+
+
+
+
+
+
+
+
+
@@ -942,6 +988,14 @@
],
},
+ // Wi-Fi
+ wifiChannel: "", // means "don't change"
+ wifiSSID: "Reticulum_WiFi",
+ wifiPSK: "password",
+ wifiIP: "",
+ wifiNetmask: "",
+
+ errors: {},
};
},
mounted() {
@@ -1849,6 +1903,83 @@
reader.readAsBinaryString(blob);
});
},
+ // mode = 0: disable Wi-Fi
+ // mode = 1: enable Wi-Fi in station mode
+ // mode = 2: enable Wi-Fi in AP mode
+ async configureWifi(mode) {
+ // Check for validation errors
+ for (const key in this.errors) {
+ if (this.errors[key]!=="") {
+ return
+ }
+ }
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // todo check if firmware hashes match, as config will not save if device has invalid target hash, because radio must be able to init
+
+ // configure
+ console.log("configuring Wi-Fi");
+ if (this.wifiChannel !== "") {
+ await rnode.setChannel(this.wifiChannel);
+ }
+ await rnode.setSSID(this.wifiSSID);
+ await rnode.setPSK(this.wifiPSK);
+ await rnode.setIP(this.wifiIP);
+ await rnode.setNetmask(this.wifiNetmask);
+ await rnode.setWifiMode(mode);
+ console.log("configuring Wi-Fi: done");
+
+ // save config
+ console.log("saving config");
+ await Utils.sleepMillis(500);
+ await rnode.saveConfig();
+ console.log("saving config: done");
+
+ await rnode.close();
+ alert("Wi-Fi has been " + (mode === 0 ? "disabled!" : "enabled!"));
+ },
+ async disableWifi() {
+ await this.configureWifi(0);
+ },
+ async enableWifiStation() {
+ await this.configureWifi(1);
+ },
+ async enableWifiAP() {
+ await this.configureWifi(2);
+ },
+ validateIP(value, name) {
+ // Regex for validating an IPv4 address (0.0.0.0 to 255.255.255.255)
+ const ipv4Pattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
+
+ if (value === '') {
+ this.errors[name] = '';
+ } else if (ipv4Pattern.test(value)) {
+ this.errors[name] = '';
+ } else {
+ this.errors[name] = 'Invalid IPv4 address format';
+ }
+ },
+ validatePSK(value, name) {
+ if (value.length < 8) {
+ this.errors[name] = 'PSK length should be between 8 and 33';
+ } else {
+ this.errors[name] = '';
+ }
+ }
},
computed: {
recommendedFirmwareFilename() {
diff --git a/js/rnode.js b/js/rnode.js
index 120ca40..7c11bf1 100644
--- a/js/rnode.js
+++ b/js/rnode.js
@@ -63,6 +63,13 @@ class RNode {
CMD_STAT_RSSI = 0x23;
CMD_STAT_SNR = 0x24;
+ CMD_WIFI_MODE = 0x6A
+ CMD_WIFI_SSID = 0x6B
+ CMD_WIFI_PSK = 0x6C
+ CMD_WIFI_CHN = 0x6E
+ CMD_WIFI_IP = 0x84
+ CMD_WIFI_NM = 0x85
+
CMD_BOARD = 0x47;
CMD_PLATFORM = 0x48;
CMD_MCU = 0x49;
@@ -766,6 +773,61 @@ class RNode {
]);
}
+ async setChannel(channel) {
+ await this.sendKissCommand([
+ this.CMD_WIFI_CHN,
+ channel
+ ]);
+ }
+
+ async setSSID(ssid) {
+ // empty ssid is valid, and means "delete"
+ const encoder = new TextEncoder();
+ let data = encoder.encode(ssid);
+
+ await this.sendKissCommand([
+ this.CMD_WIFI_SSID,
+ ...data,
+ 0x00
+ ]);
+ }
+
+ async setPSK(psk) {
+ // empty psk is valid, and means "delete"
+ const encoder = new TextEncoder();
+ let data = encoder.encode(psk);
+
+ await this.sendKissCommand([
+ this.CMD_WIFI_PSK,
+ ...data,
+ 0x00
+ ]);
+ }
+
+ async setIP(ip) {
+ let data = ipStrToBytes(ip);
+
+ await this.sendKissCommand([
+ this.CMD_WIFI_IP,
+ ...data,
+ ]);
+ }
+
+ async setNetmask(netmask) {
+ let data = ipStrToBytes(netmask);
+
+ await this.sendKissCommand([
+ this.CMD_WIFI_NM,
+ ...data,
+ ]);
+ }
+
+ async setWifiMode(mode) {
+ await this.sendKissCommand([
+ this.CMD_WIFI_MODE,
+ mode
+ ]);
+ }
}
class ROM {
@@ -1018,3 +1080,17 @@ class ROM {
}
}
+
+// ipStrToBytes converts IPv4 address in string format to array of bytes
+function ipStrToBytes(ip) {
+ if (ip.length === 0) {
+ // means "delete"
+ ip = "0.0.0.0"
+ }
+ let octets = ip.split(".")
+ let data = []
+ for (const octet of octets) {
+ data.push(+octet)
+ }
+ return data;
+}