mirror of
https://github.com/meshcore-dev/flasher.meshcore.dev.git
synced 2026-04-20 22:13:50 +00:00
sync production -> git
This commit is contained in:
parent
c548c898f3
commit
56892c5ef7
6 changed files with 685 additions and 390 deletions
513
config.json
513
config.json
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"basePath": "./firmware",
|
"staticPath": "/firmware",
|
||||||
"role": {
|
"role": {
|
||||||
"gui": {
|
"gui": {
|
||||||
"icon": "gradient",
|
"icon": "gradient",
|
||||||
|
|
@ -14,12 +14,14 @@
|
||||||
"companionBle": {
|
"companionBle": {
|
||||||
"icon": "smartphone",
|
"icon": "smartphone",
|
||||||
"class": "primary-text",
|
"class": "primary-text",
|
||||||
"title": "Companion radio: Bluetooth",
|
"title": "Companion radio",
|
||||||
|
"subTitle": "Bluetooth",
|
||||||
"tooltip": "Chat via mobile phone App or Web Client"
|
"tooltip": "Chat via mobile phone App or Web Client"
|
||||||
},
|
},
|
||||||
"companionUsb": {
|
"companionUsb": {
|
||||||
"icon": "usb",
|
"icon": "usb",
|
||||||
"title": "Companion radio: USB",
|
"title": "Companion radio",
|
||||||
|
"subTitle": "USB",
|
||||||
"tooltip": "Chat via Web client or command line client"
|
"tooltip": "Chat via Web client or command line client"
|
||||||
},
|
},
|
||||||
"repeater": {
|
"repeater": {
|
||||||
|
|
@ -41,33 +43,69 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "gui",
|
"role": "gui",
|
||||||
"files": [
|
"version": {
|
||||||
{
|
"v6.2": {
|
||||||
"type": "flash",
|
"files": [
|
||||||
"name": "RippleUltra-TDeck-v6.0-beta21-merged.bin",
|
{
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
"type": "flash",
|
||||||
|
"name": "RippleUltra-TDeck-v6.2-merged.bin",
|
||||||
|
"title": "Combined app+partition+bootloader firmware bin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "download",
|
||||||
|
"name": "RippleUltra-TDeck-v6.2.bin",
|
||||||
|
"title": "App firmware bin (use with m5 booloader)"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
"v6.0-beta22": {
|
||||||
"type": "download",
|
"files": [
|
||||||
"name": "RippleUltra-TDeck-v6.0-beta21.bin",
|
{
|
||||||
"title": "App firmware bin (use with m5 booloader)"
|
"type": "flash",
|
||||||
|
"name": "RippleUltra-TDeck-v6.0-beta22-merged.bin",
|
||||||
|
"title": "Combined app+partition+bootloader firmware bin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "download",
|
||||||
|
"name": "RippleUltra-TDeck-v6.0-beta22.bin",
|
||||||
|
"title": "App firmware bin (use with m5 booloader)"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "guiSD",
|
"role": "guiSD",
|
||||||
"files": [
|
"version": {
|
||||||
{
|
"v6.2": {
|
||||||
"type": "flash",
|
"files": [
|
||||||
"name": "RippleUltra-TDeck-SD-v6.0-beta21-merged.bin",
|
{
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
"type": "flash",
|
||||||
|
"name": "RippleUltra-TDeck-SD-v6.2-merged.bin",
|
||||||
|
"title": "Combined app+partition+bootloader firmware bin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "download",
|
||||||
|
"name": "RippleUltra-TDeck-SD-v6.2.bin",
|
||||||
|
"title": "App firmware bin (use with m5 booloader)"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
"v6.0-beta22": {
|
||||||
"type": "download",
|
"files": [
|
||||||
"name": "RippleUltra-TDeck-SD-v6.0-beta21.bin",
|
{
|
||||||
"title": "App firmware bin (use with m5 booloader)"
|
"type": "flash",
|
||||||
|
"name": "RippleUltra-TDeck-SD-v6.0-beta22-merged.bin",
|
||||||
|
"title": "Combined app+partition+bootloader firmware bin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "download",
|
||||||
|
"name": "RippleUltra-TDeck-SD-v6.0-beta22.bin",
|
||||||
|
"title": "App firmware bin (use with m5 booloader)"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -78,18 +116,22 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "gui",
|
"role": "gui",
|
||||||
"files": [
|
"version": {
|
||||||
{
|
"v6.0-beta22": {
|
||||||
"type": "flash",
|
"files": [
|
||||||
"name": "RippleUltra-T5-epaper-v6.0-beta21-merged.bin",
|
{
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
"type": "flash",
|
||||||
},
|
"name": "RippleUltra-T5-epaper-v6.0-beta21-merged.bin",
|
||||||
{
|
"title": "Combined app+partition+bootloader firmware bin"
|
||||||
"type": "download",
|
},
|
||||||
"name": "RippleUltra-T5-epaper-v6.0-beta21.bin",
|
{
|
||||||
"title": "App firmware bin (use with m5 booloader)"
|
"type": "download",
|
||||||
|
"name": "RippleUltra-T5-epaper-v6.0-beta21.bin",
|
||||||
|
"title": "App firmware bin (use with m5 booloader)"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -100,33 +142,110 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "companionUsb",
|
"role": "companionUsb",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "LilyGo_T3S3_sx1262_companion_radio_usb.bin",
|
"flash": ["LilyGo_T3S3_sx1262_companion_radio_usb","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "companionBle",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "LilyGo_T3S3_sx1262_companion_radio_ble.bin",
|
"flash": ["LilyGo_T3S3_sx1262_companion_radio_ble","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "LilyGo_T3S3_sx1262_Repeater.bin",
|
"flash": ["LilyGo_T3S3_sx1262_Repeater","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lilygo T-Echo",
|
||||||
|
"type": "nrf52",
|
||||||
|
"tooltip": "<img class='device' src='/img/lilygo_techo.png'>",
|
||||||
|
"firmware": [
|
||||||
|
{
|
||||||
|
"role": "companionBle",
|
||||||
|
"github": {
|
||||||
|
"type": "companion",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_T-Echo_companion_radio_ble","zip"],
|
||||||
|
"download": ["LilyGo_T-Echo_companion_radio_ble","uf2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "repeater",
|
||||||
|
"github": {
|
||||||
|
"type": "repeater",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_T-Echo_repeater","zip"],
|
||||||
|
"download": ["LilyGo_T-Echo_repeater","uf2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "roomServer",
|
||||||
|
"github": {
|
||||||
|
"type": "room-server",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_T-Echo_room_server","zip"],
|
||||||
|
"download": ["LilyGo_T-Echo_room_server","uf2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lilygo LoRa32 V2.1_1.6",
|
||||||
|
"type": "esp32",
|
||||||
|
"tooltip": "<img class='device' src='/img/lilygo_t3s3.png'>",
|
||||||
|
"firmware": [
|
||||||
|
{
|
||||||
|
"role": "companionUsb",
|
||||||
|
"github": {
|
||||||
|
"type": "companion",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_TLora_V2_1_1_6_companion_radio_usb","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "companionBle",
|
||||||
|
"github": {
|
||||||
|
"type": "companion",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_TLora_V2_1_1_6_companion_radio_ble","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "repeater",
|
||||||
|
"github": {
|
||||||
|
"type": "repeater",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_TLora_V2_1_1_6_Repeater","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "roomServer",
|
||||||
|
"github": {
|
||||||
|
"type": "room-server",
|
||||||
|
"files": {
|
||||||
|
"flash": ["LilyGo_TLora_V2_1_1_6_room_server","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -137,23 +256,30 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "companionUsb",
|
"role": "companionUsb",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v2_companion_radio_usb.bin",
|
"flash": ["Heltec_v2_companion_radio_usb","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "companionBle",
|
||||||
|
"github": {
|
||||||
|
"type": "companion",
|
||||||
|
"files": {
|
||||||
|
"flash": ["Heltec_v2_companion_radio_ble","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v2_repeater.bin",
|
"flash": ["Heltec_v2_repeater","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -164,43 +290,39 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "companionUsb",
|
"role": "companionUsb",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v3_companion_radio_usb.bin",
|
"flash": ["Heltec_v3_companion_radio_usb","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "companionBle",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v3_companion_radio_ble.bin",
|
"flash": ["Heltec_v3_companion_radio_ble","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v3_repeater.bin",
|
"flash": ["Heltec_v3_repeater","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "roomServer",
|
"role": "roomServer",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "room-server",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_v3_room_server.bin",
|
"flash": ["Heltec_v3_room_server","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -210,34 +332,50 @@
|
||||||
"tooltip": "<img class='device' src='/img/heltec_t114.png'>",
|
"tooltip": "<img class='device' src='/img/heltec_t114.png'>",
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_T114_repeater.zip",
|
"flash": ["Heltec_t114_companion_radio_ble","zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["Heltec_t114_companion_radio_ble","uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "Heltec_T114_repeater.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "repeater",
|
||||||
|
"github": {
|
||||||
|
"type": "repeater",
|
||||||
|
"files": {
|
||||||
|
"flash": ["Heltec_t114_repeater","zip"],
|
||||||
|
"download": ["Heltec_t114_repeater","uf2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "roomServer",
|
"role": "roomServer",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "room-server",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Heltec_T114_room_server.zip",
|
"flash": ["Heltec_t114_room_server","zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["Heltec_t114_room_server","uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "Heltec_T114_room_server.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Heltec WSL3",
|
||||||
|
"type": "esp32",
|
||||||
|
"tooltip": "<img class='device' src='/img/heltec_wsl3.png'>",
|
||||||
|
"firmware": [
|
||||||
|
{
|
||||||
|
"role": "companionBle",
|
||||||
|
"github": {
|
||||||
|
"type": "companion",
|
||||||
|
"files": {
|
||||||
|
"flash": ["Heltec_WSL3_companion_radio_ble","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -248,63 +386,43 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "companionUsb",
|
"role": "companionUsb",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "RAK_4631_companion_radio_usb.zip",
|
"flash": ["RAK_4631_companion_radio_usb", "zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["RAK_4631_companion_radio_usb", "uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "RAK_4631_companion_radio_usb.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "companionBle",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "RAK_4631_companion_radio_ble.zip",
|
"flash": ["RAK_4631_companion_radio_ble", "zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["RAK_4631_companion_radio_ble", "uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "RAK_4631_companion_radio_ble.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "RAK_4631_Repeater.zip",
|
"flash": ["RAK_4631_Repeater", "zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["RAK_4631_Repeater", "uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "RAK_4631_Repeater.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "roomServer",
|
"role": "roomServer",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "room-server",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "RAK_4631_room_server.zip",
|
"flash": ["RAK_4631_room_server", "zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["RAK_4631_room_server", "uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "RAK_4631_room_server.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -315,18 +433,13 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "companionBle",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Seeed_T1000e_companion_radio_ble.zip",
|
"flash": ["t1000e_companion_radio_ble", "zip"],
|
||||||
"title": "firmware OTA zip"
|
"download": ["t1000e_companion_radio_ble", "uf2"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"name": "Seeed_T1000e_companion_radio_ble.uf2",
|
|
||||||
"title": "firmware uf2"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -337,25 +450,23 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"title": "Repeater (Semtech SX1262)",
|
"subTitle": "(sx1262 version)",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Xiao_C3_Repeater_sx1262.bin",
|
"flash": ["Xiao_C3_Repeater_sx1262","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"title": "Repeater (Semtech SX1268)",
|
"subTitle": "(sx1268 version)",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Xiao_C3_Repeater_sx1268.bin",
|
"flash": ["Xiao_C3_Repeater_sx1268","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -365,14 +476,22 @@
|
||||||
"type": "esp32",
|
"type": "esp32",
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "companionBle",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "companion",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Xiao_S3_WIO_Repeater.bin",
|
"flash": ["Xiao_S3_WIO_companion_radio_ble","merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "repeater",
|
||||||
|
"github": {
|
||||||
|
"type": "repeater",
|
||||||
|
"files": {
|
||||||
|
"flash": ["Xiao_S3_WIO_Repeater","merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -383,13 +502,21 @@
|
||||||
"firmware": [
|
"firmware": [
|
||||||
{
|
{
|
||||||
"role": "repeater",
|
"role": "repeater",
|
||||||
"files": [
|
"github": {
|
||||||
{
|
"type": "repeater",
|
||||||
"type": "flash",
|
"files": {
|
||||||
"name": "Station_G2_repeater.bin",
|
"flash": ["Station_G2_repeater", "merged.bin"]
|
||||||
"title": "Combined app+partition+bootloader firmware bin"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "roomServer",
|
||||||
|
"github": {
|
||||||
|
"type": "room-server",
|
||||||
|
"files": {
|
||||||
|
"flash": ["Station_G2_room_server", "merged.bin"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,47 @@
|
||||||
|
[v-cloak] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#flasher {
|
#app {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
#flasher img.device {
|
#app select {
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
#app img.device {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
#flasher div.autoscroller {
|
#app div.autoscroller {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
}
|
}
|
||||||
#flasher pre.term {
|
#app pre.term {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
#flasher .overlay {
|
#app .overlay {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#flasher .console {
|
#app .console {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
#flasher .console .holder {
|
#app .console .holder {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
#flasher .console-input {
|
#app .console-input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: block;
|
display: block;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
|
@ -43,6 +50,6 @@ body {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
}
|
}
|
||||||
#flasher .console-input:focus, #flasher console-input:focus{
|
#app .console-input:focus, #app console-input:focus{
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
338
flasher.js
338
flasher.js
|
|
@ -1,13 +1,16 @@
|
||||||
import "./lib/beer.min.js";
|
import "./lib/beer.min.js";
|
||||||
import { createApp, reactive, ref, nextTick } from "./lib/vue.min.js";
|
import { createApp, reactive, ref, nextTick, watch, computed } from "./lib/vue.min.js";
|
||||||
import { Dfu } from "./lib/dfu.js";
|
import { Dfu } from "./lib/dfu.js";
|
||||||
import { ESPLoader, Transport, HardReset } from "./lib/esp32.js";
|
import { ESPLoader, Transport, HardReset } from "./lib/esp32.js";
|
||||||
import { SerialConsole } from './lib/console.js';
|
import { SerialConsole } from './lib/console.js';
|
||||||
|
|
||||||
const res = await fetch('./config.json');
|
const configRes = await fetch('./config.json');
|
||||||
const config = await res.json();
|
const config = await configRes.json();
|
||||||
|
|
||||||
|
const githubRes = await fetch('/releases');
|
||||||
|
const github = await githubRes.json();
|
||||||
|
|
||||||
const commandReference = {
|
const commandReference = {
|
||||||
'set freq ': 'Set frequency {Mhz}',
|
|
||||||
'time ': 'Set time {epoch-secs}',
|
'time ': 'Set time {epoch-secs}',
|
||||||
'erase': 'Erase filesystem',
|
'erase': 'Erase filesystem',
|
||||||
'advert': 'Send Advertisment packet',
|
'advert': 'Send Advertisment packet',
|
||||||
|
|
@ -19,6 +22,7 @@ const commandReference = {
|
||||||
'log stop': 'Stop packet logging to file system',
|
'log stop': 'Stop packet logging to file system',
|
||||||
'log erase': 'Erase the packet logs from file system',
|
'log erase': 'Erase the packet logs from file system',
|
||||||
'ver': 'Show device version',
|
'ver': 'Show device version',
|
||||||
|
'set freq ': 'Set frequency {Mhz}',
|
||||||
'set af ': 'Set Air-time factor',
|
'set af ': 'Set Air-time factor',
|
||||||
'set tx ': 'Set Tx power {dBm}',
|
'set tx ': 'Set Tx power {dBm}',
|
||||||
'set repeat ': 'Set repeater mode {on|off}',
|
'set repeat ': 'Set repeater mode {on|off}',
|
||||||
|
|
@ -27,8 +31,53 @@ const commandReference = {
|
||||||
'set name ': 'Set advertisement name',
|
'set name ': 'Set advertisement name',
|
||||||
'set lat': 'Set the advertisement map latitude',
|
'set lat': 'Set the advertisement map latitude',
|
||||||
'set lon': 'Set the advertisement map longitude',
|
'set lon': 'Set the advertisement map longitude',
|
||||||
|
'get freq ': 'Get frequency (Mhz)',
|
||||||
|
'get af': 'Get Air-time factor',
|
||||||
|
'get tx': 'Get Tx power (dBm)',
|
||||||
|
'get repeat': 'Get repeater mode',
|
||||||
|
'get advert.interval': 'Get advert rebroadcast interval (minutes)',
|
||||||
|
'get name': 'Get advertisement name',
|
||||||
|
'get lat': 'Get the advertisement map latitude',
|
||||||
|
'get lon': 'Get the advertisement map longitude',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getGithubReleases(roleType, files) {
|
||||||
|
const versions = {};
|
||||||
|
for(const [fileType, [startsWith, endsWith]] of Object.entries(files)) {
|
||||||
|
for(const versionType of github) {
|
||||||
|
if(versionType.type !== roleType) { continue }
|
||||||
|
const version = versions[versionType.version] ??= {
|
||||||
|
notes: versionType.notes,
|
||||||
|
files: []
|
||||||
|
};
|
||||||
|
for(const file of versionType.files) {
|
||||||
|
if(!(file.name.startsWith(startsWith) && file.name.endsWith(endsWith))) { continue }
|
||||||
|
version.files.push({
|
||||||
|
type: fileType,
|
||||||
|
name: file.url,
|
||||||
|
title: file.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addGithubFiles() {
|
||||||
|
for(const device of config.device) {
|
||||||
|
for(const firmware of device.firmware) {
|
||||||
|
const gDef = firmware.github;
|
||||||
|
if(!gDef?.files) { continue }
|
||||||
|
firmware.version = getGithubReleases(gDef.type, gDef.files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(addGithubFiles());
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
const consoleEditBox = ref();
|
const consoleEditBox = ref();
|
||||||
const consoleWindow = ref();
|
const consoleWindow = ref();
|
||||||
|
|
@ -36,11 +85,23 @@ function setup() {
|
||||||
const selected = reactive({
|
const selected = reactive({
|
||||||
device: null,
|
device: null,
|
||||||
firmware: null,
|
firmware: null,
|
||||||
|
version: null,
|
||||||
wipe: false,
|
wipe: false,
|
||||||
port: null
|
port: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getRoleFwValue = (firmware, key) => {
|
||||||
|
return firmware[key] || config.role[firmware.role][key] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelFwValue = (key) => {
|
||||||
|
const fwVersion = selected.firmware.version[selected.version];
|
||||||
|
|
||||||
|
return fwVersion ? fwVersion[key] || '' : '';
|
||||||
|
}
|
||||||
|
|
||||||
const flashing = reactive({
|
const flashing = reactive({
|
||||||
|
supported: 'Serial' in window,
|
||||||
instance: null,
|
instance: null,
|
||||||
active: false,
|
active: false,
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
|
|
@ -68,14 +129,47 @@ function setup() {
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFirmwarePath = (file) => {
|
||||||
|
return file.name.startsWith('/') ? file.name : `${config.staticPath}/${file.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firmwareHasData = (firmware) => {
|
||||||
|
const firstVersion = Object.keys(firmware.version)[0];
|
||||||
|
if(!firstVersion) return false;
|
||||||
|
|
||||||
|
return firmware.version[firstVersion].files.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepBack = () => {
|
||||||
|
if(selected.device && selected.firmware) {
|
||||||
|
if(selected.firmware.version[selected.version].customFile) {
|
||||||
|
selected.firmware = null;
|
||||||
|
selected.device = null;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selected.firmware = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selected.device) {
|
||||||
|
selected.device = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => selected.firmware, (firmware) => {
|
||||||
|
if(firmware == null) return;
|
||||||
|
selected.version = Object.keys(firmware.version)[0];
|
||||||
|
});
|
||||||
|
|
||||||
const flasherCleanup = async () => {
|
const flasherCleanup = async () => {
|
||||||
const port = selected.port;
|
|
||||||
flashing.active = false;
|
flashing.active = false;
|
||||||
flashing.log = '';
|
flashing.log = '';
|
||||||
flashing.error = '';
|
flashing.error = '';
|
||||||
flashing.dfuComplete = false;
|
flashing.dfuComplete = false;
|
||||||
flashing.percentage = 0;
|
flashing.percentage = 0;
|
||||||
selected.firmware = null;
|
selected.firmware = null;
|
||||||
|
selected.version = null;
|
||||||
selected.wipe = false;
|
selected.wipe = false;
|
||||||
selected.device = null;
|
selected.device = null;
|
||||||
if(flashing.instance instanceof ESPLoader) {
|
if(flashing.instance instanceof ESPLoader) {
|
||||||
|
|
@ -118,17 +212,49 @@ function setup() {
|
||||||
flashing.dfuComplete = true;
|
flashing.dfuComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customFirmwareLoad = async(ev) => {
|
||||||
|
const firmwareFile = ev.target.files[0];
|
||||||
|
const type = firmwareFile.name.endsWith('.bin') ? 'esp32' : 'nrf52';
|
||||||
|
selected.device = {
|
||||||
|
name: 'Custom device',
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
|
||||||
|
selected.firmware = {
|
||||||
|
icon: 'unknown_document',
|
||||||
|
title: firmwareFile.name,
|
||||||
|
version: {},
|
||||||
|
}
|
||||||
|
selected.version = firmwareFile.name;
|
||||||
|
selected.firmware.version[selected.version] = {
|
||||||
|
customFile: true,
|
||||||
|
files: [{ type: 'flash', file: firmwareFile }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const flashDevice = async() => {
|
const flashDevice = async() => {
|
||||||
const device = selected.device;
|
const device = selected.device;
|
||||||
const firmware = selected.firmware;
|
const firmware = selected.firmware.version[selected.version];
|
||||||
const flashFile = firmware.files.find(f => f.type === 'flash');
|
let flashFile;
|
||||||
|
|
||||||
|
flashFile = firmware.files.find(f => f.type === 'flash');
|
||||||
if(!flashFile) {
|
if(!flashFile) {
|
||||||
alert('Cannot find configuration for flash file! please report this to Discord.')
|
alert('Cannot find configuration for flash file! please report this to Discord.')
|
||||||
flasherCleanup();
|
flasherCleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = `${config.basePath}/${flashFile.name}`;
|
|
||||||
const resp = await fetch(url);
|
console.log({flashFile, instanceFile: flashFile instanceof File});
|
||||||
|
|
||||||
|
if(flashFile.file) {
|
||||||
|
flashFile = flashFile.file;
|
||||||
|
} else {
|
||||||
|
const url = getFirmwarePath(flashFile);
|
||||||
|
console.log('downloading: ' + url);
|
||||||
|
const resp = await fetch(url);
|
||||||
|
flashFile = await resp.blob();
|
||||||
|
}
|
||||||
|
|
||||||
const port = selected.port = await navigator.serial.requestPort({});
|
const port = selected.port = await navigator.serial.requestPort({});
|
||||||
|
|
||||||
if(device.type === 'esp32') {
|
if(device.type === 'esp32') {
|
||||||
|
|
@ -138,9 +264,15 @@ function setup() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
fileData = await new Promise(async (resolve) => {
|
fileData = await new Promise((resolve, reject) => {
|
||||||
|
reader.addEventListener('error', () => {
|
||||||
|
reader.abort();
|
||||||
|
reject(new DOMException('Problem parsing input file.'));
|
||||||
|
});
|
||||||
|
|
||||||
reader.addEventListener('load', () => resolve(reader.result));
|
reader.addEventListener('load', () => resolve(reader.result));
|
||||||
reader.readAsBinaryString(await resp.blob());
|
|
||||||
|
reader.readAsBinaryString(flashFile);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
|
|
@ -163,13 +295,8 @@ function setup() {
|
||||||
data: fileData,
|
data: fileData,
|
||||||
address: 0
|
address: 0
|
||||||
}],
|
}],
|
||||||
reportProgress: async (fileIndex, written, total) => {
|
reportProgress: async (_, written, total) => {
|
||||||
flashing.percentage = (written / total) * 100;
|
flashing.percentage = (written / total) * 100;
|
||||||
|
|
||||||
// we're done with this file
|
|
||||||
if (written === total) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -204,11 +331,10 @@ function setup() {
|
||||||
else if(device.type === 'nrf52') {
|
else if(device.type === 'nrf52') {
|
||||||
const dfu = flashing.instance = new Dfu(port, selected.wipe);
|
const dfu = flashing.instance = new Dfu(port, selected.wipe);
|
||||||
|
|
||||||
const zipFile = await resp.blob();
|
|
||||||
flashing.active = true;
|
flashing.active = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await dfu.dfuUpdate(zipFile, async (progress) => {
|
await dfu.dfuUpdate(flashFile, async (progress) => {
|
||||||
flashing.percentage = progress;
|
flashing.percentage = progress;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -225,173 +351,11 @@ function setup() {
|
||||||
config, selected, flashing,
|
config, selected, flashing,
|
||||||
flashDevice, flasherCleanup, dfuMode,
|
flashDevice, flasherCleanup, dfuMode,
|
||||||
serialCon, openSerialCon, sendCommand, closeSerialCon,
|
serialCon, openSerialCon, sendCommand, closeSerialCon,
|
||||||
refresh, commandReference
|
refresh, commandReference,
|
||||||
|
stepBack,
|
||||||
|
customFirmwareLoad, getFirmwarePath, getSelFwValue, getRoleFwValue,
|
||||||
|
firmwareHasData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const template = `
|
createApp({ setup }).mount('#app');
|
||||||
<div class="flash-container">
|
|
||||||
<div v-if="flashing.active">
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<i>developer_board</i>
|
|
||||||
<span class="small">{{ selected.device.name }}</span>
|
|
||||||
<i>chevron_right</i>
|
|
||||||
<i>{{ selected.firmware.icon }}</i>
|
|
||||||
<span class="small">{{ selected.firmware.title }}</span>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<article v-if="flashing.error">
|
|
||||||
<div class="row">
|
|
||||||
<div class="max">
|
|
||||||
<h6>Flashing failed!</h6>
|
|
||||||
<p><span>{{ flashing.error }}</span></p>
|
|
||||||
<p><button @click="refresh()">Retry</button></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<article v-else>
|
|
||||||
<div class="row">
|
|
||||||
<div class="max" v-if="flashing.percentage < 100">
|
|
||||||
<h6><progress class="circle small"></progress> Flashing...</h6>
|
|
||||||
<p>Please do not disconnect the device</p>
|
|
||||||
</div>
|
|
||||||
<div class="max" v-else=>
|
|
||||||
<h6>Flashing complete!</h6>
|
|
||||||
<p>
|
|
||||||
<button @click="flasherCleanup()">Close</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="autoscroller">
|
|
||||||
<pre class="term" v-if="flashing.terminal">{{ flashing.terminal }}</pre>
|
|
||||||
</div>
|
|
||||||
<nav>
|
|
||||||
<progress :value="flashing.percentage" max="100"></progress>
|
|
||||||
</nav>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="selected.firmware">
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<button class="circle transparent" @click="selected.firmware = null"><i>arrow_back</i></button>
|
|
||||||
<i>developer_board</i>
|
|
||||||
<a class="small" href="javascript:;" @click="selected.firmware = null">{{ selected.device.name }}</a>
|
|
||||||
<i>chevron_right</i>
|
|
||||||
<i>{{ selected.firmware.icon }}</i>
|
|
||||||
<span class="small">{{ selected.firmware.desc }}</span>
|
|
||||||
</nav>
|
|
||||||
<nav class="no-margin">
|
|
||||||
<h6 class="small max">Install options</h6>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<ul class="list border" v-if="selected.device.type === 'esp32'">
|
|
||||||
<li>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" v-model="selected.wipe">
|
|
||||||
<span>Erase device</span>
|
|
||||||
<div class="tooltip right max">
|
|
||||||
DO NOT carry out a full erase if you are simply updating your MeshCore device, otherwise it will erase your MeshCore identity for that device.
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button @click="dfuMode" :disabled="flashing.dfuComplete" v-if="selected.device.type === 'nrf52'">
|
|
||||||
<i>{{ flashing.dfuComplete ? 'check' : 'code' }}</i>
|
|
||||||
<span>{{ flashing.dfuComplete ? 'DFU mode active' : 'Enter DFU mode' }}</span>
|
|
||||||
<div class="tooltip right max">
|
|
||||||
Enter DFU mode - this mode enables you to flash your firmware.
|
|
||||||
If you did not trigger the DFU mode manually, please click this button.
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<div class="medium-space"></div>
|
|
||||||
<nav class="small-margin">
|
|
||||||
<button @click="flashDevice">
|
|
||||||
<i>bolt</i>
|
|
||||||
<span>Flash!</span>
|
|
||||||
<div class="tooltip right max">
|
|
||||||
Upload the firmware into your device. Existing firwmare will get overwritten.
|
|
||||||
<span v-if="selected.device.type === 'nrf52'">If you did not trigger DFU mode manually, use the <b>Enter DFU mode</b> before flashing</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<div class="max"></div>
|
|
||||||
<button data-ui="#down" class="active">
|
|
||||||
<i>download</i>
|
|
||||||
<span>Download</span><i>arrow_drop_down</i>
|
|
||||||
<menu class="no-wrap" id="down" data-ui="#down">
|
|
||||||
<li v-for="file in selected.firmware.files">
|
|
||||||
<a data-ui="menu-selector" :href="config.basePath + '/' + file.name" download>{{ file.title }}</a>
|
|
||||||
</li>
|
|
||||||
</menu>
|
|
||||||
<div class="tooltip left max">Download a copy of the firmware files for use with other flashers</div>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="selected.device">
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<button class="circle transparent" @click="selected.device = null"><i>arrow_back</i></button>
|
|
||||||
<i>developer_board</i>
|
|
||||||
<span>{{ selected.device.name }}</span>
|
|
||||||
</nav>
|
|
||||||
<nav class="no-margin">
|
|
||||||
<h6 class="small max">Choose role</h6>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<ul class="list border">
|
|
||||||
<li v-for="firmware in selected.device.firmware" :class="firmware.class || config.role[firmware.role].class || ''">
|
|
||||||
<button class="transparent" @click="selected.firmware = firmware">
|
|
||||||
<i>{{ firmware.icon || config.role[firmware.role].icon }}</i>
|
|
||||||
<span>{{ firmware.title || config.role[firmware.role].title }}</span>
|
|
||||||
<div class="tooltip right max" v-if="firmware.tooltip || config.role[firmware.role].tooltip" v-html="firmware.tooltip || config.role[firmware.role].tooltip"></div>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<i>bolt</i>
|
|
||||||
<h5 class="small max">MeshCore flasher</h5>
|
|
||||||
<button class="transparent" @click="openSerialCon()">
|
|
||||||
<i>terminal</i>
|
|
||||||
<span>Console</span>
|
|
||||||
<div class="tooltip left max">Open serial console to manage Routers and Room servers</div>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
<nav class="no-margin">
|
|
||||||
<h6 class="small max">Choose device</h6>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<ul class="list border">
|
|
||||||
<li v-for="device in config.device">
|
|
||||||
<button class="transparent" @click="selected.device = device">
|
|
||||||
<i>developer_board</i>
|
|
||||||
<span>{{ device.name }}</span>
|
|
||||||
<div class="tooltip right max" v-if="device.tooltip" v-html="device.tooltip"></div>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="serialCon.opened" class="overlay active">
|
|
||||||
<datalist id="command-db">
|
|
||||||
<option v-for="(desc, command) in commandReference" :value="command">{{ desc }}</option>
|
|
||||||
</datalist>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<button class="circle transparent" @click="closeSerialCon()"><i>arrow_back</i></button>
|
|
||||||
<h6 class="small max">Serial Console</h6>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<pre class="console" @click="consoleEditBox.focus()" ref="consoleWindow">
|
|
||||||
<code>{{ serialCon.content }}</code>
|
|
||||||
<div class="holder">
|
|
||||||
<span>></span>
|
|
||||||
<input ref="consoleEditBox" class="console-input" type="text" v-model="serialCon.edit" @keydown.enter.prevent="sendCommand(serialCon.edit)" list="command-db">
|
|
||||||
</div>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
createApp({ setup, template }).mount('#flasher');
|
|
||||||
|
|
|
||||||
BIN
img/heltec_wsl3.png
Normal file
BIN
img/heltec_wsl3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
BIN
img/lilygo_techo.png
Normal file
BIN
img/lilygo_techo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
199
index.html
199
index.html
|
|
@ -11,7 +11,204 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="dark">
|
<body class="dark">
|
||||||
<div id="flasher"></div>
|
<div id="app" v-cloak>
|
||||||
|
<div class="flash-container">
|
||||||
|
<div v-if="flashing.active">
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<i>developer_board</i>
|
||||||
|
<span class="small">{{ selected.device.name }}</span>
|
||||||
|
<i>chevron_right</i>
|
||||||
|
<i>{{ selected.firmware.icon || config.role[selected.firmware.role].icon }}</i>
|
||||||
|
<span class="small">{{ selected.firmware.title || config.role[selected.firmware.role].title }}</span>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<article v-if="flashing.error">
|
||||||
|
<div class="row">
|
||||||
|
<div class="max">
|
||||||
|
<h6>Flashing failed!</h6>
|
||||||
|
<p><span>{{ flashing.error }}</span></p>
|
||||||
|
<p><button @click="refresh()">Retry</button></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article v-else>
|
||||||
|
<div class="row">
|
||||||
|
<div class="max" v-if="flashing.percentage < 100">
|
||||||
|
<h6><progress class="circle small"></progress> Flashing...</h6>
|
||||||
|
<p>Please do not disconnect the device</p>
|
||||||
|
</div>
|
||||||
|
<div class="max" v-else>
|
||||||
|
<h6>Flashing complete!</h6>
|
||||||
|
<p>
|
||||||
|
<button @click="flasherCleanup()">Close</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="autoscroller">
|
||||||
|
<pre class="term" v-if="flashing.terminal">{{ flashing.terminal }}</pre>
|
||||||
|
</div>
|
||||||
|
<nav>
|
||||||
|
<progress :value="flashing.percentage" max="100"></progress>
|
||||||
|
</nav>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="selected.firmware">
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<button class="circle transparent" @click="stepBack"><i>arrow_back</i></button>
|
||||||
|
<i>developer_board</i>
|
||||||
|
<a class="small" href="javascript:;" @click="stepBack">{{ selected.device.name }}</a>
|
||||||
|
<i>chevron_right</i>
|
||||||
|
<i>{{ getRoleFwValue(selected.firmware, 'icon') }}</i>
|
||||||
|
<span class="small">{{ getRoleFwValue(selected.firmware, 'title') }}</span>
|
||||||
|
</nav>
|
||||||
|
<nav>
|
||||||
|
<div class="field label suffix border small">
|
||||||
|
<select v-model="selected.version">
|
||||||
|
<template v-for="(version, versionName) in selected.firmware.version">
|
||||||
|
<option v-if="version.files.length > 0">{{ versionName }}</option>
|
||||||
|
</template>
|
||||||
|
</select>
|
||||||
|
<label>Version</label>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
|
</div>
|
||||||
|
<span v-if="getSelFwValue('notes')" class="max">
|
||||||
|
{{ getSelFwValue('notes') }}
|
||||||
|
</span>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<ul class="list border" v-if="selected.device.type === 'esp32'">
|
||||||
|
<li>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" v-model="selected.wipe">
|
||||||
|
<span>Erase device</span>
|
||||||
|
<div class="tooltip right max">
|
||||||
|
DO NOT carry out a full erase if you are simply updating your MeshCore device,
|
||||||
|
otherwise it will erase your MeshCore identity for that device.
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button @click="dfuMode" :disabled="flashing.dfuComplete || !flashing.supported" v-if="selected.device.type === 'nrf52'">
|
||||||
|
<i>{{ flashing.dfuComplete ? 'check' : 'code' }}</i>
|
||||||
|
<span>{{ flashing.dfuComplete ? 'DFU mode active' : 'Enter DFU mode' }}</span>
|
||||||
|
<div class="tooltip right max" v-if="flashing.supported">
|
||||||
|
Enter DFU mode - this mode enables you to flash your firmware.
|
||||||
|
If you did not trigger the DFU mode manually, please click this button.
|
||||||
|
</div>
|
||||||
|
<div class="tooltip right max" v-else>
|
||||||
|
Your browser doesn't support Web Serial API. Please use Chrome or Edge on Desktop
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<div class="medium-space"></div>
|
||||||
|
<nav class="small-margin">
|
||||||
|
<button @click="flashDevice" :disabled="!flashing.supported">
|
||||||
|
<i>bolt</i>
|
||||||
|
<span>Flash!</span>
|
||||||
|
<div class="tooltip right max" v-if="flashing.supported">
|
||||||
|
Upload the firmware into your device. Existing firwmare will get overwritten.
|
||||||
|
<span v-if="selected.device.type === 'nrf52'">
|
||||||
|
If you did not trigger DFU mode manually, use the <b>Enter DFU mode</b> before flashing
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip right max" v-else>
|
||||||
|
Your browser doesn't support Web Serial API. Please use Chrome or Edge on Desktop
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<div class="max"></div>
|
||||||
|
<button data-ui="#down" class="active" v-if="!getSelFwValue('customFile')">
|
||||||
|
<i>download</i>
|
||||||
|
<span>Download</span><i>arrow_drop_down</i>
|
||||||
|
<menu class="left no-wrap" id="down" data-ui="#down">
|
||||||
|
<li v-for="file in getSelFwValue('files')">
|
||||||
|
<a data-ui="menu-selector" :href="getFirmwarePath(file)" download>{{ file.title }}</a>
|
||||||
|
</li>
|
||||||
|
</menu>
|
||||||
|
<div class="tooltip left max">Download a copy of the firmware files for use with other flashers</div>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="selected.device">
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<button class="circle transparent" @click="stepBack"><i>arrow_back</i></button>
|
||||||
|
<i>developer_board</i>
|
||||||
|
<span>{{ selected.device.name }}</span>
|
||||||
|
</nav>
|
||||||
|
<nav class="no-margin">
|
||||||
|
<h6 class="small max">Choose role</h6>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<ul class="list border">
|
||||||
|
<template v-for="firmware in selected.device.firmware">
|
||||||
|
<li v-if="firmwareHasData(firmware)" :class="getRoleFwValue(firmware, 'class')">
|
||||||
|
<button class="transparent" @click="selected.firmware = firmware">
|
||||||
|
<i>{{ getRoleFwValue(firmware, 'icon') }}</i>
|
||||||
|
<span>{{ getRoleFwValue(firmware, 'title') }} {{ getRoleFwValue(firmware, 'subTitle') }}</span>
|
||||||
|
<div class="tooltip right max" v-if="getRoleFwValue(firmware, 'tooltip')" v-html="getRoleFwValue(firmware, 'tooltip')"></div>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<i>bolt</i>
|
||||||
|
<h5 class="small max">MeshCore flasher</h5>
|
||||||
|
<button class="transparent" @click="openSerialCon()">
|
||||||
|
<i>terminal</i>
|
||||||
|
<span>Console</span>
|
||||||
|
<div class="tooltip left max">Open serial console to manage Routers and Room servers</div>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
<nav class="no-margin">
|
||||||
|
<h6 class="small max">Choose device</h6>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<ul class="list border">
|
||||||
|
<li v-for="device in config.device">
|
||||||
|
<button class="transparent" @click="selected.device = device">
|
||||||
|
<i>developer_board</i>
|
||||||
|
<span>{{ device.name }}</span>
|
||||||
|
<div class="tooltip right max" v-if="device.tooltip" v-html="device.tooltip"></div>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="transparent">
|
||||||
|
<i>unknown_document</i>
|
||||||
|
<span>Custom Firmware</span>
|
||||||
|
<div class="tooltip right max">
|
||||||
|
Flash custom firmware file from your computer.
|
||||||
|
Flasher supports <b>.bin</b> files for esp32 devices and OTA <b>.zip</b> files for nRF52 devices.
|
||||||
|
</div>
|
||||||
|
<input type="file" accept=".zip,.bin" @change="customFirmwareLoad">
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="serialCon.opened" class="overlay active">
|
||||||
|
<datalist id="command-db">
|
||||||
|
<option v-for="(desc, command) in commandReference" :value="command">{{ desc }}</option>
|
||||||
|
</datalist>
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<button class="circle transparent" @click="closeSerialCon()"><i>arrow_back</i></button>
|
||||||
|
<h6 class="small max">Serial Console</h6>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<pre class="console" @click="consoleEditBox.focus()" ref="consoleWindow">
|
||||||
|
<code>{{ serialCon.content }}</code>
|
||||||
|
<div class="holder">
|
||||||
|
<span>></span>
|
||||||
|
<input ref="consoleEditBox" class="console-input" type="text" v-model="serialCon.edit" @keydown.enter.prevent="sendCommand(serialCon.edit)" list="command-db">
|
||||||
|
</div>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue