docker-compose-editor #1
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-question-circle" viewBox="0 0 16 16"> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/> <path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286m1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94"/> </svg>
|
After Width: | Height: | Size: 715 B |
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#06c" width="36" height="36" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" stroke="#06c">
|
||||||
|
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_iconCarrier"> <g id="Temp_High" data-name="Temp High"> <g> <path d="M14.863,13.4V4.939a2.929,2.929,0,0,0-.84-2.03,2.859,2.859,0,0,0-2.23-.82,2.948,2.948,0,0,0-2.66,3l.01,8.28a4.755,4.755,0,0,0,1.9,8.46,5.093,5.093,0,0,0,.95.09,4.759,4.759,0,0,0,4.76-4.75A4.684,4.684,0,0,0,14.863,13.4Zm-.48,6.66a3.783,3.783,0,0,1-3.15.78,3.7,3.7,0,0,1-2.92-2.98,3.745,3.745,0,0,1,1.43-3.69.962.962,0,0,0,.39-.77V5.089a1.968,1.968,0,0,1,1.73-2,.66.66,0,0,1,.14-.01,1.878,1.878,0,0,1,1.86,1.86V13.4a.962.962,0,0,0,.39.77,3.742,3.742,0,0,1,.13,5.89Z"/> <path d="M13.893,17.169a1.89,1.89,0,0,1-3.78,0,1.858,1.858,0,0,1,1.39-1.81V5.4a.5.5,0,0,1,1,0v9.96A1.869,1.869,0,0,1,13.893,17.169Z"/> </g> </g> </g>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#06c">
|
||||||
|
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_iconCarrier"> <path d="M16 10L18.5768 8.45392C19.3699 7.97803 19.7665 7.74009 20.0928 7.77051C20.3773 7.79703 20.6369 7.944 20.806 8.17433C21 8.43848 21 8.90095 21 9.8259V14.1741C21 15.099 21 15.5615 20.806 15.8257C20.6369 16.056 20.3773 16.203 20.0928 16.2295C19.7665 16.2599 19.3699 16.022 18.5768 15.5461L16 14M6.2 18H12.8C13.9201 18 14.4802 18 14.908 17.782C15.2843 17.5903 15.5903 17.2843 15.782 16.908C16 16.4802 16 15.9201 16 14.8V9.2C16 8.0799 16 7.51984 15.782 7.09202C15.5903 6.71569 15.2843 6.40973 14.908 6.21799C14.4802 6 13.9201 6 12.8 6H6.2C5.0799 6 4.51984 6 4.09202 6.21799C3.71569 6.40973 3.40973 6.71569 3.21799 7.09202C3 7.51984 3 8.07989 3 9.2V14.8C3 15.9201 3 16.4802 3.21799 16.908C3.40973 17.2843 3.71569 17.5903 4.09202 17.782C4.51984 18 5.07989 18 6.2 18Z" stroke="#06c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="36" height="36" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
|
||||||
|
<g id="SVGRepo_iconCarrier"> <path d="M0 7L1.17157 5.82843C2.98259 4.01741 5.43884 3 8 3C10.5612 3 13.0174 4.01742 14.8284 5.82843L16 7L14.5858 8.41421L13.4142 7.24264C11.9783 5.8067 10.0307 5 8 5C5.96928 5 4.02173 5.8067 2.58579 7.24264L1.41421 8.41421L0 7Z" fill="#06c"/> <path d="M4.24264 11.2426L2.82843 9.82843L4 8.65685C5.06086 7.59599 6.49971 7 8 7C9.50029 7 10.9391 7.59599 12 8.65686L13.1716 9.82843L11.7574 11.2426L10.5858 10.0711C9.89999 9.38527 8.96986 9 8 9C7.03014 9 6.1 9.38527 5.41421 10.0711L4.24264 11.2426Z" fill="#06c"/> <path d="M8 15L5.65685 12.6569L6.82842 11.4853C7.13914 11.1746 7.56057 11 8 11C8.43942 11 8.86085 11.1746 9.17157 11.4853L10.3431 12.6569L8 15Z" fill="#06c"/> </g>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -11,84 +11,43 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container mt-5 mb-5">
|
||||||
<div class="row mt-4">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h2 class="fw-bold">SpiriLink Configuration</h2>
|
<h2 class="fw-bold">SpiriLink Configuration</h2>
|
||||||
<p>Configuration File: <i><span
|
<p>Configuration File: <i><span id="file_location"></span></i></p>
|
||||||
id='file_location'></span></i></p>
|
<p>SpiriLink provides MAVLink, RTSP video, and a UDP tunnel over a modified 8812EU wireless card to provide a long distance, high speed wireless link. Edit the configuration settings below.</p>
|
||||||
<p>SpiriLink provides Mavlink, RTSP video and a UDP tunnel over a modified 8812EU wireless card to provide a long distance, high speed wireless link. Edit the configuration settings below.</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Save Button -->
|
||||||
|
<div class="row mt-4 mb-4">
|
||||||
|
<div class="col-6">
|
||||||
|
<button class="btn btn-primary" id="save">Save/Update</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 d-flex justify-content-end">
|
||||||
|
<button id="applyEncryptionFile" class="btn btn-primary">Apply Encryption File from Base Station</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre id="result" class="mt-3 mb-3"></pre>
|
||||||
|
|
||||||
<!-- WiFi Configuration -->
|
<!-- WiFi Configuration -->
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<img src="settings_ethernet.svg" class="me-2"> WiFi Configuration
|
<img src="assets/icons/settings_wifi.svg" class="me-2"/><span>WiFi Configuration</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="wifiChannel" class="form-label">WiFi Channel</label>
|
<label for="wifiChannel" class="form-label">WiFi Channel</label>
|
||||||
<select id="wifiChannel" class="form-select">
|
<select id="wifiChannel" class="form-select"></select>
|
||||||
<!-- 2.4 GHz Channels -->
|
|
||||||
<option value="1">1 (2.412 GHz)</option>
|
|
||||||
<option value="2">2 (2.417 GHz)</option>
|
|
||||||
<option value="3">3 (2.422 GHz)</option>
|
|
||||||
<option value="4">4 (2.427 GHz)</option>
|
|
||||||
<option value="5">5 (2.432 GHz)</option>
|
|
||||||
<option value="6">6 (2.437 GHz)</option>
|
|
||||||
<option value="7">7 (2.442 GHz)</option>
|
|
||||||
<option value="8">8 (2.447 GHz)</option>
|
|
||||||
<option value="9">9 (2.452 GHz)</option>
|
|
||||||
<option value="10">10 (2.457 GHz)</option>
|
|
||||||
<option value="11">11 (2.462 GHz)</option>
|
|
||||||
<option value="12">12 (2.467 GHz)</option>
|
|
||||||
<option value="13">13 (2.472 GHz)</option>
|
|
||||||
<option value="14">14 (2.484 GHz, Japan only)</option>
|
|
||||||
|
|
||||||
<!-- 5 GHz Channels -->
|
|
||||||
<option value="36">36 (5.180 GHz)</option>
|
|
||||||
<option value="40">40 (5.200 GHz)</option>
|
|
||||||
<option value="44">44 (5.220 GHz)</option>
|
|
||||||
<option value="48">48 (5.240 GHz)</option>
|
|
||||||
<option value="52">52 (5.260 GHz)</option>
|
|
||||||
<option value="56">56 (5.280 GHz)</option>
|
|
||||||
<option value="60">60 (5.300 GHz)</option>
|
|
||||||
<option value="64">64 (5.320 GHz)</option>
|
|
||||||
<option value="100">100 (5.500 GHz)</option>
|
|
||||||
<option value="104">104 (5.520 GHz)</option>
|
|
||||||
<option value="108">108 (5.540 GHz)</option>
|
|
||||||
<option value="112">112 (5.560 GHz)</option>
|
|
||||||
<option value="116">116 (5.580 GHz)</option>
|
|
||||||
<option value="120">120 (5.600 GHz)</option>
|
|
||||||
<option value="124">124 (5.620 GHz)</option>
|
|
||||||
<option value="128">128 (5.640 GHz)</option>
|
|
||||||
<option value="132">132 (5.660 GHz)</option>
|
|
||||||
<option value="136">136 (5.680 GHz)</option>
|
|
||||||
<option value="140">140 (5.700 GHz)</option>
|
|
||||||
<option value="149">149 (5.745 GHz)</option>
|
|
||||||
<option value="153">153 (5.765 GHz)</option>
|
|
||||||
<option value="157">157 (5.785 GHz)</option>
|
|
||||||
<option value="161">161 (5.805 GHz)</option>
|
|
||||||
<option value="165">165 (5.825 GHz)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="wifiRegion" class="form-label">WiFi Region</label>
|
<label for="wifiRegion" class="form-label">WiFi Region</label>
|
||||||
<select id="wifiRegion" class="form-select">
|
<select id="wifiRegion" class="form-select">
|
||||||
<option value="BO">BO (Max TX)</option>
|
|
||||||
<option value="US">US (United States)</option>
|
|
||||||
<option value="EU">EU (Europe)</option>
|
|
||||||
<option value="JP">JP (Japan)</option>
|
|
||||||
<option value="AU">AU (Australia, Max TX)</option>
|
|
||||||
<option value="CA">CA (Canada)</option>
|
|
||||||
<option value="CN">CN (China)</option>
|
|
||||||
<option value="IN">IN (India)</option>
|
|
||||||
<option value="ZA">ZA (South Africa)</option>
|
|
||||||
<option value="KR">KR (South Korea)</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
@ -107,7 +66,7 @@
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<img src="settings_ethernet.svg" class="me-2"> Temperature Configuration
|
<img src="assets/icons/settings_temp.svg" class="me-2"/><span>Temperature Configuration</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
|
@ -125,33 +84,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Drone MAVLink Configuration -->
|
<!-- Drone Video Configuration -->
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<img src="settings_ethernet.svg" class="me-2"> Drone MAVLink Configuration
|
<img src="assets/icons/settings_video.svg" class="me-2"/><span>Drone Video Configuration</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneMavlinkFwmark" class="form-label">FWMark</label>
|
<label for="droneVideoFwmark" class="form-label">FWMark</label>
|
||||||
<input type="number" id="droneMavlinkFwmark" class="form-control" value="10">
|
<input type="number" id="droneVideoFwmark" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneMavlinkType" class="form-label">Connection Type</label>
|
<label for="droneVideoType" class="form-label">Connection Type</label>
|
||||||
<select id="droneMavlinkType" class="form-select">
|
<select id="droneVideoType" class="form-select"></select>
|
||||||
<option value="listen">Listen</option>
|
|
||||||
<option value="connect">Connect</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneMavlinkIP" class="form-label">IP Address</label>
|
<label for="droneVideoIP" class="form-label">IP Address</label>
|
||||||
<input type="text" id="droneMavlinkIP" class="form-control" value="0.0.0.0">
|
<input type="text" id="droneVideoIP" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneMavlinkPort" class="form-label">Port</label>
|
<label for="droneVideoPort" class="form-label">Port</label>
|
||||||
<input type="number" id="droneMavlinkPort" class="form-control" value="14550">
|
<input type="number" id="droneVideoPort" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,33 +115,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Drone Video Configuration -->
|
<!-- Drone MAVLink Configuration -->
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<img src="settings_ethernet.svg" class="me-2"> Drone Video Configuration
|
<img src="assets/icons/lan.svg" class="me-2"/><span>Drone MAVLink Configuration</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneVideoFwmark" class="form-label">FWMark</label>
|
<label for="droneMavlinkFwmark" class="form-label">FWMark</label>
|
||||||
<input type="number" id="droneVideoFwmark" class="form-control" value="20">
|
<input type="number" id="droneMavlinkFwmark" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneVideoType" class="form-label">Connection Type</label>
|
<label for="droneMavlinkType" class="form-label">Connection Type</label>
|
||||||
<select id="droneVideoType" class="form-select">
|
<select id="droneMavlinkType" class="form-select"></select>
|
||||||
<option value="listen">Listen</option>
|
|
||||||
<option value="connect">Connect</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneVideoIP" class="form-label">IP Address</label>
|
<label for="droneMavlinkIP" class="form-label">IP Address</label>
|
||||||
<input type="text" id="droneVideoIP" class="form-control" value="0.0.0.0">
|
<input type="text" id="droneMavlinkIP" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="droneVideoPort" class="form-label">Port</label>
|
<label for="droneMavlinkPort" class="form-label">Port</label>
|
||||||
<input type="number" id="droneVideoPort" class="form-control" value="5602">
|
<input type="number" id="droneMavlinkPort" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -198,21 +151,21 @@
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<img src="settings_ethernet.svg" class="me-2"> MAVLink Settings
|
<img src="assets/icons/settings_ethernet.svg" class="me-2"/><span>MAVLink Settings</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="injectRssi" class="form-label">Inject RSSI</label>
|
<label for="injectRssi" class="form-label">Inject RSSI</label>
|
||||||
<input type="checkbox" id="injectRssi" class="form-check-input" checked>
|
<input type="checkbox" id="injectRssi" class="form-check-input">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="mavlinkSysId" class="form-label">System ID</label>
|
<label for="mavlinkSysId" class="form-label">System ID</label>
|
||||||
<input type="number" id="mavlinkSysId" class="form-control" value="3">
|
<input type="number" id="mavlinkSysId" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="mavlinkCompId" class="form-label">Component ID</label>
|
<label for="mavlinkCompId" class="form-label">Component ID</label>
|
||||||
<input type="number" id="mavlinkCompId" class="form-control" value="68">
|
<input type="number" id="mavlinkCompId" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<label for="mavlinkTcpPort" class="form-label">MAVLink TCP Port</label>
|
<label for="mavlinkTcpPort" class="form-label">MAVLink TCP Port</label>
|
||||||
|
@ -224,19 +177,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Save Button -->
|
|
||||||
<div class="row mt-4 mb-5">
|
|
||||||
<div class="col-6">
|
|
||||||
<button class="btn btn-primary" id="save">Save/Update</button>
|
|
||||||
<span id="result" class="ms-3"></span>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<button id="applyEncryptionFile" class="btn btn-primary">Apply Encryption File from Base Station</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<pre id="output"></pre>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="spirilink.js"></script>
|
<script src="spirilink.js"></script>
|
||||||
|
|
|
@ -23,114 +23,143 @@ const mavlinkSysId = document.getElementById("mavlinkSysId");
|
||||||
const mavlinkCompId = document.getElementById("mavlinkCompId");
|
const mavlinkCompId = document.getElementById("mavlinkCompId");
|
||||||
const mavlinkTcpPort = document.getElementById("mavlinkTcpPort");
|
const mavlinkTcpPort = document.getElementById("mavlinkTcpPort");
|
||||||
|
|
||||||
|
const output = document.getElementById("output");
|
||||||
|
|
||||||
|
const wifiChannels = [
|
||||||
|
// 2.4 GHz Channels
|
||||||
|
["1", "1 (2.412 GHz)"], ["2", "2 (2.417 GHz)"], ["3", "3 (2.422 GHz)"],
|
||||||
|
["4", "4 (2.427 GHz)"], ["5", "5 (2.432 GHz)"], ["6", "6 (2.437 GHz)"],
|
||||||
|
["7", "7 (2.442 GHz)"], ["8", "8 (2.447 GHz)"], ["9", "9 (2.452 GHz)"],
|
||||||
|
["10", "10 (2.457 GHz)"], ["11", "11 (2.462 GHz)"], ["12", "12 (2.467 GHz)"],
|
||||||
|
["13", "13 (2.472 GHz)"], ["14", "14 (2.484 GHz, Japan only)"],
|
||||||
|
// 5 GHz Channels
|
||||||
|
["36", "36 (5.180 GHz)"], ["40", "40 (5.200 GHz)"], ["44", "44 (5.220 GHz)"],
|
||||||
|
["48", "48 (5.240 GHz)"], ["52", "52 (5.260 GHz)"], ["56", "56 (5.280 GHz)"],
|
||||||
|
["60", "60 (5.300 GHz)"], ["64", "64 (5.320 GHz)"], ["100", "100 (5.500 GHz)"],
|
||||||
|
["104", "104 (5.520 GHz)"], ["108", "108 (5.540 GHz)"], ["112", "112 (5.560 GHz)"],
|
||||||
|
["116", "116 (5.580 GHz)"], ["120", "120 (5.600 GHz)"], ["124", "124 (5.620 GHz)"],
|
||||||
|
["128", "128 (5.640 GHz)"], ["132", "132 (5.660 GHz)"], ["136", "136 (5.680 GHz)"],
|
||||||
|
["140", "140 (5.700 GHz)"], ["149", "149 (5.745 GHz)"], ["153", "153 (5.765 GHz)"],
|
||||||
|
["157", "157 (5.785 GHz)"], ["161", "161 (5.805 GHz)"], ["165", "165 (5.825 GHz)"]
|
||||||
|
]
|
||||||
|
|
||||||
|
const wifiRegions = [
|
||||||
|
["BO", "BO (Max TX)"],
|
||||||
|
["US", "US (United States)"],
|
||||||
|
["EU", "EU (Europe)"],
|
||||||
|
["JP", "JP (Japan)"],
|
||||||
|
["AU", "AU (Australia, Max TX)"],
|
||||||
|
["CA", "CA (Canada)"],
|
||||||
|
["CN", "CN (China)"],
|
||||||
|
["IN", "IN (India)"],
|
||||||
|
["ZA", "ZA (South Africa)"],
|
||||||
|
["KR", "KR (South Korea)"]
|
||||||
|
]
|
||||||
|
|
||||||
|
const connectionTypes = [
|
||||||
|
["listen", "Listen"],
|
||||||
|
["connect", "Connect"]
|
||||||
|
]
|
||||||
|
|
||||||
// Load initial settings
|
// Load initial settings
|
||||||
document.onload = InitPage();
|
document.onload = initPage();
|
||||||
// Save file button
|
// Save file button
|
||||||
document.getElementById("save").addEventListener("click", SaveSettings);
|
document.getElementById("save").addEventListener("click", saveSettings);
|
||||||
// Apply encryption file button
|
// Apply encryption file button
|
||||||
document.getElementById("applyEncryptionFile").addEventListener("click", ApplyEncryptionFile);
|
document.getElementById("applyEncryptionFile").addEventListener("click", applyEncryptionFile);
|
||||||
|
|
||||||
// Function to initialize the page
|
// Function to initialize the page
|
||||||
function InitPage() {
|
function initPage() {
|
||||||
cockpit.script(scriptLocation + "cockpitScript.sh -v")
|
|
||||||
file_location.innerHTML = confLocation;
|
file_location.innerHTML = confLocation;
|
||||||
|
|
||||||
|
const inputs = document.querySelectorAll("input, select, textarea");
|
||||||
|
inputs.forEach(input => {
|
||||||
|
input.addEventListener("focus", clearResult);
|
||||||
|
});
|
||||||
|
|
||||||
cockpit.file(confLocation)
|
cockpit.file(confLocation)
|
||||||
.read()
|
.read().then((content) => successReadFile(content))
|
||||||
.then((content) => {
|
.catch(error => failureReadFile(error));
|
||||||
console.log("Configuration file content:", content);
|
|
||||||
SuccessReadFile(content);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error("Failed to read configuration file:", error);
|
|
||||||
FailureReadFile(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load configuration values from the configuration file
|
// Load configuration values from the configuration file
|
||||||
function SuccessReadFile(content) {
|
function successReadFile(content) {
|
||||||
try {
|
try {
|
||||||
// WiFi Configuration
|
// WiFi Configuration
|
||||||
wifiChannel.value = getValueByKey(content, "common", "wifi_channel");
|
|
||||||
console.log("wifi_channel:", wifiChannel.value);
|
|
||||||
|
|
||||||
// Remove surrounding quotes from wifi_region value if present
|
// Remove surrounding quotes from wifi_region value if present
|
||||||
wifiRegion.value = getValueByKey(content, "common", "wifi_region").replace(/^['"]|['"]$/g, "");
|
const currentWifiChannel = getValueByKey(content, "common", "wifi_channel");
|
||||||
console.log("wifi_region:", wifiRegion.value);
|
const currentWifiRegion = getValueByKey(content, "common", "wifi_region").replace(/^['"]|['"]$/g, "");
|
||||||
|
|
||||||
// Handle "None" value for wifi_txpower
|
|
||||||
const txPowerValue = getValueByKey(content, "common", "wifi_txpower");
|
const txPowerValue = getValueByKey(content, "common", "wifi_txpower");
|
||||||
wifiTxPower.value = txPowerValue === "None" ? "" : txPowerValue;
|
|
||||||
console.log("wifi_txpower:", wifiTxPower.value);
|
|
||||||
|
|
||||||
tempInterval.value = getValueByKey(content, "common", "temp_measurement_interval");
|
|
||||||
console.log("temp_measurement_interval:", tempInterval.value);
|
|
||||||
|
|
||||||
tempWarning.value = getValueByKey(content, "common", "temp_overheat_warning");
|
|
||||||
console.log("temp_overheat_warning:", tempWarning.value);
|
|
||||||
|
|
||||||
// Drone MAVLink Configuration
|
addDropDown(wifiChannel, wifiChannels, currentWifiChannel);
|
||||||
droneMavlinkFwmark.value = getValueByKey(content, "drone_mavlink", "fwmark");
|
addDropDown(wifiRegion, wifiRegions, currentWifiRegion);
|
||||||
console.log("drone_mavlink_fwmark:", droneMavlinkFwmark.value);
|
wifiTxPower.value = txPowerValue === "None" ? "" : txPowerValue; // None should result in an empty string
|
||||||
|
|
||||||
const droneMavlinkPeer = getValueByKey(content, "drone_mavlink", "peer");
|
// Temperature Configuration
|
||||||
console.log("drone_mavlink_peer:", droneMavlinkPeer);
|
tempInterval.value = getValueByKey(content, "common", "temp_measurement_interval");
|
||||||
if (droneMavlinkPeer) {
|
tempWarning.value = getValueByKey(content, "common", "temp_overheat_warning");
|
||||||
parsePeer(droneMavlinkPeer, droneMavlinkType, droneMavlinkIP, droneMavlinkPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drone Video Configuration
|
// Drone Video Configuration
|
||||||
droneVideoFwmark.value = getValueByKey(content, "drone_video", "fwmark");
|
droneVideoFwmark.value = getValueByKey(content, "drone_video", "fwmark");
|
||||||
console.log("drone_video_fwmark:", droneVideoFwmark.value);
|
|
||||||
|
|
||||||
const droneVideoPeer = getValueByKey(content, "drone_video", "peer");
|
const droneVideoPeer = getValueByKey(content, "drone_video", "peer");
|
||||||
console.log("drone_video_peer:", droneVideoPeer);
|
|
||||||
if (droneVideoPeer) {
|
if (droneVideoPeer) {
|
||||||
parsePeer(droneVideoPeer, droneVideoType, droneVideoIP, droneVideoPort);
|
const peer = parsePeer(droneVideoPeer);
|
||||||
|
addDropDown(droneVideoType, connectionTypes, droneVideoType.value);
|
||||||
|
droneVideoIP.value = peer.ip;
|
||||||
|
droneVideoPort.value = peer.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAVLink Configuration
|
// Drone MAVLink Configuration
|
||||||
injectRssi.checked = getValueByKey(content, "mavlink", "inject_rssi") === "True";
|
droneMavlinkFwmark.value = getValueByKey(content, "drone_mavlink", "fwmark");
|
||||||
console.log("inject_rssi:", injectRssi.checked);
|
const droneMavlinkPeer = getValueByKey(content, "drone_mavlink", "peer");
|
||||||
|
if (droneMavlinkPeer) {
|
||||||
mavlinkSysId.value = getValueByKey(content, "mavlink", "mavlink_sys_id");
|
const peer = parsePeer(droneMavlinkPeer);
|
||||||
console.log("mavlink_sys_id:", mavlinkSysId.value);
|
addDropDown(droneMavlinkType, connectionTypes, peer.type);
|
||||||
|
droneMavlinkIP.value = peer.ip;
|
||||||
mavlinkCompId.value = getValueByKey(content, "mavlink", "mavlink_comp_id");
|
droneMavlinkPort.value = peer.port;
|
||||||
console.log("mavlink_comp_id:", mavlinkCompId.value);
|
}
|
||||||
|
|
||||||
|
// MAVLink Settings
|
||||||
|
injectRssi.checked = getValueByKey(content, "mavlink", "inject_rssi") === "True";
|
||||||
|
mavlinkSysId.value = getValueByKey(content, "mavlink", "mavlink_sys_id");
|
||||||
|
mavlinkCompId.value = getValueByKey(content, "mavlink", "mavlink_comp_id");
|
||||||
const tcpPortValue = getValueByKey(content, "mavlink", "mavlink_tcp_port");
|
const tcpPortValue = getValueByKey(content, "mavlink", "mavlink_tcp_port");
|
||||||
mavlinkTcpPort.value = tcpPortValue === "None" ? "" : tcpPortValue;
|
mavlinkTcpPort.value = tcpPortValue === "None" ? "" : tcpPortValue;
|
||||||
console.log("mavlink_tcp_port:", mavlinkTcpPort.value);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error parsing configuration file:", e);
|
failureReadFile(e);
|
||||||
FailureReadFile(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function failureReadFile(error) {
|
||||||
|
// Display error message
|
||||||
|
console.log("Error : " + error.message);
|
||||||
|
displayFail(error.message)
|
||||||
|
}
|
||||||
|
|
||||||
// Save configuration values to the configuration file
|
// Save configuration values to the configuration file
|
||||||
function SaveSettings() {
|
function saveSettings() {
|
||||||
try {
|
try {
|
||||||
cockpit.file(confLocation)
|
cockpit.file(confLocation)
|
||||||
.read()
|
.read()
|
||||||
.then((content) => {
|
.then((content) => {
|
||||||
// WiFi Configuration
|
// WiFi & Temperature Configuration
|
||||||
content = setValueByKey(content, "[common]", "wifi_channel", wifiChannel.value);
|
content = setValueByKey(content, "[common]", "wifi_channel", wifiChannel.value);
|
||||||
content = setValueByKey(content, "[common]", "wifi_region", wifiRegion.value);
|
content = setValueByKey(content, "[common]", "wifi_region", wifiRegion.value);
|
||||||
content = setValueByKey(content, "[common]", "wifi_txpower", wifiTxPower.value === "" ? "None" : wifiTxPower.value);
|
content = setValueByKey(content, "[common]", "wifi_txpower", wifiTxPower.value === "" ? "None" : wifiTxPower.value);
|
||||||
content = setValueByKey(content, "[common]", "temp_measurement_interval", tempInterval.value);
|
content = setValueByKey(content, "[common]", "temp_measurement_interval", tempInterval.value);
|
||||||
content = setValueByKey(content, "[common]", "temp_overheat_warning", tempWarning.value);
|
content = setValueByKey(content, "[common]", "temp_overheat_warning", tempWarning.value);
|
||||||
|
|
||||||
|
// Drone Video Configuration
|
||||||
|
const droneVideoPeer = `${droneVideoType.value}://${droneVideoIP.value}:${droneVideoPort.value}`;
|
||||||
|
content = setValueByKey(content, "[drone_video]", "fwmark", droneVideoFwmark.value);
|
||||||
|
content = setValueByKey(content, "[drone_video]", "peer", droneVideoPeer);
|
||||||
|
|
||||||
// Drone MAVLink Configuration
|
// Drone MAVLink Configuration
|
||||||
const droneMavlinkPeer = `${droneMavlinkType.value}://${droneMavlinkIP.value}:${droneMavlinkPort.value}`;
|
const droneMavlinkPeer = `${droneMavlinkType.value}://${droneMavlinkIP.value}:${droneMavlinkPort.value}`;
|
||||||
content = setValueByKey(content, "[drone_mavlink]", "fwmark", droneMavlinkFwmark.value);
|
content = setValueByKey(content, "[drone_mavlink]", "fwmark", droneMavlinkFwmark.value);
|
||||||
content = setValueByKey(content, "[drone_mavlink]", "peer", droneMavlinkPeer);
|
content = setValueByKey(content, "[drone_mavlink]", "peer", droneMavlinkPeer);
|
||||||
|
|
||||||
// Drone Video Configuration
|
|
||||||
const droneVideoPeer = `${droneVideoType.value}://${droneVideoIP.value}:${droneVideoPort.value}`;
|
|
||||||
content = setValueByKey(content, "[drone_video]", "fwmark", droneVideoFwmark.value);
|
|
||||||
content = setValueByKey(content, "[drone_video]", "peer", droneVideoPeer);
|
|
||||||
|
|
||||||
// MAVLink Configuration
|
// MAVLink Configuration
|
||||||
content = setValueByKey(content, "[mavlink]", "inject_rssi", injectRssi.checked ? "True" : "False");
|
content = setValueByKey(content, "[mavlink]", "inject_rssi", injectRssi.checked ? "True" : "False");
|
||||||
content = setValueByKey(content, "[mavlink]", "mavlink_sys_id", mavlinkSysId.value);
|
content = setValueByKey(content, "[mavlink]", "mavlink_sys_id", mavlinkSysId.value);
|
||||||
|
@ -139,27 +168,24 @@ function SaveSettings() {
|
||||||
|
|
||||||
cockpit.file(confLocation, { superuser: "try" }).replace(content)
|
cockpit.file(confLocation, { superuser: "try" }).replace(content)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log("Configuration saved successfully.");
|
restartWifibroadcastService();
|
||||||
RestartWifibroadcastService();
|
displaySuccess("Configuration saved successfully.");
|
||||||
Success();
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Failed to save configuration:", error);
|
displayFail("Failed to save configuration: " + error.message);
|
||||||
Fail(error);
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("Failed to read configuration file:", error);
|
displayFail("Failed to save configuration: " + error.message);
|
||||||
FailureReadFile(error);
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error during save operation:", e);
|
console.error("Error during save operation:", e);
|
||||||
FailureReadFile(e);
|
failureReadFile(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply encryption file from base station
|
// Apply encryption file from base station
|
||||||
function ApplyEncryptionFile() {
|
function applyEncryptionFile() {
|
||||||
const command = `
|
const command = `
|
||||||
/usr/bin/sshpass -p 'spirifriend' scp -o StrictHostKeyChecking=no spiri@spiri-base.local:/home/spiri/drone.key /tmp/drone.key &&
|
/usr/bin/sshpass -p 'spirifriend' scp -o StrictHostKeyChecking=no spiri@spiri-base.local:/home/spiri/drone.key /tmp/drone.key &&
|
||||||
/usr/bin/sudo /bin/mv /tmp/drone.key ${encryptionFileLocation} &&
|
/usr/bin/sudo /bin/mv /tmp/drone.key ${encryptionFileLocation} &&
|
||||||
|
@ -168,56 +194,82 @@ function ApplyEncryptionFile() {
|
||||||
|
|
||||||
cockpit.spawn(["bash", "-c", command], { superuser: "require" })
|
cockpit.spawn(["bash", "-c", command], { superuser: "require" })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log("Encryption key applied and wifibroadcast service restarted.");
|
displaySuccess("Encryption key applied and wifibroadcast service restarted.");
|
||||||
Success();
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Failed to apply encryption key or restart service:", error);
|
console.error("Failed to apply encryption key or restart service:", error);
|
||||||
Fail(error);
|
displayFail("Failed to apply encryption key or restart service: " + error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Restart wifibroadcast service
|
// Restart wifibroadcast service
|
||||||
function RestartWifibroadcastService() {
|
function restartWifibroadcastService() {
|
||||||
cockpit.spawn(["systemctl", "restart", "wifibroadcast@drone"], { superuser: "require" })
|
cockpit.spawn(["systemctl", "restart", "wifibroadcast@drone"], { superuser: "require" })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log("wifibroadcast@drone service restarted.");
|
displaySuccess("wifibroadcast@drone service restarted.");
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Failed to restart wifibroadcast@drone service:", error);
|
console.error("Failed to restart wifibroadcast@drone service:", error);
|
||||||
|
displayFail("Failed to restart wifibroadcast@drone service: " + error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success handler
|
// Display Success result
|
||||||
function Success() {
|
function displaySuccess(msg) {
|
||||||
result.style.color = "green";
|
result.style.color = "green";
|
||||||
result.innerHTML = "Success, settings saved.";
|
if (result.innerHTML === "")
|
||||||
setTimeout(() => result.innerHTML = "", 5000);
|
result.innerHTML = msg;
|
||||||
|
else
|
||||||
|
result.innerHTML += "<br>" + msg;
|
||||||
|
|
||||||
|
// setTimeout(() => result.innerHTML = "", 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failure handler
|
// Display failure message
|
||||||
function Fail(error) {
|
function displayFail(error) {
|
||||||
result.style.color = "red";
|
result.style.color = "red";
|
||||||
result.innerHTML = error.message;
|
result.innerHTML = "Error : " + error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the result message
|
||||||
|
function clearResult() {
|
||||||
|
result.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDropDown(box, pairs, defaultValue) {
|
||||||
|
try {
|
||||||
|
for(let i = 0; i < pairs.length; i++){
|
||||||
|
if (pairs[i].length == 0 || pairs[i][0] === "" || pairs[i][1] === "") continue;
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = pairs[i][0];
|
||||||
|
option.text = pairs[i][1];
|
||||||
|
box.add(option);
|
||||||
|
if (defaultValue === option.value) {
|
||||||
|
console.log("found")
|
||||||
|
box.value = option.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
displayFail(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Peer configuration (type, IP, port)
|
// Parse Peer configuration (type, IP, port)
|
||||||
function parsePeer(peer, typeElement, ipElement, portElement) {
|
function parsePeer(peerString) {
|
||||||
if (!peer) {
|
const peer = { type: "", ip: "", port: "" };
|
||||||
console.warn("Peer value is empty or undefined.");
|
|
||||||
return; // Skip if peer is empty
|
if (!peerString) return peer;
|
||||||
}
|
|
||||||
|
|
||||||
const regex = /(listen|connect):\/\/([\d.]+):(\d+)/;
|
const regex = /(listen|connect):\/\/([\d.]+):(\d+)/;
|
||||||
const match = peer.match(regex);
|
const match = peerString.match(regex);
|
||||||
if (match) {
|
if (match) {
|
||||||
typeElement.value = match[1];
|
peer.type = match[1];
|
||||||
ipElement.value = match[2];
|
peer.ip = match[2];
|
||||||
portElement.value = match[3];
|
peer.port = match[3];
|
||||||
} else {
|
|
||||||
console.error("Failed to parse peer:", peer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get value by key from configuration content
|
// Get value by key from configuration content
|
||||||
|
@ -225,11 +277,9 @@ function getValueByKey(content, section, key) {
|
||||||
const sectionRegex = new RegExp(`\\[${section}\\][\\s\\S]*?^${key}\\s*=\\s*(.*)`, "m");
|
const sectionRegex = new RegExp(`\\[${section}\\][\\s\\S]*?^${key}\\s*=\\s*(.*)`, "m");
|
||||||
const match = content.match(sectionRegex);
|
const match = content.match(sectionRegex);
|
||||||
if (match) {
|
if (match) {
|
||||||
let value = match[1].trim();
|
const value = match[1].trim();
|
||||||
console.log(`Found key [${key}] in section [${section}]:`, value);
|
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Key [${key}] not found in section [${section}]`);
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue