Compare commits
No commits in common. "1.0.0" and "0.8.5" have entirely different histories.
BIN
Display.pdf
Normal file → Executable file
BIN
Display.pdf
Normal file → Executable file
Binary file not shown.
139
README.md
139
README.md
|
@ -1,132 +1,56 @@
|
||||||
RadioSonde Version 1.0.0
|
RadioSonde Version 0.8.5
|
||||||
============================
|
============================
|
||||||
<img src="http://xavier.debert.free.fr/RS/TTGO2.jpg" width="50%">
|
<img src="http://xavier.debert.free.fr/RS/TTGO.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO2.jpg" width="50%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/TTGO4.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO6.jpg" width="50%">
|
<img src="http://xavier.debert.free.fr/RS/TTGO3.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO4.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO5.jpg" width="50%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/TTGO7.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO8.jpg" width="50%">
|
|
||||||
<img src="http://xavier.debert.free.fr/RS/Web4.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web.png" width="20%">
|
<img src="http://xavier.debert.free.fr/RS/Web4.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web.png" width="20%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/Web3.png" width="20%">
|
<img src="http://xavier.debert.free.fr/RS/Web3.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web2.png" width="20%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/Web5.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web6.png" width="20%">
|
<img src="http://xavier.debert.free.fr/RS/Web5.png" width="20%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/Web7.png" width="20%">
|
|
||||||
|
|
||||||
|
|
||||||
Projet basé sur le travail de DL9RDZ
|
Projet basé sur le travail de DL9RDZ
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Pour TTGO LORA 32 esp32 pico D4 <br>
|
Pour TTGO LORA 32 esp32 pico D4
|
||||||
Décodage de RadioSonde RS41/92 and DFM06/09/17 et M10+/20 et MP3H
|
Décodage de RadioSonde RS41 and DFM06/09 et M10
|
||||||
|
|
||||||
Attention à la version de votre TTGO! <br>
|
Attention à la version de votre TTGO!
|
||||||
vous devez modifier dans config.txt, le port de l'écran OLED <br>
|
vous devez modifier dans config.txt, le port de l'écran OLED
|
||||||
- TTGO v1: SDA=4 SCL=15, RST=16 <br>
|
- TTGO v1: SDA=4 SCL=15, RST=16
|
||||||
- TTGO v2: SDA=21 SCL=22, RST=16 <br>
|
- TTGO v2: SDA=21 SCL=22, RST=16
|
||||||
- puis pour le GPS:<br>
|
|
||||||
Lilygo esp32 GPS pin 34 Rx, 12 Tx<br>
|
|
||||||
- puis Buzzer<br>
|
|
||||||
par defaut 4 si gps mettre 2 <br>
|
|
||||||
- puis led<br>
|
|
||||||
par defaut 25 <br>
|
|
||||||
|
|
||||||
## 1ère Mise en route
|
## Version en production 0.8.5 et devel 0.8.7
|
||||||
## Wifi configuration
|
|
||||||
|
|
||||||
Au démarrage, si aucune connexion possible du wifi paramètré, il monte un Wifi AP<br>
|
|
||||||
le SSID et mot de passe par défaut est: Radiosonde<br>
|
|
||||||
en mode AP, il doit être en 192.168.4.1<br>
|
|
||||||
Une fois connécté au Wifi du TTGO<br>
|
|
||||||
ouvrir une page web sur http://192.168.4.1<br>
|
|
||||||
ou aussi la possibilité de mettre http://radiosonde.local<br>
|
|
||||||
|
|
||||||
## Version en production 1.0.0 devel 1.0.1
|
|
||||||
|
|
||||||
## 1.0.0
|
|
||||||
refonte du system OS, et des pages Web<br>
|
|
||||||
toujours avec la gestion:<br>
|
|
||||||
- du buzzer<br>
|
|
||||||
- du db ou smetre<br>
|
|
||||||
- de la vbat nouvelle gestion(plus necessaire calibrage)<br>
|
|
||||||
- suppression du mode telemetry export csv<br>
|
|
||||||
- suppression de la bousole<br>
|
|
||||||
- importation des RadioSonde Thank's DL9RDZ<br>
|
|
||||||
- gestion update OTA<br>
|
|
||||||
|
|
||||||
## 0.9.2
|
|
||||||
Correctif Dash SiteWeb config
|
|
||||||
ADD API SondeHub Thank's DL9RDZ
|
|
||||||
|
|
||||||
## 0.9.1
|
|
||||||
Corection RS41 <br>
|
|
||||||
Correction DFM 06/09 <br>
|
|
||||||
Add DFM17 <br>
|
|
||||||
Correction for all trame recived for M10 and M20 1000ms to 1512ms,<br>
|
|
||||||
Correction formulaire QRG, and end RS no save
|
|
||||||
|
|
||||||
## 0.9.0
|
|
||||||
Add M20
|
|
||||||
|
|
||||||
## 0.8.8
|
|
||||||
|
|
||||||
Add M10+ <br>
|
|
||||||
Add Temps restant avant impacte au sol si 99: 0. 0 soit le balon de la sonde n a pas encore éclaté, <br>
|
|
||||||
ou les informations ne sont pas disponible actuellement <br>
|
|
||||||
Add Test Buzzer au démarrage "Arche Perdu" Lol pour des chasseurs de sonde!<br>
|
|
||||||
Compatible Lilygo esp32 GPS inboard pin 34 Rx, 12 Tx
|
|
||||||
|
|
||||||
## 0.8.7
|
|
||||||
|
|
||||||
correction bug Buzzer Off->On->Off <br>
|
|
||||||
Add GainLNA RX SX1278FSK on Web config paramètre <br>
|
|
||||||
Add update OTA Os + DataWeb <br>
|
|
||||||
correction bugs sondmap.html <br>
|
|
||||||
correction text upgrade Os et DataWeb <br>
|
|
||||||
correction texte boussole S et N <br>
|
|
||||||
correction bugs distance 4928Km si lat et lon =0 erroné <br>
|
|
||||||
correction bugs fonction Vbat <br>
|
|
||||||
Add Telemetry width export data.csv <br>
|
|
||||||
Suppression µSD incompatible avec pin SX1278FSK et SPI <br>
|
|
||||||
Add transfert Telemetry To µSD on put SD automatic
|
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
travail de refonte et réécriture du code
|
||||||
|
## 0.8.1
|
||||||
|
modification de la partie Web
|
||||||
## 0.8.5
|
## 0.8.5
|
||||||
|
Evolution majeur du système
|
||||||
Evolution majeur du système <br>
|
affichage du pourcentage de la batterie en mode scanning
|
||||||
affichage du pourcentage de la batterie en mode scanning <br>
|
création d'une fenetre Batterie, Boussole
|
||||||
création d'une fenetre Batterie, Boussole <br>
|
suppresion lib et code TFT
|
||||||
suppresion lib et code TFT <br>
|
création Azimute, elevation correction de Bugs majeur , mineur
|
||||||
création Azimute, elevation correction de Bugs majeur , mineur <br>
|
Ajout fonction Smetre, Buzzer, QTH, Gps on off ...
|
||||||
Ajout fonction Smetre, Buzzer, QTH, Gps on off ... <br>
|
mise à jour OTA
|
||||||
mise à jour OTA <br>
|
|
||||||
trop de modification pour toutes les expliciter!
|
trop de modification pour toutes les expliciter!
|
||||||
|
|
||||||
## 0.8.1
|
|
||||||
|
|
||||||
modification de la partie Web
|
|
||||||
|
|
||||||
## 0.8.0
|
|
||||||
|
|
||||||
travail de refonte et réécriture du code
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## Les Boutons optionnel à ajouter(souder)
|
## Les Boutons optionnel à ajouter(souder)
|
||||||
sur les GPIO 1002 et 1004 <br>
|
sur les GPIO 1002 et 1004
|
||||||
attention:
|
attention:
|
||||||
|
|
||||||
+3.3V--[ SW ]---GPIO----[ R1 ]---/ R1=10 ou 12KOhms
|
+5V--[ SW ]---GPIO----[ R1 ]---/ R1=10 ou 12KOhms
|
||||||
|
|
||||||
- appuie court <1.5 seconds <br>
|
- appuie court <1.5 seconds
|
||||||
- appuie double court 0.5 seconds <br>
|
- appuie double court 0.5 seconds
|
||||||
- appuie moyen 2-4 seconds <br>
|
- appuie moyen 2-4 seconds
|
||||||
- appuie long >5 seconds
|
- appuie long >5 seconds
|
||||||
|
|
||||||
## Buzzer optionnel à ajouter(souder)
|
|
||||||
sur les GPIO 25 ou 12 suivant le modèl
|
|
||||||
|
|
||||||
GPIO --[ BUZZER ]---/
|
|
||||||
|
|
||||||
## Wifi configuration
|
## Wifi configuration
|
||||||
|
|
||||||
Au démarrage, si aucune connexion possible au wifi paramètré, il monte un Wifi AP<br>
|
Au démarrage, si aucune connexion possible au wifi paramètré, il monte un Wifi AP
|
||||||
le SSID et mot de passe par défaut est: <b>Radiosonde</b> <br>
|
le SSID et mot de passe par défaut est: Radiosonde
|
||||||
en mode AP, il doit être en 192.168.4.1, <br>
|
en mode AP, il doit être en 192.168.4.1,
|
||||||
mais vous avez aussi la possibilité de mettre http://radiosonde.local dans n'importe quel Wifi
|
mais vous avez aussi la possibilité de mettre http://radiosonde.local dans n'importe quel Wifi
|
||||||
connecté.
|
connecté.
|
||||||
|
|
||||||
|
@ -164,3 +88,4 @@ voir Setup.md pour l'installation!
|
||||||
73
|
73
|
||||||
Xavier
|
Xavier
|
||||||
|
|
||||||
|
|
||||||
|
|
3874
RX_FSK/RX_FSK.ino
3874
RX_FSK/RX_FSK.ino
File diff suppressed because it is too large
Load Diff
BIN
RX_FSK/data.tar
BIN
RX_FSK/data.tar
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
+
|
|
|
@ -1,177 +0,0 @@
|
||||||
var cfgs = [
|
|
||||||
[ "", "General configuration", "" ],
|
|
||||||
[ "wifi", "Wifi mode (0=off, 1=client, 2=AP, 3=client or AP autoselect on startup)" ],
|
|
||||||
[ "mdnsname", "Network mDNS name"],
|
|
||||||
[ "ephftp", "FTP server for ephemeris data (RS92 decoder)"],
|
|
||||||
[ "debug", "Debug mode (0/1)" ],
|
|
||||||
[ "maxsonde", "Maximum number of QRG entries (must be ≤ 50)" ],
|
|
||||||
[ "rxlat", "Receiver fixed latitude"],
|
|
||||||
[ "rxlon", "Receiver fixed longitude"],
|
|
||||||
[ "rxalt", "Receiver fixed altitude"],
|
|
||||||
[ "", "OLED display configuration", "" ],
|
|
||||||
[ "screenfile", "Screen config (0=automatic; 1-2=OLED predefined; other=custom)" ],
|
|
||||||
[ "display", "Display screens (scan, default, ...)" ],
|
|
||||||
[ "dispsaver", "Display saver (0=never/1=always/2=ifnorx [+10*n: after n sec.])" ],
|
|
||||||
[ "dispcontrast", "OLED contrast (-1=use default; 0..255=set contrast)" ],
|
|
||||||
[ "norx_timeout", "No-RX-timeout in seconds (-1=disabled)"],
|
|
||||||
[ "", "Spectrum display configuration", "" ],
|
|
||||||
[ "spectrum", "Show spectrum on start (-1=no, 0=forever, >0=time [sec])" ],
|
|
||||||
[ "startfreq", "Start frequency (MHz, default 400)" ],
|
|
||||||
[ "channelbw", "Bandwidth (kHz)" ],
|
|
||||||
[ "marker", "Spectrum MHz marker" ], // maybe remove, assume always ==1?
|
|
||||||
[ "noisefloor", "Spectrum noisefloor" ],
|
|
||||||
[ "", "Receiver configuration", "" ],
|
|
||||||
[ "freqofs", "RX frequency offset (Hz)"],
|
|
||||||
[ "rs41.agcbw", "RS41 AGC bandwidth"],
|
|
||||||
[ "rs41.rxbw", "RS41 RX bandwidth"],
|
|
||||||
[ "rs92.rxbw", "RS92 RX (and AGC) bandwidth"],
|
|
||||||
[ "rs92.alt2d", "RS92 2D fix default altitude"],
|
|
||||||
[ "dfm.agcbw", "DFM AGC bandwidth"],
|
|
||||||
[ "dfm.rxbw", "DFM RX bandwidth"],
|
|
||||||
[ "m10m20.agcbw", "M10/M20 AGC bandwidth"],
|
|
||||||
[ "m10m20.rxbw", "M10/M20 RX bandwidth"],
|
|
||||||
[ "mp3h.agcbw", "MP3H AGC bandwidth"],
|
|
||||||
[ "mp3h.rxbw", "MP3H RX bandwidth"],
|
|
||||||
[ "", "KISS TNC/AXUDP/AXTCP data feed configuration", ""],
|
|
||||||
[ "call", "Call"],
|
|
||||||
[ "passcode", "Passcode"],
|
|
||||||
[ "kisstnc.active", "KISS TNC (port 14590) (needs reboot)"],
|
|
||||||
[ "axudp.active", "AXUDP active"],
|
|
||||||
[ "axudp.host", "AXUDP host"],
|
|
||||||
[ "axudp.port", "AXUDP port"],
|
|
||||||
[ "axudp.highrate", "Rate limit"],
|
|
||||||
[ "tcp.active", "APRS TCP active"],
|
|
||||||
[ "tcp.host", "APRS TCP host"],
|
|
||||||
[ "tcp.port", "APRS TCP port"],
|
|
||||||
[ "tcp.highrate", "Rate limit"],
|
|
||||||
[ "tcp.objcall", "APRS object call"],
|
|
||||||
[ "tcp.beaconsym", "APRS tracker symbol"],
|
|
||||||
[ "tcp.chase", "APRS location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)"],
|
|
||||||
[ "tcp.comment", "APRS location comment"],
|
|
||||||
[ "", "MQTT data feed configuration", ""],
|
|
||||||
[ "mqtt.active", "MQTT active (needs reboot)"],
|
|
||||||
[ "mqtt.id", "MQTT client ID"],
|
|
||||||
[ "mqtt.host", "MQTT server hostname"],
|
|
||||||
[ "mqtt.port", "MQTT port"],
|
|
||||||
[ "mqtt.username", "MQTT username"],
|
|
||||||
[ "mqtt.password", "MQTT password"],
|
|
||||||
[ "mqtt.prefix", "MQTT prefix"],
|
|
||||||
[ "", "Chasemapper settings", ""],
|
|
||||||
[ "cm.active", "Chasemapper active (0=disabled, 1=active)"],
|
|
||||||
[ "cm.host", "Chasemapper UDP host"],
|
|
||||||
[ "cm.port", "Chasemapper UDP port"],
|
|
||||||
[ "", "SondeHub settings", ""],
|
|
||||||
[ "sondehub.active", "SondeHub reporting (0=disabled, 1=active)"],
|
|
||||||
[ "sondehub.chase", "SondeHub location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)"],
|
|
||||||
[ "sondehub.host", "SondeHub host (DO NOT CHANGE)"],
|
|
||||||
[ "sondehub.callsign", "Callsign"],
|
|
||||||
[ "sondehub.antenna", "Antenna (optional, visisble on SondeHub tracker)"],
|
|
||||||
[ "sondehub.email", "SondeHub email (optional, only used to contact in case of upload errors)"],
|
|
||||||
[ "", "SondeHub frequency import", "" ],
|
|
||||||
[ "sondehub.fiactive", "SondeHub frequency import active (0=disabled, 1=active)" ],
|
|
||||||
[ "sondehub.fiinterval", "Import frequency (minutes, ≥ 5)" ],
|
|
||||||
[ "sondehub.fimaxdist", "Import maximum distance (km, ≤ 700)" ],
|
|
||||||
[ "sondehub.fimaxage", "Import maximum age (hours, ≤ 48)" ],
|
|
||||||
[ "", "Hardware configuration (requires reboot)", ""],
|
|
||||||
[ "disptype", "Display type (0=OLED/SSD1306, 2=OLED/SH1106, 5=ST7789)"],
|
|
||||||
[ "oled_sda", "OLED SDA/TFT SDA"],
|
|
||||||
[ "oled_scl", "OLED SCL/TFT CLK"],
|
|
||||||
[ "oled_rst", "OLED RST/TFT RST (needs reboot)"],
|
|
||||||
[ "button_pin", "Button input port"],
|
|
||||||
[ "button2_pin", "Button 2 input port"],
|
|
||||||
[ "button2_axp", "Use AXP192 PWR as Button 2"],
|
|
||||||
[ "touch_thresh", "Touch button threshold<br>(0 for calib mode)"],
|
|
||||||
[ "power_pout", "Power control port"],
|
|
||||||
[ "led_pout", "LED output port (25)"],
|
|
||||||
|
|
||||||
["buzzerOn", "Buzzer (0=Disabled, 1 Enable)"],
|
|
||||||
["buzzerPort", "Buzzer Port (4)"],
|
|
||||||
["buzzerFreq", "Buzzer Frequency (700)"],
|
|
||||||
["dbsmetre", "dB = 0 / Smetre =1)"],
|
|
||||||
["degdec", "Lat,Lon Decimal =0 ou Degres =1)"],
|
|
||||||
|
|
||||||
[ "gps_rxd", "GPS RXD pin (-1 to disable)"],
|
|
||||||
[ "gps_txd", "GPS TXD pin (not really needed)"],
|
|
||||||
[ "batt_adc", "Battery measurement pin"],
|
|
||||||
[ "sx1278_ss", "SX1278 SS"],
|
|
||||||
[ "sx1278_miso", "SX1278 MISO"],
|
|
||||||
[ "sx1278_mosi", "SX1278 MOSI"],
|
|
||||||
[ "sx1278_sck", "SX1278 SCK"],
|
|
||||||
];
|
|
||||||
|
|
||||||
function mkcfg(id, key, label, value) {
|
|
||||||
var s = "<tr style=\"visibility: collapse;\" class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" value=\"" + value + "\"/></td></tr>\n";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
function mkcfgbtn(id, key, label, value) {
|
|
||||||
var touch = "";
|
|
||||||
var v = value;
|
|
||||||
if(v != -1 && (v&128)) {
|
|
||||||
touch = " checked";
|
|
||||||
v = v & 127;
|
|
||||||
}
|
|
||||||
var s = "<tr style=\"visibility:collapse\" class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" size=\"3\" value=\"" + v + "\"/>";
|
|
||||||
s += "<input type=\"checkbox\" name=\"" + key + "#\" "+touch+"> Touch</td></tr>\n";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mksep(id,label,url) {
|
|
||||||
return "<tr class=\"cfgheader\"><th class=\"cfg\" align=\"left\" colspan=\"2\">"+label+" <a href=\""+url+"\" target=\”_blank\">[wiki]</a></th></tr>\n";
|
|
||||||
}
|
|
||||||
function rowdisp(id,disp) {
|
|
||||||
var matches = document.querySelectorAll("tr."+id);
|
|
||||||
matches.forEach(function(e) { if(disp) e.hidden=true; else e.removeAttribute('hidden');});
|
|
||||||
hid=id; nid="N"+id;
|
|
||||||
if(!disp) { hid=nid; nid=id; }
|
|
||||||
document.querySelector("span."+hid).hidden=true;
|
|
||||||
document.querySelector("span."+nid).removeAttribute('hidden');
|
|
||||||
}
|
|
||||||
function configTable() {
|
|
||||||
// iterate over cfgs
|
|
||||||
var tab = "<table width=\"100%\"><tr><th>Option</th><th>Value</th></tr>\n";
|
|
||||||
var id=0;
|
|
||||||
for(i=0; i<cfgs.length; i++) {
|
|
||||||
var key = cfgs[i][0];
|
|
||||||
var lbl = cfgs[i][1];
|
|
||||||
if(key) {
|
|
||||||
if(key=="button_pin" || key=="button2_pin") {
|
|
||||||
tab += mkcfgbtn("s"+id, key, lbl, cf.get(key));
|
|
||||||
} else if (key=="display") {
|
|
||||||
tab += mkcfg("s"+id, key, lbl, cf.get(key));
|
|
||||||
tab += "<tr style=\"visibility:collapse\" class=\"cfgpanel\"><td>"+scr+"</td><td></td></tr>"
|
|
||||||
} else {
|
|
||||||
tab += mkcfg("s"+id, key, lbl, cf.get(key));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
id++;
|
|
||||||
tab += mksep("s"+id, lbl, cfgs[i][2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tab += "</table>";
|
|
||||||
var cfgdiv = document.getElementById("cfgtab");
|
|
||||||
cfgdiv.innerHTML = tab;
|
|
||||||
// enable collapse / expand of items below a header
|
|
||||||
var acc = document.getElementsByClassName("cfgheader");
|
|
||||||
for(i=0; i<acc.length; i++) {
|
|
||||||
acc[i].firstChild.innerHTML = "[+] " + acc[i].firstChild.innerHTML;
|
|
||||||
acc[i].addEventListener("click", function(e) {
|
|
||||||
if(e.target.nodeName=="A") return;
|
|
||||||
achar = "[+]";
|
|
||||||
if(this.classList.toggle("active")) achar = "[\u2212]";
|
|
||||||
this.firstChild.innerHTML = achar + this.firstChild.innerHTML.substring(3);
|
|
||||||
var panel = this;
|
|
||||||
console.log(panel);
|
|
||||||
while( panel = panel.nextElementSibling) {
|
|
||||||
console.log(panel);
|
|
||||||
if ( panel.className!="cfgpanel") { break; }
|
|
||||||
if(panel.style.visibility==="collapse") {
|
|
||||||
panel.style.visibility="visible";
|
|
||||||
} else {
|
|
||||||
console.log("none");
|
|
||||||
panel.style.visibility="collapse";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
acc[0].click();
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>RadioSonde LiveMap</title>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="style_map.css" />
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" />
|
|
||||||
<script>var mapcenter=[%MAPCENTER%];</script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"></script>
|
|
||||||
<script src="https://unpkg.com/leaflet.marker.slideto@0.2.0/Leaflet.Marker.SlideTo.js"></script>
|
|
||||||
<script src="livemap.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="map"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,530 +0,0 @@
|
||||||
try {
|
|
||||||
var check = $(document);
|
|
||||||
} catch (e) {
|
|
||||||
document.addEventListener("DOMContentLoaded", function(event) {
|
|
||||||
document.getElementById('map').innerHTML = '<br /><br />In order to use this functionality, there must be an internet connection.<br /><br/><a href="livemap.html">retry</a><br /><br/><a href="index.html">go back</a>';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
|
||||||
|
|
||||||
var map = L.map('map', { attributionControl: false, zoomControl: false });
|
|
||||||
map.on('mousedown touchstart',function () { follow=false; });
|
|
||||||
|
|
||||||
L.control.scale().addTo(map);
|
|
||||||
L.control.attribution({prefix:false}).addTo(map);
|
|
||||||
|
|
||||||
var osmlight = L.tileLayer('https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png', {
|
|
||||||
maxZoom: 19,
|
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
||||||
});
|
|
||||||
|
|
||||||
var osmdark = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
|
|
||||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
|
||||||
maxZoom: 19
|
|
||||||
});
|
|
||||||
|
|
||||||
var opentopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
|
|
||||||
maxZoom: 17,
|
|
||||||
attribution: 'Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a><br />Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
|
|
||||||
});
|
|
||||||
|
|
||||||
var esri = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
|
||||||
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye,<br />Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
|
|
||||||
maxZoom: 21
|
|
||||||
});
|
|
||||||
|
|
||||||
var basemap;
|
|
||||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
||||||
map.addLayer(osmdark);
|
|
||||||
basemap='osmdark';
|
|
||||||
} else {
|
|
||||||
map.addLayer(osmlight);
|
|
||||||
basemap='osmlight';
|
|
||||||
}
|
|
||||||
|
|
||||||
basemap_change = function () {
|
|
||||||
if (basemap == 'osmlight') {
|
|
||||||
map.removeLayer(osmlight);
|
|
||||||
map.addLayer(opentopo);
|
|
||||||
basemap = 'opentopo';
|
|
||||||
} else if (basemap == 'opentopo') {
|
|
||||||
map.removeLayer(opentopo);
|
|
||||||
map.addLayer(esri);
|
|
||||||
basemap = 'esri';
|
|
||||||
} else if (basemap == 'esri') {
|
|
||||||
map.removeLayer(esri);
|
|
||||||
map.addLayer(osmdark);
|
|
||||||
basemap = 'osmdark';
|
|
||||||
} else {
|
|
||||||
map.removeLayer(osmdark);
|
|
||||||
map.addLayer(osmlight);
|
|
||||||
basemap = 'osmlight';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(mapcenter) map.setView(mapcenter, 5);
|
|
||||||
else map.setView([51.163361,10.447683], 5); // Mitte DE
|
|
||||||
|
|
||||||
var reddot = '<span class="ldot rbg"></span>';
|
|
||||||
var yellowdot = '<span class="ldot ybg"></span>';
|
|
||||||
var greendot = '<span class="ldot gbg"></span>';
|
|
||||||
var lastframe = 0;
|
|
||||||
|
|
||||||
$('#map .leaflet-control-container').append(L.DomUtil.create('div', 'leaflet-top leaflet-center leaflet-header'));
|
|
||||||
var header = '';
|
|
||||||
header += '<div id="sonde_main"><b>rdzTTGOSonde LiveMap</b><br />🎈 <b><span id="sonde_id"></span> - <span id="sonde_freq"></span> MHz - <span id="sonde_type"></span></b></div>';
|
|
||||||
header += '<div id="sonde_detail"><span id="sonde_alt"></span>m | <span id="sonde_climb"></span>m/s | <span id="sonde_speed"></span>km/h | <span id="sonde_dir"></span>°<br /><span id="sonde_time"></span> | -<span id="sonde_rssi"></span>dBm</div>';
|
|
||||||
header += '<div id="sonde_status"><span id="sonde_statbar"></span></div>';
|
|
||||||
header += '<div id="settings"><br /><b>Prediction-Settings</b><br />';
|
|
||||||
|
|
||||||
header += '<label for="burst">Burst at:</label><input type="text" id="burst" maxlength="5" value="..." /> m<br />';
|
|
||||||
header += '<label for="overwrite_descend">Descending:</label><input type="text" id="overwrite_descend" maxlength="2" value="..." /> m/s<br />';
|
|
||||||
header += '<label for="overwrite_descend_till">Use this descending until:</label><input type="text" id="overwrite_descend_till" maxlength="5" value="..." /> m<br />';
|
|
||||||
header += '<small>after the transmitted descend will be used</small>';
|
|
||||||
header += '<div id="submit"><input type="button" value="save" onclick="settings_save();"/> <input type="button" id="submit" value="reset" onclick="settings_reset();"/></div>';
|
|
||||||
header += '</div>';
|
|
||||||
$('.leaflet-header').append(header);
|
|
||||||
|
|
||||||
|
|
||||||
$('#map .leaflet-control-container').append(L.DomUtil.create('div', 'leaflet-bottom leaflet-center leaflet-footer'));
|
|
||||||
var footer = '';
|
|
||||||
footer += '<div id="gps_main"><b>Direction: </b><span class="gps_dir">...</span>°<br /><b>Distance: </b><span class="gps_dist">...</span>m</div>';
|
|
||||||
$('.leaflet-footer').append(footer);
|
|
||||||
|
|
||||||
var statbar = '';
|
|
||||||
headtxt = function(data,stat) {
|
|
||||||
var staticon = (stat == '1')?greendot:yellowdot;
|
|
||||||
statbar = staticon + statbar;
|
|
||||||
if ((statbar.length) > 10*greendot.length) { statbar = statbar.substring(0,10*greendot.length); }
|
|
||||||
if (data.id && data.vframe != lastframe ) {
|
|
||||||
lastframe = data.vframe;
|
|
||||||
$('#sonde_id').html(data.id);
|
|
||||||
$('#sonde_alt').html(data.alt);
|
|
||||||
$('#sonde_climb').html(data.climb);
|
|
||||||
$('#sonde_speed').html( mr(data.speed * 3.6 * 10) / 10 );
|
|
||||||
$('#sonde_dir').html(data.dir);
|
|
||||||
$('#sonde_time').html(new Date(data.time * 1000).toISOString());
|
|
||||||
$('#sonde_rssi').html(data.rssi / 2 );
|
|
||||||
$('#sonde_detail').show();
|
|
||||||
} else {
|
|
||||||
if (!data.id) {
|
|
||||||
$('#sonde_id').html(data.launchsite.trim());
|
|
||||||
// $('#sonde_detail').hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$('#sonde_freq').html(data.freq);
|
|
||||||
$('#sonde_type').html(data.type);
|
|
||||||
$('#sonde_statbar').html(' '+statbar);
|
|
||||||
};
|
|
||||||
|
|
||||||
map.addControl(new L.Control.Button([ { position: 'topleft', text: '🔙', href: 'index.html' } ]));
|
|
||||||
|
|
||||||
L.control.zoom({ position:'topleft' }).addTo(map);
|
|
||||||
|
|
||||||
map.addControl(new L.Control.Button([ { position: 'topleft', text: '🗺️', href: 'javascript:basemap_change();' } ]));
|
|
||||||
|
|
||||||
map.addControl(new L.Control.Button([ { position: 'topright', id: "status", text: '', href: 'javascript:get_data();' } ]));
|
|
||||||
|
|
||||||
map.addControl(new L.Control.Button([
|
|
||||||
{ position:'topright', text: '🎈', href: 'javascript:show(marker[last_id],\'marker\');' },
|
|
||||||
{ text: '〰️', href: 'javascript:show_line();' },
|
|
||||||
{ text: '💥', href: 'javascript:show(marker_burst[last_id],\'burst\');' },
|
|
||||||
{ text: '🎯', href: 'javascript:show(marker_landing[last_id],\'landing\');' }
|
|
||||||
]));
|
|
||||||
|
|
||||||
map.addControl(new L.Control.Button([ { position:'topright', text: '⚙️', href: 'javascript:show_settings();' } ]));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
show = function(e,p) {
|
|
||||||
if (p == 'landing') { get_predict(last_data); }
|
|
||||||
if (e) {
|
|
||||||
map.closePopup();
|
|
||||||
map.setView(map._layers[e._leaflet_id].getLatLng());
|
|
||||||
map._layers[e._leaflet_id].openPopup();
|
|
||||||
follow = p;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
getTwoBounds = function (a,b) {
|
|
||||||
var sW = new L.LatLng((a._southWest.lat > b._southWest.lat)?b._southWest.lat:a._southWest.lat, (a._southWest.lng > b._southWest.lng)?b._southWest.lng:a._southWest.lng);
|
|
||||||
var nE = new L.LatLng((a._northEast.lat < b._northEast.lat)?b._northEast.lat:a._northEast.lat, (a._northEast.lng < b._northEast.lng)?b._northEast.lng:a._northEast.lng);
|
|
||||||
|
|
||||||
return new L.LatLngBounds(sW, nE);
|
|
||||||
};
|
|
||||||
|
|
||||||
show_line = function() {
|
|
||||||
$('.i_position, .i_landing').remove();
|
|
||||||
map.closePopup();
|
|
||||||
if (line[last_id]._latlngs.length != 0 && line_predict[last_id]._latlngs.length != 0) {
|
|
||||||
map.fitBounds(getTwoBounds(line[last_id].getBounds(),line_predict[last_id].getBounds()));
|
|
||||||
} else if (line[last_id]._latlngs.length != 0) {
|
|
||||||
map.fitBounds(line[last_id].getBounds());
|
|
||||||
} else if (line_predict[last_id]._latlngs.length != 0) {
|
|
||||||
map.fitBounds(line_predict[last_id].getBounds());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
last_data = false;
|
|
||||||
last_id = false;
|
|
||||||
follow = 'marker';
|
|
||||||
|
|
||||||
marker_landing = [];
|
|
||||||
icon_landing = L.divIcon({className: 'leaflet-landing'});
|
|
||||||
dots_predict = [];
|
|
||||||
line_predict = [];
|
|
||||||
marker_burst = [];
|
|
||||||
icon_burst = L.divIcon({className: 'leaflet-burst'});
|
|
||||||
|
|
||||||
marker = [];
|
|
||||||
dots = [];
|
|
||||||
line = [];
|
|
||||||
|
|
||||||
draw = function(data) {
|
|
||||||
var stat;
|
|
||||||
if (data.id) {
|
|
||||||
last_id = data.id;
|
|
||||||
// data.res: 0: ok 1: no rx (timeout), 2: crc err, >2 some other error
|
|
||||||
if ((data.lat && data.lon && data.alt) && (lastframe != 0)) {
|
|
||||||
var location = [data.lat,data.lon,data.alt];
|
|
||||||
if (!marker[data.id]) {
|
|
||||||
map.setView(location, 14);
|
|
||||||
marker[data.id] = L.marker(location).addTo(map)
|
|
||||||
.bindPopup(poptxt('position',data),{closeOnClick:false, autoPan:false}).openPopup();
|
|
||||||
get_predict(data);
|
|
||||||
} else {
|
|
||||||
marker[data.id].slideTo(location, {
|
|
||||||
duration: 500,
|
|
||||||
keepAtCenter: (follow=='marker')?true:false
|
|
||||||
})
|
|
||||||
.setPopupContent(poptxt('position',data));
|
|
||||||
}
|
|
||||||
if (!dots[data.id]) { dots[data.id] = []; }
|
|
||||||
dots[data.id].push(location);
|
|
||||||
if (!line[data.id]) {
|
|
||||||
line[data.id] = L.polyline(dots[data.id]).addTo(map);
|
|
||||||
} else {
|
|
||||||
line[data.id].setLatLngs(dots[data.id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (data.res == 0) {
|
|
||||||
storage_write(data);
|
|
||||||
$('#status').html(greendot);
|
|
||||||
stat = 1;
|
|
||||||
} else {
|
|
||||||
$('#status').html(yellowdot);
|
|
||||||
stat = 0;
|
|
||||||
}
|
|
||||||
headtxt(data,stat);
|
|
||||||
last_data = data;
|
|
||||||
} else {
|
|
||||||
$('#status').html(yellowdot);
|
|
||||||
headtxt(data,0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
marker_gps = false;
|
|
||||||
icon_gps = L.divIcon({className: 'leaflet-gps'});
|
|
||||||
circ_gps = false;
|
|
||||||
|
|
||||||
gps = function(e) {
|
|
||||||
gps_location = [e.lat,e.lon];
|
|
||||||
gps_accuracy = e.hdop*2;
|
|
||||||
|
|
||||||
if (last_data && last_data.lat != '0.000000') {
|
|
||||||
if ($('.leaflet-footer').css('display') == 'none') { $('.leaflet-footer').show(); }
|
|
||||||
|
|
||||||
var distance = Math.round(map.distance(gps_location,[last_data.lat, last_data.lon]));
|
|
||||||
distance = (distance > 1000)?(distance / 1000) + 'k':distance;
|
|
||||||
$('.leaflet-footer .gps_dist').html(distance);
|
|
||||||
|
|
||||||
$('.leaflet-footer .gps_dir').html( bearing(gps_location,[last_data.lat, last_data.lon]) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!marker_gps) {
|
|
||||||
map.addControl(new L.Control.Button([{ position: 'topleft', text: '🛰️', href: 'javascript:show(marker_gps,\'gps\');' }]));
|
|
||||||
|
|
||||||
marker_gps = L.marker(gps_location,{icon:icon_gps}).addTo(map)
|
|
||||||
.bindPopup(poptxt('gps',e),{closeOnClick:false, autoPan:false});
|
|
||||||
circ_gps = L.circle(gps_location, gps_accuracy).addTo(map);
|
|
||||||
} else {
|
|
||||||
marker_gps.slideTo(gps_location, {
|
|
||||||
duration: 500,
|
|
||||||
keepAtCenter: (follow=='gps')?true:false
|
|
||||||
})
|
|
||||||
.setPopupContent(poptxt('gps',e));
|
|
||||||
circ_gps.slideTo(gps_location, { duration: 500 });
|
|
||||||
circ_gps.setRadius(gps_accuracy);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
get_data = function() {
|
|
||||||
$('#status').html(reddot);
|
|
||||||
$.ajax({url: 'live.json', success: (function( data ) {
|
|
||||||
if (typeof data != "object") { data = $.parseJSON(data); }
|
|
||||||
if (data.sonde) {
|
|
||||||
draw(data.sonde);
|
|
||||||
} else {
|
|
||||||
setTimeout(function() {$('#status').html(yellowdot);},100);
|
|
||||||
}
|
|
||||||
if (data.gps) {
|
|
||||||
gps(data.gps);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
timeout: 1000}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
storage = (typeof(Storage) !== "undefined")?true:false;
|
|
||||||
|
|
||||||
settings_std = {
|
|
||||||
burst: 32500,
|
|
||||||
overwrite_descend: 6,
|
|
||||||
overwrite_descend_till: 12000
|
|
||||||
};
|
|
||||||
|
|
||||||
settings_read = function() {
|
|
||||||
if (storage) {
|
|
||||||
if (sessionStorage.settings) {
|
|
||||||
return JSON.parse(sessionStorage.settings);
|
|
||||||
} else {
|
|
||||||
settings_write(settings_std);
|
|
||||||
return settings_std;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return settings_std;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
settings_write = function (data) {
|
|
||||||
if (storage) {
|
|
||||||
sessionStorage.settings = JSON.stringify(data);
|
|
||||||
settings = data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = settings_read();
|
|
||||||
|
|
||||||
settings_save = function() {
|
|
||||||
settings.burst = parseInt($('#settings #burst').val());
|
|
||||||
settings.overwrite_descend = parseInt($('#settings #overwrite_descend').val());
|
|
||||||
settings.overwrite_descend_till = parseInt($('#settings #overwrite_descend_till').val());
|
|
||||||
if (Number.isInteger(settings.burst) && Number.isInteger(settings.overwrite_descend) && Number.isInteger(settings.overwrite_descend_till)) {
|
|
||||||
settings_write(settings);
|
|
||||||
$("#settings").slideUp();
|
|
||||||
get_predict(last_data);
|
|
||||||
} else {
|
|
||||||
alert('Error: only numeric values allowed!');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
settings_reset = function() {
|
|
||||||
if (confirm('Reset to default?')) {
|
|
||||||
settings_write(settings_std);
|
|
||||||
show_settings();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_settings = function() {
|
|
||||||
$('#settings #burst').val(settings.burst);
|
|
||||||
$('#settings #overwrite_descend').val(settings.overwrite_descend);
|
|
||||||
$('#settings #overwrite_descend_till').val(settings.overwrite_descend_till);
|
|
||||||
$("#settings").slideToggle();
|
|
||||||
};
|
|
||||||
|
|
||||||
predictor = false;
|
|
||||||
get_predict = function(data) {
|
|
||||||
if (!data) { return; }
|
|
||||||
var ascent = (data.climb > 0)? data.climb : 15;
|
|
||||||
var descent = (data.climb > 0)? settings.overwrite_descend : data.climb * -1;
|
|
||||||
|
|
||||||
var burst;
|
|
||||||
if (data.climb > 0) {
|
|
||||||
burst = (data.alt > settings.burst )?data.alt + 100 : settings.burst;
|
|
||||||
} else {
|
|
||||||
burst = parseInt(data.alt) + 7;
|
|
||||||
if (data.alt > settings.overwrite_descend_till ) { descent = settings.overwrite_descend; }
|
|
||||||
}
|
|
||||||
|
|
||||||
var m = new Date();
|
|
||||||
var datetime = m.getUTCFullYear() + "-" + az(m.getUTCMonth()+1) + "-" + az(m.getUTCDate()) + "T" +
|
|
||||||
az(m.getUTCHours()) + ":" + az(m.getUTCMinutes()) + ":" + az(m.getUTCSeconds()) + "Z";
|
|
||||||
var url = 'https://api.v2.sondehub.org/tawhiri';
|
|
||||||
url += '?launch_latitude='+data.lat + '&launch_longitude='+tawhiri_lon(data.lon);
|
|
||||||
url += '&launch_altitude='+data.alt + '&launch_datetime='+datetime;
|
|
||||||
url += '&ascent_rate='+ascent + '&burst_altitude=' + burst + '&descent_rate='+descent;
|
|
||||||
|
|
||||||
$.getJSON(url, function( prediction ) {
|
|
||||||
draw_predict(prediction,data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
draw_predict = function(prediction,data) {
|
|
||||||
var ascending = prediction.prediction[0].trajectory;
|
|
||||||
var highest = ascending[ascending.length-1];
|
|
||||||
var highest_location = [highest.latitude,sanitize_lon(highest.longitude)];
|
|
||||||
|
|
||||||
var descending = prediction.prediction[1].trajectory;
|
|
||||||
var landing = descending[descending.length-1];
|
|
||||||
var landing_location = [landing.latitude,sanitize_lon(landing.longitude)];
|
|
||||||
|
|
||||||
if (!marker_landing[data.id]) {
|
|
||||||
marker_landing[data.id] = L.marker(landing_location,{icon: icon_landing}).addTo(map)
|
|
||||||
.bindPopup(poptxt('landing',landing),{closeOnClick:false, autoPan:false});
|
|
||||||
} else {
|
|
||||||
marker_landing[data.id].slideTo(landing_location, {
|
|
||||||
duration: 500,
|
|
||||||
keepAtCenter: (follow=='landing')?true:false
|
|
||||||
})
|
|
||||||
.setPopupContent(poptxt('landing',landing));
|
|
||||||
}
|
|
||||||
|
|
||||||
dots_predict[data.id]=[];
|
|
||||||
|
|
||||||
if (data.climb > 0) {
|
|
||||||
ascending.forEach(p => dots_predict[data.id].push([p.latitude,sanitize_lon(p.longitude)]));
|
|
||||||
|
|
||||||
if (!marker_burst[data.id]) {
|
|
||||||
marker_burst[data.id] = L.marker(highest_location,{icon:icon_burst}).addTo(map).bindPopup(poptxt('burst',highest),{closeOnClick:false, autoPan:false});
|
|
||||||
} else {
|
|
||||||
marker_burst[data.id].slideTo(highest_location, {
|
|
||||||
duration: 500,
|
|
||||||
keepAtCenter: (follow=='burst')?true:false
|
|
||||||
}).setPopupContent(poptxt('burst',highest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
descending.forEach(p => dots_predict[data.id].push([p.latitude,sanitize_lon(p.longitude)]));
|
|
||||||
|
|
||||||
if (!line_predict[data.id]) {
|
|
||||||
line_predict[data.id] = L.polyline(dots_predict[data.id],{color: 'yellow'}).addTo(map);
|
|
||||||
} else {
|
|
||||||
line_predict[data.id].setLatLngs(dots_predict[data.id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.climb > 0) {
|
|
||||||
predictor_time = 5 * 60; // ascending, every 5 min
|
|
||||||
} else if (data.climb < 0 && data.alt > 5000) {
|
|
||||||
predictor_time = 2 * 60; // descending, above 5km, every 2 min
|
|
||||||
} else {
|
|
||||||
predictor_time = 30; // descending, below 5km, every 30 sec
|
|
||||||
}
|
|
||||||
clearTimeout(predictor);
|
|
||||||
predictor = setTimeout(function() {get_predict(last_data);}, predictor_time*1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
sanitize_lon = function(lon) {
|
|
||||||
if (lon > 180) { return lon - 360; }
|
|
||||||
return lon;
|
|
||||||
}
|
|
||||||
tawhiri_lon = function(lon) {
|
|
||||||
if (lon < 0) { return lon + 360; }
|
|
||||||
return lon;
|
|
||||||
}
|
|
||||||
|
|
||||||
poptxt = function(t,i) {
|
|
||||||
var lat_input = (i.id)?i.lat:i.latitude;
|
|
||||||
var lon_input = sanitize_lon((i.id)?i.lon:i.longitude);
|
|
||||||
|
|
||||||
var lat = Math.round(lat_input * 1000000) / 1000000;
|
|
||||||
var lon = Math.round(lon_input * 1000000) / 1000000;
|
|
||||||
|
|
||||||
var add =
|
|
||||||
'<br /><b>Position:</b> '+lat+', '+lon+'<br />'+
|
|
||||||
'<b>Open:</b> <a href="https://www.google.de/maps/?q='+lat+', '+lon+'" target="_blank">GMaps</a> | <a href="https://www.openstreetmap.org/?mlat='+lat+'&mlon='+lon+'&zoom=15" target="_blank">OSM</a> | <a href="geo://'+lat+','+lon+'">GeoApp</a>';
|
|
||||||
|
|
||||||
if (t == 'position') { return '<div class="i_position"><b>🎈 '+i.id+'</b>'+add+'</div>'; }
|
|
||||||
if (t == 'burst') { return '<div class="i_burst"><b>💥 Predicted Burst:</b><br />'+fd(i.datetime)+' in '+mr(i.altitude)+'m'+add+'</div>'; }
|
|
||||||
if (t == 'highest') { return '<div class="i_burst"><b>💥 Burst:</b> '+mr(i.altitude)+'m'+add+'</div>';}
|
|
||||||
if (t == 'landing') { return '<div class="i_landing"><b>🎯 Predicted Landing:</b><br />'+fd(i.datetime)+' at '+mr(i.altitude)+'m'+add+'</div>'; }
|
|
||||||
if (t == 'gps') { return '<div class="i_gps">Position: '+(i.lat)+','+(i.lon)+'<br />Altitude: '+i.alt+'m<br />Speed: '+mr(i.speed * 3.6 * 10)/10+'km/h '+i.dir+'°<br />Sat: '+i.sat+' Hdop:'+(i.hdop/10)+'</div>'; }
|
|
||||||
};
|
|
||||||
|
|
||||||
fd = function(date) {
|
|
||||||
var d = new Date(Date.parse(date));
|
|
||||||
return az(d.getUTCHours()) +':'+ az(d.getUTCMinutes())+' UTC';
|
|
||||||
};
|
|
||||||
az = function(n) { return (n<10)?'0'+n:n; };
|
|
||||||
mr = function(n) { return Math.round(n); };
|
|
||||||
|
|
||||||
storage = (typeof(Storage) !== "undefined")?true:false;
|
|
||||||
storage_write = function (data) {
|
|
||||||
if (storage) {
|
|
||||||
if (sessionStorage.sonde) {
|
|
||||||
storage_data = JSON.parse(sessionStorage.sonde);
|
|
||||||
} else {
|
|
||||||
storage_data = [];
|
|
||||||
}
|
|
||||||
if (JSON.stringify(data) != JSON.stringify(storage_data[storage_data.length - 1])) {
|
|
||||||
storage_data.push(data);
|
|
||||||
sessionStorage.sonde = JSON.stringify(storage_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
storage_read = function() {
|
|
||||||
if (storage) {
|
|
||||||
if (sessionStorage.sonde) {
|
|
||||||
storage_data = JSON.parse(sessionStorage.sonde);
|
|
||||||
return storage_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
storage_remove = function() {
|
|
||||||
sessionStorage.removeItem('sonde');
|
|
||||||
};
|
|
||||||
|
|
||||||
session_storage = storage_read();
|
|
||||||
if (session_storage) {
|
|
||||||
session_storage.forEach(function(d) {
|
|
||||||
dots.push([d.lat,d.lon,d.alt]);
|
|
||||||
session_storage_last = d;
|
|
||||||
});
|
|
||||||
draw(session_storage_last);
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(get_data,1000);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
L.Control.Button = L.Control.extend({
|
|
||||||
onAdd: function (map) {
|
|
||||||
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
|
||||||
options = this.options;
|
|
||||||
Object.keys(options).forEach(function(key) {
|
|
||||||
this.link = L.DomUtil.create('a', '', container);
|
|
||||||
this.link.text = options[key].text;
|
|
||||||
this.link.href = options[key].href;
|
|
||||||
this.link.id = options[key].id;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.options.position = this.options[0].position;
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/makinacorpus/Leaflet.GeometryUtil/blob/master/src/leaflet.geometryutil.js#L682
|
|
||||||
// modified to fit
|
|
||||||
function bearing(latlng1, latlng2) {
|
|
||||||
var rad = Math.PI / 180,
|
|
||||||
lat1 = latlng1[0] * rad,
|
|
||||||
lat2 = latlng2[0] * rad,
|
|
||||||
lon1 = latlng1[1] * rad,
|
|
||||||
lon2 = latlng2[1] * rad,
|
|
||||||
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
|
|
||||||
x = Math.cos(lat1) * Math.sin(lat2) -
|
|
||||||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
|
|
||||||
var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
|
|
||||||
bearing = bearing < 0 ? bearing-360 : bearing;
|
|
||||||
return Math.round(bearing);
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script>
|
|
||||||
maptype = "SH"; // TODO: Get from config
|
|
||||||
|
|
||||||
const maps = {
|
|
||||||
"WS": ["https://www.wettersonde.net/map.php", (s)=>"?sonde="+s, (lat,lon)=>""],
|
|
||||||
"SH": ["https://sondehub.org/#!mt=Mapnik", (lat,lon)=>'&mz=7&qm=12h&mc=' + lat + ',' + lon],
|
|
||||||
"RS": ["https://radiosondy.info/", (s)=>"sonde.php?sondenumber="+s, (lat,lon)=>""],
|
|
||||||
"OW": ["https://v2.openwx.de/start.php", (s)=>"?sonde="+s, (lat,lon)=>"?mode=mobile"],
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const data = {"gps_lat":45.62172,"gps_lon":7.02026};
|
|
||||||
|
|
||||||
urlarg = + maps[maptype][1] + data['gps_lat']+","+data['gps_lon'];
|
|
||||||
|
|
||||||
iftxt='<iframe src="' + maps[maptype][0] + urlarg +'" style="border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%"></iframe>';
|
|
||||||
document.write(iftxt);
|
|
||||||
document.getElementsByTagName('body')[0].innerHTML = iftxt;
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,6 +0,0 @@
|
||||||
Radiosonde
|
|
||||||
Radiosonde
|
|
||||||
SSIDMobile
|
|
||||||
123456
|
|
||||||
SSIDBox
|
|
||||||
123456
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Frequency in Mhz (format nnn.nnn)
|
|
||||||
# Type (4=RS41, R=RS92, D=DFM (automated normal/inverted), M=M10/M20, 3=MP3H)
|
|
||||||
# (older versions: 6=DFM6, 9=DFM9, now both treated the same as D)
|
|
||||||
# (older versions: M=M10, 2=M20, now both treaded the same: automated M10/M20 decoding)
|
|
||||||
# +: active, -: not active
|
|
||||||
#
|
|
||||||
400.000 9 + Test(FR)
|
|
||||||
402.000 2 + Nimes(FR)
|
|
||||||
402.800 4 + Cuneo(IT)
|
|
||||||
403.000 6 - Ajactio(FR)
|
|
||||||
403.200 M - OHP(FR)
|
|
||||||
403.010 6 - Canjuers(FR)
|
|
||||||
404.200 4 - Rome(IT)
|
|
||||||
404.789 9 - Frejus1(FR)
|
|
||||||
404.800 4 - Milan(IT)
|
|
||||||
405.000 R - Frejus2(FR)
|
|
||||||
405.789 9 - Pegomas(FR)
|
|
||||||
403.700 4 - Cuneo2(IT)
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
400.000 D -
|
|
||||||
# end
|
|
|
@ -1,54 +0,0 @@
|
||||||
let stypes=new Map();
|
|
||||||
stypes.set('4', 'RS41');
|
|
||||||
stypes.set('R', 'RS92');
|
|
||||||
stypes.set('D', 'DFM');
|
|
||||||
stypes.set('M', 'M10/M20');
|
|
||||||
stypes.set('3', 'MP3H');
|
|
||||||
|
|
||||||
function footer() {
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
|
||||||
var form = document.querySelector(".wrapper");
|
|
||||||
form.addEventListener("input", function() {
|
|
||||||
document.querySelector(".save").disabled = false;
|
|
||||||
});
|
|
||||||
document.querySelector(".save").disabled = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used by qrg.html in RX_FSK.ino */
|
|
||||||
function prep() {
|
|
||||||
var stlist=document.querySelectorAll("input.stype");
|
|
||||||
for(txt of stlist){
|
|
||||||
var val=txt.getAttribute('value'); var nam=txt.getAttribute('name');
|
|
||||||
if(val=='2') { val='M'; }
|
|
||||||
var sel=document.createElement('select');
|
|
||||||
sel.setAttribute('name',nam);
|
|
||||||
for(stype of stypes) {
|
|
||||||
var opt=document.createElement('option');
|
|
||||||
opt.value=stype[0];
|
|
||||||
opt.innerHTML=stype[1];
|
|
||||||
if(stype[0]==val) { opt.setAttribute('selected','selected'); }
|
|
||||||
sel.appendChild(opt);
|
|
||||||
}
|
|
||||||
txt.replaceWith(sel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function qrgTable() {
|
|
||||||
var tab=document.getElementById("divTable");
|
|
||||||
|
|
||||||
var table = "<table><tr><th>Ch</th><th>Active</th><th>Frequency</th><th>Decoder</th><th>Launchsite</th></tr>";
|
|
||||||
for(i=0; i<qrgs.length; i++) {
|
|
||||||
var ck = "";
|
|
||||||
if(qrgs[i][0]) ck="checked";
|
|
||||||
table += "<tr><td class=\"ch\">" + (i+1) + "</td><td class=\"act\"><input name=\"A" + (i+1) + "\" type=\"checkbox\" " + ck + "/></td>";
|
|
||||||
table += "<td><input name=\"F" + (i+1) + "\" type=\"text\" size=7 value=\"" + qrgs[i][1] + "\"></td>";
|
|
||||||
table += "<td><input class=\"stype\" name=\"T" + (i+1) + "\" value=\"" + qrgs[i][3] + "\"></td>";
|
|
||||||
table += "<td><input name=\"S" + (i+1) + "\" type=\"text\" value=\"" + qrgs[i][2] +"\"></td></tr>";
|
|
||||||
}
|
|
||||||
table += "</table>";
|
|
||||||
tab.innerHTML = table;
|
|
||||||
prep();
|
|
||||||
footer();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,460 +0,0 @@
|
||||||
# Definition of display content and action behaviour
|
|
||||||
#
|
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
|
||||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
|
||||||
# - view timer: time since current view (display mode and sonde) was started
|
|
||||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
|
||||||
# - norx timer: time since when no sonde data has been received continuously
|
|
||||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
|
||||||
# anything for a 1s period)
|
|
||||||
#
|
|
||||||
# Actions:
|
|
||||||
# - W: activate WiFi scan
|
|
||||||
# - F: activate frequency spectrum display
|
|
||||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
|
||||||
# - x: (1..N): activate display mode x [deprecated]
|
|
||||||
# - >: activate next display mode
|
|
||||||
# - D: activate default receiver display (display mode specified in config)
|
|
||||||
# - +: advance to next active sonde from QRG config
|
|
||||||
# - #: no action
|
|
||||||
#
|
|
||||||
# Display content (lower/upper case: small/large font)
|
|
||||||
# line,column=content
|
|
||||||
# for ILI9225 its also possible to indicate
|
|
||||||
# line,column,width=content for text within a box of width 'width'
|
|
||||||
# line,column,-width=content for right-justified text
|
|
||||||
#
|
|
||||||
# XText : Text
|
|
||||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
|
||||||
# L latitade
|
|
||||||
# O lOngitute
|
|
||||||
# A altitude
|
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
|
||||||
# C afC value
|
|
||||||
# N ip address (only tiny font)
|
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
|
||||||
# Mx telemetry value x (t temp p preassure h hyg) [not yet implemented, maybe some day in future]
|
|
||||||
# Gx GPS-related data
|
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
|
||||||
# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
# "N" (what is on top: N=north C=course)
|
|
||||||
# "C" (where does the arrow point to: C=course, S=sonde)
|
|
||||||
# "S" (what is shown by the bullet: C=course, S=sonde)
|
|
||||||
# 50: circle radius, followed by fg and bg color
|
|
||||||
# 5: bullet radius, followed by fg color
|
|
||||||
# 4: arrow width, followed by fg color
|
|
||||||
# R RSSI
|
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
|
||||||
# U=USB volt I=USB current T=IC temp
|
|
||||||
#
|
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
|
||||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
|
||||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
|
||||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
|
||||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
|
||||||
# u8x8_font_5x7_f, // 3
|
|
||||||
# u8x8_font_5x8_f, // 4
|
|
||||||
# u8x8_font_8x13_1x2_f, // 5
|
|
||||||
# u8x8_font_8x13B_1x2_f, // 6
|
|
||||||
# u8x8_font_7x14B_1x2_f, // 7
|
|
||||||
# u8x8_font_artossans8_r, // 8
|
|
||||||
# u8x8_font_artosserif8_r, // 9
|
|
||||||
# u8x8_font_torussansbold8_r, // 10
|
|
||||||
# u8x8_font_victoriabold8_r, // 11
|
|
||||||
# u8x8_font_victoriamedium8_r, // 12
|
|
||||||
# u8x8_font_pressstart2p_f, // 13
|
|
||||||
# u8x8_font_pcsenior_f, // 14
|
|
||||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
|
||||||
#
|
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
|
||||||
#
|
|
||||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
|
||||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
|
||||||
###########
|
|
||||||
#
|
|
||||||
# Default configuration for "Scanner" display:
|
|
||||||
# - view timer disabled; rx timer=0; norx timer = 0
|
|
||||||
# => after 1 second immediately an action is triggered
|
|
||||||
# (norx: go to next sonde; rx: go to default receiver display)
|
|
||||||
# - key1 actions: D,0,F,W
|
|
||||||
# => Button press activates default receiver view, double press does nothing
|
|
||||||
# Mid press activates Spectrum display, long press activates Wifi scan
|
|
||||||
# - key2 has no function
|
|
||||||
@Scanner
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=#,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
0,0=XScan
|
|
||||||
0,5=S#:
|
|
||||||
0,9=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0=S
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
# Default configuration for "Legacy" display:
|
|
||||||
# - view timer=-1, rx timer=-1 (disabled); norx timer=20 (or -1 for "old" behaviour)
|
|
||||||
# => norx timer fires after not receiving a singla for 20 seconds
|
|
||||||
# - key1 actions: +,0,F,W
|
|
||||||
# => Button1 press: next sonde; double press => @Scanner display
|
|
||||||
# => Mid press activates Spectrum display, long press activates Wifi scan
|
|
||||||
# - key2 actions: 2,#,#,#
|
|
||||||
# => BUtton2 activates display 2 (@Field)
|
|
||||||
# - timer actions: #,#,0
|
|
||||||
# (norx timer: if no signal for >20 seconds: go back to scanner mode)
|
|
||||||
#
|
|
||||||
@Legacy
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
0,5=f MHz
|
|
||||||
1,8=c
|
|
||||||
0,0=t
|
|
||||||
1,0=is
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
6,0=R
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
# Configuratoon for "Field" display (display 2)
|
|
||||||
# similar to @Legacy, but no norx timer, and Key2 goes to display 4
|
|
||||||
@Field
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
# Configuration for "Field2" display (display 3)
|
|
||||||
# similar to @Field
|
|
||||||
@Field2
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
#############
|
|
||||||
# Configuration for "GPS" display
|
|
||||||
# not yet the final version, just for testing
|
|
||||||
@GPSDIST
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,7=Q
|
|
||||||
7,0=gV
|
|
||||||
7,2=xd=
|
|
||||||
7,4=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
############
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@ScannerTFT
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=#,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
fonts=5,6
|
|
||||||
0,0=XScan
|
|
||||||
0,8,-3=S#:
|
|
||||||
0,9,5=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0,16=S
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
@MainTFT
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
color=FFD700
|
|
||||||
0,0=Is
|
|
||||||
color=0000FF
|
|
||||||
0,11,-5.5=f
|
|
||||||
1,1,6=c
|
|
||||||
1,12.5,-4=t
|
|
||||||
color=00ff00
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
color=FFA500
|
|
||||||
2,9.5,-7=A
|
|
||||||
3,9.5,-7=vm/s
|
|
||||||
color=AA5522
|
|
||||||
4,9.5,-7=hkkm/h
|
|
||||||
color=FFFFFF
|
|
||||||
6,2=r
|
|
||||||
7,0=xd=
|
|
||||||
7,2,6=gD
|
|
||||||
7,12=gI
|
|
||||||
|
|
||||||
############
|
|
||||||
@PeilungTFT
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
color=ffff00,000033
|
|
||||||
color=bbbbbb,000000
|
|
||||||
0,2=xN Top:
|
|
||||||
0,8=xCourse Top:
|
|
||||||
color=ffff00,000033
|
|
||||||
1,0=g0NCS,48,ffff00,000044,6,33ff33,5,eeaa00
|
|
||||||
1,8=g0CCS,48,ffff00,000044,6,55ff55,5,eeaa00
|
|
||||||
color=ffffff,000000
|
|
||||||
6,0=xDirection:
|
|
||||||
6,8,4=gI
|
|
||||||
7,0=xCOG:
|
|
||||||
7,4,4=gC
|
|
||||||
7,8=xturn:
|
|
||||||
7,12,4=gB
|
|
||||||
|
|
||||||
|
|
||||||
############
|
|
||||||
@GPSdataTFT
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=xOn-board GPS:
|
|
||||||
1,0,8=gA
|
|
||||||
2,0,8=gO
|
|
||||||
3,0,8=gH
|
|
||||||
4,0,8=gC
|
|
||||||
5,0=xGPS vs Sonde:
|
|
||||||
6,0,8=gD
|
|
||||||
7,0,8=gI
|
|
||||||
7,8,8=gB
|
|
||||||
|
|
||||||
############
|
|
||||||
@BatteryTFT
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=xBattery status:
|
|
||||||
0,14=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,5,5=bVV
|
|
||||||
2,0,16=bCmA(charging)
|
|
||||||
3,0,16=bDmA(discharging)
|
|
||||||
4.4,0=xUSB:
|
|
||||||
4.4,5,5=bUV
|
|
||||||
5.4,0,10=bImA
|
|
||||||
6.4,0=xTemp:
|
|
||||||
6.4,5,5=bT C
|
|
||||||
|
|
||||||
############
|
|
||||||
@BatteryOLED
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xBat.Status:
|
|
||||||
0,12=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,6=bVV
|
|
||||||
2,0=bCmA (charge)
|
|
||||||
3,0=bDmA (disch.)
|
|
||||||
4,0=xUSB:
|
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@Scan.TFT.Bazjo
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=#,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
scale=11,10
|
|
||||||
fonts=0,2
|
|
||||||
color=e0e0e0
|
|
||||||
#Row 1
|
|
||||||
0.5,0=XScanning...
|
|
||||||
#Row 2
|
|
||||||
3,0=xIndex
|
|
||||||
4,0=S/
|
|
||||||
3,9=xSite
|
|
||||||
4,9=S
|
|
||||||
#Row 3
|
|
||||||
6,0=xType
|
|
||||||
7,0=T
|
|
||||||
6,9=xFrequency
|
|
||||||
7,9=F
|
|
||||||
#Row 4
|
|
||||||
9,0=xWeb UI IP
|
|
||||||
10,0=N
|
|
||||||
#Row 5
|
|
||||||
#Footer
|
|
||||||
color=6C757D
|
|
||||||
15,0=xScan Mode
|
|
||||||
15,18=bVV
|
|
||||||
|
|
||||||
############
|
|
||||||
@Decode/General.TFT.Bazjo
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
scale=11,10
|
|
||||||
fonts=0,2
|
|
||||||
#Row 1
|
|
||||||
color=996A06
|
|
||||||
0,0=xSerial
|
|
||||||
0,5=t
|
|
||||||
color=FFB10B
|
|
||||||
1,0=Is
|
|
||||||
color=996A06
|
|
||||||
0,11=xFreq.
|
|
||||||
0,16=c
|
|
||||||
color=FFB10B
|
|
||||||
1,11=F
|
|
||||||
#Row 2
|
|
||||||
color=3C5C99
|
|
||||||
3,0=xLatitude
|
|
||||||
color=639AFF
|
|
||||||
4,0=L
|
|
||||||
color=3C5C99
|
|
||||||
3,11=xLongitude
|
|
||||||
color=639AFF
|
|
||||||
4,11=O
|
|
||||||
#Row 3
|
|
||||||
color=3C5C99
|
|
||||||
6,0=xHoriz. Speed
|
|
||||||
color=639AFF
|
|
||||||
7,0=Hkkm/h
|
|
||||||
color=3C5C99
|
|
||||||
6,11=xVert. Speed
|
|
||||||
color=639AFF
|
|
||||||
7,11=Vm/s
|
|
||||||
#Row 4
|
|
||||||
color=99004A
|
|
||||||
9,0=xAltitude
|
|
||||||
color=FF007B
|
|
||||||
10,0=A
|
|
||||||
color=99004A
|
|
||||||
9,11=xBearing
|
|
||||||
color=FF007B
|
|
||||||
10,11=GB
|
|
||||||
#Row 5
|
|
||||||
color=06998E
|
|
||||||
12,0=xRSSI
|
|
||||||
color=0AFFEF
|
|
||||||
13,0=R
|
|
||||||
color=06998E
|
|
||||||
12,11=xHistory
|
|
||||||
color=0AFFEF
|
|
||||||
13.5,11=Q4
|
|
||||||
#Footer
|
|
||||||
color=6C757D
|
|
||||||
15,0=xDecode Mode / General View
|
|
||||||
15,18=bVV
|
|
||||||
|
|
||||||
|
|
||||||
############
|
|
||||||
@Decode/Battery.TFT.Bazjo
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
scale=11,10
|
|
||||||
fonts=0,2
|
|
||||||
#Row 1
|
|
||||||
color=99001F
|
|
||||||
0,0=xBattery Status
|
|
||||||
0,11=xBattery Voltage
|
|
||||||
color=FF0035
|
|
||||||
1,0=BS
|
|
||||||
1,11=BVV
|
|
||||||
#Row 2
|
|
||||||
color=99001F
|
|
||||||
3,0=xCharge Current
|
|
||||||
3,11=xDischarge Current
|
|
||||||
color=FF0035
|
|
||||||
4,0=BCmA
|
|
||||||
4,11=BDmA
|
|
||||||
#Row 3
|
|
||||||
color=99001F
|
|
||||||
6,0=xUSB Voltage
|
|
||||||
6,11=xUSB Current
|
|
||||||
color=FF0035
|
|
||||||
7,0=BUV
|
|
||||||
7,11=BImA
|
|
||||||
#Row 4
|
|
||||||
color=99001F
|
|
||||||
9,0=xIC Temperature
|
|
||||||
#9,11=xKey
|
|
||||||
color=FF0035
|
|
||||||
10,0=BTC
|
|
||||||
#10,11=XValue
|
|
||||||
#Row 5
|
|
||||||
#12,0=xKey
|
|
||||||
#12,11=xKey
|
|
||||||
#13,0=XValue
|
|
||||||
#13,11=XValue
|
|
||||||
#Footer
|
|
||||||
color=99001F
|
|
||||||
15,0=xDecode Mode/Battery View
|
|
||||||
15,18=bVV
|
|
||||||
|
|
|
@ -1,276 +0,0 @@
|
||||||
## screens2.txt: TFT display (landscape)
|
|
||||||
# Definition of display content and action behaviour
|
|
||||||
#
|
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
|
||||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
|
||||||
# - view timer: time since current view (display mode and sonde) was started
|
|
||||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
|
||||||
# - norx timer: time since when no sonde data has been received continuously
|
|
||||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
|
||||||
# anything for a 1s period)
|
|
||||||
#
|
|
||||||
# Actions:
|
|
||||||
# - W: activate WiFi scan
|
|
||||||
# - F: activate frequency spectrum display
|
|
||||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
|
||||||
# - x: (1..N): activate display mode x [deprecated]
|
|
||||||
# - >: activate next display mode
|
|
||||||
# - D: activate default receiver display (display mode specified in config)
|
|
||||||
# - +: advance to next active sonde from QRG config
|
|
||||||
# - #: no action
|
|
||||||
#
|
|
||||||
# Display content (lower/upper case: small/large font)
|
|
||||||
# line,column=content
|
|
||||||
# for ILI9225 its also possible to indicate
|
|
||||||
# line,column,width=content for text within a box of width 'width'
|
|
||||||
# line,column,-width=content for right-justified text
|
|
||||||
#
|
|
||||||
# XText : Text
|
|
||||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
|
||||||
# L latitade
|
|
||||||
# O lOngitute
|
|
||||||
# A altitude
|
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
|
||||||
# C afC value
|
|
||||||
# N ip address (only tiny font)
|
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
|
||||||
# Mx telemetry value x (t temp p preassure h hyg b batt)
|
|
||||||
# Gx GPS-related data
|
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
|
||||||
# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
# "N" (what is on top: N=north C=course)
|
|
||||||
# "C" (where does the arrow point to: C=course, S=sonde)
|
|
||||||
# "S" (what is shown by the bullet: C=course, S=sonde)
|
|
||||||
# 50: circle radius, followed by fg and bg color
|
|
||||||
# 5: bullet radius, followed by fg color
|
|
||||||
# 4: arrow width, followed by fg color
|
|
||||||
# R RSSI
|
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
|
||||||
# U=USB volt I=USB current T=IC temp
|
|
||||||
#
|
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
|
||||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
|
||||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
|
||||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
|
||||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
|
||||||
# u8x8_font_5x7_f, // 3
|
|
||||||
# u8x8_font_5x8_f, // 4
|
|
||||||
# u8x8_font_8x13_1x2_f, // 5
|
|
||||||
# u8x8_font_8x13B_1x2_f, // 6
|
|
||||||
# u8x8_font_7x14B_1x2_f, // 7
|
|
||||||
# u8x8_font_artossans8_r, // 8
|
|
||||||
# u8x8_font_artosserif8_r, // 9
|
|
||||||
# u8x8_font_torussansbold8_r, // 10
|
|
||||||
# u8x8_font_victoriabold8_r, // 11
|
|
||||||
# u8x8_font_victoriamedium8_r, // 12
|
|
||||||
# u8x8_font_pressstart2p_f, // 13
|
|
||||||
# u8x8_font_pcsenior_f, // 14
|
|
||||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
|
||||||
#
|
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
|
||||||
#
|
|
||||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
|
||||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
|
||||||
###########
|
|
||||||
|
|
||||||
############
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@ScannerTFT
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=D,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
0,0=XScan
|
|
||||||
0,5=S#:
|
|
||||||
0,9=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0,16=S
|
|
||||||
7,0=bVV
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
@Legacy
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
0,0=t
|
|
||||||
0,5=f MHz
|
|
||||||
1,0=is
|
|
||||||
#1,8=c
|
|
||||||
1,8=z
|
|
||||||
2,0=L
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,0=O
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,0=R
|
|
||||||
6,7=Q
|
|
||||||
7,6=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field2
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@GPSDIST
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,7=Q
|
|
||||||
7,0=gV
|
|
||||||
7,2=xd=
|
|
||||||
7,4=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@BatteryOLED
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xBat.Status:
|
|
||||||
0,12=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,6=bVV
|
|
||||||
2,0=bCmA (charge)
|
|
||||||
3,0=bDmA (disch.)
|
|
||||||
4,0=xUSB:
|
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
############
|
|
||||||
@Meteo
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=xSonde
|
|
||||||
3,0=xData
|
|
||||||
2,10=A
|
|
||||||
4,0=Mt°C
|
|
||||||
4,9=Mh%rH
|
|
||||||
6,0=MphPa
|
|
||||||
6,11=MbV
|
|
||||||
|
|
||||||
##################
|
|
||||||
@GPS-Data
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xGPS-Data
|
|
||||||
1,0=xLAT :
|
|
||||||
1,6=gA
|
|
||||||
2,0=xLONG:
|
|
||||||
2,6=gO
|
|
||||||
3,0=xALT :
|
|
||||||
3,9=gH
|
|
||||||
4,0=xSonde
|
|
||||||
5,0=xAlt :
|
|
||||||
5,6=a
|
|
||||||
6,0=xDist:
|
|
||||||
6,6=gD
|
|
||||||
|
|
||||||
#################
|
|
||||||
@TelemetryData
|
|
||||||
scale=22,13
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
fonts=5,6
|
|
||||||
color=FFD700
|
|
||||||
0,0,10.5=Is
|
|
||||||
color=0000FF
|
|
||||||
0,11,-5.5=f
|
|
||||||
1,0,4=t
|
|
||||||
1,10.5,-6=c
|
|
||||||
color=00ff00
|
|
||||||
2,0,7=L
|
|
||||||
3,0,7=O
|
|
||||||
color=FFA500
|
|
||||||
2,9.5,-7=a
|
|
||||||
2.8,9.5,-7=vm/s
|
|
||||||
color=AA5522
|
|
||||||
3.6,9.5,-7=hkkm/h
|
|
||||||
color=FFFFFF
|
|
||||||
4.4,0=xTelemetry Data:
|
|
||||||
5.3,0=Mt C
|
|
||||||
5.3,9=Mh%rH
|
|
||||||
6.5,0=MphPa
|
|
||||||
6.5,11=MbV
|
|
|
@ -1,276 +0,0 @@
|
||||||
## screens2.txt: TFT display (landscape)
|
|
||||||
# Definition of display content and action behaviour
|
|
||||||
#
|
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
|
||||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
|
||||||
# - view timer: time since current view (display mode and sonde) was started
|
|
||||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
|
||||||
# - norx timer: time since when no sonde data has been received continuously
|
|
||||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
|
||||||
# anything for a 1s period)
|
|
||||||
#
|
|
||||||
# Actions:
|
|
||||||
# - W: activate WiFi scan
|
|
||||||
# - F: activate frequency spectrum display
|
|
||||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
|
||||||
# - x: (1..N): activate display mode x [deprecated]
|
|
||||||
# - >: activate next display mode
|
|
||||||
# - D: activate default receiver display (display mode specified in config)
|
|
||||||
# - +: advance to next active sonde from QRG config
|
|
||||||
# - #: no action
|
|
||||||
#
|
|
||||||
# Display content (lower/upper case: small/large font)
|
|
||||||
# line,column=content
|
|
||||||
# for ILI9225 its also possible to indicate
|
|
||||||
# line,column,width=content for text within a box of width 'width'
|
|
||||||
# line,column,-width=content for right-justified text
|
|
||||||
#
|
|
||||||
# XText : Text
|
|
||||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
|
||||||
# L latitade
|
|
||||||
# O lOngitute
|
|
||||||
# A altitude
|
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
|
||||||
# C afC value
|
|
||||||
# N ip address (only tiny font)
|
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
|
||||||
# Mx telemetry value x (t temp p preassure h hyg b batt)
|
|
||||||
# Gx GPS-related data
|
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
|
||||||
# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
# "N" (what is on top: N=north C=course)
|
|
||||||
# "C" (where does the arrow point to: C=course, S=sonde)
|
|
||||||
# "S" (what is shown by the bullet: C=course, S=sonde)
|
|
||||||
# 50: circle radius, followed by fg and bg color
|
|
||||||
# 5: bullet radius, followed by fg color
|
|
||||||
# 4: arrow width, followed by fg color
|
|
||||||
# R RSSI
|
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
|
||||||
# U=USB volt I=USB current T=IC temp
|
|
||||||
#
|
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
|
||||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
|
||||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
|
||||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
|
||||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
|
||||||
# u8x8_font_5x7_f, // 3
|
|
||||||
# u8x8_font_5x8_f, // 4
|
|
||||||
# u8x8_font_8x13_1x2_f, // 5
|
|
||||||
# u8x8_font_8x13B_1x2_f, // 6
|
|
||||||
# u8x8_font_7x14B_1x2_f, // 7
|
|
||||||
# u8x8_font_artossans8_r, // 8
|
|
||||||
# u8x8_font_artosserif8_r, // 9
|
|
||||||
# u8x8_font_torussansbold8_r, // 10
|
|
||||||
# u8x8_font_victoriabold8_r, // 11
|
|
||||||
# u8x8_font_victoriamedium8_r, // 12
|
|
||||||
# u8x8_font_pressstart2p_f, // 13
|
|
||||||
# u8x8_font_pcsenior_f, // 14
|
|
||||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
|
||||||
#
|
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
|
||||||
#
|
|
||||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
|
||||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
|
||||||
###########
|
|
||||||
|
|
||||||
############
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@ScannerTFT
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=D,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
0,0=XScan
|
|
||||||
0,5=S#:
|
|
||||||
0,9=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0,16=S
|
|
||||||
7,0=bVV
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
@Legacy
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
0,0=t
|
|
||||||
0,5=f MHz
|
|
||||||
1,0=is
|
|
||||||
#1,8=c
|
|
||||||
1,8=z
|
|
||||||
2,0=L
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,0=O
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,0=R
|
|
||||||
6,7=Q
|
|
||||||
7,6=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field2
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@GPSDIST
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,7=Q
|
|
||||||
7,0=gV
|
|
||||||
7,2=xd=
|
|
||||||
7,4=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@BatteryOLED
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xBat.Status:
|
|
||||||
0,12=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,6=bVV
|
|
||||||
2,0=bCmA (charge)
|
|
||||||
3,0=bDmA (disch.)
|
|
||||||
4,0=xUSB:
|
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
############
|
|
||||||
@Meteo
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=xSonde
|
|
||||||
3,0=xData
|
|
||||||
2,10=A
|
|
||||||
4,0=Mt°C
|
|
||||||
4,9=Mh%rH
|
|
||||||
6,0=MphPa
|
|
||||||
6,11=MbV
|
|
||||||
|
|
||||||
##################
|
|
||||||
@GPS-Data
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xGPS-Data
|
|
||||||
1,0=xLAT :
|
|
||||||
1,6=gA
|
|
||||||
2,0=xLONG:
|
|
||||||
2,6=gO
|
|
||||||
3,0=xALT :
|
|
||||||
3,9=gH
|
|
||||||
4,0=xSonde
|
|
||||||
5,0=xAlt :
|
|
||||||
5,6=a
|
|
||||||
6,0=xDist:
|
|
||||||
6,6=gD
|
|
||||||
|
|
||||||
#################
|
|
||||||
@TelemetryData
|
|
||||||
scale=22,13
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
fonts=5,6
|
|
||||||
color=FFD700
|
|
||||||
0,0,10.5=Is
|
|
||||||
color=0000FF
|
|
||||||
0,11,-5.5=f
|
|
||||||
1,0,4=t
|
|
||||||
1,10.5,-6=c
|
|
||||||
color=00ff00
|
|
||||||
2,0,7=L
|
|
||||||
3,0,7=O
|
|
||||||
color=FFA500
|
|
||||||
2,9.5,-7=a
|
|
||||||
2.8,9.5,-7=vm/s
|
|
||||||
color=AA5522
|
|
||||||
3.6,9.5,-7=hkkm/h
|
|
||||||
color=FFFFFF
|
|
||||||
4.4,0=xTelemetry Data:
|
|
||||||
5.3,0=Mt C
|
|
||||||
5.3,9=Mh%rH
|
|
||||||
6.5,0=MphPa
|
|
||||||
6.5,11=MbV
|
|
|
@ -1,276 +0,0 @@
|
||||||
## screens2.txt: TFT display (landscape)
|
|
||||||
# Definition of display content and action behaviour
|
|
||||||
#
|
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
|
||||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
|
||||||
# - view timer: time since current view (display mode and sonde) was started
|
|
||||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
|
||||||
# - norx timer: time since when no sonde data has been received continuously
|
|
||||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
|
||||||
# anything for a 1s period)
|
|
||||||
#
|
|
||||||
# Actions:
|
|
||||||
# - W: activate WiFi scan
|
|
||||||
# - F: activate frequency spectrum display
|
|
||||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
|
||||||
# - x: (1..N): activate display mode x [deprecated]
|
|
||||||
# - >: activate next display mode
|
|
||||||
# - D: activate default receiver display (display mode specified in config)
|
|
||||||
# - +: advance to next active sonde from QRG config
|
|
||||||
# - #: no action
|
|
||||||
#
|
|
||||||
# Display content (lower/upper case: small/large font)
|
|
||||||
# line,column=content
|
|
||||||
# for ILI9225 its also possible to indicate
|
|
||||||
# line,column,width=content for text within a box of width 'width'
|
|
||||||
# line,column,-width=content for right-justified text
|
|
||||||
#
|
|
||||||
# XText : Text
|
|
||||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
|
||||||
# L latitade
|
|
||||||
# O lOngitute
|
|
||||||
# A altitude
|
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
|
||||||
# C afC value
|
|
||||||
# N ip address (only tiny font)
|
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
|
||||||
# Mx telemetry value x (t temp p preassure h hyg b batt)
|
|
||||||
# Gx GPS-related data
|
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
|
||||||
# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
# "N" (what is on top: N=north C=course)
|
|
||||||
# "C" (where does the arrow point to: C=course, S=sonde)
|
|
||||||
# "S" (what is shown by the bullet: C=course, S=sonde)
|
|
||||||
# 50: circle radius, followed by fg and bg color
|
|
||||||
# 5: bullet radius, followed by fg color
|
|
||||||
# 4: arrow width, followed by fg color
|
|
||||||
# R RSSI
|
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
|
||||||
# U=USB volt I=USB current T=IC temp
|
|
||||||
#
|
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
|
||||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
|
||||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
|
||||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
|
||||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
|
||||||
# u8x8_font_5x7_f, // 3
|
|
||||||
# u8x8_font_5x8_f, // 4
|
|
||||||
# u8x8_font_8x13_1x2_f, // 5
|
|
||||||
# u8x8_font_8x13B_1x2_f, // 6
|
|
||||||
# u8x8_font_7x14B_1x2_f, // 7
|
|
||||||
# u8x8_font_artossans8_r, // 8
|
|
||||||
# u8x8_font_artosserif8_r, // 9
|
|
||||||
# u8x8_font_torussansbold8_r, // 10
|
|
||||||
# u8x8_font_victoriabold8_r, // 11
|
|
||||||
# u8x8_font_victoriamedium8_r, // 12
|
|
||||||
# u8x8_font_pressstart2p_f, // 13
|
|
||||||
# u8x8_font_pcsenior_f, // 14
|
|
||||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
|
||||||
#
|
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
|
||||||
#
|
|
||||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
|
||||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
|
||||||
###########
|
|
||||||
|
|
||||||
############
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@ScannerTFT
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=D,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
0,0=XScan
|
|
||||||
0,5=S#:
|
|
||||||
0,9=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0,16=S
|
|
||||||
7,0=bVV
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
@Legacy
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
0,0=t
|
|
||||||
0,5=f MHz
|
|
||||||
1,0=is
|
|
||||||
#1,8=c
|
|
||||||
1,8=z
|
|
||||||
2,0=L
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,0=O
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,0=R
|
|
||||||
6,7=Q
|
|
||||||
7,6=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field2
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@GPSDIST
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,7=Q
|
|
||||||
7,0=gV
|
|
||||||
7,2=xd=
|
|
||||||
7,4=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@BatteryOLED
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xBat.Status:
|
|
||||||
0,12=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,6=bVV
|
|
||||||
2,0=bCmA (charge)
|
|
||||||
3,0=bDmA (disch.)
|
|
||||||
4,0=xUSB:
|
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
############
|
|
||||||
@Meteo
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=xSonde
|
|
||||||
3,0=xData
|
|
||||||
2,10=A
|
|
||||||
4,0=Mt°C
|
|
||||||
4,9=Mh%rH
|
|
||||||
6,0=MphPa
|
|
||||||
6,11=MbV
|
|
||||||
|
|
||||||
##################
|
|
||||||
@GPS-Data
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xGPS-Data
|
|
||||||
1,0=xLAT :
|
|
||||||
1,6=gA
|
|
||||||
2,0=xLONG:
|
|
||||||
2,6=gO
|
|
||||||
3,0=xALT :
|
|
||||||
3,9=gH
|
|
||||||
4,0=xSonde
|
|
||||||
5,0=xAlt :
|
|
||||||
5,6=a
|
|
||||||
6,0=xDist:
|
|
||||||
6,6=gD
|
|
||||||
|
|
||||||
#################
|
|
||||||
@TelemetryData
|
|
||||||
scale=22,13
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
fonts=5,6
|
|
||||||
color=FFD700
|
|
||||||
0,0,10.5=Is
|
|
||||||
color=0000FF
|
|
||||||
0,11,-5.5=f
|
|
||||||
1,0,4=t
|
|
||||||
1,10.5,-6=c
|
|
||||||
color=00ff00
|
|
||||||
2,0,7=L
|
|
||||||
3,0,7=O
|
|
||||||
color=FFA500
|
|
||||||
2,9.5,-7=a
|
|
||||||
2.8,9.5,-7=vm/s
|
|
||||||
color=AA5522
|
|
||||||
3.6,9.5,-7=hkkm/h
|
|
||||||
color=FFFFFF
|
|
||||||
4.4,0=xTelemetry Data:
|
|
||||||
5.3,0=Mt C
|
|
||||||
5.3,9=Mh%rH
|
|
||||||
6.5,0=MphPa
|
|
||||||
6.5,11=MbV
|
|
|
@ -1,276 +0,0 @@
|
||||||
## screens2.txt: TFT display (landscape)
|
|
||||||
# Definition of display content and action behaviour
|
|
||||||
#
|
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
|
||||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
|
||||||
# - view timer: time since current view (display mode and sonde) was started
|
|
||||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
|
||||||
# - norx timer: time since when no sonde data has been received continuously
|
|
||||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
|
||||||
# anything for a 1s period)
|
|
||||||
#
|
|
||||||
# Actions:
|
|
||||||
# - W: activate WiFi scan
|
|
||||||
# - F: activate frequency spectrum display
|
|
||||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
|
||||||
# - x: (1..N): activate display mode x [deprecated]
|
|
||||||
# - >: activate next display mode
|
|
||||||
# - D: activate default receiver display (display mode specified in config)
|
|
||||||
# - +: advance to next active sonde from QRG config
|
|
||||||
# - #: no action
|
|
||||||
#
|
|
||||||
# Display content (lower/upper case: small/large font)
|
|
||||||
# line,column=content
|
|
||||||
# for ILI9225 its also possible to indicate
|
|
||||||
# line,column,width=content for text within a box of width 'width'
|
|
||||||
# line,column,-width=content for right-justified text
|
|
||||||
#
|
|
||||||
# XText : Text
|
|
||||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
|
||||||
# L latitade
|
|
||||||
# O lOngitute
|
|
||||||
# A altitude
|
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
|
||||||
# C afC value
|
|
||||||
# N ip address (only tiny font)
|
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
|
||||||
# Mx telemetry value x (t temp p preassure h hyg b batt)
|
|
||||||
# Gx GPS-related data
|
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
|
||||||
# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
# "N" (what is on top: N=north C=course)
|
|
||||||
# "C" (where does the arrow point to: C=course, S=sonde)
|
|
||||||
# "S" (what is shown by the bullet: C=course, S=sonde)
|
|
||||||
# 50: circle radius, followed by fg and bg color
|
|
||||||
# 5: bullet radius, followed by fg color
|
|
||||||
# 4: arrow width, followed by fg color
|
|
||||||
# R RSSI
|
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
|
||||||
# U=USB volt I=USB current T=IC temp
|
|
||||||
#
|
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
|
||||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
|
||||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
|
||||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
|
||||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
|
||||||
# u8x8_font_5x7_f, // 3
|
|
||||||
# u8x8_font_5x8_f, // 4
|
|
||||||
# u8x8_font_8x13_1x2_f, // 5
|
|
||||||
# u8x8_font_8x13B_1x2_f, // 6
|
|
||||||
# u8x8_font_7x14B_1x2_f, // 7
|
|
||||||
# u8x8_font_artossans8_r, // 8
|
|
||||||
# u8x8_font_artosserif8_r, // 9
|
|
||||||
# u8x8_font_torussansbold8_r, // 10
|
|
||||||
# u8x8_font_victoriabold8_r, // 11
|
|
||||||
# u8x8_font_victoriamedium8_r, // 12
|
|
||||||
# u8x8_font_pressstart2p_f, // 13
|
|
||||||
# u8x8_font_pcsenior_f, // 14
|
|
||||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
|
||||||
#
|
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
|
||||||
#
|
|
||||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
|
||||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
|
||||||
###########
|
|
||||||
|
|
||||||
############
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@ScannerTFT
|
|
||||||
timer=-1,0,0
|
|
||||||
key1action=D,#,F,W
|
|
||||||
key2action=D,#,#,#
|
|
||||||
timeaction=#,D,+
|
|
||||||
0,0=XScan
|
|
||||||
0,5=S#:
|
|
||||||
0,9=T
|
|
||||||
3,0=F MHz
|
|
||||||
5,0,16=S
|
|
||||||
7,0=bVV
|
|
||||||
7,5=n
|
|
||||||
|
|
||||||
############
|
|
||||||
@Legacy
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
0,0=t
|
|
||||||
0,5=f MHz
|
|
||||||
1,0=is
|
|
||||||
#1,8=c
|
|
||||||
1,8=z
|
|
||||||
2,0=L
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,0=O
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,0=R
|
|
||||||
6,7=Q
|
|
||||||
7,6=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@Field2
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
|
||||||
6,0=A
|
|
||||||
6,7=Q
|
|
||||||
|
|
||||||
############
|
|
||||||
@GPSDIST
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
2,10=a
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
5,9=gC
|
|
||||||
5,13=gB
|
|
||||||
6,7=Q
|
|
||||||
7,0=gV
|
|
||||||
7,2=xd=
|
|
||||||
7,4=gD
|
|
||||||
7,12=gI°
|
|
||||||
|
|
||||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
|
||||||
# Scan display for large 2" TFT dispaly
|
|
||||||
@BatteryOLED
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xBat.Status:
|
|
||||||
0,12=bS
|
|
||||||
1,0=xBatt:
|
|
||||||
1,6=bVV
|
|
||||||
2,0=bCmA (charge)
|
|
||||||
3,0=bDmA (disch.)
|
|
||||||
4,0=xUSB:
|
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
############
|
|
||||||
@Meteo
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=xSonde
|
|
||||||
3,0=xData
|
|
||||||
2,10=A
|
|
||||||
4,0=Mt°C
|
|
||||||
4,9=Mh%rH
|
|
||||||
6,0=MphPa
|
|
||||||
6,11=MbV
|
|
||||||
|
|
||||||
##################
|
|
||||||
@GPS-Data
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xGPS-Data
|
|
||||||
1,0=xLAT :
|
|
||||||
1,6=gA
|
|
||||||
2,0=xLONG:
|
|
||||||
2,6=gO
|
|
||||||
3,0=xALT :
|
|
||||||
3,9=gH
|
|
||||||
4,0=xSonde
|
|
||||||
5,0=xAlt :
|
|
||||||
5,6=a
|
|
||||||
6,0=xDist:
|
|
||||||
6,6=gD
|
|
||||||
|
|
||||||
#################
|
|
||||||
@TelemetryData
|
|
||||||
scale=22,13
|
|
||||||
timer=-1,-1,N
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,0
|
|
||||||
fonts=5,6
|
|
||||||
color=FFD700
|
|
||||||
0,0,10.5=Is
|
|
||||||
color=0000FF
|
|
||||||
0,11,-5.5=f
|
|
||||||
1,0,4=t
|
|
||||||
1,10.5,-6=c
|
|
||||||
color=00ff00
|
|
||||||
2,0,7=L
|
|
||||||
3,0,7=O
|
|
||||||
color=FFA500
|
|
||||||
2,9.5,-7=a
|
|
||||||
2.8,9.5,-7=vm/s
|
|
||||||
color=AA5522
|
|
||||||
3.6,9.5,-7=hkkm/h
|
|
||||||
color=FFFFFF
|
|
||||||
4.4,0=xTelemetry Data:
|
|
||||||
5.3,0=Mt C
|
|
||||||
5.3,9=Mh%rH
|
|
||||||
6.5,0=MphPa
|
|
||||||
6.5,11=MbV
|
|
|
@ -1,392 +0,0 @@
|
||||||
body, html {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
font-family: Arial;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active, .cfgheader:hover {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
.cfgpanel {
|
|
||||||
}
|
|
||||||
|
|
||||||
th.cfg {
|
|
||||||
padding:5pt
|
|
||||||
}
|
|
||||||
table.stat {
|
|
||||||
margin:0px 0px 5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 1.25em;
|
|
||||||
height: 0.8em;
|
|
||||||
margin-right: 0.3em;
|
|
||||||
border-top: 0.2em solid #fff;
|
|
||||||
border-bottom: 0.2em solid #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0.3em;
|
|
||||||
left: 0px;
|
|
||||||
width: 100%;
|
|
||||||
border-top: 0.2em solid #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.tci {
|
|
||||||
flex-grow: 1; border: none; margin: 0; padding: 0;
|
|
||||||
}
|
|
||||||
.footer {
|
|
||||||
background-color: #333;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.ch {
|
|
||||||
text-align: right;
|
|
||||||
padding: 0px 8px;
|
|
||||||
}
|
|
||||||
td.act {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
table, th, td {
|
|
||||||
border: 1px solid black;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background-color: #ddd
|
|
||||||
}
|
|
||||||
|
|
||||||
td#caption {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #aaa;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
td#sfreq {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: auto;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.tabcontent {
|
|
||||||
display: none;
|
|
||||||
flex: 1;
|
|
||||||
border-top: none;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: Helvetica;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0px auto;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
h1{
|
|
||||||
color: #0F3376;
|
|
||||||
font-size: 24px
|
|
||||||
}
|
|
||||||
p{
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button2 {
|
|
||||||
background-color: #f44336;
|
|
||||||
}
|
|
||||||
:disabled.save {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
.save {
|
|
||||||
background-color: #CC1111; /* 0F33C6; */
|
|
||||||
border: white;
|
|
||||||
border-width: 1;
|
|
||||||
color: white;
|
|
||||||
padding: 8px 30px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.ttgoinfo {
|
|
||||||
color: white;
|
|
||||||
padding: 8px 10px;
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
.ctlbtn {
|
|
||||||
background-color: #ccc;
|
|
||||||
border: black;
|
|
||||||
border-width: 1;
|
|
||||||
color: black;
|
|
||||||
padding: 4px 30px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
margin: 2;
|
|
||||||
font-size: 4vh;
|
|
||||||
}
|
|
||||||
.update {
|
|
||||||
margin: 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#map {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content table, .leaflet-popup-content table td {
|
|
||||||
border:0;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content table td:nth-child(2),.leaflet-popup-content table td:nth-child(5) {
|
|
||||||
text-align: right;
|
|
||||||
padding-left: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-popup-content table td:nth-child(3),.leaflet-popup-content table td:nth-child(6) {
|
|
||||||
text-align: left;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-gps{animation:fading 1s infinite}@keyframes fading{0%{opacity:0.7}50%{opacity:1}100%{opacity:0.7}}
|
|
||||||
|
|
||||||
.leaflet-gps::after {
|
|
||||||
content: '🔵';
|
|
||||||
}
|
|
||||||
.leaflet-gps {
|
|
||||||
margin-left: -7px !important;
|
|
||||||
margin-top: -9px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-burst::after {
|
|
||||||
content: '💥';
|
|
||||||
}
|
|
||||||
.leaflet-burst {
|
|
||||||
margin-left: -20px !important;
|
|
||||||
margin-top: -22px !important;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-landing::after {
|
|
||||||
content: '×';
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-landing {
|
|
||||||
margin-left: -13px !important;
|
|
||||||
margin-top: -30px !important;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.leaflet-header {
|
|
||||||
text-align: center;
|
|
||||||
width: 250px;
|
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
pointer-events: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-header #settings {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-header label {
|
|
||||||
display: block;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
.leaflet-header input {
|
|
||||||
width: 80px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-header #submit {
|
|
||||||
margin: 3px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-footer {
|
|
||||||
display:none;
|
|
||||||
text-align: center;
|
|
||||||
width: 180px;
|
|
||||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
|
||||||
border-top-left-radius: 4px;
|
|
||||||
border-top-right-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-center {
|
|
||||||
left:0;
|
|
||||||
right:0;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 5px;
|
|
||||||
background: #fff;
|
|
||||||
background: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-header #sonde_detail {
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.leaflet-control-attribution {
|
|
||||||
-moz-transform: rotate(-90deg) translateX(100%);
|
|
||||||
-ms-transform: rotate(-90deg) translateX(100%);
|
|
||||||
-o-transform: rotate(-90deg) translateX(100%);;
|
|
||||||
-webkit-transform: rotate(-90deg) translateX(100%);
|
|
||||||
transform: rotate(-90deg) translateX(100%);
|
|
||||||
-webkit-transform-origin: 100% 100%;
|
|
||||||
-moz-transform-origin: 100% 100%;
|
|
||||||
-ms-transform-origin: 100% 100%;
|
|
||||||
-o-transform-origin: 100% 100%;
|
|
||||||
transform-origin: 100% 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ldot {
|
|
||||||
height: 15px;
|
|
||||||
width: 15px;
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-left: -1px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ybg {
|
|
||||||
background-color: orange;
|
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, from(yellow), to(orange));
|
|
||||||
background-image: linear-gradient(top, yellow, orange);
|
|
||||||
}
|
|
||||||
.gbg {
|
|
||||||
background-color: green;
|
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, from(lime), to(green));
|
|
||||||
background-image: linear-gradient(top, lime, green);
|
|
||||||
}
|
|
||||||
.rbg {
|
|
||||||
background-color: red;
|
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, from(orange), to(red));
|
|
||||||
background-image: linear-gradient(top, orange, red);
|
|
||||||
}
|
|
||||||
|
|
||||||
#sonde_statbar .ldot {
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a black background color to the top navigation */
|
|
||||||
.topnav {
|
|
||||||
background-color: #333;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style the links inside the navigation bar */
|
|
||||||
.topnav a {
|
|
||||||
float: left;
|
|
||||||
display: block;
|
|
||||||
color: #f2f2f2;
|
|
||||||
text-align: center;
|
|
||||||
padding: 14px 16px;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change the color of links on hover */
|
|
||||||
.topnav a:hover {
|
|
||||||
background-color: #ddd;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add an active class to highlight the current page */
|
|
||||||
.topnav a.active {
|
|
||||||
background-color: #04AA6D;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide the link that should open and close the topnav on small screens */
|
|
||||||
.topnav .icon {
|
|
||||||
display: none;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
padding-top: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When the screen is less than 600 pixels wide, hide all links, except for the first one ("Home"). Show the link that contains should open and close the topnav (.icon) */
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.topnav a:not(.active) {display: none;}
|
|
||||||
.topnav a.icon {
|
|
||||||
float: right;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The "responsive" class is added to the topnav with JavaScript when the user clicks on the icon. This class makes the topnav look good on small screens (display the links vertically instead of horizontally) */
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.topnav.responsive {position: relative;}
|
|
||||||
.topnav.responsive a.icon {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.topnav.responsive a {
|
|
||||||
float: none;
|
|
||||||
display: block;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
h2{
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
table, th, td, .save, a.active {
|
|
||||||
color: white;
|
|
||||||
border: 1px solid grey;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
input, select, .tci, .warning {
|
|
||||||
color: white;
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
a:link, a:visited {
|
|
||||||
color: #D3D3D3;
|
|
||||||
}
|
|
||||||
.topnav, td#sfreq {
|
|
||||||
background-color: grey;
|
|
||||||
}
|
|
||||||
.topnav a:visited {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.ctlbtn {
|
|
||||||
color: white;
|
|
||||||
background-color: grey;
|
|
||||||
}
|
|
||||||
.leaflet-center {
|
|
||||||
color: white;
|
|
||||||
background-color: grey;
|
|
||||||
}
|
|
||||||
.leaflet-bar a {
|
|
||||||
background-color: grey !important;
|
|
||||||
}
|
|
||||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
|
|
||||||
color: white !important;
|
|
||||||
background: grey !important;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
// Configuration flags for including/excluding fuctionality from the compiled binary
|
|
||||||
// set flag to 0 for exclude/1 for include
|
|
||||||
|
|
||||||
/* data feed to sondehubv2 */
|
|
||||||
/* needs about 4k4 code, 200b data, 200b stack, 200b heap */
|
|
||||||
#define FEATURE_SONDEHUB 1
|
|
||||||
#define FEATURE_CHASEMAPPER 1
|
|
||||||
#define FEATURE_MQTT 0
|
|
||||||
|
|
||||||
#define FEATURE_RS92 1
|
|
||||||
|
|
||||||
/* Most recent version support fonts in a dedicated flash parition "fonts".
|
|
||||||
* This is incomabtible (in terms of code and flash layout) to previous versions.
|
|
||||||
* If LEGACY_FONTS_IN_CODEBIN is sets, fonts are also included in the bin image.
|
|
||||||
* This maintains compatibility for OTA with previous versions (in which case the
|
|
||||||
* bin image fonts will be used as before).
|
|
||||||
* The code automatically uses fonts in flash partition if that exists, otherwise
|
|
||||||
* fonts in code.
|
|
||||||
* The flash partition fonts support latin15 codeset (instead of 7bit ascii).
|
|
||||||
* Also, it is easier to use different fonts :) just flash the font partition w/ something else...
|
|
||||||
* This option will likely be removed post-master1.0
|
|
||||||
*/
|
|
||||||
#define LEGACY_FONTS_IN_CODEBIN 1
|
|
|
@ -1,43 +0,0 @@
|
||||||
#include "Chasemapper.h"
|
|
||||||
|
|
||||||
extern const char *sondeTypeStrSH[];
|
|
||||||
|
|
||||||
int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
|
||||||
char buf[1024];
|
|
||||||
struct tm tim;
|
|
||||||
time_t t = si->d.time;
|
|
||||||
gmtime_r(&t, &tim);
|
|
||||||
uint8_t realtype = si->type;
|
|
||||||
if (TYPE_IS_METEO(realtype)) {
|
|
||||||
realtype = si->d.subtype == 1 ? STYPE_M10 : STYPE_M20;
|
|
||||||
}
|
|
||||||
sprintf(buf, "{ \"type\": \"PAYLOAD_SUMMARY\","
|
|
||||||
"\"callsign\": \"%s\","
|
|
||||||
"\"latitude\": %.5f,"
|
|
||||||
"\"longitude\": %.5f,"
|
|
||||||
"\"altitude\": %d,"
|
|
||||||
"\"speed\": %d,"
|
|
||||||
"\"heading\": %d,"
|
|
||||||
"\"time\": \"%02d:%02d:%02d\","
|
|
||||||
"\"model\": \"%s\","
|
|
||||||
"\"freq\": \"%.3f MHz\"",
|
|
||||||
si->d.ser,
|
|
||||||
si->d.lat,
|
|
||||||
si->d.lon,
|
|
||||||
(int)si->d.alt,
|
|
||||||
(int)(si->d.hs * 1.9438445), // m/s into knots
|
|
||||||
(int)si->d.dir,
|
|
||||||
tim.tm_hour, tim.tm_min, tim.tm_sec,
|
|
||||||
sondeTypeStrSH[realtype],
|
|
||||||
si->freq);
|
|
||||||
if( !isnan(si->d.temperature) ) {
|
|
||||||
sprintf(buf + strlen(buf), ", \"temp\": %.1f", si->d.temperature);
|
|
||||||
}
|
|
||||||
strcat(buf, "}");
|
|
||||||
Serial.printf("Sending chasemapper json: %s\n", buf);
|
|
||||||
udp.beginPacket(sonde.config.cm.host, sonde.config.cm.port);
|
|
||||||
udp.write((const uint8_t *)buf, strlen(buf));
|
|
||||||
udp.endPacket();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef _CHASEMAPPER_H
|
|
||||||
#define _CHASEMAPPER_H
|
|
||||||
|
|
||||||
#include "Sonde.h"
|
|
||||||
//#include <WiFi.h>
|
|
||||||
#include <WiFiUdp.h>
|
|
||||||
#include <time.h>
|
|
||||||
class Chasemapper {
|
|
||||||
public:
|
|
||||||
static int send(WiFiUDP &udb, SondeInfo *si);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,693 +0,0 @@
|
||||||
|
|
||||||
/* DFM decoder functions */
|
|
||||||
#include "DFM.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
#define DFM_DEBUG 0
|
|
||||||
|
|
||||||
#if DFM_DEBUG
|
|
||||||
#define DFM_DBG(x) x
|
|
||||||
#else
|
|
||||||
#define DFM_DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DFM_FRAMELEN 33
|
|
||||||
|
|
||||||
#define MAXIDAGE 1800
|
|
||||||
|
|
||||||
/*
|
|
||||||
* observed DAT patterns for DFM-9:
|
|
||||||
* A: 0+1; 2+3; 4+5; 6+7; 8+0 => keep frame in shadowFrame
|
|
||||||
* B: 1+2; 3+4; 5+6; 7+8 => all good => keep date in shadowDate
|
|
||||||
* C: 0+1; 2+3; 4+5; 6+7; 8+15 => all good => keep date in shadowDate
|
|
||||||
* D: 0+1; 2+3; 4+5; 6+7; 0+1 => use shadowDate
|
|
||||||
* not seen:5+6; 7+1
|
|
||||||
* values:
|
|
||||||
* 0:packet counter; 1:utc-msec; 2:lat,vh; 3:lon,dir, 4:alt,vv, 8=utc-date(day-hh-mm)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// single data structure, search restarts after decoder change
|
|
||||||
static struct st_dfmstat {
|
|
||||||
int idcnt0;
|
|
||||||
int idcnt1;
|
|
||||||
int lastfrid;
|
|
||||||
int lastfrcnt;
|
|
||||||
uint8_t start[50];
|
|
||||||
uint16_t dat[50*2];
|
|
||||||
uint8_t cnt[50*2];
|
|
||||||
uint16_t good;
|
|
||||||
uint32_t datesec;
|
|
||||||
uint8_t frame;
|
|
||||||
uint16_t msec;
|
|
||||||
uint8_t nameregok;
|
|
||||||
uint8_t nameregtop;
|
|
||||||
uint8_t lastdat;
|
|
||||||
uint8_t cycledone; // 0=no; 1=OK, 2=partially/with errors
|
|
||||||
float meas[5+2];
|
|
||||||
} dfmstate;
|
|
||||||
|
|
||||||
decoderSetupCfg DFMSetupCfg {
|
|
||||||
.bitrate = 2500,
|
|
||||||
// continuous mode
|
|
||||||
// Enable auto-AFC, auto-AGC, RX Trigger by preamble ????
|
|
||||||
.rx_cfg = 0x1E,
|
|
||||||
.sync_cfg = 0x70,
|
|
||||||
.sync_len = 2,
|
|
||||||
.sync_data = (const uint8_t *)"\xAA\xAA",
|
|
||||||
.preamble_cfg = 0xA8,
|
|
||||||
};
|
|
||||||
|
|
||||||
int DFM::setup(float frequency, int type)
|
|
||||||
{
|
|
||||||
stype = type;
|
|
||||||
#if DFM_DEBUG
|
|
||||||
Serial.printf("Setup sx1278 for DFM sonde (type=%d)\n", stype);
|
|
||||||
#endif
|
|
||||||
if(sx1278.ON()!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(DecoderBase::setup(DFMSetupCfg, sonde.config.dfm.agcbw, sonde.config.dfm.rxbw) != 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
// This is now all done by the generic setup method in base class
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting FSM mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setBitrate(2500)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting bitrate 2500bit/s FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.dfm.agcbw)!=0) {
|
|
||||||
DFM_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.dfm.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.dfm.rxbw)!=0) {
|
|
||||||
DFM_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.dfm.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
if(sx1278.setRxConf(0x1E)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// working with continuous RX
|
|
||||||
const char *SYNC="\xAA\xAA";
|
|
||||||
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
|
||||||
//if(sx1278.setPreambleDetect(0x9F)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
sx1278.setPayloadLength(0); // infinite for now...
|
|
||||||
Serial.print("DFM: setting RX frequency to ");
|
|
||||||
Serial.println(frequency);
|
|
||||||
|
|
||||||
int retval = sx1278.setFrequency(frequency);
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
|
|
||||||
// Do this only once in setup in continous mode
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
|
|
||||||
memset((void *)&dfmstate, 0, sizeof(dfmstate));
|
|
||||||
DFM_DBG(Serial.println("Setting SX1278 config for DFM finished\n"); Serial.println());
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define bitpick(value,bitpos) (((value)>>(7-(bitpos)))&0x01)
|
|
||||||
// Input: str: packed data, MSB first
|
|
||||||
void DFM::deinterleave(uint8_t *str, int L, uint8_t *block) {
|
|
||||||
int i, j;
|
|
||||||
for (j = 0; j < B; j++) { // L = 7 (CFG), 13 (DAT1, DAT2)
|
|
||||||
for (i = 0; i < L; i++) {
|
|
||||||
block[B*i+j] = bitpick( str[(L*j+i)/8], (L*j+i)&7 )?0:1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t DFM::bits2val(const uint8_t *bits, int len) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
for (int j = 0; j < len; j++) {
|
|
||||||
val |= (bits[j] << (len-1-j));
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error correction for hamming code
|
|
||||||
// returns 0: ok >0: 1 error was corrected -1: uncorrectable error
|
|
||||||
int DFM::check(uint8_t code[8]) {
|
|
||||||
int i, j;
|
|
||||||
uint32_t synval = 0;
|
|
||||||
uint8_t syndrom[4];
|
|
||||||
int ret=0;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
syndrom[i] = 0;
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
syndrom[i] ^= H[i][j] & code[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synval = bits2val(syndrom, 4);
|
|
||||||
if (synval) {
|
|
||||||
ret = -1;
|
|
||||||
for (j = 0; j < 8; j++) { // 1-bit-error
|
|
||||||
if (synval == He[j]) { // reicht auf databits zu pruefen, d.h.
|
|
||||||
ret = j+1; // (systematischer Code) He[0..3]
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ret = 0;
|
|
||||||
if (ret > 0) code[ret-1] ^= 0x1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended (8,4) Hamming code
|
|
||||||
// Return number of corrected bits, -1 if uncorrectable error
|
|
||||||
int DFM::hamming(uint8_t *ham, int L, uint8_t *sym) {
|
|
||||||
int i, j;
|
|
||||||
int ret = 0; // DFM: length L = 7 or 13
|
|
||||||
for (i = 0; i < L; i++) { // L bytes (4bit data, 4bit parity)
|
|
||||||
if (use_ecc) {
|
|
||||||
int res = check(ham+8*i);
|
|
||||||
if( res<0 ) ret = -1;
|
|
||||||
else if ( ret >= 0 && res > 0 ) ret++;
|
|
||||||
}
|
|
||||||
// systematic Hamming code: copy bits 0..3
|
|
||||||
for (j = 0; j < 4; j++) {
|
|
||||||
sym[4*i+j] = ham[8*i+j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFM::DFM() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFM::printRaw(const char *label, int len, int ret, const uint8_t *data)
|
|
||||||
{
|
|
||||||
Serial.print(label); Serial.print("(");
|
|
||||||
Serial.print(ret);
|
|
||||||
Serial.print("):");
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len/2; i++) {
|
|
||||||
char str[10];
|
|
||||||
snprintf(str, 10, "%02X", data[i]);
|
|
||||||
Serial.print(str);
|
|
||||||
}
|
|
||||||
Serial.print(data[i]&0x0F, HEX);
|
|
||||||
Serial.print(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* typestr[16]={
|
|
||||||
"", "", "", "", "", "", // 00..05
|
|
||||||
"DFM6", // 06 => DFM6
|
|
||||||
"PS15", // 07 => PS15 (untested)
|
|
||||||
"", "",
|
|
||||||
"DFM9", // 0A => DFM9
|
|
||||||
"DF17", // 0B => DFM17?
|
|
||||||
"DF9P", // 0C => DFM9P or DFM17 test
|
|
||||||
"DF17", // 0D => DFM17
|
|
||||||
"", ""
|
|
||||||
};
|
|
||||||
|
|
||||||
void DFM::killid() {
|
|
||||||
SondeData *sd = &(sonde.si()->d);
|
|
||||||
sd->validID = false;
|
|
||||||
*(sd->id) = 0;
|
|
||||||
*(sd->ser) = 0;
|
|
||||||
memset((void *)&dfmstate, 0, sizeof(dfmstate));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DFMIDTHRESHOLD 2
|
|
||||||
/* inspired by oe5dxl's finddnmae in sondeudp.c of dxlaprs */
|
|
||||||
void DFM::finddfname(uint8_t *b)
|
|
||||||
{
|
|
||||||
uint8_t st;
|
|
||||||
uint32_t thres;
|
|
||||||
uint32_t i;
|
|
||||||
uint8_t ix;
|
|
||||||
uint16_t d;
|
|
||||||
SondeData *sd = &(sonde.si()->d);
|
|
||||||
|
|
||||||
st = b[0]; /* frame start byte */
|
|
||||||
ix = b[3]; /* hi/lo part of ser; (LSB due to our bitsToBytes...) */
|
|
||||||
d = (b[1]<<8) + b[2]; /* data byte */
|
|
||||||
/* find highest channel number single frame serial,
|
|
||||||
(2 frame serial will make a single serial too) */
|
|
||||||
if(dfmstate.idcnt0 < DFMIDTHRESHOLD && dfmstate.idcnt1 < DFMIDTHRESHOLD) {
|
|
||||||
uint32_t v = (st<<20) | (d<<4) | ix;
|
|
||||||
if ( st > (dfmstate.lastfrid>>20) ) {
|
|
||||||
dfmstate.lastfrid = v;
|
|
||||||
Serial.print(" MAXCH:"); Serial.print(st);
|
|
||||||
dfmstate.lastfrcnt = 0;
|
|
||||||
} else if ( st == (dfmstate.lastfrid>>20) ) {
|
|
||||||
/* same id found */
|
|
||||||
if (v == dfmstate.lastfrid) {
|
|
||||||
++dfmstate.lastfrcnt;
|
|
||||||
thres = DFMIDTHRESHOLD * 2;
|
|
||||||
/* may be a 2 frame serial so increase safety level */
|
|
||||||
if (ix <= 1) thres *= 2;
|
|
||||||
/* may be not a dfm6 so increase safety level */
|
|
||||||
if ( (st>>4) != 6) thres *= 2;
|
|
||||||
if (dfmstate.lastfrcnt >= thres) {
|
|
||||||
/* id found */
|
|
||||||
if (dfmstate.lastfrcnt == thres) {
|
|
||||||
uint32_t id = ((st&0x0F)<<20) | (d<<4) | ix;
|
|
||||||
uint32_t chkid = id;
|
|
||||||
int i;
|
|
||||||
/* check validity */
|
|
||||||
for(i=0; i<6; i++) {
|
|
||||||
if((chkid&0x0f)>9) { break; /* not ok */ }
|
|
||||||
chkid >>= 4;
|
|
||||||
}
|
|
||||||
if(i==6) {
|
|
||||||
snprintf(sd->id, 10, "D%x ", id);
|
|
||||||
memcpy(sd->ser, sd->id+1, 9);
|
|
||||||
sd->validID = true;
|
|
||||||
sd->subtype = (st>>4)&0x0F;
|
|
||||||
strncpy(sd->typestr, typestr[ (st>>4)&0x0F ], 5);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dfmstate.lastfrcnt = 0;
|
|
||||||
Serial.print(" NOT NUMERIC SERIAL");
|
|
||||||
}
|
|
||||||
//anonym->idtime = osic_time();
|
|
||||||
} else {
|
|
||||||
Serial.print(" MAXCHCNT/SECLVL:");
|
|
||||||
Serial.print(dfmstate.lastfrcnt);
|
|
||||||
Serial.print("/");
|
|
||||||
Serial.print(thres);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dfmstate.lastfrid = v; /* not stable ser */
|
|
||||||
dfmstate.lastfrcnt = 0UL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} /*find highest channel number single frame serial */
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i<dfmstate.nameregtop && dfmstate.start[i]!=st) i++;
|
|
||||||
Serial.printf(" %02x:i=%d,top=%d", st, i, dfmstate.nameregtop);
|
|
||||||
if (i<dfmstate.nameregtop) {
|
|
||||||
if (ix<=1UL && (dfmstate.cnt[2*i+ix]==0 || dfmstate.dat[2*i+ix]==d)) {
|
|
||||||
dfmstate.dat[2*i+ix] = d;
|
|
||||||
if(dfmstate.cnt[2*i+ix] < 255) dfmstate.cnt[2*i+ix]++;
|
|
||||||
Serial.print(" ID:");
|
|
||||||
Serial.print(st, HEX);
|
|
||||||
Serial.print("[");
|
|
||||||
Serial.print(ix);
|
|
||||||
Serial.print("] CNT:");
|
|
||||||
Serial.print(dfmstate.cnt[2*i]);
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(dfmstate.cnt[2*i+1]);
|
|
||||||
Serial.print(",st=");
|
|
||||||
Serial.print(st);
|
|
||||||
Serial.print(",lastfrid=");
|
|
||||||
Serial.print(dfmstate.lastfrid>>20);
|
|
||||||
if( (dfmstate.cnt[2*i]>DFMIDTHRESHOLD && dfmstate.cnt[2*i+1]>DFMIDTHRESHOLD) ||
|
|
||||||
(dfmstate.cnt[2*i]>0 && dfmstate.cnt[2*i+1]>0 && st == (dfmstate.lastfrid>>20) && (st>>4)>6) ) {
|
|
||||||
if(dfmstate.idcnt0 <= 1) {
|
|
||||||
dfmstate.idcnt0 = dfmstate.cnt[2*i];
|
|
||||||
dfmstate.idcnt1 = dfmstate.cnt[2*i+1];
|
|
||||||
dfmstate.nameregok = i;
|
|
||||||
// generate id.....
|
|
||||||
snprintf(sd->id, 10, "D%d", ((dfmstate.dat[2*i]<<16)|dfmstate.dat[2*i+1])%100000000);
|
|
||||||
Serial.print("\nNEW AUTOID:");
|
|
||||||
Serial.println(sd->id);
|
|
||||||
memcpy(sd->ser, sd->id+1, 9);
|
|
||||||
sd->validID = true;
|
|
||||||
sd->subtype = (st>>4)&0x0F;
|
|
||||||
strncpy(sd->typestr, typestr[ (st>>4)&0x0F ], 5);
|
|
||||||
}
|
|
||||||
if(dfmstate.nameregok==i) {
|
|
||||||
Serial.print(" ID OK");
|
|
||||||
// idtime = .... /* TODO */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* data changed so not ser */
|
|
||||||
dfmstate.cnt[2*i] = 0;
|
|
||||||
dfmstate.cnt[2*i+1] = 0;
|
|
||||||
if(dfmstate.nameregok == i) { /* found id wrong */
|
|
||||||
dfmstate.idcnt0 = 0;
|
|
||||||
dfmstate.idcnt1 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ix<=1) { /* add new entry for possible ID */
|
|
||||||
dfmstate.start[dfmstate.nameregtop] = st;
|
|
||||||
dfmstate.cnt[2*dfmstate.nameregtop] = 0;
|
|
||||||
dfmstate.cnt[2*dfmstate.nameregtop+1] = 0;
|
|
||||||
dfmstate.cnt[2*dfmstate.nameregtop+ix] = 1;
|
|
||||||
dfmstate.dat[2*dfmstate.nameregtop+ix] = d;
|
|
||||||
if(dfmstate.nameregtop<49) dfmstate.nameregtop++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static float get_Temp() {
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
if(!si->validID) { // type not yet known, so don't try to decode
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
float f = dfmstate.meas[0],
|
|
||||||
f1 = dfmstate.meas[3],
|
|
||||||
f2 = dfmstate.meas[4];
|
|
||||||
if(si->subtype >= 0x0C) {
|
|
||||||
f = dfmstate.meas[1];
|
|
||||||
f1 = dfmstate.meas[5];
|
|
||||||
f2 = dfmstate.meas[6];
|
|
||||||
}
|
|
||||||
Serial.printf("Meas: %f %f %f\n", f, f1, f2);
|
|
||||||
// as in autorx / dfm
|
|
||||||
float BB0 = 3260.0; // B/Kelvin, fit -55C..+40C
|
|
||||||
float T0 = 25 + 273.15; // t0=25C
|
|
||||||
float R0 = 5.0e3; // R0=R25=5k
|
|
||||||
float Rf = 220e3; // Rf = 220k
|
|
||||||
float g = f2/Rf;
|
|
||||||
float R = (f-f1) / g; // meas[0,3,4] > 0 ?
|
|
||||||
float T = 0; // T/Kelvin
|
|
||||||
if (f*f1*f2 == 0) R = 0;
|
|
||||||
if (R > 0) T = 1/(1/T0 + 1/BB0 * log(R/R0));
|
|
||||||
T = T - 273.15; // Celsius
|
|
||||||
if(T<-100 || T>50) {
|
|
||||||
Serial.printf("Temperature invalid: %f\n", T);
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
return T;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFM::decodeCFG(uint8_t *cfg)
|
|
||||||
{
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
// new ID
|
|
||||||
finddfname(cfg);
|
|
||||||
// get meas
|
|
||||||
uint8_t conf_id = (*cfg)>>4;
|
|
||||||
if(conf_id<=6) {
|
|
||||||
uint32_t val = (cfg[1]<<12) | (cfg[2]<<4) | cfg[3];
|
|
||||||
uint8_t exp = cfg[0] & 0xF;
|
|
||||||
dfmstate.meas[conf_id] = val / (float)(1<<exp);
|
|
||||||
Serial.printf("meas %d is %f (%d,%d)\n", conf_id, dfmstate.meas[conf_id], val, exp);
|
|
||||||
}
|
|
||||||
// get batt
|
|
||||||
if(si->validID && si->subtype>=0x0A) {
|
|
||||||
// otherwise don't try, as we might not have the right type yet...
|
|
||||||
int cid = (si->subtype >= 0x0C) ? 0x7 : 0x5;
|
|
||||||
if(conf_id == cid) {
|
|
||||||
uint16_t val = cfg[1]<<8 | cfg[2];
|
|
||||||
si->batteryVoltage = val / 1000.0;
|
|
||||||
Serial.printf("battery: %f\n", si->batteryVoltage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// not used any more
|
|
||||||
static int bitCount(int x) {
|
|
||||||
int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
|
|
||||||
int m1 = 0xFF;
|
|
||||||
int s4 = (x&m4) + ((x>>1)&m4) + ((x>>2)&m4) + ((x>>3)&m4) + ((x>>4)&m4) + ((x>>5)&m4) + ((x>>6)&m4) + ((x>>7)&m4);
|
|
||||||
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
|
||||||
|
|
||||||
void DFM::decodeDAT(uint8_t *dat)
|
|
||||||
{
|
|
||||||
// TODO: Here we need to work on a shadow copy of SondeData in order to prevent concurrent changes while using data in main loop
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
|
||||||
|
|
||||||
// We handle this case already here, because we need to update dfmstate.datesec before the cycle complete handling
|
|
||||||
if( dat[6]==8 ) {
|
|
||||||
int y = (dat[0]<<4) + (dat[1]>>4);
|
|
||||||
int m = dat[1]&0x0F;
|
|
||||||
int d = dat[2]>>3;
|
|
||||||
int h = ((dat[2]&0x07)<<2) + (dat[3]>>6);
|
|
||||||
int mi = (dat[3]&0x3F);
|
|
||||||
Serial.printf("Date: %04d-%02d-%02d %02d:%02dz ", y, m, d, h, mi);
|
|
||||||
si->sats = dat[4];
|
|
||||||
si->validPos |= 0x40;
|
|
||||||
// convert to unix time
|
|
||||||
int tt = (y-1970)*365 + (y-1969)/4; // days since 1970
|
|
||||||
if(m<=12) { tt += MON[m]; if((y%4)==0 && m>2) tt++; }
|
|
||||||
tt = (tt+d-1)*(60*60*24) + h*3600 + mi*60;
|
|
||||||
// If we get a time stamp much different to the previously received one, kill the ID.
|
|
||||||
// most likely, we have a new sonde now, so wait for the new ID.
|
|
||||||
if(tt-dfmstate.datesec > MAXIDAGE) killid();
|
|
||||||
dfmstate.datesec = tt;
|
|
||||||
dfmstate.good |= 0x100;
|
|
||||||
}
|
|
||||||
else if( dat[6]>8 ) return; // we ignore those...
|
|
||||||
|
|
||||||
/* Here we update data that should be updated only after receiving a "complete" frame (mainly for consistent SondeHub exports)
|
|
||||||
* We do this (a) when there is a DAT8 block and (b) when there is wrap from DAT7 to DAT0, for these fields:
|
|
||||||
* => frame
|
|
||||||
* => vframe (only used for SondeHub as virtual frame number)
|
|
||||||
* => time (calculated with using date and msec)
|
|
||||||
* [assuming that if there is no DAT8, then the date value did not change.]
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( dat[6]==8 || dat[6] < dfmstate.lastdat) { // After DAT8, or after a "warp around"
|
|
||||||
if( dfmstate.good&1 ) si->frame = dfmstate.frame;
|
|
||||||
if( (dfmstate.good&0x102)==0x102 ) {
|
|
||||||
si->time = dfmstate.datesec + dfmstate.msec/1000;
|
|
||||||
// Lets be consistent with autorx: the timestamp uses the msec value truncated to seconds,
|
|
||||||
// whereas the virtual frame number for DFM uses the msec value rounded to full seconds.
|
|
||||||
// Actually, tt is real UTC, and the transformation to GPS seconds lacks adjusting for leap seconds
|
|
||||||
si->vframe = dfmstate.datesec + (dfmstate.msec+500)/1000 - 315964800;
|
|
||||||
}
|
|
||||||
// All fields updated? 1=OK, 2=with errors
|
|
||||||
Serial.printf("Cycle done: good is %x\n", dfmstate.good);
|
|
||||||
si->temperature = get_Temp();
|
|
||||||
Serial.printf("Temp: %f\n", si->temperature);
|
|
||||||
dfmstate.cycledone = ((dfmstate.good&0x11F)==0x11F) ? 1 : 2;
|
|
||||||
dfmstate.good = 0;
|
|
||||||
dfmstate.lastdat = 0;
|
|
||||||
} else {
|
|
||||||
dfmstate.lastdat = dat[6];
|
|
||||||
}
|
|
||||||
dfmstate.good |= (1<<dat[6]);
|
|
||||||
switch(dat[6]) {
|
|
||||||
case 0:
|
|
||||||
Serial.print("Packet counter: "); Serial.print(dat[3]);
|
|
||||||
dfmstate.frame = dat[3];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
int val = (((uint16_t)dat[4])<<8) + (uint16_t)dat[5];
|
|
||||||
Serial.print("UTC-msec: "); Serial.print(val);
|
|
||||||
dfmstate.msec = val;
|
|
||||||
//uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
|
||||||
//si->sats = bitCount(tmp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
float lat, vh;
|
|
||||||
lat = (int32_t)(((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]));
|
|
||||||
vh = ((uint16_t)dat[4]<<8) + dat[5];
|
|
||||||
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
|
||||||
Serial.print(", hor-V: "); Serial.print(vh*0.01);
|
|
||||||
lat = lat*0.0000001;
|
|
||||||
if( lat!=0 && si->lat!=0 && abs(lat-si->lat)>.25 ) killid();
|
|
||||||
si->lat = lat;
|
|
||||||
si->hs = vh*0.01;
|
|
||||||
if(lat!=0 || vh!=0) si->validPos |= 0x11; else si->validPos &= ~0x11;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
float lon, dir;
|
|
||||||
lon = (int32_t)(((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + (uint32_t)dat[3]);
|
|
||||||
dir = ((uint16_t)dat[4]<<8) + dat[5];
|
|
||||||
lon = lon*0.0000001;
|
|
||||||
if( lon!=0 && si->lon!=0 && abs(lon-si->lon)>.25 ) killid();
|
|
||||||
si->lon = lon;
|
|
||||||
si->dir = dir*0.01;
|
|
||||||
Serial.print("GPS-lon: "); Serial.print(si->lon);
|
|
||||||
Serial.print(", dir: "); Serial.print(si->dir);
|
|
||||||
if(lon != 0 || dir != 0) si->validPos |= 0x22; else si->validPos &= ~0x22;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
float alt, vv;
|
|
||||||
alt = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + dat[3];
|
|
||||||
vv = (int16_t)( ((int16_t)dat[4]<<8) | dat[5] );
|
|
||||||
Serial.print("GPS-height: "); Serial.print(alt*0.01);
|
|
||||||
Serial.print(", vv: "); Serial.print(vv*0.01);
|
|
||||||
si->alt = alt*0.01;
|
|
||||||
si->vs = vv*0.01;
|
|
||||||
if(alt!=0 || vv != 0) si->validPos |= 0x0C; else si->validPos &= ~0x0C;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
// handled above
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Serial.print("(?)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DFM::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len*4; i++) {
|
|
||||||
//Serial.print(bits[i]?"1":"0");
|
|
||||||
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
|
||||||
}
|
|
||||||
bytes[(i-1)/8] &= 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int haveNewFrame = 0;
|
|
||||||
|
|
||||||
int DFM::processDFMdata(uint8_t dt) {
|
|
||||||
static uint8_t data[1024];
|
|
||||||
static uint32_t rxdata = 0;
|
|
||||||
static uint8_t rxbitc = 0;
|
|
||||||
static uint8_t rxbyte = 0;
|
|
||||||
static uint8_t rxsearching = 1;
|
|
||||||
static uint8_t rxp;
|
|
||||||
static int rssi=0, fei=0, afc=0;
|
|
||||||
static uint8_t invers = 0;
|
|
||||||
|
|
||||||
for(int i=0; i<8; i++) {
|
|
||||||
uint8_t d = (dt&0x80)?1:0;
|
|
||||||
dt <<= 1;
|
|
||||||
rxdata = (rxdata<<1) | d;
|
|
||||||
if( (rxbitc&1)==0 ) {
|
|
||||||
// "bit1"
|
|
||||||
rxbyte = (rxbyte<<1) | d;
|
|
||||||
} else {
|
|
||||||
// "bit2" ==> 01 or 10 => 1, otherweise => 0
|
|
||||||
// not here: (10=>1, 01=>0)!!! rxbyte = rxbyte ^ d;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
if(rxsearching) {
|
|
||||||
if( rxdata == 0x6566A5AA || rxdata == 0x9A995A55 ) {
|
|
||||||
rxsearching = false;
|
|
||||||
rxbitc = 0;
|
|
||||||
rxp = 0;
|
|
||||||
rxbyte = 0;
|
|
||||||
rssi=sx1278.getRSSI();
|
|
||||||
fei=sx1278.getFEI();
|
|
||||||
afc=sx1278.getAFC();
|
|
||||||
sonde.si()->rssi = rssi;
|
|
||||||
sonde.si()->afc = afc;
|
|
||||||
invers = (rxdata == 0x6566A5AA)?1:0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rxbitc = (rxbitc+1)%16; // 16;
|
|
||||||
if(rxbitc == 0) { // got 8 data bit
|
|
||||||
if(invers) rxbyte=~rxbyte;
|
|
||||||
data[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
|
||||||
if(rxp>=DFM_FRAMELEN) {
|
|
||||||
rxsearching = true;
|
|
||||||
//Serial.println("Got a DFM frame!");
|
|
||||||
Serial.print("[RSSI="); Serial.print(rssi);
|
|
||||||
Serial.print(" FEI="); Serial.print(fei);
|
|
||||||
Serial.print(" AFC="); Serial.print(afc); Serial.print("] ");
|
|
||||||
decodeFrameDFM(data);
|
|
||||||
haveNewFrame = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DFM::receive() {
|
|
||||||
int rxframes = 5; // UP TO 5 frames, stop at type 8 frame
|
|
||||||
|
|
||||||
// tentative continuous RX version...
|
|
||||||
unsigned long t0 = millis();
|
|
||||||
dfmstate.cycledone = 0;
|
|
||||||
while( ( millis() - t0 ) < 1300 ) {
|
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
if ( bitRead(value, 7) ) {
|
|
||||||
Serial.println("FIFO full");
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 4) ) {
|
|
||||||
Serial.println("FIFO overflow");
|
|
||||||
// new: (maybe clear only overflow??) TODO
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 2) == 1 ) {
|
|
||||||
Serial.println("FIFO: payload ready()");
|
|
||||||
// does not make much sence? (from m10): TODO
|
|
||||||
// ??????? sx1278.clearIRQFlags();
|
|
||||||
}
|
|
||||||
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
|
||||||
byte data = sx1278.readRegister(REG_FIFO);
|
|
||||||
processDFMdata(data);
|
|
||||||
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
} else {
|
|
||||||
if(haveNewFrame) {
|
|
||||||
//Serial.printf("DFM::receive(): new frame complete after %ldms\n", millis()-t0);
|
|
||||||
haveNewFrame = 0;
|
|
||||||
rxframes--;
|
|
||||||
// OK: All DAT frames (0/1/2/3/4/8) have been received in the last cycle
|
|
||||||
if(dfmstate.cycledone==1) return RX_OK;
|
|
||||||
if(dfmstate.cycledone>1 || rxframes==0) return RX_ERROR;
|
|
||||||
}
|
|
||||||
delay(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rxframes == 5 ? RX_TIMEOUT : RX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DFM::decodeFrameDFM(uint8_t *data) {
|
|
||||||
deinterleave(data, 7, hamming_conf);
|
|
||||||
deinterleave(data+7, 13, hamming_dat1);
|
|
||||||
deinterleave(data+20, 13, hamming_dat2);
|
|
||||||
|
|
||||||
int ret0 = hamming(hamming_conf, 7, block_conf);
|
|
||||||
int ret1 = hamming(hamming_dat1, 13, block_dat1);
|
|
||||||
int ret2 = hamming(hamming_dat2, 13, block_dat2);
|
|
||||||
//Serial.printf("Hamming returns %d %d %d -- %d\n", ret0, ret1, ret2, ret0|ret1|ret2);
|
|
||||||
|
|
||||||
byte byte_conf[4], byte_dat1[7], byte_dat2[7];
|
|
||||||
bitsToBytes(block_conf, byte_conf, 7);
|
|
||||||
bitsToBytes(block_dat1, byte_dat1, 13);
|
|
||||||
bitsToBytes(block_dat2, byte_dat2, 13);
|
|
||||||
|
|
||||||
printRaw("CFG", 7, ret0, byte_conf);
|
|
||||||
printRaw("DAT", 13, ret1, byte_dat1);
|
|
||||||
printRaw("DAT", 13, ret2, byte_dat2);
|
|
||||||
if (ret0>=0) decodeCFG(byte_conf);
|
|
||||||
if (ret1>=0 && ret1<=4) decodeDAT(byte_dat1);
|
|
||||||
if (ret2>=0 && ret2<=4) decodeDAT(byte_dat2);
|
|
||||||
Serial.println("");
|
|
||||||
// Consistent with autorx: If more than 4 corrected bit errors in DAT block, assume it is possibly corrupt and
|
|
||||||
// don't treat it as a correct frame (ttgo display shows data anyway, but it is not sent to external sites)
|
|
||||||
if(ret1>4 || ret2>4) return RX_ERROR;
|
|
||||||
return (ret0|ret1|ret2)>=0 ? RX_OK : RX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// moved to a single function in Sonde(). This function can be used for additional
|
|
||||||
// processing here, that takes too long for doing in the RX task loop
|
|
||||||
int DFM::waitRXcomplete() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFM dfm = DFM();
|
|
|
@ -1,51 +0,0 @@
|
||||||
|
|
||||||
#include "DecoderBase.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
#define DECODERBASE_DEBUG 1
|
|
||||||
|
|
||||||
#if DECODERBASE_DEBUG
|
|
||||||
#define DBG(x) x
|
|
||||||
#else
|
|
||||||
#define DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int DecoderBase::setup(decoderSetupCfg &setupcfg, uint16_t agcbw, uint16_t rxbw) {
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
DBG(Serial.println("Setting FSK mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setBitrate(setupcfg.bitrate)!=0) {
|
|
||||||
DBG(Serial.println("Setting bitrate FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if DECODERBASE_DEBUG
|
|
||||||
float br = sx1278.getBitrate();
|
|
||||||
Serial.print("Exact bitrate is ");
|
|
||||||
Serial.println(br);
|
|
||||||
#endif
|
|
||||||
if(sx1278.setAFCBandwidth(agcbw)!=0) {
|
|
||||||
DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(rxbw)!=0) {
|
|
||||||
DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sx1278.setRxConf(setupcfg.rx_cfg)!=0) {
|
|
||||||
DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setSyncConf(setupcfg.sync_cfg, setupcfg.sync_len, setupcfg.sync_data)!=0) {
|
|
||||||
DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setPreambleDetect(setupcfg.preamble_cfg)!=0) {
|
|
||||||
DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
|
|
||||||
#ifndef DECODER_BASE_H
|
|
||||||
#define DECODER_BASE_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
#ifndef inttypes_h
|
|
||||||
#include <inttypes.h>
|
|
||||||
#endif
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
typedef struct _decoderSetupCfg {
|
|
||||||
uint16_t bitrate;
|
|
||||||
//uint16_t agcbw;
|
|
||||||
//uint16_t rxbw;
|
|
||||||
uint8_t rx_cfg;
|
|
||||||
uint8_t sync_cfg;
|
|
||||||
uint8_t sync_len;
|
|
||||||
const uint8_t *sync_data;
|
|
||||||
uint8_t preamble_cfg;
|
|
||||||
} decoderSetupCfg;
|
|
||||||
|
|
||||||
/* Generic base class for all sonde decoders */
|
|
||||||
class DecoderBase
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
public:
|
|
||||||
int setup(decoderSetupCfg &setupcfg, uint16_t agcbw, uint16_t rxbw);
|
|
||||||
virtual int setup(float frequency, int type=0) = 0;
|
|
||||||
|
|
||||||
virtual int receive() = 0;
|
|
||||||
virtual int waitRXcomplete() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,652 +0,0 @@
|
||||||
|
|
||||||
/* M10 and M20 decoder functions */
|
|
||||||
|
|
||||||
#include "M10M20.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "rsc.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
#include <SPIFFS.h>
|
|
||||||
|
|
||||||
#define M10M20_DEBUG 1
|
|
||||||
|
|
||||||
#if M10M20_DEBUG
|
|
||||||
#define M10M20_DBG(x) x
|
|
||||||
#else
|
|
||||||
#define M10M20_DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static byte data1[512];
|
|
||||||
static byte *dataptr=data1;
|
|
||||||
|
|
||||||
static uint8_t rxbitc;
|
|
||||||
static uint16_t rxbyte;
|
|
||||||
static int rxp=0;
|
|
||||||
static int haveNewFrame = 0;
|
|
||||||
//static int lastFrame = 0;
|
|
||||||
static int headerDetected = 0;
|
|
||||||
|
|
||||||
|
|
||||||
decoderSetupCfg m10m20SetupCfg = {
|
|
||||||
.bitrate = 9600,
|
|
||||||
//// Disable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
.rx_cfg = 0x00,
|
|
||||||
.sync_cfg = 0x70,
|
|
||||||
.sync_len = 1,
|
|
||||||
.sync_data = (const uint8_t *)"\x66\x66",
|
|
||||||
// Preamble detection off (+ size 1 byte, maximum tolerance; should not matter for "off"?)
|
|
||||||
.preamble_cfg = 0x00 | 0x00 | 0x1F,
|
|
||||||
};
|
|
||||||
|
|
||||||
int M10M20::setup(float frequency, int /*type*/)
|
|
||||||
{
|
|
||||||
M10M20_DBG(Serial.println("Setup sx1278 for M10/M20 sonde"));;
|
|
||||||
if(sx1278.ON()!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// setFSK: switches to FSK standby mode
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting FSK mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Serial.print("M10/M20: setting RX frequency to ");
|
|
||||||
Serial.println(frequency);
|
|
||||||
int res = sx1278.setFrequency(frequency);
|
|
||||||
// Test: maybe fix issue after spectrum display?
|
|
||||||
sx1278.writeRegister(REG_PLL_HOP, 0);
|
|
||||||
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.m10m20.agcbw)!=0) {
|
|
||||||
M10M20_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.m10m20.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.m10m20.rxbw)!=0) {
|
|
||||||
M10M20_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.m10m20.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: Maybe do this conditionally? -- maybe skip if afc if agcbw set to 0 or -1?
|
|
||||||
//// Step 1: Tentative AFC mode
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
// preamble detector + AFC + AGC on
|
|
||||||
// wait for preamble interrupt within 2sec
|
|
||||||
sx1278.setBitrate(4800);
|
|
||||||
// DetectorOn=1, Preamble detector size 01, preamble tol 0x0A (10)
|
|
||||||
sx1278.setPreambleDetect(0x80 | 0x20 | 0x0A);
|
|
||||||
// Manual start RX, Enable Auto-AFC, Auto-AGC, RX Trigger (AGC+AFC)by preamble
|
|
||||||
sx1278.setRxConf(0x20 | 0x10 | 0x08 | 0x06);
|
|
||||||
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
|
||||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
|
||||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// enable RX
|
|
||||||
sx1278.setPayloadLength(0);
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
unsigned long t0 = millis();
|
|
||||||
M10M20_DBG(Serial.printf("M10M20::setup() AFC preamble search start at %ld\n",t0));
|
|
||||||
while( millis() - t0 < 1000 ) {
|
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS1);
|
|
||||||
if(value & 2) {
|
|
||||||
int32_t afc = sx1278.getAFC();
|
|
||||||
int16_t rssi = sx1278.getRSSI();
|
|
||||||
Serial.printf("M10M20::setup: preamble: AFC is %d, RSSI is %.1f\n", afc, rssi/2.0);
|
|
||||||
sonde.sondeList[rxtask.currentSonde].rssi = rssi;
|
|
||||||
sonde.sondeList[rxtask.currentSonde].afc = afc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
if( millis() - t0 >= 1000) {
|
|
||||||
Serial.println("Preamble scan for AFC: TIMEOUT\n");
|
|
||||||
return 1; // no preamble, so we may fail fast....
|
|
||||||
}
|
|
||||||
|
|
||||||
//// Step 2: Real reception
|
|
||||||
if( DecoderBase::setup(m10m20SetupCfg, sonde.config.m10m20.agcbw, sonde.config.m10m20.rxbw)!=0 ) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
// Now all done in DecoderBase::setup
|
|
||||||
// FSK standby mode, seems like otherweise baudrate cannot be changed?
|
|
||||||
sx1278.setFSK();
|
|
||||||
if(sx1278.setBitrate(9600)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting bitrate 9600bit/s FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
M10M20_DBG(Serial.printf("Exact bitrate is %f\n", sx1278.getBitrate()));
|
|
||||||
// Probably not necessary, as this was set before
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.m10m20.agcbw)!=0) {
|
|
||||||
M10M20_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.m10m20.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.m10m20.rxbw)!=0) {
|
|
||||||
M10M20_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.m10m20.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
//if(sx1278.setRxConf(0x1E)!=0) {
|
|
||||||
// Disable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
if(sx1278.setRxConf(0x00)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// version 1, working with continuous RX
|
|
||||||
const char *SYNC="\x66\x66";
|
|
||||||
if(sx1278.setSyncConf(0x70, 1, (const uint8_t *)SYNC)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Preamble detection off (+ size 1 byte, maximum tolerance; should not matter for "off"?)
|
|
||||||
if(sx1278.setPreambleDetect(0x00 | 0x00 | 0x1F)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
|
||||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
|
||||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
|
||||||
M10M20_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable RX
|
|
||||||
sx1278.setPayloadLength(0); // infinite for now...
|
|
||||||
sx1278.setRxConf(0x20);
|
|
||||||
uint16_t afc = sx1278.getRawAFC();
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
delay(50);
|
|
||||||
sx1278.setRawAFC(afc);
|
|
||||||
delay(50);
|
|
||||||
Serial.printf("after RX_MODE: AFC is %d\n", sx1278.getAFC());
|
|
||||||
|
|
||||||
#if M10M20_DEBUG
|
|
||||||
M10M20_DBG(Serial.println("Setting SX1278 config for M10 finished\n"); Serial.println());
|
|
||||||
#endif
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
M10M20::M10M20() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#define M10_FRAMELEN 101
|
|
||||||
#define M10_CRCPOS 99
|
|
||||||
|
|
||||||
#define M20_FRAMELEN 88
|
|
||||||
#define M20_CRCPOSB 22
|
|
||||||
|
|
||||||
void M10M20::printRaw(uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
char buf[3];
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len; i++) {
|
|
||||||
snprintf(buf, 3, "%02X ", data[i]);
|
|
||||||
Serial.print(buf);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t update_checkM10M20(int c, uint8_t b) {
|
|
||||||
int c0, c1, t, t6, t7, s;
|
|
||||||
c1 = c & 0xFF;
|
|
||||||
// B
|
|
||||||
b = (b >> 1) | ((b & 1) << 7);
|
|
||||||
b ^= (b >> 2) & 0xFF;
|
|
||||||
// A1
|
|
||||||
t6 = ( c & 1) ^ ((c >> 2) & 1) ^ ((c >> 4) & 1);
|
|
||||||
t7 = ((c >> 1) & 1) ^ ((c >> 3) & 1) ^ ((c >> 5) & 1);
|
|
||||||
t = (c & 0x3F) | (t6 << 6) | (t7 << 7);
|
|
||||||
// A2
|
|
||||||
s = (c >> 7) & 0xFF;
|
|
||||||
s ^= (s >> 2) & 0xFF;
|
|
||||||
c0 = b ^ t ^ s;
|
|
||||||
return ((c1 << 8) | c0) & 0xFFFF;
|
|
||||||
}
|
|
||||||
static uint16_t crc_M10M20(int len, uint8_t *msg) {
|
|
||||||
uint16_t cs = 0;
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
cs = update_checkM10M20(cs, msg[i]);
|
|
||||||
}
|
|
||||||
return cs;
|
|
||||||
}
|
|
||||||
static bool checkM10M20crc(int crcpos, uint8_t *msg) {
|
|
||||||
uint16_t cs, cs1;
|
|
||||||
cs = crc_M10M20(crcpos, msg);
|
|
||||||
cs1 = (msg[crcpos] << 8) | msg[crcpos+1];
|
|
||||||
return (cs1 == cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef uint32_t SET256[8];
|
|
||||||
static SET256 sondeudp_VARSET = {0x03BBBBF0UL,0x80600000UL,0x06A001A0UL,
|
|
||||||
0x0000001CUL,0x00000000UL,0x00000000UL,0x00000000UL,
|
|
||||||
0x00000000UL};
|
|
||||||
// VARSET=SET256{4..9,11..13,15..17,19..21,23..25,53..54,63,69,71,72,85,87,89,90,98..100};
|
|
||||||
static SET256 sondeudp_VARSETM20 = {0xF3E27F54UL,0x0000000FUL,0x00000030UL,
|
|
||||||
0x00000000UL, 0x00444C39UL, 0x53445A00UL, 0x00000000UL,
|
|
||||||
0x00000000UL};
|
|
||||||
// VARSET=SET256{2,4,6,8..10,11..14,17,21..25,28..35,68,69}; (* known as variable *)
|
|
||||||
|
|
||||||
static uint8_t fixcnt[M10_FRAMELEN];
|
|
||||||
static uint8_t fixbytes[M10_FRAMELEN];
|
|
||||||
|
|
||||||
static int32_t getint32(uint8_t *data) {
|
|
||||||
return (int32_t)( data[3]|(data[2]<<8)|(data[1]<<16)|(data[0]<<24) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t getint24(uint8_t *data) {
|
|
||||||
return (int32_t)(data[2]|(data[1]<<8)|(data[0]<<16) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t getint24_r(uint8_t *data) {
|
|
||||||
return (int32_t)(data[0]|(data[1]<<8)|(data[2]<<16) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int16_t getint16(uint8_t *data) {
|
|
||||||
return (int16_t)(data[1]|((uint16_t)data[0]<<8));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int16_t getint16_r(uint8_t *data) {
|
|
||||||
return (int16_t)(((uint16_t)data[1]<<8) |data[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char dez(uint8_t nr) {
|
|
||||||
nr = nr%10;
|
|
||||||
return '0'+nr;
|
|
||||||
}
|
|
||||||
static char hex(uint8_t nr) {
|
|
||||||
nr = nr&0x0f;
|
|
||||||
if(nr<10) return '0'+nr;
|
|
||||||
else return 'A'+nr-10;
|
|
||||||
}
|
|
||||||
const static float DEGMUL = 1.0/0xB60B60;
|
|
||||||
|
|
||||||
#define VMUL 0.005
|
|
||||||
#define VMUL_M20 0.01
|
|
||||||
#ifndef PI
|
|
||||||
#define PI (3.1415926535897932384626433832795)
|
|
||||||
#endif
|
|
||||||
#define RAD (PI/180)
|
|
||||||
|
|
||||||
|
|
||||||
// ret: 1=frame ok; 2=frame with errors; 0=ignored frame (m10dop-alternativ)
|
|
||||||
int M10M20::decodeframeM10(uint8_t *data) {
|
|
||||||
int repairstep = 16;
|
|
||||||
int repl = 0;
|
|
||||||
bool crcok;
|
|
||||||
// error correction, inspired by oe5dxl's sondeudp
|
|
||||||
do {
|
|
||||||
crcok = checkM10M20crc(M10_CRCPOS, data);
|
|
||||||
if(crcok || repairstep==0) break;
|
|
||||||
repl = 0;
|
|
||||||
for(int i=0; i<M10_CRCPOS; i++) {
|
|
||||||
if( ((sondeudp_VARSET[i/32]&(1<<(i%32))) == 0) && (fixcnt[i]>=repairstep) ) {
|
|
||||||
repl++;
|
|
||||||
data[i] = fixbytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
repairstep >>= 1;
|
|
||||||
} while(true);
|
|
||||||
if(crcok) {
|
|
||||||
for(int i=0; i<M10_CRCPOS; i++) {
|
|
||||||
if(fixbytes[i]==data[i] &&fixcnt[i]<255) fixcnt[i]++;
|
|
||||||
else { fixcnt[i]=0; fixbytes[i]=data[i]; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
|
||||||
Serial.printf(" repair: %d/%d\n", repl, repairstep);
|
|
||||||
if(!crcok) return 2;
|
|
||||||
|
|
||||||
if(data[1]==0x9F && data[2]==0x20) {
|
|
||||||
Serial.println("Decoding...");
|
|
||||||
//SondeInfo *si = sonde.si();
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
|
|
||||||
// Its a M10
|
|
||||||
// getid...
|
|
||||||
char ids[12];
|
|
||||||
ids[0] = 'M';
|
|
||||||
ids[1] = 'E';
|
|
||||||
ids[2] = hex(data[95]/16);
|
|
||||||
ids[3] = hex(data[95]);
|
|
||||||
ids[4] = hex(data[93]);
|
|
||||||
uint32_t id = data[96] + data[97]*256;
|
|
||||||
ids[5] = hex(id/4096);
|
|
||||||
ids[6] = hex(id/256);
|
|
||||||
ids[7] = hex(id/16);
|
|
||||||
ids[8] = hex(id);
|
|
||||||
ids[9] = 0;
|
|
||||||
strncpy(si->id, ids, 10);
|
|
||||||
ids[0] = hex(data[95]/16);
|
|
||||||
ids[1] = dez((data[95]&0x0f)/10);
|
|
||||||
ids[2] = dez((data[95]&0x0f));
|
|
||||||
ids[3] = '-';
|
|
||||||
ids[4] = dez(data[93]);
|
|
||||||
ids[5] = '-';
|
|
||||||
ids[6] = dez(id>>13);
|
|
||||||
id &= 0x1fff;
|
|
||||||
ids[7] = dez(id/1000);
|
|
||||||
ids[8] = dez((id/100)%10);
|
|
||||||
ids[9] = dez((id/10)%10);
|
|
||||||
ids[10] = dez(id%10);
|
|
||||||
ids[11] = 0;
|
|
||||||
strncpy(si->ser, ids, 12);
|
|
||||||
si->validID = true;
|
|
||||||
Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id);
|
|
||||||
// ID printed on sonde is ...-.-abbbb, with a=id>>13, bbbb=id&0x1fff in decimal
|
|
||||||
// position data
|
|
||||||
si->lat = getint32(data+14) * DEGMUL;
|
|
||||||
si->lon = getint32(data+18) * DEGMUL;
|
|
||||||
si->alt = getint32(data+22) * 0.001;
|
|
||||||
float ve = getint16(data+4)*VMUL;
|
|
||||||
float vn = getint16(data+6)*VMUL;
|
|
||||||
si->vs = getint16(data+8) * VMUL;
|
|
||||||
si->hs = sqrt(ve*ve+vn*vn);
|
|
||||||
si->sats = data[30];
|
|
||||||
float dir = atan2(ve, vn)*(1.0/RAD);
|
|
||||||
if(dir<0) dir+=360;
|
|
||||||
si->dir = dir;
|
|
||||||
si->validPos = 0x3f;
|
|
||||||
// m10 temp
|
|
||||||
float T = NAN;
|
|
||||||
{
|
|
||||||
const float p0 = 1.07303516e-03, p1 = 2.41296733e-04, p2 = 2.26744154e-06, p3 = 6.52855181e-08;
|
|
||||||
const float Rs[3] = { 12.1e3 , 36.5e3 , 475.0e3 };
|
|
||||||
const float Rp[3] = { 1e20 , 330.0e3 , 2000.0e3 };
|
|
||||||
uint8_t sct = data[62];
|
|
||||||
float rt = getint16_r(data+63) & (0xFFF);
|
|
||||||
if(rt!=0 && sct<3) {
|
|
||||||
rt = (4095-rt)/rt - (Rs[sct]/Rp[sct]);
|
|
||||||
if(rt>0) {
|
|
||||||
rt = Rs[sct] / rt;
|
|
||||||
if(rt>0) {
|
|
||||||
rt = log(rt);
|
|
||||||
rt = 1/( p0 + p1*rt + p2*rt*rt + p3*rt*rt*rt ) - 273.15;
|
|
||||||
if(rt>-99 && rt<50) { T = rt; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
si->temperature = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// m10 battery
|
|
||||||
uint16_t batADC = (uint16_t)getint16_r(data+0x45);
|
|
||||||
si->batteryVoltage = 2.709 * batADC * 2.5/1023.0;
|
|
||||||
|
|
||||||
// m10 humidity
|
|
||||||
{
|
|
||||||
float cRHc55 = ((float)(uint32_t)getint24_r(data+0x35)) / (uint32_t)getint24_r(data+0x32);
|
|
||||||
float TH = -273.15;
|
|
||||||
const float huRs = 22.1e3;
|
|
||||||
const float p0 = 4.42606809e-03, p1 = -6.58184309e-04, p2 = 8.95735557e-05, p3 = -2.84347503e-06;
|
|
||||||
float R = huRs / ( (4095.0/getint16_r(data+0x59)) - 1 );
|
|
||||||
if(R>0) TH += 1/( p0 + p1*log(R) + p2*log(R)*log(R) + p3*log(R)*log(R)*log(R) );
|
|
||||||
//float Tc = T;
|
|
||||||
float rh = (cRHc55-0.8955)/0.002;
|
|
||||||
const float T0=0.0, T1=-30.0;
|
|
||||||
//float T = Tc;
|
|
||||||
if(T<T0) rh += T0 - T/5.5;
|
|
||||||
if(T<T1) rh *= 1.0 + (T1-T)/75.0;
|
|
||||||
if(rh<0.0) rh=0.0;
|
|
||||||
if(rh>100.0) rh=100.0;
|
|
||||||
si->relativeHumidity = rh;
|
|
||||||
}
|
|
||||||
Serial.printf("hum: %.2f batt: %.2f\n", si->relativeHumidity, si->batteryVoltage);
|
|
||||||
|
|
||||||
uint32_t gpstime = getint32(data+10);
|
|
||||||
uint16_t gpsweek = getint16(data+32);
|
|
||||||
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
|
||||||
// one week = 7*24*60*60 = 604800 seconds
|
|
||||||
// unix epoch starts jan 1st 1970 0:00
|
|
||||||
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
|
||||||
// subtracting 86400 yields 315878400UL
|
|
||||||
si->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
|
||||||
// consistent with autorx, vframe is based on GPS time without the -18 seconds adjustment
|
|
||||||
// for the GPS time / UTC time difference (included in 86382 above)
|
|
||||||
si->vframe = si->time - 315964800 + 18;
|
|
||||||
si->validTime = true;
|
|
||||||
} else {
|
|
||||||
Serial.printf("data is %02x %02x %02x\n", data[0], data[1], data[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t rxdata;
|
|
||||||
static bool rxsearching=true;
|
|
||||||
static bool isM20=false;
|
|
||||||
|
|
||||||
// search for
|
|
||||||
// //101001100110011010011010011001100110100110101010100110101001
|
|
||||||
// //1010011001100110100110100110 0110.0110 1001.1010 1010.1001 1010.1001 => 0x669AA9A9
|
|
||||||
void M10M20::processM10data(uint8_t dt)
|
|
||||||
{
|
|
||||||
for(int i=0; i<8; i++) {
|
|
||||||
uint8_t d = (dt&0x80)?1:0;
|
|
||||||
dt <<= 1;
|
|
||||||
rxdata = (rxdata<<1) | d;
|
|
||||||
if( (rxbitc&1)==0 ) {
|
|
||||||
// "bit1"
|
|
||||||
rxbyte = (rxbyte<<1) | d;
|
|
||||||
} else {
|
|
||||||
// "bit2" ==> 01 or 10 => 1, otherweise => 0
|
|
||||||
rxbyte = rxbyte ^ d;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
if(rxsearching) {
|
|
||||||
if( rxdata == 0xcccca64c || rxdata == 0x333359b3 ) {
|
|
||||||
rxsearching = false;
|
|
||||||
rxbitc = 0;
|
|
||||||
rxp = 0;
|
|
||||||
isM20 = false;
|
|
||||||
headerDetected = 1;
|
|
||||||
#if 1
|
|
||||||
int rssi=sx1278.getRSSI();
|
|
||||||
int fei=sx1278.getFEI();
|
|
||||||
int afc=sx1278.getAFC();
|
|
||||||
Serial.print("SYNC!!! Test: RSSI="); Serial.print(rssi);
|
|
||||||
Serial.print(" FEI="); Serial.print(fei);
|
|
||||||
Serial.print(" AFC="); Serial.println(afc);
|
|
||||||
sonde.si()->rssi = rssi;
|
|
||||||
sonde.si()->afc = afc;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rxbitc = (rxbitc+1)%16; // 16;
|
|
||||||
if(rxbitc == 0) { // got 8 data bit
|
|
||||||
//Serial.printf("%03x ",rxbyte);
|
|
||||||
dataptr[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
|
||||||
// detect type of sonde:
|
|
||||||
// 64 9F 20 => M10
|
|
||||||
// 64 49 0x => M10 (?) -- not used here
|
|
||||||
// 45 20 7x => M20
|
|
||||||
if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
|
||||||
if(isM20) {
|
|
||||||
memcpy(sonde.si()->d.typestr, "M20 ", 5);
|
|
||||||
sonde.si()->d.subtype = 2;
|
|
||||||
if(rxp>=M20_FRAMELEN) {
|
|
||||||
rxsearching = true;
|
|
||||||
haveNewFrame = decodeframeM20(dataptr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
memcpy(sonde.si()->d.typestr, "M10 ", 5);
|
|
||||||
sonde.si()->d.subtype = 1;
|
|
||||||
if(rxp>=M10_FRAMELEN) {
|
|
||||||
rxsearching = true;
|
|
||||||
haveNewFrame = decodeframeM10(dataptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int M10M20::receive() {
|
|
||||||
unsigned long t0 = millis();
|
|
||||||
Serial.printf("M10M20::receive() start at %ld\n",t0);
|
|
||||||
while( millis() - t0 < 1100 ) {
|
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
if ( bitRead(value, 7) ) {
|
|
||||||
Serial.println("FIFO full");
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 4) ) {
|
|
||||||
Serial.println("FIFO overflow");
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 2) == 1 ) {
|
|
||||||
Serial.println("FIFO: ready()");
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
}
|
|
||||||
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
|
||||||
byte data = sx1278.readRegister(REG_FIFO);
|
|
||||||
//Serial.printf("%02x:",data);
|
|
||||||
processM10data(data);
|
|
||||||
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
} else {
|
|
||||||
if(headerDetected) {
|
|
||||||
t0 = millis(); // restart timer... don't time out if header detected...
|
|
||||||
headerDetected = 0;
|
|
||||||
}
|
|
||||||
if(haveNewFrame) {
|
|
||||||
Serial.printf("M10M20::receive(): new frame complete after %ldms\n", millis()-t0);
|
|
||||||
printRaw(dataptr, M10_FRAMELEN);
|
|
||||||
int retval = haveNewFrame==1 ? RX_OK: RX_ERROR;
|
|
||||||
haveNewFrame = 0;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
delay(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int32_t afc = sx1278.getAFC();
|
|
||||||
int16_t rssi = sx1278.getRSSI();
|
|
||||||
Serial.printf("receive: AFC is %d, RSSI is %.1f\n", afc, rssi/2.0);
|
|
||||||
Serial.printf("M10M20::receive() timed out\n");
|
|
||||||
return RX_TIMEOUT; // TODO RX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define M10MAXLEN (240)
|
|
||||||
|
|
||||||
int M10M20::waitRXcomplete() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ret: 1=frame ok; 2=frame with errors; 0=ignored frame (m20dop-alternativ)
|
|
||||||
int M10M20::decodeframeM20(uint8_t *data) {
|
|
||||||
int repairstep = 16;
|
|
||||||
int frl;
|
|
||||||
int repl = 0;
|
|
||||||
bool crcok = false;
|
|
||||||
bool crcbok = false;
|
|
||||||
//SondeInfo *si = sonde.si();
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
// error correction, inspired by oe5dxl's sondeudp
|
|
||||||
// check first block
|
|
||||||
uint8_t s[200];
|
|
||||||
s[0] = 0x16;
|
|
||||||
for(int i=1; i<=M20_CRCPOSB-1; i++) { s[i] = data[i+1]; }
|
|
||||||
crcbok = (crc_M10M20(M20_CRCPOSB-1, s) ==
|
|
||||||
((data[M20_CRCPOSB] << 8) | data[M20_CRCPOSB+1]));
|
|
||||||
|
|
||||||
frl = data[0] + 1; // frame len? (0x45+1 => 70)
|
|
||||||
if(frl>M20_FRAMELEN) { frl = M20_FRAMELEN; }
|
|
||||||
do {
|
|
||||||
crcok = checkM10M20crc(frl-2, data);
|
|
||||||
if(crcok || repairstep == 0) break;
|
|
||||||
repl = 0;
|
|
||||||
for(int i=crcbok?M20_CRCPOSB+2:0; i<frl-2; i++) {
|
|
||||||
if( ((sondeudp_VARSETM20[i/32]&(1<<(i%32))) == 0) && (fixcnt[i]>=repairstep) ) {
|
|
||||||
repl++;
|
|
||||||
data[i] = fixbytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
repairstep >>= 1;
|
|
||||||
} while(true);
|
|
||||||
if(crcbok) {
|
|
||||||
int oklen = crcok ? frl-2 : 21;
|
|
||||||
for(int i=0; i<oklen; i++) {
|
|
||||||
if(fixbytes[i]==data[i]) { if(fixcnt[i]<255) fixcnt[i]++; }
|
|
||||||
else { fixcnt[i]=0; fixbytes[i]=data[i]; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
|
||||||
Serial.printf(" repair: %d/%d\n", repl, repairstep);
|
|
||||||
if(!crcok) return 2;
|
|
||||||
|
|
||||||
Serial.println("Decoding...");
|
|
||||||
// Its a M20
|
|
||||||
// getid...
|
|
||||||
// TODO: Adjust ID calculation and serial number reconstruction
|
|
||||||
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};
|
|
||||||
|
|
||||||
ids[0] = 'M';
|
|
||||||
ids[1] = 'E';
|
|
||||||
uint32_t id = data[18]; // getint16(data+18);
|
|
||||||
ids[2] = hex(id/16);
|
|
||||||
ids[3] = hex(id);
|
|
||||||
//
|
|
||||||
id = getint16_r(data+19)/4;
|
|
||||||
ids[4] = (char)((id/10000)%10+48);
|
|
||||||
ids[5] = (char)((id/1000)%10+48);
|
|
||||||
ids[6] = (char)((id/100)%10+48);
|
|
||||||
ids[7] = (char)((id/10)%10+48);
|
|
||||||
ids[8] = (char)(id%10+48);
|
|
||||||
ids[9] = 0;
|
|
||||||
strncpy(si->id, ids, 10);
|
|
||||||
// Serial: AAB-C-DDEEE
|
|
||||||
char *ser = si->ser;
|
|
||||||
uint8_t tmp = data[18] & 0x7F;
|
|
||||||
ser[0] = (tmp/12) + '0';
|
|
||||||
ser[1] = ((tmp%12 + 1) / 10 ) + '0';
|
|
||||||
ser[2] = ((tmp%12 + 1) % 10 ) + '0';
|
|
||||||
ser[3] = '-';
|
|
||||||
ser[4] = ((data[19]&0x03)<<1) + (data[18]/128) + 1 + '0';
|
|
||||||
ser[5] = '-';
|
|
||||||
ser[6] = ids[4];
|
|
||||||
ser[7] = ids[5];
|
|
||||||
ser[8] = ids[6];
|
|
||||||
ser[9] = ids[7];
|
|
||||||
ser[10] = ids[8];
|
|
||||||
ser[11] = 0;
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
if(crcok) {
|
|
||||||
si->validID = true;
|
|
||||||
//Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id);
|
|
||||||
// ID printed on sonde is ...-.-abbbb, with a=id>>13, bbbb=id&0x1fff in decimal
|
|
||||||
// position data
|
|
||||||
// 0x1C 4 byte
|
|
||||||
si->lat = getint32(data+28) * 1e-6;
|
|
||||||
//0x20 4 byte
|
|
||||||
si->lon = getint32(data+32) * 1e-6;
|
|
||||||
//0x08 3 byte
|
|
||||||
si->alt = getint24(data+8) * VMUL_M20;
|
|
||||||
//0x0B 2 byte
|
|
||||||
//VMUL_M20 specific
|
|
||||||
float ve = getint16(data+11)*VMUL_M20;
|
|
||||||
//0x0D 2 byte
|
|
||||||
float vn = getint16(data+13)*VMUL_M20;
|
|
||||||
//0x18 2 byte
|
|
||||||
si->vs = getint16(data+24) * VMUL_M20;
|
|
||||||
si->hs = sqrt(ve*ve+vn*vn);
|
|
||||||
float dir = atan2(ve, vn)*(1.0/RAD);
|
|
||||||
if(dir<0) dir+=360;
|
|
||||||
si->dir = dir;
|
|
||||||
si->validPos = 0x3f;
|
|
||||||
|
|
||||||
//0x0F 3 byte
|
|
||||||
uint32_t tow = getint24(data+15);
|
|
||||||
uint16_t week = getint16(data+26);
|
|
||||||
si->time = (tow+week*604800+315964800)-18;
|
|
||||||
si->vframe =si->time - 315964800;
|
|
||||||
|
|
||||||
si->validTime = true;
|
|
||||||
}
|
|
||||||
return crcok?1:2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
M10M20 m10m20 = M10M20();
|
|
|
@ -1,559 +0,0 @@
|
||||||
|
|
||||||
/* MP3H decoder functions */
|
|
||||||
|
|
||||||
#include "MP3H.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "rsc.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
#include <SPIFFS.h>
|
|
||||||
|
|
||||||
#define MP3H_DEBUG 1
|
|
||||||
|
|
||||||
#if MP3H_DEBUG
|
|
||||||
#define MP3H_DBG(x) x
|
|
||||||
#else
|
|
||||||
#define MP3H_DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct st_mp3hstate {
|
|
||||||
uint32_t id1, id2;
|
|
||||||
uint8_t idok;
|
|
||||||
uint32_t gpsdate;
|
|
||||||
uint32_t gpsdatetime;
|
|
||||||
bool dateok;
|
|
||||||
} mp3hstate;
|
|
||||||
|
|
||||||
static byte data1[512];
|
|
||||||
static byte *dataptr=data1;
|
|
||||||
|
|
||||||
static uint8_t rxbitc;
|
|
||||||
static uint16_t rxbyte;
|
|
||||||
static int rxp=0;
|
|
||||||
static int haveNewFrame = 0;
|
|
||||||
//static int lastFrame = 0;
|
|
||||||
static int headerDetected = 0;
|
|
||||||
|
|
||||||
extern uint16_t MON[];
|
|
||||||
|
|
||||||
decoderSetupCfg mp3hSetupCfg = {
|
|
||||||
.bitrate = 2400,
|
|
||||||
.rx_cfg = 0x00,
|
|
||||||
.sync_cfg = 0x70,
|
|
||||||
.sync_len = 1,
|
|
||||||
.sync_data = (const uint8_t *)"\x66\x66",
|
|
||||||
.preamble_cfg = 0x00 | 0x00 | 0x1F
|
|
||||||
};
|
|
||||||
|
|
||||||
int MP3H::setup(float frequency, int /*type*/)
|
|
||||||
{
|
|
||||||
MP3H_DBG(Serial.println("Setup sx1278 for MP3H sonde"));;
|
|
||||||
if(sx1278.ON()!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// setFSK: switches to FSK standby mode
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting FSK mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Serial.print("MP3H: setting RX frequency to ");
|
|
||||||
Serial.println(frequency);
|
|
||||||
int res = sx1278.setFrequency(frequency);
|
|
||||||
// Test: maybe fix issue after spectrum display?
|
|
||||||
sx1278.writeRegister(REG_PLL_HOP, 0);
|
|
||||||
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.mp3h.agcbw)!=0) {
|
|
||||||
MP3H_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.mp3h.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.mp3h.rxbw)!=0) {
|
|
||||||
MP3H_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.mp3h.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// Step 2: Real reception
|
|
||||||
if(DecoderBase::setup(mp3hSetupCfg, sonde.config.mp3h.agcbw, sonde.config.mp3h.rxbw)!=0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
// Now all done in Decoderbase
|
|
||||||
// FSK standby mode, seems like otherweise baudrate cannot be changed?
|
|
||||||
sx1278.setFSK();
|
|
||||||
if(sx1278.setBitrate(2400)!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting bitrate 2400bit/s FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
MP3H_DBG(Serial.printf("Exact bitrate is %f\n", sx1278.getBitrate()));
|
|
||||||
// Probably not necessary, as this was set before
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.mp3h.agcbw)!=0) {
|
|
||||||
MP3H_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.mp3h.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.mp3h.rxbw)!=0) {
|
|
||||||
MP3H_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.mp3h.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
//if(sx1278.setRxConf(0x1E)!=0) {
|
|
||||||
// Disable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
if(sx1278.setRxConf(0x00)!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// version 1, working with continuous RX
|
|
||||||
const char *SYNC="\x66\x66";
|
|
||||||
if(sx1278.setSyncConf(0x70, 1, (const uint8_t *)SYNC)!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Preamble detection off (+ size 1 byte, maximum tolerance; should not matter for "off"?)
|
|
||||||
if(sx1278.setPreambleDetect(0x00 | 0x00 | 0x1F)!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
|
||||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
|
||||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
|
||||||
MP3H_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable RX
|
|
||||||
sx1278.setPayloadLength(0); // infinite for now...
|
|
||||||
//sx1278.setRxConf(0x20);
|
|
||||||
uint16_t afc = sx1278.getRawAFC();
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
delay(50);
|
|
||||||
sx1278.setRawAFC(afc);
|
|
||||||
delay(50);
|
|
||||||
Serial.printf("after RX_MODE: AFC is %d\n", sx1278.getAFC());
|
|
||||||
|
|
||||||
memset((void *)&mp3hstate, 0, sizeof(mp3hstate));
|
|
||||||
#if MP3H_DEBUG
|
|
||||||
MP3H_DBG(Serial.println("Setting SX1278 config for MP3H finished\n"); Serial.println());
|
|
||||||
#endif
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MP3H::MP3H() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MP3H_FRAMELEN 49
|
|
||||||
|
|
||||||
// offsets from zilog
|
|
||||||
// https://github.com/rs1729/RS/blob/master/demod/mod/mp3h1mod.c
|
|
||||||
#define OFS -3
|
|
||||||
#define pos_CNT1 (OFS+ 3) // 1 nibble (0x80..0x8F ?)
|
|
||||||
#define pos_TIME (OFS+ 4) // 3*1 byte
|
|
||||||
#define pos_GPSecefX (OFS+ 8) // 4 byte
|
|
||||||
#define pos_GPSecefY (OFS+12) // 4 byte
|
|
||||||
#define pos_GPSecefZ (OFS+16) // 4 byte
|
|
||||||
#define pos_GPSecefV (OFS+20) // 3*2 byte
|
|
||||||
#define pos_GPSnSats (OFS+26) // 1 byte (num Sats ?)
|
|
||||||
#define pos_PTU1 (OFS+35) // 4 byte
|
|
||||||
#define pos_PTU2 (OFS+39) // 4 byte
|
|
||||||
#define pos_CNT2 (OFS+43) // 1 byte (0x01..0x10 ?)
|
|
||||||
#define pos_CFG (OFS+44) // 2/4 byte
|
|
||||||
#define pos_CRC (OFS+48) // 2 byte
|
|
||||||
|
|
||||||
|
|
||||||
#define crc16poly 0xA001
|
|
||||||
static bool checkMP3CRC(uint8_t *data)
|
|
||||||
{
|
|
||||||
int start = pos_CNT1;
|
|
||||||
int len = 45;
|
|
||||||
uint16_t rem = 0xffff;
|
|
||||||
for(int i=0; i<len; i++) {
|
|
||||||
rem ^= data[start+i];
|
|
||||||
for(int j=0; j<8; j++) {
|
|
||||||
if(rem&0x1) rem = (rem>>1) ^ crc16poly;
|
|
||||||
else rem = rem>>1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint16_t crcdat = data[pos_CRC] | (data[pos_CRC+1]<<8);
|
|
||||||
return rem == crcdat ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MP3H::printRaw(uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
char buf[3];
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len; i++) {
|
|
||||||
snprintf(buf, 3, "%02X ", data[i]);
|
|
||||||
Serial.print(buf);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PI
|
|
||||||
#define PI (3.1415926535897932384626433832795)
|
|
||||||
#endif
|
|
||||||
#define RAD (PI/180)
|
|
||||||
#define DEG (180/PI)
|
|
||||||
|
|
||||||
static uint32_t u4(uint8_t *d)
|
|
||||||
{
|
|
||||||
return d[0] | (d[1]<<8) | (d[2]<<16) | (d[3]<<24);
|
|
||||||
}
|
|
||||||
#define i4(d) ((int32_t)u4(d))
|
|
||||||
|
|
||||||
static uint16_t u2(uint8_t *d)
|
|
||||||
{
|
|
||||||
return d[0] | (d[1]<<8);
|
|
||||||
}
|
|
||||||
#define i2(d) ((int16_t)u2(d))
|
|
||||||
|
|
||||||
|
|
||||||
// defined in RS41.cpp
|
|
||||||
extern void wgs84r(double x, double y, double z, double * lat, double * long0, double * heig);
|
|
||||||
extern double atang2(double x, double y);
|
|
||||||
|
|
||||||
|
|
||||||
void calcgps(uint8_t *buf) {
|
|
||||||
//SondeInfo *si = sonde.si();
|
|
||||||
SondeData *si =&(sonde.si()->d);
|
|
||||||
double wx = i4(buf+pos_GPSecefX) * 0.01;
|
|
||||||
double wy = i4(buf+pos_GPSecefY) * 0.01;
|
|
||||||
double wz = i4(buf+pos_GPSecefZ) * 0.01;
|
|
||||||
double vx = i2(buf+pos_GPSecefV) * 0.01;
|
|
||||||
double vy = i2(buf+pos_GPSecefV+2) * 0.01;
|
|
||||||
double vz = i2(buf+pos_GPSecefV+4) * 0.01;
|
|
||||||
if(wx==0 && wy==0 && wz==0) { if(si->validPos&0x7f) { si->validPos |= 0x80; } return; }
|
|
||||||
// wgs84r
|
|
||||||
double lat, lng, alt;
|
|
||||||
wgs84r(wx, wy, wz, &lat, &lng, &alt);
|
|
||||||
if(alt<-1000 || alt>80000) { if(si->validPos&0x7f) { si->validPos |= 0x80; } return; }
|
|
||||||
si->lat = (float)(lat*DEG);
|
|
||||||
si->lon = (float)(lng*DEG);
|
|
||||||
si->alt = alt;
|
|
||||||
// speeddir
|
|
||||||
double sinlat = sin(lat);
|
|
||||||
double coslat = cos(lat);
|
|
||||||
double sinlng = sin(lng);
|
|
||||||
double coslng = cos(lng);
|
|
||||||
double vn = -vx*sinlat*coslng - vy*sinlat*sinlng + vz*coslat;
|
|
||||||
double ve = -vx*sinlng + vy*coslng;
|
|
||||||
double clb = vx*coslat*coslng + vy*coslat*sinlng + vz*sinlat;
|
|
||||||
double dir = atang2(vn, ve)/RAD;
|
|
||||||
if(dir<0.0) dir+=360.0;
|
|
||||||
si->dir = dir;
|
|
||||||
si->vs = clb;
|
|
||||||
si->hs = sqrt(vn*vn + ve*ve);
|
|
||||||
si->sats = buf[pos_GPSnSats];
|
|
||||||
|
|
||||||
Serial.printf("Pos: %f %f alt %f dir %f vs %f hs %f sats %d\n", si->lat, si->lon, si->alt, si->dir, si->vs, si->hs, si->sats);
|
|
||||||
si->validPos = 0x7f;
|
|
||||||
}
|
|
||||||
static uint32_t getgpstime(uint8_t *buf) {
|
|
||||||
return buf[pos_TIME] * 60*60 + buf[pos_TIME+1] * 60 + buf[pos_TIME+2];
|
|
||||||
}
|
|
||||||
// unix time stamp from date and time info in frame.
|
|
||||||
static void getmp3htime(uint8_t *buf) {
|
|
||||||
//SondeInfo *si = sonde.si();
|
|
||||||
SondeData *si =&(sonde.si()->d);
|
|
||||||
|
|
||||||
// gpsdate from CFG frame 15 (0 if not yet received)
|
|
||||||
uint32_t gpsdate = mp3hstate.gpsdate;
|
|
||||||
uint32_t gpstime = getgpstime(buf);
|
|
||||||
int tt = 0;
|
|
||||||
if(gpsdate) {
|
|
||||||
uint16_t year = (gpsdate%100)+2000;
|
|
||||||
gpsdate /= 100;
|
|
||||||
uint8_t month = gpsdate%100;
|
|
||||||
gpsdate /= 100;
|
|
||||||
uint8_t day = gpsdate % 100;
|
|
||||||
// year-month-day to unix time
|
|
||||||
tt = (year-1970)*365 + (year-1969)/4; // days since 1970
|
|
||||||
if(month<=12) { tt += MON[month]; if((year%4)==0 && month>2) tt++; }
|
|
||||||
tt = (tt+day-1)*(60*60*24);
|
|
||||||
if(gpstime < mp3hstate.gpsdatetime) tt += 60*60*24; // time wrapped since last date tx
|
|
||||||
Serial.printf("date: %04d-%02d-%02d t%d ", year, month, day, gpstime);
|
|
||||||
}
|
|
||||||
tt += gpstime;
|
|
||||||
si->time = tt;
|
|
||||||
si->vframe = tt - 315964800;
|
|
||||||
Serial.printf(" mp3h TIMESTAMP: %d\n", tt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t hex(uint32_t n) {
|
|
||||||
n = n % 16;
|
|
||||||
return (n<10) ? (n+'0') : (n-10+'A');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetmp3h() {
|
|
||||||
mp3hstate.id1 = mp3hstate.id2 = 0;
|
|
||||||
mp3hstate.idok = 0;
|
|
||||||
mp3hstate.gpsdate = 0;
|
|
||||||
mp3hstate.dateok = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ret: 1=frame ok; 2=frame with errors; 0=ignored frame (m10dop-alternativ)
|
|
||||||
int MP3H::decodeframeMP3H(uint8_t *data) {
|
|
||||||
printRaw(data, MP3H_FRAMELEN);
|
|
||||||
|
|
||||||
//
|
|
||||||
if(!checkMP3CRC(data)) {
|
|
||||||
// maybe add repairing frames later...
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data is a frame with correct CRC
|
|
||||||
//SondeInfo *si = sonde.si();
|
|
||||||
SondeData *si =&(sonde.si()->d);
|
|
||||||
uint8_t cnt = data[pos_CNT1] & 0x0F;
|
|
||||||
uint32_t cfg = u4(data+pos_CFG);
|
|
||||||
if(cnt==15) {
|
|
||||||
// date
|
|
||||||
mp3hstate.gpsdate = cfg;
|
|
||||||
mp3hstate.gpsdatetime = getgpstime(data);
|
|
||||||
mp3hstate.dateok = true;
|
|
||||||
} else if(cnt==13) {
|
|
||||||
// id2
|
|
||||||
if(mp3hstate.id2 > 0 && mp3hstate.id2 != cfg) { resetmp3h(); }
|
|
||||||
mp3hstate.id2 = cfg;
|
|
||||||
mp3hstate.idok |= 2;
|
|
||||||
} else if(cnt==12) {
|
|
||||||
// id1
|
|
||||||
if(mp3hstate.id1 > 0 && mp3hstate.id1 != cfg) { resetmp3h(); }
|
|
||||||
mp3hstate.id1 = cfg;
|
|
||||||
mp3hstate.idok |= 1;
|
|
||||||
}
|
|
||||||
// get id
|
|
||||||
if((mp3hstate.idok&3) == 3) {
|
|
||||||
//...
|
|
||||||
//si->type = STYPE_MP3H;
|
|
||||||
uint32_t n = mp3hstate.id1*100000 + mp3hstate.id2;
|
|
||||||
si->id[0] = 'M';
|
|
||||||
si->id[1] = 'R';
|
|
||||||
si->id[2] = 'Z';
|
|
||||||
si->id[3] = hex(n/0x100000);
|
|
||||||
si->id[4] = hex(n/0x10000);
|
|
||||||
si->id[5] = hex(n/0x1000);
|
|
||||||
si->id[6] = hex(n/0x100);
|
|
||||||
si->id[7] = hex(n/0x10);
|
|
||||||
si->id[8] = hex(n);
|
|
||||||
si->id[9] = 0;
|
|
||||||
snprintf(si->ser, 12, "%u-%u", mp3hstate.id1, mp3hstate.id2);
|
|
||||||
si->validID = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// position
|
|
||||||
calcgps(data);
|
|
||||||
// time
|
|
||||||
getmp3htime(data);
|
|
||||||
return 1;
|
|
||||||
#if 0
|
|
||||||
int repairstep = 16;
|
|
||||||
int repl = 0;
|
|
||||||
bool crcok;
|
|
||||||
// error correction, inspired by oe5dxl's sondeudp
|
|
||||||
do {
|
|
||||||
crcok = checkMP3Hcrc(M10_CRCPOS, data);
|
|
||||||
if(crcok || repairstep==0) break;
|
|
||||||
repl = 0;
|
|
||||||
for(int i=0; i<M10_CRCPOS; i++) {
|
|
||||||
if( ((sondeudp_VARSET[i/32]&(1<<(i%32))) == 0) && (fixcnt[i]>=repairstep) ) {
|
|
||||||
repl++;
|
|
||||||
data[i] = fixbytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
repairstep >>= 1;
|
|
||||||
} while(true);
|
|
||||||
if(crcok) {
|
|
||||||
for(int i=0; i<M10_CRCPOS; i++) {
|
|
||||||
if(fixbytes[i]==data[i] &&fixcnt[i]<255) fixcnt[i]++;
|
|
||||||
else { fixcnt[i]=0; fixbytes[i]=data[i]; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
|
||||||
Serial.printf(" repair: %d/%d\n", repl, repairstep);
|
|
||||||
|
|
||||||
if(data[1]==0x9F && data[2]==0x20) {
|
|
||||||
Serial.println("Decoding...");
|
|
||||||
// Its a M10
|
|
||||||
// getid...
|
|
||||||
char ids[11];
|
|
||||||
ids[0] = 'M';
|
|
||||||
ids[1] = 'E';
|
|
||||||
ids[2] = hex(data[95]/16);
|
|
||||||
ids[3] = hex(data[95]);
|
|
||||||
ids[4] = hex(data[93]);
|
|
||||||
uint32_t id = data[96] + data[97]*256;
|
|
||||||
ids[5] = hex(id/4096);
|
|
||||||
ids[6] = hex(id/256);
|
|
||||||
ids[7] = hex(id/16);
|
|
||||||
ids[8] = hex(id);
|
|
||||||
ids[9] = 0;
|
|
||||||
strncpy(sonde.si()->id, ids, 10);
|
|
||||||
ids[0] = hex(data[95]/16);
|
|
||||||
ids[1] = dez((data[95]&0x0f)/10);
|
|
||||||
ids[2] = dez((data[95]&0x0f));
|
|
||||||
ids[3] = dez(data[93]);
|
|
||||||
ids[4] = dez(id>>13);
|
|
||||||
id &= 0x1fff;
|
|
||||||
ids[5] = dez(id/1000);
|
|
||||||
ids[6] = dez((id/100)%10);
|
|
||||||
ids[7] = dez((id/10)%10);
|
|
||||||
ids[8] = dez(id%10);
|
|
||||||
strncpy(sonde.si()->ser, ids, 10);
|
|
||||||
sonde.si()->validID = true;
|
|
||||||
Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id);
|
|
||||||
// ID printed on sonde is ...-.-abbbb, with a=id>>13, bbbb=id&0x1fff in decimal
|
|
||||||
// position data
|
|
||||||
sonde.si()->lat = getint32(data+14) * DEGMUL;
|
|
||||||
sonde.si()->lon = getint32(data+18) * DEGMUL;
|
|
||||||
sonde.si()->alt = getint32(data+22) * 0.001;
|
|
||||||
float ve = getint16(data+4)*VMUL;
|
|
||||||
float vn = getint16(data+6)*VMUL;
|
|
||||||
sonde.si()->vs = getint16(data+8) * VMUL;
|
|
||||||
sonde.si()->hs = sqrt(ve*ve+vn*vn);
|
|
||||||
float dir = atan2(vn, ve)*(1.0/RAD);
|
|
||||||
if(dir<0) dir+=360;
|
|
||||||
sonde.si()->dir = dir;
|
|
||||||
sonde.si()->validPos = 0x3f;
|
|
||||||
|
|
||||||
uint32_t gpstime = getint32(data+10);
|
|
||||||
uint16_t gpsweek = getint16(data+32);
|
|
||||||
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
|
||||||
// one week = 7*24*60*60 = 604800 seconds
|
|
||||||
// unix epoch starts jan 1st 1970 0:00
|
|
||||||
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
|
||||||
// subtracting 86400 yields 315878400UL
|
|
||||||
sonde.si()->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
|
||||||
sonde.si()->validTime = true;
|
|
||||||
} else {
|
|
||||||
Serial.printf("data is %02x %02x %02x\n", data[0], data[1], data[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return crcok?1:2;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t rxdata;
|
|
||||||
static bool rxsearching=true;
|
|
||||||
|
|
||||||
// search for
|
|
||||||
// 0xBF3H (or inverse)
|
|
||||||
void MP3H::processMP3Hdata(uint8_t dt)
|
|
||||||
{
|
|
||||||
for(int i=0; i<8; i++) {
|
|
||||||
uint8_t d = (dt&0x80)?1:0;
|
|
||||||
dt <<= 1;
|
|
||||||
rxdata = (rxdata<<1) | d;
|
|
||||||
if( (rxbitc&1)==0 ) {
|
|
||||||
// "bit1"
|
|
||||||
rxbyte = (rxbyte<<1) | d;
|
|
||||||
} else {
|
|
||||||
// "bit2" ==> 01 or 10 => 1, otherweise => 0
|
|
||||||
// rxbyte = rxbyte ^ d;
|
|
||||||
}
|
|
||||||
// BF3H => 1011 1111 0011 0101 => 10011010 10101010 01011010 01100110 => 9AAA5A66 // 6555a599
|
|
||||||
if(rxsearching) {
|
|
||||||
if( rxdata == 0x9AAA5A66 || rxdata == 0x6555a599 ) {
|
|
||||||
rxsearching = false;
|
|
||||||
rxbitc = 0;
|
|
||||||
rxp = 0;
|
|
||||||
headerDetected = 1;
|
|
||||||
Serial.print("SYNC\n");
|
|
||||||
int rssi=sx1278.getRSSI();
|
|
||||||
int fei=sx1278.getFEI();
|
|
||||||
int afc=sx1278.getAFC();
|
|
||||||
Serial.print("SYNC!!! Test: RSSI="); Serial.print(rssi);
|
|
||||||
Serial.print(" FEI="); Serial.print(fei);
|
|
||||||
Serial.print(" AFC="); Serial.println(afc);
|
|
||||||
sonde.si()->rssi = rssi;
|
|
||||||
sonde.si()->afc = afc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rxbitc = (rxbitc+1)%16; // 16;
|
|
||||||
if(rxbitc == 0) { // got 8 data bit
|
|
||||||
dataptr[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
|
||||||
//if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
|
||||||
if(rxp>=MP3H_FRAMELEN) {
|
|
||||||
rxsearching = true;
|
|
||||||
haveNewFrame = decodeframeMP3H(dataptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAXFRAMES 6
|
|
||||||
int MP3H::receive() {
|
|
||||||
// we wait for at most 6 frames or until a new seq nr.
|
|
||||||
uint8_t nFrames = MAXFRAMES; // MP3H sends every frame 6x
|
|
||||||
static uint32_t lastFrame = 0;
|
|
||||||
uint8_t retval = RX_TIMEOUT;
|
|
||||||
|
|
||||||
unsigned long t0 = millis();
|
|
||||||
Serial.printf("MP3H::receive() start at %ld\n",t0);
|
|
||||||
while( millis() - t0 < 1100 + (retval!=RX_TIMEOUT)?1000:0 ) {
|
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
if ( bitRead(value, 7) ) {
|
|
||||||
Serial.println("FIFO full");
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 4) ) {
|
|
||||||
Serial.println("FIFO overflow");
|
|
||||||
}
|
|
||||||
if ( bitRead(value, 2) == 1 ) {
|
|
||||||
Serial.println("FIFO: ready()");
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
}
|
|
||||||
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
|
||||||
byte data = sx1278.readRegister(REG_FIFO);
|
|
||||||
Serial.printf("%02x:",data);
|
|
||||||
processMP3Hdata(data);
|
|
||||||
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
|
||||||
} else {
|
|
||||||
if(headerDetected) {
|
|
||||||
t0 = millis(); // restart timer... don't time out if header detected...
|
|
||||||
headerDetected = 0;
|
|
||||||
}
|
|
||||||
if(haveNewFrame) {
|
|
||||||
Serial.printf("MP3H::receive(): new frame complete after %ldms\n", millis()-t0);
|
|
||||||
printRaw(dataptr, MP3H_FRAMELEN);
|
|
||||||
nFrames--;
|
|
||||||
// frame with CRC error: just skip and retry (unless we have waited for 6 frames alred)
|
|
||||||
if(haveNewFrame != 1) {
|
|
||||||
Serial.printf("hNF: %d (ERROR)\n", haveNewFrame);
|
|
||||||
retval = RX_ERROR;
|
|
||||||
} else if (sonde.si()->d.time == lastFrame) { // same frame number as seen before => skip
|
|
||||||
Serial.printf("Skipping frame with frame# %d\n", lastFrame);
|
|
||||||
// nothing, wait for next, "new" frame
|
|
||||||
} else { // good and new frame, return it.
|
|
||||||
Serial.println("Good frame");
|
|
||||||
haveNewFrame = 0;
|
|
||||||
lastFrame = sonde.si()->d.time;
|
|
||||||
return RX_OK;
|
|
||||||
}
|
|
||||||
haveNewFrame = 0;
|
|
||||||
#if 0
|
|
||||||
if(nFrames <= 0) {
|
|
||||||
// up to 6 old or erronous frames received => break out
|
|
||||||
Serial.printf("nFrames is %di, giving up\n", nFrames);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
delay(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int32_t afc = sx1278.getAFC();
|
|
||||||
int16_t rssi = sx1278.getRSSI();
|
|
||||||
Serial.printf("receive: AFC is %d, RSSI is %.1f\n", afc, rssi/2.0);
|
|
||||||
Serial.printf("MP3H::receive() timed out\n");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MP3H::waitRXcomplete() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MP3H mp3h = MP3H();
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* MP3H.h
|
|
||||||
* Functions for decoding MP3H radiosonde
|
|
||||||
* Copyright (C) 2021 Hansi Reiser, dl9rdz
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MP3H_h
|
|
||||||
#define MP3H_h
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
#ifndef inttypes_h
|
|
||||||
#include <inttypes.h>
|
|
||||||
#endif
|
|
||||||
#include "DecoderBase.h"
|
|
||||||
|
|
||||||
/* Main class */
|
|
||||||
class MP3H : public DecoderBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
void printRaw(uint8_t *data, int len);
|
|
||||||
void processMP3Hdata(uint8_t data);
|
|
||||||
int decodeframeMP3H(uint8_t *data);
|
|
||||||
public:
|
|
||||||
MP3H();
|
|
||||||
int setup(float frequency, int type = 0);
|
|
||||||
int receive();
|
|
||||||
int waitRXcomplete();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern MP3H mp3h;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,934 +0,0 @@
|
||||||
|
|
||||||
/* RS41 decoder functions */
|
|
||||||
#include "RS41.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "rsc.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
#define RS41_DEBUG 1
|
|
||||||
|
|
||||||
#if RS41_DEBUG
|
|
||||||
#define RS41_DBG(x) x
|
|
||||||
#else
|
|
||||||
#define RS41_DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RS41MAXLEN (320)
|
|
||||||
static byte data[800];
|
|
||||||
static int dpos = 0;
|
|
||||||
|
|
||||||
|
|
||||||
// whole 51 row frame as C structure
|
|
||||||
// taken from https://github.com/einergehtnochrein/ra-firmware
|
|
||||||
struct subframeBuffer {
|
|
||||||
uint64_t valid; // bitmask for subframe valid; lsb=frame 0, etc.
|
|
||||||
union {
|
|
||||||
byte rawData[51*16];
|
|
||||||
struct __attribute__((__packed__)) {
|
|
||||||
uint16_t crc16; /* CRC16 CCITT Checksum over range 0x002...0x31F */
|
|
||||||
uint16_t frequency; /* 0x002: TX is on 400 MHz + (frequency / 64) * 10 kHz */
|
|
||||||
uint8_t startupTxPower; /* 0x004: TX power level at startup (1...7) */
|
|
||||||
uint8_t reserved005;
|
|
||||||
uint8_t reserved006;
|
|
||||||
uint16_t reserved007; /* 0x007: ?? (some bitfield) [0],[1],[2],[3]. Init value = 0xE */
|
|
||||||
uint16_t reserved009; /* 0x009: ? */
|
|
||||||
uint8_t reserved00B;
|
|
||||||
uint8_t reserved00C;
|
|
||||||
uint8_t serial[8]; /* 0x00D: Sonde ID, 8 char, not terminated */
|
|
||||||
uint16_t firmwareVersion; /* 0x015: 10000*major + 100*minor + patch*/
|
|
||||||
uint16_t reserved017;
|
|
||||||
uint16_t minHeight4Flight; /* 0x019: Height (meter above ground) where flight mode begins */
|
|
||||||
uint8_t lowBatteryThreshold100mV; /* 0x01B: (Default=18) Shutdown if battery voltage below this
|
|
||||||
threshold for some time (10s ?)
|
|
||||||
*/
|
|
||||||
uint8_t nfcDetectorThreshold; /* 0x01C: NFC detector threshold [25mV] (Default: 0x05 = 125mV) */
|
|
||||||
uint8_t reserved01D; /* 0x01D: ?? (Init value = 0xB4) */
|
|
||||||
uint8_t reserved01E; /* 0x01E: ?? (Init value = 0x3C) */
|
|
||||||
uint16_t reserved01F;
|
|
||||||
int8_t refTemperatureThreshold; /* 0x021: Reference temperature threshold [°C] */
|
|
||||||
uint8_t reserved022;
|
|
||||||
uint16_t reserved023;
|
|
||||||
uint16_t reserved025;
|
|
||||||
int16_t flightKillFrames; /* 0x027: Number of frames in flight until kill (-1 = disabled) */
|
|
||||||
uint16_t reserved029; /* 0x029: ? (Init value = 0) */
|
|
||||||
uint8_t burstKill; /* 0x02B: Burst kill (0=disabled, 1=enabled) */
|
|
||||||
uint8_t reserved02C;
|
|
||||||
uint8_t reserved02D;
|
|
||||||
uint16_t reserved02E;
|
|
||||||
uint16_t reserved030;
|
|
||||||
uint8_t reserved032;
|
|
||||||
uint16_t reserved033;
|
|
||||||
uint16_t reserved035;
|
|
||||||
uint16_t reserved037;
|
|
||||||
uint16_t reserved039; /* 0x039: */
|
|
||||||
uint8_t reserved03B; /* 0x03B: */
|
|
||||||
uint8_t reserved03C; /* 0x03C: */
|
|
||||||
float refResistorLow; /* 0x03D: Reference resistor low (750 Ohms) */
|
|
||||||
float refResistorHigh; /* 0x041: Reference resistor high (1100 Ohms) */
|
|
||||||
float refCapLow; /* 0x045: Reference capacitance low (0) */
|
|
||||||
float refCapHigh; /* 0x049: Reference capacitance high (47 pF) */
|
|
||||||
float taylorT[3]; /* 0x04D: Tayor coefficients for main temperature calculation */
|
|
||||||
float calT; /* 0x059: Calibration factor for main sensor */
|
|
||||||
float polyT[6]; /* 0x05D: */
|
|
||||||
float calibU[2]; /* 0x075: Calibration coefficients for humidity sensor */
|
|
||||||
|
|
||||||
float matrixU[7][6]; /* 0x07D: Matrix for humidity sensor RH calculation */
|
|
||||||
float taylorTU[3]; /* 0x125: Coefficients for U sensor temperature calculation */
|
|
||||||
float calTU; /* 0x131: Calibration factor for U temperature sensor */
|
|
||||||
float polyTrh[6]; /* 0x135: */
|
|
||||||
|
|
||||||
uint8_t reserved14D; /* 0x14D: */
|
|
||||||
uint32_t reserved14E; /* 0x14E: */
|
|
||||||
|
|
||||||
float f152;
|
|
||||||
uint8_t u156;
|
|
||||||
float f157; /* 0x157: ?? (Initialized by same value as calibU[0]) */
|
|
||||||
uint8_t reserved15B; /* 0x15B: */
|
|
||||||
uint32_t reserved15C; /* 0x15C: */
|
|
||||||
float f160[35];
|
|
||||||
uint8_t startIWDG; /* 0x1EC: If ==1 or ==2: Watchdog IWDG will not be started */
|
|
||||||
uint8_t parameterSetupDone; /* 0x1ED: Set (!=0) if parameter setup was done */
|
|
||||||
uint8_t enableTestMode; /* 0x1EE: Test mode (service menu) (0=disabled, 1=enabled) */
|
|
||||||
uint8_t enableTX; /* 0x1EF: 0=TX disabled, 1=TX enabled (maybe this is autostart?) */
|
|
||||||
float f1F0[8];
|
|
||||||
float pressureLaunchSite[2]; /* 0x210: Pressure [hPa] at launch site */
|
|
||||||
struct __attribute__((__packed__)){
|
|
||||||
char variant[10]; /* 0x218: Sonde variant (e.g. "RS41-SG") */
|
|
||||||
uint8_t mainboard[10]; /* 0x222: Name of mainboard (e.g. "RSM412") */
|
|
||||||
} names;
|
|
||||||
struct __attribute__((__packed__)){
|
|
||||||
uint8_t mainboard[9]; /* 0x22C: Serial number of mainboard (e.g. "L1123553") */
|
|
||||||
uint8_t text235[12]; /* 0x235: "0000000000" */
|
|
||||||
uint16_t reserved241; /* 0x241: */
|
|
||||||
uint8_t pressureSensor[8]; /* 0x243: Serial number of pressure sensor (e.g. "N1310487") */
|
|
||||||
uint16_t reserved24B; /* 0x24B: */
|
|
||||||
} serials;
|
|
||||||
uint16_t reserved24D; /* 0x24D: */
|
|
||||||
uint16_t reserved24F; /* 0x24F: */
|
|
||||||
uint16_t reserved251; /* 0x251: (Init value = 0x21A = 538) */
|
|
||||||
uint8_t xdataUartBaud; /* 0x253: 1=9k6, 2=19k2, 3=38k4, 4=57k6, 5=115k2 */
|
|
||||||
uint8_t reserved254;
|
|
||||||
float cpuTempSensorVoltageAt25deg; /* 0x255: CPU temperature sensor voltage at 25°C */
|
|
||||||
uint8_t reserved259;
|
|
||||||
uint8_t reserved25A[0x25E -0x25A];
|
|
||||||
float matrixP[18]; /* 0x25E: Coefficients for pressure sensor polynomial */
|
|
||||||
float vectorBp[3]; /* 0x2A6: */
|
|
||||||
uint8_t reserved2B2[8]; /* 0x2B2: */
|
|
||||||
float matrixBt[12]; /* 0x2BA: */
|
|
||||||
uint8_t reserved2EA[0x2FA-0x2EA];
|
|
||||||
uint16_t halfword2FA[9];
|
|
||||||
float reserved30C;
|
|
||||||
float reserved310; /* 0x310: */
|
|
||||||
uint8_t reserved314; /* 0x314: */
|
|
||||||
uint8_t reserved315; /* 0x315: */
|
|
||||||
int16_t burstKillFrames; /* 0x316: Number of active frames after burst kill */
|
|
||||||
uint8_t reserved318[0x320-0x318];
|
|
||||||
|
|
||||||
/* This is fragment 50. It only uses 14 valid bytes! */
|
|
||||||
int16_t killCountdown; /* 0x320: Counts frames remaining until kill (-1 = inactive) */
|
|
||||||
uint8_t reserved322[6];
|
|
||||||
int8_t intTemperatureCpu; /* 0x328: Temperature [°C] of CPU */
|
|
||||||
int8_t intTemperatureRadio; /* 0x329: Temperature [°C] of radio chip */
|
|
||||||
int8_t reserved32A; /* 0x32A: */
|
|
||||||
uint8_t reserved32B; /* 0x32B: */
|
|
||||||
uint8_t reserved32C; /* 0x32C: ? (the sum of two slow 8-bit counters) */
|
|
||||||
uint8_t reserved32D; /* 0x32D: ? (the sum of two slow 8-bit counters) */
|
|
||||||
} value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// moved global variable "calibration" to sondeInfo->extra
|
|
||||||
|
|
||||||
static uint16_t CRCTAB[256];
|
|
||||||
|
|
||||||
#define X2C_DIVR(a, b) ((b) != 0.0f ? (a)/(b) : (a))
|
|
||||||
#define X2C_DIVL(a, b) ((a)/(b))
|
|
||||||
static uint32_t X2C_LSH(uint32_t a, int32_t length, int32_t n)
|
|
||||||
{
|
|
||||||
uint32_t m;
|
|
||||||
|
|
||||||
m = 0;
|
|
||||||
m = (length == 32) ? 0xFFFFFFFFl : (1 << length) - 1;
|
|
||||||
if (n > 0) {
|
|
||||||
if (n >= (int32_t)length)
|
|
||||||
return 0;
|
|
||||||
return (a << n) & m;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n <= (int32_t)-length)
|
|
||||||
return 0;
|
|
||||||
return (a >> -n) & m;
|
|
||||||
}
|
|
||||||
|
|
||||||
double atang2(double x, double y)
|
|
||||||
{
|
|
||||||
double w;
|
|
||||||
if (fabs(x)>fabs(y)) {
|
|
||||||
w = (double)atan(X2C_DIVL(y,x));
|
|
||||||
if (x<0.0) {
|
|
||||||
if (y>0.0) w = 3.1415926535898+w;
|
|
||||||
else w = w-3.1415926535898;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (y!=0.0) {
|
|
||||||
w = (double)(1.5707963267949f-atan(X2C_DIVL(x, y)));
|
|
||||||
if (y<0.0) w = w-3.1415926535898;
|
|
||||||
}
|
|
||||||
else w = 0.0;
|
|
||||||
return w;
|
|
||||||
} /* end atang2() */
|
|
||||||
|
|
||||||
|
|
||||||
static void Gencrctab(void)
|
|
||||||
{
|
|
||||||
uint16_t j;
|
|
||||||
uint16_t i;
|
|
||||||
uint16_t crc;
|
|
||||||
for (i = 0U; i<=255U; i++) {
|
|
||||||
crc = (uint16_t)(i*256U);
|
|
||||||
for (j = 0U; j<=7U; j++) {
|
|
||||||
if ((0x8000U & crc)) crc = X2C_LSH(crc,16,1)^0x1021U;
|
|
||||||
else crc = X2C_LSH(crc,16,1);
|
|
||||||
} /* end for */
|
|
||||||
CRCTAB[i] = X2C_LSH(crc,16,-8)|X2C_LSH(crc,16,8);
|
|
||||||
} /* end for */
|
|
||||||
} /* end Gencrctab() */
|
|
||||||
|
|
||||||
decoderSetupCfg rs41SetupCfg = {
|
|
||||||
.bitrate = 4800,
|
|
||||||
.rx_cfg = 0x1E, // Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
.sync_cfg = 0x57, // Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
|
||||||
.sync_len = 8,
|
|
||||||
.sync_data = (const uint8_t *)"\x08\x6D\x53\x88\x44\x69\x48\x1F",
|
|
||||||
.preamble_cfg = 0xA8,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int RS41::setup(float frequency, int /*type*/)
|
|
||||||
{
|
|
||||||
if(!initialized) {
|
|
||||||
Gencrctab();
|
|
||||||
initrsc();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sx1278.ON()!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(DecoderBase::setup(rs41SetupCfg, sonde.config.rs41.agcbw, sonde.config.rs41.rxbw)!=0 ) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
// all moved to DecoderBase now
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting FSK mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setBitrate(4800)!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting bitrate 4800bit/s FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.rs41.agcbw)!=0) {
|
|
||||||
RS41_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.rs41.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.rs41.rxbw)!=0) {
|
|
||||||
RS41_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.rs41.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
if(sx1278.setRxConf(0x1E)!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
|
||||||
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
|
||||||
|
|
||||||
//const char *SYNC="\x10\xB6\xCA\x11\x22\x96\x12\xF8";
|
|
||||||
const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
|
||||||
if(sx1278.setSyncConf(0x57, 8, (const uint8_t *)SYNC)!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
|
||||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
|
||||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
|
||||||
RS41_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int retval = sx1278.setFrequency(frequency);
|
|
||||||
dpos = 0;
|
|
||||||
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t RS41::bits2val(const uint8_t *bits, int len) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
for (int j = 0; j < len; j++) {
|
|
||||||
val |= (bits[j] << (len-1-j));
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
RS41::RS41() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RS41 reed solomon decoder, from dxlAPRS
|
|
||||||
*/
|
|
||||||
static int32_t reedsolomon41(byte buf[], uint32_t buf_len, uint32_t len2)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
int32_t res1;
|
|
||||||
/*tb1, */
|
|
||||||
int32_t res;
|
|
||||||
char b1[256];
|
|
||||||
char b[256];
|
|
||||||
uint32_t eraspos[24];
|
|
||||||
uint32_t tmp;
|
|
||||||
for (i = 0UL; i<=255UL; i++) {
|
|
||||||
b[i] = 0;
|
|
||||||
b1[i] = 0;
|
|
||||||
} /* end for */
|
|
||||||
tmp = len2;
|
|
||||||
i = 0UL;
|
|
||||||
if (i<=tmp) for (;; i++) {
|
|
||||||
b[230UL-i] = buf[i*2UL+56UL];
|
|
||||||
b1[230UL-i] = buf[i*2UL+57UL];
|
|
||||||
if (i==tmp) break;
|
|
||||||
} /* end for */
|
|
||||||
for (i = 0UL; i<=23UL; i++) {
|
|
||||||
b[254UL-i] = buf[i+8UL];
|
|
||||||
b1[254UL-i] = buf[i+32UL];
|
|
||||||
} /* end for */
|
|
||||||
res = decodersc(b, eraspos, 0);
|
|
||||||
res1 = decodersc(b1, eraspos, 0);
|
|
||||||
if (res>0L && res<=12L) {
|
|
||||||
tmp = len2;
|
|
||||||
i = 0UL;
|
|
||||||
if (i<=tmp) for (;; i++) {
|
|
||||||
buf[i*2UL+56UL] = b[230UL-i];
|
|
||||||
if (i==tmp) break;
|
|
||||||
} /* end for */
|
|
||||||
for (i = 0UL; i<=23UL; i++) {
|
|
||||||
buf[i+8UL] = b[254UL-i];
|
|
||||||
} /* end for */
|
|
||||||
}
|
|
||||||
if (res1>0L && res1<=12L) {
|
|
||||||
tmp = len2;
|
|
||||||
i = 0UL;
|
|
||||||
if (i<=tmp) for (;; i++) {
|
|
||||||
buf[i*2UL+57UL] = b1[230UL-i];
|
|
||||||
if (i==tmp) break;
|
|
||||||
} /* end for */
|
|
||||||
for (i = 0UL; i<=23UL; i++) {
|
|
||||||
buf[i+32UL] = b1[254UL-i];
|
|
||||||
} /* end for */
|
|
||||||
}
|
|
||||||
if (res<0L || res1<0L) return -1L;
|
|
||||||
else return res+res1;
|
|
||||||
return 0;
|
|
||||||
} /* end reedsolomon41() */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char crcrs(const byte frame[], uint32_t frame_len,
|
|
||||||
int32_t from, int32_t to)
|
|
||||||
{
|
|
||||||
uint16_t crc;
|
|
||||||
int32_t i;
|
|
||||||
int32_t tmp;
|
|
||||||
crc = 0xFFFFU;
|
|
||||||
tmp = to-3L;
|
|
||||||
i = from;
|
|
||||||
if (i<=tmp) for (;; i++) {
|
|
||||||
crc = X2C_LSH(crc,16,-8)^CRCTAB[(uint32_t)((crc^(uint16_t)(uint8_t)frame[i])&0xFFU)];
|
|
||||||
if (i==tmp) break;
|
|
||||||
} /* end for */
|
|
||||||
return frame[to-1L]==(char)crc && frame[to-2L]==(char)X2C_LSH(crc,
|
|
||||||
16,-8);
|
|
||||||
} /* end crcrs() */
|
|
||||||
|
|
||||||
static int32_t getint32(const byte frame[], uint32_t frame_len,
|
|
||||||
uint32_t p)
|
|
||||||
{
|
|
||||||
uint32_t n;
|
|
||||||
uint32_t i;
|
|
||||||
n = 0UL;
|
|
||||||
for (i = 3UL;; i--) {
|
|
||||||
n = n*256UL+(uint32_t)(uint8_t)frame[p+i];
|
|
||||||
if (i==0UL) break;
|
|
||||||
} /* end for */
|
|
||||||
return (int32_t)n;
|
|
||||||
} /* end getint32() */
|
|
||||||
|
|
||||||
static uint32_t getint24(const byte frame[], uint32_t frame_len, uint32_t p) { // 24bit unsigned int
|
|
||||||
uint32_t val24 = 0;
|
|
||||||
val24 = frame[p] | (frame[p+1]<<8) | (frame[p+2]<<16);
|
|
||||||
return val24;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t getcard16(const byte frame[], uint32_t frame_len,
|
|
||||||
uint32_t p)
|
|
||||||
{
|
|
||||||
return (uint32_t)(uint8_t)frame[p]+256UL*(uint32_t)(uint8_t)
|
|
||||||
frame[p+1UL];
|
|
||||||
} /* end getcard16() */
|
|
||||||
|
|
||||||
|
|
||||||
static int32_t getint16(const byte frame[], uint32_t frame_len,
|
|
||||||
uint32_t p)
|
|
||||||
{
|
|
||||||
uint32_t n;
|
|
||||||
n = (uint32_t)(uint8_t)frame[p]+256UL*(uint32_t)(uint8_t)
|
|
||||||
frame[p+1UL];
|
|
||||||
if (n>=32768UL) return (int32_t)(n-65536UL);
|
|
||||||
return (int32_t)n;
|
|
||||||
} /* end getint16() */
|
|
||||||
|
|
||||||
// also used by MP3H.cpp
|
|
||||||
void wgs84r(double x, double y, double z,
|
|
||||||
double * lat, double * long0,
|
|
||||||
double * heig)
|
|
||||||
{
|
|
||||||
double sl;
|
|
||||||
double ct;
|
|
||||||
double st;
|
|
||||||
double t;
|
|
||||||
double rh;
|
|
||||||
double xh;
|
|
||||||
double h;
|
|
||||||
h = x*x+y*y;
|
|
||||||
if (h>0.0) {
|
|
||||||
rh = sqrt(h);
|
|
||||||
xh = x+rh;
|
|
||||||
*long0 = atang2(xh, y)*2.0;
|
|
||||||
if (*long0>3.1415926535898) *long0 = *long0-6.2831853071796;
|
|
||||||
t = atan(X2C_DIVL(z*1.003364089821, rh));
|
|
||||||
st = sin(t);
|
|
||||||
ct = cos(t);
|
|
||||||
*lat = atan((X2C_DIVL(z+4.2841311513312E+4*st*st*st,
|
|
||||||
rh-4.269767270718E+4*ct*ct*ct)));
|
|
||||||
sl = sin(*lat);
|
|
||||||
*heig = X2C_DIVL(rh,cos(*lat))-(X2C_DIVR(6.378137E+6f,
|
|
||||||
sqrt((1.0-6.6943799901413E-3*sl*sl))));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*lat = 0.0;
|
|
||||||
*long0 = 0.0;
|
|
||||||
*heig = 0.0;
|
|
||||||
}
|
|
||||||
/* lat:=atan(z/(rh*(1.0 - E2))); */
|
|
||||||
/* heig:=sqrt(h + z*z) - EARTHA; */
|
|
||||||
} /* end wgs84r() */
|
|
||||||
|
|
||||||
// returns: 0=ok, -1=error
|
|
||||||
static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
|
|
||||||
{
|
|
||||||
double dir;
|
|
||||||
double vu;
|
|
||||||
double ve;
|
|
||||||
double vn;
|
|
||||||
double vz;
|
|
||||||
double vy;
|
|
||||||
double vx;
|
|
||||||
double heig;
|
|
||||||
double long0;
|
|
||||||
double lat;
|
|
||||||
double z;
|
|
||||||
double y;
|
|
||||||
double x;
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
x = (double)getint32(b, b_len, p)*0.01;
|
|
||||||
y = (double)getint32(b, b_len, p+4UL)*0.01;
|
|
||||||
z = (double)getint32(b, b_len, p+8UL)*0.01;
|
|
||||||
uint8_t sats = getcard16(b, b_len, p+18UL)&255UL;
|
|
||||||
Serial.printf("x:%g, y:%g, z:%g sats:%d\n", x, y, z, sats);
|
|
||||||
if( sats<4 || (x==0 && y==0 && z==0) ) {
|
|
||||||
// RS41 sometimes sends frame with all 0
|
|
||||||
// or, if sats<4, data is simply garbage. do not use.
|
|
||||||
if(si->validPos) si->validPos |= 0x80; // flag as old
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
si->sats = sats;
|
|
||||||
wgs84r(x, y, z, &lat, &long0, &heig);
|
|
||||||
Serial.print(" ");
|
|
||||||
si->lat = (float)(X2C_DIVL(lat,1.7453292519943E-2));
|
|
||||||
Serial.print(si->lat);
|
|
||||||
Serial.print(" ");
|
|
||||||
si->lon = (float)(X2C_DIVL(long0,1.7453292519943E-2));
|
|
||||||
Serial.print(si->lon);
|
|
||||||
if (heig<1.E+5 && heig>(-1.E+5)) {
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.print((uint32_t)heig);
|
|
||||||
Serial.print("m");
|
|
||||||
}
|
|
||||||
/*speed */
|
|
||||||
vx = (double)getint16(b, b_len, p+12UL)*0.01;
|
|
||||||
vy = (double)getint16(b, b_len, p+14UL)*0.01;
|
|
||||||
vz = (double)getint16(b, b_len, p+16UL)*0.01;
|
|
||||||
vn = (-(vx*sin(lat)*cos(long0))-vy*sin(lat)*sin(long0))+vz*cos(lat);
|
|
||||||
ve = -(vx*sin(long0))+vy*cos(long0);
|
|
||||||
vu = vx*cos(lat)*cos(long0)+vy*cos(lat)*sin(long0)+vz*sin(lat);
|
|
||||||
dir = X2C_DIVL(atang2(vn, ve),1.7453292519943E-2);
|
|
||||||
if (dir<0.0) dir = 360.0+dir;
|
|
||||||
si->dir = dir;
|
|
||||||
Serial.print(" ");
|
|
||||||
si->hs = sqrt(vn*vn+ve*ve);
|
|
||||||
Serial.print(si->hs*3.6);
|
|
||||||
Serial.print("km/h ");
|
|
||||||
Serial.print(dir);
|
|
||||||
Serial.print("deg ");
|
|
||||||
Serial.print((float)vu);
|
|
||||||
si->vs = vu;
|
|
||||||
Serial.print("m/s ");
|
|
||||||
si->alt = heig;
|
|
||||||
if( 0==(int)(lat*10000) && 0==(int)(long0*10000) ) {
|
|
||||||
if(si->validPos) {
|
|
||||||
// we have an old position, so keep previous position and mark it as old
|
|
||||||
si->validPos |= 0x80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
si->validPos = 0x7f;
|
|
||||||
} /* end posrs41() */
|
|
||||||
|
|
||||||
void ProcessSubframe( byte *subframeBytes, int subframeNumber ) {
|
|
||||||
// the total subframe consists of 51 rows, each row 16 bytes
|
|
||||||
// based on https://github.com/bazjo/RS41_Decoding/tree/master/RS41-SGP#Subframe
|
|
||||||
struct subframeBuffer *s = (struct subframeBuffer *)sonde.si()->extra;
|
|
||||||
// Allocate on demand
|
|
||||||
if(!s) {
|
|
||||||
s = (struct subframeBuffer *)malloc( sizeof(struct subframeBuffer) );
|
|
||||||
if(!s) { Serial.println("ProcessSubframe: out of memory"); return; }
|
|
||||||
sonde.si()->extra = s;
|
|
||||||
s->valid = 0;
|
|
||||||
}
|
|
||||||
memcpy( s->rawData+16*subframeNumber, subframeBytes, 16);
|
|
||||||
s->valid |= (1ULL << subframeNumber);
|
|
||||||
Serial.printf("subframe %d; valid: %x%08x\n", subframeNumber, (uint32_t)(s->valid>>32), (uint32_t)s->valid);
|
|
||||||
for(int i=0; i<16; i++) { Serial.printf("%02x[%c]", subframeBytes[i],( subframeBytes[i]>20 && subframeBytes[i]<127)? subframeBytes[i] : '.'); }
|
|
||||||
Serial.println("");
|
|
||||||
// subframeReceived[subframeNumber] = true; // mark this row of the total subframe as complete
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
Serial.printf("subframe number: 0x%02X\n", subframeNumber );
|
|
||||||
Serial.print("subframe values: ");
|
|
||||||
for ( int i = 0; i < 16; i++ ) {
|
|
||||||
Serial.printf( "%02X ", subframeBytes[i] );
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
Serial.println("Full subframe");
|
|
||||||
for ( int j = 0; j<51; j++ ) {
|
|
||||||
Serial.printf("%03X ", j*16);
|
|
||||||
for ( int i = 0; i < 16; i++ ) {
|
|
||||||
Serial.printf( "%02X ", s.rawData[j*16+i] );
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the water vapor saturation pressure for a given temperature.
|
|
||||||
* Uses the Hyland and Wexler equation with coefficients for T < 0°C.
|
|
||||||
*/
|
|
||||||
// taken from https://github.com/einergehtnochrein/ra-firmware
|
|
||||||
static float _RS41_waterVaporSaturationPressure (float Tcelsius)
|
|
||||||
{
|
|
||||||
/* Convert to Kelvin */
|
|
||||||
float T = Tcelsius + 273.15f;
|
|
||||||
|
|
||||||
/* Apply some correction magic */
|
|
||||||
T = 0
|
|
||||||
- 0.4931358f
|
|
||||||
+ (1.0f + 4.61e-3f) * T
|
|
||||||
- 1.3746454e-5f * T * T
|
|
||||||
+ 1.2743214e-8f * T * T * T
|
|
||||||
;
|
|
||||||
|
|
||||||
/* Plug into H+W equation */
|
|
||||||
float p = expf(-5800.2206f / T
|
|
||||||
+ 1.3914993f
|
|
||||||
+ 6.5459673f * logf(T)
|
|
||||||
- 4.8640239e-2f * T
|
|
||||||
+ 4.1764768e-5f * T * T
|
|
||||||
- 1.4452093e-8f * T * T * T
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Scale result to hPa */
|
|
||||||
return p / 100.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PM(x) calibration->value.matrixP[x]
|
|
||||||
// CALIB_P: matrixP (frames 0x25..0x2A) and type (frame 0x21)
|
|
||||||
#define CALIB_P ((0x3Fll<<0x25)|(1ll<<0x21))
|
|
||||||
float GetRAP( uint32_t m, uint32_t m1, uint32_t m2, int16_t ptraw) {
|
|
||||||
struct subframeBuffer *calibration = (struct subframeBuffer *)sonde.si()->extra;
|
|
||||||
float pt = (float)ptraw*0.01;
|
|
||||||
float pw[6];
|
|
||||||
pw[0] = PM(0) + pt*PM(7) + pt*pt*PM(11) + pt*pt*pt*PM(15);
|
|
||||||
pw[1] = PM(1) + pt*PM(8) + pt*pt*PM(12) + pt*pt*pt*PM(16);
|
|
||||||
pw[2] = PM(2) + pt*PM(9) + pt*pt*PM(13) + pt*pt*pt*PM(17);
|
|
||||||
pw[3] = PM(3) + pt*PM(10)+ pt*pt*PM(14);
|
|
||||||
pw[4] = PM(4);
|
|
||||||
pw[5] = PM(5);
|
|
||||||
float f = (float)m; //meas[9];
|
|
||||||
float f1 = (float)m1; //meas[10];
|
|
||||||
float f2 = (float)m2; //meas[11];
|
|
||||||
float r = f-f1;
|
|
||||||
if(r!=0.0) {
|
|
||||||
r = (f2-f1) * PM(6) / r;
|
|
||||||
float xx = 1.0;
|
|
||||||
float p = 0.0;
|
|
||||||
for(int i=0; i<=5; i++) {
|
|
||||||
p += pw[i] * xx;
|
|
||||||
xx = xx * r;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// taken from https://github.com/einergehtnochrein/ra-firmware
|
|
||||||
float GetRATemp( uint32_t measuredCurrent, uint32_t refMin, uint32_t refMax, float calT, float taylorT[3], float polyT[6] ) {
|
|
||||||
struct subframeBuffer *calibration = (struct subframeBuffer *)sonde.si()->extra;
|
|
||||||
/* Reference values for temperature are two known resistors.
|
|
||||||
* From that we can derive the resistance of the sensor.
|
|
||||||
*/
|
|
||||||
float current = ( float(measuredCurrent) - float(refMin) ) / float(refMax - refMin);
|
|
||||||
float res = calibration->value.refResistorLow
|
|
||||||
+ (calibration->value.refResistorHigh - calibration->value.refResistorLow) * current;
|
|
||||||
float x = res * calT;
|
|
||||||
|
|
||||||
float Tuncal = 0
|
|
||||||
+ taylorT[0]
|
|
||||||
+ taylorT[1] * x
|
|
||||||
+ taylorT[2] * x * x;
|
|
||||||
|
|
||||||
/* Apply calibration polynomial */
|
|
||||||
float temperature =
|
|
||||||
Tuncal + polyT[0]
|
|
||||||
+ polyT[1] * Tuncal
|
|
||||||
+ polyT[2] * Tuncal * Tuncal
|
|
||||||
+ polyT[3] * Tuncal * Tuncal * Tuncal
|
|
||||||
+ polyT[4] * Tuncal * Tuncal * Tuncal * Tuncal
|
|
||||||
+ polyT[5] * Tuncal * Tuncal * Tuncal * Tuncal * Tuncal;
|
|
||||||
|
|
||||||
return temperature;
|
|
||||||
}
|
|
||||||
|
|
||||||
// taken from https://github.com/einergehtnochrein/ra-firmware
|
|
||||||
float GetRAHumidity( uint32_t humCurrent, uint32_t humMin, uint32_t humMax, float sensorTemp, float externalTemp, float pressure ) {
|
|
||||||
struct subframeBuffer *calibration = (struct subframeBuffer *)sonde.si()->extra;
|
|
||||||
float current = float( humCurrent - humMin) / float( humMax - humMin );
|
|
||||||
/* Compute absolute capacitance from the known references */
|
|
||||||
float C = calibration->value.refCapLow
|
|
||||||
+ (calibration->value.refCapHigh - calibration->value.refCapLow) * current;
|
|
||||||
|
|
||||||
/* Apply calibration */
|
|
||||||
float Cp = ( C / calibration->value.calibU[0] - 1.0f) * calibration->value.calibU[1];
|
|
||||||
|
|
||||||
/* Compensation for low temperature and pressure at altitude */
|
|
||||||
if(isnan(pressure)) {
|
|
||||||
// if no pressure is available (non-SGP), estimate based on altitude
|
|
||||||
pressure = 1013.25f * expf(-1.18575919e-4f * sonde.si()->d.alt );
|
|
||||||
}
|
|
||||||
|
|
||||||
float Tp = (sensorTemp - 20.0f) / 180.0f;
|
|
||||||
float sum = 0;
|
|
||||||
float powc = 1.0f;
|
|
||||||
float p = pressure / 1000.0f;
|
|
||||||
for ( int i = 0; i < 3; i++) {
|
|
||||||
float l = 0;
|
|
||||||
float powt = 1.0f;
|
|
||||||
for ( int j = 0; j < 4; j++) {
|
|
||||||
l += calibration->value.matrixBt[4*i+j] * powt;
|
|
||||||
powt *= Tp;
|
|
||||||
}
|
|
||||||
float x = calibration->value.vectorBp[i];
|
|
||||||
sum += l * (x * p / (1.0f + x * p) - x * powc / (1.0f + x));
|
|
||||||
powc *= Cp;
|
|
||||||
}
|
|
||||||
Cp -= sum;
|
|
||||||
|
|
||||||
float xj = 1.0f;
|
|
||||||
for ( int j = 0; j < 7; j++) {
|
|
||||||
float yk = 1.0f;
|
|
||||||
for ( int k = 0; k < 6; k++) {
|
|
||||||
sum += xj * yk * calibration->value.matrixU[j][k];
|
|
||||||
yk *= Tp;
|
|
||||||
}
|
|
||||||
xj *= Cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Since there is always a small difference between the temperature readings for
|
|
||||||
* the atmospheric (main) tempoerature sensor and the temperature sensor inside
|
|
||||||
* the humidity sensor device, transform the humidity value to the atmospheric conditions
|
|
||||||
* with its different water vapor saturation pressure.
|
|
||||||
*/
|
|
||||||
float RH = sum
|
|
||||||
* _RS41_waterVaporSaturationPressure(sensorTemp)
|
|
||||||
/ _RS41_waterVaporSaturationPressure(externalTemp);
|
|
||||||
|
|
||||||
return RH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns: 0: ok, -1: rs or crc error
|
|
||||||
int RS41::decode41(byte *data, int maxlen)
|
|
||||||
{
|
|
||||||
char buf[128];
|
|
||||||
int crcok = 1;
|
|
||||||
SondeData *si = &(sonde.si()->d);
|
|
||||||
|
|
||||||
int32_t corr = reedsolomon41(data, 560, 131); // try short frame first
|
|
||||||
if(corr<0) {
|
|
||||||
corr = reedsolomon41(data, 560, 230); // try long frame
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
Serial.print("RS result:");
|
|
||||||
Serial.print(corr);
|
|
||||||
Serial.println();
|
|
||||||
#endif
|
|
||||||
int p = 57; // 8 byte header, 48 byte RS
|
|
||||||
while(p<maxlen) { /* why 555? */
|
|
||||||
uint8_t typ = data[p++];
|
|
||||||
uint32_t len = data[p++]+2UL;
|
|
||||||
if(p+len>maxlen) break;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// DEBUG OUTPUT
|
|
||||||
Serial.print("@");
|
|
||||||
Serial.print(p-2);
|
|
||||||
Serial.print(": ID:");
|
|
||||||
Serial.print(typ, HEX);
|
|
||||||
Serial.print(", len=");
|
|
||||||
Serial.print(len);
|
|
||||||
Serial.print(": ");
|
|
||||||
for(int i=0; i<len-1; i++) {
|
|
||||||
char buf[3];
|
|
||||||
snprintf(buf, 4, "%02X|", data[p+i]);
|
|
||||||
Serial.print(buf);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// check CRC
|
|
||||||
if(!crcrs(data, 560, p, p+len)) {
|
|
||||||
Serial.println("###CRC ERROR###");
|
|
||||||
crcok = 0;
|
|
||||||
} else {
|
|
||||||
switch(typ) {
|
|
||||||
case 'y': // name
|
|
||||||
{
|
|
||||||
if(strncmp(si->id, (const char *)(data+p+2), 8)) {
|
|
||||||
// ID changed, i.e. new sonde on same frequency. clear calibration and all other data
|
|
||||||
sonde.clearAllData(sonde.si());
|
|
||||||
struct subframeBuffer *sub = (struct subframeBuffer *)sonde.si()->extra;
|
|
||||||
if(sub) { sub->valid = 0; }
|
|
||||||
}
|
|
||||||
Serial.print("#");
|
|
||||||
uint16_t fnr = data[p]+(data[p+1]<<8);
|
|
||||||
Serial.print(fnr);
|
|
||||||
si->vframe = si->frame = fnr;
|
|
||||||
Serial.print("; RS41 ID ");
|
|
||||||
snprintf(buf, 10, "%.8s ", data+p+2);
|
|
||||||
Serial.print(buf);
|
|
||||||
si->batteryVoltage = data[p+10] / 10.0f;
|
|
||||||
// not needed, if we end up here, the type has to be RS41.... si->type=STYPE_RS41;
|
|
||||||
strncpy(si->id, (const char *)(data+p+2), 8);
|
|
||||||
si->id[8]=0;
|
|
||||||
strncpy(si->ser, (const char *)(data+p+2), 8);
|
|
||||||
si->ser[8]=0;
|
|
||||||
si->validID=true;
|
|
||||||
int calnr = data[p+23];
|
|
||||||
// not sure about this
|
|
||||||
if(calnr==0x31) {
|
|
||||||
uint16_t bt = data[p+30] + 256*data[p+31];
|
|
||||||
si->burstKT = bt;
|
|
||||||
}
|
|
||||||
// this should be right...
|
|
||||||
if(calnr==0x02) {
|
|
||||||
uint16_t kt = data[p+31] + 256*data[p+32];
|
|
||||||
si->launchKT = kt;
|
|
||||||
}
|
|
||||||
// and this seems fine as well...
|
|
||||||
if(calnr==0x32) {
|
|
||||||
uint16_t cntdown = data[p+24] + (data[p+25]<<8);
|
|
||||||
uint16_t min = cntdown - (cntdown/3600)*3600;
|
|
||||||
Serial.printf("Countdown value: %d\n [%2d:%02d:%02d]", cntdown, cntdown/3600, min/60, min-(min/60)*60);
|
|
||||||
si->countKT = cntdown;
|
|
||||||
si->crefKT = fnr;
|
|
||||||
}
|
|
||||||
ProcessSubframe( data+p+24, calnr );
|
|
||||||
|
|
||||||
}
|
|
||||||
// TODO: some more data
|
|
||||||
break;
|
|
||||||
case '|': // date
|
|
||||||
{
|
|
||||||
uint32_t gpstime = getint32(data, 560, p+2);
|
|
||||||
uint16_t gpsweek = getint16(data, 560, p);
|
|
||||||
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
|
||||||
// one week = 7*24*60*60 = 604800 seconds
|
|
||||||
// unix epoch starts jan 1st 1970 0:00
|
|
||||||
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
|
||||||
// subtracting 86400 yields 315878400UL
|
|
||||||
si->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
|
||||||
si->validTime = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '{': // pos
|
|
||||||
posrs41(data+p, len, 0);
|
|
||||||
break;
|
|
||||||
case 'z': // 0x7a is character z - 7A-MEAS temperature and humidity frame
|
|
||||||
{
|
|
||||||
uint32_t tempMeasMain = getint24(data, 560, p+0);
|
|
||||||
uint32_t tempMeasRef1 = getint24(data, 560, p+3);
|
|
||||||
uint32_t tempMeasRef2 = getint24(data, 560, p+6);
|
|
||||||
uint32_t humidityMain = getint24(data, 560, p+9);
|
|
||||||
uint32_t humidityRef1 = getint24(data, 560, p+12);
|
|
||||||
uint32_t humidityRef2 = getint24(data, 560, p+15);
|
|
||||||
uint32_t tempHumiMain = getint24(data, 560, p+18);
|
|
||||||
uint32_t tempHumiRef1 = getint24(data, 560, p+21);
|
|
||||||
uint32_t tempHumiRef2 = getint24(data, 560, p+24);
|
|
||||||
uint32_t pressureMain = getint24(data, 560, p+27);
|
|
||||||
uint32_t pressureRef1 = getint24(data, 560, p+30);
|
|
||||||
uint32_t pressureRef2 = getint24(data, 560, p+33);
|
|
||||||
int16_t ptraw = getint16(data, 560, p+38);
|
|
||||||
#if 0
|
|
||||||
Serial.printf( "External temp: tempMeasMain = %ld, tempMeasRef1 = %ld, tempMeasRef2 = %ld\n", tempMeasMain, tempMeasRef1, tempMeasRef2 );
|
|
||||||
Serial.printf( "Rel Humidity: humidityMain = %ld, humidityRef1 = %ld, humidityRef2 = %ld\n", humidityMain, humidityRef1, humidityRef2 );
|
|
||||||
Serial.printf( "Humid sensor: tempHumiMain = %ld, tempHumiRef1 = %ld, tempHumiRef2 = %ld\n", tempHumiMain, tempHumiRef1, tempHumiRef2 );
|
|
||||||
Serial.printf( "Pressure sens: pressureMain = %ld, pressureRef1 = %ld, pressureRef2 = %ld\n", pressureMain, pressureRef1, pressureRef2 );
|
|
||||||
#endif
|
|
||||||
struct subframeBuffer *calibration = (struct subframeBuffer *)(sonde.si()->extra);
|
|
||||||
// temp: 0xF8==bits 3..7 : we need refResistorlow/high, taylorT, polyT
|
|
||||||
bool validExternalTemperature = calibration!=NULL && (calibration->valid & 0xF8) == 0xF8;
|
|
||||||
|
|
||||||
// humidity: bits 3..20 and 37..46. and bit 33 (variant)
|
|
||||||
bool validHumidity = calibration!=NULL && (calibration->valid & 0x7FE2001FFFF8) == 0x7FE2001FFFF8;
|
|
||||||
|
|
||||||
// pressure: bits 33 and 37..42 (variant; x25..x2a: matrixP) /// CALIB_P is 0x7E200000000)
|
|
||||||
bool validPressure = calibration!=NULL && (calibration->valid & CALIB_P)==CALIB_P && calibration->value.names.variant[7]=='P';
|
|
||||||
|
|
||||||
if ( validPressure ) {
|
|
||||||
si->pressure = GetRAP( pressureMain, pressureRef1, pressureRef2, ptraw );
|
|
||||||
Serial.printf("Pressure sensor = %f\n", si->pressure);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( validExternalTemperature ) {
|
|
||||||
si->temperature = GetRATemp( tempMeasMain, tempMeasRef1, tempMeasRef2,
|
|
||||||
calibration->value.calT, calibration->value.taylorT, calibration->value.polyT );
|
|
||||||
Serial.printf("External temperature = %f\n", si->temperature );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( validHumidity && validExternalTemperature ) {
|
|
||||||
si->tempRHSensor = GetRATemp( tempHumiMain, tempHumiRef1, tempHumiRef2,
|
|
||||||
calibration->value.calTU, calibration->value.taylorTU, calibration->value.polyTrh );
|
|
||||||
Serial.printf("Humidity Sensor temperature = %f\n", si->tempRHSensor );
|
|
||||||
si->relativeHumidity = GetRAHumidity( humidityMain, humidityRef1, humidityRef2, si->tempRHSensor, si->temperature, si->pressure );
|
|
||||||
Serial.printf("Relative humidity = %f\n", si->relativeHumidity );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}}
|
|
||||||
p += len;
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
return crcok ? 0 : RX_ERROR;
|
|
||||||
}
|
|
||||||
void RS41::printRaw(uint8_t *data, int len)
|
|
||||||
{
|
|
||||||
char buf[3];
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len; i++) {
|
|
||||||
snprintf(buf, 3, "%02X", data[i]);
|
|
||||||
Serial.print(buf);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RS41::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len*4; i++) {
|
|
||||||
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
|
||||||
}
|
|
||||||
bytes[(i-1)/8] &= 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char lookup[16] = {
|
|
||||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
|
||||||
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };
|
|
||||||
|
|
||||||
static uint8_t reverse(uint8_t n) {
|
|
||||||
return (lookup[n&0x0f] << 4) | lookup[n>>4];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t scramble[64] = {150U,131U,62U,81U,177U,73U,8U,152U,50U,5U,89U,
|
|
||||||
14U,249U,68U,198U,38U,33U,96U,194U,234U,121U,93U,109U,161U,
|
|
||||||
84U,105U,71U,12U,220U,232U,92U,241U,247U,118U,130U,127U,7U,
|
|
||||||
153U,162U,44U,147U,124U,48U,99U,245U,16U,46U,97U,208U,188U,
|
|
||||||
180U,182U,6U,170U,244U,35U,120U,110U,59U,174U,191U,123U,76U,
|
|
||||||
193U};
|
|
||||||
|
|
||||||
|
|
||||||
int RS41::receive() {
|
|
||||||
sx1278.setPayloadLength(RS41MAXLEN-8);
|
|
||||||
int e = sx1278.receivePacketTimeout(1000, data+8);
|
|
||||||
#if 1
|
|
||||||
if(e) { /*Serial.println("TIMEOUT");*/ return RX_TIMEOUT; }
|
|
||||||
|
|
||||||
for(int i=0; i<RS41MAXLEN; i++) { data[i] = reverse(data[i]); }
|
|
||||||
for(int i=0; i<RS41MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
|
|
||||||
return decode41(data, RS41MAXLEN);
|
|
||||||
#else
|
|
||||||
// FAKE testing data
|
|
||||||
SondeInfo *si = sonde.si();
|
|
||||||
si->lat = 48;
|
|
||||||
si->lon = -100;
|
|
||||||
si->alt = 30000;
|
|
||||||
si->vs = 3.4;
|
|
||||||
si->validPos = 0x7f;
|
|
||||||
si->validID = 1;
|
|
||||||
strcpy(si->id, "A1234");
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int RS41::waitRXcomplete() {
|
|
||||||
// Currently not used. can be used for additinoal post-processing
|
|
||||||
// (required for RS92 to avoid FIFO overrun in rx task)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy variant string to buf (max buflen chars; buflen should be 11
|
|
||||||
// return 0 if subtype is available, -1 if not
|
|
||||||
int RS41::getSubtype(char *buf, int buflen, SondeInfo *si) {
|
|
||||||
struct subframeBuffer *sf = (struct subframeBuffer *)si->extra;
|
|
||||||
if(!sf) return -1;
|
|
||||||
if( ( (sf->valid>>0x21) &3) != 3 ) return -1; // or 1 instead of 3 for the first 8 chars only, as in autorx?
|
|
||||||
if(buflen>11) buflen=11; // then buflen should be capped at 9 (8+trailing \0)
|
|
||||||
strncpy(buf, sf->value.names.variant, buflen);
|
|
||||||
buf[buflen-1]=0;
|
|
||||||
if(*buf==0) return -1;
|
|
||||||
Serial.printf("subframe valid: %x%08x; subtype=%s\n", (uint32_t)(sf->valid>>32), (uint32_t)sf->valid, buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
RS41 rs41 = RS41();
|
|
|
@ -1,207 +0,0 @@
|
||||||
#include "Scanner.h"
|
|
||||||
|
|
||||||
#include <U8x8lib.h>
|
|
||||||
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
#include "Display.h"
|
|
||||||
|
|
||||||
|
|
||||||
double STARTF;
|
|
||||||
|
|
||||||
|
|
||||||
struct scancfg {
|
|
||||||
int PLOT_W; // Width of plot, in pixel
|
|
||||||
int PLOT_H8; // Height of plot, in 8 pixel units
|
|
||||||
int TICK1; // Pixel per MHz marker
|
|
||||||
int TICK2; // Pixel per sub-Mhz marker (250k or 200k)
|
|
||||||
double CHANSTEP; // Scanner frequenz steps
|
|
||||||
int SMPL_PIX; // Frequency steps per pixel
|
|
||||||
int NCHAN; // number of channels to scan, PLOT_W * SMPL_PIX
|
|
||||||
int SMOOTH;
|
|
||||||
int ADDWAIT;
|
|
||||||
int VSCALE;
|
|
||||||
};
|
|
||||||
|
|
||||||
//struct scancfg scanLCD={ 121, 7, 120/6, 120/6/4, 6000.0/120.0/20.0, 20, 120*20, 1 };
|
|
||||||
struct scancfg scanLCD={ 121, 7, 120/6, 120/6/4, 6000.0/120.0/10.0, 10, 120*10, 2, 40, 1 };
|
|
||||||
struct scancfg scanTFT={ 210, 16, 210/6, 210/6/5, 6000.0/210.0/10.0, 10, 210*10, 1, 0, 1 };
|
|
||||||
struct scancfg scan934x={ 300, 22, 300/6, 300/6/5, 6000.0/300.0/7.0, 7, 300*5, 1, 10, 2 };
|
|
||||||
|
|
||||||
struct scancfg &scanconfig = scanTFT;
|
|
||||||
|
|
||||||
#define CHANBW 12500
|
|
||||||
//#define PIXSAMPL (50/CHANBW)
|
|
||||||
//#define STARTF 401000000
|
|
||||||
|
|
||||||
// max of 120*5 and 210*3
|
|
||||||
//#define MAXN 210*10
|
|
||||||
//#define MAXN 120*20
|
|
||||||
#define MAXN 300*10
|
|
||||||
|
|
||||||
// max of 120 and 210 (ceil(210/8)*8)) -- now ceil(300/8)*8
|
|
||||||
//#define MAXDISP 216
|
|
||||||
#define MAXDISP 304
|
|
||||||
|
|
||||||
int scanresult[MAXN];
|
|
||||||
int scandisp[MAXDISP];
|
|
||||||
double peakf=0;
|
|
||||||
|
|
||||||
//#define PLOT_MIN -250
|
|
||||||
#define PLOT_MIN (sonde.config.noisefloor*2)
|
|
||||||
#define PLOT_SCALE(x) (x<PLOT_MIN?0:(x-PLOT_MIN)/2)
|
|
||||||
|
|
||||||
const byte tilepatterns[9]={0,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};
|
|
||||||
void Scanner::fillTiles(uint8_t *row, int value) {
|
|
||||||
for(int y=0; y<scanconfig.PLOT_H8; y++) {
|
|
||||||
int nbits = scanconfig.VSCALE*value - 8*(scanconfig.PLOT_H8-1-y);
|
|
||||||
if(nbits<0) { row[8*y]=0; continue; }
|
|
||||||
if(nbits>=8) { row[8*y]=255; continue; }
|
|
||||||
row[8*y] = tilepatterns[nbits];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* LCD:
|
|
||||||
* There are 16*8 columns to plot, NPLOT must be lower than that
|
|
||||||
* currently, we use 128 * 50kHz channels
|
|
||||||
* There are 8*8 values to plot; MIN is bottom end,
|
|
||||||
* TFT:
|
|
||||||
* There are 210 columns to plot
|
|
||||||
* Currently we use 210 * (6000/120)kHz channels, i.e. 28.5714kHz
|
|
||||||
*/
|
|
||||||
///// unused???? uint8_t tiles[16] = { 0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0, 1, 3, 7, 15, 31, 63, 127, 255};
|
|
||||||
|
|
||||||
// type 0: lcd, 1: tft(ILI9225), 2: lcd(sh1106) 3:TFT(ili9341), 4: TFT(ili9342)
|
|
||||||
#define ISTFT (sonde.config.disptype!=0 && sonde.config.disptype!=2)
|
|
||||||
void Scanner::plotResult()
|
|
||||||
{
|
|
||||||
int yofs = 0;
|
|
||||||
char buf[30];
|
|
||||||
if(ISTFT) {
|
|
||||||
yofs = 2;
|
|
||||||
if (sonde.config.marker != 0) {
|
|
||||||
itoa((sonde.config.startfreq), buf, 10);
|
|
||||||
disp.rdis->drawString(0, 1, buf);
|
|
||||||
disp.rdis->drawString(scanconfig.PLOT_W/2-10, 1, "MHz");
|
|
||||||
itoa((sonde.config.startfreq + 6), buf, 10);
|
|
||||||
disp.rdis->drawString(scanconfig.PLOT_W-15, 1, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (sonde.config.marker != 0) {
|
|
||||||
itoa((sonde.config.startfreq), buf, 10);
|
|
||||||
disp.rdis->drawString(0, 1, buf);
|
|
||||||
disp.rdis->drawString(7, 1, "MHz");
|
|
||||||
itoa((sonde.config.startfreq + 6), buf, 10);
|
|
||||||
disp.rdis->drawString(13, 1, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint8_t row[scanconfig.PLOT_H8*8];
|
|
||||||
for(int i=0; i<scanconfig.PLOT_W; i+=8) {
|
|
||||||
for(int j=0; j<8; j++) {
|
|
||||||
fillTiles(row+j, PLOT_SCALE(scandisp[i+j]));
|
|
||||||
if( (i+j)>=scanconfig.PLOT_W ) { for(int y=0; y<scanconfig.PLOT_H8; y++) row[j+8*y]=0; }
|
|
||||||
if( ((i+j)%scanconfig.TICK1)==0) { row[j] |= 0x07; }
|
|
||||||
if( ((i+j)%scanconfig.TICK2)==0) { row[j] |= 0x01; }
|
|
||||||
}
|
|
||||||
for(int y=0; y<scanconfig.PLOT_H8; y++) {
|
|
||||||
if(sonde.config.marker && y==1 && !ISTFT ) {
|
|
||||||
// don't overwrite MHz marker text
|
|
||||||
if(i<3*8 || (i>=7*8&&i<10*8) || i>=13*8) continue;
|
|
||||||
}
|
|
||||||
disp.rdis->drawTile(i/8, y+yofs, 1, row+8*y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ISTFT) { // large TFT
|
|
||||||
sprintf(buf, "Peak: %03.3f MHz", peakf*0.000001);
|
|
||||||
disp.rdis->drawString(0, (yofs+scanconfig.PLOT_H8+1)*8, buf);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "Peak: %03.3fMHz", peakf*0.000001);
|
|
||||||
disp.rdis->drawString(0, 7, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scanner::scan()
|
|
||||||
{
|
|
||||||
if(!ISTFT) { // LCD small
|
|
||||||
scanconfig = scanLCD;
|
|
||||||
} else if (sonde.config.disptype==1) {
|
|
||||||
scanconfig = scanTFT;
|
|
||||||
} else {
|
|
||||||
scanconfig = scan934x;
|
|
||||||
}
|
|
||||||
// Configure
|
|
||||||
STARTF = (sonde.config.startfreq * 1000000);
|
|
||||||
sx1278.writeRegister(REG_PLL_HOP, 0x80); // FastHopOn
|
|
||||||
sx1278.setRxBandwidth((int)(scanconfig.CHANSTEP*1000));
|
|
||||||
double bw = sx1278.getRxBandwidth();
|
|
||||||
Serial.print("RX Bandwith for scan: "); Serial.println(bw);
|
|
||||||
sx1278.writeRegister(REG_RSSI_CONFIG, scanconfig.SMOOTH&0x07);
|
|
||||||
sx1278.setFrequency(STARTF);
|
|
||||||
Serial.print("Start freq = "); Serial.println(STARTF);
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
|
|
||||||
unsigned long start = millis();
|
|
||||||
uint32_t lastfrf= STARTF * (1<<19) / SX127X_CRYSTAL_FREQ;
|
|
||||||
float freq = STARTF;
|
|
||||||
int wait = scanconfig.ADDWAIT + 20 + 1000*(1<<(scanconfig.SMOOTH+1))/4/(0.001*CHANBW);
|
|
||||||
Serial.print("wait time (us) is: "); Serial.println(wait);
|
|
||||||
for(int iter=0; iter<3; iter++) { // three interations, to catch all RS41 transmissions
|
|
||||||
delayMicroseconds(20000); yield();
|
|
||||||
for(int i=0; i<scanconfig.PLOT_W*scanconfig.SMPL_PIX; i++) {
|
|
||||||
freq = STARTF + 1000.0*i*scanconfig.CHANSTEP;
|
|
||||||
//freq = 404000000 + 100*i*scanconfig.CHANSTEP;
|
|
||||||
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
|
|
||||||
if( (lastfrf>>16)!=(frf>>16) ) {
|
|
||||||
sx1278.writeRegister(REG_FRF_MSB, (frf&0xff0000)>>16);
|
|
||||||
}
|
|
||||||
if( ((lastfrf&0x00ff00)>>8) != ((frf&0x00ff00)>>8) ) {
|
|
||||||
sx1278.writeRegister(REG_FRF_MID, (frf&0x00ff00)>>8);
|
|
||||||
}
|
|
||||||
sx1278.writeRegister(REG_FRF_LSB, (frf&0x0000ff));
|
|
||||||
lastfrf = frf;
|
|
||||||
// Wait TS_HOP (20us) + TS_RSSI ( 2^(scacconfig.SMOOTH+1) / 4 / CHANBW us)
|
|
||||||
delayMicroseconds(wait);
|
|
||||||
int rssi = -(int)sx1278.readRegister(REG_RSSI_VALUE_FSK);
|
|
||||||
if(iter==0) { scanresult[i] = rssi; } else {
|
|
||||||
if(rssi>scanresult[i]) scanresult[i]=rssi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yield();
|
|
||||||
unsigned long duration = millis()-start;
|
|
||||||
Serial.print("wait: ");
|
|
||||||
Serial.println(wait);
|
|
||||||
Serial.print("Scan time: ");
|
|
||||||
Serial.println(duration);
|
|
||||||
Serial.print("Final freq: ");
|
|
||||||
Serial.println(freq);
|
|
||||||
int peakidx=-1;
|
|
||||||
int peakres=-9999;
|
|
||||||
for(int i=0; i<scanconfig.PLOT_W; i+=1) {
|
|
||||||
int r=scanresult[i*scanconfig.SMPL_PIX];
|
|
||||||
if(r>peakres+1) { peakres=r; peakidx=i*scanconfig.SMPL_PIX; }
|
|
||||||
scandisp[i] = r;
|
|
||||||
for(int j=1; j<scanconfig.SMPL_PIX; j++) {
|
|
||||||
r = scanresult[i*scanconfig.SMPL_PIX+j];
|
|
||||||
scandisp[i]+=r;
|
|
||||||
if(r>peakres+1) { peakres=r; peakidx=i*scanconfig.SMPL_PIX+j; }
|
|
||||||
}
|
|
||||||
//for(int j=1; j<PIXSAMPL; j++) { if(scanresult[i+j]>scandisp[i/PIXSAMPL]) scandisp[i/PIXSAMPL] = scanresult[i+j]; }
|
|
||||||
Serial.print(scanresult[i]); Serial.print(", ");
|
|
||||||
}
|
|
||||||
peakidx--;
|
|
||||||
double newpeakf = STARTF + scanconfig.CHANSTEP*1000.0*peakidx;
|
|
||||||
if(newpeakf<peakf-20000 || newpeakf>peakf+20000) peakf=newpeakf; // different frequency
|
|
||||||
else if (newpeakf < peakf) peakf = 0.75*newpeakf + 0.25*peakf; // averaging on frequency, some bias towards lower...
|
|
||||||
else peakf = 0.25*newpeakf + 0.75*peakf;
|
|
||||||
Serial.println("\n");
|
|
||||||
for(int i=0; i<scanconfig.PLOT_W; i++) {
|
|
||||||
scandisp[i]/=scanconfig.SMPL_PIX;
|
|
||||||
Serial.print(scandisp[i]); Serial.print(", ");
|
|
||||||
}
|
|
||||||
Serial.println("\n");
|
|
||||||
Serial.print("Peak: ");
|
|
||||||
Serial.print(peakf);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scanner scanner = Scanner();
|
|
|
@ -1,247 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#include "ShFreqImport.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
static int ppos;
|
|
||||||
static int quotes;
|
|
||||||
static char id[20];
|
|
||||||
static int idpos;
|
|
||||||
static float lat, lon, freq;
|
|
||||||
static char type[20];
|
|
||||||
|
|
||||||
static uint8_t inuse[1+99/8]; // MAXSONDE is 99
|
|
||||||
|
|
||||||
static char keyword[40];
|
|
||||||
static int keywordpos;
|
|
||||||
static char value[40];
|
|
||||||
static int valuepos;
|
|
||||||
|
|
||||||
static int importState;
|
|
||||||
static float homelat, homelon;
|
|
||||||
|
|
||||||
|
|
||||||
// Map SondeHub type string to Stype. -1 for not supported types.
|
|
||||||
int ShFreqImport::stringToStype(const char *type) {
|
|
||||||
if(type[2]=='4') return STYPE_RS41;
|
|
||||||
if(type[2]=='9') return STYPE_RS92;
|
|
||||||
if(type[1]=='1') return STYPE_M10M20;
|
|
||||||
if(type[1]=='2') return STYPE_M10M20;
|
|
||||||
if(type[0]=='D') return STYPE_DFM;
|
|
||||||
if(type[2]=='3') return STYPE_MP3H; // TODO: check if '3' is correct
|
|
||||||
return -1; // iMet is not supported
|
|
||||||
}
|
|
||||||
|
|
||||||
// in Display.cpp
|
|
||||||
extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2);
|
|
||||||
|
|
||||||
void ShFreqImport::setLabel(int idx, char *id, float lat, float lon) {
|
|
||||||
snprintf(sonde.sondeList[idx].launchsite, 18, "@%s/%d", id, (int)(calcLatLonDist(homelat, homelon, lat, lon)/1000));
|
|
||||||
sonde.sondeList[idx].launchsite[17] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShFreqImport::usekeyvalue() {
|
|
||||||
if(strcmp(keyword,"lat")==0) lat = atof(value);
|
|
||||||
if(strcmp(keyword,"lon")==0) lon = atof(value);
|
|
||||||
if(strcmp(keyword,"frequency")==0) { if(isnan(freq)) freq = atof(value); } // prefer tx_frequency if available
|
|
||||||
if(strcmp(keyword,"tx_frequency")==0) freq = atof(value);
|
|
||||||
if(strcmp(keyword,"type")==0) strcpy(type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* populate qrg.txt with frequency of near sonde */
|
|
||||||
void ShFreqImport::populate(char *id, float lat, float lon, float freq, const char *type)
|
|
||||||
{
|
|
||||||
//printf(" ID %s: %.5f, %.5f f=%.3f, type=%s \n", id, lat, lon, freq, type);
|
|
||||||
// Skip if freq already exists
|
|
||||||
int stype = stringToStype(type);
|
|
||||||
if(stype<0) return; // unsupported type
|
|
||||||
|
|
||||||
// check if frequency exists already
|
|
||||||
// don't do anything if its a static entry
|
|
||||||
// update label if its a dynamic SH entry
|
|
||||||
int i;
|
|
||||||
for(i=0; i<sonde.config.maxsonde; i++) {
|
|
||||||
if( abs(sonde.sondeList[i].freq-freq)<0.003 ) { // exists already, max error 3000 Hz
|
|
||||||
Serial.printf("id %s close to %d\n", id, i);
|
|
||||||
if( sonde.sondeList[i].type == stype) {
|
|
||||||
char *l = sonde.sondeList[i].launchsite;
|
|
||||||
if( *l=='@' || *l==' ' || *l==0 ) {
|
|
||||||
setLabel(i, id, lat, lon);
|
|
||||||
inuse[i/8] |= (1<<(i&7));
|
|
||||||
}
|
|
||||||
sonde.sondeList[i].active = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find slot
|
|
||||||
// slots with empty launchsite are considered available for automated entries
|
|
||||||
while(ppos < sonde.config.maxsonde) {
|
|
||||||
if( *sonde.sondeList[ppos].launchsite==' ' || *sonde.sondeList[ppos].launchsite== 0 ) break;
|
|
||||||
ppos++;
|
|
||||||
}
|
|
||||||
if(ppos >= sonde.config.maxsonde) {
|
|
||||||
Serial.println("populate: out of free slots");
|
|
||||||
return;
|
|
||||||
} // no more free slots
|
|
||||||
|
|
||||||
sonde.clearAllData(&sonde.sondeList[ppos]);
|
|
||||||
sonde.sondeList[ppos].active = 1;
|
|
||||||
sonde.sondeList[ppos].freq = freq;
|
|
||||||
sonde.sondeList[ppos].type = (SondeType)stype;
|
|
||||||
setLabel(ppos, id, lat, lon);
|
|
||||||
inuse[ppos/8] |= (1<<(ppos&7));
|
|
||||||
ppos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clears all remaining automatically filled slots (no longer in SH data)
|
|
||||||
void ShFreqImport::cleanup() {
|
|
||||||
//Serial.println("Cleanup called ********");
|
|
||||||
for(int i=0; i<sonde.config.maxsonde; i++) {
|
|
||||||
if( (((inuse[i/8]>>(i&7))&1) == 0) && *sonde.sondeList[i].launchsite=='@' ) {
|
|
||||||
// Don't remove the currently active entry
|
|
||||||
if(i==sonde.currentSonde) continue;
|
|
||||||
Serial.printf("removing #%d\n", i);
|
|
||||||
sonde.sondeList[i].launchsite[0] = 0;
|
|
||||||
sonde.sondeList[i].active = 0;
|
|
||||||
sonde.sondeList[i].freq = 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BUFLEN 128
|
|
||||||
#define VALLEN 20
|
|
||||||
int ShFreqImport::handleChar(char c) {
|
|
||||||
Serial.print(c);
|
|
||||||
switch(importState) {
|
|
||||||
case START:
|
|
||||||
// wait for initial '{'
|
|
||||||
if(c=='{') {
|
|
||||||
Serial.println("{ found");
|
|
||||||
importState++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BEFOREID:
|
|
||||||
// what for first '"' in { "A1234567" : { ... } }; or detect end
|
|
||||||
if(c=='"') { idpos = 0; lat = NAN; lon = NAN; freq = NAN; *type = 0; importState++; }
|
|
||||||
if(c=='}') {
|
|
||||||
importState = ENDREACHED;
|
|
||||||
cleanup();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COPYID:
|
|
||||||
// copy ID "A1234567" until second '"' is earched
|
|
||||||
if(c=='"') { id[idpos] = 0; importState++; }
|
|
||||||
else id[idpos++] = c;
|
|
||||||
break;
|
|
||||||
case AFTERID:
|
|
||||||
// wait for '{' in '"A1234567": { ...'
|
|
||||||
if(c=='{') importState++;
|
|
||||||
break;
|
|
||||||
case BEFOREKEY:
|
|
||||||
if(c=='"') { keywordpos = 0; importState++; }
|
|
||||||
break;
|
|
||||||
case COPYKEY:
|
|
||||||
if(c=='"') { importState++; keyword[keywordpos] = 0; /* printf("Key: >%s<\n", keyword);*/ }
|
|
||||||
else keyword[keywordpos++] = c;
|
|
||||||
break;
|
|
||||||
case AFTERKEY:
|
|
||||||
if(c==':') {
|
|
||||||
valuepos = 0;
|
|
||||||
quotes = 0;
|
|
||||||
if(strcmp(keyword,"lat")==0 || strcmp(keyword, "lon")==0 || strcmp(keyword, "frequency")==0 || strcmp(keyword, "tx_frequency")==0)
|
|
||||||
importState = BEFORENUMVAL;
|
|
||||||
else {
|
|
||||||
if (strcmp(keyword, "type")==0)
|
|
||||||
importState = BEFORESTRINGVAL;
|
|
||||||
else
|
|
||||||
importState = SKIPVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BEFORENUMVAL:
|
|
||||||
if( (c>='0'&&c<='9') || c=='-') { value[0] = c; valuepos=1; importState++; }
|
|
||||||
break;
|
|
||||||
case COPYNUMVAL:
|
|
||||||
if( !(c>='0'&&c<='9') && c!='-' && c!='.' ) {
|
|
||||||
value[valuepos]=0; importState=SKIPVAL; usekeyvalue();
|
|
||||||
if(c!=',' && c!='}') break;
|
|
||||||
}
|
|
||||||
else { value[valuepos++] = c; break; }
|
|
||||||
// intenionall fall-through
|
|
||||||
case SKIPVAL:
|
|
||||||
// This is rather fragile, we *should* handle more escaping and so on but do not do so so far, only simple quotes
|
|
||||||
if(c=='"') quotes = !quotes;
|
|
||||||
if(quotes) break;
|
|
||||||
if(c==',') importState = BEFOREKEY;
|
|
||||||
if(c=='}') {
|
|
||||||
// we have an ID and all key/value pairs, check if its good....
|
|
||||||
if( !isnan(lat) && !isnan(lon) && !isnan(freq) && type[0] ) {
|
|
||||||
printf("SondeHub import: populate %s %f %f %f %s\n", id, lat, lon, freq, type);
|
|
||||||
populate(id, lat, lon, freq, type);
|
|
||||||
} else {
|
|
||||||
printf("Skipping incomplete %s\n", id);
|
|
||||||
}
|
|
||||||
importState = ENDORNEXT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BEFORESTRINGVAL:
|
|
||||||
if(c=='"') importState++;
|
|
||||||
break;
|
|
||||||
case COPYSTRINGVAL:
|
|
||||||
if(c=='"') { importState=SKIPVAL; value[valuepos]=0; usekeyvalue(); }
|
|
||||||
else value[valuepos++] = c;
|
|
||||||
break;
|
|
||||||
case ENDORNEXT:
|
|
||||||
// next we have to see either a final "}', or a comma before the next id
|
|
||||||
if(c==',') importState = BEFOREID;
|
|
||||||
else if (c=='}') { importState = ENDREACHED; cleanup(); return 1; }
|
|
||||||
break;
|
|
||||||
case ENDREACHED:
|
|
||||||
Serial.println("REPLY: END REACHED");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lat lon in deg, dist in km, time in minutes
|
|
||||||
int ShFreqImport::shImportSendRequest(WiFiClient *client, float lat, float lon, int dist, int time) {
|
|
||||||
if(!client->connected()) {
|
|
||||||
if(!client->connect(sonde.config.sondehub.host, 80)) {
|
|
||||||
Serial.println("Connection FAILED");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println("Sending SondeHub import request");
|
|
||||||
char req[300];
|
|
||||||
snprintf(req, 200, "GET /sondes?lat=%f&lon=%f&distance=%d&last=%d HTTP/1.1\r\n"
|
|
||||||
"Host: %s\r\n"
|
|
||||||
"Accept: application/json\r\n"
|
|
||||||
"Cache-Control: no-cache\r\n\r\n",
|
|
||||||
lat, lon, dist*1000, time*60, sonde.config.sondehub.host);
|
|
||||||
client->print(req);
|
|
||||||
Serial.print(req);
|
|
||||||
importState = START;
|
|
||||||
homelat = lat;
|
|
||||||
homelon = lon;
|
|
||||||
memset(inuse, 0, sizeof(inuse));
|
|
||||||
ppos = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return 0 if more data should be read (later), 1 if finished (close connection...)
|
|
||||||
int ShFreqImport::shImportHandleReply(WiFiClient *client) {
|
|
||||||
if(!client->connected()) return 1;
|
|
||||||
while(client->available()) {
|
|
||||||
int res = handleChar(client->read());
|
|
||||||
if(res) return res;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
#ifndef SH_FREQ_IMPORT_
|
|
||||||
#define SH_FREQ_IMPORT_H
|
|
||||||
// Automated frequency import from SondeHub
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
enum ImportState { START, BEFOREID, COPYID, AFTERID, BEFOREKEY, COPYKEY, AFTERKEY, SKIPVAL, BEFORENUMVAL, COPYNUMVAL, BEFORESTRINGVAL, COPYSTRINGVAL, AFTERPAYLOAD, ENDORNEXT, ENDREACHED };
|
|
||||||
|
|
||||||
class ShFreqImport {
|
|
||||||
public:
|
|
||||||
// Fetch data from sondehub and populate qrg.txt with result
|
|
||||||
// return: 0: ok; 1: failure
|
|
||||||
static int shImportSendRequest(WiFiClient *client, float lat, float lon, int dist, int time);
|
|
||||||
|
|
||||||
// return 0: ok, need more data; 1: finished/failure, close connection
|
|
||||||
// Asynchronous I/O. Handle data if available
|
|
||||||
static int shImportHandleReply(WiFiClient *client);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static int stringToStype(const char *type);
|
|
||||||
static void setLabel(int idx, char *id, float lat, float lon);
|
|
||||||
static void usekeyvalue();
|
|
||||||
static int handleChar(char c);
|
|
||||||
|
|
||||||
// add one entry on available slot at or after ppos
|
|
||||||
static void populate(char *id, float lat, float lon, float freq, const char *type);
|
|
||||||
static void cleanup();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,495 +0,0 @@
|
||||||
const uint8_t FreeMono12pt8bBitmaps[] PROGMEM = {
|
|
||||||
0x00, 0xDB, 0x6D, 0x92, 0x48, 0x01, 0xB8, 0xF7, 0x67, 0x67, 0x67, 0x66,
|
|
||||||
0x66, 0x62, 0x00, 0x02, 0x40, 0x90, 0x44, 0x11, 0x04, 0x87, 0xFC, 0x48,
|
|
||||||
0x12, 0x04, 0x87, 0xF8, 0x48, 0x12, 0x04, 0x81, 0x20, 0x48, 0x12, 0x00,
|
|
||||||
0x08, 0x04, 0x0F, 0x0C, 0x6C, 0x14, 0x02, 0x00, 0xC0, 0x1E, 0x00, 0x80,
|
|
||||||
0x30, 0x18, 0x17, 0x18, 0x70, 0x10, 0x08, 0x04, 0x00, 0x18, 0x19, 0x04,
|
|
||||||
0x21, 0x08, 0x44, 0x0F, 0x00, 0x0C, 0x1C, 0x78, 0x20, 0xC0, 0xC8, 0x22,
|
|
||||||
0x08, 0x42, 0x20, 0x78, 0x3E, 0x40, 0x40, 0x40, 0x20, 0x60, 0x91, 0x8A,
|
|
||||||
0x8A, 0x86, 0x86, 0x7B, 0xFF, 0x6D, 0xB0, 0x01, 0x26, 0x44, 0xCC, 0xCC,
|
|
||||||
0xCC, 0x44, 0x62, 0x31, 0x13, 0x24, 0xC9, 0x24, 0x92, 0xD6, 0x90, 0x00,
|
|
||||||
0x04, 0x02, 0x11, 0x17, 0xF0, 0xC0, 0x50, 0x4C, 0x42, 0x00, 0x04, 0x00,
|
|
||||||
0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x3F, 0xF8, 0x20, 0x04, 0x00, 0x80,
|
|
||||||
0x10, 0x02, 0x00, 0x3B, 0x9C, 0xC4, 0x60, 0xFF, 0xE0, 0x6F, 0x70, 0x00,
|
|
||||||
0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x06,
|
|
||||||
0x02, 0x01, 0x01, 0x00, 0x80, 0x80, 0x40, 0x00, 0x1C, 0x33, 0x10, 0x50,
|
|
||||||
0x28, 0x14, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x2C, 0x12, 0x18,
|
|
||||||
0xF8, 0x18, 0x1C, 0x1A, 0x19, 0x08, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04,
|
|
||||||
0x02, 0x01, 0x00, 0x80, 0x43, 0xFE, 0x1E, 0x11, 0x90, 0x38, 0x10, 0x08,
|
|
||||||
0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x07, 0xFE, 0x1E,
|
|
||||||
0x08, 0x64, 0x08, 0x02, 0x00, 0x80, 0x20, 0x70, 0x1C, 0x00, 0x80, 0x10,
|
|
||||||
0x04, 0x01, 0x00, 0x70, 0x23, 0xF0, 0x06, 0x0A, 0x0A, 0x12, 0x12, 0x22,
|
|
||||||
0x62, 0x42, 0x82, 0x82, 0xFF, 0x02, 0x02, 0x02, 0x0F, 0x3F, 0x08, 0x22,
|
|
||||||
0x00, 0x80, 0x20, 0x08, 0x03, 0xF0, 0x02, 0x00, 0x40, 0x10, 0x04, 0x01,
|
|
||||||
0x00, 0xD0, 0x23, 0xF0, 0x07, 0x8E, 0x0C, 0x0C, 0x04, 0x02, 0x02, 0x31,
|
|
||||||
0x66, 0xA0, 0xE0, 0x60, 0x28, 0x14, 0x09, 0x08, 0x7C, 0xFF, 0x81, 0x81,
|
|
||||||
0x01, 0x01, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08,
|
|
||||||
0x1C, 0x31, 0x20, 0x50, 0x28, 0x14, 0x09, 0x08, 0x78, 0x43, 0x40, 0xA0,
|
|
||||||
0x30, 0x18, 0x16, 0x09, 0xF8, 0x1C, 0x31, 0x10, 0x50, 0x18, 0x0C, 0x05,
|
|
||||||
0x06, 0x87, 0x3E, 0x80, 0x40, 0x20, 0x20, 0x30, 0x33, 0xF0, 0x7F, 0x70,
|
|
||||||
0x00, 0x06, 0xF7, 0x39, 0xCE, 0x00, 0x00, 0x07, 0x73, 0x98, 0xCC, 0x00,
|
|
||||||
0x00, 0xC0, 0x60, 0x18, 0x0C, 0x06, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03,
|
|
||||||
0x00, 0x30, 0x01, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xC0, 0x06,
|
|
||||||
0x00, 0x30, 0x01, 0x80, 0x18, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x02,
|
|
||||||
0x00, 0x00, 0x3C, 0x61, 0xA0, 0x40, 0x10, 0x08, 0x08, 0x08, 0x18, 0x08,
|
|
||||||
0x04, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x3C, 0x62, 0xC1, 0x81, 0x81, 0x87,
|
|
||||||
0x99, 0x91, 0x91, 0x91, 0x8F, 0x81, 0x80, 0x80, 0x40, 0x3F, 0x1F, 0x00,
|
|
||||||
0x0C, 0x00, 0x48, 0x01, 0x20, 0x04, 0x80, 0x21, 0x00, 0x84, 0x02, 0x08,
|
|
||||||
0x1F, 0xE0, 0x40, 0x81, 0x01, 0x08, 0x04, 0x20, 0x13, 0xE1, 0xF0, 0x7E,
|
|
||||||
0x02, 0x1C, 0x20, 0x62, 0x02, 0x20, 0x22, 0x06, 0x3F, 0x82, 0x1C, 0x20,
|
|
||||||
0x22, 0x01, 0x20, 0x12, 0x01, 0x20, 0x2F, 0xFC, 0x1E, 0x06, 0x39, 0x01,
|
|
||||||
0x40, 0x28, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x20,
|
|
||||||
0x16, 0x04, 0x3F, 0x00, 0x7C, 0x08, 0x71, 0x01, 0x20, 0x14, 0x02, 0x80,
|
|
||||||
0x50, 0x0A, 0x01, 0x40, 0x28, 0x05, 0x00, 0xA0, 0x24, 0x0D, 0xFE, 0x00,
|
|
||||||
0x7F, 0xE4, 0x04, 0x80, 0x90, 0x12, 0x00, 0x44, 0x0F, 0x81, 0x10, 0x22,
|
|
||||||
0x04, 0x00, 0x80, 0x90, 0x12, 0x03, 0xFF, 0xC0, 0x7F, 0xE4, 0x04, 0x80,
|
|
||||||
0x90, 0x12, 0x00, 0x44, 0x0F, 0x81, 0x10, 0x22, 0x04, 0x00, 0x80, 0x10,
|
|
||||||
0x02, 0x01, 0xFC, 0x00, 0x0F, 0x06, 0x39, 0x01, 0x40, 0x08, 0x01, 0x00,
|
|
||||||
0x20, 0x04, 0x00, 0x83, 0xF0, 0x0A, 0x01, 0x60, 0x26, 0x04, 0x7F, 0x80,
|
|
||||||
0x70, 0xE2, 0x04, 0x20, 0x42, 0x04, 0x20, 0x42, 0x04, 0x3F, 0xC2, 0x04,
|
|
||||||
0x20, 0x42, 0x04, 0x20, 0x42, 0x04, 0x20, 0x4F, 0x8F, 0xFF, 0x04, 0x02,
|
|
||||||
0x01, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x87,
|
|
||||||
0xFC, 0x0F, 0xE0, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80,
|
|
||||||
0x08, 0x80, 0x88, 0x08, 0x80, 0x88, 0x08, 0xC1, 0x03, 0xE0, 0x78, 0xF1,
|
|
||||||
0x01, 0x08, 0x10, 0x43, 0x02, 0x30, 0x13, 0x00, 0xB0, 0x06, 0x60, 0x21,
|
|
||||||
0x81, 0x04, 0x08, 0x10, 0x40, 0x82, 0x06, 0x7C, 0x1C, 0xFC, 0x04, 0x00,
|
|
||||||
0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x04, 0x80,
|
|
||||||
0x90, 0x12, 0x03, 0xFF, 0xC0, 0x70, 0x18, 0xC0, 0x73, 0x02, 0x8A, 0x0A,
|
|
||||||
0x28, 0x48, 0x91, 0x22, 0x48, 0x88, 0xA2, 0x23, 0x08, 0x84, 0x22, 0x00,
|
|
||||||
0x88, 0x02, 0x20, 0x0B, 0xE1, 0xF0, 0xE0, 0xF6, 0x02, 0x50, 0x25, 0x82,
|
|
||||||
0x48, 0x24, 0x42, 0x44, 0x24, 0x22, 0x43, 0x24, 0x12, 0x40, 0xA4, 0x0A,
|
|
||||||
0x40, 0x6F, 0x86, 0x0F, 0x01, 0x8C, 0x20, 0x64, 0x02, 0x40, 0x18, 0x01,
|
|
||||||
0x80, 0x18, 0x01, 0x80, 0x1C, 0x01, 0x40, 0x36, 0x02, 0x30, 0x41, 0xF8,
|
|
||||||
0x7E, 0x04, 0x38, 0x81, 0x10, 0x12, 0x02, 0x40, 0x48, 0x11, 0xFC, 0x20,
|
|
||||||
0x04, 0x00, 0x80, 0x10, 0x02, 0x01, 0xFC, 0x00, 0x0F, 0x01, 0x8C, 0x20,
|
|
||||||
0x64, 0x02, 0x40, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x40,
|
|
||||||
0x36, 0x02, 0x30, 0x41, 0xF8, 0x04, 0x01, 0xF9, 0x10, 0xE0, 0x7E, 0x01,
|
|
||||||
0x0E, 0x08, 0x10, 0x40, 0x42, 0x02, 0x10, 0x30, 0x83, 0x07, 0xE0, 0x21,
|
|
||||||
0x81, 0x06, 0x08, 0x10, 0x40, 0x42, 0x02, 0x7C, 0x0C, 0x1E, 0x0C, 0x74,
|
|
||||||
0x0D, 0x01, 0x40, 0x18, 0x03, 0x80, 0x1E, 0x00, 0xC0, 0x18, 0x06, 0x01,
|
|
||||||
0xC0, 0xEF, 0xC0, 0xFF, 0xF0, 0x86, 0x10, 0xC2, 0x10, 0x40, 0x08, 0x01,
|
|
||||||
0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x7F, 0x00, 0xF0,
|
|
||||||
0xF4, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40,
|
|
||||||
0x24, 0x02, 0x60, 0x22, 0x06, 0x30, 0x41, 0xF8, 0x78, 0x3C, 0x80, 0x22,
|
|
||||||
0x01, 0x08, 0x04, 0x10, 0x10, 0x40, 0x80, 0x82, 0x02, 0x10, 0x08, 0x40,
|
|
||||||
0x11, 0x00, 0x48, 0x01, 0xA0, 0x03, 0x00, 0x0C, 0x00, 0x78, 0x39, 0x00,
|
|
||||||
0x22, 0x00, 0x88, 0xC2, 0x23, 0x08, 0x8A, 0x42, 0x29, 0x09, 0x24, 0x24,
|
|
||||||
0x90, 0x91, 0x41, 0x85, 0x06, 0x14, 0x18, 0x50, 0x60, 0xC0, 0x70, 0x76,
|
|
||||||
0x02, 0x20, 0x41, 0x0C, 0x08, 0x80, 0xD0, 0x06, 0x00, 0x60, 0x0D, 0x00,
|
|
||||||
0x98, 0x10, 0x82, 0x04, 0x60, 0x2F, 0x0F, 0x70, 0x76, 0x02, 0x20, 0x41,
|
|
||||||
0x0C, 0x18, 0x80, 0x90, 0x05, 0x00, 0x60, 0x02, 0x00, 0x20, 0x02, 0x00,
|
|
||||||
0x20, 0x02, 0x01, 0xFC, 0x7F, 0x90, 0x24, 0x09, 0x04, 0x42, 0x00, 0x80,
|
|
||||||
0x40, 0x20, 0x18, 0x04, 0x12, 0x05, 0x01, 0x40, 0x7F, 0xF0, 0xE8, 0x88,
|
|
||||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8F, 0x80, 0x40, 0x10, 0x08, 0x02,
|
|
||||||
0x01, 0x00, 0x40, 0x20, 0x18, 0x04, 0x02, 0x00, 0x80, 0x40, 0x10, 0x08,
|
|
||||||
0x02, 0x01, 0x00, 0x40, 0xF1, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
||||||
0x1F, 0x00, 0x0C, 0x0D, 0x04, 0x44, 0x34, 0x08, 0x00, 0xFF, 0xFC, 0x84,
|
|
||||||
0x30, 0x7F, 0x00, 0x10, 0x02, 0x00, 0x43, 0xF9, 0x81, 0x20, 0x24, 0x04,
|
|
||||||
0x81, 0x8F, 0xDC, 0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0xFC,
|
|
||||||
0x50, 0x66, 0x02, 0x60, 0x14, 0x01, 0x40, 0x16, 0x01, 0x60, 0x25, 0x06,
|
|
||||||
0xCF, 0xC0, 0x3F, 0xCC, 0x19, 0x01, 0x40, 0x08, 0x01, 0x00, 0x20, 0x02,
|
|
||||||
0x01, 0x60, 0x47, 0xF0, 0x00, 0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, 0x43,
|
|
||||||
0xE4, 0x41, 0xC8, 0x0C, 0x80, 0x48, 0x04, 0x80, 0x48, 0x04, 0x80, 0xC4,
|
|
||||||
0x1C, 0x3E, 0x70, 0x3F, 0x10, 0x28, 0x06, 0x01, 0xFF, 0xE0, 0x08, 0x02,
|
|
||||||
0x00, 0x40, 0x4F, 0xE0, 0x00, 0x07, 0xF1, 0x00, 0x40, 0x10, 0x3F, 0xE1,
|
|
||||||
0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x0F, 0xF0, 0x3E,
|
|
||||||
0x68, 0x2A, 0x03, 0x40, 0x68, 0x05, 0x01, 0xA0, 0x36, 0x0E, 0x63, 0x43,
|
|
||||||
0x88, 0x01, 0x00, 0x40, 0x08, 0x3E, 0x00, 0x60, 0x02, 0x00, 0x20, 0x02,
|
|
||||||
0x00, 0x20, 0x02, 0xF8, 0x30, 0x42, 0x04, 0x20, 0x42, 0x04, 0x20, 0x42,
|
|
||||||
0x04, 0x20, 0x42, 0x04, 0xF8, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x00,
|
|
||||||
0x1F, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x0F,
|
|
||||||
0xFC, 0x04, 0x08, 0x10, 0x00, 0x1F, 0xC0, 0x81, 0x02, 0x04, 0x08, 0x10,
|
|
||||||
0x20, 0x40, 0x81, 0x02, 0x0F, 0xF0, 0xC0, 0x08, 0x01, 0x00, 0x20, 0x04,
|
|
||||||
0x00, 0x8F, 0x90, 0x82, 0x20, 0x48, 0x0F, 0x01, 0xB0, 0x23, 0x04, 0x30,
|
|
||||||
0x83, 0x30, 0x78, 0x3C, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40,
|
|
||||||
0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x0F, 0xFC, 0xFE, 0xF0,
|
|
||||||
0xC6, 0x22, 0x10, 0x88, 0x42, 0x21, 0x08, 0x84, 0x22, 0x10, 0x88, 0x42,
|
|
||||||
0x21, 0x0B, 0xC6, 0x30, 0x6F, 0x83, 0x04, 0x20, 0x42, 0x02, 0x20, 0x22,
|
|
||||||
0x02, 0x20, 0x22, 0x02, 0x20, 0x2F, 0x8F, 0x3F, 0x0C, 0x13, 0x01, 0x40,
|
|
||||||
0x28, 0x03, 0x00, 0x60, 0x14, 0x02, 0x40, 0x87, 0xE0, 0xCF, 0xC5, 0x06,
|
|
||||||
0x60, 0x26, 0x01, 0x40, 0x16, 0x01, 0x60, 0x17, 0x02, 0x58, 0xC4, 0x70,
|
|
||||||
0x40, 0x04, 0x00, 0x40, 0x0F, 0x80, 0x3F, 0x74, 0x1C, 0x80, 0xC8, 0x04,
|
|
||||||
0x80, 0x48, 0x04, 0x80, 0x4C, 0x0C, 0x63, 0x41, 0xC4, 0x00, 0x40, 0x04,
|
|
||||||
0x00, 0x40, 0x1E, 0x73, 0xC2, 0xC4, 0x60, 0x08, 0x01, 0x00, 0x20, 0x04,
|
|
||||||
0x00, 0x80, 0x10, 0x1F, 0xF0, 0x3F, 0x90, 0x24, 0x09, 0x80, 0x1E, 0x00,
|
|
||||||
0x60, 0x06, 0x01, 0xC0, 0xEF, 0xE0, 0x00, 0x04, 0x00, 0x80, 0x10, 0x0F,
|
|
||||||
0xF8, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x01, 0x02,
|
|
||||||
0x3F, 0x80, 0xE1, 0xE2, 0x02, 0x20, 0x22, 0x02, 0x20, 0x22, 0x02, 0x20,
|
|
||||||
0x22, 0x06, 0x20, 0xA1, 0xF3, 0xF8, 0xF9, 0x01, 0x08, 0x10, 0x60, 0x81,
|
|
||||||
0x0C, 0x08, 0x40, 0x22, 0x01, 0x20, 0x05, 0x00, 0x30, 0x00, 0xF0, 0x7A,
|
|
||||||
0x01, 0x10, 0x08, 0x8C, 0x42, 0x62, 0x12, 0x90, 0xA5, 0x05, 0x18, 0x28,
|
|
||||||
0xC0, 0x86, 0x00, 0x78, 0xF3, 0x04, 0x18, 0x80, 0xD0, 0x06, 0x00, 0x70,
|
|
||||||
0x09, 0x81, 0x0C, 0x20, 0x6F, 0x8F, 0xF0, 0xF2, 0x02, 0x20, 0x41, 0x04,
|
|
||||||
0x10, 0x80, 0x88, 0x09, 0x00, 0x50, 0x05, 0x00, 0x20, 0x02, 0x00, 0x40,
|
|
||||||
0x04, 0x07, 0xE0, 0xFF, 0x41, 0xA0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81,
|
|
||||||
0xC0, 0xFF, 0xC0, 0x00, 0x61, 0x04, 0x10, 0x41, 0x04, 0x63, 0x02, 0x04,
|
|
||||||
0x10, 0x41, 0x04, 0x10, 0x30, 0x7F, 0xFF, 0xC0, 0x03, 0x02, 0x08, 0x20,
|
|
||||||
0x82, 0x08, 0x30, 0x72, 0x08, 0x20, 0x82, 0x08, 0x43, 0x00, 0x78, 0x71,
|
|
||||||
0x30, 0x30, 0xFF, 0xFE, 0x00, 0x18, 0x00, 0x61, 0xE1, 0x98, 0x66, 0x40,
|
|
||||||
0x98, 0x01, 0x60, 0x05, 0x80, 0x26, 0x01, 0x18, 0x18, 0x60, 0x41, 0x81,
|
|
||||||
0x06, 0x00, 0x18, 0x00, 0x60, 0xE1, 0x83, 0x86, 0x00, 0x1F, 0xFF, 0xC0,
|
|
||||||
0x00, 0xFC, 0x00, 0x92, 0x4B, 0x6D, 0xB0, 0x08, 0x08, 0x08, 0x3E, 0x63,
|
|
||||||
0x81, 0x80, 0x80, 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x08, 0x0E, 0x0C,
|
|
||||||
0xC2, 0x00, 0x80, 0x20, 0x08, 0x0F, 0xC0, 0x40, 0x10, 0x04, 0x01, 0x00,
|
|
||||||
0x80, 0x20, 0x7F, 0xF0, 0x07, 0x81, 0x87, 0x30, 0x32, 0x02, 0x40, 0x04,
|
|
||||||
0x00, 0xFF, 0x84, 0x00, 0xFF, 0x84, 0x00, 0x60, 0x02, 0x00, 0x10, 0x30,
|
|
||||||
0xFC, 0x70, 0x76, 0x02, 0x20, 0x41, 0x0C, 0x18, 0x80, 0x90, 0x07, 0x03,
|
|
||||||
0xFC, 0x02, 0x00, 0x20, 0x3F, 0xC0, 0x20, 0x02, 0x01, 0xF8, 0x20, 0x84,
|
|
||||||
0xC0, 0xE0, 0x10, 0x1E, 0x0C, 0x74, 0x0D, 0x01, 0x40, 0x18, 0x03, 0x80,
|
|
||||||
0x1E, 0x00, 0xC0, 0x18, 0x06, 0x01, 0xC0, 0xEF, 0xC0, 0x1F, 0xC4, 0x08,
|
|
||||||
0x81, 0x10, 0x0D, 0x81, 0x18, 0x20, 0xC3, 0x06, 0x30, 0x61, 0x84, 0x0B,
|
|
||||||
0x80, 0xC0, 0x08, 0x83, 0x1F, 0xC0, 0x31, 0x86, 0x80, 0xC0, 0x00, 0x00,
|
|
||||||
0x0F, 0xE4, 0x09, 0x02, 0x60, 0x07, 0x80, 0x18, 0x01, 0x80, 0x70, 0x3B,
|
|
||||||
0xF8, 0x07, 0x80, 0x61, 0x82, 0x01, 0x10, 0xD2, 0x4C, 0xC6, 0x21, 0x18,
|
|
||||||
0x80, 0x62, 0x01, 0x88, 0x06, 0x21, 0x14, 0x7C, 0xD8, 0x02, 0x30, 0x30,
|
|
||||||
0x3F, 0x80, 0x30, 0x90, 0x13, 0xE8, 0x50, 0xBF, 0x80, 0x08, 0x23, 0x08,
|
|
||||||
0xC2, 0x30, 0xCC, 0x31, 0x86, 0x18, 0x61, 0x84, 0x18, 0x41, 0x04, 0xFF,
|
|
||||||
0xE0, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0xFF, 0xE0, 0x07,
|
|
||||||
0x80, 0x61, 0x82, 0x01, 0x13, 0xC2, 0x44, 0xC6, 0x11, 0x18, 0x44, 0x61,
|
|
||||||
0xE1, 0x84, 0x86, 0x11, 0x14, 0xE6, 0xD8, 0x02, 0x30, 0x30, 0x3F, 0x80,
|
|
||||||
0xFE, 0x79, 0x0A, 0x0C, 0x18, 0x49, 0x8C, 0x00, 0x04, 0x00, 0x80, 0x10,
|
|
||||||
0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, 0x04, 0x00, 0x80, 0x00, 0x00,
|
|
||||||
0x0F, 0xFE, 0x31, 0x28, 0x41, 0x08, 0x42, 0x30, 0xFC, 0x31, 0x20, 0x42,
|
|
||||||
0x18, 0x10, 0x61, 0x78, 0x21, 0x84, 0xC0, 0xC0, 0x00, 0x7F, 0x90, 0x24,
|
|
||||||
0x09, 0x04, 0x42, 0x00, 0x80, 0x40, 0x20, 0x18, 0x04, 0x12, 0x05, 0x01,
|
|
||||||
0x40, 0x7F, 0xF0, 0xE1, 0xE2, 0x02, 0x20, 0x22, 0x02, 0x20, 0x22, 0x02,
|
|
||||||
0x20, 0x22, 0x06, 0x20, 0xE3, 0xF3, 0x20, 0x02, 0x00, 0x20, 0x02, 0x00,
|
|
||||||
0x20, 0x00, 0x07, 0xCF, 0xA3, 0x14, 0x62, 0x8C, 0x51, 0x8A, 0x31, 0x43,
|
|
||||||
0xA8, 0x1D, 0x00, 0xA0, 0x14, 0x02, 0x80, 0x50, 0x0A, 0x01, 0x41, 0xE6,
|
|
||||||
0x74, 0x42, 0x1A, 0x06, 0x00, 0x00, 0x07, 0xFA, 0x0D, 0x04, 0x04, 0x04,
|
|
||||||
0x04, 0x04, 0x04, 0x0E, 0x07, 0xFE, 0x27, 0x08, 0x42, 0x10, 0x84, 0xF8,
|
|
||||||
0x39, 0x8A, 0x0C, 0x18, 0x30, 0x9E, 0x00, 0x84, 0x18, 0x41, 0x84, 0x18,
|
|
||||||
0xC1, 0x8C, 0x31, 0x8C, 0x63, 0x08, 0xC2, 0x10, 0x80, 0x03, 0xFC, 0x74,
|
|
||||||
0x12, 0x10, 0x50, 0x41, 0x41, 0x06, 0x04, 0x88, 0x1E, 0x20, 0x48, 0x81,
|
|
||||||
0x23, 0x04, 0x04, 0x10, 0x58, 0x41, 0x31, 0x04, 0x3F, 0xF0, 0x3C, 0xF1,
|
|
||||||
0x0A, 0x24, 0x30, 0xE0, 0x41, 0x81, 0xFE, 0x04, 0x08, 0x10, 0x10, 0xC0,
|
|
||||||
0x42, 0x84, 0xF1, 0xE0, 0x38, 0xC1, 0x8C, 0x00, 0x07, 0x07, 0x60, 0x22,
|
|
||||||
0x04, 0x10, 0xC1, 0x88, 0x09, 0x00, 0x50, 0x06, 0x00, 0x20, 0x02, 0x00,
|
|
||||||
0x20, 0x02, 0x00, 0x20, 0x1F, 0xC0, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x08,
|
|
||||||
0x18, 0x60, 0xC0, 0x80, 0x80, 0x81, 0xC1, 0x7E, 0x08, 0x00, 0x30, 0x00,
|
|
||||||
0x20, 0x00, 0x40, 0x00, 0x00, 0x7C, 0x00, 0x30, 0x01, 0x20, 0x04, 0x80,
|
|
||||||
0x12, 0x00, 0x84, 0x02, 0x10, 0x08, 0x20, 0x7F, 0x81, 0x02, 0x04, 0x04,
|
|
||||||
0x20, 0x10, 0x80, 0x4F, 0x87, 0xC0, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00,
|
|
||||||
0x80, 0x00, 0x00, 0x7C, 0x00, 0x30, 0x01, 0x20, 0x04, 0x80, 0x12, 0x00,
|
|
||||||
0x84, 0x02, 0x10, 0x08, 0x20, 0x7F, 0x81, 0x02, 0x04, 0x04, 0x20, 0x10,
|
|
||||||
0x80, 0x4F, 0x87, 0xC0, 0x03, 0x00, 0x1A, 0x00, 0x84, 0x00, 0x00, 0x1F,
|
|
||||||
0x00, 0x0C, 0x00, 0x48, 0x01, 0x20, 0x04, 0x80, 0x21, 0x00, 0x84, 0x02,
|
|
||||||
0x08, 0x1F, 0xE0, 0x40, 0x81, 0x01, 0x08, 0x04, 0x20, 0x13, 0xE1, 0xF0,
|
|
||||||
0x06, 0x20, 0x27, 0x00, 0x00, 0x07, 0xC0, 0x03, 0x00, 0x12, 0x00, 0x48,
|
|
||||||
0x01, 0x20, 0x08, 0x40, 0x21, 0x00, 0x82, 0x07, 0xF8, 0x10, 0x20, 0x40,
|
|
||||||
0x42, 0x01, 0x08, 0x04, 0xF8, 0x7C, 0x08, 0x60, 0x71, 0x80, 0x00, 0x07,
|
|
||||||
0xC0, 0x03, 0x00, 0x12, 0x00, 0x48, 0x01, 0x20, 0x08, 0x40, 0x21, 0x00,
|
|
||||||
0x82, 0x07, 0xF8, 0x10, 0x20, 0x40, 0x42, 0x01, 0x08, 0x04, 0xF8, 0x7C,
|
|
||||||
0x03, 0x80, 0x12, 0x00, 0x48, 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x30,
|
|
||||||
0x01, 0x20, 0x04, 0x80, 0x12, 0x00, 0x84, 0x02, 0x10, 0x08, 0x20, 0x7F,
|
|
||||||
0x81, 0x02, 0x04, 0x04, 0x20, 0x10, 0x80, 0x4F, 0x87, 0xC0, 0x1F, 0xFC,
|
|
||||||
0x14, 0x10, 0x50, 0x42, 0x41, 0x09, 0x04, 0x24, 0x80, 0x9E, 0x04, 0x48,
|
|
||||||
0x1F, 0x20, 0x44, 0x02, 0x10, 0x48, 0x41, 0x21, 0x07, 0xDF, 0xF0, 0x1E,
|
|
||||||
0x06, 0x39, 0x01, 0x40, 0x28, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10,
|
|
||||||
0x02, 0x00, 0x20, 0x16, 0x04, 0x3F, 0x01, 0x00, 0x30, 0x02, 0x03, 0xC0,
|
|
||||||
0x10, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0xFF, 0xC8, 0x09, 0x01, 0x20,
|
|
||||||
0x24, 0x00, 0x88, 0x1F, 0x02, 0x20, 0x44, 0x08, 0x01, 0x01, 0x20, 0x24,
|
|
||||||
0x07, 0xFF, 0x80, 0x00, 0x00, 0x60, 0x18, 0x06, 0x00, 0x00, 0xFF, 0xC8,
|
|
||||||
0x09, 0x01, 0x20, 0x24, 0x00, 0x88, 0x1F, 0x02, 0x20, 0x44, 0x08, 0x01,
|
|
||||||
0x01, 0x20, 0x24, 0x07, 0xFF, 0x80, 0x06, 0x01, 0xE0, 0x42, 0x00, 0x07,
|
|
||||||
0xFE, 0x40, 0x48, 0x09, 0x01, 0x20, 0x04, 0x40, 0xF8, 0x11, 0x02, 0x20,
|
|
||||||
0x40, 0x08, 0x09, 0x01, 0x20, 0x3F, 0xFC, 0x30, 0xC6, 0x38, 0x00, 0x3F,
|
|
||||||
0xF2, 0x02, 0x40, 0x48, 0x09, 0x00, 0x22, 0x07, 0xC0, 0x88, 0x11, 0x02,
|
|
||||||
0x00, 0x40, 0x48, 0x09, 0x01, 0xFF, 0xE0, 0x00, 0x18, 0x06, 0x01, 0x80,
|
|
||||||
0x07, 0xF8, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20,
|
|
||||||
0x10, 0x08, 0x04, 0x3F, 0xE0, 0x00, 0x01, 0x03, 0x03, 0x00, 0x07, 0xF8,
|
|
||||||
0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08,
|
|
||||||
0x04, 0x3F, 0xE0, 0x18, 0x1A, 0x10, 0xC0, 0x0F, 0xF0, 0x40, 0x20, 0x10,
|
|
||||||
0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x7F, 0xC0,
|
|
||||||
0x43, 0x71, 0x80, 0x1F, 0xE0, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02,
|
|
||||||
0x01, 0x00, 0x80, 0x40, 0x20, 0x10, 0xFF, 0x80, 0x3E, 0x02, 0x1C, 0x20,
|
|
||||||
0x22, 0x01, 0x20, 0x12, 0x01, 0x7E, 0x1A, 0x11, 0x20, 0x12, 0x01, 0x20,
|
|
||||||
0x12, 0x02, 0x20, 0x67, 0xF8, 0x1C, 0x43, 0x38, 0x00, 0x0E, 0x0F, 0x60,
|
|
||||||
0x25, 0x02, 0x58, 0x24, 0x82, 0x44, 0x24, 0x42, 0x42, 0x24, 0x32, 0x41,
|
|
||||||
0x24, 0x0A, 0x40, 0xA4, 0x06, 0xF8, 0x60, 0x00, 0x00, 0x80, 0x06, 0x00,
|
|
||||||
0x20, 0x00, 0x00, 0xF0, 0x18, 0xC2, 0x06, 0x40, 0x24, 0x01, 0x80, 0x18,
|
|
||||||
0x01, 0x80, 0x18, 0x01, 0xC0, 0x14, 0x03, 0x60, 0x23, 0x04, 0x1F, 0x80,
|
|
||||||
0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x00, 0x00, 0xF0, 0x18, 0xC2, 0x06,
|
|
||||||
0x40, 0x24, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xC0, 0x14, 0x03,
|
|
||||||
0x60, 0x23, 0x04, 0x1F, 0x80, 0x06, 0x00, 0xD0, 0x10, 0x80, 0x00, 0x0F,
|
|
||||||
0x01, 0x8C, 0x20, 0x64, 0x02, 0x40, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80,
|
|
||||||
0x1C, 0x01, 0x40, 0x36, 0x02, 0x30, 0x41, 0xF8, 0x0C, 0x41, 0x38, 0x00,
|
|
||||||
0x00, 0xF0, 0x18, 0xC2, 0x06, 0x40, 0x24, 0x01, 0x80, 0x18, 0x01, 0x80,
|
|
||||||
0x18, 0x01, 0xC0, 0x14, 0x03, 0x60, 0x23, 0x04, 0x1F, 0x80, 0x10, 0xC3,
|
|
||||||
0x8C, 0x00, 0x00, 0xF0, 0x18, 0xC2, 0x06, 0x40, 0x24, 0x01, 0x80, 0x18,
|
|
||||||
0x01, 0x80, 0x18, 0x01, 0xC0, 0x14, 0x03, 0x60, 0x23, 0x04, 0x1F, 0x80,
|
|
||||||
0x81, 0xA1, 0x89, 0x83, 0x81, 0x81, 0xA1, 0x89, 0x82, 0x80, 0x00, 0x00,
|
|
||||||
0x00, 0xF1, 0x18, 0xE2, 0x06, 0x40, 0x64, 0x09, 0x81, 0x18, 0x21, 0x86,
|
|
||||||
0x18, 0x41, 0xC8, 0x15, 0x03, 0x60, 0x27, 0x04, 0x5F, 0x88, 0x00, 0x00,
|
|
||||||
0x00, 0x80, 0x06, 0x00, 0x20, 0x00, 0x0F, 0x0F, 0x40, 0x24, 0x02, 0x40,
|
|
||||||
0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x26, 0x02, 0x20,
|
|
||||||
0x63, 0x04, 0x1F, 0x80, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x00, 0x0F,
|
|
||||||
0x0F, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24,
|
|
||||||
0x02, 0x40, 0x26, 0x02, 0x20, 0x63, 0x04, 0x1F, 0x80, 0x06, 0x00, 0xD0,
|
|
||||||
0x10, 0x80, 0x00, 0xF0, 0xF4, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02,
|
|
||||||
0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x60, 0x22, 0x06, 0x30, 0x41, 0xF8,
|
|
||||||
0x10, 0xC3, 0x8C, 0x00, 0x0F, 0x0F, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02,
|
|
||||||
0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x26, 0x02, 0x20, 0x63, 0x04,
|
|
||||||
0x1F, 0x80, 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x00, 0x07, 0x07, 0x60,
|
|
||||||
0x22, 0x04, 0x10, 0xC1, 0x88, 0x09, 0x00, 0x50, 0x06, 0x00, 0x20, 0x02,
|
|
||||||
0x00, 0x20, 0x02, 0x00, 0x20, 0x1F, 0xC0, 0x7E, 0x04, 0x00, 0x80, 0x1F,
|
|
||||||
0x02, 0x1C, 0x40, 0x88, 0x09, 0x01, 0x20, 0x24, 0x08, 0xFE, 0x10, 0x02,
|
|
||||||
0x01, 0xFC, 0x00, 0x00, 0x03, 0xE0, 0x84, 0x30, 0x44, 0x08, 0x82, 0x11,
|
|
||||||
0xC2, 0x0C, 0x40, 0x48, 0x05, 0x00, 0xA0, 0x14, 0x42, 0x88, 0xF8, 0xF0,
|
|
||||||
0x30, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x20, 0x04, 0x00,
|
|
||||||
0x87, 0xF3, 0x02, 0x40, 0x48, 0x09, 0x03, 0x1F, 0xB8, 0x02, 0x00, 0x80,
|
|
||||||
0x20, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x20, 0x04, 0x00, 0x87, 0xF3, 0x02,
|
|
||||||
0x40, 0x48, 0x09, 0x03, 0x1F, 0xB8, 0x0C, 0x03, 0xC0, 0x8C, 0x00, 0x00,
|
|
||||||
0x00, 0xFE, 0x00, 0x20, 0x04, 0x00, 0x87, 0xF3, 0x02, 0x40, 0x48, 0x09,
|
|
||||||
0x03, 0x1F, 0xB8, 0x18, 0x84, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x01, 0x00,
|
|
||||||
0x20, 0x04, 0x3F, 0x98, 0x12, 0x02, 0x40, 0x48, 0x18, 0xFD, 0xC0, 0x63,
|
|
||||||
0x8C, 0x70, 0x00, 0x00, 0x07, 0xF0, 0x01, 0x00, 0x20, 0x04, 0x3F, 0x98,
|
|
||||||
0x12, 0x02, 0x40, 0x48, 0x18, 0xFD, 0xC0, 0x0E, 0x02, 0x40, 0x48, 0x07,
|
|
||||||
0x00, 0x00, 0x00, 0x1F, 0xC0, 0x04, 0x00, 0x80, 0x10, 0xFE, 0x60, 0x48,
|
|
||||||
0x09, 0x01, 0x20, 0x63, 0xF7, 0x3E, 0xF0, 0x0A, 0x20, 0x10, 0x80, 0x41,
|
|
||||||
0x3F, 0xFD, 0x04, 0x08, 0x10, 0x20, 0x40, 0x43, 0x85, 0xF7, 0xE0, 0x3F,
|
|
||||||
0xCC, 0x19, 0x01, 0x40, 0x08, 0x01, 0x00, 0x20, 0x02, 0x01, 0x60, 0x47,
|
|
||||||
0xF0, 0x10, 0x03, 0x00, 0x20, 0x3C, 0x00, 0x10, 0x02, 0x00, 0x40, 0x00,
|
|
||||||
0x00, 0x0F, 0xC4, 0x0A, 0x01, 0x80, 0x7F, 0xF8, 0x02, 0x00, 0x80, 0x10,
|
|
||||||
0x13, 0xF8, 0x03, 0x01, 0x00, 0x80, 0x00, 0x00, 0x0F, 0xC4, 0x0A, 0x01,
|
|
||||||
0x80, 0x7F, 0xF8, 0x02, 0x00, 0x80, 0x10, 0x13, 0xF8, 0x04, 0x06, 0x83,
|
|
||||||
0x10, 0x82, 0x00, 0x0F, 0xC4, 0x0A, 0x01, 0x80, 0x7F, 0xF8, 0x02, 0x00,
|
|
||||||
0x80, 0x10, 0x13, 0xF8, 0x31, 0x8C, 0x60, 0x00, 0x00, 0x3F, 0x10, 0x28,
|
|
||||||
0x06, 0x01, 0xFF, 0xE0, 0x08, 0x02, 0x00, 0x40, 0x4F, 0xE0, 0x30, 0x02,
|
|
||||||
0x00, 0x40, 0x00, 0x00, 0x1F, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40,
|
|
||||||
0x10, 0x04, 0x01, 0x0F, 0xFC, 0x02, 0x01, 0x00, 0x80, 0x00, 0x00, 0x1F,
|
|
||||||
0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x0F, 0xFC,
|
|
||||||
0x08, 0x05, 0x82, 0x30, 0x00, 0x00, 0x1F, 0x00, 0x40, 0x10, 0x04, 0x01,
|
|
||||||
0x00, 0x40, 0x10, 0x04, 0x01, 0x0F, 0xFC, 0x63, 0x98, 0xE0, 0x00, 0x00,
|
|
||||||
0x7C, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x3F,
|
|
||||||
0xF0, 0x30, 0x81, 0xE0, 0x78, 0x00, 0x80, 0x08, 0x7F, 0x98, 0x36, 0x02,
|
|
||||||
0x80, 0x70, 0x06, 0x00, 0xC0, 0x2C, 0x04, 0xC1, 0x0F, 0xC0, 0x1C, 0x43,
|
|
||||||
0x38, 0x00, 0x00, 0x00, 0x6F, 0x83, 0x04, 0x20, 0x42, 0x02, 0x20, 0x22,
|
|
||||||
0x02, 0x20, 0x22, 0x02, 0x20, 0x2F, 0x8F, 0x10, 0x01, 0x00, 0x10, 0x00,
|
|
||||||
0x00, 0x00, 0x7E, 0x18, 0x26, 0x02, 0x80, 0x50, 0x06, 0x00, 0xC0, 0x28,
|
|
||||||
0x04, 0x81, 0x0F, 0xC0, 0x02, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x7E,
|
|
||||||
0x18, 0x26, 0x02, 0x80, 0x50, 0x06, 0x00, 0xC0, 0x28, 0x04, 0x81, 0x0F,
|
|
||||||
0xC0, 0x0C, 0x03, 0x40, 0xC4, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x26, 0x02,
|
|
||||||
0x80, 0x50, 0x06, 0x00, 0xC0, 0x28, 0x04, 0x81, 0x0F, 0xC0, 0x18, 0x84,
|
|
||||||
0xE0, 0x00, 0x00, 0x03, 0xF0, 0xC1, 0x30, 0x14, 0x02, 0x80, 0x30, 0x06,
|
|
||||||
0x01, 0x40, 0x24, 0x08, 0x7E, 0x00, 0x71, 0x8E, 0x30, 0x00, 0x00, 0x03,
|
|
||||||
0xF0, 0xC1, 0x30, 0x14, 0x02, 0x80, 0x30, 0x06, 0x01, 0x40, 0x24, 0x08,
|
|
||||||
0x7E, 0x00, 0x0C, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x11, 0xFA, 0x30, 0x46,
|
|
||||||
0x0A, 0x41, 0x24, 0x21, 0x44, 0x14, 0x82, 0x70, 0x22, 0x04, 0x5F, 0x88,
|
|
||||||
0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x0E, 0x1E, 0x20, 0x22,
|
|
||||||
0x02, 0x20, 0x22, 0x02, 0x20, 0x22, 0x02, 0x20, 0x62, 0x0A, 0x1F, 0x30,
|
|
||||||
0x01, 0x00, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x0E, 0x1E, 0x20, 0x22, 0x02,
|
|
||||||
0x20, 0x22, 0x02, 0x20, 0x22, 0x02, 0x20, 0x62, 0x0A, 0x1F, 0x30, 0x06,
|
|
||||||
0x00, 0xF0, 0x18, 0x80, 0x00, 0x00, 0x0E, 0x1E, 0x20, 0x22, 0x02, 0x20,
|
|
||||||
0x22, 0x02, 0x20, 0x22, 0x02, 0x20, 0x62, 0x0A, 0x1F, 0x30, 0x30, 0xC3,
|
|
||||||
0x0C, 0x00, 0x00, 0x00, 0xE1, 0xE2, 0x02, 0x20, 0x22, 0x02, 0x20, 0x22,
|
|
||||||
0x02, 0x20, 0x22, 0x06, 0x20, 0xA1, 0xF3, 0x00, 0x80, 0x10, 0x02, 0x00,
|
|
||||||
0x00, 0x00, 0x0F, 0x0F, 0x20, 0x22, 0x04, 0x10, 0x41, 0x08, 0x08, 0x80,
|
|
||||||
0x90, 0x05, 0x00, 0x50, 0x02, 0x00, 0x20, 0x04, 0x00, 0x40, 0x7E, 0x00,
|
|
||||||
0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, 0x4F, 0xC5, 0x06, 0x60, 0x26, 0x01,
|
|
||||||
0x40, 0x16, 0x01, 0x60, 0x17, 0x02, 0x58, 0xC4, 0x70, 0x40, 0x04, 0x00,
|
|
||||||
0x40, 0x0F, 0x80, 0x38, 0xC3, 0x8C, 0x00, 0x00, 0x00, 0xF0, 0xF2, 0x02,
|
|
||||||
0x20, 0x41, 0x04, 0x10, 0x80, 0x88, 0x09, 0x00, 0x50, 0x05, 0x00, 0x20,
|
|
||||||
0x02, 0x00, 0x40, 0x04, 0x07, 0xE0 };
|
|
||||||
|
|
||||||
const GFXglyph FreeMono12pt8bGlyphs[] PROGMEM = {
|
|
||||||
{ 0, 1, 1, 14, 0, 0 }, // 0x20 ' ' U+0020
|
|
||||||
{ 1, 3, 15, 14, 6, -14 }, // 0x21 '!' U+0021
|
|
||||||
{ 7, 8, 7, 14, 3, -14 }, // 0x22 '"' U+0022
|
|
||||||
{ 14, 10, 17, 14, 2, -15 }, // 0x23 '#' U+0023
|
|
||||||
{ 36, 9, 18, 14, 3, -15 }, // 0x24 '$' U+0024
|
|
||||||
{ 57, 10, 15, 14, 2, -14 }, // 0x25 '%' U+0025
|
|
||||||
{ 76, 8, 12, 14, 3, -11 }, // 0x26 '&' U+0026
|
|
||||||
{ 88, 3, 7, 14, 6, -14 }, // 0x27 ''' U+0027
|
|
||||||
{ 91, 4, 18, 14, 7, -14 }, // 0x28 '(' U+0028
|
|
||||||
{ 100, 3, 18, 14, 4, -14 }, // 0x29 ')' U+0029
|
|
||||||
{ 107, 9, 9, 14, 3, -14 }, // 0x2a '*' U+002A
|
|
||||||
{ 118, 11, 12, 14, 2, -12 }, // 0x2b '+' U+002B
|
|
||||||
{ 135, 5, 6, 14, 3, -2 }, // 0x2c ',' U+002C
|
|
||||||
{ 139, 11, 1, 14, 2, -6 }, // 0x2d '-' U+002D
|
|
||||||
{ 141, 4, 3, 14, 5, -2 }, // 0x2e '.' U+002E
|
|
||||||
{ 143, 9, 18, 14, 3, -15 }, // 0x2f '/' U+002F
|
|
||||||
{ 164, 9, 15, 14, 3, -14 }, // 0x30 '0' U+0030
|
|
||||||
{ 181, 9, 15, 14, 3, -14 }, // 0x31 '1' U+0031
|
|
||||||
{ 198, 9, 15, 14, 2, -14 }, // 0x32 '2' U+0032
|
|
||||||
{ 215, 10, 15, 14, 2, -14 }, // 0x33 '3' U+0033
|
|
||||||
{ 234, 8, 15, 14, 3, -14 }, // 0x34 '4' U+0034
|
|
||||||
{ 249, 10, 15, 14, 2, -14 }, // 0x35 '5' U+0035
|
|
||||||
{ 268, 9, 15, 14, 3, -14 }, // 0x36 '6' U+0036
|
|
||||||
{ 285, 8, 15, 14, 3, -14 }, // 0x37 '7' U+0037
|
|
||||||
{ 300, 9, 15, 14, 3, -14 }, // 0x38 '8' U+0038
|
|
||||||
{ 317, 9, 15, 14, 3, -14 }, // 0x39 '9' U+0039
|
|
||||||
{ 334, 4, 10, 14, 5, -9 }, // 0x3a ':' U+003A
|
|
||||||
{ 339, 5, 13, 14, 3, -9 }, // 0x3b ';' U+003B
|
|
||||||
{ 348, 11, 11, 14, 2, -11 }, // 0x3c '<' U+003C
|
|
||||||
{ 364, 12, 4, 14, 1, -8 }, // 0x3d '=' U+003D
|
|
||||||
{ 370, 11, 11, 14, 2, -11 }, // 0x3e '>' U+003E
|
|
||||||
{ 386, 9, 14, 14, 3, -13 }, // 0x3f '?' U+003F
|
|
||||||
{ 402, 8, 16, 14, 3, -14 }, // 0x40 '@' U+0040
|
|
||||||
{ 418, 14, 14, 14, 0, -13 }, // 0x41 'A' U+0041
|
|
||||||
{ 443, 12, 14, 14, 1, -13 }, // 0x42 'B' U+0042
|
|
||||||
{ 464, 11, 14, 14, 2, -13 }, // 0x43 'C' U+0043
|
|
||||||
{ 484, 11, 14, 14, 1, -13 }, // 0x44 'D' U+0044
|
|
||||||
{ 504, 11, 14, 14, 1, -13 }, // 0x45 'E' U+0045
|
|
||||||
{ 524, 11, 14, 14, 1, -13 }, // 0x46 'F' U+0046
|
|
||||||
{ 544, 11, 14, 14, 2, -13 }, // 0x47 'G' U+0047
|
|
||||||
{ 564, 12, 14, 14, 1, -13 }, // 0x48 'H' U+0048
|
|
||||||
{ 585, 9, 14, 14, 3, -13 }, // 0x49 'I' U+0049
|
|
||||||
{ 601, 12, 14, 14, 2, -13 }, // 0x4a 'J' U+004A
|
|
||||||
{ 622, 13, 14, 14, 1, -13 }, // 0x4b 'K' U+004B
|
|
||||||
{ 645, 11, 14, 14, 2, -13 }, // 0x4c 'L' U+004C
|
|
||||||
{ 665, 14, 14, 14, 0, -13 }, // 0x4d 'M' U+004D
|
|
||||||
{ 690, 12, 14, 14, 1, -13 }, // 0x4e 'N' U+004E
|
|
||||||
{ 711, 12, 14, 14, 1, -13 }, // 0x4f 'O' U+004F
|
|
||||||
{ 732, 11, 14, 14, 1, -13 }, // 0x50 'P' U+0050
|
|
||||||
{ 752, 12, 17, 14, 1, -13 }, // 0x51 'Q' U+0051
|
|
||||||
{ 778, 13, 14, 14, 1, -13 }, // 0x52 'R' U+0052
|
|
||||||
{ 801, 10, 14, 14, 2, -13 }, // 0x53 'S' U+0053
|
|
||||||
{ 819, 11, 14, 14, 2, -13 }, // 0x54 'T' U+0054
|
|
||||||
{ 839, 12, 14, 14, 1, -13 }, // 0x55 'U' U+0055
|
|
||||||
{ 860, 14, 14, 14, 0, -13 }, // 0x56 'V' U+0056
|
|
||||||
{ 885, 14, 14, 14, 0, -13 }, // 0x57 'W' U+0057
|
|
||||||
{ 910, 12, 14, 14, 1, -13 }, // 0x58 'X' U+0058
|
|
||||||
{ 931, 12, 14, 14, 1, -13 }, // 0x59 'Y' U+0059
|
|
||||||
{ 952, 10, 14, 14, 2, -13 }, // 0x5a 'Z' U+005A
|
|
||||||
{ 970, 4, 18, 14, 7, -14 }, // 0x5b '[' U+005B
|
|
||||||
{ 979, 9, 18, 14, 3, -15 }, // 0x5c '\' U+005C
|
|
||||||
{ 1000, 4, 18, 14, 4, -14 }, // 0x5d ']' U+005D
|
|
||||||
{ 1009, 9, 7, 14, 3, -14 }, // 0x5e '^' U+005E
|
|
||||||
{ 1017, 14, 1, 14, 0, 3 }, // 0x5f '_' U+005F
|
|
||||||
{ 1019, 4, 3, 14, 4, -14 }, // 0x60 '`' U+0060
|
|
||||||
{ 1021, 11, 10, 14, 2, -9 }, // 0x61 'a' U+0061
|
|
||||||
{ 1035, 12, 15, 14, 1, -14 }, // 0x62 'b' U+0062
|
|
||||||
{ 1058, 11, 10, 14, 2, -9 }, // 0x63 'c' U+0063
|
|
||||||
{ 1072, 12, 15, 14, 2, -14 }, // 0x64 'd' U+0064
|
|
||||||
{ 1095, 10, 10, 14, 2, -9 }, // 0x65 'e' U+0065
|
|
||||||
{ 1108, 10, 15, 14, 3, -14 }, // 0x66 'f' U+0066
|
|
||||||
{ 1127, 11, 14, 14, 2, -9 }, // 0x67 'g' U+0067
|
|
||||||
{ 1147, 12, 15, 14, 1, -14 }, // 0x68 'h' U+0068
|
|
||||||
{ 1170, 10, 15, 14, 2, -14 }, // 0x69 'i' U+0069
|
|
||||||
{ 1189, 7, 19, 14, 4, -14 }, // 0x6a 'j' U+006A
|
|
||||||
{ 1206, 11, 15, 14, 2, -14 }, // 0x6b 'k' U+006B
|
|
||||||
{ 1227, 10, 15, 14, 2, -14 }, // 0x6c 'l' U+006C
|
|
||||||
{ 1246, 14, 10, 14, 0, -9 }, // 0x6d 'm' U+006D
|
|
||||||
{ 1264, 12, 10, 14, 1, -9 }, // 0x6e 'n' U+006E
|
|
||||||
{ 1279, 11, 10, 14, 2, -9 }, // 0x6f 'o' U+006F
|
|
||||||
{ 1293, 12, 14, 14, 1, -9 }, // 0x70 'p' U+0070
|
|
||||||
{ 1314, 12, 14, 14, 2, -9 }, // 0x71 'q' U+0071
|
|
||||||
{ 1335, 11, 10, 14, 2, -9 }, // 0x72 'r' U+0072
|
|
||||||
{ 1349, 10, 10, 14, 2, -9 }, // 0x73 's' U+0073
|
|
||||||
{ 1362, 11, 14, 14, 1, -13 }, // 0x74 't' U+0074
|
|
||||||
{ 1382, 12, 10, 14, 1, -9 }, // 0x75 'u' U+0075
|
|
||||||
{ 1397, 13, 10, 14, 1, -9 }, // 0x76 'v' U+0076
|
|
||||||
{ 1414, 13, 10, 14, 1, -9 }, // 0x77 'w' U+0077
|
|
||||||
{ 1431, 12, 10, 14, 1, -9 }, // 0x78 'x' U+0078
|
|
||||||
{ 1446, 12, 14, 14, 1, -9 }, // 0x79 'y' U+0079
|
|
||||||
{ 1467, 9, 10, 14, 3, -9 }, // 0x7a 'z' U+007A
|
|
||||||
{ 1479, 6, 18, 14, 4, -14 }, // 0x7b '{' U+007B
|
|
||||||
{ 1493, 1, 18, 14, 7, -14 }, // 0x7c '|' U+007C
|
|
||||||
{ 1496, 6, 18, 14, 5, -14 }, // 0x7d '}' U+007D
|
|
||||||
{ 1510, 10, 3, 14, 2, -7 }, // 0x7e '~' U+007E
|
|
||||||
{ 1514, 14, 19, 14, 0, -16 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
|
|
||||||
{ 1548, 1, 1, 14, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
|
|
||||||
{ 1549, 3, 15, 14, 6, -10 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
|
|
||||||
{ 1555, 8, 15, 14, 3, -14 }, // 0x82 'CENT SIGN' U+00A2
|
|
||||||
{ 1570, 10, 14, 14, 2, -13 }, // 0x83 'POUND SIGN' U+00A3
|
|
||||||
{ 1588, 12, 14, 14, 1, -13 }, // 0x84 'EURO SIGN *' U+20AC
|
|
||||||
{ 1609, 12, 14, 14, 1, -13 }, // 0x85 'YEN SIGN' U+00A5
|
|
||||||
{ 1630, 10, 18, 14, 2, -17 }, // 0x86 'LATIN CAPITAL LETTER S WITH CARON *' U+0160
|
|
||||||
{ 1653, 11, 15, 14, 2, -13 }, // 0x87 'SECTION SIGN' U+00A7
|
|
||||||
{ 1674, 10, 15, 14, 2, -14 }, // 0x88 'LATIN SMALL LETTER S WITH CARON *' U+0161
|
|
||||||
{ 1693, 14, 14, 14, 0, -13 }, // 0x89 'COPYRIGHT SIGN' U+00A9
|
|
||||||
{ 1718, 7, 7, 14, 4, -13 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
|
|
||||||
{ 1725, 11, 10, 14, 2, -9 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
|
|
||||||
{ 1739, 11, 7, 14, 2, -10 }, // 0x8c 'NOT SIGN' U+00AC
|
|
||||||
{ 1749, 11, 1, 14, 2, -6 }, // 0x8d 'SOFT HYPHEN' U+00AD
|
|
||||||
{ 1751, 14, 14, 14, 0, -13 }, // 0x8e 'REGISTERED SIGN' U+00AE
|
|
||||||
{ 1776, 7, 1, 14, 4, -13 }, // 0x8f 'MACRON' U+00AF
|
|
||||||
{ 1777, 7, 7, 14, 4, -14 }, // 0x90 'DEGREE SIGN' U+00B0
|
|
||||||
{ 1784, 11, 13, 14, 2, -12 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
|
|
||||||
{ 1802, 6, 9, 14, 4, -14 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
|
|
||||||
{ 1809, 6, 9, 14, 4, -14 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
|
|
||||||
{ 1816, 10, 18, 14, 2, -17 }, // 0x94 'LATIN CAPITAL LETTER Z WITH CARON *' U+017D
|
|
||||||
{ 1839, 12, 15, 14, 1, -9 }, // 0x95 'MICRO SIGN' U+00B5
|
|
||||||
{ 1862, 11, 16, 14, 2, -14 }, // 0x96 'PILCROW SIGN' U+00B6
|
|
||||||
{ 1884, 2, 3, 14, 6, -6 }, // 0x97 'MIDDLE DOT' U+00B7
|
|
||||||
{ 1885, 9, 15, 14, 3, -14 }, // 0x98 'LATIN SMALL LETTER Z WITH CARON *' U+017E
|
|
||||||
{ 1902, 5, 9, 14, 5, -14 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
|
|
||||||
{ 1908, 7, 7, 14, 4, -13 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
|
|
||||||
{ 1915, 11, 10, 14, 2, -9 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
|
|
||||||
{ 1929, 14, 14, 14, 0, -13 }, // 0x9c 'LATIN CAPITAL LIGATURE OE *' U+0152
|
|
||||||
{ 1954, 14, 10, 14, 0, -9 }, // 0x9d 'LATIN SMALL LIGATURE OE *' U+0153
|
|
||||||
{ 1972, 12, 17, 14, 1, -16 }, // 0x9e 'LATIN CAPITAL LETTER Y WITH DIAERESIS *' U+0178
|
|
||||||
{ 1998, 8, 14, 14, 3, -9 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
|
|
||||||
{ 2012, 14, 19, 14, 0, -18 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
|
|
||||||
{ 2046, 14, 19, 14, 0, -18 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
|
|
||||||
{ 2080, 14, 18, 14, 0, -17 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
|
|
||||||
{ 2112, 14, 17, 14, 0, -16 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
|
|
||||||
{ 2142, 14, 17, 14, 0, -16 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
|
|
||||||
{ 2172, 14, 19, 14, 0, -18 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
|
|
||||||
{ 2206, 14, 14, 14, 0, -13 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
|
|
||||||
{ 2231, 11, 18, 14, 2, -13 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
|
|
||||||
{ 2256, 11, 19, 14, 1, -18 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
|
|
||||||
{ 2283, 11, 19, 14, 1, -18 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
|
|
||||||
{ 2310, 11, 18, 14, 1, -17 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
|
|
||||||
{ 2335, 11, 17, 14, 1, -16 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
|
|
||||||
{ 2359, 9, 19, 14, 3, -18 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
|
|
||||||
{ 2381, 9, 19, 14, 3, -18 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
|
|
||||||
{ 2403, 9, 18, 14, 3, -17 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
|
|
||||||
{ 2424, 9, 17, 14, 3, -16 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
|
|
||||||
{ 2444, 12, 14, 14, 0, -13 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
|
|
||||||
{ 2465, 12, 17, 14, 1, -16 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
|
|
||||||
{ 2491, 12, 19, 14, 1, -18 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
|
|
||||||
{ 2520, 12, 19, 14, 1, -18 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
|
|
||||||
{ 2549, 12, 18, 14, 1, -17 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
|
|
||||||
{ 2576, 12, 17, 14, 1, -16 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
|
|
||||||
{ 2602, 12, 17, 14, 1, -16 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
|
|
||||||
{ 2628, 9, 9, 14, 3, -10 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
|
|
||||||
{ 2639, 12, 16, 14, 1, -14 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
|
|
||||||
{ 2663, 12, 19, 14, 1, -18 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
|
|
||||||
{ 2692, 12, 19, 14, 1, -18 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
|
|
||||||
{ 2721, 12, 18, 14, 1, -17 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
|
|
||||||
{ 2748, 12, 17, 14, 1, -16 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
|
|
||||||
{ 2774, 12, 19, 14, 1, -18 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
|
|
||||||
{ 2803, 11, 14, 14, 1, -13 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
|
|
||||||
{ 2823, 11, 15, 14, 1, -14 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
|
|
||||||
{ 2844, 11, 15, 14, 2, -14 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
|
|
||||||
{ 2865, 11, 15, 14, 2, -14 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
|
|
||||||
{ 2886, 11, 15, 14, 2, -14 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
|
|
||||||
{ 2907, 11, 14, 14, 2, -13 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
|
|
||||||
{ 2927, 11, 14, 14, 2, -13 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
|
|
||||||
{ 2947, 11, 16, 14, 2, -15 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
|
|
||||||
{ 2969, 14, 10, 14, 0, -9 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
|
|
||||||
{ 2987, 11, 14, 14, 2, -9 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
|
|
||||||
{ 3007, 10, 15, 14, 2, -14 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
|
|
||||||
{ 3026, 10, 15, 14, 2, -14 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
|
|
||||||
{ 3045, 10, 15, 14, 2, -14 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
|
|
||||||
{ 3064, 10, 14, 14, 2, -13 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
|
|
||||||
{ 3082, 10, 15, 14, 2, -14 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
|
|
||||||
{ 3101, 10, 15, 14, 2, -14 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
|
|
||||||
{ 3120, 10, 15, 14, 2, -14 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
|
|
||||||
{ 3139, 10, 14, 14, 2, -13 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
|
|
||||||
{ 3157, 11, 15, 14, 2, -14 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
|
|
||||||
{ 3178, 12, 14, 14, 1, -13 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
|
|
||||||
{ 3199, 11, 15, 14, 2, -14 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
|
|
||||||
{ 3220, 11, 15, 14, 2, -14 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
|
|
||||||
{ 3241, 11, 15, 14, 2, -14 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
|
|
||||||
{ 3262, 11, 14, 14, 2, -13 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
|
|
||||||
{ 3282, 11, 14, 14, 2, -13 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
|
|
||||||
{ 3302, 11, 12, 14, 2, -12 }, // 0xd7 'DIVISION SIGN' U+00F7
|
|
||||||
{ 3319, 12, 12, 14, 1, -10 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
|
|
||||||
{ 3337, 12, 15, 14, 1, -14 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
|
|
||||||
{ 3360, 12, 15, 14, 1, -14 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
|
|
||||||
{ 3383, 12, 15, 14, 1, -14 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
|
|
||||||
{ 3406, 12, 14, 14, 1, -13 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
|
|
||||||
{ 3427, 12, 19, 14, 1, -14 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
|
|
||||||
{ 3456, 12, 18, 14, 1, -13 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
|
|
||||||
{ 3483, 12, 18, 14, 1, -13 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
|
|
||||||
|
|
||||||
const GFXfont FreeMono12pt8b PROGMEM = {
|
|
||||||
(uint8_t *)FreeMono12pt8bBitmaps,
|
|
||||||
(GFXglyph *)FreeMono12pt8bGlyphs,
|
|
||||||
0x20, 0xDF, 26 };
|
|
||||||
|
|
||||||
// Approx. 4861 bytes
|
|
|
@ -1,374 +0,0 @@
|
||||||
const uint8_t FreeMono9pt8bBitmaps[] PROGMEM = {
|
|
||||||
0x00, 0x55, 0x54, 0x1C, 0xDE, 0xF7, 0x39, 0x80, 0x20, 0x50, 0xA1, 0x42,
|
|
||||||
0x9F, 0xCA, 0x14, 0xFE, 0x91, 0x22, 0x44, 0x80, 0x10, 0x21, 0xB4, 0x08,
|
|
||||||
0x08, 0x0F, 0x01, 0x83, 0x0B, 0xE0, 0x81, 0x02, 0x00, 0x71, 0x22, 0x44,
|
|
||||||
0x86, 0x23, 0xB8, 0x0E, 0x22, 0x44, 0x70, 0x78, 0x81, 0x02, 0x06, 0x12,
|
|
||||||
0xA6, 0x44, 0x76, 0xD9, 0x24, 0x25, 0x25, 0x24, 0x49, 0x12, 0x91, 0x24,
|
|
||||||
0x9B, 0x49, 0x48, 0x10, 0x22, 0x4B, 0xE2, 0x89, 0x00, 0x00, 0x08, 0x04,
|
|
||||||
0x02, 0x01, 0x00, 0x83, 0xF8, 0x20, 0x10, 0x08, 0x00, 0x37, 0x64, 0x40,
|
|
||||||
0x7F, 0x00, 0xFC, 0x02, 0x08, 0x10, 0x40, 0x82, 0x04, 0x10, 0x20, 0x41,
|
|
||||||
0x02, 0x08, 0x00, 0x38, 0x8A, 0x14, 0x18, 0x30, 0x60, 0xC1, 0x82, 0x89,
|
|
||||||
0xE0, 0x30, 0xA2, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x23, 0xF8, 0x79,
|
|
||||||
0x0A, 0x10, 0x20, 0x41, 0x04, 0x10, 0x41, 0x07, 0xF8, 0x79, 0x08, 0x08,
|
|
||||||
0x20, 0xC3, 0x80, 0x81, 0x02, 0x07, 0xF0, 0x0C, 0x28, 0x91, 0x24, 0x48,
|
|
||||||
0xA1, 0x7F, 0x04, 0x08, 0x78, 0x7D, 0x02, 0x04, 0x07, 0xC0, 0x40, 0x81,
|
|
||||||
0x03, 0x09, 0xF0, 0x1E, 0x41, 0x02, 0x08, 0x96, 0xB0, 0xC1, 0x42, 0x84,
|
|
||||||
0xF0, 0xFF, 0x04, 0x10, 0x20, 0x41, 0x02, 0x04, 0x10, 0x20, 0x40, 0x79,
|
|
||||||
0x0A, 0x0C, 0x14, 0x47, 0x31, 0x41, 0x83, 0x09, 0xF0, 0x38, 0x8A, 0x0C,
|
|
||||||
0x18, 0x28, 0xCE, 0x81, 0x04, 0x09, 0xE0, 0x1F, 0x00, 0x3F, 0x03, 0x30,
|
|
||||||
0x03, 0x76, 0x44, 0x00, 0x03, 0x04, 0x18, 0x60, 0x60, 0x18, 0x04, 0x03,
|
|
||||||
0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x40, 0x18, 0x03, 0x00, 0x60, 0x20, 0x60,
|
|
||||||
0xC0, 0x80, 0xFD, 0x04, 0x08, 0x10, 0xC2, 0x04, 0x00, 0x10, 0x70, 0x78,
|
|
||||||
0x8A, 0x14, 0x29, 0xD4, 0xA9, 0x4A, 0x89, 0x01, 0x01, 0xE0, 0x3C, 0x01,
|
|
||||||
0x40, 0x48, 0x09, 0x01, 0x10, 0x42, 0x0F, 0xC1, 0x04, 0x40, 0x9E, 0x3C,
|
|
||||||
0xFE, 0x20, 0x90, 0x48, 0x27, 0xE2, 0x09, 0x02, 0x81, 0x41, 0x7F, 0x00,
|
|
||||||
0x3F, 0x20, 0xA0, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x41, 0x1F, 0x00,
|
|
||||||
0xFC, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0xFC, 0xFF, 0x41,
|
|
||||||
0x41, 0x40, 0x78, 0x48, 0x40, 0x41, 0x41, 0xFF, 0xFF, 0x41, 0x40, 0x40,
|
|
||||||
0x78, 0x48, 0x40, 0x40, 0x40, 0xF8, 0x3F, 0x20, 0xA0, 0x10, 0x08, 0x04,
|
|
||||||
0x3E, 0x05, 0x02, 0x41, 0x1F, 0x80, 0xE3, 0x20, 0x90, 0x48, 0x27, 0xF2,
|
|
||||||
0x09, 0x04, 0x82, 0x41, 0x73, 0xC0, 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04,
|
|
||||||
0x08, 0x11, 0xFC, 0x3F, 0x02, 0x01, 0x00, 0x80, 0x40, 0x22, 0x11, 0x08,
|
|
||||||
0x84, 0x3C, 0x00, 0xF3, 0xA1, 0x11, 0x09, 0x05, 0x83, 0x21, 0x08, 0x84,
|
|
||||||
0x42, 0x78, 0xC0, 0xF8, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x82, 0x41,
|
|
||||||
0x20, 0xFF, 0xC0, 0xE0, 0xCC, 0x29, 0x45, 0x29, 0x24, 0xA4, 0x94, 0x91,
|
|
||||||
0x12, 0x02, 0x40, 0x5E, 0x3C, 0x61, 0xCC, 0x23, 0x08, 0xA2, 0x24, 0x89,
|
|
||||||
0x22, 0x28, 0x8A, 0x21, 0x9C, 0x20, 0x3E, 0x20, 0xA0, 0x50, 0x18, 0x0C,
|
|
||||||
0x06, 0x03, 0x02, 0x41, 0x1F, 0x00, 0xFE, 0x41, 0x41, 0x41, 0x42, 0x7C,
|
|
||||||
0x40, 0x40, 0x40, 0xF8, 0x3E, 0x20, 0xA0, 0x50, 0x18, 0x0C, 0x06, 0x03,
|
|
||||||
0x02, 0x41, 0x1B, 0x06, 0x07, 0xF0, 0xFE, 0x10, 0x44, 0x11, 0x04, 0x42,
|
|
||||||
0x1F, 0x04, 0x21, 0x08, 0x41, 0x3C, 0x30, 0x7F, 0x06, 0x0C, 0x07, 0x01,
|
|
||||||
0x80, 0x81, 0x83, 0xF8, 0xFF, 0xC4, 0x42, 0x01, 0x00, 0x80, 0x40, 0x20,
|
|
||||||
0x10, 0x08, 0x1F, 0x00, 0xE3, 0xA0, 0x90, 0x48, 0x24, 0x12, 0x09, 0x04,
|
|
||||||
0x82, 0x41, 0x1F, 0x00, 0xF1, 0xE8, 0x10, 0x82, 0x10, 0x82, 0x10, 0x22,
|
|
||||||
0x04, 0x80, 0x50, 0x0C, 0x00, 0x80, 0xF1, 0xD0, 0x14, 0x49, 0x32, 0x4A,
|
|
||||||
0x92, 0xA3, 0x28, 0xCA, 0x31, 0x88, 0x60, 0xE3, 0xA1, 0x08, 0x82, 0x80,
|
|
||||||
0x80, 0xC0, 0x50, 0x44, 0x41, 0x71, 0xC0, 0xE3, 0xA1, 0x08, 0x82, 0x81,
|
|
||||||
0x80, 0x40, 0x20, 0x10, 0x08, 0x1F, 0x00, 0xFD, 0x0A, 0x20, 0x41, 0x04,
|
|
||||||
0x10, 0xA1, 0x83, 0xFC, 0xF2, 0x49, 0x24, 0x92, 0x4E, 0x81, 0x01, 0x02,
|
|
||||||
0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0xE4, 0x92, 0x49,
|
|
||||||
0x24, 0x9E, 0x10, 0x51, 0x24, 0x28, 0x20, 0xFF, 0xE0, 0x11, 0x80, 0x1C,
|
|
||||||
0x31, 0x00, 0x83, 0xC6, 0x24, 0x12, 0x08, 0xFB, 0xE0, 0x08, 0x02, 0x00,
|
|
||||||
0xB8, 0x31, 0x88, 0x22, 0x04, 0x81, 0x20, 0x48, 0x2F, 0xF0, 0x38, 0x46,
|
|
||||||
0x82, 0x80, 0x80, 0x80, 0x81, 0x7E, 0x03, 0x00, 0x40, 0x10, 0x64, 0x67,
|
|
||||||
0x20, 0x48, 0x12, 0x04, 0x81, 0x10, 0xC3, 0xD8, 0x1C, 0x62, 0x81, 0x81,
|
|
||||||
0xFE, 0x80, 0x40, 0x3F, 0x1F, 0x20, 0x20, 0x7C, 0x20, 0x20, 0x20, 0x20,
|
|
||||||
0x20, 0x20, 0xFE, 0x39, 0xA3, 0xA0, 0x50, 0x28, 0x14, 0x09, 0x0C, 0x7A,
|
|
||||||
0x01, 0x01, 0x07, 0x80, 0xC0, 0x20, 0x10, 0x0B, 0x86, 0x22, 0x09, 0x04,
|
|
||||||
0x82, 0x41, 0x20, 0xB8, 0xE0, 0x10, 0x20, 0x03, 0x81, 0x02, 0x04, 0x08,
|
|
||||||
0x10, 0x23, 0xF8, 0x10, 0x81, 0xF0, 0x84, 0x21, 0x08, 0x42, 0x10, 0xFC,
|
|
||||||
0xC0, 0x20, 0x10, 0x08, 0xC4, 0x42, 0x41, 0x40, 0x50, 0x44, 0x21, 0x31,
|
|
||||||
0xE0, 0xF0, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x23, 0xF8, 0x59,
|
|
||||||
0x8C, 0xD1, 0x11, 0x22, 0x24, 0x44, 0x88, 0x91, 0x17, 0x33, 0x5C, 0x31,
|
|
||||||
0x10, 0x48, 0x24, 0x12, 0x09, 0x05, 0xC7, 0x1C, 0x31, 0x10, 0x50, 0x28,
|
|
||||||
0x14, 0x09, 0x04, 0x7C, 0x6E, 0x0C, 0x62, 0x08, 0x81, 0x20, 0x48, 0x23,
|
|
||||||
0x08, 0xBC, 0x20, 0x08, 0x07, 0x00, 0x1D, 0x98, 0xC8, 0x12, 0x04, 0x81,
|
|
||||||
0x20, 0x44, 0x30, 0xF4, 0x01, 0x00, 0x40, 0x38, 0xC6, 0x59, 0x20, 0x40,
|
|
||||||
0x40, 0x40, 0x40, 0xFC, 0x39, 0x8E, 0x03, 0x01, 0xC0, 0x60, 0xFE, 0x40,
|
|
||||||
0x40, 0xFC, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x3F, 0xC3, 0x20, 0x90,
|
|
||||||
0x48, 0x24, 0x12, 0x09, 0x0C, 0x7B, 0xE3, 0xA0, 0x90, 0x84, 0x42, 0x21,
|
|
||||||
0x20, 0x50, 0x10, 0xC1, 0xC0, 0xA2, 0x49, 0x25, 0x52, 0xB1, 0x98, 0x44,
|
|
||||||
0x63, 0x20, 0x88, 0x83, 0x81, 0x81, 0x21, 0x09, 0xC7, 0xC3, 0x20, 0x90,
|
|
||||||
0x44, 0x42, 0x20, 0xA0, 0x50, 0x10, 0x08, 0x08, 0x1E, 0x00, 0xFF, 0x0A,
|
|
||||||
0x20, 0x81, 0x04, 0x10, 0xFF, 0x12, 0x22, 0x22, 0xC2, 0x22, 0x22, 0x30,
|
|
||||||
0xFF, 0xF8, 0xC1, 0x08, 0x42, 0x10, 0x64, 0x21, 0x08, 0x44, 0x00, 0xE2,
|
|
||||||
0x38, 0xFF, 0xF0, 0x06, 0xFC, 0xD0, 0x58, 0x0B, 0x01, 0x60, 0xCC, 0x21,
|
|
||||||
0x84, 0x30, 0x06, 0x10, 0xC7, 0x18, 0x03, 0xFF, 0xC0, 0x00, 0xC0, 0x55,
|
|
||||||
0x54, 0x10, 0x43, 0x91, 0x82, 0x08, 0x11, 0x38, 0x41, 0x00, 0x3C, 0x20,
|
|
||||||
0x20, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x21, 0x7F, 0x3F, 0xA0, 0x90, 0x10,
|
|
||||||
0x0F, 0xE7, 0xE2, 0x00, 0x80, 0x20, 0x8F, 0x80, 0xE3, 0xA1, 0x08, 0x82,
|
|
||||||
0x81, 0x83, 0xF8, 0x20, 0x7C, 0x08, 0x1F, 0x00, 0x6C, 0x20, 0x03, 0xF8,
|
|
||||||
0x30, 0x60, 0x38, 0x0C, 0x04, 0x0C, 0x1F, 0xC0, 0x1F, 0x10, 0x88, 0x4C,
|
|
||||||
0x09, 0x82, 0x30, 0x84, 0x31, 0x07, 0x01, 0x10, 0x8F, 0x80, 0x00, 0xD8,
|
|
||||||
0x40, 0x03, 0x98, 0xE0, 0x30, 0x1C, 0x06, 0x0F, 0xE0, 0x3F, 0x08, 0x12,
|
|
||||||
0x3D, 0x48, 0x9A, 0x03, 0x40, 0x64, 0x4A, 0x72, 0x40, 0x87, 0xE0, 0xF0,
|
|
||||||
0xBD, 0x2F, 0x80, 0x00, 0x08, 0x88, 0x88, 0xCC, 0x43, 0x10, 0x44, 0x11,
|
|
||||||
0xFF, 0x80, 0x40, 0x20, 0x10, 0x00, 0x7F, 0x00, 0x3F, 0x08, 0x12, 0x79,
|
|
||||||
0x49, 0x19, 0x23, 0x3C, 0x64, 0x8A, 0xCA, 0x40, 0x87, 0xE0, 0xF8, 0xF4,
|
|
||||||
0x63, 0x17, 0x00, 0x00, 0x04, 0x02, 0x01, 0x0F, 0xF0, 0x40, 0x20, 0x10,
|
|
||||||
0x00, 0x7F, 0x80, 0x79, 0x12, 0x4F, 0x71, 0x13, 0x1F, 0x04, 0xD0, 0x40,
|
|
||||||
0x0F, 0xD0, 0xA2, 0x04, 0x10, 0x41, 0x0A, 0x18, 0x3F, 0xC0, 0xC3, 0x20,
|
|
||||||
0x90, 0x48, 0x24, 0x12, 0x09, 0x0C, 0xDB, 0x50, 0x20, 0x10, 0x08, 0x00,
|
|
||||||
0x3F, 0x6A, 0xCA, 0xCA, 0x4A, 0x7A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x3B,
|
|
||||||
0x50, 0x00, 0xD8, 0x40, 0x0F, 0xF0, 0xA2, 0x08, 0x10, 0x41, 0x0F, 0xF0,
|
|
||||||
0x62, 0x22, 0x27, 0xF4, 0x63, 0x17, 0x00, 0x00, 0x22, 0x18, 0x86, 0x61,
|
|
||||||
0x11, 0x11, 0x11, 0x10, 0x3F, 0xC8, 0x8A, 0x11, 0x42, 0x08, 0x71, 0x0A,
|
|
||||||
0x21, 0x02, 0x21, 0x44, 0x27, 0xFC, 0x31, 0x92, 0x98, 0x46, 0x11, 0x87,
|
|
||||||
0xA1, 0x04, 0xC1, 0xEF, 0x22, 0x11, 0x00, 0x1C, 0x74, 0x21, 0x10, 0x50,
|
|
||||||
0x30, 0x08, 0x04, 0x02, 0x01, 0x03, 0xE0, 0x10, 0xE0, 0x00, 0x10, 0xC4,
|
|
||||||
0x20, 0x82, 0x17, 0xC0, 0x10, 0x01, 0x00, 0x10, 0x00, 0x03, 0xC0, 0x14,
|
|
||||||
0x04, 0x80, 0x90, 0x11, 0x04, 0x20, 0xFC, 0x10, 0x44, 0x09, 0xE3, 0xC0,
|
|
||||||
0x02, 0x00, 0x80, 0x20, 0x00, 0x03, 0xC0, 0x14, 0x04, 0x80, 0x90, 0x11,
|
|
||||||
0x04, 0x20, 0xFC, 0x10, 0x44, 0x09, 0xE3, 0xC0, 0x04, 0x01, 0x40, 0x44,
|
|
||||||
0x00, 0x03, 0xC0, 0x14, 0x04, 0x80, 0x90, 0x11, 0x04, 0x20, 0xFC, 0x10,
|
|
||||||
0x44, 0x09, 0xE3, 0xC0, 0x08, 0x02, 0xE0, 0x00, 0x1E, 0x00, 0xA0, 0x24,
|
|
||||||
0x04, 0x80, 0x88, 0x21, 0x07, 0xE0, 0x82, 0x20, 0x4F, 0x1E, 0x11, 0x02,
|
|
||||||
0x20, 0x00, 0x1E, 0x00, 0xA0, 0x24, 0x04, 0x80, 0x88, 0x21, 0x07, 0xE0,
|
|
||||||
0x82, 0x20, 0x4F, 0x1E, 0x0E, 0x02, 0x40, 0x30, 0x00, 0x03, 0xC0, 0x14,
|
|
||||||
0x04, 0x80, 0x90, 0x11, 0x04, 0x20, 0xFC, 0x10, 0x44, 0x09, 0xE3, 0xC0,
|
|
||||||
0x3F, 0xC2, 0x88, 0x51, 0x0A, 0x02, 0x70, 0x4A, 0x0F, 0x01, 0x21, 0x44,
|
|
||||||
0x3D, 0xFC, 0x3F, 0x20, 0xA0, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x41,
|
|
||||||
0x1B, 0x02, 0x00, 0x81, 0xC0, 0x20, 0x10, 0x08, 0x00, 0xFF, 0x41, 0x41,
|
|
||||||
0x40, 0x78, 0x48, 0x40, 0x41, 0x41, 0xFF, 0x04, 0x08, 0x10, 0x00, 0xFF,
|
|
||||||
0x41, 0x41, 0x40, 0x78, 0x48, 0x40, 0x41, 0x41, 0xFF, 0x00, 0x1C, 0x22,
|
|
||||||
0x00, 0xFF, 0x41, 0x41, 0x40, 0x78, 0x48, 0x40, 0x41, 0x41, 0xFF, 0x22,
|
|
||||||
0x66, 0x00, 0xFF, 0x41, 0x41, 0x40, 0x78, 0x48, 0x40, 0x41, 0x41, 0xFF,
|
|
||||||
0x20, 0x20, 0x00, 0x0F, 0xE2, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x1F,
|
|
||||||
0xC0, 0x04, 0x10, 0x40, 0x0F, 0xE2, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81,
|
|
||||||
0x1F, 0xC0, 0x10, 0x51, 0x10, 0x0F, 0xE2, 0x04, 0x08, 0x10, 0x20, 0x40,
|
|
||||||
0x81, 0x1F, 0xC0, 0x44, 0x88, 0x07, 0xF1, 0x02, 0x04, 0x08, 0x10, 0x20,
|
|
||||||
0x40, 0x8F, 0xE0, 0x7E, 0x10, 0x88, 0x24, 0x1F, 0xC9, 0x04, 0x82, 0x41,
|
|
||||||
0x21, 0x3F, 0x00, 0x19, 0x09, 0x80, 0x01, 0x87, 0x30, 0x8C, 0x22, 0x88,
|
|
||||||
0x92, 0x24, 0x88, 0xA2, 0x28, 0x86, 0x70, 0x80, 0x20, 0x0C, 0x00, 0x00,
|
|
||||||
0x03, 0xE2, 0x0A, 0x05, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x24, 0x11, 0xF0,
|
|
||||||
0x04, 0x04, 0x04, 0x00, 0x03, 0xE2, 0x0A, 0x05, 0x01, 0x80, 0xC0, 0x60,
|
|
||||||
0x30, 0x24, 0x11, 0xF0, 0x08, 0x0A, 0x08, 0x80, 0x03, 0xE2, 0x0A, 0x05,
|
|
||||||
0x01, 0x80, 0xC0, 0x60, 0x30, 0x24, 0x11, 0xF0, 0x10, 0x17, 0x00, 0x07,
|
|
||||||
0xC4, 0x14, 0x0A, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x48, 0x23, 0xE0, 0x22,
|
|
||||||
0x11, 0x00, 0x07, 0xC4, 0x14, 0x0A, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x48,
|
|
||||||
0x23, 0xE0, 0x84, 0x90, 0xC1, 0x84, 0x90, 0x80, 0x00, 0x9F, 0x90, 0x50,
|
|
||||||
0x68, 0x4C, 0x46, 0x43, 0x21, 0xA1, 0x20, 0xAD, 0x81, 0x00, 0x20, 0x0C,
|
|
||||||
0x00, 0x00, 0x0E, 0x3A, 0x09, 0x04, 0x82, 0x41, 0x20, 0x90, 0x48, 0x24,
|
|
||||||
0x11, 0xF0, 0x04, 0x04, 0x04, 0x00, 0x0E, 0x3A, 0x09, 0x04, 0x82, 0x41,
|
|
||||||
0x20, 0x90, 0x48, 0x24, 0x11, 0xF0, 0x08, 0x0A, 0x08, 0x80, 0x0E, 0x3A,
|
|
||||||
0x09, 0x04, 0x82, 0x41, 0x20, 0x90, 0x48, 0x24, 0x11, 0xF0, 0x22, 0x11,
|
|
||||||
0x00, 0x1C, 0x74, 0x12, 0x09, 0x04, 0x82, 0x41, 0x20, 0x90, 0x48, 0x23,
|
|
||||||
0xE0, 0x04, 0x04, 0x04, 0x00, 0x0E, 0x3A, 0x10, 0x88, 0x28, 0x18, 0x04,
|
|
||||||
0x02, 0x01, 0x00, 0x81, 0xF0, 0xF8, 0x40, 0x7C, 0x43, 0x41, 0x41, 0x41,
|
|
||||||
0x7E, 0x40, 0xF8, 0x1C, 0x11, 0x08, 0x84, 0x42, 0xC1, 0x18, 0x82, 0x41,
|
|
||||||
0x20, 0x94, 0x79, 0xC0, 0x20, 0x08, 0x02, 0x00, 0x01, 0xC3, 0x10, 0x08,
|
|
||||||
0x3C, 0x62, 0x41, 0x20, 0x8F, 0xB0, 0x00, 0x06, 0x04, 0x00, 0x01, 0xC3,
|
|
||||||
0x10, 0x08, 0x3C, 0x62, 0x41, 0x20, 0x8F, 0xB0, 0x18, 0x12, 0x00, 0x03,
|
|
||||||
0x86, 0x20, 0x10, 0x78, 0xC4, 0x82, 0x41, 0x1F, 0x60, 0x3E, 0x00, 0x07,
|
|
||||||
0x0C, 0x40, 0x20, 0xF1, 0x89, 0x04, 0x82, 0x3E, 0xC0, 0x22, 0x33, 0x00,
|
|
||||||
0x03, 0x86, 0x20, 0x10, 0x78, 0xC4, 0x82, 0x41, 0x1F, 0x60, 0x1C, 0x12,
|
|
||||||
0x05, 0x01, 0x01, 0xC3, 0x10, 0x08, 0x3C, 0x62, 0x41, 0x20, 0x8F, 0xB0,
|
|
||||||
0x39, 0x91, 0x90, 0x44, 0xF1, 0x47, 0xA1, 0x08, 0x41, 0xFF, 0x38, 0x46,
|
|
||||||
0x82, 0x80, 0x80, 0x80, 0x81, 0x6E, 0x10, 0x08, 0x38, 0x00, 0x10, 0x08,
|
|
||||||
0x00, 0x1C, 0x62, 0x81, 0x81, 0xFE, 0x80, 0x40, 0x3F, 0x00, 0x04, 0x18,
|
|
||||||
0x00, 0x1C, 0x62, 0x81, 0x81, 0xFE, 0x80, 0x40, 0x3F, 0x08, 0x36, 0x00,
|
|
||||||
0x1C, 0x62, 0x81, 0x81, 0xFE, 0x80, 0x40, 0x3F, 0x22, 0x22, 0x00, 0x1C,
|
|
||||||
0x62, 0x81, 0x81, 0xFE, 0x80, 0x40, 0x3F, 0x40, 0x40, 0x40, 0x07, 0x02,
|
|
||||||
0x04, 0x08, 0x10, 0x20, 0x47, 0xF0, 0x00, 0x30, 0x80, 0x07, 0x02, 0x04,
|
|
||||||
0x08, 0x10, 0x20, 0x47, 0xF0, 0x30, 0x90, 0x03, 0x81, 0x02, 0x04, 0x08,
|
|
||||||
0x10, 0x23, 0xF8, 0x45, 0x98, 0x03, 0x81, 0x02, 0x04, 0x08, 0x10, 0x23,
|
|
||||||
0xF8, 0x36, 0x0E, 0x00, 0x83, 0xC6, 0x32, 0x0A, 0x05, 0x02, 0x81, 0x20,
|
|
||||||
0x8F, 0x80, 0x3E, 0x00, 0x17, 0x0C, 0x44, 0x12, 0x09, 0x04, 0x82, 0x41,
|
|
||||||
0x71, 0xC0, 0x00, 0x08, 0x02, 0x00, 0x01, 0xC3, 0x11, 0x05, 0x02, 0x81,
|
|
||||||
0x40, 0x90, 0x47, 0xC0, 0x00, 0x02, 0x06, 0x00, 0x01, 0xC3, 0x11, 0x05,
|
|
||||||
0x02, 0x81, 0x40, 0x90, 0x47, 0xC0, 0x18, 0x13, 0x00, 0x03, 0x86, 0x22,
|
|
||||||
0x0A, 0x05, 0x02, 0x81, 0x20, 0x8F, 0x80, 0x3E, 0x00, 0x07, 0x0C, 0x44,
|
|
||||||
0x14, 0x0A, 0x05, 0x02, 0x41, 0x1F, 0x00, 0x22, 0x11, 0x00, 0x03, 0x86,
|
|
||||||
0x22, 0x0A, 0x05, 0x02, 0x81, 0x20, 0x8F, 0x80, 0x08, 0x04, 0x00, 0x00,
|
|
||||||
0x00, 0x03, 0xF8, 0x00, 0x00, 0x08, 0x04, 0x00, 0x1D, 0x31, 0x10, 0xD0,
|
|
||||||
0xA8, 0x94, 0x89, 0x84, 0xEC, 0x88, 0x00, 0x00, 0x08, 0x02, 0x00, 0x0C,
|
|
||||||
0x32, 0x09, 0x04, 0x82, 0x41, 0x20, 0x90, 0xC7, 0xB0, 0x04, 0x04, 0x04,
|
|
||||||
0x00, 0x0C, 0x32, 0x09, 0x04, 0x82, 0x41, 0x20, 0x90, 0xC7, 0xB0, 0x18,
|
|
||||||
0x12, 0x00, 0x18, 0x64, 0x12, 0x09, 0x04, 0x82, 0x41, 0x21, 0x8F, 0x60,
|
|
||||||
0x22, 0x33, 0x00, 0x18, 0x64, 0x12, 0x09, 0x04, 0x82, 0x41, 0x21, 0x8F,
|
|
||||||
0x60, 0x02, 0x02, 0x02, 0x00, 0x0C, 0x32, 0x09, 0x04, 0x44, 0x22, 0x0A,
|
|
||||||
0x05, 0x01, 0x00, 0x80, 0x81, 0xE0, 0xE0, 0x08, 0x02, 0x00, 0xB8, 0x31,
|
|
||||||
0x88, 0x22, 0x04, 0x81, 0x20, 0x8C, 0x22, 0xF0, 0x80, 0x20, 0x1C, 0x00,
|
|
||||||
0x22, 0x11, 0x00, 0x18, 0x64, 0x12, 0x08, 0x88, 0x44, 0x14, 0x0A, 0x02,
|
|
||||||
0x01, 0x01, 0x03, 0xC0 };
|
|
||||||
|
|
||||||
const GFXglyph FreeMono9pt8bGlyphs[] PROGMEM = {
|
|
||||||
{ 0, 1, 1, 11, 0, 0 }, // 0x20 ' ' U+0020
|
|
||||||
{ 1, 2, 11, 11, 4, -10 }, // 0x21 '!' U+0021
|
|
||||||
{ 4, 5, 5, 11, 3, -10 }, // 0x22 '"' U+0022
|
|
||||||
{ 8, 7, 13, 11, 2, -11 }, // 0x23 '#' U+0023
|
|
||||||
{ 20, 7, 14, 11, 2, -11 }, // 0x24 '$' U+0024
|
|
||||||
{ 33, 7, 11, 11, 2, -10 }, // 0x25 '%' U+0025
|
|
||||||
{ 43, 7, 9, 11, 2, -8 }, // 0x26 '&' U+0026
|
|
||||||
{ 51, 3, 5, 11, 4, -10 }, // 0x27 ''' U+0027
|
|
||||||
{ 53, 3, 13, 11, 5, -10 }, // 0x28 '(' U+0028
|
|
||||||
{ 58, 3, 13, 11, 3, -10 }, // 0x29 ')' U+0029
|
|
||||||
{ 63, 7, 7, 11, 2, -10 }, // 0x2a '*' U+002A
|
|
||||||
{ 70, 9, 9, 11, 1, -9 }, // 0x2b '+' U+002B
|
|
||||||
{ 81, 4, 6, 11, 2, -2 }, // 0x2c ',' U+002C
|
|
||||||
{ 84, 9, 1, 11, 1, -5 }, // 0x2d '-' U+002D
|
|
||||||
{ 86, 3, 2, 11, 4, -1 }, // 0x2e '.' U+002E
|
|
||||||
{ 87, 7, 13, 11, 2, -11 }, // 0x2f '/' U+002F
|
|
||||||
{ 99, 7, 11, 11, 2, -10 }, // 0x30 '0' U+0030
|
|
||||||
{ 109, 7, 11, 11, 2, -10 }, // 0x31 '1' U+0031
|
|
||||||
{ 119, 7, 11, 11, 2, -10 }, // 0x32 '2' U+0032
|
|
||||||
{ 129, 7, 11, 11, 2, -10 }, // 0x33 '3' U+0033
|
|
||||||
{ 139, 7, 11, 11, 2, -10 }, // 0x34 '4' U+0034
|
|
||||||
{ 149, 7, 11, 11, 2, -10 }, // 0x35 '5' U+0035
|
|
||||||
{ 159, 7, 11, 11, 2, -10 }, // 0x36 '6' U+0036
|
|
||||||
{ 169, 7, 11, 11, 2, -10 }, // 0x37 '7' U+0037
|
|
||||||
{ 179, 7, 11, 11, 2, -10 }, // 0x38 '8' U+0038
|
|
||||||
{ 189, 7, 11, 11, 2, -10 }, // 0x39 '9' U+0039
|
|
||||||
{ 199, 3, 8, 11, 4, -7 }, // 0x3a ':' U+003A
|
|
||||||
{ 202, 4, 11, 11, 2, -7 }, // 0x3b ';' U+003B
|
|
||||||
{ 208, 8, 8, 11, 1, -8 }, // 0x3c '<' U+003C
|
|
||||||
{ 216, 9, 4, 11, 1, -6 }, // 0x3d '=' U+003D
|
|
||||||
{ 221, 9, 8, 11, 1, -8 }, // 0x3e '>' U+003E
|
|
||||||
{ 230, 7, 10, 11, 2, -9 }, // 0x3f '?' U+003F
|
|
||||||
{ 239, 7, 12, 11, 2, -10 }, // 0x40 '@' U+0040
|
|
||||||
{ 250, 11, 10, 11, 0, -9 }, // 0x41 'A' U+0041
|
|
||||||
{ 264, 9, 10, 11, 1, -9 }, // 0x42 'B' U+0042
|
|
||||||
{ 276, 9, 10, 11, 1, -9 }, // 0x43 'C' U+0043
|
|
||||||
{ 288, 8, 10, 11, 1, -9 }, // 0x44 'D' U+0044
|
|
||||||
{ 298, 8, 10, 11, 1, -9 }, // 0x45 'E' U+0045
|
|
||||||
{ 308, 8, 10, 11, 1, -9 }, // 0x46 'F' U+0046
|
|
||||||
{ 318, 9, 10, 11, 1, -9 }, // 0x47 'G' U+0047
|
|
||||||
{ 330, 9, 10, 11, 1, -9 }, // 0x48 'H' U+0048
|
|
||||||
{ 342, 7, 10, 11, 2, -9 }, // 0x49 'I' U+0049
|
|
||||||
{ 351, 9, 10, 11, 2, -9 }, // 0x4a 'J' U+004A
|
|
||||||
{ 363, 9, 10, 11, 1, -9 }, // 0x4b 'K' U+004B
|
|
||||||
{ 375, 9, 10, 11, 1, -9 }, // 0x4c 'L' U+004C
|
|
||||||
{ 387, 11, 10, 11, 0, -9 }, // 0x4d 'M' U+004D
|
|
||||||
{ 401, 10, 10, 11, 0, -9 }, // 0x4e 'N' U+004E
|
|
||||||
{ 414, 9, 10, 11, 1, -9 }, // 0x4f 'O' U+004F
|
|
||||||
{ 426, 8, 10, 11, 1, -9 }, // 0x50 'P' U+0050
|
|
||||||
{ 436, 9, 12, 11, 1, -9 }, // 0x51 'Q' U+0051
|
|
||||||
{ 450, 10, 10, 11, 1, -9 }, // 0x52 'R' U+0052
|
|
||||||
{ 463, 7, 10, 11, 2, -9 }, // 0x53 'S' U+0053
|
|
||||||
{ 472, 9, 10, 11, 1, -9 }, // 0x54 'T' U+0054
|
|
||||||
{ 484, 9, 10, 11, 1, -9 }, // 0x55 'U' U+0055
|
|
||||||
{ 496, 11, 10, 11, 0, -9 }, // 0x56 'V' U+0056
|
|
||||||
{ 510, 10, 10, 11, 0, -9 }, // 0x57 'W' U+0057
|
|
||||||
{ 523, 9, 10, 11, 1, -9 }, // 0x58 'X' U+0058
|
|
||||||
{ 535, 9, 10, 11, 1, -9 }, // 0x59 'Y' U+0059
|
|
||||||
{ 547, 7, 10, 11, 2, -9 }, // 0x5a 'Z' U+005A
|
|
||||||
{ 556, 3, 13, 11, 5, -10 }, // 0x5b '[' U+005B
|
|
||||||
{ 561, 7, 13, 11, 2, -11 }, // 0x5c '\' U+005C
|
|
||||||
{ 573, 3, 13, 11, 3, -10 }, // 0x5d ']' U+005D
|
|
||||||
{ 578, 7, 5, 11, 2, -10 }, // 0x5e '^' U+005E
|
|
||||||
{ 583, 11, 1, 11, 0, 2 }, // 0x5f '_' U+005F
|
|
||||||
{ 585, 3, 3, 11, 3, -11 }, // 0x60 '`' U+0060
|
|
||||||
{ 587, 9, 8, 11, 1, -7 }, // 0x61 'a' U+0061
|
|
||||||
{ 596, 10, 11, 11, 0, -10 }, // 0x62 'b' U+0062
|
|
||||||
{ 610, 8, 8, 11, 2, -7 }, // 0x63 'c' U+0063
|
|
||||||
{ 618, 10, 11, 11, 1, -10 }, // 0x64 'd' U+0064
|
|
||||||
{ 632, 8, 8, 11, 1, -7 }, // 0x65 'e' U+0065
|
|
||||||
{ 640, 8, 11, 11, 2, -10 }, // 0x66 'f' U+0066
|
|
||||||
{ 651, 9, 11, 11, 1, -7 }, // 0x67 'g' U+0067
|
|
||||||
{ 664, 9, 11, 11, 1, -10 }, // 0x68 'h' U+0068
|
|
||||||
{ 677, 7, 11, 11, 2, -10 }, // 0x69 'i' U+0069
|
|
||||||
{ 687, 5, 14, 11, 3, -10 }, // 0x6a 'j' U+006A
|
|
||||||
{ 696, 9, 11, 11, 1, -10 }, // 0x6b 'k' U+006B
|
|
||||||
{ 709, 7, 11, 11, 2, -10 }, // 0x6c 'l' U+006C
|
|
||||||
{ 719, 11, 8, 11, 0, -7 }, // 0x6d 'm' U+006D
|
|
||||||
{ 730, 9, 8, 11, 1, -7 }, // 0x6e 'n' U+006E
|
|
||||||
{ 739, 9, 8, 11, 1, -7 }, // 0x6f 'o' U+006F
|
|
||||||
{ 748, 10, 11, 11, 0, -7 }, // 0x70 'p' U+0070
|
|
||||||
{ 762, 10, 11, 11, 1, -7 }, // 0x71 'q' U+0071
|
|
||||||
{ 776, 8, 8, 11, 2, -7 }, // 0x72 'r' U+0072
|
|
||||||
{ 784, 7, 8, 11, 2, -7 }, // 0x73 's' U+0073
|
|
||||||
{ 791, 8, 10, 11, 1, -9 }, // 0x74 't' U+0074
|
|
||||||
{ 801, 9, 8, 11, 1, -7 }, // 0x75 'u' U+0075
|
|
||||||
{ 810, 9, 8, 11, 1, -7 }, // 0x76 'v' U+0076
|
|
||||||
{ 819, 9, 8, 11, 1, -7 }, // 0x77 'w' U+0077
|
|
||||||
{ 828, 9, 8, 11, 1, -7 }, // 0x78 'x' U+0078
|
|
||||||
{ 837, 9, 11, 11, 1, -7 }, // 0x79 'y' U+0079
|
|
||||||
{ 850, 7, 8, 11, 2, -7 }, // 0x7a 'z' U+007A
|
|
||||||
{ 857, 4, 13, 11, 3, -10 }, // 0x7b '{' U+007B
|
|
||||||
{ 864, 1, 13, 11, 5, -10 }, // 0x7c '|' U+007C
|
|
||||||
{ 866, 5, 13, 11, 3, -10 }, // 0x7d '}' U+007D
|
|
||||||
{ 875, 7, 2, 11, 2, -5 }, // 0x7e '~' U+007E
|
|
||||||
{ 877, 11, 14, 11, 0, -11 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
|
|
||||||
{ 897, 1, 1, 11, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
|
|
||||||
{ 898, 2, 11, 11, 4, -7 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
|
|
||||||
{ 901, 6, 11, 11, 2, -10 }, // 0x82 'CENT SIGN' U+00A2
|
|
||||||
{ 910, 8, 10, 11, 1, -9 }, // 0x83 'POUND SIGN' U+00A3
|
|
||||||
{ 920, 9, 10, 11, 1, -9 }, // 0x84 'EURO SIGN *' U+20AC
|
|
||||||
{ 932, 9, 10, 11, 1, -9 }, // 0x85 'YEN SIGN' U+00A5
|
|
||||||
{ 944, 7, 13, 11, 2, -12 }, // 0x86 'LATIN CAPITAL LETTER S WITH CARON *' U+0160
|
|
||||||
{ 956, 9, 12, 11, 1, -10 }, // 0x87 'SECTION SIGN' U+00A7
|
|
||||||
{ 970, 7, 12, 11, 2, -11 }, // 0x88 'LATIN SMALL LETTER S WITH CARON *' U+0161
|
|
||||||
{ 981, 11, 10, 11, 0, -9 }, // 0x89 'COPYRIGHT SIGN' U+00A9
|
|
||||||
{ 995, 5, 5, 11, 3, -9 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
|
|
||||||
{ 999, 9, 8, 11, 1, -7 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
|
|
||||||
{ 1008, 9, 5, 11, 1, -7 }, // 0x8c 'NOT SIGN' U+00AC
|
|
||||||
{ 1014, 9, 1, 11, 1, -5 }, // 0x8d 'SOFT HYPHEN' U+00AD
|
|
||||||
{ 1016, 11, 10, 11, 0, -9 }, // 0x8e 'REGISTERED SIGN' U+00AE
|
|
||||||
{ 1030, 5, 1, 11, 3, -10 }, // 0x8f 'MACRON' U+00AF
|
|
||||||
{ 1031, 5, 5, 11, 3, -10 }, // 0x90 'DEGREE SIGN' U+00B0
|
|
||||||
{ 1035, 9, 10, 11, 1, -9 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
|
|
||||||
{ 1047, 4, 6, 11, 3, -10 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
|
|
||||||
{ 1050, 4, 6, 11, 3, -10 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
|
|
||||||
{ 1053, 7, 14, 11, 2, -13 }, // 0x94 'LATIN CAPITAL LETTER Z WITH CARON *' U+017D
|
|
||||||
{ 1066, 9, 12, 11, 1, -7 }, // 0x95 'MICRO SIGN' U+00B5
|
|
||||||
{ 1080, 8, 12, 11, 1, -10 }, // 0x96 'PILCROW SIGN' U+00B6
|
|
||||||
{ 1092, 2, 2, 11, 4, -4 }, // 0x97 'MIDDLE DOT' U+00B7
|
|
||||||
{ 1093, 7, 12, 11, 2, -11 }, // 0x98 'LATIN SMALL LETTER Z WITH CARON *' U+017E
|
|
||||||
{ 1104, 4, 6, 11, 3, -10 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
|
|
||||||
{ 1107, 5, 5, 11, 3, -9 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
|
|
||||||
{ 1111, 9, 8, 11, 1, -7 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
|
|
||||||
{ 1120, 11, 10, 11, 0, -9 }, // 0x9c 'LATIN CAPITAL LIGATURE OE *' U+0152
|
|
||||||
{ 1134, 10, 8, 11, 0, -7 }, // 0x9d 'LATIN SMALL LIGATURE OE *' U+0153
|
|
||||||
{ 1144, 9, 13, 11, 1, -12 }, // 0x9e 'LATIN CAPITAL LETTER Y WITH DIAERESIS *' U+0178
|
|
||||||
{ 1159, 6, 11, 11, 2, -7 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
|
|
||||||
{ 1168, 11, 14, 11, 0, -13 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
|
|
||||||
{ 1188, 11, 14, 11, 0, -13 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
|
|
||||||
{ 1208, 11, 14, 11, 0, -13 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
|
|
||||||
{ 1228, 11, 13, 11, 0, -12 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
|
|
||||||
{ 1246, 11, 13, 11, 0, -12 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
|
|
||||||
{ 1264, 11, 14, 11, 0, -13 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
|
|
||||||
{ 1284, 11, 10, 11, 0, -9 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
|
|
||||||
{ 1298, 9, 13, 11, 1, -9 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
|
|
||||||
{ 1313, 8, 14, 11, 1, -13 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
|
|
||||||
{ 1327, 8, 14, 11, 1, -13 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
|
|
||||||
{ 1341, 8, 14, 11, 1, -13 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
|
|
||||||
{ 1355, 8, 13, 11, 1, -12 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
|
|
||||||
{ 1368, 7, 14, 11, 2, -13 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
|
|
||||||
{ 1381, 7, 14, 11, 2, -13 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
|
|
||||||
{ 1394, 7, 14, 11, 2, -13 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
|
|
||||||
{ 1407, 7, 13, 11, 2, -12 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
|
|
||||||
{ 1419, 9, 10, 11, 0, -9 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
|
|
||||||
{ 1431, 10, 13, 11, 0, -12 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
|
|
||||||
{ 1448, 9, 14, 11, 1, -13 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
|
|
||||||
{ 1464, 9, 14, 11, 1, -13 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
|
|
||||||
{ 1480, 9, 14, 11, 1, -13 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
|
|
||||||
{ 1496, 9, 13, 11, 1, -12 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
|
|
||||||
{ 1511, 9, 13, 11, 1, -12 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
|
|
||||||
{ 1526, 7, 6, 11, 2, -7 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
|
|
||||||
{ 1532, 9, 12, 11, 1, -10 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
|
|
||||||
{ 1546, 9, 14, 11, 1, -13 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
|
|
||||||
{ 1562, 9, 14, 11, 1, -13 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
|
|
||||||
{ 1578, 9, 14, 11, 1, -13 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
|
|
||||||
{ 1594, 9, 13, 11, 1, -12 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
|
|
||||||
{ 1609, 9, 14, 11, 1, -13 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
|
|
||||||
{ 1625, 8, 10, 11, 1, -9 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
|
|
||||||
{ 1635, 9, 11, 11, 0, -10 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
|
|
||||||
{ 1648, 9, 12, 11, 1, -11 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
|
|
||||||
{ 1662, 9, 12, 11, 1, -11 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
|
|
||||||
{ 1676, 9, 11, 11, 1, -10 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
|
|
||||||
{ 1689, 9, 10, 11, 1, -9 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
|
|
||||||
{ 1701, 9, 11, 11, 1, -10 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
|
|
||||||
{ 1714, 9, 12, 11, 1, -11 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
|
|
||||||
{ 1728, 10, 8, 11, 0, -7 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
|
|
||||||
{ 1738, 8, 11, 11, 2, -7 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
|
|
||||||
{ 1749, 8, 12, 11, 1, -11 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
|
|
||||||
{ 1761, 8, 12, 11, 1, -11 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
|
|
||||||
{ 1773, 8, 11, 11, 1, -10 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
|
|
||||||
{ 1784, 8, 11, 11, 1, -10 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
|
|
||||||
{ 1795, 7, 12, 11, 2, -11 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
|
|
||||||
{ 1806, 7, 12, 11, 2, -11 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
|
|
||||||
{ 1817, 7, 11, 11, 2, -10 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
|
|
||||||
{ 1827, 7, 11, 11, 2, -10 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
|
|
||||||
{ 1837, 9, 11, 11, 1, -10 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
|
|
||||||
{ 1850, 9, 10, 11, 1, -9 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
|
|
||||||
{ 1862, 9, 12, 11, 1, -11 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
|
|
||||||
{ 1876, 9, 12, 11, 1, -11 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
|
|
||||||
{ 1890, 9, 11, 11, 1, -10 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
|
|
||||||
{ 1903, 9, 10, 11, 1, -9 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
|
|
||||||
{ 1915, 9, 11, 11, 1, -10 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
|
|
||||||
{ 1928, 9, 10, 11, 1, -9 }, // 0xd7 'DIVISION SIGN' U+00F7
|
|
||||||
{ 1940, 9, 9, 11, 1, -7 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
|
|
||||||
{ 1951, 9, 12, 11, 1, -11 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
|
|
||||||
{ 1965, 9, 12, 11, 1, -11 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
|
|
||||||
{ 1979, 9, 11, 11, 1, -10 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
|
|
||||||
{ 1992, 9, 11, 11, 1, -10 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
|
|
||||||
{ 2005, 9, 15, 11, 1, -11 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
|
|
||||||
{ 2022, 10, 14, 11, 0, -10 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
|
|
||||||
{ 2040, 9, 14, 11, 1, -10 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
|
|
||||||
|
|
||||||
const GFXfont FreeMono9pt8b PROGMEM = {
|
|
||||||
(uint8_t *)FreeMono9pt8bBitmaps,
|
|
||||||
(GFXglyph *)FreeMono9pt8bGlyphs,
|
|
||||||
0x20, 0xDF, 19 };
|
|
||||||
|
|
||||||
// Approx. 3407 bytes
|
|
|
@ -1,596 +0,0 @@
|
||||||
const uint8_t FreeSans12pt8bBitmaps[] PROGMEM = {
|
|
||||||
0x00, 0xFF, 0xFF, 0xFF, 0xF3, 0xF0, 0xCF, 0x3C, 0xF3, 0x4D, 0x10, 0x06,
|
|
||||||
0x30, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x3F, 0xFD, 0xFF, 0xE1, 0x98,
|
|
||||||
0x18, 0xC0, 0xC6, 0x06, 0x31, 0xFF, 0xE1, 0x88, 0x08, 0xC0, 0xC6, 0x06,
|
|
||||||
0x30, 0x31, 0x80, 0x04, 0x03, 0xF1, 0xFF, 0x32, 0x7C, 0x47, 0x88, 0xF1,
|
|
||||||
0x07, 0x20, 0x7C, 0x07, 0xF0, 0x1F, 0x02, 0x70, 0x47, 0x88, 0xF1, 0x1E,
|
|
||||||
0x23, 0x64, 0xE7, 0xF8, 0x10, 0x02, 0x00, 0x40, 0x00, 0x06, 0x07, 0xC0,
|
|
||||||
0x40, 0xE6, 0x0C, 0x0C, 0x30, 0x80, 0x83, 0x18, 0x0C, 0x31, 0x00, 0xC6,
|
|
||||||
0x30, 0x07, 0xE2, 0x00, 0x38, 0x60, 0x00, 0x0C, 0x38, 0x00, 0xC7, 0xC0,
|
|
||||||
0x18, 0xC6, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x08, 0x20, 0x60, 0xC6,
|
|
||||||
0x04, 0x07, 0xC0, 0x0F, 0x00, 0x7E, 0x03, 0x8C, 0x0C, 0x30, 0x30, 0xC0,
|
|
||||||
0x67, 0x01, 0xF8, 0x03, 0xC0, 0x1E, 0x00, 0xCC, 0x66, 0x39, 0xB0, 0x7C,
|
|
||||||
0xC0, 0xF3, 0x01, 0x8E, 0x0F, 0x1C, 0xFE, 0x3F, 0x9C, 0x10, 0x00, 0xFF,
|
|
||||||
0x50, 0x08, 0x8C, 0x46, 0x31, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC2,
|
|
||||||
0x18, 0x43, 0x08, 0x60, 0x86, 0x18, 0xC3, 0x18, 0x43, 0x18, 0xC6, 0x31,
|
|
||||||
0x8C, 0x63, 0x11, 0x8C, 0x46, 0x23, 0x00, 0x10, 0x22, 0x4F, 0xF3, 0x85,
|
|
||||||
0x1B, 0x00, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x0F, 0xFF, 0x06,
|
|
||||||
0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0x97, 0xA0, 0xFC, 0xFF,
|
|
||||||
0x80, 0x06, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02,
|
|
||||||
0x0C, 0x10, 0x20, 0xC1, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6E, 0x0F,
|
|
||||||
0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x06, 0xC1,
|
|
||||||
0xD8, 0x31, 0xCE, 0x3F, 0x80, 0x80, 0x04, 0x30, 0xFF, 0xFC, 0x30, 0xC3,
|
|
||||||
0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x1F, 0x07, 0xF9, 0xC3, 0xB0,
|
|
||||||
0x3C, 0x07, 0x80, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x07,
|
|
||||||
0x01, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0, 0x1F, 0x0F, 0xF9, 0x83, 0x70,
|
|
||||||
0x7C, 0x0E, 0x01, 0xC0, 0x30, 0x7C, 0x0F, 0x80, 0x38, 0x01, 0x80, 0x3C,
|
|
||||||
0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x80, 0x80, 0x01, 0x80, 0x70, 0x0E,
|
|
||||||
0x03, 0xC0, 0xD8, 0x33, 0x06, 0x61, 0x8C, 0x61, 0x8C, 0x33, 0x06, 0x7F,
|
|
||||||
0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xCF, 0xF9, 0x80,
|
|
||||||
0x30, 0x06, 0x00, 0xC0, 0x1F, 0xE3, 0xFE, 0xE0, 0xE0, 0x0C, 0x01, 0x80,
|
|
||||||
0x30, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x80, 0x80, 0x0F, 0x07, 0xF9,
|
|
||||||
0xC3, 0x30, 0x36, 0x01, 0x80, 0x30, 0x86, 0xFC, 0xF9, 0xDC, 0x1F, 0x81,
|
|
||||||
0xE0, 0x3C, 0x06, 0xC0, 0xD8, 0x3B, 0xCE, 0x3F, 0x80, 0x80, 0xFF, 0xFF,
|
|
||||||
0xFC, 0x01, 0x80, 0x60, 0x0C, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x00, 0xC0,
|
|
||||||
0x30, 0x06, 0x00, 0xC0, 0x30, 0x06, 0x00, 0xC0, 0x38, 0x00, 0x1F, 0x07,
|
|
||||||
0xF9, 0xC3, 0x30, 0x7E, 0x06, 0xC1, 0xD8, 0x31, 0xFC, 0x3F, 0x8E, 0x1B,
|
|
||||||
0x81, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x80, 0x80, 0x1F,
|
|
||||||
0x07, 0xF1, 0x87, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x60, 0xEF,
|
|
||||||
0xFC, 0x7D, 0x80, 0x30, 0x07, 0x81, 0x98, 0x33, 0x9C, 0x3F, 0x00, 0x80,
|
|
||||||
0xFC, 0x00, 0x0F, 0xC0, 0xFC, 0x00, 0x0F, 0xD7, 0x00, 0x00, 0x30, 0x1F,
|
|
||||||
0x07, 0x81, 0xE0, 0xF8, 0x0E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0xC0, 0x0F,
|
|
||||||
0x00, 0x30, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0xC0, 0x0F,
|
|
||||||
0x80, 0x1E, 0x00, 0x78, 0x01, 0xF0, 0x03, 0x01, 0xE0, 0x78, 0x3E, 0x0F,
|
|
||||||
0x00, 0xC0, 0x00, 0x1E, 0x1F, 0xE6, 0x1F, 0x03, 0xC0, 0xF0, 0x30, 0x0C,
|
|
||||||
0x06, 0x03, 0x01, 0x80, 0xC0, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x30, 0x0C,
|
|
||||||
0x03, 0x00, 0x00, 0x7C, 0x00, 0x0F, 0xFE, 0x00, 0x70, 0x3C, 0x07, 0x00,
|
|
||||||
0x38, 0x38, 0x00, 0x70, 0xC0, 0x40, 0xE6, 0x0F, 0xD9, 0x98, 0x71, 0xC7,
|
|
||||||
0xC3, 0x87, 0x0F, 0x0C, 0x0C, 0x3C, 0x30, 0x70, 0xF1, 0xC1, 0x86, 0xC7,
|
|
||||||
0x06, 0x1B, 0x1C, 0x38, 0xEC, 0x39, 0xE7, 0x18, 0x7D, 0xF8, 0x70, 0x01,
|
|
||||||
0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0xF3, 0xC0, 0x03, 0xFF, 0x00,
|
|
||||||
0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x06, 0x60, 0x06, 0x60,
|
|
||||||
0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30, 0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8,
|
|
||||||
0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E, 0x60, 0x06, 0x60, 0x07,
|
|
||||||
0xFE, 0x07, 0xFF, 0x30, 0x79, 0x80, 0xEC, 0x03, 0x60, 0x1B, 0x00, 0xD8,
|
|
||||||
0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x7C, 0x01, 0xE0, 0x0F, 0x00,
|
|
||||||
0xF8, 0x0E, 0xFF, 0xF7, 0xFE, 0x00, 0x03, 0xC0, 0x1F, 0xF0, 0xF0, 0xE1,
|
|
||||||
0x80, 0xE7, 0x00, 0xEC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x80,
|
|
||||||
0x03, 0x00, 0x07, 0x00, 0x06, 0x00, 0x6C, 0x01, 0xDC, 0x03, 0x9C, 0x0E,
|
|
||||||
0x1F, 0x78, 0x1F, 0xE0, 0x04, 0x00, 0xFE, 0x03, 0xFF, 0x8C, 0x1F, 0x30,
|
|
||||||
0x0E, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C,
|
|
||||||
0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3,
|
|
||||||
0xFF, 0x00, 0xFF, 0xF7, 0xFF, 0xB0, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03,
|
|
||||||
0x00, 0x18, 0x00, 0xFF, 0xF7, 0xFF, 0xB0, 0x01, 0x80, 0x0C, 0x00, 0x60,
|
|
||||||
0x03, 0x00, 0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xC0,
|
|
||||||
0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0,
|
|
||||||
0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x03,
|
|
||||||
0xE0, 0x0F, 0xF8, 0x1E, 0x3C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x07, 0xE0,
|
|
||||||
0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xE0, 0x03, 0xE0,
|
|
||||||
0x03, 0x60, 0x03, 0x70, 0x07, 0x38, 0x0F, 0x1F, 0x7B, 0x0F, 0xF3, 0x00,
|
|
||||||
0x80, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00,
|
|
||||||
0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F,
|
|
||||||
0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFC, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03,
|
|
||||||
0x00, 0xC0, 0x30, 0x0C, 0x03, 0xE0, 0xF8, 0x3E, 0x0D, 0x87, 0x73, 0x8F,
|
|
||||||
0xE0, 0x40, 0xC0, 0x1F, 0x00, 0xEC, 0x07, 0x30, 0x38, 0xC1, 0xC3, 0x0E,
|
|
||||||
0x0C, 0x70, 0x33, 0x80, 0xDE, 0x03, 0xFC, 0x0F, 0x38, 0x38, 0x60, 0xC1,
|
|
||||||
0xC3, 0x03, 0x8C, 0x06, 0x30, 0x1C, 0xC0, 0x3B, 0x00, 0x60, 0xC0, 0x18,
|
|
||||||
0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03,
|
|
||||||
0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xFF, 0xFC, 0xE0,
|
|
||||||
0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xD8, 0x1B, 0xD8,
|
|
||||||
0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6,
|
|
||||||
0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83, 0xC0,
|
|
||||||
0x1F, 0x80, 0x7F, 0x01, 0xFC, 0x07, 0xF8, 0x1F, 0x60, 0x7C, 0xC1, 0xF3,
|
|
||||||
0x87, 0xC6, 0x1F, 0x0C, 0x7C, 0x39, 0xF0, 0x67, 0xC1, 0xDF, 0x03, 0xFC,
|
|
||||||
0x07, 0xF0, 0x1F, 0xC0, 0x3F, 0x00, 0x70, 0x03, 0xE0, 0x07, 0xFC, 0x0F,
|
|
||||||
0x8F, 0x07, 0x01, 0xC7, 0x00, 0x73, 0x00, 0x1B, 0x80, 0x0D, 0x80, 0x07,
|
|
||||||
0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x7E, 0x00, 0x33, 0x00,
|
|
||||||
0x19, 0xC0, 0x1C, 0x70, 0x1C, 0x1F, 0x7C, 0x07, 0xFC, 0x00, 0x20, 0x00,
|
|
||||||
0xFE, 0x07, 0xFF, 0x30, 0x7D, 0x80, 0x6C, 0x03, 0xE0, 0x1F, 0x00, 0xF8,
|
|
||||||
0x07, 0xC0, 0xF7, 0xFF, 0x3F, 0xC1, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00,
|
|
||||||
0x18, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x03, 0xE0, 0x07, 0xFC, 0x0F, 0x8F,
|
|
||||||
0x07, 0x01, 0xC7, 0x00, 0x73, 0x00, 0x1B, 0x80, 0x0D, 0x80, 0x07, 0xC0,
|
|
||||||
0x01, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x00, 0x7E, 0x00, 0x33, 0x01, 0x19,
|
|
||||||
0xC0, 0xDC, 0x70, 0x3C, 0x1F, 0x7E, 0x07, 0xFF, 0x80, 0x20, 0xC0, 0xFF,
|
|
||||||
0x03, 0xFF, 0xCC, 0x0F, 0xB0, 0x06, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xB0,
|
|
||||||
0x06, 0xC0, 0xF3, 0xFF, 0x8C, 0x0F, 0x30, 0x06, 0xC0, 0x1B, 0x00, 0x6C,
|
|
||||||
0x01, 0xB0, 0x06, 0xC0, 0x1F, 0x00, 0x70, 0x07, 0x80, 0xFF, 0x87, 0x87,
|
|
||||||
0x18, 0x0E, 0x60, 0x19, 0x80, 0x66, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F,
|
|
||||||
0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x1F, 0x00, 0x3E, 0x01, 0xDC, 0x06, 0x7E,
|
|
||||||
0xF8, 0x7F, 0x80, 0x20, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x38, 0x00, 0xE0,
|
|
||||||
0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38,
|
|
||||||
0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E,
|
|
||||||
0x00, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00,
|
|
||||||
0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F,
|
|
||||||
0x80, 0x6C, 0x07, 0x7D, 0xF1, 0xFF, 0x00, 0x80, 0xC0, 0x0F, 0x00, 0x3E,
|
|
||||||
0x01, 0xD8, 0x06, 0x70, 0x18, 0xC0, 0xE3, 0x03, 0x0E, 0x0C, 0x18, 0x70,
|
|
||||||
0x61, 0x81, 0xC6, 0x03, 0x38, 0x0C, 0xC0, 0x3B, 0x00, 0x6C, 0x01, 0xE0,
|
|
||||||
0x07, 0x80, 0x0E, 0x00, 0xC0, 0x70, 0x1E, 0x03, 0x80, 0xF0, 0x1C, 0x0F,
|
|
||||||
0xC1, 0xE0, 0x76, 0x0D, 0x83, 0x30, 0x6C, 0x19, 0x83, 0x61, 0xCE, 0x33,
|
|
||||||
0x8E, 0x31, 0x8C, 0x61, 0x8C, 0x63, 0x0C, 0xE3, 0x18, 0x76, 0x0D, 0xC1,
|
|
||||||
0xB0, 0x6C, 0x0D, 0x83, 0x60, 0x78, 0x1F, 0x03, 0xC0, 0x78, 0x0E, 0x03,
|
|
||||||
0x80, 0x70, 0x1C, 0x00, 0xE0, 0x0C, 0xC0, 0x39, 0xC0, 0xE1, 0xC1, 0x81,
|
|
||||||
0x87, 0x03, 0x9C, 0x03, 0xB0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E,
|
|
||||||
0x00, 0x76, 0x01, 0xCE, 0x03, 0x0C, 0x0E, 0x0C, 0x38, 0x1C, 0x60, 0x1D,
|
|
||||||
0xC0, 0x38, 0xE0, 0x07, 0x70, 0x06, 0x30, 0x0E, 0x38, 0x1C, 0x18, 0x18,
|
|
||||||
0x1C, 0x38, 0x0E, 0x30, 0x06, 0x70, 0x07, 0x60, 0x03, 0xC0, 0x01, 0xC0,
|
|
||||||
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
|
|
||||||
0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x06, 0x00, 0x70,
|
|
||||||
0x07, 0x00, 0x70, 0x07, 0x00, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18,
|
|
||||||
0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xCC, 0xCC, 0xCC,
|
|
||||||
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0, 0x81, 0x03, 0x02, 0x04,
|
|
||||||
0x0C, 0x08, 0x10, 0x30, 0x20, 0x40, 0xC0, 0x81, 0x03, 0x02, 0x04, 0x0C,
|
|
||||||
0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0,
|
|
||||||
0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80, 0xFF,
|
|
||||||
0xFE, 0xC3, 0x0C, 0x20, 0x1F, 0x07, 0xFC, 0x60, 0xC6, 0x0C, 0x00, 0xC0,
|
|
||||||
0x1C, 0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C, 0xC0, 0xCE, 0x3E, 0x7E, 0x70,
|
|
||||||
0x02, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF0, 0xDF, 0xCF,
|
|
||||||
0x0E, 0xE0, 0x6E, 0x06, 0xC0, 0x6C, 0x07, 0xC0, 0x7C, 0x06, 0xE0, 0x6E,
|
|
||||||
0x0E, 0xF9, 0xCD, 0xF8, 0x00, 0x00, 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0,
|
|
||||||
0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x3E, 0x0D, 0xC7, 0x3F, 0x81, 0x00,
|
|
||||||
0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xDF, 0xDB, 0x8F, 0xE0,
|
|
||||||
0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3F, 0x07, 0x7B, 0xE7,
|
|
||||||
0xEC, 0x10, 0x00, 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x3C, 0x07, 0x80, 0xFF,
|
|
||||||
0xFE, 0x00, 0xC0, 0x18, 0x0D, 0x83, 0xBC, 0xE3, 0xF8, 0x08, 0x00, 0x04,
|
|
||||||
0x73, 0x0C, 0x33, 0xFF, 0xCC, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30,
|
|
||||||
0xC0, 0x1E, 0x67, 0xED, 0x87, 0xF0, 0x7C, 0x0F, 0x80, 0xF0, 0x1E, 0x03,
|
|
||||||
0xC0, 0x78, 0x1F, 0x83, 0xB9, 0xF3, 0xF6, 0x00, 0xF0, 0x37, 0x06, 0x7F,
|
|
||||||
0xC7, 0xE0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCF, 0xFB, 0x87,
|
|
||||||
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0,
|
|
||||||
0x30, 0xFC, 0x3F, 0xFF, 0xFF, 0xF0, 0x33, 0x30, 0x03, 0x33, 0x33, 0x33,
|
|
||||||
0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C,
|
|
||||||
0x01, 0x81, 0xB0, 0x66, 0x18, 0xC6, 0x19, 0x83, 0x70, 0x7B, 0x0E, 0x71,
|
|
||||||
0x86, 0x30, 0xE6, 0x0C, 0xC0, 0xD8, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
|
|
||||||
0xDE, 0x1E, 0xFF, 0x7F, 0xE3, 0xC3, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83,
|
|
||||||
0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83,
|
|
||||||
0xC1, 0x83, 0xCF, 0x3F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
|
|
||||||
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, 0x1F, 0x07, 0xF1, 0xC7, 0x70,
|
|
||||||
0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0D, 0x83, 0xBD, 0xE3,
|
|
||||||
0xF8, 0x08, 0x00, 0xCF, 0x0D, 0xFC, 0xF0, 0xCE, 0x06, 0xE0, 0x6C, 0x06,
|
|
||||||
0xC0, 0x7C, 0x07, 0xC0, 0x6E, 0x06, 0xE0, 0xEF, 0x9C, 0xDF, 0x8C, 0x00,
|
|
||||||
0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x1E, 0x6F, 0xFD, 0xC7, 0xF0, 0x7C,
|
|
||||||
0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x1F, 0x83, 0xBD, 0xF3, 0xF6,
|
|
||||||
0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0xDF, 0xFF, 0x30, 0xC3, 0x0C,
|
|
||||||
0x30, 0xC3, 0x0C, 0x30, 0xC0, 0x1E, 0x1F, 0xEE, 0x1B, 0x06, 0xC0, 0x3C,
|
|
||||||
0x07, 0xF0, 0x3E, 0x01, 0xF0, 0x3C, 0x0F, 0xCE, 0x7F, 0x82, 0x00, 0x30,
|
|
||||||
0xC3, 0x3F, 0xFC, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0x08,
|
|
||||||
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC1, 0xF0,
|
|
||||||
0x7C, 0x1F, 0x8F, 0x7E, 0xC4, 0x00, 0xE0, 0x76, 0x06, 0x60, 0x67, 0x0C,
|
|
||||||
0x30, 0xC3, 0x0C, 0x39, 0x81, 0x98, 0x19, 0x81, 0xB0, 0x0F, 0x00, 0xE0,
|
|
||||||
0x0E, 0x00, 0xC1, 0xC1, 0xF0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36,
|
|
||||||
0x31, 0x9B, 0x38, 0xCD, 0x98, 0x64, 0x6C, 0x36, 0x36, 0x0F, 0x1E, 0x07,
|
|
||||||
0x8F, 0x03, 0x83, 0x80, 0xC1, 0x80, 0x60, 0x6E, 0x1C, 0xC3, 0x0C, 0xC1,
|
|
||||||
0xF0, 0x1E, 0x01, 0x80, 0x78, 0x0F, 0x03, 0x30, 0xC7, 0x38, 0x66, 0x06,
|
|
||||||
0x60, 0x6C, 0x0D, 0x81, 0x98, 0x63, 0x0C, 0x63, 0x86, 0x60, 0xCC, 0x1B,
|
|
||||||
0x81, 0xE0, 0x3C, 0x07, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x60, 0x78, 0x0F,
|
|
||||||
0x00, 0xFF, 0xFF, 0xF0, 0x18, 0x0E, 0x07, 0x03, 0x80, 0xC0, 0x60, 0x30,
|
|
||||||
0x1C, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, 0x04, 0xF3, 0x0C, 0x30, 0xC3, 0x0C,
|
|
||||||
0x30, 0xC6, 0x30, 0xE1, 0x83, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xE1, 0xC0,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x87, 0x18, 0x42, 0x10, 0x84, 0x21,
|
|
||||||
0x8C, 0x31, 0x98, 0xC4, 0x21, 0x08, 0x42, 0x73, 0x80, 0x00, 0x3E, 0x1D,
|
|
||||||
0xC6, 0x1F, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01,
|
|
||||||
0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C,
|
|
||||||
0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFC,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xF0, 0x04, 0x00, 0x80, 0x3C, 0x1F, 0xE7, 0x4E, 0xC8,
|
|
||||||
0xD9, 0x1E, 0x20, 0xC4, 0x18, 0x83, 0x10, 0x32, 0x36, 0x46, 0x7B, 0x87,
|
|
||||||
0xE0, 0x30, 0x04, 0x00, 0x80, 0x00, 0x01, 0xF8, 0x79, 0xC6, 0x0E, 0xE0,
|
|
||||||
0x6E, 0x06, 0xE0, 0x06, 0x00, 0x70, 0x0F, 0xF0, 0x38, 0x01, 0x80, 0x18,
|
|
||||||
0x01, 0x00, 0x30, 0x06, 0x00, 0xFF, 0xEE, 0xFF, 0x00, 0x80, 0x01, 0xF0,
|
|
||||||
0x1F, 0xF0, 0xE0, 0x87, 0x00, 0x18, 0x00, 0xC0, 0x0F, 0xFF, 0x3F, 0xFC,
|
|
||||||
0x30, 0x03, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x38, 0x00, 0x60, 0x01, 0xC0,
|
|
||||||
0x03, 0xC6, 0x07, 0xF8, 0x00, 0x00, 0x60, 0x1B, 0x01, 0x8C, 0x0C, 0x60,
|
|
||||||
0xC1, 0x86, 0x0C, 0x60, 0x36, 0x00, 0xF0, 0x07, 0xF1, 0xFF, 0x80, 0xC0,
|
|
||||||
0x06, 0x03, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x0C, 0xC0,
|
|
||||||
0x16, 0x00, 0x78, 0x00, 0x00, 0x07, 0x80, 0xFF, 0x87, 0x87, 0x18, 0x0E,
|
|
||||||
0x60, 0x19, 0x80, 0x66, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F,
|
|
||||||
0x80, 0x07, 0xC0, 0x1F, 0x00, 0x3E, 0x01, 0xDC, 0x06, 0x7E, 0xF8, 0x7F,
|
|
||||||
0x80, 0x20, 0x00, 0x00, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x60, 0x0E,
|
|
||||||
0x01, 0xF0, 0x67, 0x98, 0x7B, 0x03, 0xE0, 0x37, 0x06, 0xF0, 0xC7, 0x18,
|
|
||||||
0x7E, 0x07, 0x80, 0x31, 0x87, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0, 0x21,
|
|
||||||
0x0C, 0xC1, 0xE0, 0x70, 0x00, 0x07, 0x87, 0xFB, 0x86, 0xC1, 0xB0, 0x0F,
|
|
||||||
0x01, 0xFC, 0x0F, 0x80, 0x7C, 0x0F, 0x03, 0xF3, 0x9F, 0xE0, 0x80, 0x03,
|
|
||||||
0xE0, 0x03, 0xFF, 0x01, 0x80, 0xE0, 0xC0, 0x0C, 0x61, 0xE1, 0xB0, 0xCC,
|
|
||||||
0x6C, 0x61, 0x8F, 0x10, 0x63, 0x8C, 0x00, 0xE3, 0x00, 0x38, 0xC0, 0x0F,
|
|
||||||
0x10, 0x63, 0xC6, 0x18, 0x90, 0xFC, 0x66, 0x1E, 0x30, 0xC0, 0x1C, 0x1C,
|
|
||||||
0x0E, 0x01, 0xFE, 0x00, 0x08, 0x00, 0x39, 0xDB, 0x10, 0x67, 0x50, 0xA3,
|
|
||||||
0x7F, 0x01, 0xFF, 0xF8, 0x00, 0x18, 0xDC, 0xF8, 0xC8, 0x47, 0x31, 0xCE,
|
|
||||||
0x23, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30,
|
|
||||||
0xFC, 0x03, 0xE0, 0x03, 0xFF, 0x01, 0x80, 0xE0, 0xC0, 0x0C, 0x67, 0xF1,
|
|
||||||
0xB1, 0x8E, 0x6C, 0x61, 0x8F, 0x18, 0x63, 0x86, 0x38, 0xE1, 0xFC, 0x38,
|
|
||||||
0x61, 0x8F, 0x18, 0x63, 0xC6, 0x18, 0x91, 0x86, 0x66, 0x60, 0xF0, 0xC0,
|
|
||||||
0x1C, 0x1C, 0x0E, 0x01, 0xFE, 0x00, 0x08, 0x00, 0xFF, 0xF0, 0x7D, 0x8A,
|
|
||||||
0x1C, 0x38, 0x7F, 0x8E, 0x00, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06,
|
|
||||||
0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x00,
|
|
||||||
0x00, 0x00, 0xFF, 0xF0, 0x3C, 0x66, 0x43, 0x43, 0x02, 0x0E, 0x38, 0x60,
|
|
||||||
0x40, 0xFF, 0x3C, 0x66, 0x42, 0x02, 0x1E, 0x1E, 0x03, 0xC3, 0x43, 0x7E,
|
|
||||||
0x00, 0x08, 0xC0, 0x6C, 0x01, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00,
|
|
||||||
0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x03, 0x80,
|
|
||||||
0x38, 0x03, 0x80, 0x38, 0x01, 0x80, 0x1C, 0x01, 0xC0, 0x0F, 0xFF, 0xFF,
|
|
||||||
0xFC, 0xC0, 0xD8, 0x1B, 0x03, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x36, 0x06,
|
|
||||||
0xC1, 0xD8, 0x3B, 0x07, 0x71, 0xEF, 0xEF, 0xA0, 0x30, 0x06, 0x00, 0xC0,
|
|
||||||
0x18, 0x00, 0x03, 0xF3, 0xFF, 0x7E, 0x47, 0xE4, 0xFE, 0x4F, 0xE4, 0xFE,
|
|
||||||
0x4F, 0xE4, 0x7E, 0x47, 0xE4, 0x3E, 0x40, 0xE4, 0x06, 0x40, 0x64, 0x06,
|
|
||||||
0x40, 0x64, 0x06, 0x40, 0x64, 0x06, 0x40, 0x64, 0x06, 0x40, 0x64, 0xFF,
|
|
||||||
0x80, 0x21, 0x0C, 0xC1, 0xE0, 0x30, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03,
|
|
||||||
0x81, 0xC0, 0xE0, 0x30, 0x18, 0x0C, 0x07, 0x03, 0x80, 0xFF, 0xFF, 0xF0,
|
|
||||||
0x33, 0xF3, 0x33, 0x33, 0x33, 0x38, 0xDB, 0x1C, 0x38, 0x70, 0xF1, 0x3E,
|
|
||||||
0x01, 0xFF, 0xF8, 0xC4, 0x73, 0x8C, 0xE2, 0x13, 0x1F, 0x3B, 0x18, 0x00,
|
|
||||||
0x07, 0x8F, 0xFC, 0x7F, 0xBF, 0xF3, 0x87, 0xC0, 0x1C, 0x0F, 0x00, 0x60,
|
|
||||||
0x1C, 0x01, 0x80, 0x30, 0x0E, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0F,
|
|
||||||
0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xE0, 0x0C, 0x01,
|
|
||||||
0x80, 0x30, 0x06, 0x01, 0xC0, 0x1C, 0x0F, 0x00, 0x3F, 0xEF, 0xFC, 0x3F,
|
|
||||||
0x3F, 0xF0, 0x1F, 0x07, 0x83, 0xF9, 0xFE, 0x71, 0xF8, 0x7E, 0x0F, 0x03,
|
|
||||||
0xC0, 0x60, 0x3C, 0x06, 0x03, 0xC0, 0x7F, 0xFC, 0x06, 0x00, 0xC0, 0x60,
|
|
||||||
0x0C, 0x07, 0x03, 0x60, 0xF0, 0x77, 0xBF, 0xCE, 0x3F, 0x9F, 0xC0, 0x40,
|
|
||||||
0x20, 0x06, 0x60, 0x06, 0x60, 0x00, 0x00, 0xE0, 0x07, 0x70, 0x06, 0x30,
|
|
||||||
0x0E, 0x38, 0x1C, 0x18, 0x18, 0x1C, 0x38, 0x0E, 0x30, 0x06, 0x70, 0x07,
|
|
||||||
0x60, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
|
||||||
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x0C, 0x03, 0x00, 0xC0, 0x00,
|
|
||||||
0x00, 0x03, 0x00, 0xC0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00, 0xC0, 0xF0,
|
|
||||||
0x3C, 0x0F, 0x86, 0x7F, 0x87, 0x80, 0x07, 0x00, 0x03, 0x00, 0x01, 0x80,
|
|
||||||
0x00, 0x00, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x06, 0x60,
|
|
||||||
0x06, 0x60, 0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30, 0x1C, 0x38, 0x18, 0x18,
|
|
||||||
0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E, 0x60, 0x06,
|
|
||||||
0x60, 0x07, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x01, 0xC0,
|
|
||||||
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70,
|
|
||||||
0x0C, 0x30, 0x0C, 0x30, 0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8, 0x3F, 0xFC,
|
|
||||||
0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E, 0x60, 0x06, 0x60, 0x07, 0x03, 0xC0,
|
|
||||||
0x03, 0xC0, 0x06, 0x60, 0x00, 0x00, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
|
|
||||||
0x03, 0xE0, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30,
|
|
||||||
0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C,
|
|
||||||
0x70, 0x0E, 0x60, 0x06, 0x60, 0x07, 0x07, 0xB0, 0x0D, 0xE0, 0x00, 0x00,
|
|
||||||
0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x06, 0x60, 0x06, 0x60,
|
|
||||||
0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30, 0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8,
|
|
||||||
0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E, 0x60, 0x06, 0x60, 0x07,
|
|
||||||
0x06, 0x60, 0x06, 0x60, 0x00, 0x00, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
|
|
||||||
0x03, 0xE0, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30,
|
|
||||||
0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C,
|
|
||||||
0x70, 0x0E, 0x60, 0x06, 0x60, 0x07, 0x03, 0xC0, 0x03, 0x40, 0x06, 0x60,
|
|
||||||
0x03, 0xC0, 0x01, 0x80, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xE0,
|
|
||||||
0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x0C, 0x30, 0x0C, 0x30, 0x1C, 0x38,
|
|
||||||
0x18, 0x18, 0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x70, 0x0E,
|
|
||||||
0x60, 0x06, 0x60, 0x07, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xF8, 0x06, 0x60,
|
|
||||||
0x00, 0x18, 0xC0, 0x00, 0x31, 0x80, 0x00, 0xE3, 0x00, 0x01, 0x86, 0x00,
|
|
||||||
0x03, 0x0C, 0x00, 0x0C, 0x1F, 0xFC, 0x18, 0x3F, 0xF8, 0x70, 0x60, 0x00,
|
|
||||||
0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x07, 0x03, 0x00, 0x0C, 0x06, 0x00, 0x38,
|
|
||||||
0x0C, 0x00, 0x60, 0x1F, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xC0, 0x1F, 0xF0,
|
|
||||||
0xF0, 0xE1, 0x80, 0xE7, 0x00, 0xEC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xC0,
|
|
||||||
0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x06, 0x00, 0x6C, 0x01, 0xDC, 0x03,
|
|
||||||
0x9C, 0x0E, 0x1F, 0x78, 0x1F, 0xE0, 0x04, 0x00, 0x0C, 0x00, 0x0C, 0x00,
|
|
||||||
0x18, 0x01, 0xF0, 0x00, 0x1C, 0x00, 0x30, 0x00, 0x80, 0x00, 0x0F, 0xFF,
|
|
||||||
0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0F,
|
|
||||||
0xFF, 0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80,
|
|
||||||
0x0F, 0xFF, 0xFF, 0xFC, 0x03, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0F, 0xFF,
|
|
||||||
0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0F,
|
|
||||||
0xFF, 0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80,
|
|
||||||
0x0F, 0xFF, 0xFF, 0xFC, 0x07, 0x00, 0x6C, 0x06, 0x60, 0x00, 0x0F, 0xFF,
|
|
||||||
0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0F,
|
|
||||||
0xFF, 0x7F, 0xFB, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80,
|
|
||||||
0x0F, 0xFF, 0xFF, 0xFC, 0x1D, 0xC0, 0xEE, 0x00, 0x01, 0xFF, 0xEF, 0xFF,
|
|
||||||
0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0xFF, 0xEF,
|
|
||||||
0xFF, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0xFF,
|
|
||||||
0xFF, 0xFF, 0x80, 0xE1, 0x84, 0x13, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C,
|
|
||||||
0xE7, 0x39, 0xCE, 0x73, 0x9C, 0x33, 0x30, 0x0E, 0x73, 0x9C, 0xE7, 0x39,
|
|
||||||
0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x70, 0x38, 0xD9, 0x14, 0x03, 0x87,
|
|
||||||
0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1,
|
|
||||||
0xC3, 0x87, 0x00, 0xEF, 0xDC, 0x01, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70,
|
|
||||||
0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x80, 0x3F, 0x80,
|
|
||||||
0x3F, 0xF8, 0x30, 0x7C, 0x30, 0x0E, 0x30, 0x06, 0x30, 0x06, 0x30, 0x07,
|
|
||||||
0x30, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07,
|
|
||||||
0x30, 0x06, 0x30, 0x0E, 0x30, 0x1C, 0x3F, 0xF8, 0x3F, 0xF0, 0x0C, 0x40,
|
|
||||||
0x7F, 0x01, 0x08, 0x30, 0x07, 0xE0, 0x1F, 0xC0, 0x7F, 0x01, 0xFE, 0x07,
|
|
||||||
0xD8, 0x1F, 0x30, 0x7C, 0xE1, 0xF1, 0x87, 0xC3, 0x1F, 0x0E, 0x7C, 0x19,
|
|
||||||
0xF0, 0x77, 0xC0, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xC0, 0x1C, 0x07,
|
|
||||||
0x00, 0x00, 0xC0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x7F, 0xC0,
|
|
||||||
0xF8, 0xF0, 0x70, 0x1C, 0x70, 0x07, 0x30, 0x01, 0xB8, 0x00, 0xD8, 0x00,
|
|
||||||
0x7C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x07, 0xE0, 0x03, 0x30,
|
|
||||||
0x01, 0x9C, 0x01, 0xC7, 0x01, 0xC1, 0xF7, 0xC0, 0x7F, 0xC0, 0x02, 0x00,
|
|
||||||
0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x7F,
|
|
||||||
0xC0, 0xF8, 0xF0, 0x70, 0x1C, 0x70, 0x07, 0x30, 0x01, 0xB8, 0x00, 0xD8,
|
|
||||||
0x00, 0x7C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x07, 0xE0, 0x03,
|
|
||||||
0x30, 0x01, 0x9C, 0x01, 0xC7, 0x01, 0xC1, 0xF7, 0xC0, 0x7F, 0xC0, 0x02,
|
|
||||||
0x00, 0x01, 0xC0, 0x01, 0xB0, 0x01, 0x88, 0x00, 0x00, 0x00, 0x3E, 0x00,
|
|
||||||
0x7F, 0xC0, 0xF8, 0xF0, 0x70, 0x1C, 0x70, 0x07, 0x30, 0x01, 0xB8, 0x00,
|
|
||||||
0xD8, 0x00, 0x7C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x07, 0xE0,
|
|
||||||
0x03, 0x30, 0x01, 0x9C, 0x01, 0xC7, 0x01, 0xC1, 0xF7, 0xC0, 0x7F, 0xC0,
|
|
||||||
0x02, 0x00, 0x07, 0xB0, 0x03, 0xF8, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFF,
|
|
||||||
0x81, 0xF1, 0xE0, 0xE0, 0x38, 0xE0, 0x0E, 0x60, 0x03, 0x70, 0x01, 0xB0,
|
|
||||||
0x00, 0xF8, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x0F, 0xC0, 0x06,
|
|
||||||
0x60, 0x03, 0x38, 0x03, 0x8E, 0x03, 0x83, 0xEF, 0x80, 0xFF, 0x80, 0x04,
|
|
||||||
0x00, 0x07, 0x70, 0x03, 0xB8, 0x00, 0x00, 0x00, 0x7C, 0x00, 0xFF, 0x81,
|
|
||||||
0xF1, 0xE0, 0xE0, 0x38, 0xE0, 0x0E, 0x60, 0x03, 0x70, 0x01, 0xB0, 0x00,
|
|
||||||
0xF8, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x0F, 0xC0, 0x06, 0x60,
|
|
||||||
0x03, 0x38, 0x03, 0x8E, 0x03, 0x83, 0xEF, 0x80, 0xFF, 0x80, 0x04, 0x00,
|
|
||||||
0x40, 0x98, 0x63, 0x30, 0x78, 0x0C, 0x07, 0x83, 0x31, 0x86, 0x40, 0x80,
|
|
||||||
0x03, 0xC1, 0x87, 0xFD, 0x8F, 0x8F, 0x86, 0x01, 0xC7, 0x00, 0xF7, 0x00,
|
|
||||||
0xDB, 0x00, 0xCD, 0x80, 0xC7, 0xC0, 0xC3, 0xE0, 0xC1, 0xF0, 0xC0, 0xF8,
|
|
||||||
0xC0, 0x7E, 0xC0, 0x33, 0xC0, 0x19, 0xC0, 0x18, 0x70, 0x1C, 0x5F, 0x7C,
|
|
||||||
0x67, 0xFC, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x0C,
|
|
||||||
0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80,
|
|
||||||
0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x06,
|
|
||||||
0xC0, 0x77, 0xDF, 0x1F, 0xF0, 0x08, 0x00, 0x01, 0xC0, 0x18, 0x00, 0x80,
|
|
||||||
0x08, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0,
|
|
||||||
0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00,
|
|
||||||
0xF8, 0x06, 0xC0, 0x77, 0xDF, 0x1F, 0xF0, 0x08, 0x00, 0x07, 0x00, 0x2C,
|
|
||||||
0x03, 0x30, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E,
|
|
||||||
0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0,
|
|
||||||
0x1E, 0x00, 0xF8, 0x06, 0xC0, 0x77, 0xDF, 0x1F, 0xF0, 0x08, 0x00, 0x0C,
|
|
||||||
0xC0, 0x66, 0x00, 0x01, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03,
|
|
||||||
0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78,
|
|
||||||
0x03, 0xC0, 0x1F, 0x00, 0xD8, 0x0E, 0xFB, 0xE3, 0xFE, 0x01, 0x00, 0x00,
|
|
||||||
0xE0, 0x00, 0xC0, 0x01, 0x80, 0x00, 0x00, 0xE0, 0x07, 0x70, 0x06, 0x30,
|
|
||||||
0x0E, 0x38, 0x1C, 0x18, 0x18, 0x1C, 0x38, 0x0E, 0x30, 0x06, 0x70, 0x07,
|
|
||||||
0x60, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
|
||||||
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xC0, 0x06, 0x00, 0x30, 0x01,
|
|
||||||
0xFE, 0x0F, 0xFE, 0x60, 0x7B, 0x00, 0xD8, 0x07, 0xC0, 0x3E, 0x01, 0xF0,
|
|
||||||
0x0D, 0x83, 0xEF, 0xFE, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00,
|
|
||||||
0x00, 0x7F, 0x8F, 0x3C, 0xC0, 0xEC, 0x06, 0xC0, 0x6C, 0x0E, 0xC1, 0xCC,
|
|
||||||
0x78, 0xC7, 0xEC, 0x06, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x06, 0xC0, 0x6C,
|
|
||||||
0xFC, 0xCF, 0x80, 0x1C, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x1F, 0x07, 0xFC,
|
|
||||||
0x60, 0xC6, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C,
|
|
||||||
0xC0, 0xCE, 0x3E, 0x7E, 0x70, 0x02, 0x03, 0x00, 0x60, 0x0C, 0x00, 0x00,
|
|
||||||
0x1F, 0x07, 0xFC, 0x60, 0xC6, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xC7, 0x8C,
|
|
||||||
0xE0, 0xCC, 0x0C, 0xC0, 0xCE, 0x3E, 0x7E, 0x70, 0x02, 0x0E, 0x01, 0xB0,
|
|
||||||
0x11, 0x80, 0x00, 0x1F, 0x07, 0xFC, 0x60, 0xC6, 0x0C, 0x00, 0xC0, 0x1C,
|
|
||||||
0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C, 0xC0, 0xCE, 0x3E, 0x7E, 0x70, 0x02,
|
|
||||||
0x1C, 0x83, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0x07, 0xFC, 0x60, 0xC6, 0x0C,
|
|
||||||
0x00, 0xC0, 0x1C, 0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C, 0xC0, 0xCE, 0x3E,
|
|
||||||
0x7E, 0x70, 0x02, 0x3B, 0x83, 0xB8, 0x00, 0x00, 0x00, 0x1F, 0x07, 0xFC,
|
|
||||||
0x60, 0xC6, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C,
|
|
||||||
0xC0, 0xCE, 0x3E, 0x7E, 0x70, 0x02, 0x04, 0x00, 0xF0, 0x19, 0x01, 0xB0,
|
|
||||||
0x0F, 0x00, 0x00, 0x1F, 0x07, 0xFC, 0x60, 0xC6, 0x0C, 0x00, 0xC0, 0x1C,
|
|
||||||
0x3F, 0xC7, 0x8C, 0xE0, 0xCC, 0x0C, 0xC0, 0xCE, 0x3E, 0x7E, 0x70, 0x02,
|
|
||||||
0x1F, 0x0F, 0x0F, 0xF7, 0xF9, 0x83, 0xC3, 0xB0, 0x70, 0x30, 0x0C, 0x06,
|
|
||||||
0x03, 0x80, 0xCF, 0xFF, 0xFB, 0xC6, 0x00, 0xE0, 0xC0, 0x18, 0x1C, 0x0F,
|
|
||||||
0x03, 0x83, 0xF1, 0xDC, 0xE7, 0xE3, 0xF8, 0x00, 0x08, 0x00, 0x1F, 0x0F,
|
|
||||||
0xE6, 0x1F, 0x83, 0xC0, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x3E, 0x0D,
|
|
||||||
0xC7, 0x3F, 0x83, 0x00, 0xC0, 0x0C, 0x03, 0x0F, 0x80, 0x38, 0x03, 0x80,
|
|
||||||
0x30, 0x03, 0x00, 0x00, 0x1E, 0x0F, 0xF3, 0x86, 0x60, 0x78, 0x0F, 0x01,
|
|
||||||
0xFF, 0xFC, 0x01, 0x80, 0x30, 0x1B, 0x07, 0x79, 0xC7, 0xF0, 0x10, 0x00,
|
|
||||||
0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x00, 0x1E, 0x0F, 0xF3, 0x86, 0x60,
|
|
||||||
0x78, 0x0F, 0x01, 0xFF, 0xFC, 0x01, 0x80, 0x30, 0x1B, 0x07, 0x79, 0xC7,
|
|
||||||
0xF0, 0x10, 0x00, 0x0F, 0x03, 0x60, 0x66, 0x00, 0x00, 0xF0, 0x7F, 0x9C,
|
|
||||||
0x33, 0x03, 0xC0, 0x78, 0x0F, 0xFF, 0xE0, 0x0C, 0x01, 0x80, 0xD8, 0x3B,
|
|
||||||
0xCE, 0x3F, 0x80, 0x80, 0x19, 0x83, 0x30, 0x00, 0x00, 0x00, 0xF0, 0x7F,
|
|
||||||
0x9C, 0x33, 0x03, 0xC0, 0x78, 0x0F, 0xFF, 0xE0, 0x0C, 0x01, 0x80, 0xD8,
|
|
||||||
0x3B, 0xCE, 0x3F, 0x80, 0x80, 0xE3, 0x0C, 0x30, 0x18, 0xC6, 0x31, 0x8C,
|
|
||||||
0x63, 0x18, 0xC6, 0x31, 0x80, 0x39, 0x99, 0x80, 0x31, 0x8C, 0x63, 0x18,
|
|
||||||
0xC6, 0x31, 0x8C, 0x63, 0x00, 0x30, 0xF1, 0xB6, 0x20, 0x06, 0x0C, 0x18,
|
|
||||||
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xCF, 0x30, 0x00,
|
|
||||||
0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0x20, 0x07,
|
|
||||||
0xE0, 0x70, 0x3F, 0x00, 0x30, 0x3F, 0x0F, 0xF3, 0x8E, 0xE0, 0xF8, 0x0F,
|
|
||||||
0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1B, 0x07, 0x7B, 0xC7, 0xF0, 0x10,
|
|
||||||
0x00, 0x39, 0x1F, 0xC4, 0x20, 0x00, 0xCF, 0x3F, 0xEE, 0x1F, 0x03, 0xC0,
|
|
||||||
0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, 0x38,
|
|
||||||
0x03, 0x00, 0x30, 0x03, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8,
|
|
||||||
0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1B, 0x07, 0x7B, 0xC7, 0xF0,
|
|
||||||
0x10, 0x00, 0x03, 0x80, 0xE0, 0x18, 0x06, 0x00, 0x00, 0x3E, 0x0F, 0xE3,
|
|
||||||
0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1B, 0x07,
|
|
||||||
0x7B, 0xC7, 0xF0, 0x10, 0x00, 0x0E, 0x01, 0xC0, 0x6C, 0x18, 0xC0, 0x00,
|
|
||||||
0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80,
|
|
||||||
0xF0, 0x1B, 0x07, 0x7B, 0xC7, 0xF0, 0x10, 0x00, 0x1C, 0x87, 0xF0, 0x00,
|
|
||||||
0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0,
|
|
||||||
0x3C, 0x07, 0x80, 0xD8, 0x3B, 0xDE, 0x3F, 0x80, 0x80, 0x3B, 0x87, 0x70,
|
|
||||||
0xEE, 0x00, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01,
|
|
||||||
0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1B, 0x07, 0x7B, 0xC7, 0xF0, 0x10, 0x00,
|
|
||||||
0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
|
||||||
0x06, 0x00, 0x60, 0x06, 0x00, 0x0F, 0x80, 0xFE, 0x8E, 0x38, 0xE0, 0xE6,
|
|
||||||
0x0B, 0x30, 0x99, 0x8C, 0xCC, 0xC6, 0x6C, 0x33, 0x41, 0x8C, 0x1C, 0x79,
|
|
||||||
0xC5, 0xFC, 0x01, 0x00, 0x70, 0x0C, 0x01, 0x80, 0x30, 0x00, 0x30, 0x3C,
|
|
||||||
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, 0x07,
|
|
||||||
0xE3, 0xDF, 0xB1, 0x00, 0x07, 0x03, 0x80, 0xC0, 0x60, 0x00, 0x30, 0x3C,
|
|
||||||
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, 0x07,
|
|
||||||
0xE3, 0xDF, 0xB1, 0x00, 0x1C, 0x07, 0x03, 0x60, 0x8C, 0x00, 0x30, 0x3C,
|
|
||||||
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, 0x07,
|
|
||||||
0xE3, 0xDF, 0xB1, 0x00, 0x77, 0x1D, 0xC7, 0x70, 0x00, 0x00, 0x30, 0x3C,
|
|
||||||
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, 0x07,
|
|
||||||
0xE3, 0xDF, 0xB1, 0x00, 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x00, 0xC0,
|
|
||||||
0xD8, 0x1B, 0x03, 0x30, 0xC6, 0x18, 0xC7, 0x0C, 0xC1, 0x98, 0x37, 0x03,
|
|
||||||
0xC0, 0x78, 0x0E, 0x00, 0xC0, 0x18, 0x06, 0x00, 0xC0, 0xF0, 0x1E, 0x00,
|
|
||||||
0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xCF, 0x0D, 0xFC, 0xF0, 0xCE, 0x06,
|
|
||||||
0xE0, 0x6C, 0x06, 0xC0, 0x7C, 0x07, 0xC0, 0x6E, 0x06, 0xE0, 0xEF, 0x9C,
|
|
||||||
0xDF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x19, 0x83, 0x30,
|
|
||||||
0x66, 0x00, 0x00, 0x00, 0xC0, 0xD8, 0x1B, 0x03, 0x30, 0xC6, 0x18, 0xC7,
|
|
||||||
0x0C, 0xC1, 0x98, 0x37, 0x03, 0xC0, 0x78, 0x0E, 0x00, 0xC0, 0x18, 0x06,
|
|
||||||
0x00, 0xC0, 0xF0, 0x1E, 0x00 };
|
|
||||||
|
|
||||||
const GFXglyph FreeSans12pt8bGlyphs[] PROGMEM = {
|
|
||||||
{ 0, 1, 1, 7, 0, 0 }, // 0x20 ' ' U+0020
|
|
||||||
{ 1, 2, 18, 7, 3, -17 }, // 0x21 '!' U+0021
|
|
||||||
{ 6, 6, 6, 9, 1, -16 }, // 0x22 '"' U+0022
|
|
||||||
{ 11, 13, 17, 13, 0, -16 }, // 0x23 '#' U+0023
|
|
||||||
{ 39, 11, 21, 13, 1, -17 }, // 0x24 '$' U+0024
|
|
||||||
{ 68, 20, 17, 21, 1, -16 }, // 0x25 '%' U+0025
|
|
||||||
{ 111, 14, 18, 16, 1, -16 }, // 0x26 '&' U+0026
|
|
||||||
{ 143, 2, 6, 5, 1, -16 }, // 0x27 ''' U+0027
|
|
||||||
{ 145, 5, 23, 8, 2, -17 }, // 0x28 '(' U+0028
|
|
||||||
{ 160, 5, 23, 8, 1, -17 }, // 0x29 ')' U+0029
|
|
||||||
{ 175, 7, 7, 9, 1, -17 }, // 0x2a '*' U+002A
|
|
||||||
{ 182, 12, 11, 14, 1, -10 }, // 0x2b '+' U+002B
|
|
||||||
{ 199, 3, 7, 7, 2, -2 }, // 0x2c ',' U+002C
|
|
||||||
{ 202, 6, 1, 8, 1, -6 }, // 0x2d '-' U+002D
|
|
||||||
{ 203, 3, 3, 7, 2, -2 }, // 0x2e '.' U+002E
|
|
||||||
{ 205, 7, 18, 7, 0, -17 }, // 0x2f '/' U+002F
|
|
||||||
{ 221, 11, 18, 13, 1, -16 }, // 0x30 '0' U+0030
|
|
||||||
{ 246, 6, 17, 13, 2, -16 }, // 0x31 '1' U+0031
|
|
||||||
{ 259, 11, 17, 13, 1, -16 }, // 0x32 '2' U+0032
|
|
||||||
{ 283, 11, 18, 13, 1, -16 }, // 0x33 '3' U+0033
|
|
||||||
{ 308, 11, 17, 13, 1, -16 }, // 0x34 '4' U+0034
|
|
||||||
{ 332, 11, 18, 13, 1, -16 }, // 0x35 '5' U+0035
|
|
||||||
{ 357, 11, 18, 13, 1, -16 }, // 0x36 '6' U+0036
|
|
||||||
{ 382, 11, 17, 13, 1, -16 }, // 0x37 '7' U+0037
|
|
||||||
{ 406, 11, 18, 13, 1, -16 }, // 0x38 '8' U+0038
|
|
||||||
{ 431, 11, 18, 13, 1, -16 }, // 0x39 '9' U+0039
|
|
||||||
{ 456, 2, 13, 7, 3, -12 }, // 0x3a ':' U+003A
|
|
||||||
{ 460, 2, 17, 7, 3, -12 }, // 0x3b ';' U+003B
|
|
||||||
{ 465, 12, 11, 14, 1, -10 }, // 0x3c '<' U+003C
|
|
||||||
{ 482, 12, 5, 14, 1, -7 }, // 0x3d '=' U+003D
|
|
||||||
{ 490, 12, 11, 14, 1, -10 }, // 0x3e '>' U+003E
|
|
||||||
{ 507, 10, 18, 13, 2, -17 }, // 0x3f '?' U+003F
|
|
||||||
{ 530, 22, 21, 24, 1, -17 }, // 0x40 '@' U+0040
|
|
||||||
{ 588, 16, 18, 16, 0, -17 }, // 0x41 'A' U+0041
|
|
||||||
{ 624, 13, 18, 16, 2, -17 }, // 0x42 'B' U+0042
|
|
||||||
{ 654, 15, 19, 17, 1, -17 }, // 0x43 'C' U+0043
|
|
||||||
{ 690, 14, 18, 17, 2, -17 }, // 0x44 'D' U+0044
|
|
||||||
{ 722, 13, 18, 16, 2, -17 }, // 0x45 'E' U+0045
|
|
||||||
{ 752, 12, 18, 15, 2, -17 }, // 0x46 'F' U+0046
|
|
||||||
{ 779, 16, 19, 19, 1, -17 }, // 0x47 'G' U+0047
|
|
||||||
{ 817, 13, 18, 17, 2, -17 }, // 0x48 'H' U+0048
|
|
||||||
{ 847, 3, 18, 7, 2, -17 }, // 0x49 'I' U+0049
|
|
||||||
{ 854, 10, 19, 12, 0, -17 }, // 0x4a 'J' U+004A
|
|
||||||
{ 878, 14, 18, 16, 2, -17 }, // 0x4b 'K' U+004B
|
|
||||||
{ 910, 11, 18, 13, 2, -17 }, // 0x4c 'L' U+004C
|
|
||||||
{ 935, 16, 18, 20, 2, -17 }, // 0x4d 'M' U+004D
|
|
||||||
{ 971, 14, 18, 17, 2, -17 }, // 0x4e 'N' U+004E
|
|
||||||
{ 1003, 17, 19, 19, 1, -17 }, // 0x4f 'O' U+004F
|
|
||||||
{ 1044, 13, 18, 16, 2, -17 }, // 0x50 'P' U+0050
|
|
||||||
{ 1074, 17, 19, 19, 1, -17 }, // 0x51 'Q' U+0051
|
|
||||||
{ 1115, 14, 18, 17, 2, -17 }, // 0x52 'R' U+0052
|
|
||||||
{ 1147, 14, 19, 16, 1, -17 }, // 0x53 'S' U+0053
|
|
||||||
{ 1181, 14, 18, 15, 0, -17 }, // 0x54 'T' U+0054
|
|
||||||
{ 1213, 13, 19, 17, 2, -17 }, // 0x55 'U' U+0055
|
|
||||||
{ 1244, 14, 18, 16, 1, -17 }, // 0x56 'V' U+0056
|
|
||||||
{ 1276, 21, 18, 23, 1, -17 }, // 0x57 'W' U+0057
|
|
||||||
{ 1324, 15, 18, 16, 1, -17 }, // 0x58 'X' U+0058
|
|
||||||
{ 1358, 16, 18, 16, 0, -17 }, // 0x59 'Y' U+0059
|
|
||||||
{ 1394, 13, 18, 15, 1, -17 }, // 0x5a 'Z' U+005A
|
|
||||||
{ 1424, 4, 23, 7, 2, -17 }, // 0x5b '[' U+005B
|
|
||||||
{ 1436, 7, 18, 7, 0, -17 }, // 0x5c '\' U+005C
|
|
||||||
{ 1452, 4, 23, 7, 1, -17 }, // 0x5d ']' U+005D
|
|
||||||
{ 1464, 9, 9, 11, 1, -16 }, // 0x5e '^' U+005E
|
|
||||||
{ 1475, 15, 1, 13, -1, 4 }, // 0x5f '_' U+005F
|
|
||||||
{ 1477, 5, 4, 8, 1, -17 }, // 0x60 '`' U+0060
|
|
||||||
{ 1480, 12, 14, 13, 1, -12 }, // 0x61 'a' U+0061
|
|
||||||
{ 1501, 12, 19, 13, 1, -17 }, // 0x62 'b' U+0062
|
|
||||||
{ 1530, 10, 14, 12, 1, -12 }, // 0x63 'c' U+0063
|
|
||||||
{ 1548, 11, 19, 13, 1, -17 }, // 0x64 'd' U+0064
|
|
||||||
{ 1575, 11, 14, 13, 1, -12 }, // 0x65 'e' U+0065
|
|
||||||
{ 1595, 6, 18, 7, 0, -17 }, // 0x66 'f' U+0066
|
|
||||||
{ 1609, 11, 18, 13, 1, -12 }, // 0x67 'g' U+0067
|
|
||||||
{ 1634, 10, 18, 13, 2, -17 }, // 0x68 'h' U+0068
|
|
||||||
{ 1657, 2, 18, 5, 2, -17 }, // 0x69 'i' U+0069
|
|
||||||
{ 1662, 4, 23, 5, 0, -17 }, // 0x6a 'j' U+006A
|
|
||||||
{ 1674, 11, 18, 12, 1, -17 }, // 0x6b 'k' U+006B
|
|
||||||
{ 1699, 2, 18, 5, 2, -17 }, // 0x6c 'l' U+006C
|
|
||||||
{ 1704, 16, 13, 20, 2, -12 }, // 0x6d 'm' U+006D
|
|
||||||
{ 1730, 10, 13, 13, 2, -12 }, // 0x6e 'n' U+006E
|
|
||||||
{ 1747, 11, 14, 13, 1, -12 }, // 0x6f 'o' U+006F
|
|
||||||
{ 1767, 12, 18, 13, 1, -12 }, // 0x70 'p' U+0070
|
|
||||||
{ 1794, 11, 18, 13, 1, -12 }, // 0x71 'q' U+0071
|
|
||||||
{ 1819, 6, 13, 8, 2, -12 }, // 0x72 'r' U+0072
|
|
||||||
{ 1829, 10, 14, 12, 1, -12 }, // 0x73 's' U+0073
|
|
||||||
{ 1847, 6, 17, 7, 0, -15 }, // 0x74 't' U+0074
|
|
||||||
{ 1860, 10, 14, 13, 2, -12 }, // 0x75 'u' U+0075
|
|
||||||
{ 1878, 12, 13, 12, 0, -12 }, // 0x76 'v' U+0076
|
|
||||||
{ 1898, 17, 13, 17, 0, -12 }, // 0x77 'w' U+0077
|
|
||||||
{ 1926, 11, 13, 12, 0, -12 }, // 0x78 'x' U+0078
|
|
||||||
{ 1944, 11, 18, 12, 0, -12 }, // 0x79 'y' U+0079
|
|
||||||
{ 1969, 10, 13, 12, 1, -12 }, // 0x7a 'z' U+007A
|
|
||||||
{ 1986, 6, 23, 8, 1, -17 }, // 0x7b '{' U+007B
|
|
||||||
{ 2004, 2, 23, 6, 2, -17 }, // 0x7c '|' U+007C
|
|
||||||
{ 2010, 5, 23, 8, 1, -17 }, // 0x7d '}' U+007D
|
|
||||||
{ 2025, 10, 5, 14, 2, -10 }, // 0x7e '~' U+007E
|
|
||||||
{ 2032, 13, 18, 17, 2, -17 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
|
|
||||||
{ 2062, 1, 1, 7, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
|
|
||||||
{ 2063, 2, 18, 7, 3, -12 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
|
|
||||||
{ 2068, 11, 18, 13, 1, -14 }, // 0x82 'CENT SIGN' U+00A2
|
|
||||||
{ 2093, 12, 19, 13, 1, -17 }, // 0x83 'POUND SIGN' U+00A3
|
|
||||||
{ 2122, 14, 18, 16, 1, -16 }, // 0x84 'EURO SIGN *' U+20AC
|
|
||||||
{ 2154, 13, 17, 13, 0, -16 }, // 0x85 'YEN SIGN' U+00A5
|
|
||||||
{ 2182, 14, 23, 16, 1, -21 }, // 0x86 'LATIN CAPITAL LETTER S WITH CARON *' U+0160
|
|
||||||
{ 2223, 11, 23, 13, 1, -17 }, // 0x87 'SECTION SIGN' U+00A7
|
|
||||||
{ 2255, 10, 19, 12, 1, -17 }, // 0x88 'LATIN SMALL LETTER S WITH CARON *' U+0161
|
|
||||||
{ 2279, 18, 19, 18, 0, -17 }, // 0x89 'COPYRIGHT SIGN' U+00A9
|
|
||||||
{ 2322, 7, 11, 9, 1, -17 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
|
|
||||||
{ 2332, 9, 8, 11, 1, -10 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
|
|
||||||
{ 2341, 12, 7, 14, 1, -8 }, // 0x8c 'NOT SIGN' U+00AC
|
|
||||||
{ 2352, 6, 1, 8, 1, -6 }, // 0x8d 'SOFT HYPHEN' U+00AD
|
|
||||||
{ 2353, 18, 19, 18, 0, -17 }, // 0x8e 'REGISTERED SIGN' U+00AE
|
|
||||||
{ 2396, 6, 2, 8, 1, -16 }, // 0x8f 'MACRON' U+00AF
|
|
||||||
{ 2398, 7, 7, 15, 4, -15 }, // 0x90 'DEGREE SIGN' U+00B0
|
|
||||||
{ 2405, 12, 15, 14, 1, -14 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
|
|
||||||
{ 2428, 8, 10, 8, 0, -16 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
|
|
||||||
{ 2438, 8, 11, 8, 0, -16 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
|
|
||||||
{ 2449, 13, 22, 15, 1, -21 }, // 0x94 'LATIN CAPITAL LETTER Z WITH CARON *' U+017D
|
|
||||||
{ 2485, 11, 18, 13, 2, -12 }, // 0x95 'MICRO SIGN' U+00B5
|
|
||||||
{ 2510, 12, 22, 13, 1, -17 }, // 0x96 'PILCROW SIGN' U+00B6
|
|
||||||
{ 2543, 3, 3, 7, 2, -7 }, // 0x97 'MIDDLE DOT' U+00B7
|
|
||||||
{ 2545, 10, 18, 12, 1, -17 }, // 0x98 'LATIN SMALL LETTER Z WITH CARON *' U+017E
|
|
||||||
{ 2568, 4, 10, 8, 2, -16 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
|
|
||||||
{ 2573, 7, 11, 9, 1, -17 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
|
|
||||||
{ 2583, 9, 8, 11, 1, -9 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
|
|
||||||
{ 2592, 22, 18, 24, 1, -17 }, // 0x9c 'LATIN CAPITAL LIGATURE OE *' U+0152
|
|
||||||
{ 2642, 20, 14, 23, 1, -12 }, // 0x9d 'LATIN SMALL LIGATURE OE *' U+0153
|
|
||||||
{ 2677, 16, 21, 16, 0, -20 }, // 0x9e 'LATIN CAPITAL LETTER Y WITH DIAERESIS *' U+0178
|
|
||||||
{ 2719, 10, 18, 13, 3, -12 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
|
|
||||||
{ 2742, 16, 22, 16, 0, -21 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
|
|
||||||
{ 2786, 16, 22, 16, 0, -21 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
|
|
||||||
{ 2830, 16, 22, 16, 0, -21 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
|
|
||||||
{ 2874, 16, 21, 16, 0, -20 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
|
|
||||||
{ 2916, 16, 21, 16, 0, -20 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
|
|
||||||
{ 2958, 16, 23, 16, 0, -22 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
|
|
||||||
{ 3004, 23, 18, 24, 0, -17 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
|
|
||||||
{ 3056, 15, 23, 17, 1, -17 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
|
|
||||||
{ 3100, 13, 22, 16, 2, -21 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
|
|
||||||
{ 3136, 13, 22, 16, 2, -21 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
|
|
||||||
{ 3172, 13, 22, 16, 2, -21 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
|
|
||||||
{ 3208, 13, 21, 16, 2, -20 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
|
|
||||||
{ 3243, 5, 22, 7, 0, -21 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
|
|
||||||
{ 3257, 5, 22, 7, 2, -21 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
|
|
||||||
{ 3271, 7, 22, 7, 0, -21 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
|
|
||||||
{ 3291, 7, 21, 7, 0, -20 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
|
|
||||||
{ 3310, 16, 18, 17, 0, -17 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
|
|
||||||
{ 3346, 14, 21, 17, 2, -20 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
|
|
||||||
{ 3383, 17, 23, 19, 1, -21 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
|
|
||||||
{ 3432, 17, 23, 19, 1, -21 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
|
|
||||||
{ 3481, 17, 23, 19, 1, -21 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
|
|
||||||
{ 3530, 17, 22, 19, 1, -20 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
|
|
||||||
{ 3577, 17, 22, 19, 1, -20 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
|
|
||||||
{ 3624, 10, 9, 14, 2, -9 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
|
|
||||||
{ 3636, 17, 19, 19, 1, -17 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
|
|
||||||
{ 3677, 13, 23, 17, 2, -21 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
|
|
||||||
{ 3715, 13, 23, 17, 2, -21 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
|
|
||||||
{ 3753, 13, 23, 17, 2, -21 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
|
|
||||||
{ 3791, 13, 22, 17, 2, -20 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
|
|
||||||
{ 3827, 16, 22, 16, 0, -21 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
|
|
||||||
{ 3871, 13, 18, 16, 2, -17 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
|
|
||||||
{ 3901, 12, 17, 15, 2, -16 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
|
|
||||||
{ 3927, 12, 18, 13, 1, -16 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
|
|
||||||
{ 3954, 12, 18, 13, 1, -16 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
|
|
||||||
{ 3981, 12, 18, 13, 1, -16 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
|
|
||||||
{ 4008, 12, 18, 13, 1, -16 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
|
|
||||||
{ 4035, 12, 18, 13, 1, -16 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
|
|
||||||
{ 4062, 12, 20, 13, 1, -18 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
|
|
||||||
{ 4092, 19, 14, 22, 1, -12 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
|
|
||||||
{ 4126, 10, 18, 12, 1, -12 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
|
|
||||||
{ 4149, 11, 19, 13, 1, -17 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
|
|
||||||
{ 4176, 11, 19, 13, 1, -17 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
|
|
||||||
{ 4203, 11, 18, 13, 1, -16 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
|
|
||||||
{ 4228, 11, 18, 13, 1, -16 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
|
|
||||||
{ 4253, 5, 18, 6, 0, -17 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
|
|
||||||
{ 4265, 5, 18, 6, 1, -17 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
|
|
||||||
{ 4277, 7, 18, 6, 0, -17 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
|
|
||||||
{ 4293, 6, 17, 6, 0, -16 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
|
|
||||||
{ 4306, 11, 19, 13, 1, -17 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
|
|
||||||
{ 4333, 10, 17, 13, 2, -16 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
|
|
||||||
{ 4355, 11, 19, 13, 1, -17 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
|
|
||||||
{ 4382, 11, 19, 13, 1, -17 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
|
|
||||||
{ 4409, 11, 19, 13, 1, -17 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
|
|
||||||
{ 4436, 11, 18, 13, 1, -16 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
|
|
||||||
{ 4461, 11, 19, 13, 1, -17 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
|
|
||||||
{ 4488, 12, 11, 14, 1, -10 }, // 0xd7 'DIVISION SIGN' U+00F7
|
|
||||||
{ 4505, 13, 14, 15, 0, -12 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
|
|
||||||
{ 4528, 10, 19, 13, 2, -17 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
|
|
||||||
{ 4552, 10, 19, 13, 2, -17 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
|
|
||||||
{ 4576, 10, 19, 13, 2, -17 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
|
|
||||||
{ 4600, 10, 19, 13, 2, -17 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
|
|
||||||
{ 4624, 11, 23, 12, 0, -17 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
|
|
||||||
{ 4656, 12, 22, 13, 1, -16 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
|
|
||||||
{ 4689, 11, 23, 12, 0, -17 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
|
|
||||||
|
|
||||||
const GFXfont FreeSans12pt8b PROGMEM = {
|
|
||||||
(uint8_t *)FreeSans12pt8bBitmaps,
|
|
||||||
(GFXglyph *)FreeSans12pt8bGlyphs,
|
|
||||||
0x20, 0xDF, 33 };
|
|
||||||
|
|
||||||
// Approx. 6072 bytes
|
|
|
@ -1,451 +0,0 @@
|
||||||
const uint8_t FreeSans18pt7bBitmaps[] PROGMEM = {
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0x20, 0x3F, 0xFC, 0xE3, 0xF1,
|
|
||||||
0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8E, 0x82, 0x41, 0x00, 0x01, 0xC3, 0x80,
|
|
||||||
0x38, 0x70, 0x06, 0x0E, 0x00, 0xC1, 0x80, 0x38, 0x70, 0x07, 0x0E, 0x0F,
|
|
||||||
0xFF, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0xE1, 0xC0, 0x1C, 0x38, 0x03,
|
|
||||||
0x87, 0x00, 0x70, 0xE0, 0x0C, 0x18, 0x3F, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF,
|
|
||||||
0xFF, 0xC1, 0xC3, 0x80, 0x30, 0x60, 0x06, 0x0C, 0x01, 0xC3, 0x80, 0x38,
|
|
||||||
0x70, 0x07, 0x0E, 0x00, 0xC1, 0x80, 0x03, 0x00, 0x0F, 0xC0, 0x3F, 0xF0,
|
|
||||||
0x3F, 0xF8, 0x7B, 0x3C, 0xF3, 0x1C, 0xE3, 0x0E, 0xE3, 0x0E, 0xE3, 0x0E,
|
|
||||||
0xE3, 0x00, 0xE3, 0x00, 0xF3, 0x00, 0x7B, 0x00, 0x7F, 0x80, 0x1F, 0xF0,
|
|
||||||
0x07, 0xFC, 0x03, 0x7E, 0x03, 0x0F, 0x03, 0x07, 0xE3, 0x07, 0xE3, 0x07,
|
|
||||||
0xE3, 0x07, 0xE3, 0x0F, 0x73, 0x3E, 0x7F, 0xFC, 0x3F, 0xF8, 0x0F, 0xE0,
|
|
||||||
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x78, 0x00,
|
|
||||||
0xE0, 0x0F, 0xF0, 0x06, 0x00, 0xFF, 0xC0, 0x70, 0x07, 0x0E, 0x07, 0x00,
|
|
||||||
0x70, 0x38, 0x38, 0x03, 0x00, 0xC3, 0x80, 0x18, 0x06, 0x1C, 0x00, 0xE0,
|
|
||||||
0x71, 0xC0, 0x03, 0x87, 0x8C, 0x00, 0x1F, 0xF8, 0xE0, 0x00, 0x7F, 0x86,
|
|
||||||
0x00, 0x01, 0xF8, 0x70, 0x00, 0x00, 0x03, 0x03, 0xC0, 0x00, 0x38, 0x7F,
|
|
||||||
0x80, 0x01, 0x87, 0xFE, 0x00, 0x1C, 0x38, 0x70, 0x00, 0xC3, 0x81, 0xC0,
|
|
||||||
0x0E, 0x18, 0x06, 0x00, 0xE0, 0xC0, 0x30, 0x07, 0x07, 0x03, 0x80, 0x70,
|
|
||||||
0x1C, 0x38, 0x03, 0x80, 0xFF, 0xC0, 0x38, 0x03, 0xFC, 0x01, 0x80, 0x07,
|
|
||||||
0x80, 0x01, 0xF0, 0x00, 0x7F, 0x80, 0x0F, 0xFC, 0x01, 0xE1, 0xE0, 0x1C,
|
|
||||||
0x0E, 0x01, 0xC0, 0xE0, 0x1C, 0x0E, 0x01, 0xE1, 0xE0, 0x0E, 0x3C, 0x00,
|
|
||||||
0x77, 0x80, 0x07, 0xF0, 0x00, 0x7C, 0x00, 0x0F, 0xE0, 0x03, 0xCF, 0x1C,
|
|
||||||
0x78, 0x79, 0xC7, 0x03, 0xDC, 0xE0, 0x1F, 0x8E, 0x00, 0xF8, 0xE0, 0x0F,
|
|
||||||
0x0E, 0x00, 0x70, 0xF0, 0x0F, 0x87, 0xC3, 0xFC, 0x7F, 0xFD, 0xC3, 0xFF,
|
|
||||||
0x0E, 0x0F, 0xC0, 0xF0, 0xFF, 0xFF, 0xFA, 0x40, 0x06, 0x06, 0x0C, 0x0C,
|
|
||||||
0x18, 0x18, 0x38, 0x30, 0x70, 0x70, 0x70, 0x60, 0xE0, 0xE0, 0xE0, 0xE0,
|
|
||||||
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x60, 0x70, 0x70, 0x70, 0x30, 0x38, 0x18,
|
|
||||||
0x18, 0x0C, 0x0C, 0x06, 0x03, 0xC0, 0x60, 0x30, 0x30, 0x38, 0x18, 0x1C,
|
|
||||||
0x0C, 0x0E, 0x0E, 0x0E, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
||||||
0x07, 0x07, 0x06, 0x0E, 0x0E, 0x0E, 0x0C, 0x1C, 0x18, 0x38, 0x30, 0x30,
|
|
||||||
0x60, 0xC0, 0x0C, 0x03, 0x00, 0xC3, 0xB7, 0xFF, 0xC7, 0x81, 0xE0, 0xEC,
|
|
||||||
0x73, 0x88, 0x40, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
|
||||||
0x80, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01,
|
|
||||||
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xFF,
|
|
||||||
0xF6, 0xDA, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xC0, 0x30, 0x18,
|
|
||||||
0x06, 0x01, 0x80, 0xC0, 0x30, 0x0C, 0x06, 0x01, 0x80, 0x60, 0x30, 0x0C,
|
|
||||||
0x03, 0x00, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x00, 0xC0, 0x30, 0x18, 0x06,
|
|
||||||
0x01, 0x80, 0xC0, 0x30, 0x00, 0x07, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, 0x3C,
|
|
||||||
0x3C, 0x78, 0x1E, 0x70, 0x0E, 0x70, 0x0E, 0xE0, 0x07, 0xE0, 0x07, 0xE0,
|
|
||||||
0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0,
|
|
||||||
0x07, 0xE0, 0x07, 0xE0, 0x0F, 0x70, 0x0E, 0x70, 0x0E, 0x78, 0x1E, 0x3C,
|
|
||||||
0x3C, 0x1F, 0xF8, 0x1F, 0xF0, 0x07, 0xE0, 0x03, 0x03, 0x07, 0x0F, 0x3F,
|
|
||||||
0xFF, 0xFF, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
||||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xE0, 0x1F, 0xF8,
|
|
||||||
0x3F, 0xFC, 0x7C, 0x3E, 0x70, 0x0F, 0xF0, 0x0F, 0xE0, 0x07, 0xE0, 0x07,
|
|
||||||
0x00, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF8,
|
|
||||||
0x03, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x70, 0x00,
|
|
||||||
0x60, 0x00, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0,
|
|
||||||
0x07, 0xFE, 0x07, 0xFF, 0x87, 0x83, 0xC3, 0x80, 0xF3, 0x80, 0x39, 0xC0,
|
|
||||||
0x1C, 0xE0, 0x0E, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x7F, 0x00, 0x3F, 0x00,
|
|
||||||
0x1F, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0xF0, 0x01,
|
|
||||||
0xF8, 0x00, 0xFE, 0x00, 0x77, 0x00, 0x73, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F,
|
|
||||||
0xF8, 0x07, 0xF0, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x78, 0x00, 0xF8,
|
|
||||||
0x00, 0xF8, 0x01, 0xF8, 0x03, 0xB8, 0x03, 0x38, 0x07, 0x38, 0x0E, 0x38,
|
|
||||||
0x1C, 0x38, 0x18, 0x38, 0x38, 0x38, 0x70, 0x38, 0x60, 0x38, 0xE0, 0x38,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
|
||||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x1F, 0xFF, 0x0F, 0xFF, 0x8F, 0xFF,
|
|
||||||
0xC7, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x39,
|
|
||||||
0xF0, 0x3F, 0xFE, 0x1F, 0xFF, 0x8F, 0x83, 0xE7, 0x00, 0xF0, 0x00, 0x3C,
|
|
||||||
0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xFC, 0x00,
|
|
||||||
0xEF, 0x00, 0x73, 0xC0, 0xF0, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xE0, 0x00,
|
|
||||||
0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, 0x3C, 0x1E, 0x38, 0x0E, 0x70, 0x0E,
|
|
||||||
0x70, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xE3, 0xE0, 0xEF, 0xF8, 0xFF, 0xFC,
|
|
||||||
0xFC, 0x3E, 0xF0, 0x0E, 0xF0, 0x0F, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07,
|
|
||||||
0x60, 0x07, 0x70, 0x0F, 0x70, 0x0E, 0x3C, 0x3E, 0x3F, 0xFC, 0x1F, 0xF8,
|
|
||||||
0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0E,
|
|
||||||
0x00, 0x1C, 0x00, 0x18, 0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00, 0xE0,
|
|
||||||
0x00, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0x00,
|
|
||||||
0x07, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00,
|
|
||||||
0x1C, 0x00, 0x1C, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x87, 0x83,
|
|
||||||
0xC7, 0x80, 0xF3, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x78, 0x0F, 0x1E,
|
|
||||||
0x0F, 0x07, 0xFF, 0x01, 0xFF, 0x03, 0xFF, 0xE3, 0xE0, 0xF9, 0xC0, 0x1D,
|
|
||||||
0xC0, 0x0F, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0xF7, 0x00,
|
|
||||||
0x73, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x07, 0xE0,
|
|
||||||
0x1F, 0xF8, 0x3F, 0xFC, 0x7C, 0x3C, 0x70, 0x0E, 0xF0, 0x0E, 0xE0, 0x06,
|
|
||||||
0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0x70, 0x0F, 0x78, 0x3F,
|
|
||||||
0x3F, 0xFF, 0x1F, 0xF7, 0x07, 0xC7, 0x00, 0x07, 0x00, 0x06, 0x00, 0x0E,
|
|
||||||
0x70, 0x0E, 0x70, 0x1C, 0x78, 0x3C, 0x3F, 0xF8, 0x1F, 0xF0, 0x07, 0xC0,
|
|
||||||
0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x00, 0x00,
|
|
||||||
0x00, 0x07, 0xFF, 0xB6, 0xD6, 0x00, 0x00, 0x80, 0x03, 0xC0, 0x07, 0xE0,
|
|
||||||
0x0F, 0xC0, 0x3F, 0x80, 0x7E, 0x00, 0xFC, 0x01, 0xF0, 0x00, 0xE0, 0x00,
|
|
||||||
0x7C, 0x00, 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x80, 0x07, 0xF0, 0x00,
|
|
||||||
0x7E, 0x00, 0x0F, 0x00, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0x80, 0x80, 0x00, 0x70, 0x00, 0x3E, 0x00, 0x0F, 0xE0, 0x00, 0xFC,
|
|
||||||
0x00, 0x1F, 0xC0, 0x03, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0x80, 0x0F, 0xC0,
|
|
||||||
0x1F, 0x80, 0x7F, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x01, 0xC0, 0x00,
|
|
||||||
0x80, 0x00, 0x00, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE3, 0xC3, 0xEF, 0x01,
|
|
||||||
0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0x00, 0x0E, 0x00, 0x38, 0x00, 0xF0,
|
|
||||||
0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x0E,
|
|
||||||
0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x03, 0x80,
|
|
||||||
0x07, 0x00, 0x0E, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0x00,
|
|
||||||
0x00, 0xFF, 0xFF, 0xC0, 0x01, 0xF8, 0x0F, 0xE0, 0x03, 0xE0, 0x01, 0xF0,
|
|
||||||
0x07, 0x80, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x3C, 0x1E, 0x00, 0x00, 0x1E,
|
|
||||||
0x3C, 0x03, 0xE0, 0x1E, 0x38, 0x0F, 0xF3, 0x8E, 0x78, 0x1E, 0x3F, 0x0F,
|
|
||||||
0x70, 0x38, 0x1F, 0x07, 0x70, 0x78, 0x0F, 0x07, 0xE0, 0x70, 0x0E, 0x07,
|
|
||||||
0xE0, 0x70, 0x0E, 0x07, 0xE0, 0xE0, 0x0E, 0x07, 0xE0, 0xE0, 0x1C, 0x07,
|
|
||||||
0xE0, 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x38, 0x1C,
|
|
||||||
0xF0, 0x70, 0x78, 0x3C, 0x70, 0x78, 0xFC, 0x78, 0x78, 0x3F, 0xDF, 0xF0,
|
|
||||||
0x38, 0x1F, 0x0F, 0xC0, 0x3C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
|
|
||||||
0x0F, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0E, 0x00, 0x01, 0xFF, 0xFE, 0x00,
|
|
||||||
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x03,
|
|
||||||
0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xDC, 0x00, 0x07, 0x78,
|
|
||||||
0x00, 0x3C, 0xE0, 0x00, 0xE3, 0x80, 0x03, 0x8F, 0x00, 0x1E, 0x1C, 0x00,
|
|
||||||
0x70, 0x70, 0x01, 0xC1, 0xE0, 0x0E, 0x03, 0x80, 0x38, 0x0E, 0x00, 0xE0,
|
|
||||||
0x3C, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0xFF, 0xFF, 0x83, 0xC0, 0x0E,
|
|
||||||
0x0E, 0x00, 0x3C, 0x78, 0x00, 0xF1, 0xE0, 0x01, 0xC7, 0x00, 0x07, 0xBC,
|
|
||||||
0x00, 0x1E, 0xF0, 0x00, 0x3B, 0x80, 0x00, 0xF0, 0xFF, 0xFC, 0x1F, 0xFF,
|
|
||||||
0xE3, 0xFF, 0xFE, 0x70, 0x03, 0xCE, 0x00, 0x3D, 0xC0, 0x03, 0xB8, 0x00,
|
|
||||||
0x77, 0x00, 0x0E, 0xE0, 0x01, 0xDC, 0x00, 0x73, 0x80, 0x1E, 0x7F, 0xFF,
|
|
||||||
0x8F, 0xFF, 0xF1, 0xFF, 0xFF, 0x38, 0x00, 0xF7, 0x00, 0x0E, 0xE0, 0x00,
|
|
||||||
0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x03,
|
|
||||||
0xF8, 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0xFF, 0x1F, 0xFF, 0x80, 0x00, 0xFF,
|
|
||||||
0x00, 0x0F, 0xFF, 0x00, 0xFF, 0xFE, 0x07, 0xE0, 0x7C, 0x3E, 0x00, 0x78,
|
|
||||||
0xF0, 0x00, 0xE7, 0x80, 0x03, 0xDC, 0x00, 0x07, 0x70, 0x00, 0x03, 0x80,
|
|
||||||
0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00,
|
|
||||||
0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x1D, 0xC0, 0x00, 0x77,
|
|
||||||
0x00, 0x03, 0xDE, 0x00, 0x0E, 0x3C, 0x00, 0x78, 0xF8, 0x03, 0xC1, 0xF8,
|
|
||||||
0x1F, 0x03, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x03, 0xF8, 0x00, 0xFF, 0xF8,
|
|
||||||
0x0F, 0xFF, 0xE0, 0xFF, 0xFF, 0x0E, 0x00, 0xF8, 0xE0, 0x03, 0xCE, 0x00,
|
|
||||||
0x1C, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xFE, 0x00, 0x07, 0xE0,
|
|
||||||
0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E,
|
|
||||||
0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x0F, 0xE0, 0x00, 0xEE, 0x00, 0x0E,
|
|
||||||
0xE0, 0x01, 0xEE, 0x00, 0x3C, 0xE0, 0x0F, 0x8F, 0xFF, 0xF0, 0xFF, 0xFE,
|
|
||||||
0x0F, 0xFF, 0x80, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0xFF, 0xFB, 0x80, 0x00,
|
|
||||||
0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38,
|
|
||||||
0x00, 0x0E, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0xFF, 0xBF, 0xFF, 0xEE, 0x00,
|
|
||||||
0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00,
|
|
||||||
0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0E, 0x00,
|
|
||||||
0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38,
|
|
||||||
0x00, 0x1F, 0xFF, 0xCF, 0xFF, 0xE7, 0xFF, 0xF3, 0x80, 0x01, 0xC0, 0x00,
|
|
||||||
0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00,
|
|
||||||
0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7F,
|
|
||||||
0x80, 0x03, 0xFF, 0xE0, 0x07, 0xFF, 0xF8, 0x0F, 0x80, 0xFC, 0x1E, 0x00,
|
|
||||||
0x3E, 0x3C, 0x00, 0x0E, 0x78, 0x00, 0x0F, 0x70, 0x00, 0x07, 0x70, 0x00,
|
|
||||||
0x00, 0xE0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xE0, 0x03,
|
|
||||||
0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x00, 0x07, 0xF0, 0x00,
|
|
||||||
0x07, 0x70, 0x00, 0x07, 0x70, 0x00, 0x0F, 0x78, 0x00, 0x0F, 0x3C, 0x00,
|
|
||||||
0x1F, 0x1E, 0x00, 0x3F, 0x0F, 0xC0, 0xF7, 0x07, 0xFF, 0xE7, 0x03, 0xFF,
|
|
||||||
0xC3, 0x00, 0xFF, 0x03, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0,
|
|
||||||
0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0,
|
|
||||||
0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80,
|
|
||||||
0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00,
|
|
||||||
0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00,
|
|
||||||
0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0,
|
|
||||||
0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x80, 0x7E,
|
|
||||||
0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0,
|
|
||||||
0x3F, 0x00, 0xE0, 0x01, 0xEE, 0x00, 0x3C, 0xE0, 0x07, 0x8E, 0x00, 0xF0,
|
|
||||||
0xE0, 0x1E, 0x0E, 0x03, 0xE0, 0xE0, 0x7C, 0x0E, 0x0F, 0x80, 0xE1, 0xF0,
|
|
||||||
0x0E, 0x1E, 0x00, 0xE3, 0xC0, 0x0E, 0x7C, 0x00, 0xEF, 0xE0, 0x0F, 0xCE,
|
|
||||||
0x00, 0xF8, 0xF0, 0x0F, 0x07, 0x80, 0xE0, 0x3C, 0x0E, 0x03, 0xC0, 0xE0,
|
|
||||||
0x1E, 0x0E, 0x00, 0xF0, 0xE0, 0x0F, 0x0E, 0x00, 0x78, 0xE0, 0x03, 0xCE,
|
|
||||||
0x00, 0x3C, 0xE0, 0x01, 0xEE, 0x00, 0x0F, 0xE0, 0x01, 0xC0, 0x03, 0x80,
|
|
||||||
0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01,
|
|
||||||
0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70,
|
|
||||||
0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00,
|
|
||||||
0x38, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0x00, 0x1F, 0xF8,
|
|
||||||
0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC,
|
|
||||||
0x00, 0x3F, 0xEE, 0x00, 0x77, 0xEE, 0x00, 0x77, 0xEE, 0x00, 0x77, 0xE7,
|
|
||||||
0x00, 0xE7, 0xE7, 0x00, 0xE7, 0xE7, 0x00, 0xE7, 0xE3, 0x81, 0xC7, 0xE3,
|
|
||||||
0x81, 0xC7, 0xE3, 0x81, 0xC7, 0xE1, 0xC3, 0x87, 0xE1, 0xC3, 0x87, 0xE1,
|
|
||||||
0xC3, 0x87, 0xE0, 0xE7, 0x07, 0xE0, 0xE7, 0x07, 0xE0, 0xE7, 0x07, 0xE0,
|
|
||||||
0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x3C, 0x07, 0xE0,
|
|
||||||
0x3C, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0xC0, 0x07,
|
|
||||||
0xFC, 0x00, 0x7F, 0xE0, 0x07, 0xEF, 0x00, 0x7E, 0x70, 0x07, 0xE7, 0x80,
|
|
||||||
0x7E, 0x3C, 0x07, 0xE1, 0xC0, 0x7E, 0x1E, 0x07, 0xE0, 0xE0, 0x7E, 0x0F,
|
|
||||||
0x07, 0xE0, 0x78, 0x7E, 0x03, 0x87, 0xE0, 0x3C, 0x7E, 0x01, 0xE7, 0xE0,
|
|
||||||
0x0E, 0x7E, 0x00, 0xF7, 0xE0, 0x07, 0xFE, 0x00, 0x3F, 0xE0, 0x03, 0xFE,
|
|
||||||
0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x0F, 0x00, 0x7F, 0x00, 0x01, 0xFF,
|
|
||||||
0xF0, 0x01, 0xFF, 0xFC, 0x01, 0xF0, 0x1F, 0x01, 0xE0, 0x03, 0xC1, 0xE0,
|
|
||||||
0x00, 0xF1, 0xE0, 0x00, 0x3C, 0xE0, 0x00, 0x0E, 0x70, 0x00, 0x07, 0x70,
|
|
||||||
0x00, 0x03, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F,
|
|
||||||
0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03,
|
|
||||||
0xB8, 0x00, 0x03, 0x9C, 0x00, 0x01, 0xCF, 0x00, 0x01, 0xE3, 0xC0, 0x01,
|
|
||||||
0xE0, 0xF0, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0x0F, 0xFF, 0xE0, 0x03, 0xFF,
|
|
||||||
0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3,
|
|
||||||
0x80, 0x3E, 0xE0, 0x03, 0xF8, 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0,
|
|
||||||
0x01, 0xF8, 0x00, 0x7E, 0x00, 0x3F, 0x80, 0x1E, 0xFF, 0xFF, 0x3F, 0xFF,
|
|
||||||
0x8F, 0xFF, 0xC3, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03,
|
|
||||||
0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0,
|
|
||||||
0x00, 0x38, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xF0, 0x01, 0xFF,
|
|
||||||
0xFC, 0x01, 0xF0, 0x1F, 0x01, 0xE0, 0x03, 0xC1, 0xE0, 0x00, 0xF1, 0xE0,
|
|
||||||
0x00, 0x3C, 0xE0, 0x00, 0x0E, 0x70, 0x00, 0x07, 0x70, 0x00, 0x01, 0xF8,
|
|
||||||
0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F,
|
|
||||||
0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xB8, 0x00, 0x03,
|
|
||||||
0x9C, 0x00, 0x01, 0xCF, 0x00, 0x39, 0xE3, 0xC0, 0x1F, 0xE0, 0xF0, 0x07,
|
|
||||||
0xE0, 0x3E, 0x03, 0xF0, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xEE, 0x00, 0x3F,
|
|
||||||
0x83, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x20, 0xFF, 0xFE, 0x0F, 0xFF,
|
|
||||||
0xF8, 0xFF, 0xFF, 0xCE, 0x00, 0x3C, 0xE0, 0x01, 0xEE, 0x00, 0x0E, 0xE0,
|
|
||||||
0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x01, 0xCE,
|
|
||||||
0x00, 0x3C, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0xFF, 0xFF, 0x8E, 0x00, 0x3C,
|
|
||||||
0xE0, 0x01, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00,
|
|
||||||
0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xFE, 0x00,
|
|
||||||
0x0F, 0x03, 0xFC, 0x00, 0xFF, 0xF0, 0x1F, 0xFF, 0x83, 0xE0, 0x7C, 0x38,
|
|
||||||
0x01, 0xE7, 0x00, 0x0E, 0x70, 0x00, 0xE7, 0x00, 0x00, 0x70, 0x00, 0x07,
|
|
||||||
0x80, 0x00, 0x3E, 0x00, 0x01, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0x3F, 0xF8,
|
|
||||||
0x00, 0x3F, 0xE0, 0x00, 0x3E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0xE0, 0x00,
|
|
||||||
0x7E, 0x00, 0x07, 0xF0, 0x00, 0x77, 0x80, 0x0E, 0x7C, 0x03, 0xE3, 0xFF,
|
|
||||||
0xFC, 0x1F, 0xFF, 0x80, 0x3F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0x80, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07,
|
|
||||||
0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E,
|
|
||||||
0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C,
|
|
||||||
0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x38,
|
|
||||||
0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0xE0, 0x00, 0xFC, 0x00,
|
|
||||||
0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00,
|
|
||||||
0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00,
|
|
||||||
0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00,
|
|
||||||
0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x1E, 0xF0, 0x07,
|
|
||||||
0x9F, 0x01, 0xF1, 0xFF, 0xFC, 0x1F, 0xFE, 0x00, 0x7F, 0x00, 0xE0, 0x00,
|
|
||||||
0x7F, 0x80, 0x03, 0xFC, 0x00, 0x1C, 0xE0, 0x01, 0xE7, 0x80, 0x0F, 0x3C,
|
|
||||||
0x00, 0x70, 0xE0, 0x07, 0x87, 0x80, 0x3C, 0x1C, 0x01, 0xC0, 0xE0, 0x0E,
|
|
||||||
0x07, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x38, 0x07, 0x83, 0x80, 0x1C,
|
|
||||||
0x1C, 0x00, 0xE0, 0xE0, 0x07, 0x8E, 0x00, 0x1C, 0x70, 0x00, 0xE3, 0x80,
|
|
||||||
0x07, 0xB8, 0x00, 0x1D, 0xC0, 0x00, 0xEE, 0x00, 0x07, 0xE0, 0x00, 0x1F,
|
|
||||||
0x00, 0x00, 0xF8, 0x00, 0x03, 0x80, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x70,
|
|
||||||
0x03, 0xC0, 0x0F, 0x78, 0x03, 0xE0, 0x0F, 0x78, 0x03, 0xE0, 0x0E, 0x38,
|
|
||||||
0x07, 0xE0, 0x0E, 0x38, 0x07, 0xF0, 0x1E, 0x3C, 0x07, 0x70, 0x1E, 0x3C,
|
|
||||||
0x07, 0x70, 0x1C, 0x1C, 0x0E, 0x70, 0x1C, 0x1C, 0x0E, 0x38, 0x3C, 0x1C,
|
|
||||||
0x0E, 0x38, 0x3C, 0x1E, 0x1E, 0x38, 0x38, 0x0E, 0x1C, 0x38, 0x38, 0x0E,
|
|
||||||
0x1C, 0x1C, 0x38, 0x0E, 0x1C, 0x1C, 0x78, 0x0F, 0x3C, 0x1C, 0x70, 0x07,
|
|
||||||
0x38, 0x0E, 0x70, 0x07, 0x38, 0x0E, 0x70, 0x07, 0x38, 0x0E, 0x70, 0x07,
|
|
||||||
0x70, 0x0E, 0xE0, 0x03, 0xF0, 0x07, 0xE0, 0x03, 0xF0, 0x07, 0xE0, 0x03,
|
|
||||||
0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xC0, 0x01, 0xE0, 0x03, 0xC0, 0x01,
|
|
||||||
0xE0, 0x03, 0xC0, 0xF0, 0x00, 0x7B, 0xC0, 0x07, 0x8F, 0x00, 0x38, 0x78,
|
|
||||||
0x03, 0xC1, 0xE0, 0x3C, 0x07, 0x81, 0xC0, 0x3C, 0x1E, 0x00, 0xF1, 0xE0,
|
|
||||||
0x03, 0x8E, 0x00, 0x1E, 0xF0, 0x00, 0x7F, 0x00, 0x01, 0xF0, 0x00, 0x0F,
|
|
||||||
0x80, 0x00, 0x7C, 0x00, 0x07, 0xF0, 0x00, 0x3B, 0x80, 0x03, 0xDE, 0x00,
|
|
||||||
0x3C, 0x78, 0x01, 0xC1, 0xC0, 0x1E, 0x0F, 0x01, 0xE0, 0x3C, 0x0E, 0x00,
|
|
||||||
0xE0, 0xF0, 0x07, 0x8F, 0x00, 0x1E, 0x70, 0x00, 0xF7, 0x80, 0x03, 0xC0,
|
|
||||||
0xF0, 0x00, 0x3C, 0xF0, 0x00, 0x78, 0xF0, 0x01, 0xE1, 0xE0, 0x03, 0x81,
|
|
||||||
0xE0, 0x0F, 0x01, 0xC0, 0x1C, 0x03, 0xC0, 0x78, 0x03, 0xC1, 0xE0, 0x07,
|
|
||||||
0x83, 0x80, 0x07, 0x8F, 0x00, 0x07, 0x1C, 0x00, 0x0F, 0x78, 0x00, 0x0E,
|
|
||||||
0xE0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38,
|
|
||||||
0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80,
|
|
||||||
0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00,
|
|
||||||
0x00, 0x70, 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0x80, 0x00,
|
|
||||||
0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E,
|
|
||||||
0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0,
|
|
||||||
0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x7C, 0x00,
|
|
||||||
0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xF8, 0xE3, 0x8E, 0x38, 0xE3,
|
|
||||||
0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3,
|
|
||||||
0x8E, 0x38, 0xE3, 0x8F, 0xFF, 0xFC, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x60,
|
|
||||||
0x0C, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x01, 0x80, 0x20, 0x0C, 0x03, 0x00,
|
|
||||||
0x40, 0x18, 0x06, 0x01, 0x80, 0x30, 0x0C, 0x03, 0x00, 0x60, 0x18, 0x06,
|
|
||||||
0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7,
|
|
||||||
0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7,
|
|
||||||
0x1C, 0x7F, 0xFF, 0xFC, 0x07, 0x00, 0x78, 0x03, 0xC0, 0x3F, 0x01, 0xD8,
|
|
||||||
0x0C, 0xE0, 0xE3, 0x06, 0x1C, 0x70, 0xE3, 0x83, 0x18, 0x1D, 0xC0, 0x6C,
|
|
||||||
0x03, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xF0, 0xF0, 0xE0, 0xE0,
|
|
||||||
0xE0, 0x07, 0xF0, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, 0x03, 0xC7, 0x00, 0xE0,
|
|
||||||
0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0xFE, 0x0F, 0xFF, 0x1F, 0xF3,
|
|
||||||
0x9F, 0x01, 0xCF, 0x00, 0xE7, 0x00, 0x73, 0x80, 0x79, 0xE0, 0xFC, 0x7F,
|
|
||||||
0xEF, 0x9F, 0xE3, 0xC7, 0xE1, 0xE0, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00,
|
|
||||||
0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE3, 0xE0, 0xEF, 0xF8,
|
|
||||||
0xFF, 0xFC, 0xFC, 0x3E, 0xF8, 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xE0, 0x07,
|
|
||||||
0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0E,
|
|
||||||
0xF8, 0x1E, 0xFC, 0x3C, 0xEF, 0xFC, 0xEF, 0xF8, 0xE3, 0xE0, 0x07, 0xF0,
|
|
||||||
0x1F, 0xF8, 0x3F, 0xFC, 0x3C, 0x1E, 0x78, 0x0E, 0x70, 0x07, 0xE0, 0x00,
|
|
||||||
0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x07,
|
|
||||||
0x70, 0x07, 0x78, 0x0E, 0x7C, 0x1E, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0,
|
|
||||||
0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00,
|
|
||||||
0x1C, 0x00, 0x0E, 0x0F, 0xC7, 0x1F, 0xFB, 0x9F, 0xFF, 0xDF, 0x07, 0xEF,
|
|
||||||
0x01, 0xF7, 0x00, 0x7F, 0x80, 0x3F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03,
|
|
||||||
0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x77, 0x00, 0x7B, 0xC0, 0x7D, 0xF0,
|
|
||||||
0x7E, 0x7F, 0xFB, 0x1F, 0xF9, 0x83, 0xF0, 0xC0, 0x07, 0xE0, 0x1F, 0xF8,
|
|
||||||
0x3F, 0xFC, 0x7C, 0x1E, 0x70, 0x0E, 0x60, 0x06, 0xE0, 0x07, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x70, 0x07,
|
|
||||||
0x78, 0x0E, 0x3C, 0x1E, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, 0x0E, 0x3C,
|
|
||||||
0xF9, 0xC3, 0x87, 0x0E, 0x7F, 0xFF, 0xFC, 0xE1, 0xC3, 0x87, 0x0E, 0x1C,
|
|
||||||
0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0x07, 0xC7, 0x1F,
|
|
||||||
0xF7, 0x3F, 0xFF, 0x3C, 0x3F, 0x78, 0x0F, 0x70, 0x0F, 0xE0, 0x07, 0xE0,
|
|
||||||
0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0x70,
|
|
||||||
0x0F, 0x78, 0x0F, 0x7C, 0x3F, 0x3F, 0xF7, 0x1F, 0xE7, 0x07, 0xC7, 0x00,
|
|
||||||
0x07, 0x00, 0x07, 0x00, 0x0E, 0x70, 0x0E, 0x78, 0x1E, 0x3F, 0xFC, 0x1F,
|
|
||||||
0xF8, 0x07, 0xE0, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00,
|
|
||||||
0x1C, 0x00, 0x38, 0x00, 0x71, 0xF8, 0xE7, 0xFD, 0xDF, 0xFB, 0xF0, 0xFF,
|
|
||||||
0xC0, 0xFF, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0,
|
|
||||||
0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07,
|
|
||||||
0xE0, 0x0F, 0xC0, 0x1C, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFC, 0x1C, 0x71, 0xC7, 0x00, 0x00, 0x07, 0x1C, 0x71, 0xC7, 0x1C,
|
|
||||||
0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C,
|
|
||||||
0x73, 0xFF, 0xFB, 0xC0, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00,
|
|
||||||
0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x3C, 0xE0, 0x78, 0xE0, 0xF0,
|
|
||||||
0xE1, 0xE0, 0xE3, 0xC0, 0xE7, 0x80, 0xEF, 0x00, 0xEF, 0x80, 0xFF, 0x80,
|
|
||||||
0xFB, 0xC0, 0xF1, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xE0, 0x70, 0xE0, 0x78,
|
|
||||||
0xE0, 0x3C, 0xE0, 0x1C, 0xE0, 0x1E, 0xE0, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xE3, 0xE0, 0xF8, 0xE7, 0xF1, 0xFE,
|
|
||||||
0xEF, 0xFB, 0xFE, 0xF8, 0x7F, 0x0F, 0xF0, 0x3E, 0x07, 0xF0, 0x1C, 0x07,
|
|
||||||
0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07,
|
|
||||||
0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07,
|
|
||||||
0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07,
|
|
||||||
0xE0, 0x1C, 0x07, 0xE3, 0xF1, 0xCF, 0xFB, 0xBF, 0xF7, 0xE1, 0xFF, 0x81,
|
|
||||||
0xFE, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F,
|
|
||||||
0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0,
|
|
||||||
0x1F, 0x80, 0x38, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x87, 0x83, 0xC7,
|
|
||||||
0x80, 0xF3, 0x80, 0x3B, 0x80, 0x1F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01,
|
|
||||||
0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3B, 0x80, 0x39, 0xE0, 0x3C, 0x78,
|
|
||||||
0x3C, 0x3F, 0xFE, 0x0F, 0xFE, 0x01, 0xFC, 0x00, 0xE3, 0xE0, 0xE7, 0xF8,
|
|
||||||
0xEF, 0xFC, 0xFC, 0x3E, 0xF8, 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xE0, 0x07,
|
|
||||||
0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0E,
|
|
||||||
0xF8, 0x1E, 0xFC, 0x3E, 0xFF, 0xFC, 0xEF, 0xF8, 0xE3, 0xE0, 0xE0, 0x00,
|
|
||||||
0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x07, 0xE1,
|
|
||||||
0x8F, 0xFC, 0xCF, 0xFF, 0x67, 0x83, 0xF7, 0x80, 0xFB, 0x80, 0x3F, 0xC0,
|
|
||||||
0x1F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7E,
|
|
||||||
0x00, 0x3B, 0x80, 0x3D, 0xE0, 0x3E, 0xF8, 0x3F, 0x3F, 0xFF, 0x8F, 0xFD,
|
|
||||||
0xC1, 0xF8, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00,
|
|
||||||
0x07, 0x00, 0x03, 0x80, 0xE3, 0xF7, 0xFB, 0xFF, 0x8F, 0x07, 0x83, 0x81,
|
|
||||||
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70,
|
|
||||||
0x38, 0x00, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x3C, 0x1E, 0xE0, 0x3B, 0x80,
|
|
||||||
0x0E, 0x00, 0x3C, 0x00, 0x7F, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x7F, 0x00,
|
|
||||||
0x3F, 0x80, 0x7E, 0x01, 0xFC, 0x1F, 0x7F, 0xF8, 0xFF, 0xC1, 0xFC, 0x00,
|
|
||||||
0x38, 0x70, 0xE1, 0xCF, 0xFF, 0xFF, 0x9C, 0x38, 0x70, 0xE1, 0xC3, 0x87,
|
|
||||||
0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0xE7, 0xC7, 0x80, 0xE0, 0x0F, 0xC0,
|
|
||||||
0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07,
|
|
||||||
0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x03, 0xFC,
|
|
||||||
0x0F, 0xFC, 0x3F, 0x7F, 0xEE, 0xFF, 0x9C, 0x7E, 0x38, 0x70, 0x03, 0xB8,
|
|
||||||
0x03, 0x9C, 0x01, 0xC7, 0x00, 0xE3, 0x80, 0xE1, 0xC0, 0x70, 0x70, 0x38,
|
|
||||||
0x38, 0x38, 0x1C, 0x1C, 0x07, 0x0E, 0x03, 0x8E, 0x01, 0xC7, 0x00, 0x77,
|
|
||||||
0x00, 0x3B, 0x80, 0x1D, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00,
|
|
||||||
0x70, 0x00, 0xF0, 0x1C, 0x03, 0xB8, 0x1F, 0x03, 0xDC, 0x0F, 0x81, 0xCE,
|
|
||||||
0x07, 0xC0, 0xE7, 0x83, 0xE0, 0x71, 0xC3, 0xB8, 0x70, 0xE1, 0xDC, 0x38,
|
|
||||||
0x70, 0xEE, 0x1C, 0x1C, 0x63, 0x0E, 0x0E, 0x71, 0xCE, 0x07, 0x38, 0xE7,
|
|
||||||
0x03, 0x9C, 0x73, 0x80, 0xEC, 0x19, 0x80, 0x7E, 0x0F, 0xC0, 0x3F, 0x07,
|
|
||||||
0xE0, 0x0F, 0x83, 0xF0, 0x07, 0x80, 0xF0, 0x03, 0xC0, 0x78, 0x01, 0xE0,
|
|
||||||
0x3C, 0x00, 0x70, 0x07, 0x38, 0x0E, 0x3C, 0x1C, 0x1C, 0x1C, 0x0E, 0x38,
|
|
||||||
0x0F, 0x70, 0x07, 0x70, 0x03, 0xE0, 0x03, 0xC0, 0x01, 0xC0, 0x03, 0xE0,
|
|
||||||
0x07, 0xE0, 0x07, 0x70, 0x0E, 0x78, 0x1E, 0x38, 0x1C, 0x1C, 0x38, 0x1E,
|
|
||||||
0x78, 0x0E, 0x70, 0x07, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xC7, 0x01,
|
|
||||||
0xC3, 0x80, 0xE1, 0xC0, 0x70, 0x70, 0x70, 0x38, 0x38, 0x1C, 0x3C, 0x07,
|
|
||||||
0x1C, 0x03, 0x8E, 0x01, 0xCE, 0x00, 0x77, 0x00, 0x3B, 0x80, 0x1F, 0x80,
|
|
||||||
0x07, 0xC0, 0x03, 0xE0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x38,
|
|
||||||
0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x0F,
|
|
||||||
0x00, 0x00, 0x7F, 0xFC, 0xFF, 0xF9, 0xFF, 0xF0, 0x00, 0xE0, 0x03, 0x80,
|
|
||||||
0x0E, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x1C, 0x00, 0x70,
|
|
||||||
0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xF8, 0x07, 0x0F, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
|
|
||||||
0x1C, 0x1C, 0x1C, 0x1C, 0x38, 0xF8, 0xE0, 0xF8, 0x38, 0x1C, 0x1C, 0x1C,
|
|
||||||
0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x0F, 0x07, 0xFF,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0xF0, 0xF8, 0x38,
|
|
||||||
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x1C, 0x1F,
|
|
||||||
0x07, 0x1F, 0x1C, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
|
|
||||||
0x38, 0x38, 0xF8, 0xF0, 0xE0, 0x38, 0x00, 0xFC, 0x03, 0xFC, 0x1F, 0x3E,
|
|
||||||
0x3C, 0x1F, 0xE0, 0x1F, 0x80, 0x1E, 0x00};
|
|
||||||
|
|
||||||
const GFXglyph FreeSans18pt7bGlyphs[] PROGMEM = {
|
|
||||||
{0, 0, 0, 9, 0, 1}, // 0x20 ' '
|
|
||||||
{0, 3, 26, 12, 4, -25}, // 0x21 '!'
|
|
||||||
{10, 9, 9, 12, 1, -24}, // 0x22 '"'
|
|
||||||
{21, 19, 24, 19, 0, -23}, // 0x23 '#'
|
|
||||||
{78, 16, 30, 19, 2, -26}, // 0x24 '$'
|
|
||||||
{138, 29, 25, 31, 1, -24}, // 0x25 '%'
|
|
||||||
{229, 20, 25, 23, 2, -24}, // 0x26 '&'
|
|
||||||
{292, 3, 9, 7, 2, -24}, // 0x27 '''
|
|
||||||
{296, 8, 33, 12, 3, -25}, // 0x28 '('
|
|
||||||
{329, 8, 33, 12, 1, -25}, // 0x29 ')'
|
|
||||||
{362, 10, 10, 14, 2, -25}, // 0x2A '*'
|
|
||||||
{375, 16, 16, 20, 2, -15}, // 0x2B '+'
|
|
||||||
{407, 3, 9, 10, 3, -3}, // 0x2C ','
|
|
||||||
{411, 8, 3, 12, 2, -10}, // 0x2D '-'
|
|
||||||
{414, 3, 4, 9, 3, -3}, // 0x2E '.'
|
|
||||||
{416, 10, 26, 10, 0, -25}, // 0x2F '/'
|
|
||||||
{449, 16, 25, 19, 2, -24}, // 0x30 '0'
|
|
||||||
{499, 8, 25, 19, 4, -24}, // 0x31 '1'
|
|
||||||
{524, 16, 25, 19, 2, -24}, // 0x32 '2'
|
|
||||||
{574, 17, 25, 19, 1, -24}, // 0x33 '3'
|
|
||||||
{628, 16, 25, 19, 1, -24}, // 0x34 '4'
|
|
||||||
{678, 17, 25, 19, 1, -24}, // 0x35 '5'
|
|
||||||
{732, 16, 25, 19, 2, -24}, // 0x36 '6'
|
|
||||||
{782, 16, 25, 19, 2, -24}, // 0x37 '7'
|
|
||||||
{832, 17, 25, 19, 1, -24}, // 0x38 '8'
|
|
||||||
{886, 16, 25, 19, 1, -24}, // 0x39 '9'
|
|
||||||
{936, 3, 19, 9, 3, -18}, // 0x3A ':'
|
|
||||||
{944, 3, 24, 9, 3, -18}, // 0x3B ';'
|
|
||||||
{953, 17, 17, 20, 2, -16}, // 0x3C '<'
|
|
||||||
{990, 17, 9, 20, 2, -12}, // 0x3D '='
|
|
||||||
{1010, 17, 17, 20, 2, -16}, // 0x3E '>'
|
|
||||||
{1047, 15, 26, 19, 3, -25}, // 0x3F '?'
|
|
||||||
{1096, 32, 31, 36, 1, -25}, // 0x40 '@'
|
|
||||||
{1220, 22, 26, 23, 1, -25}, // 0x41 'A'
|
|
||||||
{1292, 19, 26, 23, 3, -25}, // 0x42 'B'
|
|
||||||
{1354, 22, 26, 25, 1, -25}, // 0x43 'C'
|
|
||||||
{1426, 20, 26, 24, 3, -25}, // 0x44 'D'
|
|
||||||
{1491, 18, 26, 22, 3, -25}, // 0x45 'E'
|
|
||||||
{1550, 17, 26, 21, 3, -25}, // 0x46 'F'
|
|
||||||
{1606, 24, 26, 27, 1, -25}, // 0x47 'G'
|
|
||||||
{1684, 19, 26, 25, 3, -25}, // 0x48 'H'
|
|
||||||
{1746, 3, 26, 10, 4, -25}, // 0x49 'I'
|
|
||||||
{1756, 14, 26, 18, 1, -25}, // 0x4A 'J'
|
|
||||||
{1802, 20, 26, 24, 3, -25}, // 0x4B 'K'
|
|
||||||
{1867, 15, 26, 20, 3, -25}, // 0x4C 'L'
|
|
||||||
{1916, 24, 26, 30, 3, -25}, // 0x4D 'M'
|
|
||||||
{1994, 20, 26, 26, 3, -25}, // 0x4E 'N'
|
|
||||||
{2059, 25, 26, 27, 1, -25}, // 0x4F 'O'
|
|
||||||
{2141, 18, 26, 23, 3, -25}, // 0x50 'P'
|
|
||||||
{2200, 25, 28, 27, 1, -25}, // 0x51 'Q'
|
|
||||||
{2288, 20, 26, 25, 3, -25}, // 0x52 'R'
|
|
||||||
{2353, 20, 26, 23, 1, -25}, // 0x53 'S'
|
|
||||||
{2418, 19, 26, 22, 1, -25}, // 0x54 'T'
|
|
||||||
{2480, 19, 26, 25, 3, -25}, // 0x55 'U'
|
|
||||||
{2542, 21, 26, 23, 1, -25}, // 0x56 'V'
|
|
||||||
{2611, 32, 26, 33, 0, -25}, // 0x57 'W'
|
|
||||||
{2715, 21, 26, 23, 1, -25}, // 0x58 'X'
|
|
||||||
{2784, 23, 26, 24, 0, -25}, // 0x59 'Y'
|
|
||||||
{2859, 19, 26, 22, 1, -25}, // 0x5A 'Z'
|
|
||||||
{2921, 6, 33, 10, 2, -25}, // 0x5B '['
|
|
||||||
{2946, 10, 26, 10, 0, -25}, // 0x5C '\'
|
|
||||||
{2979, 6, 33, 10, 1, -25}, // 0x5D ']'
|
|
||||||
{3004, 13, 13, 16, 2, -24}, // 0x5E '^'
|
|
||||||
{3026, 21, 2, 19, -1, 5}, // 0x5F '_'
|
|
||||||
{3032, 7, 5, 9, 1, -25}, // 0x60 '`'
|
|
||||||
{3037, 17, 19, 19, 1, -18}, // 0x61 'a'
|
|
||||||
{3078, 16, 26, 20, 2, -25}, // 0x62 'b'
|
|
||||||
{3130, 16, 19, 18, 1, -18}, // 0x63 'c'
|
|
||||||
{3168, 17, 26, 20, 1, -25}, // 0x64 'd'
|
|
||||||
{3224, 16, 19, 19, 1, -18}, // 0x65 'e'
|
|
||||||
{3262, 7, 26, 10, 1, -25}, // 0x66 'f'
|
|
||||||
{3285, 16, 27, 19, 1, -18}, // 0x67 'g'
|
|
||||||
{3339, 15, 26, 19, 2, -25}, // 0x68 'h'
|
|
||||||
{3388, 3, 26, 8, 2, -25}, // 0x69 'i'
|
|
||||||
{3398, 6, 34, 9, 0, -25}, // 0x6A 'j'
|
|
||||||
{3424, 16, 26, 18, 2, -25}, // 0x6B 'k'
|
|
||||||
{3476, 3, 26, 7, 2, -25}, // 0x6C 'l'
|
|
||||||
{3486, 24, 19, 28, 2, -18}, // 0x6D 'm'
|
|
||||||
{3543, 15, 19, 19, 2, -18}, // 0x6E 'n'
|
|
||||||
{3579, 17, 19, 19, 1, -18}, // 0x6F 'o'
|
|
||||||
{3620, 16, 25, 20, 2, -18}, // 0x70 'p'
|
|
||||||
{3670, 17, 25, 20, 1, -18}, // 0x71 'q'
|
|
||||||
{3724, 9, 19, 12, 2, -18}, // 0x72 'r'
|
|
||||||
{3746, 14, 19, 17, 2, -18}, // 0x73 's'
|
|
||||||
{3780, 7, 23, 10, 1, -22}, // 0x74 't'
|
|
||||||
{3801, 15, 19, 19, 2, -18}, // 0x75 'u'
|
|
||||||
{3837, 17, 19, 17, 0, -18}, // 0x76 'v'
|
|
||||||
{3878, 25, 19, 25, 0, -18}, // 0x77 'w'
|
|
||||||
{3938, 16, 19, 17, 0, -18}, // 0x78 'x'
|
|
||||||
{3976, 17, 27, 17, 0, -18}, // 0x79 'y'
|
|
||||||
{4034, 15, 19, 17, 1, -18}, // 0x7A 'z'
|
|
||||||
{4070, 8, 33, 12, 1, -25}, // 0x7B '{'
|
|
||||||
{4103, 2, 33, 9, 3, -25}, // 0x7C '|'
|
|
||||||
{4112, 8, 33, 12, 3, -25}, // 0x7D '}'
|
|
||||||
{4145, 15, 7, 18, 1, -15}}; // 0x7E '~'
|
|
||||||
|
|
||||||
const GFXfont FreeSans18pt7b PROGMEM = {(uint8_t *)FreeSans18pt7bBitmaps,
|
|
||||||
(GFXglyph *)FreeSans18pt7bGlyphs, 0x20,
|
|
||||||
0x7E, 42};
|
|
||||||
|
|
||||||
// Approx. 4831 bytes
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,421 +0,0 @@
|
||||||
const uint8_t FreeSans9pt8bBitmaps[] PROGMEM = {
|
|
||||||
0x00, 0xFF, 0xFF, 0x83, 0xC0, 0xDD, 0xD9, 0x90, 0x09, 0x82, 0x61, 0x90,
|
|
||||||
0x64, 0x7F, 0xC4, 0xC1, 0x30, 0xC8, 0xFF, 0xBF, 0xE2, 0x20, 0x98, 0x26,
|
|
||||||
0x00, 0x10, 0x3C, 0x76, 0xD3, 0x93, 0xD0, 0xF0, 0x7C, 0x17, 0x13, 0x91,
|
|
||||||
0x91, 0xD3, 0x7E, 0x10, 0x10, 0x00, 0x21, 0xE1, 0x08, 0x84, 0x23, 0x20,
|
|
||||||
0x8C, 0x83, 0x64, 0x07, 0x10, 0x00, 0x8E, 0x06, 0x6C, 0x13, 0x10, 0xCC,
|
|
||||||
0x42, 0x11, 0x18, 0x78, 0x1C, 0x0F, 0x86, 0x21, 0x88, 0x36, 0x0F, 0x03,
|
|
||||||
0x81, 0xB2, 0xC6, 0xA0, 0xEC, 0x13, 0x1E, 0x7C, 0xC0, 0xFE, 0x80, 0x12,
|
|
||||||
0x26, 0x44, 0xCC, 0xCC, 0x44, 0x46, 0x22, 0x10, 0x84, 0x46, 0x22, 0x23,
|
|
||||||
0x33, 0x22, 0x26, 0x4C, 0x80, 0x25, 0x5C, 0xA5, 0x00, 0x08, 0x04, 0x02,
|
|
||||||
0x01, 0x0F, 0xF8, 0x40, 0x20, 0x10, 0x08, 0x00, 0xF0, 0xFF, 0xC0, 0x08,
|
|
||||||
0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, 0x18, 0x7E, 0x42, 0xC3,
|
|
||||||
0xC3, 0x83, 0x83, 0x83, 0x83, 0xC3, 0xC3, 0x46, 0x7C, 0x11, 0x7F, 0x11,
|
|
||||||
0x11, 0x11, 0x11, 0x10, 0x3C, 0x7E, 0xC3, 0xC1, 0x81, 0x03, 0x06, 0x1C,
|
|
||||||
0x30, 0x60, 0xC0, 0xFF, 0xFF, 0x3C, 0x7E, 0xC3, 0xC3, 0x03, 0x06, 0x1C,
|
|
||||||
0x03, 0x03, 0x83, 0x83, 0xC3, 0x7E, 0x02, 0x03, 0x01, 0x81, 0x41, 0xA1,
|
|
||||||
0x90, 0x88, 0xC4, 0xC2, 0x7F, 0xC0, 0x80, 0x40, 0x20, 0x7F, 0x7F, 0x40,
|
|
||||||
0x40, 0xC0, 0xFE, 0xC3, 0x03, 0x01, 0x01, 0x83, 0xC3, 0x7E, 0x1C, 0x7E,
|
|
||||||
0x43, 0xC3, 0xC0, 0xBC, 0xFE, 0xC3, 0xC1, 0xC1, 0xC3, 0x63, 0x7E, 0xFF,
|
|
||||||
0xFF, 0x03, 0x02, 0x04, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x30, 0x20, 0x20,
|
|
||||||
0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0x66, 0x7C, 0xC3, 0x83, 0x81, 0x83, 0xC3,
|
|
||||||
0x7E, 0x38, 0x7E, 0xC2, 0x83, 0x83, 0x83, 0xC3, 0x7D, 0x13, 0x03, 0xC3,
|
|
||||||
0xC6, 0x7C, 0xC0, 0x03, 0xC0, 0xC0, 0x03, 0xD6, 0x00, 0x01, 0xC3, 0x8F,
|
|
||||||
0x0C, 0x07, 0x00, 0xF0, 0x0E, 0x01, 0x80, 0xFF, 0x80, 0x00, 0x1F, 0xF0,
|
|
||||||
0x00, 0x60, 0x1E, 0x01, 0xC0, 0x38, 0x3C, 0x71, 0xE0, 0x80, 0x00, 0x3E,
|
|
||||||
0x63, 0x43, 0xC1, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18,
|
|
||||||
0x07, 0xF0, 0x1C, 0x1C, 0x30, 0x0E, 0x60, 0x06, 0x43, 0xD3, 0xC6, 0x33,
|
|
||||||
0x8C, 0x31, 0x8C, 0x23, 0x88, 0x23, 0x8C, 0x62, 0xCC, 0xEC, 0xC7, 0x38,
|
|
||||||
0x60, 0x00, 0x38, 0x00, 0x0F, 0xF0, 0x01, 0x80, 0x06, 0x00, 0xF0, 0x0F,
|
|
||||||
0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x06, 0x60,
|
|
||||||
0x66, 0x06, 0xC0, 0x30, 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xB0, 0xEF,
|
|
||||||
0xFB, 0x03, 0xC0, 0xF0, 0x1C, 0x0F, 0x07, 0xFF, 0x00, 0x1F, 0x86, 0x19,
|
|
||||||
0x81, 0xE0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x78, 0x0D, 0x81,
|
|
||||||
0xB8, 0x63, 0xF8, 0xFE, 0x20, 0xC8, 0x1A, 0x03, 0x80, 0xE0, 0x38, 0x0E,
|
|
||||||
0x03, 0x80, 0xE0, 0x38, 0x1A, 0x1C, 0xFE, 0x00, 0xFF, 0xC0, 0x20, 0x10,
|
|
||||||
0x08, 0x04, 0x03, 0xFD, 0x00, 0x80, 0x40, 0x20, 0x10, 0x0F, 0xF8, 0xFF,
|
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
||||||
0x1F, 0x83, 0x0E, 0x60, 0x6C, 0x03, 0xC0, 0x0C, 0x00, 0x83, 0xFC, 0x3F,
|
|
||||||
0xC0, 0x3C, 0x03, 0x60, 0x77, 0x0F, 0x1F, 0x90, 0xC0, 0x78, 0x0F, 0x01,
|
|
||||||
0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0,
|
|
||||||
0x3C, 0x06, 0xFF, 0xF8, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
||||||
0x03, 0xC3, 0xC3, 0x66, 0x7E, 0xC0, 0xD8, 0x33, 0x0C, 0x63, 0x0C, 0xC1,
|
|
||||||
0xB8, 0x3F, 0x07, 0x30, 0xC3, 0x18, 0x63, 0x06, 0x60, 0x6C, 0x04, 0xC0,
|
|
||||||
0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18,
|
|
||||||
0x0F, 0xF8, 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F,
|
|
||||||
0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80,
|
|
||||||
0xE0, 0x7C, 0x0F, 0xC1, 0xEC, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3,
|
|
||||||
0x78, 0x2F, 0x07, 0xE0, 0x7C, 0x0E, 0x1F, 0x87, 0x0E, 0x60, 0x6C, 0x03,
|
|
||||||
0xC0, 0x38, 0x01, 0x80, 0x18, 0x01, 0xC0, 0x3C, 0x03, 0x60, 0x67, 0x0E,
|
|
||||||
0x1F, 0x80, 0xFF, 0x41, 0xE0, 0x70, 0x38, 0x1C, 0x0F, 0xFD, 0x00, 0x80,
|
|
||||||
0x40, 0x20, 0x10, 0x08, 0x00, 0x1F, 0x87, 0x0E, 0x60, 0x6C, 0x03, 0xC0,
|
|
||||||
0x38, 0x01, 0x80, 0x18, 0x01, 0xC0, 0x3C, 0x03, 0x61, 0xE7, 0x0E, 0x1F,
|
|
||||||
0xF0, 0x01, 0xFF, 0x20, 0x68, 0x0E, 0x03, 0x80, 0xE0, 0x6F, 0xF2, 0x06,
|
|
||||||
0x80, 0xA0, 0x28, 0x0A, 0x03, 0x80, 0xC0, 0x3F, 0x18, 0x6C, 0x0F, 0x03,
|
|
||||||
0xC0, 0x1E, 0x01, 0xF0, 0x0F, 0x00, 0xF0, 0x3C, 0x0D, 0x87, 0x3F, 0x80,
|
|
||||||
0xFF, 0xE0, 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04,
|
|
||||||
0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80,
|
|
||||||
0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3C, 0x0B, 0x86, 0x7F, 0x00, 0xC0,
|
|
||||||
0x58, 0x1B, 0x03, 0x30, 0x46, 0x18, 0x43, 0x0C, 0x41, 0x98, 0x13, 0x03,
|
|
||||||
0x40, 0x78, 0x07, 0x00, 0xC0, 0x41, 0xC1, 0xB0, 0xE1, 0x98, 0x50, 0xCC,
|
|
||||||
0x28, 0x62, 0x36, 0x31, 0x9B, 0x10, 0xC8, 0x98, 0x64, 0x6C, 0x16, 0x36,
|
|
||||||
0x0B, 0x0A, 0x07, 0x07, 0x03, 0x83, 0x80, 0xC1, 0xC0, 0x60, 0x63, 0x0C,
|
|
||||||
0x30, 0xC1, 0x98, 0x0F, 0x00, 0x70, 0x06, 0x00, 0xF0, 0x09, 0x81, 0x98,
|
|
||||||
0x30, 0xC6, 0x06, 0x60, 0x60, 0x60, 0x36, 0x06, 0x30, 0xC1, 0x0C, 0x19,
|
|
||||||
0x80, 0xD0, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06,
|
|
||||||
0x00, 0x7F, 0xC0, 0x18, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x80, 0x60,
|
|
||||||
0x18, 0x06, 0x01, 0x80, 0x30, 0x0F, 0xFE, 0xFC, 0xCC, 0xCC, 0xCC, 0xCC,
|
|
||||||
0xCC, 0xCC, 0xCC, 0xF0, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10,
|
|
||||||
0x80, 0xF3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xF0, 0x30, 0x60,
|
|
||||||
0xA2, 0x44, 0xD8, 0xA1, 0x00, 0xFF, 0xC0, 0x63, 0x3C, 0x3F, 0x30, 0x80,
|
|
||||||
0x60, 0x73, 0xFB, 0x0D, 0x06, 0xC7, 0x7D, 0xC0, 0x80, 0x80, 0x80, 0x9C,
|
|
||||||
0xBE, 0xC3, 0xC1, 0xC1, 0x81, 0xC1, 0xC3, 0xE3, 0xBE, 0x38, 0x7E, 0xC2,
|
|
||||||
0x82, 0x80, 0x80, 0x80, 0x82, 0xC6, 0x7C, 0x01, 0x80, 0xC0, 0x63, 0xB3,
|
|
||||||
0xFB, 0x0D, 0x06, 0x83, 0xC1, 0xA0, 0xD0, 0x6C, 0x73, 0xE8, 0x18, 0x7E,
|
|
||||||
0xC3, 0xC3, 0x81, 0xFF, 0x80, 0xC3, 0xC3, 0x7E, 0x39, 0x08, 0x4F, 0x90,
|
|
||||||
0x84, 0x21, 0x08, 0x42, 0x00, 0x38, 0x7F, 0xC7, 0x83, 0x83, 0x83, 0x83,
|
|
||||||
0x83, 0xC7, 0x7F, 0x03, 0x82, 0xE6, 0x7C, 0xC0, 0xC0, 0xC0, 0xDC, 0xFE,
|
|
||||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xF0, 0xFF, 0xFF, 0xC0,
|
|
||||||
0x6C, 0x06, 0xDB, 0x6D, 0xB6, 0xDB, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC6,
|
|
||||||
0xCC, 0xD8, 0xF8, 0xD8, 0xCC, 0xC4, 0xC6, 0xC3, 0xFF, 0xFF, 0xFF, 0xC0,
|
|
||||||
0x1C, 0x67, 0xFF, 0xB0, 0xC7, 0x84, 0x3C, 0x21, 0xE1, 0x0F, 0x08, 0x78,
|
|
||||||
0x43, 0xC2, 0x1E, 0x10, 0xC0, 0x1C, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC3, 0x38, 0x7E, 0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6,
|
|
||||||
0x7E, 0x1C, 0xBE, 0xC3, 0xC1, 0xC1, 0x81, 0xC1, 0xC3, 0xE3, 0xBE, 0x80,
|
|
||||||
0x80, 0x80, 0x80, 0x1C, 0x1F, 0x58, 0x68, 0x34, 0x1E, 0x0D, 0x06, 0x83,
|
|
||||||
0x63, 0x9F, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x1F, 0xF9, 0x8C, 0x63, 0x18,
|
|
||||||
0xC6, 0x00, 0x39, 0xFB, 0x1C, 0x0E, 0x07, 0x81, 0xC1, 0xC7, 0xF8, 0x21,
|
|
||||||
0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, 0x70, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC7, 0x7F, 0x41, 0x31, 0x98, 0xC4, 0x42, 0x61, 0xA0, 0x50,
|
|
||||||
0x38, 0x18, 0x00, 0xC7, 0x12, 0x38, 0x99, 0x4C, 0xCA, 0x62, 0xDA, 0x14,
|
|
||||||
0xD0, 0xE3, 0x87, 0x18, 0x18, 0xC0, 0x63, 0x13, 0x0D, 0x03, 0x81, 0xC0,
|
|
||||||
0xE0, 0xD8, 0xC6, 0x43, 0x00, 0x41, 0x31, 0x98, 0xC4, 0x43, 0x61, 0xA0,
|
|
||||||
0x50, 0x38, 0x18, 0x0C, 0x06, 0x0E, 0x06, 0x00, 0xFE, 0x08, 0x30, 0xC3,
|
|
||||||
0x0C, 0x10, 0x60, 0xFE, 0x36, 0x66, 0x66, 0x4C, 0x84, 0x66, 0x66, 0x66,
|
|
||||||
0x30, 0xFF, 0xFF, 0x80, 0xC4, 0x44, 0x44, 0x46, 0x36, 0x44, 0x44, 0x44,
|
|
||||||
0x80, 0x60, 0x59, 0x8F, 0xFF, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03,
|
|
||||||
0x01, 0x80, 0xC0, 0x60, 0x30, 0x1F, 0xF8, 0x00, 0xF0, 0x7F, 0xFF, 0xC0,
|
|
||||||
0x08, 0x1C, 0x7E, 0x4B, 0xC9, 0xC8, 0xC8, 0xC8, 0xCB, 0x6B, 0x3E, 0x08,
|
|
||||||
0x08, 0x1F, 0x0C, 0xE6, 0x19, 0x82, 0x60, 0x08, 0x0F, 0xE0, 0x40, 0x10,
|
|
||||||
0x04, 0x03, 0x01, 0xF2, 0x7F, 0xC0, 0x07, 0x07, 0xF3, 0x04, 0x80, 0x60,
|
|
||||||
0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x18, 0x03, 0x00, 0x61, 0x0F, 0xC0, 0xC0,
|
|
||||||
0xD0, 0x22, 0x18, 0xCC, 0x12, 0x07, 0x80, 0xC1, 0xFE, 0x0C, 0x1F, 0xE0,
|
|
||||||
0xC0, 0x30, 0x0C, 0x00, 0x12, 0x07, 0x80, 0xC0, 0x00, 0x3F, 0x18, 0x6C,
|
|
||||||
0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0F, 0x00, 0xF0, 0x3C, 0x0D, 0x87,
|
|
||||||
0x3F, 0x80, 0x3C, 0x66, 0x62, 0x62, 0x30, 0x5C, 0x8E, 0x83, 0xC1, 0x61,
|
|
||||||
0x3B, 0x1E, 0x06, 0xC6, 0x46, 0x7E, 0x38, 0x6C, 0x70, 0x41, 0xCF, 0xD8,
|
|
||||||
0xE0, 0x70, 0x3C, 0x0E, 0x0E, 0x3F, 0xC0, 0x1F, 0xC0, 0xC1, 0x86, 0x31,
|
|
||||||
0x33, 0x66, 0x88, 0xCA, 0x60, 0x29, 0x80, 0xE6, 0x12, 0x88, 0xCB, 0x36,
|
|
||||||
0x66, 0x71, 0x0C, 0x18, 0x1F, 0xC0, 0xF4, 0x9D, 0x29, 0x74, 0x1F, 0x21,
|
|
||||||
0x99, 0xA6, 0x4C, 0x90, 0xFF, 0xFF, 0xC0, 0x20, 0x10, 0x08, 0xFF, 0x1F,
|
|
||||||
0xC0, 0xC1, 0x86, 0xF1, 0x33, 0xF6, 0x88, 0x4A, 0x23, 0x28, 0xF8, 0xE2,
|
|
||||||
0x32, 0x88, 0xCB, 0x23, 0x66, 0x01, 0x0C, 0x18, 0x1F, 0xC0, 0xFF, 0xC0,
|
|
||||||
0xF4, 0x63, 0x17, 0x00, 0x08, 0x04, 0x02, 0x01, 0x0F, 0xF8, 0x40, 0x20,
|
|
||||||
0x10, 0x08, 0x00, 0x3F, 0xE0, 0x39, 0x34, 0x43, 0x19, 0x84, 0x3F, 0x31,
|
|
||||||
0x2C, 0xC6, 0x08, 0x1C, 0xDE, 0x11, 0x01, 0x60, 0x18, 0x00, 0x07, 0xFC,
|
|
||||||
0x01, 0x80, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x06, 0x01, 0x80, 0x60,
|
|
||||||
0x18, 0x03, 0x00, 0xFF, 0xE0, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B,
|
|
||||||
0x0D, 0x8E, 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x00, 0x3F, 0x7A, 0xFA, 0xFA,
|
|
||||||
0xFA, 0xFA, 0xFA, 0x7A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
|
||||||
0xC0, 0x6C, 0x50, 0x40, 0x0F, 0xE0, 0x83, 0x0C, 0x30, 0xC1, 0x06, 0x0F,
|
|
||||||
0xE0, 0x27, 0x92, 0x49, 0xF4, 0x63, 0x19, 0x38, 0x1F, 0x93, 0x26, 0x59,
|
|
||||||
0x98, 0x40, 0x3F, 0xFF, 0x71, 0xC0, 0x40, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
|
|
||||||
0x80, 0xC0, 0x80, 0xFF, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x40, 0xC0,
|
|
||||||
0x61, 0xC0, 0x3F, 0xFF, 0x38, 0x30, 0xFD, 0xFB, 0x0E, 0x1C, 0x18, 0x38,
|
|
||||||
0x10, 0x70, 0x3F, 0xE0, 0x40, 0x61, 0x83, 0xC7, 0x84, 0xFD, 0xF8, 0x19,
|
|
||||||
0x81, 0x98, 0x00, 0x06, 0x03, 0x60, 0x63, 0x0C, 0x10, 0xC1, 0x98, 0x0D,
|
|
||||||
0x00, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x18,
|
|
||||||
0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x60, 0xC0, 0x83, 0xC2, 0xC6, 0x7C,
|
|
||||||
0x0C, 0x00, 0x40, 0x02, 0x00, 0x00, 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90,
|
|
||||||
0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x06, 0x60, 0x66, 0x06,
|
|
||||||
0xC0, 0x30, 0x01, 0x80, 0x30, 0x06, 0x00, 0x00, 0x06, 0x00, 0xF0, 0x0F,
|
|
||||||
0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x06, 0x60,
|
|
||||||
0x66, 0x06, 0xC0, 0x30, 0x06, 0x00, 0xF0, 0x09, 0x00, 0x00, 0x06, 0x00,
|
|
||||||
0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2,
|
|
||||||
0x06, 0x60, 0x66, 0x06, 0xC0, 0x30, 0x0C, 0x81, 0x30, 0x00, 0x00, 0x60,
|
|
||||||
0x0F, 0x00, 0xF0, 0x09, 0x01, 0x98, 0x19, 0x81, 0x08, 0x30, 0xC3, 0xFC,
|
|
||||||
0x20, 0x66, 0x06, 0x60, 0x6C, 0x03, 0x19, 0x81, 0x98, 0x00, 0x00, 0x60,
|
|
||||||
0x0F, 0x00, 0xF0, 0x09, 0x01, 0x98, 0x19, 0x81, 0x08, 0x30, 0xC3, 0xFC,
|
|
||||||
0x20, 0x66, 0x06, 0x60, 0x6C, 0x03, 0x0F, 0x00, 0x90, 0x0F, 0x00, 0x00,
|
|
||||||
0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C,
|
|
||||||
0x3F, 0xC2, 0x06, 0x60, 0x66, 0x06, 0xC0, 0x30, 0x07, 0xFF, 0x83, 0x60,
|
|
||||||
0x01, 0x30, 0x01, 0x98, 0x00, 0x8C, 0x00, 0xC6, 0x00, 0x63, 0xFC, 0x61,
|
|
||||||
0x80, 0x3F, 0xC0, 0x10, 0x60, 0x18, 0x30, 0x0C, 0x18, 0x0C, 0x0F, 0xF8,
|
|
||||||
0x1F, 0x86, 0x19, 0x81, 0xE0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0,
|
|
||||||
0x78, 0x0D, 0x81, 0xB8, 0x63, 0xF8, 0x08, 0x01, 0x80, 0x10, 0x0E, 0x00,
|
|
||||||
0x30, 0x08, 0x02, 0x00, 0x0F, 0xFC, 0x02, 0x01, 0x00, 0x80, 0x40, 0x3F,
|
|
||||||
0xD0, 0x08, 0x04, 0x02, 0x01, 0x00, 0xFF, 0x80, 0x04, 0x04, 0x04, 0x00,
|
|
||||||
0x0F, 0xFC, 0x02, 0x01, 0x00, 0x80, 0x40, 0x3F, 0xD0, 0x08, 0x04, 0x02,
|
|
||||||
0x01, 0x00, 0xFF, 0x80, 0x18, 0x0E, 0x09, 0x00, 0x0F, 0xFC, 0x02, 0x01,
|
|
||||||
0x00, 0x80, 0x40, 0x3F, 0xD0, 0x08, 0x04, 0x02, 0x01, 0x00, 0xFF, 0x80,
|
|
||||||
0x66, 0x33, 0x00, 0x1F, 0xF8, 0x04, 0x02, 0x01, 0x00, 0x80, 0x7F, 0xA0,
|
|
||||||
0x10, 0x08, 0x04, 0x02, 0x01, 0xFF, 0xC6, 0x20, 0x22, 0x22, 0x22, 0x22,
|
|
||||||
0x22, 0x22, 0x20, 0x36, 0x40, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x40,
|
|
||||||
0x32, 0xB2, 0x02, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0x84, 0x20, 0xCF,
|
|
||||||
0x30, 0x08, 0x20, 0x82, 0x08, 0x20, 0x82, 0x08, 0x20, 0x82, 0x08, 0x3F,
|
|
||||||
0x82, 0x0C, 0x20, 0x62, 0x03, 0x20, 0x32, 0x03, 0xFC, 0x32, 0x03, 0x20,
|
|
||||||
0x32, 0x03, 0x20, 0x62, 0x1C, 0x3F, 0x80, 0x09, 0x03, 0xE0, 0x00, 0x70,
|
|
||||||
0x3E, 0x07, 0xE0, 0xF6, 0x1E, 0xC3, 0xCC, 0x78, 0x8F, 0x19, 0xE1, 0xBC,
|
|
||||||
0x17, 0x83, 0xF0, 0x3E, 0x07, 0x0C, 0x00, 0x40, 0x02, 0x00, 0x00, 0x1F,
|
|
||||||
0x87, 0x0E, 0x60, 0x6C, 0x03, 0xC0, 0x38, 0x01, 0x80, 0x18, 0x01, 0xC0,
|
|
||||||
0x3C, 0x03, 0x60, 0x67, 0x0E, 0x1F, 0x80, 0x03, 0x00, 0x20, 0x04, 0x00,
|
|
||||||
0x00, 0x1F, 0x87, 0x0E, 0x60, 0x6C, 0x03, 0xC0, 0x38, 0x01, 0x80, 0x18,
|
|
||||||
0x01, 0xC0, 0x3C, 0x03, 0x60, 0x67, 0x0E, 0x1F, 0x80, 0x06, 0x00, 0xF0,
|
|
||||||
0x09, 0x00, 0x00, 0x1F, 0x87, 0x0E, 0x60, 0x6C, 0x03, 0xC0, 0x38, 0x01,
|
|
||||||
0x80, 0x18, 0x01, 0xC0, 0x3C, 0x03, 0x60, 0x67, 0x0E, 0x1F, 0x80, 0x0C,
|
|
||||||
0x81, 0x30, 0x00, 0x01, 0xF8, 0x70, 0xE6, 0x06, 0xC0, 0x3C, 0x03, 0x80,
|
|
||||||
0x18, 0x01, 0x80, 0x1C, 0x03, 0xC0, 0x36, 0x06, 0x70, 0xE1, 0xF8, 0x19,
|
|
||||||
0x81, 0x98, 0x00, 0x01, 0xF8, 0x70, 0xE6, 0x06, 0xC0, 0x3C, 0x03, 0x80,
|
|
||||||
0x18, 0x01, 0x80, 0x1C, 0x03, 0xC0, 0x36, 0x06, 0x70, 0xE1, 0xF8, 0x81,
|
|
||||||
0x89, 0xA1, 0x83, 0x89, 0xA1, 0x80, 0x00, 0x01, 0xF9, 0x70, 0xE6, 0x06,
|
|
||||||
0xC0, 0xBC, 0x13, 0x82, 0x18, 0x41, 0x8C, 0x1D, 0x83, 0xF0, 0x36, 0x06,
|
|
||||||
0x70, 0xE9, 0xF8, 0x30, 0x06, 0x00, 0x80, 0x00, 0x80, 0xE0, 0x38, 0x0E,
|
|
||||||
0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3C, 0x0B, 0x86, 0x7F,
|
|
||||||
0x00, 0x06, 0x03, 0x00, 0x80, 0x00, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80,
|
|
||||||
0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3C, 0x0B, 0x86, 0x7F, 0x00, 0x0C,
|
|
||||||
0x05, 0x03, 0x20, 0x00, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38,
|
|
||||||
0x0E, 0x03, 0x80, 0xE0, 0x3C, 0x0B, 0x86, 0x7F, 0x00, 0x33, 0x0C, 0xC0,
|
|
||||||
0x02, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03,
|
|
||||||
0x80, 0xF0, 0x2E, 0x19, 0xFC, 0x01, 0x00, 0x20, 0x04, 0x00, 0x00, 0x60,
|
|
||||||
0x36, 0x06, 0x30, 0xC1, 0x0C, 0x19, 0x80, 0xD0, 0x0F, 0x00, 0x60, 0x06,
|
|
||||||
0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x80, 0x40, 0x3F, 0x9F, 0xE8,
|
|
||||||
0x1C, 0x0E, 0x07, 0x03, 0xFF, 0x7E, 0x20, 0x10, 0x08, 0x00, 0x3E, 0x31,
|
|
||||||
0xB0, 0x78, 0x3C, 0x16, 0x7B, 0x3D, 0x83, 0xC0, 0xE0, 0x70, 0x78, 0x7C,
|
|
||||||
0xF0, 0x30, 0x0C, 0x02, 0x07, 0x87, 0xE6, 0x10, 0x0C, 0x0E, 0x7F, 0x61,
|
|
||||||
0xA0, 0xD8, 0xEF, 0xB8, 0x0C, 0x0C, 0x04, 0x07, 0x87, 0xE6, 0x10, 0x0C,
|
|
||||||
0x0E, 0x7F, 0x61, 0xA0, 0xD8, 0xEF, 0xB8, 0x18, 0x16, 0x19, 0x07, 0x87,
|
|
||||||
0xE6, 0x10, 0x0C, 0x0E, 0x7F, 0x61, 0xA0, 0xD8, 0xEF, 0xB8, 0x32, 0x3E,
|
|
||||||
0x00, 0x07, 0x87, 0xE6, 0x10, 0x0C, 0x0E, 0x7F, 0x61, 0xA0, 0xD8, 0xEF,
|
|
||||||
0xB8, 0x66, 0x33, 0x00, 0x07, 0x87, 0xE6, 0x10, 0x0C, 0x0E, 0x7F, 0x61,
|
|
||||||
0xA0, 0xD8, 0xEF, 0xB8, 0x18, 0x12, 0x09, 0x03, 0x03, 0xC3, 0xF3, 0x08,
|
|
||||||
0x06, 0x07, 0x3F, 0xB0, 0xD0, 0x6C, 0x77, 0xDC, 0x38, 0x71, 0xFF, 0xEC,
|
|
||||||
0x30, 0xC0, 0xC1, 0x06, 0x05, 0xFF, 0xFC, 0x20, 0x20, 0xC1, 0xC7, 0x8F,
|
|
||||||
0xE7, 0xE0, 0x38, 0x7E, 0xC2, 0x82, 0x80, 0x80, 0x80, 0x83, 0xC6, 0x7C,
|
|
||||||
0x10, 0x18, 0x08, 0x78, 0x30, 0x18, 0x08, 0x18, 0x7E, 0xC3, 0xC3, 0x81,
|
|
||||||
0xFF, 0x80, 0xC3, 0xC3, 0x7E, 0x0C, 0x18, 0x10, 0x18, 0x7E, 0xC3, 0xC3,
|
|
||||||
0x81, 0xFF, 0x80, 0xC3, 0xC3, 0x7E, 0x18, 0x34, 0x22, 0x18, 0x7E, 0xC3,
|
|
||||||
0xC3, 0x81, 0xFF, 0x80, 0xC3, 0xC3, 0x7E, 0x66, 0x66, 0x00, 0x18, 0x7E,
|
|
||||||
0xC3, 0xC3, 0x81, 0xFF, 0x80, 0xC3, 0xC3, 0x7E, 0x42, 0x10, 0x22, 0x22,
|
|
||||||
0x22, 0x22, 0x20, 0x6C, 0x80, 0x44, 0x44, 0x44, 0x44, 0x40, 0x72, 0xA2,
|
|
||||||
0x02, 0x10, 0x84, 0x21, 0x08, 0x42, 0x00, 0xCF, 0x30, 0x00, 0x10, 0x41,
|
|
||||||
0x04, 0x10, 0x41, 0x04, 0x10, 0x6C, 0x30, 0x4C, 0x3E, 0x7E, 0xC3, 0x83,
|
|
||||||
0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E, 0x32, 0x7C, 0x00, 0x1C, 0xFE, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x30, 0x10, 0x08, 0x38, 0x7E,
|
|
||||||
0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E, 0x0C, 0x18, 0x10, 0x38,
|
|
||||||
0x7E, 0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E, 0x18, 0x2C, 0x64,
|
|
||||||
0x38, 0x7E, 0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E, 0x32, 0x5C,
|
|
||||||
0x00, 0x38, 0x7E, 0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E, 0x66,
|
|
||||||
0x66, 0x00, 0x38, 0x7E, 0xC3, 0x83, 0x81, 0x81, 0x81, 0xC3, 0xC6, 0x7E,
|
|
||||||
0x18, 0x0C, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x30, 0x18, 0x00, 0x1C,
|
|
||||||
0x0F, 0xE6, 0x19, 0x8E, 0x44, 0x92, 0x25, 0x09, 0xC6, 0x63, 0x1F, 0xC0,
|
|
||||||
0x00, 0x30, 0x10, 0x08, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC7, 0x7F, 0x0C, 0x18, 0x10, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC7, 0x7F, 0x18, 0x2C, 0x64, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC7, 0x7F, 0x66, 0x66, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC3, 0xC7, 0x7F, 0x0C, 0x04, 0x04, 0x00, 0x04, 0x13, 0x19,
|
|
||||||
0x8C, 0x44, 0x36, 0x1A, 0x05, 0x03, 0x81, 0x80, 0xC0, 0x60, 0xE0, 0x60,
|
|
||||||
0x00, 0x80, 0x80, 0x80, 0x9C, 0xBE, 0xC3, 0xC1, 0xC1, 0x81, 0xC1, 0xC3,
|
|
||||||
0xE3, 0xBE, 0x80, 0x80, 0x80, 0x80, 0x22, 0x11, 0x00, 0x00, 0x04, 0x13,
|
|
||||||
0x19, 0x8C, 0x44, 0x36, 0x1A, 0x05, 0x03, 0x81, 0x80, 0xC0, 0x60, 0xE0,
|
|
||||||
0x60, 0x00 };
|
|
||||||
|
|
||||||
const GFXglyph FreeSans9pt8bGlyphs[] PROGMEM = {
|
|
||||||
{ 0, 1, 1, 5, 0, 0 }, // 0x20 ' ' U+0020
|
|
||||||
{ 1, 2, 13, 5, 2, -12 }, // 0x21 '!' U+0021
|
|
||||||
{ 5, 4, 5, 6, 1, -12 }, // 0x22 '"' U+0022
|
|
||||||
{ 8, 10, 13, 10, 0, -12 }, // 0x23 '#' U+0023
|
|
||||||
{ 25, 8, 16, 10, 1, -13 }, // 0x24 '$' U+0024
|
|
||||||
{ 41, 14, 13, 16, 1, -12 }, // 0x25 '%' U+0025
|
|
||||||
{ 64, 10, 13, 12, 1, -12 }, // 0x26 '&' U+0026
|
|
||||||
{ 81, 2, 5, 3, 1, -12 }, // 0x27 ''' U+0027
|
|
||||||
{ 83, 4, 17, 6, 1, -12 }, // 0x28 '(' U+0028
|
|
||||||
{ 92, 4, 17, 6, 1, -12 }, // 0x29 ')' U+0029
|
|
||||||
{ 101, 5, 5, 7, 1, -12 }, // 0x2a '*' U+002A
|
|
||||||
{ 105, 9, 9, 11, 1, -8 }, // 0x2b '+' U+002B
|
|
||||||
{ 116, 1, 5, 5, 2, -1 }, // 0x2c ',' U+002C
|
|
||||||
{ 117, 4, 2, 6, 1, -5 }, // 0x2d '-' U+002D
|
|
||||||
{ 118, 1, 2, 5, 2, -1 }, // 0x2e '.' U+002E
|
|
||||||
{ 119, 5, 13, 5, 0, -12 }, // 0x2f '/' U+002F
|
|
||||||
{ 128, 8, 13, 10, 1, -12 }, // 0x30 '0' U+0030
|
|
||||||
{ 141, 4, 13, 10, 2, -12 }, // 0x31 '1' U+0031
|
|
||||||
{ 148, 8, 13, 10, 1, -12 }, // 0x32 '2' U+0032
|
|
||||||
{ 161, 8, 13, 10, 1, -12 }, // 0x33 '3' U+0033
|
|
||||||
{ 174, 9, 13, 10, 0, -12 }, // 0x34 '4' U+0034
|
|
||||||
{ 189, 8, 13, 10, 1, -12 }, // 0x35 '5' U+0035
|
|
||||||
{ 202, 8, 13, 10, 1, -12 }, // 0x36 '6' U+0036
|
|
||||||
{ 215, 8, 13, 10, 1, -12 }, // 0x37 '7' U+0037
|
|
||||||
{ 228, 8, 13, 10, 1, -12 }, // 0x38 '8' U+0038
|
|
||||||
{ 241, 8, 13, 10, 1, -12 }, // 0x39 '9' U+0039
|
|
||||||
{ 254, 2, 9, 5, 2, -8 }, // 0x3a ':' U+003A
|
|
||||||
{ 257, 2, 12, 5, 2, -8 }, // 0x3b ';' U+003B
|
|
||||||
{ 260, 9, 9, 11, 1, -8 }, // 0x3c '<' U+003C
|
|
||||||
{ 271, 9, 4, 11, 1, -5 }, // 0x3d '=' U+003D
|
|
||||||
{ 276, 9, 9, 11, 1, -8 }, // 0x3e '>' U+003E
|
|
||||||
{ 287, 8, 13, 10, 1, -12 }, // 0x3f '?' U+003F
|
|
||||||
{ 300, 16, 16, 18, 1, -12 }, // 0x40 '@' U+0040
|
|
||||||
{ 332, 12, 13, 12, 0, -12 }, // 0x41 'A' U+0041
|
|
||||||
{ 352, 10, 13, 12, 1, -12 }, // 0x42 'B' U+0042
|
|
||||||
{ 369, 11, 13, 13, 1, -12 }, // 0x43 'C' U+0043
|
|
||||||
{ 387, 10, 13, 13, 2, -12 }, // 0x44 'D' U+0044
|
|
||||||
{ 404, 9, 13, 12, 2, -12 }, // 0x45 'E' U+0045
|
|
||||||
{ 419, 8, 13, 11, 2, -12 }, // 0x46 'F' U+0046
|
|
||||||
{ 432, 12, 13, 14, 1, -12 }, // 0x47 'G' U+0047
|
|
||||||
{ 452, 11, 13, 13, 1, -12 }, // 0x48 'H' U+0048
|
|
||||||
{ 470, 1, 13, 5, 2, -12 }, // 0x49 'I' U+0049
|
|
||||||
{ 472, 8, 13, 9, 0, -12 }, // 0x4a 'J' U+004A
|
|
||||||
{ 485, 11, 13, 12, 1, -12 }, // 0x4b 'K' U+004B
|
|
||||||
{ 503, 9, 13, 10, 1, -12 }, // 0x4c 'L' U+004C
|
|
||||||
{ 518, 13, 13, 15, 1, -12 }, // 0x4d 'M' U+004D
|
|
||||||
{ 540, 11, 13, 13, 1, -12 }, // 0x4e 'N' U+004E
|
|
||||||
{ 558, 12, 13, 14, 1, -12 }, // 0x4f 'O' U+004F
|
|
||||||
{ 578, 9, 13, 12, 2, -12 }, // 0x50 'P' U+0050
|
|
||||||
{ 593, 12, 14, 14, 1, -12 }, // 0x51 'Q' U+0051
|
|
||||||
{ 614, 10, 13, 13, 2, -12 }, // 0x52 'R' U+0052
|
|
||||||
{ 631, 10, 13, 12, 1, -12 }, // 0x53 'S' U+0053
|
|
||||||
{ 648, 11, 13, 11, 0, -12 }, // 0x54 'T' U+0054
|
|
||||||
{ 666, 10, 13, 13, 2, -12 }, // 0x55 'U' U+0055
|
|
||||||
{ 683, 11, 13, 12, 1, -12 }, // 0x56 'V' U+0056
|
|
||||||
{ 701, 17, 13, 17, 0, -12 }, // 0x57 'W' U+0057
|
|
||||||
{ 729, 12, 13, 12, 0, -12 }, // 0x58 'X' U+0058
|
|
||||||
{ 749, 12, 13, 12, 0, -12 }, // 0x59 'Y' U+0059
|
|
||||||
{ 769, 11, 13, 11, 0, -12 }, // 0x5a 'Z' U+005A
|
|
||||||
{ 787, 4, 17, 5, 1, -12 }, // 0x5b '[' U+005B
|
|
||||||
{ 796, 5, 13, 5, 0, -12 }, // 0x5c '\' U+005C
|
|
||||||
{ 805, 4, 17, 5, 0, -12 }, // 0x5d ']' U+005D
|
|
||||||
{ 814, 7, 7, 8, 1, -12 }, // 0x5e '^' U+005E
|
|
||||||
{ 821, 10, 1, 10, 0, 3 }, // 0x5f '_' U+005F
|
|
||||||
{ 823, 4, 2, 6, 0, -12 }, // 0x60 '`' U+0060
|
|
||||||
{ 824, 9, 10, 10, 1, -9 }, // 0x61 'a' U+0061
|
|
||||||
{ 836, 8, 13, 10, 1, -12 }, // 0x62 'b' U+0062
|
|
||||||
{ 849, 8, 10, 9, 1, -9 }, // 0x63 'c' U+0063
|
|
||||||
{ 859, 9, 13, 10, 0, -12 }, // 0x64 'd' U+0064
|
|
||||||
{ 874, 8, 10, 10, 1, -9 }, // 0x65 'e' U+0065
|
|
||||||
{ 884, 5, 13, 5, 0, -12 }, // 0x66 'f' U+0066
|
|
||||||
{ 893, 8, 14, 10, 1, -9 }, // 0x67 'g' U+0067
|
|
||||||
{ 907, 8, 13, 10, 1, -12 }, // 0x68 'h' U+0068
|
|
||||||
{ 920, 2, 13, 4, 1, -12 }, // 0x69 'i' U+0069
|
|
||||||
{ 924, 3, 17, 4, 0, -12 }, // 0x6a 'j' U+006A
|
|
||||||
{ 931, 8, 13, 9, 1, -12 }, // 0x6b 'k' U+006B
|
|
||||||
{ 944, 2, 13, 4, 1, -12 }, // 0x6c 'l' U+006C
|
|
||||||
{ 948, 13, 10, 15, 1, -9 }, // 0x6d 'm' U+006D
|
|
||||||
{ 965, 8, 10, 10, 1, -9 }, // 0x6e 'n' U+006E
|
|
||||||
{ 975, 8, 10, 10, 1, -9 }, // 0x6f 'o' U+006F
|
|
||||||
{ 985, 8, 14, 10, 1, -9 }, // 0x70 'p' U+0070
|
|
||||||
{ 999, 9, 14, 10, 0, -9 }, // 0x71 'q' U+0071
|
|
||||||
{ 1015, 5, 10, 6, 1, -9 }, // 0x72 'r' U+0072
|
|
||||||
{ 1022, 7, 10, 9, 1, -9 }, // 0x73 's' U+0073
|
|
||||||
{ 1031, 5, 12, 5, 0, -11 }, // 0x74 't' U+0074
|
|
||||||
{ 1039, 8, 9, 10, 1, -8 }, // 0x75 'u' U+0075
|
|
||||||
{ 1048, 9, 9, 9, 0, -8 }, // 0x76 'v' U+0076
|
|
||||||
{ 1059, 13, 9, 13, 0, -8 }, // 0x77 'w' U+0077
|
|
||||||
{ 1074, 9, 9, 9, 0, -8 }, // 0x78 'x' U+0078
|
|
||||||
{ 1085, 9, 13, 9, 0, -8 }, // 0x79 'y' U+0079
|
|
||||||
{ 1100, 7, 9, 9, 1, -8 }, // 0x7a 'z' U+007A
|
|
||||||
{ 1108, 4, 17, 6, 1, -12 }, // 0x7b '{' U+007B
|
|
||||||
{ 1117, 1, 17, 5, 2, -12 }, // 0x7c '|' U+007C
|
|
||||||
{ 1120, 4, 17, 6, 1, -12 }, // 0x7d '}' U+007D
|
|
||||||
{ 1129, 8, 3, 11, 1, -7 }, // 0x7e '~' U+007E
|
|
||||||
{ 1132, 9, 13, 13, 2, -12 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
|
|
||||||
{ 1147, 1, 1, 5, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
|
|
||||||
{ 1148, 2, 13, 5, 2, -8 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
|
|
||||||
{ 1152, 8, 13, 10, 1, -10 }, // 0x82 'CENT SIGN' U+00A2
|
|
||||||
{ 1165, 10, 13, 10, 0, -12 }, // 0x83 'POUND SIGN' U+00A3
|
|
||||||
{ 1182, 10, 13, 12, 1, -12 }, // 0x84 'EURO SIGN *' U+20AC
|
|
||||||
{ 1199, 10, 13, 10, 0, -12 }, // 0x85 'YEN SIGN' U+00A5
|
|
||||||
{ 1216, 10, 17, 12, 1, -16 }, // 0x86 'LATIN CAPITAL LETTER S WITH CARON *' U+0160
|
|
||||||
{ 1238, 8, 17, 10, 1, -12 }, // 0x87 'SECTION SIGN' U+00A7
|
|
||||||
{ 1255, 7, 13, 9, 1, -12 }, // 0x88 'LATIN SMALL LETTER S WITH CARON *' U+0161
|
|
||||||
{ 1267, 14, 13, 13, 0, -12 }, // 0x89 'COPYRIGHT SIGN' U+00A9
|
|
||||||
{ 1290, 5, 8, 7, 1, -12 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
|
|
||||||
{ 1295, 6, 6, 8, 1, -7 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
|
|
||||||
{ 1300, 9, 5, 11, 1, -6 }, // 0x8c 'NOT SIGN' U+00AC
|
|
||||||
{ 1306, 4, 2, 6, 1, -5 }, // 0x8d 'SOFT HYPHEN' U+00AD
|
|
||||||
{ 1307, 14, 13, 13, 0, -12 }, // 0x8e 'REGISTERED SIGN' U+00AE
|
|
||||||
{ 1330, 5, 2, 6, 0, -12 }, // 0x8f 'MACRON' U+00AF
|
|
||||||
{ 1332, 5, 5, 11, 3, -11 }, // 0x90 'DEGREE SIGN' U+00B0
|
|
||||||
{ 1336, 9, 11, 11, 1, -10 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
|
|
||||||
{ 1349, 6, 8, 6, 0, -12 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
|
|
||||||
{ 1355, 6, 8, 6, 0, -12 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
|
|
||||||
{ 1361, 11, 17, 11, 0, -16 }, // 0x94 'LATIN CAPITAL LETTER Z WITH CARON *' U+017D
|
|
||||||
{ 1385, 9, 13, 10, 1, -8 }, // 0x95 'MICRO SIGN' U+00B5
|
|
||||||
{ 1400, 8, 16, 10, 1, -12 }, // 0x96 'PILCROW SIGN' U+00B6
|
|
||||||
{ 1416, 1, 2, 5, 2, -5 }, // 0x97 'MIDDLE DOT' U+00B7
|
|
||||||
{ 1417, 7, 13, 9, 1, -12 }, // 0x98 'LATIN SMALL LETTER Z WITH CARON *' U+017E
|
|
||||||
{ 1429, 3, 8, 6, 1, -12 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
|
|
||||||
{ 1432, 5, 8, 7, 1, -12 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
|
|
||||||
{ 1437, 6, 6, 8, 1, -7 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
|
|
||||||
{ 1442, 16, 13, 18, 1, -12 }, // 0x9c 'LATIN CAPITAL LIGATURE OE *' U+0152
|
|
||||||
{ 1468, 15, 10, 17, 1, -9 }, // 0x9d 'LATIN SMALL LIGATURE OE *' U+0153
|
|
||||||
{ 1487, 12, 16, 12, 0, -15 }, // 0x9e 'LATIN CAPITAL LETTER Y WITH DIAERESIS *' U+0178
|
|
||||||
{ 1511, 8, 13, 10, 2, -8 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
|
|
||||||
{ 1524, 12, 17, 12, 0, -16 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
|
|
||||||
{ 1550, 12, 17, 12, 0, -16 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
|
|
||||||
{ 1576, 12, 17, 12, 0, -16 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
|
|
||||||
{ 1602, 12, 16, 12, 0, -15 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
|
|
||||||
{ 1626, 12, 16, 12, 0, -15 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
|
|
||||||
{ 1650, 12, 17, 12, 0, -16 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
|
|
||||||
{ 1676, 17, 13, 18, 0, -12 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
|
|
||||||
{ 1704, 11, 17, 13, 1, -12 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
|
|
||||||
{ 1728, 9, 17, 12, 2, -16 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
|
|
||||||
{ 1748, 9, 17, 12, 2, -16 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
|
|
||||||
{ 1768, 9, 17, 12, 2, -16 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
|
|
||||||
{ 1788, 9, 16, 12, 2, -15 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
|
|
||||||
{ 1806, 4, 17, 5, 0, -16 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
|
|
||||||
{ 1815, 4, 17, 5, 1, -16 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
|
|
||||||
{ 1824, 5, 17, 5, 0, -16 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
|
|
||||||
{ 1835, 6, 16, 5, 0, -15 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
|
|
||||||
{ 1847, 12, 13, 13, 0, -12 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
|
|
||||||
{ 1867, 11, 16, 13, 1, -15 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
|
|
||||||
{ 1889, 12, 17, 14, 1, -16 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
|
|
||||||
{ 1915, 12, 17, 14, 1, -16 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
|
|
||||||
{ 1941, 12, 17, 14, 1, -16 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
|
|
||||||
{ 1967, 12, 16, 14, 1, -15 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
|
|
||||||
{ 1991, 12, 16, 14, 1, -15 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
|
|
||||||
{ 2015, 7, 7, 11, 2, -7 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
|
|
||||||
{ 2022, 12, 14, 14, 1, -13 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
|
|
||||||
{ 2043, 10, 17, 13, 2, -16 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
|
|
||||||
{ 2065, 10, 17, 13, 2, -16 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
|
|
||||||
{ 2087, 10, 17, 13, 2, -16 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
|
|
||||||
{ 2109, 10, 16, 13, 2, -15 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
|
|
||||||
{ 2129, 12, 17, 12, 0, -16 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
|
|
||||||
{ 2155, 9, 13, 12, 2, -12 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
|
|
||||||
{ 2170, 9, 13, 11, 1, -12 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
|
|
||||||
{ 2185, 9, 13, 10, 1, -12 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
|
|
||||||
{ 2200, 9, 13, 10, 1, -12 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
|
|
||||||
{ 2215, 9, 13, 10, 1, -12 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
|
|
||||||
{ 2230, 9, 13, 10, 1, -12 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
|
|
||||||
{ 2245, 9, 13, 10, 1, -12 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
|
|
||||||
{ 2260, 9, 14, 10, 1, -13 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
|
|
||||||
{ 2276, 14, 10, 16, 1, -9 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
|
|
||||||
{ 2294, 8, 14, 9, 1, -9 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
|
|
||||||
{ 2308, 8, 13, 10, 1, -12 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
|
|
||||||
{ 2321, 8, 13, 10, 1, -12 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
|
|
||||||
{ 2334, 8, 13, 10, 1, -12 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
|
|
||||||
{ 2347, 8, 13, 10, 1, -12 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
|
|
||||||
{ 2360, 4, 13, 5, 0, -12 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
|
|
||||||
{ 2367, 4, 13, 5, 1, -12 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
|
|
||||||
{ 2374, 5, 13, 5, 0, -12 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
|
|
||||||
{ 2383, 6, 13, 5, -1, -12 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
|
|
||||||
{ 2393, 8, 13, 10, 1, -12 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
|
|
||||||
{ 2406, 8, 13, 10, 1, -12 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
|
|
||||||
{ 2419, 8, 13, 10, 1, -12 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
|
|
||||||
{ 2432, 8, 13, 10, 1, -12 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
|
|
||||||
{ 2445, 8, 13, 10, 1, -12 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
|
|
||||||
{ 2458, 8, 13, 10, 1, -12 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
|
|
||||||
{ 2471, 8, 13, 10, 1, -12 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
|
|
||||||
{ 2484, 9, 9, 11, 1, -8 }, // 0xd7 'DIVISION SIGN' U+00F7
|
|
||||||
{ 2495, 10, 11, 11, 0, -9 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
|
|
||||||
{ 2509, 8, 13, 10, 1, -12 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
|
|
||||||
{ 2522, 8, 13, 10, 1, -12 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
|
|
||||||
{ 2535, 8, 13, 10, 1, -12 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
|
|
||||||
{ 2548, 8, 13, 10, 1, -12 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
|
|
||||||
{ 2561, 9, 17, 9, 0, -12 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
|
|
||||||
{ 2581, 8, 17, 10, 1, -12 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
|
|
||||||
{ 2598, 9, 17, 9, 0, -12 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
|
|
||||||
|
|
||||||
const GFXfont FreeSans9pt8b PROGMEM = {
|
|
||||||
(uint8_t *)FreeSans9pt8bBitmaps,
|
|
||||||
(GFXglyph *)FreeSans9pt8bGlyphs,
|
|
||||||
0x20, 0xDF, 25 };
|
|
||||||
|
|
||||||
// Approx. 3969 bytes
|
|
|
@ -1,221 +0,0 @@
|
||||||
const uint8_t Terminal11x16Bitmap[] = {
|
|
||||||
0x0C, 0x18, 0x78, 0xF1, 0xE3, 0xC7, 0x86, 0x0C, 0x18, 0x00, 0x00, 0xC1,
|
|
||||||
0x80, 0x33, 0x33, 0x33, 0x33, 0x0C, 0xC1, 0x98, 0x33, 0x3F, 0xF1, 0x98,
|
|
||||||
0x33, 0x0C, 0xC1, 0x98, 0xFF, 0x8C, 0xC1, 0x98, 0x33, 0x00, 0x0C, 0x06,
|
|
||||||
0x0F, 0xCF, 0xF6, 0xC3, 0x61, 0xFC, 0x7F, 0x0D, 0x86, 0xDF, 0xE7, 0xE0,
|
|
||||||
0xC0, 0x60, 0x00, 0x2E, 0x0D, 0xC3, 0xB8, 0xE0, 0x38, 0x0E, 0x03, 0x80,
|
|
||||||
0xE0, 0x38, 0x0E, 0x3B, 0x87, 0x60, 0xE0, 0x0E, 0x06, 0xC3, 0x30, 0xCC,
|
|
||||||
0x36, 0x07, 0x03, 0xC1, 0xF0, 0x66, 0xD9, 0xE6, 0x31, 0xDE, 0x3C, 0xC0,
|
|
||||||
0x1C, 0x71, 0xC3, 0x0C, 0x60, 0x07, 0x0C, 0x1C, 0x18, 0x38, 0x38, 0x38,
|
|
||||||
0x38, 0x38, 0x38, 0x18, 0x1C, 0x0C, 0x07, 0x38, 0x0C, 0x0E, 0x06, 0x07,
|
|
||||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0E, 0x0C, 0x38, 0x6D, 0xB6, 0xCF,
|
|
||||||
0xC3, 0xC7, 0xF8, 0xF0, 0xFC, 0xDB, 0x6D, 0x80, 0x0C, 0x06, 0x03, 0x0F,
|
|
||||||
0xF7, 0xF8, 0x60, 0x30, 0x18, 0x1C, 0x71, 0xC3, 0x18, 0x7F, 0xBF, 0xC0,
|
|
||||||
0x1C, 0x71, 0xC0, 0x00, 0x20, 0x0C, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03,
|
|
||||||
0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0x60, 0x00, 0x1F, 0x0F, 0xF9, 0x83,
|
|
||||||
0x60, 0x7C, 0x1F, 0x86, 0xF1, 0x9E, 0x63, 0xD8, 0x7E, 0x0F, 0x81, 0xB0,
|
|
||||||
0x67, 0xFC, 0x3E, 0x00, 0x06, 0x03, 0x83, 0xE0, 0xF8, 0x06, 0x01, 0x80,
|
|
||||||
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x3F, 0xCF, 0xF0, 0x3F, 0x8F,
|
|
||||||
0xFB, 0x83, 0xE0, 0x3C, 0x0E, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80,
|
|
||||||
0xE0, 0x38, 0x0F, 0xFF, 0xFF, 0xC0, 0x3F, 0x8F, 0xFB, 0x83, 0xE0, 0x30,
|
|
||||||
0x06, 0x01, 0xC7, 0xF0, 0xFC, 0x00, 0xC0, 0x0F, 0x01, 0xF0, 0x77, 0xFC,
|
|
||||||
0x7F, 0x00, 0x03, 0x80, 0xF0, 0x3E, 0x0E, 0xC3, 0x98, 0xE3, 0x38, 0x66,
|
|
||||||
0x0C, 0xFF, 0xFF, 0xFC, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0xFF, 0xFF,
|
|
||||||
0xFF, 0x00, 0x60, 0x0C, 0x01, 0xFF, 0x1F, 0xF0, 0x07, 0x00, 0x60, 0x0F,
|
|
||||||
0x01, 0xF0, 0x77, 0xFC, 0x7F, 0x00, 0x07, 0x81, 0xF0, 0x70, 0x1C, 0x07,
|
|
||||||
0x00, 0xC0, 0x3F, 0xE7, 0xFE, 0xE0, 0xF8, 0x0F, 0x01, 0xF0, 0x77, 0xFC,
|
|
||||||
0x7F, 0x00, 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0x60, 0x18, 0x03, 0x00, 0xC0,
|
|
||||||
0x18, 0x06, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, 0x1F, 0x07,
|
|
||||||
0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xE3, 0x8F, 0xE3, 0xFE, 0xE0, 0xF8, 0x0F,
|
|
||||||
0x01, 0xF0, 0x77, 0xFC, 0x7F, 0x00, 0x3F, 0x8F, 0xFB, 0x83, 0xE0, 0x3C,
|
|
||||||
0x07, 0xC1, 0xDF, 0xF9, 0xFF, 0x00, 0xC0, 0x38, 0x0E, 0x03, 0x83, 0xE0,
|
|
||||||
0x78, 0x00, 0x1C, 0x71, 0xC0, 0x00, 0x01, 0xC7, 0x1C, 0x1C, 0x71, 0xC0,
|
|
||||||
0x00, 0x01, 0xC7, 0x1C, 0x30, 0xC6, 0x01, 0x81, 0xC1, 0xC1, 0xC1, 0xC1,
|
|
||||||
0xC1, 0xC0, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38, 0x0C, 0x7F, 0xDF,
|
|
||||||
0xF0, 0x00, 0x00, 0x7F, 0xDF, 0xF0, 0x60, 0x38, 0x0E, 0x03, 0x80, 0xE0,
|
|
||||||
0x38, 0x0E, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x00, 0x3F, 0x1F,
|
|
||||||
0xEE, 0x1F, 0x03, 0xC1, 0xC0, 0xE0, 0x70, 0x38, 0x0C, 0x03, 0x00, 0xC0,
|
|
||||||
0x00, 0x0C, 0x03, 0x00, 0x3F, 0x8F, 0xF9, 0x83, 0x67, 0xBD, 0xF7, 0xB6,
|
|
||||||
0xF6, 0xDE, 0xDB, 0xDB, 0x7B, 0xFB, 0x3E, 0x70, 0x07, 0xF8, 0x3F, 0x00,
|
|
||||||
0x0C, 0x03, 0x01, 0xE0, 0x78, 0x1E, 0x0C, 0xC3, 0x30, 0xCC, 0x61, 0x9F,
|
|
||||||
0xE7, 0xFB, 0x03, 0xC0, 0xF0, 0x30, 0xFE, 0x3F, 0xCC, 0x3B, 0x06, 0xC1,
|
|
||||||
0xB0, 0xEF, 0xF3, 0xFE, 0xC1, 0xF0, 0x3C, 0x0F, 0x07, 0xFF, 0xBF, 0xC0,
|
|
||||||
0x1F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30,
|
|
||||||
0x06, 0x0D, 0xC7, 0x3F, 0x87, 0xC0, 0xFE, 0x3F, 0xCC, 0x3B, 0x06, 0xC0,
|
|
||||||
0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1B, 0x0E, 0xFF, 0x3F, 0x80,
|
|
||||||
0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xC0, 0x30, 0x0F, 0xF3, 0xFC, 0xC0, 0x30,
|
|
||||||
0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xC0,
|
|
||||||
0x30, 0x0F, 0xF3, 0xFC, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00,
|
|
||||||
0x1F, 0x8F, 0xF7, 0x0D, 0x80, 0xC0, 0x30, 0x0C, 0x7F, 0x1F, 0xC0, 0xF0,
|
|
||||||
0x36, 0x0D, 0xC3, 0x3F, 0xC7, 0xF0, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0,
|
|
||||||
0xF0, 0x3F, 0xFF, 0xFF, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
|
|
||||||
0x3F, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
|
||||||
0x3F, 0x3F, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03,
|
|
||||||
0x00, 0xF0, 0x3C, 0x0F, 0x86, 0x7F, 0x8F, 0xC0, 0xC0, 0xF0, 0x7C, 0x3B,
|
|
||||||
0x1C, 0xCE, 0x37, 0x0F, 0x83, 0xE0, 0xDC, 0x33, 0x8C, 0x73, 0x0E, 0xC1,
|
|
||||||
0xF0, 0x30, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
|
|
||||||
0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, 0xC0, 0xF8, 0x7E, 0x1F,
|
|
||||||
0xCF, 0xF3, 0xF7, 0xBD, 0xEF, 0x33, 0xCC, 0xF0, 0x3C, 0x0F, 0x03, 0xC0,
|
|
||||||
0xF0, 0x30, 0xC0, 0xF8, 0x3E, 0x0F, 0xC3, 0xD8, 0xF6, 0x3C, 0xCF, 0x33,
|
|
||||||
0xC6, 0xF1, 0xBC, 0x3F, 0x07, 0xC1, 0xF0, 0x30, 0x1E, 0x0F, 0xC7, 0x39,
|
|
||||||
0x86, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xCE, 0x3F,
|
|
||||||
0x07, 0x80, 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE,
|
|
||||||
0xFF, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00, 0x1E, 0x0F, 0xC7, 0x39,
|
|
||||||
0x86, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF1, 0xB6, 0x79, 0xCE, 0x3F,
|
|
||||||
0xC7, 0xB0, 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE,
|
|
||||||
0xFF, 0x33, 0x8C, 0x73, 0x0E, 0xC1, 0xF0, 0x30, 0x3F, 0x1F, 0xEE, 0x1F,
|
|
||||||
0x03, 0xC0, 0x38, 0x07, 0xF0, 0xFE, 0x01, 0xC0, 0x3C, 0x0F, 0x87, 0x7F,
|
|
||||||
0x8F, 0xC0, 0x7F, 0xBF, 0xC3, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C,
|
|
||||||
0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0,
|
|
||||||
0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0D, 0x86, 0x7F, 0x8F, 0xC0,
|
|
||||||
0xC0, 0xF0, 0x3C, 0x0D, 0x86, 0x61, 0x98, 0x63, 0x30, 0xCC, 0x33, 0x07,
|
|
||||||
0x81, 0xE0, 0x78, 0x0C, 0x03, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0,
|
|
||||||
0xF0, 0x3C, 0x0F, 0x33, 0xCC, 0xF7, 0xBF, 0x3F, 0x87, 0xE1, 0xF0, 0x30,
|
|
||||||
0xC0, 0xF0, 0x36, 0x19, 0x86, 0x33, 0x07, 0x80, 0xC0, 0x30, 0x1E, 0x0C,
|
|
||||||
0xC6, 0x19, 0x86, 0xC0, 0xF0, 0x30, 0xC0, 0xF0, 0x36, 0x19, 0x86, 0x33,
|
|
||||||
0x0C, 0xC1, 0xE0, 0x78, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
|
|
||||||
0xFF, 0xFF, 0xF0, 0x18, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C,
|
|
||||||
0x06, 0x01, 0x80, 0xFF, 0xFF, 0xF0, 0x3F, 0x3F, 0x30, 0x30, 0x30, 0x30,
|
|
||||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3F, 0x3F, 0x80, 0x18, 0x03, 0x80,
|
|
||||||
0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80,
|
|
||||||
0x30, 0x3F, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
||||||
0x03, 0x3F, 0x3F, 0x04, 0x01, 0xC0, 0x7C, 0x1D, 0xC7, 0x1D, 0xC1, 0xF0,
|
|
||||||
0x18, 0xFF, 0xFF, 0xFC, 0x0E, 0x1C, 0x38, 0x60, 0xC0, 0xC0, 0x3F, 0x9F,
|
|
||||||
0xF0, 0x0C, 0xFF, 0x7F, 0xF0, 0x3C, 0x0F, 0xFF, 0x7F, 0xC0, 0xC0, 0x30,
|
|
||||||
0x0C, 0x03, 0x00, 0xC0, 0x37, 0xCF, 0xFB, 0x87, 0xC0, 0xF0, 0x3C, 0x0F,
|
|
||||||
0x07, 0xFF, 0xBF, 0xC0, 0x3F, 0x1F, 0xEE, 0x0F, 0x00, 0xC0, 0x30, 0x0E,
|
|
||||||
0x0D, 0xFE, 0x3F, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xCF, 0xB7,
|
|
||||||
0xFF, 0x8F, 0xC0, 0xF0, 0x3C, 0x0F, 0x83, 0x7F, 0xCF, 0xF0, 0x3F, 0x1F,
|
|
||||||
0xEE, 0x0F, 0xFF, 0xFF, 0xB0, 0x0E, 0x01, 0xFE, 0x3F, 0x00, 0x0F, 0x1F,
|
|
||||||
0x38, 0x30, 0x30, 0x30, 0xFE, 0xFE, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
|
||||||
0x3F, 0xDF, 0xFE, 0x0F, 0x03, 0xE1, 0xDF, 0xF3, 0xEC, 0x03, 0x01, 0xDF,
|
|
||||||
0xE7, 0xF0, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0xF3, 0xFD, 0xC7, 0xC1,
|
|
||||||
0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0C, 0x0C, 0x0C, 0x00, 0x1C, 0x1C, 0x0C,
|
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x3F, 0x03, 0x03, 0x00, 0x07, 0x07, 0x03,
|
|
||||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x33, 0x3F, 0x1E, 0x60, 0x30, 0x18, 0x0C,
|
|
||||||
0x06, 0x03, 0x19, 0x9C, 0xDC, 0x7C, 0x3E, 0x1B, 0x8C, 0xE6, 0x3B, 0x0C,
|
|
||||||
0x1C, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
|
||||||
0x3F, 0x3F, 0xB3, 0x3F, 0xEF, 0xFF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33,
|
|
||||||
0xCC, 0xC0, 0x7F, 0x1F, 0xE6, 0x1D, 0x83, 0x60, 0xD8, 0x36, 0x0D, 0x83,
|
|
||||||
0x60, 0xC0, 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x3E, 0x1D, 0xFE,
|
|
||||||
0x3F, 0x00, 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF8, 0x7F, 0xFB, 0x7C,
|
|
||||||
0xC0, 0x30, 0x0C, 0x00, 0x3F, 0xDF, 0xFE, 0x0F, 0x03, 0xC0, 0xF8, 0x77,
|
|
||||||
0xFC, 0xFB, 0x00, 0xC0, 0x30, 0x0C, 0x6F, 0x9F, 0xF7, 0x0D, 0x80, 0x60,
|
|
||||||
0x18, 0x06, 0x01, 0x80, 0x60, 0x00, 0x7E, 0xFF, 0xC0, 0xFE, 0x7F, 0x03,
|
|
||||||
0x03, 0xFF, 0x7E, 0x30, 0x30, 0x30, 0x30, 0xFE, 0xFE, 0x30, 0x30, 0x30,
|
|
||||||
0x30, 0x30, 0x3F, 0x1F, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3E,
|
|
||||||
0x1D, 0xFF, 0x3E, 0xC0, 0xC0, 0xF0, 0x36, 0x19, 0x86, 0x33, 0x0C, 0xC1,
|
|
||||||
0xE0, 0x78, 0x0C, 0x00, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xF7, 0xB7,
|
|
||||||
0xF9, 0xCE, 0x21, 0x00, 0xC1, 0xF1, 0xDD, 0xC7, 0xC1, 0xC1, 0xF1, 0xDD,
|
|
||||||
0xC7, 0xC1, 0x80, 0x61, 0xB0, 0xCC, 0xC6, 0x61, 0xE0, 0xF0, 0x30, 0x18,
|
|
||||||
0x18, 0x0C, 0x0C, 0x00, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
|
|
||||||
0xFF, 0xFF, 0x80, 0x07, 0x87, 0xC7, 0x03, 0x01, 0x80, 0xC0, 0xE0, 0xE0,
|
|
||||||
0x38, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x7C, 0x1E, 0x0C, 0x30, 0xC3, 0x0C,
|
|
||||||
0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0x78, 0x3E, 0x03, 0x80, 0xC0,
|
|
||||||
0x60, 0x30, 0x1C, 0x07, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xE3, 0xE1, 0xE0,
|
|
||||||
0x38, 0xDB, 0x6C, 0x70, 0x0C, 0x07, 0x83, 0x31, 0x86, 0xC0, 0xF0, 0x3F,
|
|
||||||
0xFF, 0xFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
const GFXglyph Terminal11x16Glyphs[] = {
|
|
||||||
{ 0, 6, 0, 7, 0, 4 }, // 0x20 ' '
|
|
||||||
{ 0, 7, 14, 8, 0, -12 }, // 0x21 '!'
|
|
||||||
{ 13, 8, 4, 9, 0, -10 }, // 0x22 '"'
|
|
||||||
{ 17, 11, 12, 12, 0, -11 }, // 0x23 '#'
|
|
||||||
{ 34, 9, 14, 10, 0, -12 }, // 0x24 '$'
|
|
||||||
{ 50, 11, 12, 12, 0, -10 }, // 0x25 '%'
|
|
||||||
{ 67, 10, 13, 11, 0, -11 }, // 0x26 '&'
|
|
||||||
{ 84, 6, 6, 7, 0, -12 }, // 0x27 '''
|
|
||||||
{ 89, 8, 14, 9, 0, -12 }, // 0x28 '('
|
|
||||||
{ 103, 8, 14, 9, 0, -12 }, // 0x29 ')'
|
|
||||||
{ 117, 9, 9, 10, 0, -9 }, // 0x2a '*'
|
|
||||||
{ 128, 9, 8, 10, 0, -8 }, // 0x2b '+'
|
|
||||||
{ 137, 6, 5, 7, 0, -1 }, // 0x2c ','
|
|
||||||
{ 141, 9, 2, 10, 0, -5 }, // 0x2d '-'
|
|
||||||
{ 144, 6, 3, 7, 0, -1 }, // 0x2e '.'
|
|
||||||
{ 147, 11, 12, 12, 0, -11 }, // 0x2f '/'
|
|
||||||
{ 164, 11, 14, 12, 0, -12 }, // 0x30 '0'
|
|
||||||
{ 184, 10, 14, 11, 0, -12 }, // 0x31 '1'
|
|
||||||
{ 202, 11, 14, 12, 0, -12 }, // 0x32 '2'
|
|
||||||
{ 222, 11, 14, 12, 0, -12 }, // 0x33 '3'
|
|
||||||
{ 242, 11, 14, 12, 0, -12 }, // 0x34 '4'
|
|
||||||
{ 262, 11, 14, 12, 0, -12 }, // 0x35 '5'
|
|
||||||
{ 282, 11, 14, 12, 0, -12 }, // 0x36 '6'
|
|
||||||
{ 302, 11, 14, 12, 0, -12 }, // 0x37 '7'
|
|
||||||
{ 322, 11, 14, 12, 0, -12 }, // 0x38 '8'
|
|
||||||
{ 342, 11, 14, 12, 0, -12 }, // 0x39 '9'
|
|
||||||
{ 362, 6, 9, 7, 0, -8 }, // 0x3a ':'
|
|
||||||
{ 369, 6, 12, 7, 0, -8 }, // 0x3b ';'
|
|
||||||
{ 378, 9, 14, 10, 0, -12 }, // 0x3c '<'
|
|
||||||
{ 394, 10, 6, 11, 0, -7 }, // 0x3d '='
|
|
||||||
{ 402, 9, 14, 10, 0, -12 }, // 0x3e '>'
|
|
||||||
{ 418, 10, 14, 11, 0, -12 }, // 0x3f '?'
|
|
||||||
{ 436, 11, 14, 12, 0, -12 }, // 0x40 '@'
|
|
||||||
{ 456, 10, 14, 11, 0, -12 }, // 0x41 'A'
|
|
||||||
{ 474, 10, 14, 11, 0, -12 }, // 0x42 'B'
|
|
||||||
{ 492, 10, 14, 11, 0, -12 }, // 0x43 'C'
|
|
||||||
{ 510, 10, 14, 11, 0, -12 }, // 0x44 'D'
|
|
||||||
{ 528, 10, 14, 11, 0, -12 }, // 0x45 'E'
|
|
||||||
{ 546, 10, 14, 11, 0, -12 }, // 0x46 'F'
|
|
||||||
{ 564, 10, 14, 11, 0, -12 }, // 0x47 'G'
|
|
||||||
{ 582, 10, 14, 11, 0, -12 }, // 0x48 'H'
|
|
||||||
{ 600, 8, 14, 9, 0, -12 }, // 0x49 'I'
|
|
||||||
{ 614, 10, 14, 11, 0, -12 }, // 0x4a 'J'
|
|
||||||
{ 632, 10, 14, 11, 0, -12 }, // 0x4b 'K'
|
|
||||||
{ 650, 10, 14, 11, 0, -12 }, // 0x4c 'L'
|
|
||||||
{ 668, 10, 14, 11, 0, -12 }, // 0x4d 'M'
|
|
||||||
{ 686, 10, 14, 11, 0, -12 }, // 0x4e 'N'
|
|
||||||
{ 704, 10, 14, 11, 0, -12 }, // 0x4f 'O'
|
|
||||||
{ 722, 10, 14, 11, 0, -12 }, // 0x50 'P'
|
|
||||||
{ 740, 10, 14, 11, 0, -12 }, // 0x51 'Q'
|
|
||||||
{ 758, 10, 14, 11, 0, -12 }, // 0x52 'R'
|
|
||||||
{ 776, 10, 14, 11, 0, -12 }, // 0x53 'S'
|
|
||||||
{ 794, 9, 14, 10, 0, -12 }, // 0x54 'T'
|
|
||||||
{ 810, 10, 14, 11, 0, -12 }, // 0x55 'U'
|
|
||||||
{ 828, 10, 14, 11, 0, -12 }, // 0x56 'V'
|
|
||||||
{ 846, 10, 14, 11, 0, -12 }, // 0x57 'W'
|
|
||||||
{ 864, 10, 14, 11, 0, -12 }, // 0x58 'X'
|
|
||||||
{ 882, 10, 14, 11, 0, -12 }, // 0x59 'Y'
|
|
||||||
{ 900, 10, 14, 11, 0, -12 }, // 0x5a 'Z'
|
|
||||||
{ 918, 8, 14, 9, 0, -12 }, // 0x5b '['
|
|
||||||
{ 932, 11, 12, 12, 0, -11 }, // 0x5c '\'
|
|
||||||
{ 949, 8, 14, 9, 0, -12 }, // 0x5d ']'
|
|
||||||
{ 963, 11, 7, 12, 0, -12 }, // 0x5e '^'
|
|
||||||
{ 973, 11, 2, 12, 0, 2 }, // 0x5f '_'
|
|
||||||
{ 976, 7, 6, 8, 0, -11 }, // 0x60 '`'
|
|
||||||
{ 982, 10, 9, 11, 0, -7 }, // 0x61 'a'
|
|
||||||
{ 994, 10, 14, 11, 0, -12 }, // 0x62 'b'
|
|
||||||
{ 1012, 10, 9, 11, 0, -7 }, // 0x63 'c'
|
|
||||||
{ 1024, 10, 14, 11, 0, -12 }, // 0x64 'd'
|
|
||||||
{ 1042, 10, 9, 11, 0, -7 }, // 0x65 'e'
|
|
||||||
{ 1054, 8, 14, 9, 0, -12 }, // 0x66 'f'
|
|
||||||
{ 1068, 10, 11, 11, 0, -7 }, // 0x67 'g'
|
|
||||||
{ 1082, 9, 14, 10, 0, -12 }, // 0x68 'h'
|
|
||||||
{ 1098, 8, 12, 9, 0, -10 }, // 0x69 'i'
|
|
||||||
{ 1110, 8, 14, 9, 0, -10 }, // 0x6a 'j'
|
|
||||||
{ 1124, 9, 14, 10, 0, -12 }, // 0x6b 'k'
|
|
||||||
{ 1140, 8, 14, 9, 0, -12 }, // 0x6c 'l'
|
|
||||||
{ 1154, 10, 9, 11, 0, -7 }, // 0x6d 'm'
|
|
||||||
{ 1166, 10, 9, 11, 0, -7 }, // 0x6e 'n'
|
|
||||||
{ 1178, 10, 9, 11, 0, -7 }, // 0x6f 'o'
|
|
||||||
{ 1190, 10, 11, 11, 0, -7 }, // 0x70 'p'
|
|
||||||
{ 1204, 10, 11, 11, 0, -7 }, // 0x71 'q'
|
|
||||||
{ 1218, 10, 9, 11, 0, -7 }, // 0x72 'r'
|
|
||||||
{ 1230, 8, 9, 9, 0, -7 }, // 0x73 's'
|
|
||||||
{ 1239, 8, 13, 9, 0, -11 }, // 0x74 't'
|
|
||||||
{ 1252, 10, 9, 11, 0, -7 }, // 0x75 'u'
|
|
||||||
{ 1264, 10, 9, 11, 0, -7 }, // 0x76 'v'
|
|
||||||
{ 1276, 10, 9, 11, 0, -7 }, // 0x77 'w'
|
|
||||||
{ 1288, 9, 9, 10, 0, -7 }, // 0x78 'x'
|
|
||||||
{ 1299, 9, 11, 10, 0, -7 }, // 0x79 'y'
|
|
||||||
{ 1312, 9, 9, 10, 0, -7 }, // 0x7a 'z'
|
|
||||||
{ 1323, 9, 15, 10, 0, -12 }, // 0x7b '{'
|
|
||||||
{ 1340, 6, 14, 7, 0, -12 }, // 0x7c '|'
|
|
||||||
{ 1351, 9, 15, 10, 0, -12 }, // 0x7d '}'
|
|
||||||
{ 1368, 10, 3, 11, 0, -10 }, // 0x7e '~'
|
|
||||||
{ 1372, 10, 8, 11, 0, -8 }, // 0x7f ''
|
|
||||||
};
|
|
||||||
const GFXfont Terminal11x16Font = {
|
|
||||||
(uint8_t *)Terminal11x16Bitmap,
|
|
||||||
(GFXglyph *)Terminal11x16Glyphs,
|
|
||||||
0x20, 0x7F, 18 };
|
|
|
@ -1,25 +0,0 @@
|
||||||
#include <inttypes.h>
|
|
||||||
#include "gfxfont.h"
|
|
||||||
|
|
||||||
#define PROGMEM
|
|
||||||
|
|
||||||
#include "FreeMono12pt8b.h"
|
|
||||||
#include "FreeMono9pt8b.h"
|
|
||||||
#include "FreeSans12pt8b.h"
|
|
||||||
#include "FreeSans18pt8b.h"
|
|
||||||
#include "FreeSans9pt8b.h"
|
|
||||||
#include "Picopixel.h"
|
|
||||||
#include "Terminal11x16.h"
|
|
||||||
|
|
||||||
__attribute__((used)) const GFXfont * const allfonts[]={
|
|
||||||
(const GFXfont *)0x544E4F46,
|
|
||||||
&Terminal11x16Font,
|
|
||||||
&Terminal11x16Font,
|
|
||||||
&FreeSans9pt8b,
|
|
||||||
&FreeSans12pt8b,
|
|
||||||
&Picopixel,
|
|
||||||
&FreeSans18pt8b,
|
|
||||||
&FreeMono9pt8b,
|
|
||||||
&FreeMono12pt8b,
|
|
||||||
0,
|
|
||||||
};
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Font structures for newer Adafruit_GFX (1.1 and later).
|
|
||||||
// Example fonts are included in 'Fonts' directory.
|
|
||||||
// To use a font in your Arduino sketch, #include the corresponding .h
|
|
||||||
// file and pass address of GFXfont struct to setFont(). Pass NULL to
|
|
||||||
// revert to 'classic' fixed-space bitmap font.
|
|
||||||
|
|
||||||
#ifndef _GFXFONT_H_
|
|
||||||
#define _GFXFONT_H_
|
|
||||||
|
|
||||||
/// Font data stored PER GLYPH
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
|
||||||
uint8_t width; ///< Bitmap dimensions in pixels
|
|
||||||
uint8_t height; ///< Bitmap dimensions in pixels
|
|
||||||
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
|
|
||||||
int8_t xOffset; ///< X dist from cursor pos to UL corner
|
|
||||||
int8_t yOffset; ///< Y dist from cursor pos to UL corner
|
|
||||||
} GFXglyph;
|
|
||||||
|
|
||||||
/// Data stored for FONT AS A WHOLE
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
|
||||||
GFXglyph *glyph; ///< Glyph array
|
|
||||||
uint8_t first; ///< ASCII extents (first char)
|
|
||||||
uint8_t last; ///< ASCII extents (last char)
|
|
||||||
uint8_t yAdvance; ///< Newline distance (y axis)
|
|
||||||
} GFXfont;
|
|
||||||
|
|
||||||
#endif // _GFXFONT_H_
|
|
|
@ -1,11 +0,0 @@
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifndef GETEPH_H
|
|
||||||
#define GETEPH_H
|
|
||||||
void geteph();
|
|
||||||
|
|
||||||
enum EPHSTATE { EPH_NOTUSED, EPH_PENDING, EPH_TIMEERR, EPH_ERROR, EPH_EPHERROR, EPH_GOOD };
|
|
||||||
|
|
||||||
extern uint8_t ephstate;
|
|
||||||
extern const char *ephtxt[];
|
|
||||||
#endif
|
|
|
@ -1,106 +0,0 @@
|
||||||
#include "json.h"
|
|
||||||
#include "RS41.h"
|
|
||||||
|
|
||||||
extern const char *sondeTypeStrSH[];
|
|
||||||
extern const char *dfmSubtypeStrSH[];
|
|
||||||
|
|
||||||
static char typestr[11];
|
|
||||||
|
|
||||||
const char *getType(SondeInfo *si) {
|
|
||||||
if( si->type == STYPE_RS41 ) {
|
|
||||||
if ( RS41::getSubtype(typestr, 11, si) == 0 ) return typestr;
|
|
||||||
} else if ( TYPE_IS_DFM(si->type) && si->d.subtype > 0 && si->d.subtype < 16 ) {
|
|
||||||
const char *t = dfmSubtypeStrSH[si->d.subtype];
|
|
||||||
if(t) return t;
|
|
||||||
sprintf(typestr, "DFMx%X", si->d.subtype);
|
|
||||||
return typestr;
|
|
||||||
}
|
|
||||||
return sondeTypeStrSH[sonde.realType(si)];
|
|
||||||
}
|
|
||||||
|
|
||||||
int float2json(char **buf, int *maxlen, const char *fmt, float value) {
|
|
||||||
if(isnan(value)) return 0;
|
|
||||||
int n = snprintf(*buf, *maxlen, fmt, value);
|
|
||||||
if(n>*maxlen) return -1;
|
|
||||||
*buf += n; *maxlen -= n;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To be used by
|
|
||||||
// - MQTT
|
|
||||||
// - rdzJSON (for Android app)
|
|
||||||
// - Web map
|
|
||||||
int sonde2json(char *buf, int maxlen, SondeInfo *si)
|
|
||||||
{
|
|
||||||
SondeData *s = &(si->d);
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = float2json(&buf, &maxlen, "\"lat\": %.5f,", s->lat);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"lon\": %.5f,", s->lon);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"alt\": %.1f,", s->alt);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"vs\": %.1f,", s->vs);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"hs\": %.1f,", s->hs);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"climb\": %.1f,", s->vs); // used by HTML map, to be removed (-> vs)
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"speed\": %.1f,", s->hs); // used by HTML map, to be removed (-> hs)
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"dir\": %.1f,", s->dir);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"temp\": %.1f,", s->temperature );
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"humidity\": %.1f,", s->relativeHumidity);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = float2json(&buf, &maxlen, "\"pressure\": %.1f,", s->pressure);
|
|
||||||
if(n<0) return -1;
|
|
||||||
n = snprintf(buf, maxlen,
|
|
||||||
"\"type\":\"%s\","
|
|
||||||
"\"id\": \"%s\"," // TODO: maybe remove in the future, ser is enough, client can calculate APRS id if needed
|
|
||||||
"\"ser\": \"%s\","
|
|
||||||
"\"frame\": %u," // raw frame, from sonde, can be 0. (TODO: add virtual frame # as in sondehub?)
|
|
||||||
"\"vframe\": %d,"
|
|
||||||
"\"time\": %u,"
|
|
||||||
"\"sats\": %d,"
|
|
||||||
"\"freq\": %.2f,"
|
|
||||||
"\"rssi\": %d,"
|
|
||||||
"\"afc\": %d,"
|
|
||||||
"\"launchKT\": %d,"
|
|
||||||
"\"burstKT\": %d,"
|
|
||||||
"\"countKT\": %d,"
|
|
||||||
"\"crefKT\": %d,"
|
|
||||||
"\"launchsite\": \"%s\","
|
|
||||||
"\"res\": %d",
|
|
||||||
getType(si),
|
|
||||||
s->id,
|
|
||||||
s->ser,
|
|
||||||
s->frame,
|
|
||||||
s->vframe,
|
|
||||||
s->time,
|
|
||||||
s->sats,
|
|
||||||
si->freq,
|
|
||||||
si->rssi,
|
|
||||||
si->afc,
|
|
||||||
s->launchKT,
|
|
||||||
s->burstKT,
|
|
||||||
s->countKT,
|
|
||||||
s->crefKT,
|
|
||||||
si->launchsite,
|
|
||||||
(int)si->rxStat[0]
|
|
||||||
);
|
|
||||||
if(n>=maxlen) return -1;
|
|
||||||
buf += n; maxlen -= n;
|
|
||||||
|
|
||||||
// add only if available
|
|
||||||
if(s->batteryVoltage > 0) {
|
|
||||||
n = snprintf(buf, maxlen, ",\"batt\": %.1f", s->batteryVoltage);
|
|
||||||
if(n>=maxlen) return -1;
|
|
||||||
buf += n; maxlen -= n;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef _JSON_H
|
|
||||||
#define _JSON_H
|
|
||||||
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
int sonde2json(char *buf, int maxlen, SondeInfo *si);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
|
|
||||||
"dependencies":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"owner": "olikraus",
|
|
||||||
"name": "U8g2",
|
|
||||||
"version": "^2.28.8"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,165 +0,0 @@
|
||||||
#include <Arduino.h>
|
|
||||||
#include "mqtt.h"
|
|
||||||
#include <WiFi.h>
|
|
||||||
//#include <AsyncMqttClient.h>
|
|
||||||
#include <AsyncMqtt_Generic.h>
|
|
||||||
#include <ESPmDNS.h>
|
|
||||||
#include "RS41.h"
|
|
||||||
#include "json.h"
|
|
||||||
|
|
||||||
extern const char *version_name;
|
|
||||||
extern const char *version_id;
|
|
||||||
|
|
||||||
TimerHandle_t mqttReconnectTimer;
|
|
||||||
|
|
||||||
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
||||||
Serial.print("Message arrived [");
|
|
||||||
Serial.print(topic);
|
|
||||||
Serial.print("] ");
|
|
||||||
for (int i=0;i<length;i++) {
|
|
||||||
Serial.print((char)payload[i]);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
static char buffer[21];
|
|
||||||
void MQTT::init(const char* host, uint16_t port, const char* id, const char *username, const char *password, const char *prefix)
|
|
||||||
{
|
|
||||||
WiFi.hostByName(host, this->ip);
|
|
||||||
this->port = port;
|
|
||||||
this->username = username;
|
|
||||||
this->password = password;
|
|
||||||
this->prefix = prefix;
|
|
||||||
|
|
||||||
Serial.println("[MQTT] pubsub client");
|
|
||||||
mqttClient.setServer(ip, port);
|
|
||||||
snprintf(buffer, 20, "%s%04d", id, (int)random(0, 1000));
|
|
||||||
buffer[20] = 0;
|
|
||||||
Serial.print(buffer);
|
|
||||||
mqttClient.setClientId(buffer);
|
|
||||||
if (strlen(password) > 0) {
|
|
||||||
mqttClient.setCredentials(username, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::connectToMqtt() {
|
|
||||||
Serial.println("Connecting to MQTT...");
|
|
||||||
mqttClient.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publishUptime()
|
|
||||||
{
|
|
||||||
mqttClient.connect(); // ensure we've got connection
|
|
||||||
|
|
||||||
Serial.println("[MQTT] writing");
|
|
||||||
char payload[256];
|
|
||||||
// maybe TODO: Use dynamic position if GPS is available?
|
|
||||||
// rxlat, rxlon only if not empty
|
|
||||||
snprintf(payload, 256, "{\"uptime\": %lu, \"user\": \"%s\", ", millis(), username);
|
|
||||||
if( !isnan(sonde.config.rxlat) && !isnan(sonde.config.rxlon) ) {
|
|
||||||
snprintf(payload, 256, "%s\"rxlat\": %.5f, \"rxlon\": %.5f, ", payload, sonde.config.rxlat, sonde.config.rxlon);
|
|
||||||
}
|
|
||||||
snprintf(payload, 256, "%s\"SW\": \"%s\", \"VER\": \"%s\"}", payload, version_name, version_id);
|
|
||||||
Serial.println(payload);
|
|
||||||
char topic[128];
|
|
||||||
snprintf(topic, 128, "%s%s", this->prefix, "uptime");
|
|
||||||
mqttClient.publish(topic, 1, 1, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publishPacket(SondeInfo *si)
|
|
||||||
{
|
|
||||||
SondeData *s = &(si->d);
|
|
||||||
mqttClient.connect(); // ensure we've got connection
|
|
||||||
|
|
||||||
char payload[1024];
|
|
||||||
payload[0] = '{';
|
|
||||||
int n = sonde2json(payload+1, 1023, si);
|
|
||||||
if(n<0) {
|
|
||||||
// ERROR
|
|
||||||
Serial.println("publishPacket: sonde2json failed, string too long");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
snprintf(payload, 1024, "{"
|
|
||||||
"\"active\": %d,"
|
|
||||||
"\"freq\": %.2f,"
|
|
||||||
"\"id\": \"%s\","
|
|
||||||
"\"ser\": \"%s\","
|
|
||||||
"\"validId\": %d,"
|
|
||||||
"\"launchsite\": \"%s\","
|
|
||||||
"\"lat\": %.5f,"
|
|
||||||
"\"lon\": %.5f,"
|
|
||||||
"\"alt\": %.1f,"
|
|
||||||
"\"vs\": %.1f,"
|
|
||||||
"\"hs\": %.1f,"
|
|
||||||
"\"dir\": %.1f,"
|
|
||||||
"\"sats\": %d,"
|
|
||||||
"\"validPos\": %d,"
|
|
||||||
"\"time\": %u,"
|
|
||||||
"\"frame\": %u,"
|
|
||||||
"\"validTime\": %d,"
|
|
||||||
"\"rssi\": %d,"
|
|
||||||
"\"afc\": %d,"
|
|
||||||
"\"rxStat\": \"%s\","
|
|
||||||
"\"rxStart\": %u,"
|
|
||||||
"\"norxStart\": %u,"
|
|
||||||
"\"viewStart\": %u,"
|
|
||||||
"\"lastState\": %d,"
|
|
||||||
"\"launchKT\": %d,"
|
|
||||||
"\"burstKT\": %d,"
|
|
||||||
"\"countKT\": %d,"
|
|
||||||
"\"crefKT\": %d",
|
|
||||||
(int)si->active,
|
|
||||||
si->freq,
|
|
||||||
s->id,
|
|
||||||
s->ser,
|
|
||||||
(int)s->validID,
|
|
||||||
si->launchsite,
|
|
||||||
s->lat,
|
|
||||||
s->lon,
|
|
||||||
s->alt,
|
|
||||||
s->vs,
|
|
||||||
s->hs,
|
|
||||||
s->dir,
|
|
||||||
s->sats,
|
|
||||||
s->validPos,
|
|
||||||
s->time,
|
|
||||||
s->frame,
|
|
||||||
(int)s->validTime,
|
|
||||||
si->rssi,
|
|
||||||
si->afc,
|
|
||||||
si->rxStat,
|
|
||||||
si->rxStart,
|
|
||||||
si->norxStart,
|
|
||||||
si->viewStart,
|
|
||||||
si->lastState,
|
|
||||||
s->launchKT,
|
|
||||||
s->burstKT,
|
|
||||||
s->countKT,
|
|
||||||
s->crefKT
|
|
||||||
);
|
|
||||||
if ( !isnan( s->temperature ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"temp\": ", s->temperature );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->relativeHumidity ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"humidity\": ", s->relativeHumidity );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->pressure ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"pressure\": ", s->pressure );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->batteryVoltage && s->batteryVoltage > 0 ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"batt\": ", s->batteryVoltage );
|
|
||||||
}
|
|
||||||
char subtype[11];
|
|
||||||
if ( RS41::getSubtype( subtype, 11, si) == 0 ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%s%s", payload, ",\"subtype\": \"", subtype, "\"" );
|
|
||||||
}
|
|
||||||
snprintf(payload, 1024, "%s%s", payload, "}" ); // terminate payload string
|
|
||||||
#endif
|
|
||||||
strcat(payload, "}"); // terminate payload string
|
|
||||||
|
|
||||||
char topic[128];
|
|
||||||
snprintf(topic, 128, "%s%s", this->prefix, "packet");
|
|
||||||
Serial.print(payload);
|
|
||||||
mqttClient.publish(topic, 1, 1, payload);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#ifndef MQTT_h
|
|
||||||
#define MQTT_h
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
//#include <AsyncMqttClient.h>
|
|
||||||
#include <AsyncMqtt_Generic.h>
|
|
||||||
#include "Sonde.h"
|
|
||||||
#include "RS41.h"
|
|
||||||
|
|
||||||
class MQTT
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WiFiClient mqttWifiClient;
|
|
||||||
AsyncMqttClient mqttClient;
|
|
||||||
TimerHandle_t mqttReconnectTimer;
|
|
||||||
IPAddress ip;
|
|
||||||
uint16_t port;
|
|
||||||
const char *username;
|
|
||||||
const char *password;
|
|
||||||
const char *prefix;
|
|
||||||
|
|
||||||
void init(const char *host, uint16_t port, const char *id, const char *username, const char *password, const char *prefix);
|
|
||||||
void publishPacket(SondeInfo *s);
|
|
||||||
void publishUptime();
|
|
||||||
private:
|
|
||||||
void connectToMqtt();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Binary file not shown.
|
@ -1,4 +0,0 @@
|
||||||
const char *version_name = "RadioSonde";
|
|
||||||
const char *version_id = "1.0.0";
|
|
||||||
const int SPIFFS_MAJOR=1;
|
|
||||||
const int SPIFFS_MINOR=0;
|
|
2412
RadioSonde_FSK/RadioSonde_FSK.ino
Executable file
2412
RadioSonde_FSK/RadioSonde_FSK.ino
Executable file
File diff suppressed because it is too large
Load Diff
93
RX_FSK/data/config.txt → RadioSonde_FSK/data/config.txt
Normal file → Executable file
93
RX_FSK/data/config.txt → RadioSonde_FSK/data/config.txt
Normal file → Executable file
|
@ -2,8 +2,8 @@
|
||||||
# Hardware depending settings
|
# Hardware depending settings
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# pin: 255=disabled; x=button x+128=touch button
|
# pin: 255=disabled; x=button x+128=touch button
|
||||||
#button_pin=130
|
button_pin=2
|
||||||
#button2_pin=142
|
button2_pin=4
|
||||||
# No specification in config file: try autodetection (gpio4 pin level at startup)
|
# No specification in config file: try autodetection (gpio4 pin level at startup)
|
||||||
#button_pin=0
|
#button_pin=0
|
||||||
#button2_pin=255
|
#button2_pin=255
|
||||||
|
@ -22,12 +22,15 @@
|
||||||
#oled_sda=21
|
#oled_sda=21
|
||||||
#oled_scl=22
|
#oled_scl=22
|
||||||
#oled_rst=16
|
#oled_rst=16
|
||||||
rxlat=
|
|
||||||
rxlon=
|
|
||||||
rxalt=
|
|
||||||
oled_orient=1
|
oled_orient=1
|
||||||
#gps_rxd=-1
|
gpsOn=0
|
||||||
#gps_txd=-1
|
gps_rxd=-1
|
||||||
|
gps_txd=-1
|
||||||
|
gps_lat=43.59169
|
||||||
|
gps_lon=7.10071
|
||||||
|
gps_alt=123
|
||||||
|
# Show AFC value (for RS41 only, maybe also DFM, but useful for RS92 or M10)
|
||||||
|
# showafc=1
|
||||||
# Frequency correction, in Hz
|
# Frequency correction, in Hz
|
||||||
# freqofs=0
|
# freqofs=0
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
|
@ -39,24 +42,19 @@ debug=0
|
||||||
wifi=3
|
wifi=3
|
||||||
# TCP/IP KISS TNC in port 14590 for APRSdroid (0=disabled, 1=enabled)
|
# TCP/IP KISS TNC in port 14590 for APRSdroid (0=disabled, 1=enabled)
|
||||||
kisstnc.active = 1
|
kisstnc.active = 1
|
||||||
|
mdnsname=radiosonde
|
||||||
# which screens file to use (0: automated selection based on display type and orientation, i>0: screens${i}.txt
|
|
||||||
# predefined: 1: for OLED, 2: for ILI9225; 3: for ILI9225 (portrait mode); 4: for ILI9431; 5: for ILI9431 (portrait mode)
|
|
||||||
# screenfile=2
|
|
||||||
# display configuration. List of "displays"
|
# display configuration. List of "displays"
|
||||||
# first entry: "Scanner" display
|
# first entry: "Scanner" display
|
||||||
# second entry: default "Receiver" display
|
# second entry: default "Receiver" display
|
||||||
# additional entries: alternative receiver display, activated by button
|
# additional entries: alternative receiver display, activated by button
|
||||||
display=0,1,2,3,4,5,6,7
|
display=0,1,2,3,4,5,6
|
||||||
# turn off display: 0=never, 1=always, 2=if no RX; (+n*10: after n seconds)
|
|
||||||
dispsaver=0
|
|
||||||
# set OLED contrast (0..255) or leave at factory default (-1)
|
|
||||||
dispcontrast=-1
|
|
||||||
# set to -1 to disable (used for "N" values in timers in screens.txt). Value in seconds
|
# set to -1 to disable (used for "N" values in timers in screens.txt). Value in seconds
|
||||||
norx_timeout=20
|
norx_timeout=20
|
||||||
#Add F4IYT
|
vbatmax=1.86
|
||||||
buzzerOn=1
|
vbatmin=1.64
|
||||||
buzzerPort=25
|
sdOn=0
|
||||||
|
buzzerOn=0
|
||||||
|
buzzerPort=12
|
||||||
buzzerFreq=700
|
buzzerFreq=700
|
||||||
dbsmetre=1
|
dbsmetre=1
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
|
@ -64,14 +62,14 @@ dbsmetre=1
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
startfreq=400
|
startfreq=400
|
||||||
channelbw=10
|
channelbw=10
|
||||||
spectrum=-1 #10
|
spectrum=30 #10
|
||||||
noisefloor=-125
|
noisefloor=-125
|
||||||
marker=1
|
marker=1
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# APRS settings
|
# APRS settings
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
call=N0CALL
|
call=NOCALL
|
||||||
passcode=12345
|
passcode=123456
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# Sonde specific settings: bandwidth
|
# Sonde specific settings: bandwidth
|
||||||
# valid values: 3100, 3900, 5200, 6300, 7800, 10400, 12500,
|
# valid values: 3100, 3900, 5200, 6300, 7800, 10400, 12500,
|
||||||
|
@ -86,65 +84,26 @@ rs92.alt2d=480
|
||||||
dfm.agcbw=20800
|
dfm.agcbw=20800
|
||||||
dfm.rxbw=10400
|
dfm.rxbw=10400
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# ftp server for RINEX data (for RS92)
|
|
||||||
# YYYY/DDD/brdcDDD0.YYn.gz is appended
|
|
||||||
# s1: igs.bkg.bund.de/IGS/BRDC/
|
|
||||||
# s2: www.ngs.noaa.gov/cors/rinex/
|
|
||||||
#-------------------------------#
|
|
||||||
#ephftp=www.ngs.noaa.gov/cors/rinex/
|
|
||||||
#ephftp=igs.bkg.bund.de/IGS/BRDC/
|
|
||||||
ephftp=gssc.esa.int/gnss/data/daily/
|
|
||||||
#-------------------------------#
|
|
||||||
# axudp for sending to aprsmap
|
# axudp for sending to aprsmap
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# local use only, do not feed to public services
|
# local use only, do not feed to public services
|
||||||
# data not sanitized / quality checked, outliers not filtered out
|
# data not sanitized / quality checked, outliers not filtered out
|
||||||
axudp.active=1
|
axudp.active=1
|
||||||
axudp.host=192.168.42.20
|
axudp.host=monurl.fr
|
||||||
axudp.port=9002
|
axudp.port=14580
|
||||||
axudp.symbol=/O
|
axudp.symbol=/O
|
||||||
axudp.highrate=1
|
axudp.highrate=1
|
||||||
|
axudp.idformat=0
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# connect to some aprs server
|
# maybe some time in the future
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
|
# currently simply not implemented, no need to put anything here anyway
|
||||||
tcp.active=0
|
tcp.active=0
|
||||||
tcp.host=radiosondy.info
|
tcp.host=radiosondy.info
|
||||||
tcp.port=14590
|
tcp.port=14590
|
||||||
tcp.symbol=/O
|
tcp.symbol=/O
|
||||||
tcp.highrate=20
|
tcp.highrate=20
|
||||||
# send beacon (possibly with different call or SSID)
|
tcp.idformat=0
|
||||||
tcp.chase=0
|
|
||||||
tcp.objcall=
|
|
||||||
tcp.beaconsym=/`/(
|
|
||||||
tcp.comment=
|
|
||||||
#-------------------------------#
|
|
||||||
# mqtt settings
|
|
||||||
#-------------------------------#
|
|
||||||
# data not sanitized / quality checked, outliers not filtered out
|
|
||||||
mqtt.active=0
|
|
||||||
mqtt.id=rdz_sonde_server
|
|
||||||
mqtt.ip=192.168.1.5
|
|
||||||
mqtt.port=1883
|
|
||||||
mqtt.username=
|
|
||||||
mqtt.password=
|
|
||||||
mqtt.prefix=rdz_sonde_server/
|
|
||||||
#-------------------------------#
|
|
||||||
# Sondehub v2 settings
|
|
||||||
#-------------------------------#
|
|
||||||
# Sondehub v2 DB settings
|
|
||||||
sondehub.active=0
|
|
||||||
sondehub.chase=3
|
|
||||||
sondehub.host=api.v2.sondehub.org
|
|
||||||
sondehub.callsign=CHANGEME_RDZTTGO
|
|
||||||
sondehub.antenna=
|
|
||||||
sondehub.email=
|
|
||||||
#-------------------------------#
|
|
||||||
# Sondehub freq import settings
|
|
||||||
#-------------------------------#
|
|
||||||
shfimp.active=0
|
|
||||||
shfimp.interval=60
|
|
||||||
shfimp.maxdist=150
|
|
||||||
shfimp.maxage=6
|
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# EOF
|
# EOF
|
||||||
#-------------------------------#
|
#-------------------------------#
|
|
@ -23,8 +23,7 @@
|
||||||
<button class="tablinks fa fa-dashboard" onclick="selTab(event,'QRG'); w3_close()" id="defaultTab"> QRG</button><br>
|
<button class="tablinks fa fa-dashboard" onclick="selTab(event,'QRG'); w3_close()" id="defaultTab"> QRG</button><br>
|
||||||
<button class="tablinks fa fa-wifi" onclick="selTab(event,'WiFi'); w3_close()"> WiFi</button><br>
|
<button class="tablinks fa fa-wifi" onclick="selTab(event,'WiFi'); w3_close()"> WiFi</button><br>
|
||||||
<button class="tablinks fa fa-database" onclick="selTab(event,'Data'); w3_close()"> Data</button><br>
|
<button class="tablinks fa fa-database" onclick="selTab(event,'Data'); w3_close()"> Data</button><br>
|
||||||
<button class="tablinks fa fa-map-marker" onclick="selTab(event,'Map'); w3_close()"> Map</button><br>
|
<button class="tablinks fa fa-map-marker" onclick="selTab(event,'SondeMap'); w3_close()"> URL SondeMap</button><br>
|
||||||
<button class="tablinks fa fa-map-marker" onclick="document.location.href='livemap.html'"> Livemap</button><br>
|
|
||||||
<button class="tablinks fa fa-gears" onclick="selTab(event,'Config'); w3_close()"> Config</button><br>
|
<button class="tablinks fa fa-gears" onclick="selTab(event,'Config'); w3_close()"> Config</button><br>
|
||||||
<button class="tablinks fa fa-sliders" onclick="selTab(event,'Control'); w3_close()"> Control</button><br>
|
<button class="tablinks fa fa-sliders" onclick="selTab(event,'Control'); w3_close()"> Control</button><br>
|
||||||
<button class="tablinks fa fa-download" onclick="selTab(event,'Update'); w3_close()"> Update</button><br>
|
<button class="tablinks fa fa-download" onclick="selTab(event,'Update'); w3_close()"> Update</button><br>
|
||||||
|
@ -46,14 +45,20 @@
|
||||||
<iframe src="status.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
<iframe src="status.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="Map" class="tabcontent" data-src="map.html">
|
<div id="SondeMap" class="tabcontent" data-src="sondemap.html">
|
||||||
<iframe src="map.html" style="border:none;" width="98%%" height="98%%"></iframe>
|
<iframe src="sondemap.html" style="border:none;" width="98%%" height="98%%"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<div id="LiveMap" class="tabcontent" data-src="livemap.html">
|
<div id="SondeMap" class="tabcontent" data-src="http://wx.dl2mf.de/#?">
|
||||||
<iframe src="livemap.html" style="border:none;" width="98%%" height="98%%"></iframe>
|
<iframe src="http://wx.dl2mf.de/" style="border:none;" width="98%%" height="98%%"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="SondeMap2" class="tabcontent" data-src="https://radiosondy.info/">
|
||||||
|
<iframe src="https://radiosondy.info/" style="border:none;" width="98%%" height="98%%"></iframe>
|
||||||
|
</div>
|
||||||
|
<div id="SondeMap3" class="tabcontent" data-src="https://tracker.sondehub.org/?sondehub=1#!mt=osm&mz=8&qm=6_hours&mc=43.76665,6.24011&f=none&q=RS_*;*chase">
|
||||||
|
<iframe src="https://tracker.sondehub.org/?sondehub=1#!mt=osm&mz=8&qm=6_hours&mc=43.76665,6.24011&f=none&q=RS_*;*chase" style="border:none;" width="98%%" height="98%%"></iframe>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
<div id="Config" class="tabcontent">
|
<div id="Config" class="tabcontent">
|
||||||
<h3>Configuration</h3>
|
<h3>Configuration</h3>
|
||||||
<iframe src="config.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
<iframe src="config.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
||||||
|
@ -68,34 +73,23 @@
|
||||||
<h3>Update</h3>
|
<h3>Update</h3>
|
||||||
<iframe src="update.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
<iframe src="update.html" style="border:none;" width="100%%" height="100%%"></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div id="Telemetry" class="tabcontent">
|
|
||||||
<h3>Telemetry</h3>
|
|
||||||
<button onclick="javascript:window.open('/download','_self');">Telemetry</button>
|
|
||||||
</div>
|
|
||||||
<div id="About" class="tabcontent">
|
<div id="About" class="tabcontent">
|
||||||
|
<h3>About</h3>
|
||||||
%VERSION_NAME%<br>
|
%VERSION_NAME%<br>
|
||||||
CopyLeft 2020-2022 Modifier par <a href="http://openpmr.fr.nf/">Xav, FRS2013</a> & Vigor<br>
|
Copyright © 2019 by Hansi Reiser, DL9RDZ<br>
|
||||||
<a href="#Update">Check for update (requires TTGO internet connection via WiFi)</a><br><br>
|
(version %VERSION_ID%)<br>
|
||||||
<br>
|
with mods by <a href="https://www.dl2mf.de/" target="_blank">Meinhard Guenther, DL2MF</a><br>
|
||||||
(version %VERSION_ID%)
|
|
||||||
<br>
|
<br>
|
||||||
Original project by Hansi<br>
|
|
||||||
Copyright © 2019-2022 by Hansi Reiser, DL9RDZ<br>
|
|
||||||
<br><br>
|
|
||||||
Autodetect info: %AUTODETECT_INFO%<br>
|
Autodetect info: %AUTODETECT_INFO%<br>
|
||||||
<br>
|
<br>
|
||||||
RS92 RINEX eph state: %EPHSTATE%<br>
|
CopyLeft 2020 Modifier par <a href="http://openpmr.cla.fr">FRS2013</a><br>
|
||||||
<br>
|
Licence GNU GPL <a href="https://www.gnu.org/licenses/gpl-2.0.txt">https://www.gnu.org/licenses/gpl-2.0.txt</a>
|
||||||
This program is free software; you can redistribute it and/or
|
for details
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of
|
|
||||||
the License, or (at your option) any later version.<br>
|
|
||||||
See <a href="https://www.gnu.org/licenses/gpl-2.0.txt">https://www.gnu.org/licenses/gpl-2.0.txt</a>
|
|
||||||
for details.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="background-color: #008CBA;"><br>
|
<div style="background-color: #008CBA;"><br>
|
||||||
<div class="footer"><span></span><span class="ttgoinfo">RadioSonde %VERSION_ID%</span></div>
|
<h2>by FRS2013</h2>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
function selTab(evt, id) {
|
function selTab(evt, id) {
|
4
RadioSonde_FSK/data/networks.txt
Executable file
4
RadioSonde_FSK/data/networks.txt
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
Radiosonde
|
||||||
|
Radiosonde
|
||||||
|
VotreSSID
|
||||||
|
votrepass
|
24
RadioSonde_FSK/data/qrg.txt
Executable file
24
RadioSonde_FSK/data/qrg.txt
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
# Frequency in Mhz (format nnn.nnn)
|
||||||
|
# Type (4=RS41, R=RS92, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09, M=M10)
|
||||||
|
#
|
||||||
|
400.000 9 + Test(FR)
|
||||||
|
401.500 4 - Santander(ES)
|
||||||
|
402.000 M + Nimes(FR)
|
||||||
|
402.800 4 + Cuneo(IT)
|
||||||
|
403.000 6 + Ajactio(FR)
|
||||||
|
403.010 6 + Canjuers(FR)
|
||||||
|
404.200 4 + Rome(IT)
|
||||||
|
404.500 4 - Payern(CH)
|
||||||
|
404.500 M - Bourges(FR)
|
||||||
|
404.789 9 + Frejus1(FR)
|
||||||
|
404.800 4 + Milan(IT)
|
||||||
|
405.000 R + Frejus2(FR)
|
||||||
|
401.199 M - Trappes(FR)
|
||||||
|
405.789 9 + Pegomas(FR)
|
||||||
|
405.100 4 - Lindenberg
|
||||||
|
405.700 4 - Bergen
|
||||||
|
405.900 4 - Bergen_2
|
||||||
|
405.100 4 - Meppen_2
|
||||||
|
405.300 4 - Essen
|
||||||
|
405.500 4 - Essen_2
|
||||||
|
# end
|
142
RX_FSK/data/screens1.txt → RadioSonde_FSK/data/screens.txt
Normal file → Executable file
142
RX_FSK/data/screens1.txt → RadioSonde_FSK/data/screens.txt
Normal file → Executable file
|
@ -1,4 +1,3 @@
|
||||||
### screens1.txt: OLED display
|
|
||||||
# Definition of display content and action behaviour
|
# Definition of display content and action behaviour
|
||||||
#
|
#
|
||||||
# Timer: (view timer, rx timer, norx timer)
|
# Timer: (view timer, rx timer, norx timer)
|
||||||
|
@ -33,10 +32,7 @@
|
||||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
||||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
# Ix sonde ID (dfm format by x: d=>dxlaprs, a=>autorx, s=>real serial number)
|
||||||
# RS41,RS92: all identical R1234567
|
|
||||||
# DFMx: ID M12345678; short ID and serial 12345678
|
|
||||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
|
||||||
# Q signal quality statistics bar
|
# Q signal quality statistics bar
|
||||||
# T type string (RS41/DFM9/DFM6/RS92)
|
# T type string (RS41/DFM9/DFM6/RS92)
|
||||||
# C afC value
|
# C afC value
|
||||||
|
@ -44,7 +40,7 @@
|
||||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
||||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
||||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
||||||
# Mx telemetry value x (t temp p preassure h hyg b battery)
|
# Mx telemetry value x (t temp p preassure h hyg) [not yet implemented, maybe some day in future]
|
||||||
# Gx GPS-related data
|
# Gx GPS-related data
|
||||||
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground
|
||||||
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
# relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing
|
||||||
|
@ -58,6 +54,7 @@
|
||||||
# R RSSI
|
# R RSSI
|
||||||
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current
|
||||||
# U=USB volt I=USB current T=IC temp
|
# U=USB volt I=USB current T=IC temp
|
||||||
|
# AA Azimut degres
|
||||||
#
|
#
|
||||||
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
# fonts=x,y can be used to select font (x=small, y=large) for all items below
|
||||||
# for SSD1306, x and y can be used to select one of those fonts:
|
# for SSD1306, x and y can be used to select one of those fonts:
|
||||||
|
@ -81,15 +78,6 @@
|
||||||
# u8x8_font_pxplusibmcga_f, // 16
|
# u8x8_font_pxplusibmcga_f, // 16
|
||||||
# u8x8_font_pxplustandynewtv_f, // 17
|
# u8x8_font_pxplustandynewtv_f, // 17
|
||||||
#
|
#
|
||||||
# for ILI9225, these fonts are available:
|
|
||||||
# Terminal6x8 // 0
|
|
||||||
# Terminal11x16 // 1
|
|
||||||
# Terminal12x16 // 2
|
|
||||||
# FreeMono9pt7b, // 3
|
|
||||||
# FreeMono12pt7b, // 4
|
|
||||||
# FreeSans9pt7b, // 5
|
|
||||||
# FreeSans12pt7b, // 6
|
|
||||||
# Picopixel, // 7
|
|
||||||
#
|
#
|
||||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
||||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
||||||
|
@ -109,15 +97,14 @@
|
||||||
@Scanner
|
@Scanner
|
||||||
timer=-1,0,0
|
timer=-1,0,0
|
||||||
key1action=D,#,F,W
|
key1action=D,#,F,W
|
||||||
key2action=D,#,#,#
|
key2action=#,#,#,#
|
||||||
timeaction=#,D,+
|
timeaction=#,D,+
|
||||||
0,0=XScan
|
0,0=XScan
|
||||||
0,5=S#:
|
0,5=S#:
|
||||||
0,9=T
|
0,9=T
|
||||||
3,0=F MHz
|
3,0=F MHz
|
||||||
5,0,16=S
|
5,0=S
|
||||||
7,0=bVV
|
7,0=y%
|
||||||
#7,0=gV
|
|
||||||
7,5=n
|
7,5=n
|
||||||
|
|
||||||
############
|
############
|
||||||
|
@ -137,17 +124,22 @@ timer=-1,-1,N
|
||||||
key1action=+,0,F,W
|
key1action=+,0,F,W
|
||||||
key2action=>,#,#,#
|
key2action=>,#,#,#
|
||||||
timeaction=#,#,0
|
timeaction=#,#,0
|
||||||
0,5=f MHz
|
|
||||||
1,8=c
|
|
||||||
0,0=t
|
0,0=t
|
||||||
|
0,5=f MHz
|
||||||
1,0=is
|
1,0=is
|
||||||
|
1,8=c
|
||||||
2,0=L
|
2,0=L
|
||||||
4,0=O
|
|
||||||
2,10=a
|
2,10=a
|
||||||
3,10=h
|
3,10=h
|
||||||
|
4,0=O
|
||||||
4,9=v
|
4,9=v
|
||||||
|
5,9=gC
|
||||||
|
5,13=gB
|
||||||
6,0=R
|
6,0=R
|
||||||
6,7=Q
|
6,7=Q
|
||||||
|
7,6=gD
|
||||||
|
7,12=gI°
|
||||||
|
|
||||||
|
|
||||||
############
|
############
|
||||||
# Configuratoon for "Field" display (display 2)
|
# Configuratoon for "Field" display (display 2)
|
||||||
|
@ -157,13 +149,19 @@ timer=-1,-1,N
|
||||||
key1action=+,0,F,W
|
key1action=+,0,F,W
|
||||||
key2action=>,#,#,#
|
key2action=>,#,#,#
|
||||||
timeaction=#,#,#
|
timeaction=#,#,#
|
||||||
|
0,0=Is
|
||||||
2,0=L
|
2,0=L
|
||||||
|
2,9=xEl:
|
||||||
|
2,12=gE
|
||||||
4,0=O
|
4,0=O
|
||||||
3,10=h
|
3,10=h
|
||||||
4,9=v
|
4,9=v
|
||||||
0,0=Is
|
5,9=gC
|
||||||
|
5,13=gB
|
||||||
6,0=A
|
6,0=A
|
||||||
6,7=Q
|
6,7=Q
|
||||||
|
7,6=gD
|
||||||
|
7,12=gI°
|
||||||
|
|
||||||
############
|
############
|
||||||
# Configuration for "Field2" display (display 3)
|
# Configuration for "Field2" display (display 3)
|
||||||
|
@ -173,15 +171,21 @@ timer=-1,-1,N
|
||||||
key1action=+,0,F,W
|
key1action=+,0,F,W
|
||||||
key2action=>,#,#,#
|
key2action=>,#,#,#
|
||||||
timeaction=#,#,#
|
timeaction=#,#,#
|
||||||
2,0=L
|
|
||||||
4,0=O
|
|
||||||
1,12=t
|
|
||||||
0,9=f
|
|
||||||
3,10=h
|
|
||||||
4,9=v
|
|
||||||
0,0=Is
|
0,0=Is
|
||||||
|
0,9=f
|
||||||
|
1,12=t
|
||||||
|
2,9=xEl:
|
||||||
|
2,12=gE
|
||||||
|
2,0=L
|
||||||
|
3,10=h
|
||||||
|
4,0=O
|
||||||
|
4,9=v
|
||||||
|
5,9=gC
|
||||||
|
5,13=gB
|
||||||
6,0=A
|
6,0=A
|
||||||
6,7=Q
|
6,7=Q
|
||||||
|
7,6=gD
|
||||||
|
7,12=gI°
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# Configuration for "GPS" display
|
# Configuration for "GPS" display
|
||||||
|
@ -201,11 +205,32 @@ timeaction=#,#,#
|
||||||
4,9=v
|
4,9=v
|
||||||
5,9=gC
|
5,9=gC
|
||||||
5,13=gB
|
5,13=gB
|
||||||
|
6,0=xEl:
|
||||||
|
6,2=gE
|
||||||
6,7=Q
|
6,7=Q
|
||||||
7,0=gV
|
7,0=gW
|
||||||
7,2=xd=
|
7,2=xd=
|
||||||
7,4=gD
|
7,4=gD
|
||||||
7,12=gI°
|
7,11=gI°
|
||||||
|
|
||||||
|
############
|
||||||
|
# Boussole Oled
|
||||||
|
@BOUSSOLE
|
||||||
|
timer=-1,-1,-1
|
||||||
|
key1action=+,0,F,W
|
||||||
|
key2action=>,#,#,#
|
||||||
|
timeaction=#,#,#
|
||||||
|
0,0=g0
|
||||||
|
0,10=a
|
||||||
|
1,10=h
|
||||||
|
2,9=v
|
||||||
|
3,10=gC
|
||||||
|
3,13=gB
|
||||||
|
4,9=gD
|
||||||
|
5,11=gI°
|
||||||
|
6,9=xEl:
|
||||||
|
6,11=gE
|
||||||
|
7,9=t
|
||||||
|
|
||||||
############
|
############
|
||||||
@BatteryOLED
|
@BatteryOLED
|
||||||
|
@ -215,53 +240,10 @@ key2action=>,#,#,#
|
||||||
timeaction=#,#,#
|
timeaction=#,#,#
|
||||||
fonts=0,1
|
fonts=0,1
|
||||||
0,0=xBat.Status:
|
0,0=xBat.Status:
|
||||||
0,12=bS
|
2,0=xCpu:
|
||||||
1,0=xBatt:
|
2,7=bVV
|
||||||
1,6=bVV
|
4,0=xVbus:
|
||||||
2,0=bCmA (charge)
|
4,7=bCV
|
||||||
3,0=bDmA (disch.)
|
6,0=xPower:
|
||||||
4,0=xUSB:
|
6,7=bPmW
|
||||||
4,5=bUV
|
|
||||||
5,5=bImA
|
|
||||||
6,0=xTemp:
|
|
||||||
6,5=bT C
|
|
||||||
|
|
||||||
#############
|
|
||||||
@Meteo
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=Is
|
|
||||||
0,9=f
|
|
||||||
1,12=t
|
|
||||||
2,0=xSonde
|
|
||||||
3,0=xData
|
|
||||||
2,10=A
|
|
||||||
4,0=Mt°C
|
|
||||||
4,9=Mh%rH
|
|
||||||
6,0=MphPa
|
|
||||||
6,11=MbV
|
|
||||||
|
|
||||||
#############
|
|
||||||
@GPS-Data
|
|
||||||
timer=-1,-1,-1
|
|
||||||
key1action=+,0,F,W
|
|
||||||
key2action=>,#,#,#
|
|
||||||
timeaction=#,#,#
|
|
||||||
fonts=0,1
|
|
||||||
0,0=xGPS-Data
|
|
||||||
1,0=xLAT :
|
|
||||||
1,6=gA
|
|
||||||
2,0=xLONG:
|
|
||||||
2,6=gO
|
|
||||||
3,0=xALT :
|
|
||||||
3,9=gH
|
|
||||||
4,0=xSonde
|
|
||||||
5,0=xAlt :
|
|
||||||
5,6=a
|
|
||||||
6,0=xDist:
|
|
||||||
6,6=gD
|
|
||||||
|
|
||||||
|
|
10
RadioSonde_FSK/data/sondemap.html
Executable file
10
RadioSonde_FSK/data/sondemap.html
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button class="tablinks" onclick="javascript:window.open('http://wx.dl2mf.de/','_self')"> Sonde Map</button><br><br>
|
||||||
|
<button class="tablinks" onclick="javascript:window.open('https://radiosondy.info/','_self')"> RadioSony</button><br><br>
|
||||||
|
<button class="tablinks" onclick="javascript:window.open('https://tracker.sondehub.org/?sondehub=1#!mt=osm&mz=8&qm=6_hours&mc=43.76665,6.24011&f=none&q=RS_*;*chase','_self')"> SondeHub</button><br><br>
|
||||||
|
</body>
|
||||||
|
</html>
|
4
RadioSonde_FSK/version.h
Executable file
4
RadioSonde_FSK/version.h
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
const char *version_name = "RadioSonde";
|
||||||
|
const char *version_id = "0.8.5";
|
||||||
|
const int SPIFFS_MAJOR=2;
|
||||||
|
const int SPIFFS_MINOR=4;
|
9
Setup.md
9
Setup.md
|
@ -38,8 +38,10 @@ Installer "U8g2"
|
||||||
|
|
||||||
Installer "MicroNMEA"
|
Installer "MicroNMEA"
|
||||||
|
|
||||||
|
Installer "TFT_22_ILI9225" nécessaire pas pour l'écran car j'ai tout supprimé
|
||||||
mais pour les fonts, car le TTGO fonctionne avec OLED SSD1306 par défaut!
|
mais pour les fonts, car le TTGO fonctionne avec OLED SSD1306 par défaut!
|
||||||
|
|
||||||
|
|
||||||
## Ajouter les bibliothèques, parties 2
|
## Ajouter les bibliothèques, parties 2
|
||||||
|
|
||||||
Depuis https://github.com/me-no-dev/ESPAsyncWebServer télécharger le ZIP , l'extraire dans "libraries"
|
Depuis https://github.com/me-no-dev/ESPAsyncWebServer télécharger le ZIP , l'extraire dans "libraries"
|
||||||
|
@ -50,7 +52,6 @@ Depuis https://github.com/me-no-dev/AsyncTCP télécharger le ZIP, l'extraire da
|
||||||
de même pour https://github.com/lewisxhe/AXP202X_Library télécharger le ZIP, l'extraire dans "libraries", et renommer le répertoire en AXP202X_Library
|
de même pour https://github.com/lewisxhe/AXP202X_Library télécharger le ZIP, l'extraire dans "libraries", et renommer le répertoire en AXP202X_Library
|
||||||
|
|
||||||
|
|
||||||
aussi https://www.arduino.cc/reference/en/libraries/gfx-library-for-arduino/
|
|
||||||
## Ajouter les bibliothèques, parties 3
|
## Ajouter les bibliothèques, parties 3
|
||||||
|
|
||||||
Copier libraries/SX1278FSK
|
Copier libraries/SX1278FSK
|
||||||
|
@ -68,6 +69,12 @@ ln -s <whereyouclonedthegit>/radiosonde/libraries/SX1278FSK/ .
|
||||||
```
|
```
|
||||||
Redémarrer Arduino IDE
|
Redémarrer Arduino IDE
|
||||||
|
|
||||||
|
## Ajout carte esp32
|
||||||
|
|
||||||
|
Allez dans Outils-> type de cartes -> gestionnaire de cartes
|
||||||
|
|
||||||
|
puis dans la case taper esp32 et Installer.
|
||||||
|
|
||||||
## Dernière parties
|
## Dernière parties
|
||||||
|
|
||||||
Dans Outils -> Esp32 arduino: ->
|
Dans Outils -> Esp32 arduino: ->
|
||||||
|
|
BIN
ant_cju.jpg
Executable file
BIN
ant_cju.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
89
libraries/SD/.travis.yml
Executable file
89
libraries/SD/.travis.yml
Executable file
|
@ -0,0 +1,89 @@
|
||||||
|
# default language
|
||||||
|
language: generic
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- CLI_VERSION=latest
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# compile example sketches for the following boards
|
||||||
|
- env:
|
||||||
|
- BOARD='arduino:avr:mega:cpu=atmega2560'
|
||||||
|
install:
|
||||||
|
- arduino-cli core install arduino:avr
|
||||||
|
|
||||||
|
- env:
|
||||||
|
- BOARD='arduino:samd:mkrzero'
|
||||||
|
install:
|
||||||
|
- arduino-cli core install arduino:samd
|
||||||
|
|
||||||
|
- env:
|
||||||
|
- BOARD='arduino:megaavr:uno2018:mode=on'
|
||||||
|
install:
|
||||||
|
- arduino-cli core install arduino:megaavr
|
||||||
|
|
||||||
|
- env:
|
||||||
|
- BOARD='arduino:sam:arduino_due_x'
|
||||||
|
install:
|
||||||
|
- arduino-cli core install arduino:sam
|
||||||
|
|
||||||
|
# check all code files for compliance with the Arduino code formatting style
|
||||||
|
- env:
|
||||||
|
- NAME='Code Formatting Check'
|
||||||
|
language: minimal
|
||||||
|
before_install:
|
||||||
|
# install Artistic Style code formatter tool: http://astyle.sourceforge.net
|
||||||
|
- |
|
||||||
|
mkdir "${HOME}/astyle";
|
||||||
|
wget --no-verbose --output-document="${HOME}/astyle/astyle.tar.gz" "https://iweb.dl.sourceforge.net/project/astyle/astyle/astyle%203.1/astyle_3.1_linux.tar.gz";
|
||||||
|
tar --extract --file="${HOME}/astyle/astyle.tar.gz" --directory="${HOME}/astyle";
|
||||||
|
cd "${HOME}/astyle/astyle/build/gcc";
|
||||||
|
make;
|
||||||
|
export PATH="$PWD/bin:$PATH";
|
||||||
|
cd "$TRAVIS_BUILD_DIR"
|
||||||
|
# download Arduino's Artistic Style configuration file
|
||||||
|
- wget --directory-prefix="${HOME}/astyle" https://raw.githubusercontent.com/arduino/Arduino/master/build/shared/examples_formatter.conf
|
||||||
|
script:
|
||||||
|
# check code formatting
|
||||||
|
- find . -regextype posix-extended -path './.git' -prune -or \( -iregex '.*\.((ino)|(h)|(hpp)|(hh)|(hxx)|(h\+\+)|(cpp)|(cc)|(cxx)|(c\+\+)|(cp)|(c)|(ipp)|(ii)|(ixx)|(inl)|(tpp)|(txx)|(tpl))$' -and -type f \) -print0 | xargs -0 -L1 bash -c 'if ! diff "$0" <(astyle --options=${HOME}/astyle/examples_formatter.conf --dry-run < "$0"); then echo "Non-compliant code formatting in $0"; false; fi'
|
||||||
|
|
||||||
|
# check all files for commonly misspelled words
|
||||||
|
- env:
|
||||||
|
- NAME='Spell Check'
|
||||||
|
language: python
|
||||||
|
python: 3.6
|
||||||
|
before_install:
|
||||||
|
# https://github.com/codespell-project/codespell
|
||||||
|
- pip install codespell
|
||||||
|
script:
|
||||||
|
# codespell will ignore any words in extras/codespell-ignore-words-list.txt, which may be used to fix false positives
|
||||||
|
- codespell --skip="${TRAVIS_BUILD_DIR}/.git" --ignore-words="${TRAVIS_BUILD_DIR}/extras/codespell-ignore-words-list.txt" "${TRAVIS_BUILD_DIR}"
|
||||||
|
|
||||||
|
# default phases shared by the compilation tests
|
||||||
|
before_install:
|
||||||
|
- wget http://downloads.arduino.cc/arduino-cli/arduino-cli-$CLI_VERSION-linux64.tar.bz2
|
||||||
|
- tar xf arduino-cli-$CLI_VERSION-linux64.tar.bz2
|
||||||
|
- mkdir -p "$HOME/bin"
|
||||||
|
- mv arduino-cli "$HOME/bin"
|
||||||
|
- export PATH="$PATH:$HOME/bin"
|
||||||
|
- arduino-cli core update-index
|
||||||
|
- buildExampleSketch() { arduino-cli compile --verbose --warnings all --fqbn $BOARD "$PWD/examples/$1"; }
|
||||||
|
- mkdir -p "$HOME/Arduino/libraries"
|
||||||
|
- ln -s "$PWD" "$HOME/Arduino/libraries/."
|
||||||
|
|
||||||
|
script:
|
||||||
|
- buildExampleSketch CardInfo
|
||||||
|
- buildExampleSketch Datalogger
|
||||||
|
- buildExampleSketch DumpFile
|
||||||
|
- buildExampleSketch Files
|
||||||
|
- buildExampleSketch listfiles
|
||||||
|
- buildExampleSketch ReadWrite
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
# use TravisBuddy to comment on any pull request that results in a failed CI build
|
||||||
|
urls:
|
||||||
|
- https://www.travisbuddy.com/
|
||||||
|
on_success: never
|
||||||
|
on_failure: always
|
26
libraries/SD/README.adoc
Executable file
26
libraries/SD/README.adoc
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
= SD Library for Arduino =
|
||||||
|
|
||||||
|
image:https://travis-ci.org/arduino-libraries/SD.svg?branch=master[Build Status, link=https://travis-ci.org/arduino-libraries/SD]
|
||||||
|
|
||||||
|
The SD library allows for reading from and writing to SD cards.
|
||||||
|
|
||||||
|
For more information about this library please visit us at
|
||||||
|
http://www.arduino.cc/en/Reference/SD
|
||||||
|
|
||||||
|
== License ==
|
||||||
|
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
Copyright (c) 2010 SparkFun Electronics
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
116
libraries/SD/examples/CardInfo/CardInfo.ino
Executable file
116
libraries/SD/examples/CardInfo/CardInfo.ino
Executable file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
SD card test
|
||||||
|
|
||||||
|
This example shows how use the utility libraries on which the'
|
||||||
|
SD library is based in order to get info about your SD card.
|
||||||
|
Very useful for testing a card when you're not sure whether its working or not.
|
||||||
|
|
||||||
|
The circuit:
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
|
||||||
|
** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
|
||||||
|
** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
|
||||||
|
** CS - depends on your SD card shield or module.
|
||||||
|
Pin 4 used here for consistency with other Arduino examples
|
||||||
|
|
||||||
|
|
||||||
|
created 28 Mar 2011
|
||||||
|
by Limor Fried
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
*/
|
||||||
|
// include the SD library:
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
// set up variables using the SD utility library functions:
|
||||||
|
Sd2Card card;
|
||||||
|
SdVolume volume;
|
||||||
|
SdFile root;
|
||||||
|
|
||||||
|
// change this to match your SD shield or module;
|
||||||
|
// Arduino Ethernet shield: pin 4
|
||||||
|
// Adafruit SD shields and modules: pin 10
|
||||||
|
// Sparkfun SD shield: pin 8
|
||||||
|
// MKRZero SD: SDCARD_SS_PIN
|
||||||
|
const int chipSelect = 4;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("\nInitializing SD card...");
|
||||||
|
|
||||||
|
// we'll use the initialization code from the utility libraries
|
||||||
|
// since we're just testing if the card is working!
|
||||||
|
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
|
||||||
|
Serial.println("initialization failed. Things to check:");
|
||||||
|
Serial.println("* is a card inserted?");
|
||||||
|
Serial.println("* is your wiring correct?");
|
||||||
|
Serial.println("* did you change the chipSelect pin to match your shield or module?");
|
||||||
|
while (1);
|
||||||
|
} else {
|
||||||
|
Serial.println("Wiring is correct and a card is present.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the type of card
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("Card type: ");
|
||||||
|
switch (card.type()) {
|
||||||
|
case SD_CARD_TYPE_SD1:
|
||||||
|
Serial.println("SD1");
|
||||||
|
break;
|
||||||
|
case SD_CARD_TYPE_SD2:
|
||||||
|
Serial.println("SD2");
|
||||||
|
break;
|
||||||
|
case SD_CARD_TYPE_SDHC:
|
||||||
|
Serial.println("SDHC");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println("Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
|
||||||
|
if (!volume.init(card)) {
|
||||||
|
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("Clusters: ");
|
||||||
|
Serial.println(volume.clusterCount());
|
||||||
|
Serial.print("Blocks x Cluster: ");
|
||||||
|
Serial.println(volume.blocksPerCluster());
|
||||||
|
|
||||||
|
Serial.print("Total Blocks: ");
|
||||||
|
Serial.println(volume.blocksPerCluster() * volume.clusterCount());
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// print the type and size of the first FAT-type volume
|
||||||
|
uint32_t volumesize;
|
||||||
|
Serial.print("Volume type is: FAT");
|
||||||
|
Serial.println(volume.fatType(), DEC);
|
||||||
|
|
||||||
|
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
|
||||||
|
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
|
||||||
|
volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)
|
||||||
|
Serial.print("Volume size (Kb): ");
|
||||||
|
Serial.println(volumesize);
|
||||||
|
Serial.print("Volume size (Mb): ");
|
||||||
|
volumesize /= 1024;
|
||||||
|
Serial.println(volumesize);
|
||||||
|
Serial.print("Volume size (Gb): ");
|
||||||
|
Serial.println((float)volumesize / 1024.0);
|
||||||
|
|
||||||
|
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
|
||||||
|
root.openRoot(volume);
|
||||||
|
|
||||||
|
// list all files in the card with date and size
|
||||||
|
root.ls(LS_R | LS_DATE | LS_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
}
|
84
libraries/SD/examples/Datalogger/Datalogger.ino
Executable file
84
libraries/SD/examples/Datalogger/Datalogger.ino
Executable file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
SD card datalogger
|
||||||
|
|
||||||
|
This example shows how to log data from three analog sensors
|
||||||
|
to an SD card using the SD library.
|
||||||
|
|
||||||
|
The circuit:
|
||||||
|
analog sensors on analog ins 0, 1, and 2
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
|
||||||
|
|
||||||
|
created 24 Nov 2010
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
const int chipSelect = 4;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("Initializing SD card...");
|
||||||
|
|
||||||
|
// see if the card is present and can be initialized:
|
||||||
|
if (!SD.begin(chipSelect)) {
|
||||||
|
Serial.println("Card failed, or not present");
|
||||||
|
// don't do anything more:
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
Serial.println("card initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// make a string for assembling the data to log:
|
||||||
|
String dataString = "";
|
||||||
|
|
||||||
|
// read three sensors and append to the string:
|
||||||
|
for (int analogPin = 0; analogPin < 3; analogPin++) {
|
||||||
|
int sensor = analogRead(analogPin);
|
||||||
|
dataString += String(sensor);
|
||||||
|
if (analogPin < 2) {
|
||||||
|
dataString += ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the file. note that only one file can be open at a time,
|
||||||
|
// so you have to close this one before opening another.
|
||||||
|
File dataFile = SD.open("datalog.txt", FILE_WRITE);
|
||||||
|
|
||||||
|
// if the file is available, write to it:
|
||||||
|
if (dataFile) {
|
||||||
|
dataFile.println(dataString);
|
||||||
|
dataFile.close();
|
||||||
|
// print to the serial port too:
|
||||||
|
Serial.println(dataString);
|
||||||
|
}
|
||||||
|
// if the file isn't open, pop up an error:
|
||||||
|
else {
|
||||||
|
Serial.println("error opening datalog.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
65
libraries/SD/examples/DumpFile/DumpFile.ino
Executable file
65
libraries/SD/examples/DumpFile/DumpFile.ino
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
SD card file dump
|
||||||
|
|
||||||
|
This example shows how to read a file from the SD card using the
|
||||||
|
SD library and send it over the serial port.
|
||||||
|
|
||||||
|
The circuit:
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
|
||||||
|
|
||||||
|
created 22 December 2010
|
||||||
|
by Limor Fried
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
const int chipSelect = 4;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("Initializing SD card...");
|
||||||
|
|
||||||
|
// see if the card is present and can be initialized:
|
||||||
|
if (!SD.begin(chipSelect)) {
|
||||||
|
Serial.println("Card failed, or not present");
|
||||||
|
// don't do anything more:
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
Serial.println("card initialized.");
|
||||||
|
|
||||||
|
// open the file. note that only one file can be open at a time,
|
||||||
|
// so you have to close this one before opening another.
|
||||||
|
File dataFile = SD.open("datalog.txt");
|
||||||
|
|
||||||
|
// if the file is available, write to it:
|
||||||
|
if (dataFile) {
|
||||||
|
while (dataFile.available()) {
|
||||||
|
Serial.write(dataFile.read());
|
||||||
|
}
|
||||||
|
dataFile.close();
|
||||||
|
}
|
||||||
|
// if the file isn't open, pop up an error:
|
||||||
|
else {
|
||||||
|
Serial.println("error opening datalog.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
|
|
75
libraries/SD/examples/Files/Files.ino
Executable file
75
libraries/SD/examples/Files/Files.ino
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
SD card basic file example
|
||||||
|
|
||||||
|
This example shows how to create and destroy an SD card file
|
||||||
|
The circuit:
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
|
||||||
|
|
||||||
|
created Nov 2010
|
||||||
|
by David A. Mellis
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
File myFile;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("Initializing SD card...");
|
||||||
|
|
||||||
|
if (!SD.begin(4)) {
|
||||||
|
Serial.println("initialization failed!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
Serial.println("initialization done.");
|
||||||
|
|
||||||
|
if (SD.exists("example.txt")) {
|
||||||
|
Serial.println("example.txt exists.");
|
||||||
|
} else {
|
||||||
|
Serial.println("example.txt doesn't exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// open a new file and immediately close it:
|
||||||
|
Serial.println("Creating example.txt...");
|
||||||
|
myFile = SD.open("example.txt", FILE_WRITE);
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
// Check to see if the file exists:
|
||||||
|
if (SD.exists("example.txt")) {
|
||||||
|
Serial.println("example.txt exists.");
|
||||||
|
} else {
|
||||||
|
Serial.println("example.txt doesn't exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the file:
|
||||||
|
Serial.println("Removing example.txt...");
|
||||||
|
SD.remove("example.txt");
|
||||||
|
|
||||||
|
if (SD.exists("example.txt")) {
|
||||||
|
Serial.println("example.txt exists.");
|
||||||
|
} else {
|
||||||
|
Serial.println("example.txt doesn't exist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing happens after setup finishes.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
91
libraries/SD/examples/NonBlockingWrite/NonBlockingWrite.ino
Executable file
91
libraries/SD/examples/NonBlockingWrite/NonBlockingWrite.ino
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
Non-blocking Write
|
||||||
|
|
||||||
|
This example demonstrates how to perform non-blocking writes
|
||||||
|
to a file on a SD card. The file will contain the current millis()
|
||||||
|
value every 10ms. If the SD card is busy, the data will be buffered
|
||||||
|
in order to not block the sketch.
|
||||||
|
|
||||||
|
NOTE: myFile.availableForWrite() will automatically sync the
|
||||||
|
file contents as needed. You may lose some unsynced data
|
||||||
|
still if myFile.sync() or myFile.close() is not called.
|
||||||
|
|
||||||
|
The circuit:
|
||||||
|
- Arduino MKR Zero board
|
||||||
|
- micro SD card attached
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
// file name to use for writing
|
||||||
|
const char filename[] = "demo.txt";
|
||||||
|
|
||||||
|
// File object to represent file
|
||||||
|
File txtFile;
|
||||||
|
|
||||||
|
// string to buffer output
|
||||||
|
String buffer;
|
||||||
|
|
||||||
|
unsigned long lastMillis = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial);
|
||||||
|
|
||||||
|
// reserve 1kB for String used as a buffer
|
||||||
|
buffer.reserve(1024);
|
||||||
|
|
||||||
|
// set LED pin to output, used to blink when writing
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
|
// init the SD card
|
||||||
|
if (!SD.begin()) {
|
||||||
|
Serial.println("Card failed, or not present");
|
||||||
|
// don't do anything more:
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you want to start from an empty file,
|
||||||
|
// uncomment the next line:
|
||||||
|
// SD.remove(filename);
|
||||||
|
|
||||||
|
// try to open the file for writing
|
||||||
|
txtFile = SD.open(filename, FILE_WRITE);
|
||||||
|
if (!txtFile) {
|
||||||
|
Serial.print("error opening ");
|
||||||
|
Serial.println(filename);
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add some new lines to start
|
||||||
|
txtFile.println();
|
||||||
|
txtFile.println("Hello World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// check if it's been over 10 ms since the last line added
|
||||||
|
unsigned long now = millis();
|
||||||
|
if ((now - lastMillis) >= 10) {
|
||||||
|
// add a new line to the buffer
|
||||||
|
buffer += "Hello ";
|
||||||
|
buffer += now;
|
||||||
|
buffer += "\r\n";
|
||||||
|
|
||||||
|
lastMillis = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the SD card is available to write data without blocking
|
||||||
|
// and if the buffered data is enough for the full chunk size
|
||||||
|
unsigned int chunkSize = txtFile.availableForWrite();
|
||||||
|
if (chunkSize && buffer.length() >= chunkSize) {
|
||||||
|
// write to file and blink LED
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
txtFile.write(buffer.c_str(), chunkSize);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
|
||||||
|
// remove written data from buffer
|
||||||
|
buffer.remove(0, chunkSize);
|
||||||
|
}
|
||||||
|
}
|
79
libraries/SD/examples/ReadWrite/ReadWrite.ino
Executable file
79
libraries/SD/examples/ReadWrite/ReadWrite.ino
Executable file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
SD card read/write
|
||||||
|
|
||||||
|
This example shows how to read and write data to and from an SD card file
|
||||||
|
The circuit:
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
|
||||||
|
|
||||||
|
created Nov 2010
|
||||||
|
by David A. Mellis
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
File myFile;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Serial.print("Initializing SD card...");
|
||||||
|
|
||||||
|
if (!SD.begin(4)) {
|
||||||
|
Serial.println("initialization failed!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
Serial.println("initialization done.");
|
||||||
|
|
||||||
|
// open the file. note that only one file can be open at a time,
|
||||||
|
// so you have to close this one before opening another.
|
||||||
|
myFile = SD.open("test.txt", FILE_WRITE);
|
||||||
|
|
||||||
|
// if the file opened okay, write to it:
|
||||||
|
if (myFile) {
|
||||||
|
Serial.print("Writing to test.txt...");
|
||||||
|
myFile.println("testing 1, 2, 3.");
|
||||||
|
// close the file:
|
||||||
|
myFile.close();
|
||||||
|
Serial.println("done.");
|
||||||
|
} else {
|
||||||
|
// if the file didn't open, print an error:
|
||||||
|
Serial.println("error opening test.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-open the file for reading:
|
||||||
|
myFile = SD.open("test.txt");
|
||||||
|
if (myFile) {
|
||||||
|
Serial.println("test.txt:");
|
||||||
|
|
||||||
|
// read from the file until there's nothing else in it:
|
||||||
|
while (myFile.available()) {
|
||||||
|
Serial.write(myFile.read());
|
||||||
|
}
|
||||||
|
// close the file:
|
||||||
|
myFile.close();
|
||||||
|
} else {
|
||||||
|
// if the file didn't open, print an error:
|
||||||
|
Serial.println("error opening test.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing happens after setup
|
||||||
|
}
|
||||||
|
|
||||||
|
|
80
libraries/SD/examples/listfiles/listfiles.ino
Executable file
80
libraries/SD/examples/listfiles/listfiles.ino
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
Listfiles
|
||||||
|
|
||||||
|
This example shows how print out the files in a
|
||||||
|
directory on a SD card
|
||||||
|
|
||||||
|
The circuit:
|
||||||
|
SD card attached to SPI bus as follows:
|
||||||
|
** MOSI - pin 11
|
||||||
|
** MISO - pin 12
|
||||||
|
** CLK - pin 13
|
||||||
|
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
|
||||||
|
|
||||||
|
created Nov 2010
|
||||||
|
by David A. Mellis
|
||||||
|
modified 9 Apr 2012
|
||||||
|
by Tom Igoe
|
||||||
|
modified 2 Feb 2014
|
||||||
|
by Scott Fitzgerald
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
File root;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Open serial communications and wait for port to open:
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) {
|
||||||
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("Initializing SD card...");
|
||||||
|
|
||||||
|
if (!SD.begin(4)) {
|
||||||
|
Serial.println("initialization failed!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
Serial.println("initialization done.");
|
||||||
|
|
||||||
|
root = SD.open("/");
|
||||||
|
|
||||||
|
printDirectory(root, 0);
|
||||||
|
|
||||||
|
Serial.println("done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing happens after setup finishes.
|
||||||
|
}
|
||||||
|
|
||||||
|
void printDirectory(File dir, int numTabs) {
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
File entry = dir.openNextFile();
|
||||||
|
if (! entry) {
|
||||||
|
// no more files
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < numTabs; i++) {
|
||||||
|
Serial.print('\t');
|
||||||
|
}
|
||||||
|
Serial.print(entry.name());
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
Serial.println("/");
|
||||||
|
printDirectory(entry, numTabs + 1);
|
||||||
|
} else {
|
||||||
|
// files have sizes, directories do not
|
||||||
|
Serial.print("\t\t");
|
||||||
|
Serial.println(entry.size(), DEC);
|
||||||
|
}
|
||||||
|
entry.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
0
libraries/SD/extras/codespell-ignore-words-list.txt
Executable file
0
libraries/SD/extras/codespell-ignore-words-list.txt
Executable file
31
libraries/SD/keywords.txt
Executable file
31
libraries/SD/keywords.txt
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map SD
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
SD KEYWORD1 SD
|
||||||
|
File KEYWORD1 SD
|
||||||
|
SDFile KEYWORD1 SD
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
begin KEYWORD2
|
||||||
|
exists KEYWORD2
|
||||||
|
mkdir KEYWORD2
|
||||||
|
remove KEYWORD2
|
||||||
|
rmdir KEYWORD2
|
||||||
|
open KEYWORD2
|
||||||
|
close KEYWORD2
|
||||||
|
seek KEYWORD2
|
||||||
|
position KEYWORD2
|
||||||
|
size KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
FILE_READ LITERAL1
|
||||||
|
FILE_WRITE LITERAL1
|
9
libraries/SD/library.properties
Executable file
9
libraries/SD/library.properties
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
name=SD
|
||||||
|
version=1.2.4
|
||||||
|
author=Arduino, SparkFun
|
||||||
|
maintainer=Arduino <info@arduino.cc>
|
||||||
|
sentence=Enables reading and writing on SD cards.
|
||||||
|
paragraph=Once an SD memory card is connected to the SPI interface of the Arduino or Genuino board you can create files and read/write on them. You can also move through directories on the SD card.
|
||||||
|
category=Data Storage
|
||||||
|
url=http://www.arduino.cc/en/Reference/SD
|
||||||
|
architectures=*
|
168
libraries/SD/src/File.cpp
Executable file
168
libraries/SD/src/File.cpp
Executable file
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
SD - a slightly more friendly wrapper for sdfatlib
|
||||||
|
|
||||||
|
This library aims to expose a subset of SD card functionality
|
||||||
|
in the form of a higher level "wrapper" object.
|
||||||
|
|
||||||
|
License: GNU General Public License V3
|
||||||
|
(Because sdfatlib is licensed with this.)
|
||||||
|
|
||||||
|
(C) Copyright 2010 SparkFun Electronics
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
/* for debugging file open/close leaks
|
||||||
|
uint8_t nfilecount=0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
File::File(SdFile f, const char *n) {
|
||||||
|
// oh man you are kidding me, new() doesn't exist? Ok we do it by hand!
|
||||||
|
_file = (SdFile *)malloc(sizeof(SdFile));
|
||||||
|
if (_file) {
|
||||||
|
memcpy(_file, &f, sizeof(SdFile));
|
||||||
|
|
||||||
|
strncpy(_name, n, 12);
|
||||||
|
_name[12] = 0;
|
||||||
|
|
||||||
|
/* for debugging file open/close leaks
|
||||||
|
nfilecount++;
|
||||||
|
Serial.print("Created \"");
|
||||||
|
Serial.print(n);
|
||||||
|
Serial.print("\": ");
|
||||||
|
Serial.println(nfilecount, DEC);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(void) {
|
||||||
|
_file = 0;
|
||||||
|
_name[0] = 0;
|
||||||
|
//Serial.print("Created empty file object");
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a pointer to the file name
|
||||||
|
char *File::name(void) {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a directory is a special type of file
|
||||||
|
boolean File::isDirectory(void) {
|
||||||
|
return (_file && _file->isDir());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t File::write(uint8_t val) {
|
||||||
|
return write(&val, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::write(const uint8_t *buf, size_t size) {
|
||||||
|
size_t t;
|
||||||
|
if (!_file) {
|
||||||
|
setWriteError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_file->clearWriteError();
|
||||||
|
t = _file->write(buf, size);
|
||||||
|
if (_file->getWriteError()) {
|
||||||
|
setWriteError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::availableForWrite() {
|
||||||
|
if (_file) {
|
||||||
|
return _file->availableForWrite();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::peek() {
|
||||||
|
if (! _file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c = _file->read();
|
||||||
|
if (c != -1) {
|
||||||
|
_file->seekCur(-1);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::read() {
|
||||||
|
if (_file) {
|
||||||
|
return _file->read();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffered read for more efficient, high speed reading
|
||||||
|
int File::read(void *buf, uint16_t nbyte) {
|
||||||
|
if (_file) {
|
||||||
|
return _file->read(buf, nbyte);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::available() {
|
||||||
|
if (! _file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t n = size() - position();
|
||||||
|
|
||||||
|
return n > 0X7FFF ? 0X7FFF : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::flush() {
|
||||||
|
if (_file) {
|
||||||
|
_file->sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean File::seek(uint32_t pos) {
|
||||||
|
if (! _file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _file->seekSet(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t File::position() {
|
||||||
|
if (! _file) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _file->curPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t File::size() {
|
||||||
|
if (! _file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _file->fileSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::close() {
|
||||||
|
if (_file) {
|
||||||
|
_file->close();
|
||||||
|
free(_file);
|
||||||
|
_file = 0;
|
||||||
|
|
||||||
|
/* for debugging file open/close leaks
|
||||||
|
nfilecount--;
|
||||||
|
Serial.print("Deleted ");
|
||||||
|
Serial.println(nfilecount, DEC);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File::operator bool() {
|
||||||
|
if (_file) {
|
||||||
|
return _file->isOpen();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
13
libraries/SD/src/README.txt
Executable file
13
libraries/SD/src/README.txt
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
** SD - a slightly more friendly wrapper for sdfatlib **
|
||||||
|
|
||||||
|
This library aims to expose a subset of SD card functionality in the
|
||||||
|
form of a higher level "wrapper" object.
|
||||||
|
|
||||||
|
License: GNU General Public License V3
|
||||||
|
(Because sdfatlib is licensed with this.)
|
||||||
|
|
||||||
|
(C) Copyright 2010 SparkFun Electronics
|
||||||
|
|
||||||
|
Now better than ever with optimization, multiple file support, directory handling, etc - ladyada!
|
||||||
|
|
637
libraries/SD/src/SD.cpp
Executable file
637
libraries/SD/src/SD.cpp
Executable file
|
@ -0,0 +1,637 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
SD - a slightly more friendly wrapper for sdfatlib
|
||||||
|
|
||||||
|
This library aims to expose a subset of SD card functionality
|
||||||
|
in the form of a higher level "wrapper" object.
|
||||||
|
|
||||||
|
License: GNU General Public License V3
|
||||||
|
(Because sdfatlib is licensed with this.)
|
||||||
|
|
||||||
|
(C) Copyright 2010 SparkFun Electronics
|
||||||
|
|
||||||
|
|
||||||
|
This library provides four key benefits:
|
||||||
|
|
||||||
|
Including `SD.h` automatically creates a global
|
||||||
|
`SD` object which can be interacted with in a similar
|
||||||
|
manner to other standard global objects like `Serial` and `Ethernet`.
|
||||||
|
|
||||||
|
Boilerplate initialisation code is contained in one method named
|
||||||
|
`begin` and no further objects need to be created in order to access
|
||||||
|
the SD card.
|
||||||
|
|
||||||
|
Calls to `open` can supply a full path name including parent
|
||||||
|
directories which simplifies interacting with files in subdirectories.
|
||||||
|
|
||||||
|
Utility methods are provided to determine whether a file exists
|
||||||
|
and to create a directory hierarchy.
|
||||||
|
|
||||||
|
|
||||||
|
Note however that not all functionality provided by the underlying
|
||||||
|
sdfatlib library is exposed.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Implementation Notes
|
||||||
|
|
||||||
|
In order to handle multi-directory path traversal, functionality that
|
||||||
|
requires this ability is implemented as callback functions.
|
||||||
|
|
||||||
|
Individual methods call the `walkPath` function which performs the actual
|
||||||
|
directory traversal (swapping between two different directory/file handles
|
||||||
|
along the way) and at each level calls the supplied callback function.
|
||||||
|
|
||||||
|
Some types of functionality will take an action at each level (e.g. exists
|
||||||
|
or make directory) which others will only take an action at the bottom
|
||||||
|
level (e.g. open).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SD.h"
|
||||||
|
|
||||||
|
namespace SDLib {
|
||||||
|
|
||||||
|
// Used by `getNextPathComponent`
|
||||||
|
#define MAX_COMPONENT_LEN 12 // What is max length?
|
||||||
|
#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1
|
||||||
|
|
||||||
|
bool getNextPathComponent(const char *path, unsigned int *p_offset,
|
||||||
|
char *buffer) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Parse individual path components from a path.
|
||||||
|
|
||||||
|
e.g. after repeated calls '/foo/bar/baz' will be split
|
||||||
|
into 'foo', 'bar', 'baz'.
|
||||||
|
|
||||||
|
This is similar to `strtok()` but copies the component into the
|
||||||
|
supplied buffer rather than modifying the original string.
|
||||||
|
|
||||||
|
|
||||||
|
`buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size.
|
||||||
|
|
||||||
|
`p_offset` needs to point to an integer of the offset at
|
||||||
|
which the previous path component finished.
|
||||||
|
|
||||||
|
Returns `true` if more components remain.
|
||||||
|
|
||||||
|
Returns `false` if this is the last component.
|
||||||
|
(This means path ended with 'foo' or 'foo/'.)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Have buffer local to this function, so we know it's the
|
||||||
|
// correct length?
|
||||||
|
|
||||||
|
int bufferOffset = 0;
|
||||||
|
|
||||||
|
int offset = *p_offset;
|
||||||
|
|
||||||
|
// Skip root or other separator
|
||||||
|
if (path[offset] == '/') {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the next next path segment
|
||||||
|
while (bufferOffset < MAX_COMPONENT_LEN
|
||||||
|
&& (path[offset] != '/')
|
||||||
|
&& (path[offset] != '\0')) {
|
||||||
|
buffer[bufferOffset++] = path[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[bufferOffset] = '\0';
|
||||||
|
|
||||||
|
// Skip trailing separator so we can determine if this
|
||||||
|
// is the last component in the path or not.
|
||||||
|
if (path[offset] == '/') {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_offset = offset;
|
||||||
|
|
||||||
|
return (path[offset] != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean walkPath(const char *filepath, SdFile& parentDir,
|
||||||
|
boolean(*callback)(SdFile& parentDir,
|
||||||
|
const char *filePathComponent,
|
||||||
|
boolean isLastComponent,
|
||||||
|
void *object),
|
||||||
|
void *object = NULL) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
When given a file path (and parent directory--normally root),
|
||||||
|
this function traverses the directories in the path and at each
|
||||||
|
level calls the supplied callback function while also providing
|
||||||
|
the supplied object for context if required.
|
||||||
|
|
||||||
|
e.g. given the path '/foo/bar/baz'
|
||||||
|
the callback would be called at the equivalent of
|
||||||
|
'/foo', '/foo/bar' and '/foo/bar/baz'.
|
||||||
|
|
||||||
|
The implementation swaps between two different directory/file
|
||||||
|
handles as it traverses the directories and does not use recursion
|
||||||
|
in an attempt to use memory efficiently.
|
||||||
|
|
||||||
|
If a callback wishes to stop the directory traversal it should
|
||||||
|
return false--in this case the function will stop the traversal,
|
||||||
|
tidy up and return false.
|
||||||
|
|
||||||
|
If a directory path doesn't exist at some point this function will
|
||||||
|
also return false and not subsequently call the callback.
|
||||||
|
|
||||||
|
If a directory path specified is complete, valid and the callback
|
||||||
|
did not indicate the traversal should be interrupted then this
|
||||||
|
function will return true.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
SdFile subfile1;
|
||||||
|
SdFile subfile2;
|
||||||
|
|
||||||
|
char buffer[PATH_COMPONENT_BUFFER_LEN];
|
||||||
|
|
||||||
|
unsigned int offset = 0;
|
||||||
|
|
||||||
|
SdFile *p_parent;
|
||||||
|
SdFile *p_child;
|
||||||
|
|
||||||
|
SdFile *p_tmp_sdfile;
|
||||||
|
|
||||||
|
p_child = &subfile1;
|
||||||
|
|
||||||
|
p_parent = &parentDir;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);
|
||||||
|
|
||||||
|
boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);
|
||||||
|
|
||||||
|
if (!shouldContinue) {
|
||||||
|
// TODO: Don't repeat this code?
|
||||||
|
// If it's one we've created then we
|
||||||
|
// don't need the parent handle anymore.
|
||||||
|
if (p_parent != &parentDir) {
|
||||||
|
(*p_parent).close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moreComponents) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);
|
||||||
|
|
||||||
|
// If it's one we've created then we
|
||||||
|
// don't need the parent handle anymore.
|
||||||
|
if (p_parent != &parentDir) {
|
||||||
|
(*p_parent).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle case when it doesn't exist and we can't continue...
|
||||||
|
if (exists) {
|
||||||
|
// We alternate between two file handles as we go down
|
||||||
|
// the path.
|
||||||
|
if (p_parent == &parentDir) {
|
||||||
|
p_parent = &subfile2;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_tmp_sdfile = p_parent;
|
||||||
|
p_parent = p_child;
|
||||||
|
p_child = p_tmp_sdfile;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_parent != &parentDir) {
|
||||||
|
(*p_parent).close(); // TODO: Return/ handle different?
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
The callbacks used to implement various functionality follow.
|
||||||
|
|
||||||
|
Each callback is supplied with a parent directory handle,
|
||||||
|
character string with the name of the current file path component,
|
||||||
|
a flag indicating if this component is the last in the path and
|
||||||
|
a pointer to an arbitrary object used for context.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
boolean callback_pathExists(SdFile& parentDir, const char *filePathComponent,
|
||||||
|
boolean /* isLastComponent */, void * /* object */) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Callback used to determine if a file/directory exists in parent
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Returns true if file path exists.
|
||||||
|
|
||||||
|
*/
|
||||||
|
SdFile child;
|
||||||
|
|
||||||
|
boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
child.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean callback_makeDirPath(SdFile& parentDir, const char *filePathComponent,
|
||||||
|
boolean isLastComponent, void *object) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Callback used to create a directory in the parent directory if
|
||||||
|
it does not already exist.
|
||||||
|
|
||||||
|
Returns true if a directory was created or it already existed.
|
||||||
|
|
||||||
|
*/
|
||||||
|
boolean result = false;
|
||||||
|
SdFile child;
|
||||||
|
|
||||||
|
result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object);
|
||||||
|
if (!result) {
|
||||||
|
result = child.makeDir(parentDir, filePathComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
|
||||||
|
boolean isLastComponent, void *object) {
|
||||||
|
|
||||||
|
Callback used to open a file specified by a filepath that may
|
||||||
|
specify one or more directories above it.
|
||||||
|
|
||||||
|
Expects the context object to be an instance of `SDClass` and
|
||||||
|
will use the `file` property of the instance to open the requested
|
||||||
|
file/directory with the associated file open mode property.
|
||||||
|
|
||||||
|
Always returns true if the directory traversal hasn't reached the
|
||||||
|
bottom of the directory hierarchy.
|
||||||
|
|
||||||
|
Returns false once the file has been opened--to prevent the traversal
|
||||||
|
from descending further. (This may be unnecessary.)
|
||||||
|
|
||||||
|
if (isLastComponent) {
|
||||||
|
SDClass *p_SD = static_cast<SDClass*>(object);
|
||||||
|
p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
|
||||||
|
if (p_SD->fileOpenMode == FILE_WRITE) {
|
||||||
|
p_SD->file.seekSet(p_SD->file.fileSize());
|
||||||
|
}
|
||||||
|
// TODO: Return file open result?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean callback_remove(SdFile& parentDir, const char *filePathComponent,
|
||||||
|
boolean isLastComponent, void * /* object */) {
|
||||||
|
if (isLastComponent) {
|
||||||
|
return SdFile::remove(parentDir, filePathComponent);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean callback_rmdir(SdFile& parentDir, const char *filePathComponent,
|
||||||
|
boolean isLastComponent, void * /* object */) {
|
||||||
|
if (isLastComponent) {
|
||||||
|
SdFile f;
|
||||||
|
if (!f.open(parentDir, filePathComponent, O_READ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return f.rmDir();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Implementation of class used to create `SDCard` object. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean SDClass::begin(uint8_t csPin) {
|
||||||
|
if (root.isOpen()) {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Performs the initialisation required by the sdfatlib library.
|
||||||
|
|
||||||
|
Return true if initialization succeeds, false otherwise.
|
||||||
|
|
||||||
|
*/
|
||||||
|
return card.init(SPI_HALF_SPEED, csPin) &&
|
||||||
|
volume.init(card) &&
|
||||||
|
root.openRoot(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean SDClass::begin(uint32_t clock, uint8_t csPin) {
|
||||||
|
if (root.isOpen()) {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return card.init(SPI_HALF_SPEED, csPin) &&
|
||||||
|
card.setSpiClock(clock) &&
|
||||||
|
volume.init(card) &&
|
||||||
|
root.openRoot(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
//call this when a card is removed. It will allow you to insert and initialise a new card.
|
||||||
|
void SDClass::end() {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this little helper is used to traverse paths
|
||||||
|
SdFile SDClass::getParentDir(const char *filepath, int *index) {
|
||||||
|
// get parent directory
|
||||||
|
SdFile d1;
|
||||||
|
SdFile d2;
|
||||||
|
|
||||||
|
d1.openRoot(volume); // start with the mostparent, root!
|
||||||
|
|
||||||
|
// we'll use the pointers to swap between the two objects
|
||||||
|
SdFile *parent = &d1;
|
||||||
|
SdFile *subdir = &d2;
|
||||||
|
|
||||||
|
const char *origpath = filepath;
|
||||||
|
|
||||||
|
while (strchr(filepath, '/')) {
|
||||||
|
|
||||||
|
// get rid of leading /'s
|
||||||
|
if (filepath[0] == '/') {
|
||||||
|
filepath++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! strchr(filepath, '/')) {
|
||||||
|
// it was in the root directory, so leave now
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract just the name of the next subdirectory
|
||||||
|
uint8_t idx = strchr(filepath, '/') - filepath;
|
||||||
|
if (idx > 12) {
|
||||||
|
idx = 12; // don't let them specify long names
|
||||||
|
}
|
||||||
|
char subdirname[13];
|
||||||
|
strncpy(subdirname, filepath, idx);
|
||||||
|
subdirname[idx] = 0;
|
||||||
|
|
||||||
|
// close the subdir (we reuse them) if open
|
||||||
|
subdir->close();
|
||||||
|
if (! subdir->open(parent, subdirname, O_READ)) {
|
||||||
|
// failed to open one of the subdirectories
|
||||||
|
return SdFile();
|
||||||
|
}
|
||||||
|
// move forward to the next subdirectory
|
||||||
|
filepath += idx;
|
||||||
|
|
||||||
|
// we reuse the objects, close it.
|
||||||
|
parent->close();
|
||||||
|
|
||||||
|
// swap the pointers
|
||||||
|
SdFile *t = parent;
|
||||||
|
parent = subdir;
|
||||||
|
subdir = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
*index = (int)(filepath - origpath);
|
||||||
|
// parent is now the parent directory of the file!
|
||||||
|
return *parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File SDClass::open(const char *filepath, uint8_t mode) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Open the supplied file path for reading or writing.
|
||||||
|
|
||||||
|
The file content can be accessed via the `file` property of
|
||||||
|
the `SDClass` object--this property is currently
|
||||||
|
a standard `SdFile` object from `sdfatlib`.
|
||||||
|
|
||||||
|
Defaults to read only.
|
||||||
|
|
||||||
|
If `write` is true, default action (when `append` is true) is to
|
||||||
|
append data to the end of the file.
|
||||||
|
|
||||||
|
If `append` is false then the file will be truncated first.
|
||||||
|
|
||||||
|
If the file does not exist and it is opened for writing the file
|
||||||
|
will be created.
|
||||||
|
|
||||||
|
An attempt to open a file for reading that does not exist is an
|
||||||
|
error.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
int pathidx;
|
||||||
|
|
||||||
|
// do the interactive search
|
||||||
|
SdFile parentdir = getParentDir(filepath, &pathidx);
|
||||||
|
// no more subdirs!
|
||||||
|
|
||||||
|
filepath += pathidx;
|
||||||
|
|
||||||
|
if (! filepath[0]) {
|
||||||
|
// it was the directory itself!
|
||||||
|
return File(parentdir, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the file itself
|
||||||
|
SdFile file;
|
||||||
|
|
||||||
|
// failed to open a subdir!
|
||||||
|
if (!parentdir.isOpen()) {
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! file.open(parentdir, filepath, mode)) {
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
// close the parent
|
||||||
|
parentdir.close();
|
||||||
|
|
||||||
|
if ((mode & (O_APPEND | O_WRITE)) == (O_APPEND | O_WRITE)) {
|
||||||
|
file.seekSet(file.fileSize());
|
||||||
|
}
|
||||||
|
return File(file, filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
File SDClass::open(char *filepath, uint8_t mode) {
|
||||||
|
//
|
||||||
|
|
||||||
|
Open the supplied file path for reading or writing.
|
||||||
|
|
||||||
|
The file content can be accessed via the `file` property of
|
||||||
|
the `SDClass` object--this property is currently
|
||||||
|
a standard `SdFile` object from `sdfatlib`.
|
||||||
|
|
||||||
|
Defaults to read only.
|
||||||
|
|
||||||
|
If `write` is true, default action (when `append` is true) is to
|
||||||
|
append data to the end of the file.
|
||||||
|
|
||||||
|
If `append` is false then the file will be truncated first.
|
||||||
|
|
||||||
|
If the file does not exist and it is opened for writing the file
|
||||||
|
will be created.
|
||||||
|
|
||||||
|
An attempt to open a file for reading that does not exist is an
|
||||||
|
error.
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// TODO: Allow for read&write? (Possibly not, as it requires seek.)
|
||||||
|
|
||||||
|
fileOpenMode = mode;
|
||||||
|
walkPath(filepath, root, callback_openPath, this);
|
||||||
|
|
||||||
|
return File();
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//boolean SDClass::close() {
|
||||||
|
// /*
|
||||||
|
//
|
||||||
|
// Closes the file opened by the `open` method.
|
||||||
|
//
|
||||||
|
// */
|
||||||
|
// file.close();
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
boolean SDClass::exists(const char *filepath) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Returns true if the supplied file path exists.
|
||||||
|
|
||||||
|
*/
|
||||||
|
return walkPath(filepath, root, callback_pathExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
|
||||||
|
// /*
|
||||||
|
//
|
||||||
|
// Returns true if the supplied file path rooted at `parentDir`
|
||||||
|
// exists.
|
||||||
|
//
|
||||||
|
// */
|
||||||
|
// return walkPath(filepath, parentDir, callback_pathExists);
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
boolean SDClass::mkdir(const char *filepath) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Makes a single directory or a hierarchy of directories.
|
||||||
|
|
||||||
|
A rough equivalent to `mkdir -p`.
|
||||||
|
|
||||||
|
*/
|
||||||
|
return walkPath(filepath, root, callback_makeDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean SDClass::rmdir(const char *filepath) {
|
||||||
|
/*
|
||||||
|
|
||||||
|
Remove a single directory or a hierarchy of directories.
|
||||||
|
|
||||||
|
A rough equivalent to `rm -rf`.
|
||||||
|
|
||||||
|
*/
|
||||||
|
return walkPath(filepath, root, callback_rmdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean SDClass::remove(const char *filepath) {
|
||||||
|
return walkPath(filepath, root, callback_remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// allows you to recurse into a directory
|
||||||
|
File File::openNextFile(uint8_t mode) {
|
||||||
|
dir_t p;
|
||||||
|
|
||||||
|
//Serial.print("\t\treading dir...");
|
||||||
|
while (_file->readDir(&p) > 0) {
|
||||||
|
|
||||||
|
// done if past last used entry
|
||||||
|
if (p.name[0] == DIR_NAME_FREE) {
|
||||||
|
//Serial.println("end");
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip deleted entry and entries for . and ..
|
||||||
|
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') {
|
||||||
|
//Serial.println("dots");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only list subdirectories and files
|
||||||
|
if (!DIR_IS_FILE_OR_SUBDIR(&p)) {
|
||||||
|
//Serial.println("notafile");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print file name with possible blank fill
|
||||||
|
SdFile f;
|
||||||
|
char name[13];
|
||||||
|
_file->dirName(p, name);
|
||||||
|
//Serial.print("try to open file ");
|
||||||
|
//Serial.println(name);
|
||||||
|
|
||||||
|
if (f.open(_file, name, mode)) {
|
||||||
|
//Serial.println("OK!");
|
||||||
|
return File(f, name);
|
||||||
|
} else {
|
||||||
|
//Serial.println("ugh");
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Serial.println("nothing");
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::rewindDirectory(void) {
|
||||||
|
if (isDirectory()) {
|
||||||
|
_file->rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDClass SD;
|
||||||
|
|
||||||
|
};
|
138
libraries/SD/src/SD.h
Executable file
138
libraries/SD/src/SD.h
Executable file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
SD - a slightly more friendly wrapper for sdfatlib
|
||||||
|
|
||||||
|
This library aims to expose a subset of SD card functionality
|
||||||
|
in the form of a higher level "wrapper" object.
|
||||||
|
|
||||||
|
License: GNU General Public License V3
|
||||||
|
(Because sdfatlib is licensed with this.)
|
||||||
|
|
||||||
|
(C) Copyright 2010 SparkFun Electronics
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SD_H__
|
||||||
|
#define __SD_H__
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "utility/SdFat.h"
|
||||||
|
#include "utility/SdFatUtil.h"
|
||||||
|
|
||||||
|
#define FILE_READ O_READ
|
||||||
|
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_APPEND)
|
||||||
|
|
||||||
|
namespace SDLib {
|
||||||
|
|
||||||
|
class File : public Stream {
|
||||||
|
private:
|
||||||
|
char _name[13]; // our name
|
||||||
|
SdFile *_file; // underlying file pointer
|
||||||
|
|
||||||
|
public:
|
||||||
|
File(SdFile f, const char *name); // wraps an underlying SdFile
|
||||||
|
File(void); // 'empty' constructor
|
||||||
|
virtual size_t write(uint8_t);
|
||||||
|
virtual size_t write(const uint8_t *buf, size_t size);
|
||||||
|
virtual int availableForWrite();
|
||||||
|
virtual int read();
|
||||||
|
virtual int peek();
|
||||||
|
virtual int available();
|
||||||
|
virtual void flush();
|
||||||
|
int read(void *buf, uint16_t nbyte);
|
||||||
|
boolean seek(uint32_t pos);
|
||||||
|
uint32_t position();
|
||||||
|
uint32_t size();
|
||||||
|
void close();
|
||||||
|
operator bool();
|
||||||
|
char * name();
|
||||||
|
|
||||||
|
boolean isDirectory(void);
|
||||||
|
File openNextFile(uint8_t mode = O_RDONLY);
|
||||||
|
void rewindDirectory(void);
|
||||||
|
|
||||||
|
using Print::write;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SDClass {
|
||||||
|
|
||||||
|
private:
|
||||||
|
// These are required for initialisation and use of sdfatlib
|
||||||
|
Sd2Card card;
|
||||||
|
SdVolume volume;
|
||||||
|
SdFile root;
|
||||||
|
|
||||||
|
// my quick&dirty iterator, should be replaced
|
||||||
|
SdFile getParentDir(const char *filepath, int *indx);
|
||||||
|
public:
|
||||||
|
// This needs to be called to set up the connection to the SD card
|
||||||
|
// before other methods are used.
|
||||||
|
boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);
|
||||||
|
boolean begin(uint32_t clock, uint8_t csPin);
|
||||||
|
|
||||||
|
//call this when a card is removed. It will allow you to insert and initialise a new card.
|
||||||
|
void end();
|
||||||
|
|
||||||
|
// Open the specified file/directory with the supplied mode (e.g. read or
|
||||||
|
// write, etc). Returns a File object for interacting with the file.
|
||||||
|
// Note that currently only one file can be open at a time.
|
||||||
|
File open(const char *filename, uint8_t mode = FILE_READ);
|
||||||
|
File open(const String &filename, uint8_t mode = FILE_READ) {
|
||||||
|
return open(filename.c_str(), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods to determine if the requested file path exists.
|
||||||
|
boolean exists(const char *filepath);
|
||||||
|
boolean exists(const String &filepath) {
|
||||||
|
return exists(filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the requested directory heirarchy--if intermediate directories
|
||||||
|
// do not exist they will be created.
|
||||||
|
boolean mkdir(const char *filepath);
|
||||||
|
boolean mkdir(const String &filepath) {
|
||||||
|
return mkdir(filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file.
|
||||||
|
boolean remove(const char *filepath);
|
||||||
|
boolean remove(const String &filepath) {
|
||||||
|
return remove(filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean rmdir(const char *filepath);
|
||||||
|
boolean rmdir(const String &filepath) {
|
||||||
|
return rmdir(filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// This is used to determine the mode used to open a file
|
||||||
|
// it's here because it's the easiest place to pass the
|
||||||
|
// information through the directory walking function. But
|
||||||
|
// it's probably not the best place for it.
|
||||||
|
// It shouldn't be set directly--it is set via the parameters to `open`.
|
||||||
|
int fileOpenMode;
|
||||||
|
|
||||||
|
friend class File;
|
||||||
|
friend boolean callback_openPath(SdFile&, const char *, boolean, void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SDClass SD;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// We enclose File and SD classes in namespace SDLib to avoid conflicts
|
||||||
|
// with others legacy libraries that redefines File class.
|
||||||
|
|
||||||
|
// This ensure compatibility with sketches that uses only SD library
|
||||||
|
using namespace SDLib;
|
||||||
|
|
||||||
|
// This allows sketches to use SDLib::File with other libraries (in the
|
||||||
|
// sketch you must use SDFile instead of File to disambiguate)
|
||||||
|
typedef SDLib::File SDFile;
|
||||||
|
typedef SDLib::SDClass SDFileSystemClass;
|
||||||
|
#define SDFileSystem SDLib::SD
|
||||||
|
|
||||||
|
#endif
|
418
libraries/SD/src/utility/FatStructs.h
Executable file
418
libraries/SD/src/utility/FatStructs.h
Executable file
|
@ -0,0 +1,418 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef FatStructs_h
|
||||||
|
#define FatStructs_h
|
||||||
|
/**
|
||||||
|
\file
|
||||||
|
FAT file structures
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
mostly from Microsoft document fatgen103.doc
|
||||||
|
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Value for byte 510 of boot block or MBR */
|
||||||
|
uint8_t const BOOTSIG0 = 0X55;
|
||||||
|
/** Value for byte 511 of boot block or MBR */
|
||||||
|
uint8_t const BOOTSIG1 = 0XAA;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\struct partitionTable
|
||||||
|
\brief MBR partition table entry
|
||||||
|
|
||||||
|
A partition table entry for a MBR formatted storage device.
|
||||||
|
The MBR partition table has four entries.
|
||||||
|
*/
|
||||||
|
struct partitionTable {
|
||||||
|
/**
|
||||||
|
Boot Indicator . Indicates whether the volume is the active
|
||||||
|
partition. Legal values include: 0X00. Do not use for booting.
|
||||||
|
0X80 Active partition.
|
||||||
|
*/
|
||||||
|
uint8_t boot;
|
||||||
|
/**
|
||||||
|
Head part of Cylinder-head-sector address of the first block in
|
||||||
|
the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginHead;
|
||||||
|
/**
|
||||||
|
Sector part of Cylinder-head-sector address of the first block in
|
||||||
|
the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned beginSector : 6;
|
||||||
|
/** High bits cylinder for first block in partition. */
|
||||||
|
unsigned beginCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||||
|
are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginCylinderLow;
|
||||||
|
/**
|
||||||
|
Partition type. See defines that begin with PART_TYPE_ for
|
||||||
|
some Microsoft partition types.
|
||||||
|
*/
|
||||||
|
uint8_t type;
|
||||||
|
/**
|
||||||
|
head part of cylinder-head-sector address of the last sector in the
|
||||||
|
partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endHead;
|
||||||
|
/**
|
||||||
|
Sector part of cylinder-head-sector address of the last sector in
|
||||||
|
the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned endSector : 6;
|
||||||
|
/** High bits of end cylinder */
|
||||||
|
unsigned endCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
Combine endCylinderLow with endCylinderHigh. Legal values
|
||||||
|
are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endCylinderLow;
|
||||||
|
/** Logical block address of the first block in the partition. */
|
||||||
|
uint32_t firstSector;
|
||||||
|
/** Length of the partition, in blocks. */
|
||||||
|
uint32_t totalSectors;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for partitionTable */
|
||||||
|
typedef struct partitionTable part_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\struct masterBootRecord
|
||||||
|
|
||||||
|
\brief Master Boot Record
|
||||||
|
|
||||||
|
The first block of a storage device that is formatted with a MBR.
|
||||||
|
*/
|
||||||
|
struct masterBootRecord {
|
||||||
|
/** Code Area for master boot program. */
|
||||||
|
uint8_t codeArea[440];
|
||||||
|
/** Optional WindowsNT disk signature. May contain more boot code. */
|
||||||
|
uint32_t diskSignature;
|
||||||
|
/** Usually zero but may be more boot code. */
|
||||||
|
uint16_t usuallyZero;
|
||||||
|
/** Partition tables. */
|
||||||
|
part_t part[4];
|
||||||
|
/** First MBR signature byte. Must be 0X55 */
|
||||||
|
uint8_t mbrSig0;
|
||||||
|
/** Second MBR signature byte. Must be 0XAA */
|
||||||
|
uint8_t mbrSig1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for masterBootRecord */
|
||||||
|
typedef struct masterBootRecord mbr_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\struct biosParmBlock
|
||||||
|
|
||||||
|
\brief BIOS parameter block
|
||||||
|
|
||||||
|
The BIOS parameter block describes the physical layout of a FAT volume.
|
||||||
|
*/
|
||||||
|
struct biosParmBlock {
|
||||||
|
/**
|
||||||
|
Count of bytes per sector. This value may take on only the
|
||||||
|
following values: 512, 1024, 2048 or 4096
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
Number of sectors per allocation unit. This value must be a
|
||||||
|
power of 2 that is greater than 0. The legal values are
|
||||||
|
1, 2, 4, 8, 16, 32, 64, and 128.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
Number of sectors before the first FAT.
|
||||||
|
This value must not be zero.
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/** The count of FAT data structures on the volume. This field should
|
||||||
|
always contain the value 2 for any FAT volume of any type.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
For FAT12 and FAT16 volumes, this field contains the count of
|
||||||
|
32-byte directory entries in the root directory. For FAT32 volumes,
|
||||||
|
this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||||
|
value should always specify a count that when multiplied by 32
|
||||||
|
results in a multiple of bytesPerSector. FAT16 volumes should
|
||||||
|
use the value 512.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
This field is the old 16-bit total count of sectors on the volume.
|
||||||
|
This count includes the count of all sectors in all four regions
|
||||||
|
of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||||
|
must be non-zero. For FAT32 volumes, this field must be 0. For
|
||||||
|
FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||||
|
totalSectors32 is 0 if the total sector count fits
|
||||||
|
(is less than 0x10000).
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
for fixed (non-removable) media. For removable media, 0xF0 is
|
||||||
|
frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||||
|
On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrtack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
Count of hidden sectors preceding the partition that contains this
|
||||||
|
FAT volume. This field is generally only relevant for media
|
||||||
|
visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
This field is the new 32-bit total count of sectors on the volume.
|
||||||
|
This count includes the count of all sectors in all four regions
|
||||||
|
of the volume. This field can be 0; if it is 0, then
|
||||||
|
totalSectors16 must be non-zero.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
Count of sectors occupied by one FAT on FAT32 volumes.
|
||||||
|
*/
|
||||||
|
uint32_t sectorsPerFat32;
|
||||||
|
/**
|
||||||
|
This field is only defined for FAT32 media and does not exist on
|
||||||
|
FAT12 and FAT16 media.
|
||||||
|
Bits 0-3 -- Zero-based number of active FAT.
|
||||||
|
Only valid if mirroring is disabled.
|
||||||
|
Bits 4-6 -- Reserved.
|
||||||
|
Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||||
|
-- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||||
|
Bits 8-15 -- Reserved.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Flags;
|
||||||
|
/**
|
||||||
|
FAT32 version. High byte is major revision number.
|
||||||
|
Low byte is minor revision number. Only 0.0 define.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Version;
|
||||||
|
/**
|
||||||
|
Cluster number of the first cluster of the root directory for FAT32.
|
||||||
|
This usually 2 but not required to be 2.
|
||||||
|
*/
|
||||||
|
uint32_t fat32RootCluster;
|
||||||
|
/**
|
||||||
|
Sector number of FSINFO structure in the reserved area of the
|
||||||
|
FAT32 volume. Usually 1.
|
||||||
|
*/
|
||||||
|
uint16_t fat32FSInfo;
|
||||||
|
/**
|
||||||
|
If non-zero, indicates the sector number in the reserved area
|
||||||
|
of the volume of a copy of the boot record. Usually 6.
|
||||||
|
No value other than 6 is recommended.
|
||||||
|
*/
|
||||||
|
uint16_t fat32BackBootBlock;
|
||||||
|
/**
|
||||||
|
Reserved for future expansion. Code that formats FAT32 volumes
|
||||||
|
should always set all of the bytes of this field to 0.
|
||||||
|
*/
|
||||||
|
uint8_t fat32Reserved[12];
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for biosParmBlock */
|
||||||
|
typedef struct biosParmBlock bpb_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\struct fat32BootSector
|
||||||
|
|
||||||
|
\brief Boot sector for a FAT16 or FAT32 volume.
|
||||||
|
|
||||||
|
*/
|
||||||
|
struct fat32BootSector {
|
||||||
|
/** X86 jmp to boot program */
|
||||||
|
uint8_t jmpToBootCode[3];
|
||||||
|
/** informational only - don't depend on it */
|
||||||
|
char oemName[8];
|
||||||
|
/** BIOS Parameter Block */
|
||||||
|
bpb_t bpb;
|
||||||
|
/** for int0x13 use value 0X80 for hard drive */
|
||||||
|
uint8_t driveNumber;
|
||||||
|
/** used by Windows NT - should be zero for FAT */
|
||||||
|
uint8_t reserved1;
|
||||||
|
/** 0X29 if next three fields are valid */
|
||||||
|
uint8_t bootSignature;
|
||||||
|
/** usually generated by combining date and time */
|
||||||
|
uint32_t volumeSerialNumber;
|
||||||
|
/** should match volume label in root dir */
|
||||||
|
char volumeLabel[11];
|
||||||
|
/** informational only - don't depend on it */
|
||||||
|
char fileSystemType[8];
|
||||||
|
/** X86 boot code */
|
||||||
|
uint8_t bootCode[420];
|
||||||
|
/** must be 0X55 */
|
||||||
|
uint8_t bootSectorSig0;
|
||||||
|
/** must be 0XAA */
|
||||||
|
uint8_t bootSectorSig1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// End Of Chain values for FAT entries
|
||||||
|
/** FAT16 end of chain value used by Microsoft. */
|
||||||
|
uint16_t const FAT16EOC = 0XFFFF;
|
||||||
|
/** Minimum value for FAT16 EOC. Use to test for EOC. */
|
||||||
|
uint16_t const FAT16EOC_MIN = 0XFFF8;
|
||||||
|
/** FAT32 end of chain value used by Microsoft. */
|
||||||
|
uint32_t const FAT32EOC = 0X0FFFFFFF;
|
||||||
|
/** Minimum value for FAT32 EOC. Use to test for EOC. */
|
||||||
|
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
|
||||||
|
/** Mask a for FAT32 entry. Entries are 28 bits. */
|
||||||
|
uint32_t const FAT32MASK = 0X0FFFFFFF;
|
||||||
|
|
||||||
|
/** Type name for fat32BootSector */
|
||||||
|
typedef struct fat32BootSector fbs_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\struct directoryEntry
|
||||||
|
\brief FAT short directory entry
|
||||||
|
|
||||||
|
Short means short 8.3 name, not the entry size.
|
||||||
|
|
||||||
|
Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||||
|
basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||||
|
format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||||
|
16-bit word):
|
||||||
|
|
||||||
|
Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||||
|
inclusive (1980-2107).
|
||||||
|
|
||||||
|
Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||||
|
|
||||||
|
Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||||
|
|
||||||
|
Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||||
|
a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||||
|
16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||||
|
|
||||||
|
Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||||
|
|
||||||
|
Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||||
|
|
||||||
|
Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||||
|
|
||||||
|
The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||||
|
*/
|
||||||
|
struct directoryEntry {
|
||||||
|
/**
|
||||||
|
Short 8.3 name.
|
||||||
|
The first eight bytes contain the file name with blank fill.
|
||||||
|
The last three bytes contain the file extension with blank fill.
|
||||||
|
*/
|
||||||
|
uint8_t name[11];
|
||||||
|
/** Entry attributes.
|
||||||
|
|
||||||
|
The upper two bits of the attribute byte are reserved and should
|
||||||
|
always be set to 0 when a file is created and never modified or
|
||||||
|
looked at after that. See defines that begin with DIR_ATT_.
|
||||||
|
*/
|
||||||
|
uint8_t attributes;
|
||||||
|
/**
|
||||||
|
Reserved for use by Windows NT. Set value to 0 when a file is
|
||||||
|
created and never modify or look at it after that.
|
||||||
|
*/
|
||||||
|
uint8_t reservedNT;
|
||||||
|
/**
|
||||||
|
The granularity of the seconds part of creationTime is 2 seconds
|
||||||
|
so this field is a count of tenths of a second and its valid
|
||||||
|
value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||||
|
*/
|
||||||
|
uint8_t creationTimeTenths;
|
||||||
|
/** Time file was created. */
|
||||||
|
uint16_t creationTime;
|
||||||
|
/** Date file was created. */
|
||||||
|
uint16_t creationDate;
|
||||||
|
/**
|
||||||
|
Last access date. Note that there is no last access time, only
|
||||||
|
a date. This is the date of last read or write. In the case of
|
||||||
|
a write, this should be set to the same date as lastWriteDate.
|
||||||
|
*/
|
||||||
|
uint16_t lastAccessDate;
|
||||||
|
/**
|
||||||
|
High word of this entry's first cluster number (always 0 for a
|
||||||
|
FAT12 or FAT16 volume).
|
||||||
|
*/
|
||||||
|
uint16_t firstClusterHigh;
|
||||||
|
/** Time of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteTime;
|
||||||
|
/** Date of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteDate;
|
||||||
|
/** Low word of this entry's first cluster number. */
|
||||||
|
uint16_t firstClusterLow;
|
||||||
|
/** 32-bit unsigned holding this file's size in bytes. */
|
||||||
|
uint32_t fileSize;
|
||||||
|
} __attribute__((packed));
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Definitions for directory entries
|
||||||
|
//
|
||||||
|
/** Type name for directoryEntry */
|
||||||
|
typedef struct directoryEntry dir_t;
|
||||||
|
/** escape for name[0] = 0XE5 */
|
||||||
|
uint8_t const DIR_NAME_0XE5 = 0X05;
|
||||||
|
/** name[0] value for entry that is free after being "deleted" */
|
||||||
|
uint8_t const DIR_NAME_DELETED = 0XE5;
|
||||||
|
/** name[0] value for entry that is free and no allocated entries follow */
|
||||||
|
uint8_t const DIR_NAME_FREE = 0X00;
|
||||||
|
/** file is read-only */
|
||||||
|
uint8_t const DIR_ATT_READ_ONLY = 0X01;
|
||||||
|
/** File should hidden in directory listings */
|
||||||
|
uint8_t const DIR_ATT_HIDDEN = 0X02;
|
||||||
|
/** Entry is for a system file */
|
||||||
|
uint8_t const DIR_ATT_SYSTEM = 0X04;
|
||||||
|
/** Directory entry contains the volume label */
|
||||||
|
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
|
||||||
|
/** Entry is for a directory */
|
||||||
|
uint8_t const DIR_ATT_DIRECTORY = 0X10;
|
||||||
|
/** Old DOS archive bit for backup support */
|
||||||
|
uint8_t const DIR_ATT_ARCHIVE = 0X20;
|
||||||
|
/** Test value for long name entry. Test is
|
||||||
|
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
|
||||||
|
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
|
||||||
|
/** Test mask for long name entry */
|
||||||
|
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
|
||||||
|
/** defined attribute bits */
|
||||||
|
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
|
||||||
|
/** Directory entry is part of a long name */
|
||||||
|
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||||
|
}
|
||||||
|
/** Mask for file/subdirectory tests */
|
||||||
|
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||||
|
/** Directory entry is for a file */
|
||||||
|
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a subdirectory */
|
||||||
|
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a file or subdirectory */
|
||||||
|
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||||
|
}
|
||||||
|
#endif // FatStructs_h
|
777
libraries/SD/src/utility/Sd2Card.cpp
Executable file
777
libraries/SD/src/utility/Sd2Card.cpp
Executable file
|
@ -0,0 +1,777 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino Sd2Card Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino Sd2Card Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#define USE_SPI_LIB
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "Sd2Card.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
|
||||||
|
#ifndef SDCARD_SPI
|
||||||
|
#define SDCARD_SPI SPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
static SPISettings settings;
|
||||||
|
#endif
|
||||||
|
// functions for hardware SPI
|
||||||
|
/** Send a byte to the card */
|
||||||
|
static void spiSend(uint8_t b) {
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
SPDR = b;
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
#else
|
||||||
|
SDCARD_SPI.transfer(b);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/** Receive a byte from the card */
|
||||||
|
static uint8_t spiRec(void) {
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
spiSend(0XFF);
|
||||||
|
return SPDR;
|
||||||
|
#else
|
||||||
|
return SDCARD_SPI.transfer(0xFF);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else // SOFTWARE_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** nop to tune soft SPI timing */
|
||||||
|
#define nop asm volatile ("nop\n\t")
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI receive */
|
||||||
|
uint8_t spiRec(void) {
|
||||||
|
uint8_t data = 0;
|
||||||
|
// no interrupts during byte receive - about 8 us
|
||||||
|
cli();
|
||||||
|
// output pin high - like sending 0XFF
|
||||||
|
fastDigitalWrite(SPI_MOSI_PIN, HIGH);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||||
|
|
||||||
|
// adjust so SCK is nice
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
|
||||||
|
data <<= 1;
|
||||||
|
|
||||||
|
if (fastDigitalRead(SPI_MISO_PIN)) {
|
||||||
|
data |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
}
|
||||||
|
// enable interrupts
|
||||||
|
sei();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Soft SPI send */
|
||||||
|
void spiSend(uint8_t data) {
|
||||||
|
// no interrupts during byte send - about 8 us
|
||||||
|
cli();
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
|
||||||
|
|
||||||
|
data <<= 1;
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||||
|
}
|
||||||
|
// hold SCK high for a few ns
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
|
||||||
|
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||||
|
// enable interrupts
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send command and return error code. Return zero for OK
|
||||||
|
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||||
|
// end read if in partialBlockRead mode
|
||||||
|
readEnd();
|
||||||
|
|
||||||
|
// select card
|
||||||
|
chipSelectLow();
|
||||||
|
|
||||||
|
// wait up to 300 ms if busy
|
||||||
|
waitNotBusy(300);
|
||||||
|
|
||||||
|
// send command
|
||||||
|
spiSend(cmd | 0x40);
|
||||||
|
|
||||||
|
// send argument
|
||||||
|
for (int8_t s = 24; s >= 0; s -= 8) {
|
||||||
|
spiSend(arg >> s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send CRC
|
||||||
|
uint8_t crc = 0XFF;
|
||||||
|
if (cmd == CMD0) {
|
||||||
|
crc = 0X95; // correct crc for CMD0 with arg 0
|
||||||
|
}
|
||||||
|
if (cmd == CMD8) {
|
||||||
|
crc = 0X87; // correct crc for CMD8 with arg 0X1AA
|
||||||
|
}
|
||||||
|
spiSend(crc);
|
||||||
|
|
||||||
|
// wait for response
|
||||||
|
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++)
|
||||||
|
;
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Determine the size of an SD flash memory card.
|
||||||
|
|
||||||
|
\return The number of 512 byte data blocks in the card
|
||||||
|
or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
uint32_t Sd2Card::cardSize(void) {
|
||||||
|
csd_t csd;
|
||||||
|
if (!readCSD(&csd)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (csd.v1.csd_ver == 0) {
|
||||||
|
uint8_t read_bl_len = csd.v1.read_bl_len;
|
||||||
|
uint16_t c_size = (csd.v1.c_size_high << 10)
|
||||||
|
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
|
||||||
|
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
|
||||||
|
| csd.v1.c_size_mult_low;
|
||||||
|
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
||||||
|
} else if (csd.v2.csd_ver == 1) {
|
||||||
|
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
|
||||||
|
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
|
||||||
|
return (c_size + 1) << 10;
|
||||||
|
} else {
|
||||||
|
error(SD_CARD_ERROR_BAD_CSD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static uint8_t chip_select_asserted = 0;
|
||||||
|
|
||||||
|
void Sd2Card::chipSelectHigh(void) {
|
||||||
|
digitalWrite(chipSelectPin_, HIGH);
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
if (chip_select_asserted) {
|
||||||
|
chip_select_asserted = 0;
|
||||||
|
SDCARD_SPI.endTransaction();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void Sd2Card::chipSelectLow(void) {
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
if (!chip_select_asserted) {
|
||||||
|
chip_select_asserted = 1;
|
||||||
|
SDCARD_SPI.beginTransaction(settings);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
digitalWrite(chipSelectPin_, LOW);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Erase a range of blocks.
|
||||||
|
|
||||||
|
\param[in] firstBlock The address of the first block in the range.
|
||||||
|
\param[in] lastBlock The address of the last block in the range.
|
||||||
|
|
||||||
|
\note This function requests the SD card to do a flash erase for a
|
||||||
|
range of blocks. The data on the card after an erase operation is
|
||||||
|
either 0 or 1, depends on the card vendor. The card must support
|
||||||
|
single block erase.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||||
|
if (!eraseSingleBlockEnable()) {
|
||||||
|
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (type_ != SD_CARD_TYPE_SDHC) {
|
||||||
|
firstBlock <<= 9;
|
||||||
|
lastBlock <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD32, firstBlock)
|
||||||
|
|| cardCommand(CMD33, lastBlock)
|
||||||
|
|| cardCommand(CMD38, 0)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Determine if card supports single block erase.
|
||||||
|
|
||||||
|
\return The value one, true, is returned if single block erase is supported.
|
||||||
|
The value zero, false, is returned if single block erase is not supported.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::eraseSingleBlockEnable(void) {
|
||||||
|
csd_t csd;
|
||||||
|
return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Initialize an SD flash memory card.
|
||||||
|
|
||||||
|
\param[in] sckRateID SPI clock rate selector. See setSckRate().
|
||||||
|
\param[in] chipSelectPin SD chip select pin number.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure. The reason for failure
|
||||||
|
can be determined by calling errorCode() and errorData().
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
|
||||||
|
errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
|
||||||
|
chipSelectPin_ = chipSelectPin;
|
||||||
|
// 16-bit init start time allows over a minute
|
||||||
|
unsigned int t0 = millis();
|
||||||
|
uint32_t arg;
|
||||||
|
|
||||||
|
// set pin modes
|
||||||
|
pinMode(chipSelectPin_, OUTPUT);
|
||||||
|
digitalWrite(chipSelectPin_, HIGH);
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
pinMode(SPI_MISO_PIN, INPUT);
|
||||||
|
pinMode(SPI_MOSI_PIN, OUTPUT);
|
||||||
|
pinMode(SPI_SCK_PIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
// SS must be in output mode even it is not chip select
|
||||||
|
pinMode(SS_PIN, OUTPUT);
|
||||||
|
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
|
||||||
|
// Enable SPI, Master, clock rate f_osc/128
|
||||||
|
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
|
||||||
|
// clear double speed
|
||||||
|
SPSR &= ~(1 << SPI2X);
|
||||||
|
#else // USE_SPI_LIB
|
||||||
|
SDCARD_SPI.begin();
|
||||||
|
settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
|
||||||
|
#endif // USE_SPI_LIB
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
|
||||||
|
// must supply min of 74 clock cycles with CS high.
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
SDCARD_SPI.beginTransaction(settings);
|
||||||
|
#endif
|
||||||
|
for (uint8_t i = 0; i < 10; i++) {
|
||||||
|
spiSend(0XFF);
|
||||||
|
}
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
SDCARD_SPI.endTransaction();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
chipSelectLow();
|
||||||
|
|
||||||
|
// command to go idle in SPI mode
|
||||||
|
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
|
||||||
|
unsigned int d = millis() - t0;
|
||||||
|
if (d > SD_INIT_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_CMD0);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check SD version
|
||||||
|
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
||||||
|
type(SD_CARD_TYPE_SD1);
|
||||||
|
} else {
|
||||||
|
// only need last byte of r7 response
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
status_ = spiRec();
|
||||||
|
}
|
||||||
|
if (status_ != 0XAA) {
|
||||||
|
error(SD_CARD_ERROR_CMD8);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
type(SD_CARD_TYPE_SD2);
|
||||||
|
}
|
||||||
|
// initialize card and send host supports SDHC if SD2
|
||||||
|
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
||||||
|
|
||||||
|
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
||||||
|
// check for timeout
|
||||||
|
unsigned int d = millis() - t0;
|
||||||
|
if (d > SD_INIT_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_ACMD41);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if SD2 read OCR register to check for SDHC card
|
||||||
|
if (type() == SD_CARD_TYPE_SD2) {
|
||||||
|
if (cardCommand(CMD58, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD58);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((spiRec() & 0XC0) == 0XC0) {
|
||||||
|
type(SD_CARD_TYPE_SDHC);
|
||||||
|
}
|
||||||
|
// discard rest of ocr - contains allowed voltage range
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
spiRec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
return setSckRate(sckRateID);
|
||||||
|
#else // SOFTWARE_SPI
|
||||||
|
return true;
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Enable or disable partial block reads.
|
||||||
|
|
||||||
|
Enabling partial block reads improves performance by allowing a block
|
||||||
|
to be read over the SPI bus as several sub-blocks. Errors may occur
|
||||||
|
if the time between reads is too long since the SD card may timeout.
|
||||||
|
The SPI SS line will be held low until the entire block is read or
|
||||||
|
readEnd() is called.
|
||||||
|
|
||||||
|
Use this for applications like the Adafruit Wave Shield.
|
||||||
|
|
||||||
|
\param[in] value The value TRUE (non-zero) or FALSE (zero).)
|
||||||
|
*/
|
||||||
|
void Sd2Card::partialBlockRead(uint8_t value) {
|
||||||
|
readEnd();
|
||||||
|
partialBlockRead_ = value;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Read a 512 byte block from an SD card device.
|
||||||
|
|
||||||
|
\param[in] block Logical block to be read.
|
||||||
|
\param[out] dst Pointer to the location that will receive the data.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
|
||||||
|
return readData(block, 0, 512, dst);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Read part of a 512 byte block from an SD card.
|
||||||
|
|
||||||
|
\param[in] block Logical block to be read.
|
||||||
|
\param[in] offset Number of bytes to skip at start of block
|
||||||
|
\param[out] dst Pointer to the location that will receive the data.
|
||||||
|
\param[in] count Number of bytes to read
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::readData(uint32_t block,
|
||||||
|
uint16_t offset, uint16_t count, uint8_t* dst) {
|
||||||
|
if (count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((count + offset) > 512) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!inBlock_ || block != block_ || offset < offset_) {
|
||||||
|
block_ = block;
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
block <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD17, block)) {
|
||||||
|
error(SD_CARD_ERROR_CMD17);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!waitStartBlock()) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
offset_ = 0;
|
||||||
|
inBlock_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||||
|
// start first spi transfer
|
||||||
|
SPDR = 0XFF;
|
||||||
|
|
||||||
|
// skip data before offset
|
||||||
|
for (; offset_ < offset; offset_++) {
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
}
|
||||||
|
// transfer data
|
||||||
|
n = count - 1;
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
dst[i] = SPDR;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
}
|
||||||
|
// wait for last byte
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
dst[n] = SPDR;
|
||||||
|
|
||||||
|
#else // OPTIMIZE_HARDWARE_SPI
|
||||||
|
|
||||||
|
// skip data before offset
|
||||||
|
for (; offset_ < offset; offset_++) {
|
||||||
|
spiRec();
|
||||||
|
}
|
||||||
|
// transfer data
|
||||||
|
for (uint16_t i = 0; i < count; i++) {
|
||||||
|
dst[i] = spiRec();
|
||||||
|
}
|
||||||
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
|
|
||||||
|
offset_ += count;
|
||||||
|
if (!partialBlockRead_ || offset_ >= 512) {
|
||||||
|
// read rest of data, checksum and set chip select high
|
||||||
|
readEnd();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Skip remaining data in a block when in partial block read mode. */
|
||||||
|
void Sd2Card::readEnd(void) {
|
||||||
|
if (inBlock_) {
|
||||||
|
// skip data and crc
|
||||||
|
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||||
|
// optimize skip for hardware
|
||||||
|
SPDR = 0XFF;
|
||||||
|
while (offset_++ < 513) {
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
}
|
||||||
|
// wait for last crc byte
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
#else // OPTIMIZE_HARDWARE_SPI
|
||||||
|
while (offset_++ < 514) {
|
||||||
|
spiRec();
|
||||||
|
}
|
||||||
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
|
chipSelectHigh();
|
||||||
|
inBlock_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** read CID or CSR register */
|
||||||
|
uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
||||||
|
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||||
|
if (cardCommand(cmd, 0)) {
|
||||||
|
error(SD_CARD_ERROR_READ_REG);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!waitStartBlock()) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// transfer data
|
||||||
|
for (uint16_t i = 0; i < 16; i++) {
|
||||||
|
dst[i] = spiRec();
|
||||||
|
}
|
||||||
|
spiRec(); // get first crc byte
|
||||||
|
spiRec(); // get second crc byte
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Set the SPI clock rate.
|
||||||
|
|
||||||
|
\param[in] sckRateID A value in the range [0, 6].
|
||||||
|
|
||||||
|
The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
|
||||||
|
SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
|
||||||
|
for \a scsRateID = 6.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and the value zero,
|
||||||
|
false, is returned for an invalid value of \a sckRateID.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
|
||||||
|
if (sckRateID > 6) {
|
||||||
|
error(SD_CARD_ERROR_SCK_RATE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
// see avr processor datasheet for SPI register bit definitions
|
||||||
|
if ((sckRateID & 1) || sckRateID == 6) {
|
||||||
|
SPSR &= ~(1 << SPI2X);
|
||||||
|
} else {
|
||||||
|
SPSR |= (1 << SPI2X);
|
||||||
|
}
|
||||||
|
SPCR &= ~((1 << SPR1) | (1 << SPR0));
|
||||||
|
SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
|
||||||
|
| (sckRateID & 2 ? (1 << SPR0) : 0);
|
||||||
|
#else // USE_SPI_LIB
|
||||||
|
switch (sckRateID) {
|
||||||
|
case 0: settings = SPISettings(25000000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
case 1: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
case 2: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
case 3: settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
case 4: settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
case 5: settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break;
|
||||||
|
default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0);
|
||||||
|
}
|
||||||
|
#endif // USE_SPI_LIB
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// set the SPI clock frequency
|
||||||
|
uint8_t Sd2Card::setSpiClock(uint32_t clock) {
|
||||||
|
settings = SPISettings(clock, MSBFIRST, SPI_MODE0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// wait for card to go not busy
|
||||||
|
uint8_t Sd2Card::waitNotBusy(unsigned int timeoutMillis) {
|
||||||
|
unsigned int t0 = millis();
|
||||||
|
unsigned int d;
|
||||||
|
do {
|
||||||
|
if (spiRec() == 0XFF) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
d = millis() - t0;
|
||||||
|
} while (d < timeoutMillis);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Wait for start block token */
|
||||||
|
uint8_t Sd2Card::waitStartBlock(void) {
|
||||||
|
unsigned int t0 = millis();
|
||||||
|
while ((status_ = spiRec()) == 0XFF) {
|
||||||
|
unsigned int d = millis() - t0;
|
||||||
|
if (d > SD_READ_TIMEOUT) {
|
||||||
|
error(SD_CARD_ERROR_READ_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status_ != DATA_START_BLOCK) {
|
||||||
|
error(SD_CARD_ERROR_READ);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Writes a 512 byte block to an SD card.
|
||||||
|
|
||||||
|
\param[in] blockNumber Logical block to be written.
|
||||||
|
\param[in] src Pointer to the location of the data to be written.
|
||||||
|
\param[in] blocking If the write should be blocking.
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src, uint8_t blocking) {
|
||||||
|
#if SD_PROTECT_BLOCK_ZERO
|
||||||
|
// don't allow write to first block
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif // SD_PROTECT_BLOCK_ZERO
|
||||||
|
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD24, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD24);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!writeData(DATA_START_BLOCK, src)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (blocking) {
|
||||||
|
// wait for flash programming to complete
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// response is r2 so get and check two bytes for nonzero
|
||||||
|
if (cardCommand(CMD13, 0) || spiRec()) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Write one data block in a multiple block write sequence */
|
||||||
|
uint8_t Sd2Card::writeData(const uint8_t* src) {
|
||||||
|
// wait for previous write to finish
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return writeData(WRITE_MULTIPLE_TOKEN, src);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send one block of data for write block or write multiple blocks
|
||||||
|
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
||||||
|
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||||
|
|
||||||
|
// send data - optimized loop
|
||||||
|
SPDR = token;
|
||||||
|
|
||||||
|
// send two byte per iteration
|
||||||
|
for (uint16_t i = 0; i < 512; i += 2) {
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
SPDR = src[i];
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
SPDR = src[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for last data byte
|
||||||
|
while (!(SPSR & (1 << SPIF)))
|
||||||
|
;
|
||||||
|
|
||||||
|
#else // OPTIMIZE_HARDWARE_SPI
|
||||||
|
spiSend(token);
|
||||||
|
for (uint16_t i = 0; i < 512; i++) {
|
||||||
|
spiSend(src[i]);
|
||||||
|
}
|
||||||
|
#endif // OPTIMIZE_HARDWARE_SPI
|
||||||
|
spiSend(0xff); // dummy crc
|
||||||
|
spiSend(0xff); // dummy crc
|
||||||
|
|
||||||
|
status_ = spiRec();
|
||||||
|
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||||
|
error(SD_CARD_ERROR_WRITE);
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Start a write multiple blocks sequence.
|
||||||
|
|
||||||
|
\param[in] blockNumber Address of first block in sequence.
|
||||||
|
\param[in] eraseCount The number of blocks to be pre-erased.
|
||||||
|
|
||||||
|
\note This function is used with writeData() and writeStop()
|
||||||
|
for optimized multiple block writes.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||||
|
#if SD_PROTECT_BLOCK_ZERO
|
||||||
|
// don't allow write to first block
|
||||||
|
if (blockNumber == 0) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif // SD_PROTECT_BLOCK_ZERO
|
||||||
|
// send pre-erase count
|
||||||
|
if (cardAcmd(ACMD23, eraseCount)) {
|
||||||
|
error(SD_CARD_ERROR_ACMD23);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD25, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD25);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** End a write multiple blocks sequence.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::writeStop(void) {
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
spiSend(STOP_TRAN_TOKEN);
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chipSelectHigh();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
error(SD_CARD_ERROR_STOP_TRAN);
|
||||||
|
chipSelectHigh();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Check if the SD card is busy
|
||||||
|
|
||||||
|
\return The value one, true, is returned when is busy and
|
||||||
|
the value zero, false, is returned for when is NOT busy.
|
||||||
|
*/
|
||||||
|
uint8_t Sd2Card::isBusy(void) {
|
||||||
|
chipSelectLow();
|
||||||
|
byte b = spiRec();
|
||||||
|
chipSelectHigh();
|
||||||
|
|
||||||
|
return (b != 0XFF);
|
||||||
|
}
|
273
libraries/SD/src/utility/Sd2Card.h
Executable file
273
libraries/SD/src/utility/Sd2Card.h
Executable file
|
@ -0,0 +1,273 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino Sd2Card Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino Sd2Card Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef Sd2Card_h
|
||||||
|
#define Sd2Card_h
|
||||||
|
/**
|
||||||
|
\file
|
||||||
|
Sd2Card class
|
||||||
|
*/
|
||||||
|
#include "Sd2PinMap.h"
|
||||||
|
#include "SdInfo.h"
|
||||||
|
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_FULL_SPEED = 0;
|
||||||
|
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_HALF_SPEED = 1;
|
||||||
|
/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
|
||||||
|
uint8_t const SPI_QUARTER_SPEED = 2;
|
||||||
|
/**
|
||||||
|
USE_SPI_LIB: if set, use the SPI library bundled with Arduino IDE, otherwise
|
||||||
|
run with a standalone driver for AVR.
|
||||||
|
*/
|
||||||
|
#define USE_SPI_LIB
|
||||||
|
/**
|
||||||
|
Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
|
||||||
|
Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||||
|
|
||||||
|
MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||||
|
on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||||
|
but many SD cards will fail with GPS Shield V1.0.
|
||||||
|
*/
|
||||||
|
#define MEGA_SOFT_SPI 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
|
||||||
|
#define SOFTWARE_SPI
|
||||||
|
#endif // MEGA_SOFT_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SPI pin definitions
|
||||||
|
//
|
||||||
|
#ifndef SOFTWARE_SPI
|
||||||
|
// hardware pin defs
|
||||||
|
|
||||||
|
// include pins_arduino.h or variant.h depending on architecture, via Arduino.h
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
SD Chip Select pin
|
||||||
|
|
||||||
|
Warning if this pin is redefined the hardware SS will pin will be enabled
|
||||||
|
as an output by init(). An avr processor will not function as an SPI
|
||||||
|
master unless SS is set to output mode.
|
||||||
|
*/
|
||||||
|
#ifndef SDCARD_SS_PIN
|
||||||
|
/** The default chip select pin for the SD card is SS. */
|
||||||
|
uint8_t const SD_CHIP_SELECT_PIN = SS;
|
||||||
|
#else
|
||||||
|
uint8_t const SD_CHIP_SELECT_PIN = SDCARD_SS_PIN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The following three pins must not be redefined for hardware SPI,
|
||||||
|
// so ensure that they are taken from pins_arduino.h or variant.h, depending on architecture.
|
||||||
|
#ifndef SDCARD_MOSI_PIN
|
||||||
|
/** SPI Master Out Slave In pin */
|
||||||
|
uint8_t const SPI_MOSI_PIN = MOSI;
|
||||||
|
/** SPI Master In Slave Out pin */
|
||||||
|
uint8_t const SPI_MISO_PIN = MISO;
|
||||||
|
/** SPI Clock pin */
|
||||||
|
uint8_t const SPI_SCK_PIN = SCK;
|
||||||
|
#else
|
||||||
|
uint8_t const SPI_MOSI_PIN = SDCARD_MOSI_PIN;
|
||||||
|
uint8_t const SPI_MISO_PIN = SDCARD_MISO_PIN;
|
||||||
|
uint8_t const SPI_SCK_PIN = SDCARD_SCK_PIN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** optimize loops for hardware SPI */
|
||||||
|
#ifndef USE_SPI_LIB
|
||||||
|
#define OPTIMIZE_HARDWARE_SPI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else // SOFTWARE_SPI
|
||||||
|
// define software SPI pins so Mega can use unmodified GPS Shield
|
||||||
|
/** SPI chip select pin */
|
||||||
|
uint8_t const SD_CHIP_SELECT_PIN = 10;
|
||||||
|
/** SPI Master Out Slave In pin */
|
||||||
|
uint8_t const SPI_MOSI_PIN = 11;
|
||||||
|
/** SPI Master In Slave Out pin */
|
||||||
|
uint8_t const SPI_MISO_PIN = 12;
|
||||||
|
/** SPI Clock pin */
|
||||||
|
uint8_t const SPI_SCK_PIN = 13;
|
||||||
|
#endif // SOFTWARE_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Protect block zero from write if nonzero */
|
||||||
|
#define SD_PROTECT_BLOCK_ZERO 1
|
||||||
|
/** init timeout ms */
|
||||||
|
unsigned int const SD_INIT_TIMEOUT = 2000;
|
||||||
|
/** erase timeout ms */
|
||||||
|
unsigned int const SD_ERASE_TIMEOUT = 10000;
|
||||||
|
/** read timeout ms */
|
||||||
|
unsigned int const SD_READ_TIMEOUT = 300;
|
||||||
|
/** write time out ms */
|
||||||
|
unsigned int const SD_WRITE_TIMEOUT = 600;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card errors
|
||||||
|
/** timeout error for command CMD0 */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
|
||||||
|
/** CMD8 was not accepted - not a valid SD card*/
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
|
||||||
|
/** card returned an error response for CMD17 (read block) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
|
||||||
|
/** card returned an error response for CMD24 (write block) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
|
||||||
|
/** WRITE_MULTIPLE_BLOCKS command failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
|
||||||
|
/** card returned an error response for CMD58 (read OCR) */
|
||||||
|
uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
|
||||||
|
/** SET_WR_BLK_ERASE_COUNT failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
|
||||||
|
/** card's ACMD41 initialization process timeout */
|
||||||
|
uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
|
||||||
|
/** card returned a bad CSR version field */
|
||||||
|
uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
|
||||||
|
/** erase block group command failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
|
||||||
|
/** card not capable of single block erase */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
|
||||||
|
/** Erase sequence timed out */
|
||||||
|
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
|
||||||
|
/** card returned an error token instead of read data */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ = 0X0D;
|
||||||
|
/** read CID or CSD failed */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
|
||||||
|
/** timeout while waiting for start of read data */
|
||||||
|
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
|
||||||
|
/** card did not accept STOP_TRAN_TOKEN */
|
||||||
|
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
|
||||||
|
/** card returned an error token as a response to a write operation */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE = 0X11;
|
||||||
|
/** attempt to write protected block zero */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
|
||||||
|
/** card did not go ready for a multiple block write */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
|
||||||
|
/** card returned an error to a CMD13 status check after a write */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
|
||||||
|
/** timeout occurred during write programming */
|
||||||
|
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
|
||||||
|
/** incorrect rate selected */
|
||||||
|
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// card types
|
||||||
|
/** Standard capacity V1 SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SD1 = 1;
|
||||||
|
/** Standard capacity V2 SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SD2 = 2;
|
||||||
|
/** High Capacity SD card */
|
||||||
|
uint8_t const SD_CARD_TYPE_SDHC = 3;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\class Sd2Card
|
||||||
|
\brief Raw access to SD and SDHC flash memory cards.
|
||||||
|
*/
|
||||||
|
class Sd2Card {
|
||||||
|
public:
|
||||||
|
/** Construct an instance of Sd2Card. */
|
||||||
|
Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
|
||||||
|
uint32_t cardSize(void);
|
||||||
|
uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||||
|
uint8_t eraseSingleBlockEnable(void);
|
||||||
|
/**
|
||||||
|
\return error code for last error. See Sd2Card.h for a list of error codes.
|
||||||
|
*/
|
||||||
|
uint8_t errorCode(void) const {
|
||||||
|
return errorCode_;
|
||||||
|
}
|
||||||
|
/** \return error data for last error. */
|
||||||
|
uint8_t errorData(void) const {
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Initialize an SD flash memory card with default clock rate and chip
|
||||||
|
select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||||
|
*/
|
||||||
|
uint8_t init(void) {
|
||||||
|
return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Initialize an SD flash memory card with the selected SPI clock rate
|
||||||
|
and the default SD chip select pin.
|
||||||
|
See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||||
|
*/
|
||||||
|
uint8_t init(uint8_t sckRateID) {
|
||||||
|
return init(sckRateID, SD_CHIP_SELECT_PIN);
|
||||||
|
}
|
||||||
|
uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin);
|
||||||
|
void partialBlockRead(uint8_t value);
|
||||||
|
/** Returns the current value, true or false, for partial block read. */
|
||||||
|
uint8_t partialBlockRead(void) const {
|
||||||
|
return partialBlockRead_;
|
||||||
|
}
|
||||||
|
uint8_t readBlock(uint32_t block, uint8_t* dst);
|
||||||
|
uint8_t readData(uint32_t block,
|
||||||
|
uint16_t offset, uint16_t count, uint8_t* dst);
|
||||||
|
/**
|
||||||
|
Read a cards CID register. The CID contains card identification
|
||||||
|
information such as Manufacturer ID, Product name, Product serial
|
||||||
|
number and Manufacturing date. */
|
||||||
|
uint8_t readCID(cid_t* cid) {
|
||||||
|
return readRegister(CMD10, cid);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Read a cards CSD register. The CSD contains Card-Specific Data that
|
||||||
|
provides information regarding access to the card's contents. */
|
||||||
|
uint8_t readCSD(csd_t* csd) {
|
||||||
|
return readRegister(CMD9, csd);
|
||||||
|
}
|
||||||
|
void readEnd(void);
|
||||||
|
uint8_t setSckRate(uint8_t sckRateID);
|
||||||
|
#ifdef USE_SPI_LIB
|
||||||
|
uint8_t setSpiClock(uint32_t clock);
|
||||||
|
#endif
|
||||||
|
/** Return the card type: SD V1, SD V2 or SDHC */
|
||||||
|
uint8_t type(void) const {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src, uint8_t blocking = 1);
|
||||||
|
uint8_t writeData(const uint8_t* src);
|
||||||
|
uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||||
|
uint8_t writeStop(void);
|
||||||
|
uint8_t isBusy(void);
|
||||||
|
private:
|
||||||
|
uint32_t block_;
|
||||||
|
uint8_t chipSelectPin_;
|
||||||
|
uint8_t errorCode_;
|
||||||
|
uint8_t inBlock_;
|
||||||
|
uint16_t offset_;
|
||||||
|
uint8_t partialBlockRead_;
|
||||||
|
uint8_t status_;
|
||||||
|
uint8_t type_;
|
||||||
|
// private functions
|
||||||
|
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||||
|
cardCommand(CMD55, 0);
|
||||||
|
return cardCommand(cmd, arg);
|
||||||
|
}
|
||||||
|
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||||
|
void error(uint8_t code) {
|
||||||
|
errorCode_ = code;
|
||||||
|
}
|
||||||
|
uint8_t readRegister(uint8_t cmd, void* buf);
|
||||||
|
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
|
||||||
|
void chipSelectHigh(void);
|
||||||
|
void chipSelectLow(void);
|
||||||
|
void type(uint8_t value) {
|
||||||
|
type_ = value;
|
||||||
|
}
|
||||||
|
uint8_t waitNotBusy(unsigned int timeoutMillis);
|
||||||
|
uint8_t writeData(uint8_t token, const uint8_t* src);
|
||||||
|
uint8_t waitStartBlock(void);
|
||||||
|
};
|
||||||
|
#endif // Sd2Card_h
|
525
libraries/SD/src/utility/Sd2PinMap.h
Executable file
525
libraries/SD/src/utility/Sd2PinMap.h
Executable file
|
@ -0,0 +1,525 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2010 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#if defined(__arm__) // Arduino Due Board follows
|
||||||
|
|
||||||
|
#ifndef Sd2PinMap_h
|
||||||
|
#define Sd2PinMap_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
uint8_t const SS_PIN = SS;
|
||||||
|
uint8_t const MOSI_PIN = MOSI;
|
||||||
|
uint8_t const MISO_PIN = MISO;
|
||||||
|
uint8_t const SCK_PIN = SCK;
|
||||||
|
|
||||||
|
#endif // Sd2PinMap_h
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATmega4809__) // Arduino UNO WiFI Rev2 follows
|
||||||
|
|
||||||
|
#ifndef Sd2PinMap_h
|
||||||
|
#define Sd2PinMap_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
uint8_t const SS_PIN = SS;
|
||||||
|
uint8_t const MOSI_PIN = MOSI;
|
||||||
|
uint8_t const MISO_PIN = MISO;
|
||||||
|
uint8_t const SCK_PIN = SCK;
|
||||||
|
|
||||||
|
#endif // Sd2PinMap_h
|
||||||
|
|
||||||
|
#elif defined(__AVR__) // Other AVR based Boards follows
|
||||||
|
|
||||||
|
// Warning this file was generated by a program.
|
||||||
|
#ifndef Sd2PinMap_h
|
||||||
|
#define Sd2PinMap_h
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** struct for mapping digital pins */
|
||||||
|
struct pin_map_t {
|
||||||
|
volatile uint8_t* ddr;
|
||||||
|
volatile uint8_t* pin;
|
||||||
|
volatile uint8_t* port;
|
||||||
|
uint8_t bit;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
// Mega
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 20;
|
||||||
|
uint8_t const SCL_PIN = 21;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 53;
|
||||||
|
uint8_t const MOSI_PIN = 51;
|
||||||
|
uint8_t const MISO_PIN = 50;
|
||||||
|
uint8_t const SCK_PIN = 52;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||||
|
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||||
|
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||||
|
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||||
|
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||||
|
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||||
|
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||||
|
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||||
|
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||||
|
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||||
|
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||||
|
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||||
|
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||||
|
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||||
|
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||||
|
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||||
|
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||||
|
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||||
|
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||||
|
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||||
|
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||||
|
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||||
|
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||||
|
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||||
|
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||||
|
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||||
|
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||||
|
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||||
|
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||||
|
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||||
|
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||||
|
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||||
|
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||||
|
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||||
|
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||||
|
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||||
|
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||||
|
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||||
|
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||||
|
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||||
|
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||||
|
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||||
|
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||||
|
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||||
|
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||||
|
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||||
|
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||||
|
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||||
|
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||||
|
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||||
|
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||||
|
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||||
|
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||||
|
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||||
|
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif (defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && defined(CORE_MICRODUINO)
|
||||||
|
// Microduino Core+
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 20;
|
||||||
|
uint8_t const SCL_PIN = 21;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 10;
|
||||||
|
uint8_t const MOSI_PIN = 11;
|
||||||
|
uint8_t const MISO_PIN = 12;
|
||||||
|
uint8_t const SCK_PIN = 13;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 PD0
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 PD1
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 PD2
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 PD3
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // D4 PB0
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // D5 PB1
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // D6 PB2
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // D7 PB3
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D8 PD6
|
||||||
|
{&DDRD, &PIND, &PORTD, 5}, // D9 PD5
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // D10 PB4
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // D11 PB5
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // D12 PB6
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // D13 PB7
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // D14 PC7
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // D15 PC6
|
||||||
|
{&DDRC, &PINC, &PORTC, 5}, // D16 PC5
|
||||||
|
{&DDRC, &PINC, &PORTC, 4}, // D17 PC4
|
||||||
|
{&DDRC, &PINC, &PORTC, 3}, // D18 PC3
|
||||||
|
{&DDRC, &PINC, &PORTC, 2}, // D19 PC2
|
||||||
|
{&DDRC, &PINC, &PORTC, 1}, // D20 PC1
|
||||||
|
{&DDRC, &PINC, &PORTC, 0}, // D21 PC0
|
||||||
|
{&DDRD, &PIND, &PORTD, 4}, // D22 PD4
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D23 PD7
|
||||||
|
{&DDRA, &PINA, &PORTA, 7}, // D24 PA7
|
||||||
|
{&DDRA, &PINA, &PORTA, 6}, // D25 PA6
|
||||||
|
{&DDRA, &PINA, &PORTA, 5}, // D26 PA5
|
||||||
|
{&DDRA, &PINA, &PORTA, 4}, // D27 PA4
|
||||||
|
{&DDRA, &PINA, &PORTA, 3}, // D28 PA3
|
||||||
|
{&DDRA, &PINA, &PORTA, 2}, // D29 PA2
|
||||||
|
{&DDRA, &PINA, &PORTA, 1}, // D30 PA1
|
||||||
|
{&DDRA, &PINA, &PORTA, 0} // D31 PA0
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif defined(__AVR_ATmega128RFA1__) && defined(CORE_MICRODUINO)
|
||||||
|
// Microduino Core RF
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 18;
|
||||||
|
uint8_t const SCL_PIN = 19;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 10;
|
||||||
|
uint8_t const MOSI_PIN = 11;
|
||||||
|
uint8_t const MISO_PIN = 12;
|
||||||
|
uint8_t const SCK_PIN = 13;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PINE, &PORTE, 0}, // D0 PE0
|
||||||
|
{&DDRD, &PINE, &PORTE, 1}, // D1 PE1
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 PD2
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 PD3
|
||||||
|
{&DDRB, &PINE, &PORTE, 3}, // D4 PE3
|
||||||
|
{&DDRB, &PINE, &PORTE, 4}, // D5 PE4
|
||||||
|
{&DDRB, &PINE, &PORTE, 5}, // D6 PE5
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // D7 PB7
|
||||||
|
{&DDRD, &PINB, &PORTB, 6}, // D8 PB6
|
||||||
|
{&DDRD, &PINB, &PORTB, 5}, // D9 PB5
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // D10 PB4
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // D11 PB2
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // D12 PB3
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // D13 PB1
|
||||||
|
{&DDRF, &PINF, &PORTF, 7}, // D14 PF7
|
||||||
|
{&DDRF, &PINF, &PORTF, 6}, // D15 PF6
|
||||||
|
{&DDRF, &PINF, &PORTF, 5}, // D16 PF5
|
||||||
|
{&DDRF, &PINF, &PORTF, 4}, // D17 PF4
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D18 PD1
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D19 PD0
|
||||||
|
{&DDRF, &PINF, &PORTF, 3}, // D20 PF3
|
||||||
|
{&DDRF, &PINF, &PORTF, 2}, // D21 PF2
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif defined(__AVR_ATmega32U4__) && defined(CORE_MICRODUINO)
|
||||||
|
// Microduino Core USB
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 18;
|
||||||
|
uint8_t const SCL_PIN = 19;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 10;
|
||||||
|
uint8_t const MOSI_PIN = 11;
|
||||||
|
uint8_t const MISO_PIN = 12;
|
||||||
|
uint8_t const SCK_PIN = 13;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D0 - PD2
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D1 - PD3
|
||||||
|
{&DDRE, &PINE, &PORTE, 6}, // D2 - PE6
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D3 - PD6
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D4 - PD7
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // D5 - PC6
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // D6 - PC7
|
||||||
|
{&DDRE, &PINE, &PORTE, 7}, // D7 - PE7
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // D8 - PB6
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // D9 - PB5
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // D10 - PB0
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // D11 - MOSI - PB2
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // D12 -MISO - PB3
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // D13 -SCK - PB1
|
||||||
|
{&DDRF, &PINF, &PORTF, 7}, // D14 - A0 - PF7
|
||||||
|
{&DDRF, &PINF, &PORTF, 6}, // D15 - A1 - PF6
|
||||||
|
{&DDRF, &PINF, &PORTF, 5}, // D16 - A2 - PF5
|
||||||
|
{&DDRF, &PINF, &PORTF, 4}, // D17 - A3 - PF4
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D18 - PD1
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D19 - PD0
|
||||||
|
{&DDRF, &PINF, &PORTF, 1}, // D20 - A6 - PF1
|
||||||
|
{&DDRF, &PINF, &PORTF, 0}, // D21 - A7 - PF0
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||||
|
// Sanguino
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 17;
|
||||||
|
uint8_t const SCL_PIN = 18;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 4;
|
||||||
|
uint8_t const MOSI_PIN = 5;
|
||||||
|
uint8_t const MISO_PIN = 6;
|
||||||
|
uint8_t const SCK_PIN = 7;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||||
|
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||||
|
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||||
|
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||||
|
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||||
|
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||||
|
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||||
|
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||||
|
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||||
|
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||||
|
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||||
|
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||||
|
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||||
|
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||||
|
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||||
|
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||||
|
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
// Leonardo
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 2;
|
||||||
|
uint8_t const SCL_PIN = 3;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 17;
|
||||||
|
uint8_t const MOSI_PIN = 16;
|
||||||
|
uint8_t const MISO_PIN = 14;
|
||||||
|
uint8_t const SCK_PIN = 15;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 0
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 1
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 2
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 3
|
||||||
|
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // C6 5
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D7 6
|
||||||
|
{&DDRE, &PINE, &PORTE, 6}, // E6 7
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // B4 8
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // B5 9
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // B6 10
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // B7 11
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D6 12
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // C7 13
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // B3 14
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // B1 15
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // B2 16
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // B0 17
|
||||||
|
{&DDRF, &PINF, &PORTF, 7}, // F7 18
|
||||||
|
{&DDRF, &PINF, &PORTF, 6}, // F6 19
|
||||||
|
{&DDRF, &PINF, &PORTF, 5}, // F5 20
|
||||||
|
{&DDRF, &PINF, &PORTF, 4}, // F4 21
|
||||||
|
{&DDRF, &PINF, &PORTF, 1}, // F1 22
|
||||||
|
{&DDRF, &PINF, &PORTF, 0}, // F0 23
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||||
|
// Teensy++ 1.0 & 2.0
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 1;
|
||||||
|
uint8_t const SCL_PIN = 0;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 20;
|
||||||
|
uint8_t const MOSI_PIN = 22;
|
||||||
|
uint8_t const MISO_PIN = 23;
|
||||||
|
uint8_t const SCK_PIN = 21;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||||
|
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||||
|
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||||
|
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||||
|
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||||
|
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||||
|
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||||
|
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||||
|
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||||
|
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||||
|
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||||
|
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||||
|
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||||
|
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||||
|
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||||
|
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||||
|
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||||
|
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||||
|
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||||
|
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||||
|
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||||
|
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||||
|
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||||
|
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||||
|
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||||
|
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||||
|
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||||
|
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||||
|
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||||
|
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||||
|
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||||
|
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||||
|
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||||
|
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||||
|
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
// 168 and 328 Arduinos
|
||||||
|
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 18;
|
||||||
|
uint8_t const SCL_PIN = 19;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 10;
|
||||||
|
uint8_t const MOSI_PIN = 11;
|
||||||
|
uint8_t const MISO_PIN = 12;
|
||||||
|
uint8_t const SCK_PIN = 13;
|
||||||
|
|
||||||
|
static const pin_map_t digitalPinMap[] = {
|
||||||
|
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||||
|
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||||
|
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||||
|
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||||
|
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||||
|
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||||
|
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||||
|
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||||
|
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||||
|
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||||
|
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||||
|
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||||
|
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||||
|
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||||
|
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||||
|
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||||
|
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||||
|
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||||
|
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||||
|
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||||
|
};
|
||||||
|
#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static const uint8_t digitalPinCount = sizeof(digitalPinMap) / sizeof(pin_map_t);
|
||||||
|
|
||||||
|
uint8_t badPinNumber(void)
|
||||||
|
__attribute__((error("Pin number is too large or not a constant")));
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
uint8_t getPinMode(uint8_t pin) {
|
||||||
|
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||||
|
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
|
||||||
|
} else {
|
||||||
|
return badPinNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void setPinMode(uint8_t pin, uint8_t mode) {
|
||||||
|
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||||
|
if (mode) {
|
||||||
|
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
|
||||||
|
} else {
|
||||||
|
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
badPinNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
uint8_t fastDigitalRead(uint8_t pin) {
|
||||||
|
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||||
|
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
|
||||||
|
} else {
|
||||||
|
return badPinNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalWrite(uint8_t pin, uint8_t value) {
|
||||||
|
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||||
|
if (value) {
|
||||||
|
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
|
||||||
|
} else {
|
||||||
|
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
badPinNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // Sd2PinMap_h
|
||||||
|
|
||||||
|
#elif defined (__CPU_ARC__)
|
||||||
|
|
||||||
|
#if defined (__ARDUINO_ARC__)
|
||||||
|
// Two Wire (aka I2C) ports
|
||||||
|
uint8_t const SDA_PIN = 18;
|
||||||
|
uint8_t const SCL_PIN = 19;
|
||||||
|
|
||||||
|
// SPI port
|
||||||
|
uint8_t const SS_PIN = 10;
|
||||||
|
uint8_t const MOSI_PIN = 11;
|
||||||
|
uint8_t const MISO_PIN = 12;
|
||||||
|
uint8_t const SCK_PIN = 13;
|
||||||
|
|
||||||
|
#endif // Arduino ARC
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Architecture or board not supported.
|
||||||
|
#endif
|
641
libraries/SD/src/utility/SdFat.h
Executable file
641
libraries/SD/src/utility/SdFat.h
Executable file
|
@ -0,0 +1,641 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdFat_h
|
||||||
|
#define SdFat_h
|
||||||
|
/**
|
||||||
|
\file
|
||||||
|
SdFile and SdVolume classes
|
||||||
|
*/
|
||||||
|
#if defined (__AVR__) || defined (__CPU_ARC__)
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#endif
|
||||||
|
#include "Sd2Card.h"
|
||||||
|
#include "FatStructs.h"
|
||||||
|
#include <Print.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Allow use of deprecated functions if non-zero
|
||||||
|
*/
|
||||||
|
#define ALLOW_DEPRECATED_FUNCTIONS 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// forward declaration since SdVolume is used in SdFile
|
||||||
|
class SdVolume;
|
||||||
|
//==============================================================================
|
||||||
|
// SdFile class
|
||||||
|
|
||||||
|
#ifdef O_RDONLY //ARDUINO_ARCH_MBED
|
||||||
|
#undef O_READ
|
||||||
|
#undef O_RDONLY
|
||||||
|
#undef O_WRITE
|
||||||
|
#undef O_WRONLY
|
||||||
|
#undef O_RDWR
|
||||||
|
#undef O_ACCMODE
|
||||||
|
#undef O_APPEND
|
||||||
|
#undef O_SYNC
|
||||||
|
#undef O_CREAT
|
||||||
|
#undef O_EXCL
|
||||||
|
#undef O_TRUNC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// flags for ls()
|
||||||
|
/** ls() flag to print modify date */
|
||||||
|
uint8_t const LS_DATE = 1;
|
||||||
|
/** ls() flag to print file size */
|
||||||
|
uint8_t const LS_SIZE = 2;
|
||||||
|
/** ls() flag for recursive list of subdirectories */
|
||||||
|
uint8_t const LS_R = 4;
|
||||||
|
|
||||||
|
// use the gnu style oflag in open()
|
||||||
|
/** open() oflag for reading */
|
||||||
|
uint8_t const O_READ = 0X01;
|
||||||
|
/** open() oflag - same as O_READ */
|
||||||
|
uint8_t const O_RDONLY = O_READ;
|
||||||
|
/** open() oflag for write */
|
||||||
|
uint8_t const O_WRITE = 0X02;
|
||||||
|
/** open() oflag - same as O_WRITE */
|
||||||
|
uint8_t const O_WRONLY = O_WRITE;
|
||||||
|
/** open() oflag for reading and writing */
|
||||||
|
uint8_t const O_RDWR = (O_READ | O_WRITE);
|
||||||
|
/** open() oflag mask for access modes */
|
||||||
|
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
|
||||||
|
/** The file offset shall be set to the end of the file prior to each write. */
|
||||||
|
uint8_t const O_APPEND = 0X04;
|
||||||
|
/** synchronous writes - call sync() after each write */
|
||||||
|
uint8_t const O_SYNC = 0X08;
|
||||||
|
/** create the file if nonexistent */
|
||||||
|
uint8_t const O_CREAT = 0X10;
|
||||||
|
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||||
|
uint8_t const O_EXCL = 0X20;
|
||||||
|
/** truncate the file to zero length */
|
||||||
|
uint8_t const O_TRUNC = 0X40;
|
||||||
|
|
||||||
|
// flags for timestamp
|
||||||
|
/** set the file's last access date */
|
||||||
|
uint8_t const T_ACCESS = 1;
|
||||||
|
/** set the file's creation date and time */
|
||||||
|
uint8_t const T_CREATE = 2;
|
||||||
|
/** Set the file's write date and time */
|
||||||
|
uint8_t const T_WRITE = 4;
|
||||||
|
// values for type_
|
||||||
|
/** This SdFile has not been opened. */
|
||||||
|
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
|
||||||
|
/** SdFile for a file */
|
||||||
|
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
|
||||||
|
/** SdFile for a FAT16 root directory */
|
||||||
|
uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
|
||||||
|
/** SdFile for a FAT32 root directory */
|
||||||
|
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
|
||||||
|
/** SdFile for a subdirectory */
|
||||||
|
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
|
||||||
|
/** Test value for directory type */
|
||||||
|
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
|
||||||
|
|
||||||
|
/** date field for FAT directory entry */
|
||||||
|
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
|
||||||
|
return (year - 1980) << 9 | month << 5 | day;
|
||||||
|
}
|
||||||
|
/** year part of FAT directory date field */
|
||||||
|
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
|
||||||
|
return 1980 + (fatDate >> 9);
|
||||||
|
}
|
||||||
|
/** month part of FAT directory date field */
|
||||||
|
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
|
||||||
|
return (fatDate >> 5) & 0XF;
|
||||||
|
}
|
||||||
|
/** day part of FAT directory date field */
|
||||||
|
static inline uint8_t FAT_DAY(uint16_t fatDate) {
|
||||||
|
return fatDate & 0X1F;
|
||||||
|
}
|
||||||
|
/** time field for FAT directory entry */
|
||||||
|
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||||
|
return hour << 11 | minute << 5 | second >> 1;
|
||||||
|
}
|
||||||
|
/** hour part of FAT directory time field */
|
||||||
|
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
|
||||||
|
return fatTime >> 11;
|
||||||
|
}
|
||||||
|
/** minute part of FAT directory time field */
|
||||||
|
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
|
||||||
|
return (fatTime >> 5) & 0X3F;
|
||||||
|
}
|
||||||
|
/** second part of FAT directory time field */
|
||||||
|
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
|
||||||
|
return 2 * (fatTime & 0X1F);
|
||||||
|
}
|
||||||
|
/** Default date for file timestamps is 1 Jan 2000 */
|
||||||
|
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||||
|
/** Default time for file timestamp is 1 am */
|
||||||
|
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\class SdFile
|
||||||
|
\brief Access FAT16 and FAT32 files on SD and SDHC cards.
|
||||||
|
*/
|
||||||
|
class SdFile : public Print {
|
||||||
|
public:
|
||||||
|
/** Create an instance of SdFile. */
|
||||||
|
SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
|
||||||
|
/**
|
||||||
|
writeError is set to true if an error occurs during a write().
|
||||||
|
Set writeError to false before calling print() and/or write() and check
|
||||||
|
for true after calls to print() and/or write().
|
||||||
|
*/
|
||||||
|
//bool writeError;
|
||||||
|
/**
|
||||||
|
Cancel unbuffered reads for this file.
|
||||||
|
See setUnbufferedRead()
|
||||||
|
*/
|
||||||
|
void clearUnbufferedRead(void) {
|
||||||
|
flags_ &= ~F_FILE_UNBUFFERED_READ;
|
||||||
|
}
|
||||||
|
uint8_t close(void);
|
||||||
|
uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||||
|
uint8_t createContiguous(SdFile* dirFile,
|
||||||
|
const char* fileName, uint32_t size);
|
||||||
|
/** \return The current cluster number for a file or directory. */
|
||||||
|
uint32_t curCluster(void) const {
|
||||||
|
return curCluster_;
|
||||||
|
}
|
||||||
|
/** \return The current position for a file or directory. */
|
||||||
|
uint32_t curPosition(void) const {
|
||||||
|
return curPosition_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Set the date/time callback function
|
||||||
|
|
||||||
|
\param[in] dateTime The user's call back function. The callback
|
||||||
|
function is of the form:
|
||||||
|
|
||||||
|
\code
|
||||||
|
void dateTime(uint16_t* date, uint16_t* time) {
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month, day, hour, minute, second;
|
||||||
|
|
||||||
|
// User gets date and time from GPS or real-time clock here
|
||||||
|
|
||||||
|
// return date using FAT_DATE macro to format fields
|
||||||
|
* *date = FAT_DATE(year, month, day);
|
||||||
|
|
||||||
|
// return time using FAT_TIME macro to format fields
|
||||||
|
* *time = FAT_TIME(hour, minute, second);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Sets the function that is called when a file is created or when
|
||||||
|
a file's directory entry is modified by sync(). All timestamps,
|
||||||
|
access, creation, and modify, are set when a file is created.
|
||||||
|
sync() maintains the last access date and last modify date/time.
|
||||||
|
|
||||||
|
See the timestamp() function.
|
||||||
|
*/
|
||||||
|
static void dateTimeCallback(
|
||||||
|
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||||
|
dateTime_ = dateTime;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Cancel the date/time callback function.
|
||||||
|
*/
|
||||||
|
static void dateTimeCallbackCancel(void) {
|
||||||
|
// use explicit zero since NULL is not defined for Sanguino
|
||||||
|
dateTime_ = 0;
|
||||||
|
}
|
||||||
|
/** \return Address of the block that contains this file's directory. */
|
||||||
|
uint32_t dirBlock(void) const {
|
||||||
|
return dirBlock_;
|
||||||
|
}
|
||||||
|
uint8_t dirEntry(dir_t* dir);
|
||||||
|
/** \return Index of this file's directory in the block dirBlock. */
|
||||||
|
uint8_t dirIndex(void) const {
|
||||||
|
return dirIndex_;
|
||||||
|
}
|
||||||
|
static void dirName(const dir_t& dir, char* name);
|
||||||
|
/** \return The total number of bytes in a file or directory. */
|
||||||
|
uint32_t fileSize(void) const {
|
||||||
|
return fileSize_;
|
||||||
|
}
|
||||||
|
/** \return The first cluster number for a file or directory. */
|
||||||
|
uint32_t firstCluster(void) const {
|
||||||
|
return firstCluster_;
|
||||||
|
}
|
||||||
|
/** \return True if this is a SdFile for a directory else false. */
|
||||||
|
uint8_t isDir(void) const {
|
||||||
|
return type_ >= FAT_FILE_TYPE_MIN_DIR;
|
||||||
|
}
|
||||||
|
/** \return True if this is a SdFile for a file else false. */
|
||||||
|
uint8_t isFile(void) const {
|
||||||
|
return type_ == FAT_FILE_TYPE_NORMAL;
|
||||||
|
}
|
||||||
|
/** \return True if this is a SdFile for an open file/directory else false. */
|
||||||
|
uint8_t isOpen(void) const {
|
||||||
|
return type_ != FAT_FILE_TYPE_CLOSED;
|
||||||
|
}
|
||||||
|
/** \return True if this is a SdFile for a subdirectory else false. */
|
||||||
|
uint8_t isSubDir(void) const {
|
||||||
|
return type_ == FAT_FILE_TYPE_SUBDIR;
|
||||||
|
}
|
||||||
|
/** \return True if this is a SdFile for the root directory. */
|
||||||
|
uint8_t isRoot(void) const {
|
||||||
|
return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
|
||||||
|
}
|
||||||
|
void ls(uint8_t flags = 0, uint8_t indent = 0);
|
||||||
|
uint8_t makeDir(SdFile* dir, const char* dirName);
|
||||||
|
uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||||
|
uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||||
|
|
||||||
|
uint8_t openRoot(SdVolume* vol);
|
||||||
|
static void printDirName(const dir_t& dir, uint8_t width);
|
||||||
|
static void printFatDate(uint16_t fatDate);
|
||||||
|
static void printFatTime(uint16_t fatTime);
|
||||||
|
static void printTwoDigits(uint8_t v);
|
||||||
|
/**
|
||||||
|
Read the next byte from a file.
|
||||||
|
|
||||||
|
\return For success read returns the next byte in the file as an int.
|
||||||
|
If an error occurs or end of file is reached -1 is returned.
|
||||||
|
*/
|
||||||
|
int16_t read(void) {
|
||||||
|
uint8_t b;
|
||||||
|
return read(&b, 1) == 1 ? b : -1;
|
||||||
|
}
|
||||||
|
int16_t read(void* buf, uint16_t nbyte);
|
||||||
|
int8_t readDir(dir_t* dir);
|
||||||
|
static uint8_t remove(SdFile* dirFile, const char* fileName);
|
||||||
|
uint8_t remove(void);
|
||||||
|
/** Set the file's current position to zero. */
|
||||||
|
void rewind(void) {
|
||||||
|
curPosition_ = curCluster_ = 0;
|
||||||
|
}
|
||||||
|
uint8_t rmDir(void);
|
||||||
|
uint8_t rmRfStar(void);
|
||||||
|
/** Set the files position to current position + \a pos. See seekSet(). */
|
||||||
|
uint8_t seekCur(uint32_t pos) {
|
||||||
|
return seekSet(curPosition_ + pos);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Set the files current position to end of file. Useful to position
|
||||||
|
a file for append. See seekSet().
|
||||||
|
*/
|
||||||
|
uint8_t seekEnd(void) {
|
||||||
|
return seekSet(fileSize_);
|
||||||
|
}
|
||||||
|
uint8_t seekSet(uint32_t pos);
|
||||||
|
/**
|
||||||
|
Use unbuffered reads to access this file. Used with Wave
|
||||||
|
Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
|
||||||
|
|
||||||
|
Not recommended for normal applications.
|
||||||
|
*/
|
||||||
|
void setUnbufferedRead(void) {
|
||||||
|
if (isFile()) {
|
||||||
|
flags_ |= F_FILE_UNBUFFERED_READ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||||
|
uint8_t hour, uint8_t minute, uint8_t second);
|
||||||
|
uint8_t sync(uint8_t blocking = 1);
|
||||||
|
/** Type of this SdFile. You should use isFile() or isDir() instead of type()
|
||||||
|
if possible.
|
||||||
|
|
||||||
|
\return The file or directory type.
|
||||||
|
*/
|
||||||
|
uint8_t type(void) const {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
uint8_t truncate(uint32_t size);
|
||||||
|
/** \return Unbuffered read flag. */
|
||||||
|
uint8_t unbufferedRead(void) const {
|
||||||
|
return flags_ & F_FILE_UNBUFFERED_READ;
|
||||||
|
}
|
||||||
|
/** \return SdVolume that contains this file. */
|
||||||
|
SdVolume* volume(void) const {
|
||||||
|
return vol_;
|
||||||
|
}
|
||||||
|
size_t write(uint8_t b);
|
||||||
|
size_t write(const void* buf, uint16_t nbyte);
|
||||||
|
size_t write(const char* str);
|
||||||
|
#ifdef __AVR__
|
||||||
|
void write_P(PGM_P str);
|
||||||
|
void writeln_P(PGM_P str);
|
||||||
|
#endif
|
||||||
|
int availableForWrite(void);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||||
|
/** \deprecated Use:
|
||||||
|
uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||||
|
*/
|
||||||
|
uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
|
||||||
|
return contiguousRange(&bgnBlock, &endBlock);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
uint8_t SdFile::createContiguous(SdFile* dirFile,
|
||||||
|
const char* fileName, uint32_t size)
|
||||||
|
*/
|
||||||
|
uint8_t createContiguous(SdFile& dirFile, // NOLINT
|
||||||
|
const char* fileName, uint32_t size) {
|
||||||
|
return createContiguous(&dirFile, fileName, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\deprecated Use:
|
||||||
|
static void SdFile::dateTimeCallback(
|
||||||
|
void (*dateTime)(uint16_t* date, uint16_t* time));
|
||||||
|
*/
|
||||||
|
static void dateTimeCallback(
|
||||||
|
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
|
||||||
|
oldDateTime_ = dateTime;
|
||||||
|
dateTime_ = dateTime ? oldToNew : 0;
|
||||||
|
}
|
||||||
|
/** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
|
||||||
|
uint8_t dirEntry(dir_t& dir) {
|
||||||
|
return dirEntry(&dir); // NOLINT
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
|
||||||
|
*/
|
||||||
|
uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
|
||||||
|
return makeDir(&dir, dirName);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||||
|
*/
|
||||||
|
uint8_t open(SdFile& dirFile, // NOLINT
|
||||||
|
const char* fileName, uint8_t oflag) {
|
||||||
|
return open(&dirFile, fileName, oflag);
|
||||||
|
}
|
||||||
|
/** \deprecated Do not use in new apps */
|
||||||
|
uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||||
|
return open(dirFile, fileName, O_RDWR);
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||||
|
*/
|
||||||
|
uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
|
||||||
|
return open(&dirFile, index, oflag);
|
||||||
|
}
|
||||||
|
/** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
|
||||||
|
uint8_t openRoot(SdVolume& vol) {
|
||||||
|
return openRoot(&vol); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
|
||||||
|
int8_t readDir(dir_t& dir) {
|
||||||
|
return readDir(&dir); // NOLINT
|
||||||
|
}
|
||||||
|
/** \deprecated Use:
|
||||||
|
static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
|
||||||
|
*/
|
||||||
|
static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||||
|
return remove(&dirFile, fileName);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// rest are private
|
||||||
|
private:
|
||||||
|
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
|
||||||
|
static void oldToNew(uint16_t* date, uint16_t* time) {
|
||||||
|
uint16_t d;
|
||||||
|
uint16_t t;
|
||||||
|
oldDateTime_(d, t);
|
||||||
|
*date = d;
|
||||||
|
*time = t;
|
||||||
|
}
|
||||||
|
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
private:
|
||||||
|
// bits defined in flags_
|
||||||
|
// should be 0XF
|
||||||
|
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
|
||||||
|
// available bits
|
||||||
|
static uint8_t const F_FILE_NON_BLOCKING_WRITE = 0X10;
|
||||||
|
// a new cluster was added to the file
|
||||||
|
static uint8_t const F_FILE_CLUSTER_ADDED = 0X20;
|
||||||
|
// use unbuffered SD read
|
||||||
|
static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
|
||||||
|
// sync of directory entry required
|
||||||
|
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
|
||||||
|
|
||||||
|
// make sure F_OFLAG is ok
|
||||||
|
#if ((F_FILE_NON_BLOCKING_WRITE | F_FILE_CLUSTER_ADDED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
|
||||||
|
#error flags_ bits conflict
|
||||||
|
#endif // flags_ bits
|
||||||
|
|
||||||
|
// private data
|
||||||
|
uint8_t flags_; // See above for definition of flags_ bits
|
||||||
|
uint8_t type_; // type of file see above for values
|
||||||
|
uint32_t curCluster_; // cluster for current file position
|
||||||
|
uint32_t curPosition_; // current file position in bytes from beginning
|
||||||
|
uint32_t dirBlock_; // SD block that contains directory entry for file
|
||||||
|
uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
|
||||||
|
uint32_t fileSize_; // file size in bytes
|
||||||
|
uint32_t firstCluster_; // first cluster of file
|
||||||
|
SdVolume* vol_; // volume where file is located
|
||||||
|
|
||||||
|
// private functions
|
||||||
|
uint8_t addCluster(void);
|
||||||
|
uint8_t addDirCluster(void);
|
||||||
|
dir_t* cacheDirEntry(uint8_t action);
|
||||||
|
static void (*dateTime_)(uint16_t* date, uint16_t* time);
|
||||||
|
static uint8_t make83Name(const char* str, uint8_t* name);
|
||||||
|
uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||||
|
dir_t* readDirCache(void);
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
// SdVolume class
|
||||||
|
/**
|
||||||
|
\brief Cache for an SD data block
|
||||||
|
*/
|
||||||
|
union cache_t {
|
||||||
|
/** Used to access cached file data blocks. */
|
||||||
|
uint8_t data[512];
|
||||||
|
/** Used to access cached FAT16 entries. */
|
||||||
|
uint16_t fat16[256];
|
||||||
|
/** Used to access cached FAT32 entries. */
|
||||||
|
uint32_t fat32[128];
|
||||||
|
/** Used to access cached directory entries. */
|
||||||
|
dir_t dir[16];
|
||||||
|
/** Used to access a cached MasterBoot Record. */
|
||||||
|
mbr_t mbr;
|
||||||
|
/** Used to access to a cached FAT boot sector. */
|
||||||
|
fbs_t fbs;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
\class SdVolume
|
||||||
|
\brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||||
|
*/
|
||||||
|
class SdVolume {
|
||||||
|
public:
|
||||||
|
/** Create an instance of SdVolume */
|
||||||
|
SdVolume(void) : allocSearchStart_(2), fatType_(0) {}
|
||||||
|
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||||
|
recorder to do raw write to the SD card. Not for normal apps.
|
||||||
|
*/
|
||||||
|
static uint8_t* cacheClear(void) {
|
||||||
|
cacheFlush();
|
||||||
|
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||||
|
return cacheBuffer_.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Initialize a FAT volume. Try partition one first then try super
|
||||||
|
floppy format.
|
||||||
|
|
||||||
|
\param[in] dev The Sd2Card where the volume is located.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure. Reasons for
|
||||||
|
failure include not finding a valid partition, not finding a valid
|
||||||
|
FAT file system or an I/O error.
|
||||||
|
*/
|
||||||
|
uint8_t init(Sd2Card* dev) {
|
||||||
|
return init(dev, 1) ? true : init(dev, 0);
|
||||||
|
}
|
||||||
|
uint8_t init(Sd2Card* dev, uint8_t part);
|
||||||
|
|
||||||
|
// inline functions that return volume info
|
||||||
|
/** \return The volume's cluster size in blocks. */
|
||||||
|
uint8_t blocksPerCluster(void) const {
|
||||||
|
return blocksPerCluster_;
|
||||||
|
}
|
||||||
|
/** \return The number of blocks in one FAT. */
|
||||||
|
uint32_t blocksPerFat(void) const {
|
||||||
|
return blocksPerFat_;
|
||||||
|
}
|
||||||
|
/** \return The total number of clusters in the volume. */
|
||||||
|
uint32_t clusterCount(void) const {
|
||||||
|
return clusterCount_;
|
||||||
|
}
|
||||||
|
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||||
|
uint8_t clusterSizeShift(void) const {
|
||||||
|
return clusterSizeShift_;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of file data. */
|
||||||
|
uint32_t dataStartBlock(void) const {
|
||||||
|
return dataStartBlock_;
|
||||||
|
}
|
||||||
|
/** \return The number of FAT structures on the volume. */
|
||||||
|
uint8_t fatCount(void) const {
|
||||||
|
return fatCount_;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of the first FAT. */
|
||||||
|
uint32_t fatStartBlock(void) const {
|
||||||
|
return fatStartBlock_;
|
||||||
|
}
|
||||||
|
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||||
|
uint8_t fatType(void) const {
|
||||||
|
return fatType_;
|
||||||
|
}
|
||||||
|
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||||
|
uint32_t rootDirEntryCount(void) const {
|
||||||
|
return rootDirEntryCount_;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of the root directory
|
||||||
|
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||||
|
uint32_t rootDirStart(void) const {
|
||||||
|
return rootDirStart_;
|
||||||
|
}
|
||||||
|
/** return a pointer to the Sd2Card object for this volume */
|
||||||
|
static Sd2Card* sdCard(void) {
|
||||||
|
return sdCard_;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||||
|
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
|
||||||
|
uint8_t init(Sd2Card& dev) {
|
||||||
|
return init(&dev); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
|
||||||
|
uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
|
||||||
|
return init(&dev, part);
|
||||||
|
}
|
||||||
|
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
private:
|
||||||
|
// Allow SdFile access to SdVolume private data.
|
||||||
|
friend class SdFile;
|
||||||
|
|
||||||
|
// value for action argument in cacheRawBlock to indicate read from cache
|
||||||
|
static uint8_t const CACHE_FOR_READ = 0;
|
||||||
|
// value for action argument in cacheRawBlock to indicate cache dirty
|
||||||
|
static uint8_t const CACHE_FOR_WRITE = 1;
|
||||||
|
|
||||||
|
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||||
|
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||||
|
static Sd2Card* sdCard_; // Sd2Card object for cache
|
||||||
|
static uint8_t cacheDirty_; // cacheFlush() will write block if true
|
||||||
|
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||||
|
//
|
||||||
|
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||||
|
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||||
|
uint32_t blocksPerFat_; // FAT size in blocks
|
||||||
|
uint32_t clusterCount_; // clusters in one FAT
|
||||||
|
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||||
|
uint32_t dataStartBlock_; // first data block number
|
||||||
|
uint8_t fatCount_; // number of FATs on volume
|
||||||
|
uint32_t fatStartBlock_; // start block for first FAT
|
||||||
|
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||||
|
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||||
|
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
|
||||||
|
uint8_t blockOfCluster(uint32_t position) const {
|
||||||
|
return (position >> 9) & (blocksPerCluster_ - 1);
|
||||||
|
}
|
||||||
|
uint32_t clusterStartBlock(uint32_t cluster) const {
|
||||||
|
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);
|
||||||
|
}
|
||||||
|
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
|
||||||
|
return clusterStartBlock(cluster) + blockOfCluster(position);
|
||||||
|
}
|
||||||
|
static uint8_t cacheFlush(uint8_t blocking = 1);
|
||||||
|
static uint8_t cacheMirrorBlockFlush(uint8_t blocking);
|
||||||
|
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
|
||||||
|
static void cacheSetDirty(void) {
|
||||||
|
cacheDirty_ |= CACHE_FOR_WRITE;
|
||||||
|
}
|
||||||
|
static uint8_t cacheZeroBlock(uint32_t blockNumber);
|
||||||
|
uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
|
||||||
|
uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
|
||||||
|
uint8_t fatPut(uint32_t cluster, uint32_t value);
|
||||||
|
uint8_t fatPutEOC(uint32_t cluster) {
|
||||||
|
return fatPut(cluster, 0x0FFFFFFF);
|
||||||
|
}
|
||||||
|
uint8_t freeChain(uint32_t cluster);
|
||||||
|
uint8_t isEOC(uint32_t cluster) const {
|
||||||
|
return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
|
||||||
|
}
|
||||||
|
uint8_t readBlock(uint32_t block, uint8_t* dst) {
|
||||||
|
return sdCard_->readBlock(block, dst);
|
||||||
|
}
|
||||||
|
uint8_t readData(uint32_t block, uint16_t offset,
|
||||||
|
uint16_t count, uint8_t* dst) {
|
||||||
|
return sdCard_->readData(block, offset, count, dst);
|
||||||
|
}
|
||||||
|
uint8_t writeBlock(uint32_t block, const uint8_t* dst, uint8_t blocking = 1) {
|
||||||
|
return sdCard_->writeBlock(block, dst, blocking);
|
||||||
|
}
|
||||||
|
uint8_t isBusy(void) {
|
||||||
|
return sdCard_->isBusy();
|
||||||
|
}
|
||||||
|
uint8_t isCacheMirrorBlockDirty(void) {
|
||||||
|
return (cacheMirrorBlock_ != 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // SdFat_h
|
77
libraries/SD/src/utility/SdFatUtil.h
Executable file
77
libraries/SD/src/utility/SdFatUtil.h
Executable file
|
@ -0,0 +1,77 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2008 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdFatUtil_h
|
||||||
|
#define SdFatUtil_h
|
||||||
|
/**
|
||||||
|
\file
|
||||||
|
Useful utility functions.
|
||||||
|
*/
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
/** Store and print a string in flash memory.*/
|
||||||
|
#define PgmPrint(x) SerialPrint_P(PSTR(x))
|
||||||
|
/** Store and print a string in flash memory followed by a CR/LF.*/
|
||||||
|
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
|
||||||
|
/** Defined so doxygen works for function definitions. */
|
||||||
|
#endif
|
||||||
|
#define NOINLINE __attribute__((noinline,unused))
|
||||||
|
#define UNUSEDOK __attribute__((unused))
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Return the number of bytes currently free in RAM. */
|
||||||
|
static UNUSEDOK int FreeRam(void) {
|
||||||
|
extern int __bss_end;
|
||||||
|
extern int* __brkval;
|
||||||
|
int free_memory;
|
||||||
|
if (reinterpret_cast<int>(__brkval) == 0) {
|
||||||
|
// if no heap use from end of bss section
|
||||||
|
free_memory = reinterpret_cast<int>(&free_memory)
|
||||||
|
- reinterpret_cast<int>(&__bss_end);
|
||||||
|
} else {
|
||||||
|
// use from top of stack to heap
|
||||||
|
free_memory = reinterpret_cast<int>(&free_memory)
|
||||||
|
- reinterpret_cast<int>(__brkval);
|
||||||
|
}
|
||||||
|
return free_memory;
|
||||||
|
}
|
||||||
|
#ifdef __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
%Print a string in flash memory to the serial port.
|
||||||
|
|
||||||
|
\param[in] str Pointer to string stored in flash memory.
|
||||||
|
*/
|
||||||
|
static NOINLINE void SerialPrint_P(PGM_P str) {
|
||||||
|
for (uint8_t c; (c = pgm_read_byte(str)); str++) {
|
||||||
|
Serial.write(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
%Print a string in flash memory followed by a CR/LF.
|
||||||
|
|
||||||
|
\param[in] str Pointer to string stored in flash memory.
|
||||||
|
*/
|
||||||
|
static NOINLINE void SerialPrintln_P(PGM_P str) {
|
||||||
|
SerialPrint_P(str);
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
#endif // __AVR__
|
||||||
|
#endif // #define SdFatUtil_h
|
202
libraries/SD/src/utility/SdFatmainpage.h
Executable file
202
libraries/SD/src/utility/SdFatmainpage.h
Executable file
|
@ -0,0 +1,202 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
\mainpage Arduino SdFat Library
|
||||||
|
<CENTER>Copyright © 2009 by William Greiman
|
||||||
|
</CENTER>
|
||||||
|
|
||||||
|
\section Intro Introduction
|
||||||
|
The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
|
||||||
|
file systems on SD flash memory cards. Standard SD and high capacity
|
||||||
|
SDHC cards are supported.
|
||||||
|
|
||||||
|
The SdFat only supports short 8.3 names.
|
||||||
|
|
||||||
|
The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
|
||||||
|
|
||||||
|
The Sd2Card class supports access to standard SD cards and SDHC cards. Most
|
||||||
|
applications will only need to call the Sd2Card::init() member function.
|
||||||
|
|
||||||
|
The SdVolume class supports FAT16 and FAT32 partitions. Most applications
|
||||||
|
will only need to call the SdVolume::init() member function.
|
||||||
|
|
||||||
|
The SdFile class provides file access functions such as open(), read(),
|
||||||
|
remove(), write(), close() and sync(). This class supports access to the root
|
||||||
|
directory and subdirectories.
|
||||||
|
|
||||||
|
A number of example are provided in the SdFat/examples folder. These were
|
||||||
|
developed to test SdFat and illustrate its use.
|
||||||
|
|
||||||
|
SdFat was developed for high speed data recording. SdFat was used to implement
|
||||||
|
an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
|
||||||
|
application uses special Sd2Card calls to write to contiguous files in raw mode.
|
||||||
|
These functions reduce write latency so that audio can be recorded with the
|
||||||
|
small amount of RAM in the Arduino.
|
||||||
|
|
||||||
|
\section SDcard SD\SDHC Cards
|
||||||
|
|
||||||
|
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
|
||||||
|
most consumer devices use the 4-bit parallel SD protocol. A card that
|
||||||
|
functions well on A PC or Mac may not work well on the Arduino.
|
||||||
|
|
||||||
|
Most cards have good SPI read performance but cards vary widely in SPI
|
||||||
|
write performance. Write performance is limited by how efficiently the
|
||||||
|
card manages internal erase/remapping operations. The Arduino cannot
|
||||||
|
optimize writes to reduce erase operations because of its limit RAM.
|
||||||
|
|
||||||
|
SanDisk cards generally have good write performance. They seem to have
|
||||||
|
more internal RAM buffering than other cards and therefore can limit
|
||||||
|
the number of flash erase operations that the Arduino forces due to its
|
||||||
|
limited RAM.
|
||||||
|
|
||||||
|
\section Hardware Hardware Configuration
|
||||||
|
|
||||||
|
SdFat was developed using an
|
||||||
|
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
|
||||||
|
<A HREF = "http://www.ladyada.net/make/waveshield/"> Wave Shield</A>.
|
||||||
|
|
||||||
|
The hardware interface to the SD card should not use a resistor based level
|
||||||
|
shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
|
||||||
|
rise times that are too slow for the edge detectors in many newer SD card
|
||||||
|
controllers when resistor voltage dividers are used.
|
||||||
|
|
||||||
|
The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
|
||||||
|
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
|
||||||
|
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
|
||||||
|
74LCX245.
|
||||||
|
|
||||||
|
If you are using a resistor based level shifter and are having problems try
|
||||||
|
setting the SPI bus frequency to 4 MHz. This can be done by using
|
||||||
|
card.init(SPI_HALF_SPEED) to initialize the SD card.
|
||||||
|
|
||||||
|
\section comment Bugs and Comments
|
||||||
|
|
||||||
|
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
|
||||||
|
|
||||||
|
\section SdFatClass SdFat Usage
|
||||||
|
|
||||||
|
SdFat uses a slightly restricted form of short names.
|
||||||
|
Only printable ASCII characters are supported. No characters with code point
|
||||||
|
values greater than 127 are allowed. Space is not allowed even though space
|
||||||
|
was allowed in the API of early versions of DOS.
|
||||||
|
|
||||||
|
Short names are limited to 8 characters followed by an optional period (.)
|
||||||
|
and extension of up to 3 characters. The characters may be any combination
|
||||||
|
of letters and digits. The following special characters are also allowed:
|
||||||
|
|
||||||
|
$ % ' - _ @ ~ ` ! ( ) { } ^ # &
|
||||||
|
|
||||||
|
Short names are always converted to upper case and their original case
|
||||||
|
value is lost.
|
||||||
|
|
||||||
|
\note
|
||||||
|
The Arduino Print class uses character
|
||||||
|
at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
|
||||||
|
function to control when data is written to the SD card.
|
||||||
|
|
||||||
|
\par
|
||||||
|
An application which writes to a file using \link Print::print() print()\endlink,
|
||||||
|
\link Print::println() println() \endlink
|
||||||
|
or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
|
||||||
|
at the appropriate time to force data and directory information to be written
|
||||||
|
to the SD Card. Data and directory information are also written to the SD card
|
||||||
|
when \link SdFile::close() close() \endlink is called.
|
||||||
|
|
||||||
|
\par
|
||||||
|
Applications must use care calling \link SdFile::sync() sync() \endlink
|
||||||
|
since 2048 bytes of I/O is required to update file and
|
||||||
|
directory information. This includes writing the current data block, reading
|
||||||
|
the block that contains the directory entry for update, writing the directory
|
||||||
|
block back and reading back the current data block.
|
||||||
|
|
||||||
|
It is possible to open a file with two or more instances of SdFile. A file may
|
||||||
|
be corrupted if data is written to the file by more than one instance of SdFile.
|
||||||
|
|
||||||
|
\section HowTo How to format SD Cards as FAT Volumes
|
||||||
|
|
||||||
|
You should use a freshly formatted SD card for best performance. FAT
|
||||||
|
file systems become slower if many files have been created and deleted.
|
||||||
|
This is because the directory entry for a deleted file is marked as deleted,
|
||||||
|
but is not deleted. When a new file is created, these entries must be scanned
|
||||||
|
before creating the file, a flaw in the FAT design. Also files can become
|
||||||
|
fragmented which causes reads and writes to be slower.
|
||||||
|
|
||||||
|
Microsoft operating systems support removable media formatted with a
|
||||||
|
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
|
||||||
|
in block zero.
|
||||||
|
|
||||||
|
Microsoft operating systems expect MBR formatted removable media
|
||||||
|
to have only one partition. The first partition should be used.
|
||||||
|
|
||||||
|
Microsoft operating systems do not support partitioning SD flash cards.
|
||||||
|
If you erase an SD card with a program like KillDisk, Most versions of
|
||||||
|
Windows will format the card as a super floppy.
|
||||||
|
|
||||||
|
The best way to restore an SD card's format is to use SDFormatter
|
||||||
|
which can be downloaded from:
|
||||||
|
|
||||||
|
http://www.sdcard.org/consumers/formatter/
|
||||||
|
|
||||||
|
SDFormatter aligns flash erase boundaries with file
|
||||||
|
system structures which reduces write latency and file system overhead.
|
||||||
|
|
||||||
|
SDFormatter does not have an option for FAT type so it may format
|
||||||
|
small cards as FAT12.
|
||||||
|
|
||||||
|
After the MBR is restored by SDFormatter you may need to reformat small
|
||||||
|
cards that have been formatted FAT12 to force the volume type to be FAT16.
|
||||||
|
|
||||||
|
If you reformat the SD card with an OS utility, choose a cluster size that
|
||||||
|
will result in:
|
||||||
|
|
||||||
|
4084 < CountOfClusters && CountOfClusters < 65525
|
||||||
|
|
||||||
|
The volume will then be FAT16.
|
||||||
|
|
||||||
|
If you are formatting an SD card on OS X or Linux, be sure to use the first
|
||||||
|
partition. Format this partition with a cluster count in above range.
|
||||||
|
|
||||||
|
\section References References
|
||||||
|
|
||||||
|
Adafruit Industries:
|
||||||
|
|
||||||
|
http://www.adafruit.com/
|
||||||
|
|
||||||
|
http://www.ladyada.net/make/waveshield/
|
||||||
|
|
||||||
|
The Arduino site:
|
||||||
|
|
||||||
|
http://www.arduino.cc/
|
||||||
|
|
||||||
|
For more information about FAT file systems see:
|
||||||
|
|
||||||
|
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||||
|
|
||||||
|
For information about using SD cards as SPI devices see:
|
||||||
|
|
||||||
|
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||||
|
|
||||||
|
The ATmega328 datasheet:
|
||||||
|
|
||||||
|
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
1527
libraries/SD/src/utility/SdFile.cpp
Executable file
1527
libraries/SD/src/utility/SdFile.cpp
Executable file
File diff suppressed because it is too large
Load Diff
232
libraries/SD/src/utility/SdInfo.h
Executable file
232
libraries/SD/src/utility/SdInfo.h
Executable file
|
@ -0,0 +1,232 @@
|
||||||
|
/* Arduino Sd2Card Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino Sd2Card Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino Sd2Card Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SdInfo_h
|
||||||
|
#define SdInfo_h
|
||||||
|
#include <stdint.h>
|
||||||
|
// Based on the document:
|
||||||
|
//
|
||||||
|
// SD Specifications
|
||||||
|
// Part 1
|
||||||
|
// Physical Layer
|
||||||
|
// Simplified Specification
|
||||||
|
// Version 2.00
|
||||||
|
// September 25, 2006
|
||||||
|
//
|
||||||
|
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card commands
|
||||||
|
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||||
|
uint8_t const CMD0 = 0X00;
|
||||||
|
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||||
|
uint8_t const CMD8 = 0X08;
|
||||||
|
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||||
|
uint8_t const CMD9 = 0X09;
|
||||||
|
/** SEND_CID - read the card identification information (CID register) */
|
||||||
|
uint8_t const CMD10 = 0X0A;
|
||||||
|
/** SEND_STATUS - read the card status register */
|
||||||
|
uint8_t const CMD13 = 0X0D;
|
||||||
|
/** READ_BLOCK - read a single data block from the card */
|
||||||
|
uint8_t const CMD17 = 0X11;
|
||||||
|
/** WRITE_BLOCK - write a single data block to the card */
|
||||||
|
uint8_t const CMD24 = 0X18;
|
||||||
|
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||||
|
uint8_t const CMD25 = 0X19;
|
||||||
|
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||||
|
uint8_t const CMD32 = 0X20;
|
||||||
|
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||||
|
range to be erased*/
|
||||||
|
uint8_t const CMD33 = 0X21;
|
||||||
|
/** ERASE - erase all previously selected blocks */
|
||||||
|
uint8_t const CMD38 = 0X26;
|
||||||
|
/** APP_CMD - escape for application specific command */
|
||||||
|
uint8_t const CMD55 = 0X37;
|
||||||
|
/** READ_OCR - read the OCR register of a card */
|
||||||
|
uint8_t const CMD58 = 0X3A;
|
||||||
|
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||||
|
pre-erased before writing */
|
||||||
|
uint8_t const ACMD23 = 0X17;
|
||||||
|
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||||
|
activates the card's initialization process */
|
||||||
|
uint8_t const ACMD41 = 0X29;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** status for card in the ready state */
|
||||||
|
uint8_t const R1_READY_STATE = 0X00;
|
||||||
|
/** status for card in the idle state */
|
||||||
|
uint8_t const R1_IDLE_STATE = 0X01;
|
||||||
|
/** status bit for illegal command */
|
||||||
|
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
|
||||||
|
/** start data token for read or write single block*/
|
||||||
|
uint8_t const DATA_START_BLOCK = 0XFE;
|
||||||
|
/** stop token for write multiple blocks*/
|
||||||
|
uint8_t const STOP_TRAN_TOKEN = 0XFD;
|
||||||
|
/** start data token for write multiple blocks*/
|
||||||
|
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||||
|
/** mask for data response tokens after a write block operation */
|
||||||
|
uint8_t const DATA_RES_MASK = 0X1F;
|
||||||
|
/** write data accepted token */
|
||||||
|
uint8_t const DATA_RES_ACCEPTED = 0X05;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
typedef struct CID {
|
||||||
|
// byte 0
|
||||||
|
uint8_t mid; // Manufacturer ID
|
||||||
|
// byte 1-2
|
||||||
|
char oid[2]; // OEM/Application ID
|
||||||
|
// byte 3-7
|
||||||
|
char pnm[5]; // Product name
|
||||||
|
// byte 8
|
||||||
|
unsigned prv_m : 4; // Product revision n.m
|
||||||
|
unsigned prv_n : 4;
|
||||||
|
// byte 9-12
|
||||||
|
uint32_t psn; // Product serial number
|
||||||
|
// byte 13
|
||||||
|
unsigned mdt_year_high : 4; // Manufacturing date
|
||||||
|
unsigned reserved : 4;
|
||||||
|
// byte 14
|
||||||
|
unsigned mdt_month : 4;
|
||||||
|
unsigned mdt_year_low : 4;
|
||||||
|
// byte 15
|
||||||
|
unsigned always1 : 1;
|
||||||
|
unsigned crc : 7;
|
||||||
|
} cid_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// CSD for version 1.00 cards
|
||||||
|
typedef struct CSDV1 {
|
||||||
|
// byte 0
|
||||||
|
unsigned reserved1 : 6;
|
||||||
|
unsigned csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
uint8_t taac;
|
||||||
|
// byte 2
|
||||||
|
uint8_t nsac;
|
||||||
|
// byte 3
|
||||||
|
uint8_t tran_speed;
|
||||||
|
// byte 4
|
||||||
|
uint8_t ccc_high;
|
||||||
|
// byte 5
|
||||||
|
unsigned read_bl_len : 4;
|
||||||
|
unsigned ccc_low : 4;
|
||||||
|
// byte 6
|
||||||
|
unsigned c_size_high : 2;
|
||||||
|
unsigned reserved2 : 2;
|
||||||
|
unsigned dsr_imp : 1;
|
||||||
|
unsigned read_blk_misalign : 1;
|
||||||
|
unsigned write_blk_misalign : 1;
|
||||||
|
unsigned read_bl_partial : 1;
|
||||||
|
// byte 7
|
||||||
|
uint8_t c_size_mid;
|
||||||
|
// byte 8
|
||||||
|
unsigned vdd_r_curr_max : 3;
|
||||||
|
unsigned vdd_r_curr_min : 3;
|
||||||
|
unsigned c_size_low : 2;
|
||||||
|
// byte 9
|
||||||
|
unsigned c_size_mult_high : 2;
|
||||||
|
unsigned vdd_w_cur_max : 3;
|
||||||
|
unsigned vdd_w_curr_min : 3;
|
||||||
|
// byte 10
|
||||||
|
unsigned sector_size_high : 6;
|
||||||
|
unsigned erase_blk_en : 1;
|
||||||
|
unsigned c_size_mult_low : 1;
|
||||||
|
// byte 11
|
||||||
|
unsigned wp_grp_size : 7;
|
||||||
|
unsigned sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
unsigned write_bl_len_high : 2;
|
||||||
|
unsigned r2w_factor : 3;
|
||||||
|
unsigned reserved3 : 2;
|
||||||
|
unsigned wp_grp_enable : 1;
|
||||||
|
// byte 13
|
||||||
|
unsigned reserved4 : 5;
|
||||||
|
unsigned write_partial : 1;
|
||||||
|
unsigned write_bl_len_low : 2;
|
||||||
|
// byte 14
|
||||||
|
unsigned reserved5: 2;
|
||||||
|
unsigned file_format : 2;
|
||||||
|
unsigned tmp_write_protect : 1;
|
||||||
|
unsigned perm_write_protect : 1;
|
||||||
|
unsigned copy : 1;
|
||||||
|
unsigned file_format_grp : 1;
|
||||||
|
// byte 15
|
||||||
|
unsigned always1 : 1;
|
||||||
|
unsigned crc : 7;
|
||||||
|
} csd1_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// CSD for version 2.00 cards
|
||||||
|
typedef struct CSDV2 {
|
||||||
|
// byte 0
|
||||||
|
unsigned reserved1 : 6;
|
||||||
|
unsigned csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
uint8_t taac;
|
||||||
|
// byte 2
|
||||||
|
uint8_t nsac;
|
||||||
|
// byte 3
|
||||||
|
uint8_t tran_speed;
|
||||||
|
// byte 4
|
||||||
|
uint8_t ccc_high;
|
||||||
|
// byte 5
|
||||||
|
unsigned read_bl_len : 4;
|
||||||
|
unsigned ccc_low : 4;
|
||||||
|
// byte 6
|
||||||
|
unsigned reserved2 : 4;
|
||||||
|
unsigned dsr_imp : 1;
|
||||||
|
unsigned read_blk_misalign : 1;
|
||||||
|
unsigned write_blk_misalign : 1;
|
||||||
|
unsigned read_bl_partial : 1;
|
||||||
|
// byte 7
|
||||||
|
unsigned reserved3 : 2;
|
||||||
|
unsigned c_size_high : 6;
|
||||||
|
// byte 8
|
||||||
|
uint8_t c_size_mid;
|
||||||
|
// byte 9
|
||||||
|
uint8_t c_size_low;
|
||||||
|
// byte 10
|
||||||
|
unsigned sector_size_high : 6;
|
||||||
|
unsigned erase_blk_en : 1;
|
||||||
|
unsigned reserved4 : 1;
|
||||||
|
// byte 11
|
||||||
|
unsigned wp_grp_size : 7;
|
||||||
|
unsigned sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
unsigned write_bl_len_high : 2;
|
||||||
|
unsigned r2w_factor : 3;
|
||||||
|
unsigned reserved5 : 2;
|
||||||
|
unsigned wp_grp_enable : 1;
|
||||||
|
// byte 13
|
||||||
|
unsigned reserved6 : 5;
|
||||||
|
unsigned write_partial : 1;
|
||||||
|
unsigned write_bl_len_low : 2;
|
||||||
|
// byte 14
|
||||||
|
unsigned reserved7: 2;
|
||||||
|
unsigned file_format : 2;
|
||||||
|
unsigned tmp_write_protect : 1;
|
||||||
|
unsigned perm_write_protect : 1;
|
||||||
|
unsigned copy : 1;
|
||||||
|
unsigned file_format_grp : 1;
|
||||||
|
// byte 15
|
||||||
|
unsigned always1 : 1;
|
||||||
|
unsigned crc : 7;
|
||||||
|
} csd2_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// union of old and new style CSD register
|
||||||
|
union csd_t {
|
||||||
|
csd1_t v1;
|
||||||
|
csd2_t v2;
|
||||||
|
};
|
||||||
|
#endif // SdInfo_h
|
351
libraries/SD/src/utility/SdVolume.cpp
Executable file
351
libraries/SD/src/utility/SdVolume.cpp
Executable file
|
@ -0,0 +1,351 @@
|
||||||
|
/* Arduino SdFat Library
|
||||||
|
Copyright (C) 2009 by William Greiman
|
||||||
|
|
||||||
|
This file is part of the Arduino SdFat Library
|
||||||
|
|
||||||
|
This Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the Arduino SdFat Library. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "SdFat.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// raw block cache
|
||||||
|
// init cacheBlockNumber_to invalid SD block number
|
||||||
|
uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
|
||||||
|
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
||||||
|
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
|
||||||
|
uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true
|
||||||
|
uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// find a contiguous group of clusters
|
||||||
|
uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
|
||||||
|
// start of group
|
||||||
|
uint32_t bgnCluster;
|
||||||
|
|
||||||
|
// flag to save place to start next search
|
||||||
|
uint8_t setStart;
|
||||||
|
|
||||||
|
// set search start cluster
|
||||||
|
if (*curCluster) {
|
||||||
|
// try to make file contiguous
|
||||||
|
bgnCluster = *curCluster + 1;
|
||||||
|
|
||||||
|
// don't save new start location
|
||||||
|
setStart = false;
|
||||||
|
} else {
|
||||||
|
// start at likely place for free cluster
|
||||||
|
bgnCluster = allocSearchStart_;
|
||||||
|
|
||||||
|
// save next search start if one cluster
|
||||||
|
setStart = 1 == count;
|
||||||
|
}
|
||||||
|
// end of group
|
||||||
|
uint32_t endCluster = bgnCluster;
|
||||||
|
|
||||||
|
// last cluster of FAT
|
||||||
|
uint32_t fatEnd = clusterCount_ + 1;
|
||||||
|
|
||||||
|
// search the FAT for free clusters
|
||||||
|
for (uint32_t n = 0;; n++, endCluster++) {
|
||||||
|
// can't find space checked all clusters
|
||||||
|
if (n >= clusterCount_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// past end - start from beginning of FAT
|
||||||
|
if (endCluster > fatEnd) {
|
||||||
|
bgnCluster = endCluster = 2;
|
||||||
|
}
|
||||||
|
uint32_t f;
|
||||||
|
if (!fatGet(endCluster, &f)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f != 0) {
|
||||||
|
// cluster in use try next cluster as bgnCluster
|
||||||
|
bgnCluster = endCluster + 1;
|
||||||
|
} else if ((endCluster - bgnCluster + 1) == count) {
|
||||||
|
// done - found space
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// mark end of chain
|
||||||
|
if (!fatPutEOC(endCluster)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// link clusters
|
||||||
|
while (endCluster > bgnCluster) {
|
||||||
|
if (!fatPut(endCluster - 1, endCluster)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
endCluster--;
|
||||||
|
}
|
||||||
|
if (*curCluster != 0) {
|
||||||
|
// connect chains
|
||||||
|
if (!fatPut(*curCluster, bgnCluster)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return first cluster number to caller
|
||||||
|
*curCluster = bgnCluster;
|
||||||
|
|
||||||
|
// remember possible next free cluster
|
||||||
|
if (setStart) {
|
||||||
|
allocSearchStart_ = bgnCluster + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint8_t SdVolume::cacheFlush(uint8_t blocking) {
|
||||||
|
if (cacheDirty_) {
|
||||||
|
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data, blocking)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blocking) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mirror FAT tables
|
||||||
|
if (!cacheMirrorBlockFlush(blocking)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheDirty_ = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint8_t SdVolume::cacheMirrorBlockFlush(uint8_t blocking) {
|
||||||
|
if (cacheMirrorBlock_) {
|
||||||
|
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data, blocking)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheMirrorBlock_ = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
|
||||||
|
if (cacheBlockNumber_ != blockNumber) {
|
||||||
|
if (!cacheFlush()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheBlockNumber_ = blockNumber;
|
||||||
|
}
|
||||||
|
cacheDirty_ |= action;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// cache a zero block for blockNumber
|
||||||
|
uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
|
||||||
|
if (!cacheFlush()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop take less flash than memset(cacheBuffer_.data, 0, 512);
|
||||||
|
for (uint16_t i = 0; i < 512; i++) {
|
||||||
|
cacheBuffer_.data[i] = 0;
|
||||||
|
}
|
||||||
|
cacheBlockNumber_ = blockNumber;
|
||||||
|
cacheSetDirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// return the size in bytes of a cluster chain
|
||||||
|
uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const {
|
||||||
|
uint32_t s = 0;
|
||||||
|
do {
|
||||||
|
if (!fatGet(cluster, &cluster)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
s += 512UL << clusterSizeShift_;
|
||||||
|
} while (!isEOC(cluster));
|
||||||
|
*size = s;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Fetch a FAT entry
|
||||||
|
uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
|
||||||
|
if (cluster > (clusterCount_ + 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t lba = fatStartBlock_;
|
||||||
|
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
||||||
|
if (lba != cacheBlockNumber_) {
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
*value = cacheBuffer_.fat16[cluster & 0XFF];
|
||||||
|
} else {
|
||||||
|
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Store a FAT entry
|
||||||
|
uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||||
|
// error if reserved cluster
|
||||||
|
if (cluster < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error if not in FAT
|
||||||
|
if (cluster > (clusterCount_ + 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate block address for entry
|
||||||
|
uint32_t lba = fatStartBlock_;
|
||||||
|
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
||||||
|
|
||||||
|
if (lba != cacheBlockNumber_) {
|
||||||
|
if (!cacheRawBlock(lba, CACHE_FOR_READ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// store entry
|
||||||
|
if (fatType_ == 16) {
|
||||||
|
cacheBuffer_.fat16[cluster & 0XFF] = value;
|
||||||
|
} else {
|
||||||
|
cacheBuffer_.fat32[cluster & 0X7F] = value;
|
||||||
|
}
|
||||||
|
cacheSetDirty();
|
||||||
|
|
||||||
|
// mirror second FAT
|
||||||
|
if (fatCount_ > 1) {
|
||||||
|
cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// free a cluster chain
|
||||||
|
uint8_t SdVolume::freeChain(uint32_t cluster) {
|
||||||
|
// clear free cluster location
|
||||||
|
allocSearchStart_ = 2;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t next;
|
||||||
|
if (!fatGet(cluster, &next)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// free cluster
|
||||||
|
if (!fatPut(cluster, 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster = next;
|
||||||
|
} while (!isEOC(cluster));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
Initialize a FAT volume.
|
||||||
|
|
||||||
|
\param[in] dev The SD card where the volume is located.
|
||||||
|
|
||||||
|
\param[in] part The partition to be used. Legal values for \a part are
|
||||||
|
1-4 to use the corresponding partition on a device formatted with
|
||||||
|
a MBR, Master Boot Record, or zero if the device is formatted as
|
||||||
|
a super floppy with the FAT boot sector in block zero.
|
||||||
|
|
||||||
|
\return The value one, true, is returned for success and
|
||||||
|
the value zero, false, is returned for failure. Reasons for
|
||||||
|
failure include not finding a valid partition, not finding a valid
|
||||||
|
FAT file system in the specified partition or an I/O error.
|
||||||
|
*/
|
||||||
|
uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
|
||||||
|
uint32_t volumeStartBlock = 0;
|
||||||
|
sdCard_ = dev;
|
||||||
|
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||||
|
// if part > 0 assume mbr volume with partition table
|
||||||
|
if (part) {
|
||||||
|
if (part > 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
part_t* p = &cacheBuffer_.mbr.part[part - 1];
|
||||||
|
if ((p->boot & 0X7F) != 0 ||
|
||||||
|
p->totalSectors < 100 ||
|
||||||
|
p->firstSector == 0) {
|
||||||
|
// not a valid partition
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
volumeStartBlock = p->firstSector;
|
||||||
|
}
|
||||||
|
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bpb_t* bpb = &cacheBuffer_.fbs.bpb;
|
||||||
|
if (bpb->bytesPerSector != 512 ||
|
||||||
|
bpb->fatCount == 0 ||
|
||||||
|
bpb->reservedSectorCount == 0 ||
|
||||||
|
bpb->sectorsPerCluster == 0) {
|
||||||
|
// not valid FAT volume
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fatCount_ = bpb->fatCount;
|
||||||
|
blocksPerCluster_ = bpb->sectorsPerCluster;
|
||||||
|
|
||||||
|
// determine shift that is same as multiply by blocksPerCluster_
|
||||||
|
clusterSizeShift_ = 0;
|
||||||
|
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
|
||||||
|
// error if not power of 2
|
||||||
|
if (clusterSizeShift_++ > 7) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blocksPerFat_ = bpb->sectorsPerFat16 ?
|
||||||
|
bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
|
||||||
|
|
||||||
|
fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
|
||||||
|
|
||||||
|
// count for FAT16 zero for FAT32
|
||||||
|
rootDirEntryCount_ = bpb->rootDirEntryCount;
|
||||||
|
|
||||||
|
// directory start for FAT16 dataStart for FAT32
|
||||||
|
rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
|
||||||
|
|
||||||
|
// data start for FAT16 and FAT32
|
||||||
|
dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511) / 512);
|
||||||
|
|
||||||
|
// total blocks for FAT16 or FAT32
|
||||||
|
uint32_t totalBlocks = bpb->totalSectors16 ?
|
||||||
|
bpb->totalSectors16 : bpb->totalSectors32;
|
||||||
|
// total data blocks
|
||||||
|
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||||
|
|
||||||
|
// divide by cluster size to get cluster count
|
||||||
|
clusterCount_ >>= clusterSizeShift_;
|
||||||
|
|
||||||
|
// FAT type is determined by cluster count
|
||||||
|
if (clusterCount_ < 4085) {
|
||||||
|
fatType_ = 12;
|
||||||
|
} else if (clusterCount_ < 65525) {
|
||||||
|
fatType_ = 16;
|
||||||
|
} else {
|
||||||
|
rootDirStart_ = bpb->fat32RootCluster;
|
||||||
|
fatType_ = 32;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
85
RX_FSK/src/SX1278FSK.cpp → libraries/SX1278FSK/SX1278FSK.cpp
Normal file → Executable file
85
RX_FSK/src/SX1278FSK.cpp → libraries/SX1278FSK/SX1278FSK.cpp
Normal file → Executable file
|
@ -11,41 +11,16 @@
|
||||||
|
|
||||||
#include "SX1278FSK.h"
|
#include "SX1278FSK.h"
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "Sonde.h"
|
#include <Sonde.h>
|
||||||
#include "Display.h"
|
#include <Display.h>
|
||||||
|
|
||||||
|
SX1278FSK::SX1278FSK()
|
||||||
#define SPI_MUTEX_LOCK() \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS)
|
|
||||||
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(_lock)
|
|
||||||
|
|
||||||
SX1278FSK::SX1278FSK() {}
|
|
||||||
|
|
||||||
void SX1278FSK::setup(xSemaphoreHandle lock)
|
|
||||||
{
|
{
|
||||||
_lock = lock;
|
// Initialize class variables
|
||||||
Serial.println("Setup sx1278");
|
|
||||||
if(_lock) SPI_MUTEX_LOCK();
|
|
||||||
digitalWrite(sonde.config.sx1278_ss, HIGH);
|
|
||||||
pinMode(sonde.config.sx1278_ss, OUTPUT);
|
|
||||||
Serial.printf("Configuing SX1278FSK SPI with miso=%d, mosi=%d, sck=%d, ss=%d\n", sonde.config.sx1278_miso,
|
|
||||||
sonde.config.sx1278_mosi, sonde.config.sx1278_sck, sonde.config.sx1278_ss);
|
|
||||||
SPI.begin(sonde.config.sx1278_sck, sonde.config.sx1278_miso, sonde.config.sx1278_mosi, -1); // no hardware CS
|
|
||||||
// was: SPI.begin();
|
|
||||||
|
|
||||||
//Set most significant bit first
|
|
||||||
SPI.setBitOrder(MSBFIRST);
|
|
||||||
//Divide the clock frequency
|
|
||||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
|
||||||
//Set data mode
|
|
||||||
SPI.setDataMode(SPI_MODE0);
|
|
||||||
if(_lock) SPI_MUTEX_UNLOCK();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static SPISettings spiset = SPISettings(10000000L, MSBFIRST, SPI_MODE0);
|
static SPISettings spiset = SPISettings(40000000L, MSBFIRST, SPI_MODE0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: Turns the module ON.
|
Function: Turns the module ON.
|
||||||
|
@ -59,6 +34,19 @@ uint8_t SX1278FSK::ON()
|
||||||
Serial.println(F("Starting 'ON'"));
|
Serial.println(F("Starting 'ON'"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Powering the module
|
||||||
|
pinMode(SX1278_SS, OUTPUT);
|
||||||
|
digitalWrite(SX1278_SS, HIGH);
|
||||||
|
|
||||||
|
//Configure the MISO, MOSI, CS, SPCR.
|
||||||
|
SPI.begin();
|
||||||
|
//Set most significant bit first
|
||||||
|
SPI.setBitOrder(MSBFIRST);
|
||||||
|
//Divide the clock frequency
|
||||||
|
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||||
|
//Set data mode
|
||||||
|
SPI.setDataMode(SPI_MODE0);
|
||||||
|
|
||||||
// Set Maximum Over Current Protection
|
// Set Maximum Over Current Protection
|
||||||
state = setMaxCurrent(0x1B);
|
state = setMaxCurrent(0x1B);
|
||||||
if( state == 0 )
|
if( state == 0 )
|
||||||
|
@ -72,6 +60,7 @@ uint8_t SX1278FSK::ON()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set FSK mode
|
// set FSK mode
|
||||||
state = setFSK();
|
state = setFSK();
|
||||||
return state;
|
return state;
|
||||||
|
@ -88,12 +77,10 @@ void SX1278FSK::OFF()
|
||||||
Serial.println(F("Starting 'OFF'"));
|
Serial.println(F("Starting 'OFF'"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//SPI.end();
|
SPI.end();
|
||||||
#if 0
|
|
||||||
// Powering the module
|
// Powering the module
|
||||||
pinMode(SX1278_SS,OUTPUT);
|
pinMode(SX1278_SS,OUTPUT);
|
||||||
digitalWrite(SX1278_SS,LOW);
|
digitalWrite(SX1278_SS,LOW);
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
Serial.println(F("## Setting OFF ##"));
|
Serial.println(F("## Setting OFF ##"));
|
||||||
|
@ -111,16 +98,15 @@ byte SX1278FSK::readRegister(byte address)
|
||||||
{
|
{
|
||||||
byte value = 0x00;
|
byte value = 0x00;
|
||||||
|
|
||||||
if(_lock) SPI_MUTEX_LOCK();
|
|
||||||
digitalWrite(sonde.config.sx1278_ss,LOW);
|
|
||||||
SPI.beginTransaction(spiset);
|
SPI.beginTransaction(spiset);
|
||||||
|
digitalWrite(SX1278_SS,LOW);
|
||||||
|
|
||||||
//delay(1);
|
//delay(1);
|
||||||
bitClear(address, 7); // Bit 7 cleared to write in registers
|
bitClear(address, 7); // Bit 7 cleared to write in registers
|
||||||
SPI.transfer(address);
|
SPI.transfer(address);
|
||||||
value = SPI.transfer(0x00);
|
value = SPI.transfer(0x00);
|
||||||
|
digitalWrite(SX1278_SS,HIGH);
|
||||||
SPI.endTransaction();
|
SPI.endTransaction();
|
||||||
digitalWrite(sonde.config.sx1278_ss,HIGH);
|
|
||||||
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
if(address!=0x3F) {
|
if(address!=0x3F) {
|
||||||
|
@ -132,7 +118,7 @@ byte SX1278FSK::readRegister(byte address)
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(_lock) SPI_MUTEX_UNLOCK();
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +131,15 @@ Parameters:
|
||||||
*/
|
*/
|
||||||
void SX1278FSK::writeRegister(byte address, byte data)
|
void SX1278FSK::writeRegister(byte address, byte data)
|
||||||
{
|
{
|
||||||
if(_lock) SPI_MUTEX_LOCK();
|
|
||||||
digitalWrite(sonde.config.sx1278_ss,LOW);
|
|
||||||
SPI.beginTransaction(spiset);
|
SPI.beginTransaction(spiset);
|
||||||
|
digitalWrite(SX1278_SS,LOW);
|
||||||
|
|
||||||
//delay(1);
|
//delay(1);
|
||||||
bitSet(address, 7); // Bit 7 set to read from registers
|
bitSet(address, 7); // Bit 7 set to read from registers
|
||||||
SPI.transfer(address);
|
SPI.transfer(address);
|
||||||
SPI.transfer(data);
|
SPI.transfer(data);
|
||||||
|
digitalWrite(SX1278_SS,HIGH);
|
||||||
SPI.endTransaction();
|
SPI.endTransaction();
|
||||||
digitalWrite(sonde.config.sx1278_ss,HIGH);
|
|
||||||
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
Serial.print(F("## Writing: ##\t"));
|
Serial.print(F("## Writing: ##\t"));
|
||||||
|
@ -165,7 +150,7 @@ void SX1278FSK::writeRegister(byte address, byte data)
|
||||||
Serial.print(data, HEX);
|
Serial.print(data, HEX);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
#endif
|
#endif
|
||||||
if(_lock) SPI_MUTEX_UNLOCK();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -179,23 +164,20 @@ void SX1278FSK::writeRegister(byte address, byte data)
|
||||||
*/
|
*/
|
||||||
void SX1278FSK::clearIRQFlags()
|
void SX1278FSK::clearIRQFlags()
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
byte st0;
|
byte st0;
|
||||||
|
|
||||||
// Save the previous status
|
// Save the previous status
|
||||||
st0 = readRegister(REG_OP_MODE);
|
st0 = readRegister(REG_OP_MODE);
|
||||||
// Stdby mode to write in registers
|
// Stdby mode to write in registers
|
||||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
|
||||||
#endif
|
|
||||||
// FSK mode flags1 register
|
// FSK mode flags1 register
|
||||||
writeRegister(REG_IRQ_FLAGS1, 0xFF);
|
writeRegister(REG_IRQ_FLAGS1, 0xFF);
|
||||||
// FSK mode flags2 register
|
// FSK mode flags2 register
|
||||||
writeRegister(REG_IRQ_FLAGS2, 0xFF);
|
writeRegister(REG_IRQ_FLAGS2, 0xFF);
|
||||||
#if 0
|
|
||||||
// Getting back to previous status
|
// Getting back to previous status
|
||||||
if(st0 != FSK_STANDBY_MODE) {
|
if(st0 != FSK_STANDBY_MODE) {
|
||||||
writeRegister(REG_OP_MODE, st0);
|
writeRegister(REG_OP_MODE, st0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
Serial.println(F("## FSK flags cleared ##"));
|
Serial.println(F("## FSK flags cleared ##"));
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,7 +194,7 @@ uint8_t SX1278FSK::setFSK()
|
||||||
{
|
{
|
||||||
uint8_t state = 2;
|
uint8_t state = 2;
|
||||||
byte st0;
|
byte st0;
|
||||||
//byte config1;
|
byte config1;
|
||||||
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
@ -581,13 +563,6 @@ int32_t SX1278FSK::getAFC()
|
||||||
AFC = (int32_t)(regval * SX127X_FSTEP);
|
AFC = (int32_t)(regval * SX127X_FSTEP);
|
||||||
return AFC;
|
return AFC;
|
||||||
}
|
}
|
||||||
uint16_t SX1278FSK::getRawAFC() {
|
|
||||||
return (readRegister(REG_AFC_MSB)<<8) | readRegister(REG_AFC_LSB);
|
|
||||||
}
|
|
||||||
void SX1278FSK::setRawAFC(uint16_t afc) {
|
|
||||||
writeRegister(REG_AFC_MSB, afc>>8);
|
|
||||||
writeRegister(REG_AFC_LSB, afc&0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: Gets the current supply limit of the power amplifier, protecting battery chemistries.
|
Function: Gets the current supply limit of the power amplifier, protecting battery chemistries.
|
||||||
|
@ -667,7 +642,7 @@ int8_t SX1278FSK::setMaxCurrent(uint8_t rate)
|
||||||
// Enable Over Current Protection
|
// Enable Over Current Protection
|
||||||
rate |= B00100000;
|
rate |= B00100000;
|
||||||
|
|
||||||
//state = 1;
|
state = 1;
|
||||||
st0 = readRegister(REG_OP_MODE); // Save the previous status
|
st0 = readRegister(REG_OP_MODE); // Save the previous status
|
||||||
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers
|
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers
|
||||||
writeRegister(REG_OCP, rate); // Modifying maximum current supply
|
writeRegister(REG_OCP, rate); // Modifying maximum current supply
|
||||||
|
@ -744,6 +719,7 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
|
||||||
// It's a bit of a hack.... get RSSI and AFC (a) at beginning of packet and
|
// It's a bit of a hack.... get RSSI and AFC (a) at beginning of packet and
|
||||||
// for RS41 after about 0.5 sec. It might be more logical to put this decoder-specific
|
// for RS41 after about 0.5 sec. It might be more logical to put this decoder-specific
|
||||||
// code into RS41.cpp instead of this file... (maybe TODO?)
|
// code into RS41.cpp instead of this file... (maybe TODO?)
|
||||||
|
|
||||||
if(di==1 || di==290 ) {
|
if(di==1 || di==290 ) {
|
||||||
int rssi=getRSSI();
|
int rssi=getRSSI();
|
||||||
int afc=getAFC();
|
int afc=getAFC();
|
||||||
|
@ -882,5 +858,4 @@ void SX1278FSK::showRxRegisters()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xSemaphoreHandle globalLock =xSemaphoreCreateMutex();
|
|
||||||
SX1278FSK sx1278 = SX1278FSK();
|
SX1278FSK sx1278 = SX1278FSK();
|
10
RX_FSK/src/SX1278FSK.h → libraries/SX1278FSK/SX1278FSK.h
Normal file → Executable file
10
RX_FSK/src/SX1278FSK.h → libraries/SX1278FSK/SX1278FSK.h
Normal file → Executable file
|
@ -35,6 +35,8 @@
|
||||||
|
|
||||||
#define SX1278FSK_debug_mode 0
|
#define SX1278FSK_debug_mode 0
|
||||||
|
|
||||||
|
#define SX1278_SS SS
|
||||||
|
|
||||||
//! MACROS //
|
//! MACROS //
|
||||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) // read a bit
|
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) // read a bit
|
||||||
#define bitSet(value, bit) ((value) |= (1UL << (bit))) // set bit to '1'
|
#define bitSet(value, bit) ((value) |= (1UL << (bit))) // set bit to '1'
|
||||||
|
@ -169,9 +171,7 @@ class SX1278FSK
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// class constructor
|
// class constructor
|
||||||
SX1278FSK();
|
SX1278FSK();
|
||||||
|
|
||||||
void setup(xSemaphoreHandle lock);
|
|
||||||
|
|
||||||
// Turn on SX1278 module (return 0 on sucess, 1 otherwise)
|
// Turn on SX1278 module (return 0 on sucess, 1 otherwise)
|
||||||
uint8_t ON();
|
uint8_t ON();
|
||||||
|
@ -240,8 +240,6 @@ public:
|
||||||
|
|
||||||
// Get current AFC value
|
// Get current AFC value
|
||||||
int32_t getAFC();
|
int32_t getAFC();
|
||||||
uint16_t getRawAFC();
|
|
||||||
void setRawAFC(uint16_t afc);
|
|
||||||
|
|
||||||
// Get the maximum current supply by the module.
|
// Get the maximum current supply by the module.
|
||||||
int getMaxCurrent();
|
int getMaxCurrent();
|
||||||
|
@ -256,7 +254,7 @@ public:
|
||||||
// Receive a packet
|
// Receive a packet
|
||||||
uint8_t receivePacketTimeout(uint32_t wait, byte *data);
|
uint8_t receivePacketTimeout(uint32_t wait, byte *data);
|
||||||
|
|
||||||
xSemaphoreHandle _lock = NULL;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
//! It gets the internal temperature of the module.
|
//! It gets the internal temperature of the module.
|
347
libraries/SondeLib/DFM.cpp
Executable file
347
libraries/SondeLib/DFM.cpp
Executable file
|
@ -0,0 +1,347 @@
|
||||||
|
|
||||||
|
/* DFM decoder functions */
|
||||||
|
#include "DFM.h"
|
||||||
|
#include "SX1278FSK.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
|
#define DFM_DEBUG 1
|
||||||
|
|
||||||
|
#if DFM_DEBUG
|
||||||
|
#define DFM_DBG(x) x
|
||||||
|
#else
|
||||||
|
#define DFM_DBG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int DFM::setup(float frequency, int inv)
|
||||||
|
{
|
||||||
|
inverse = inv;
|
||||||
|
#if DFM_DEBUG
|
||||||
|
Serial.printf("Setup sx1278 for DFM sonde (inv=%d)\n",inv);
|
||||||
|
#endif
|
||||||
|
if(sx1278.ON()!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setFSK()!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting FSM mode FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setBitrate(2500)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting bitrate 2500bit/s FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#if DFM_DEBUG
|
||||||
|
float br = sx1278.getBitrate();
|
||||||
|
Serial.print("Exact bitrate is ");
|
||||||
|
Serial.println(br);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(sx1278.setAFCBandwidth(sonde.config.dfm.agcbw)!=0) {
|
||||||
|
DFM_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.dfm.agcbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setRxBandwidth(sonde.config.dfm.rxbw)!=0) {
|
||||||
|
DFM_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.dfm.rxbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
||||||
|
if(sx1278.setRxConf(0x1E)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting RX Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
||||||
|
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
||||||
|
|
||||||
|
const char *SYNC=inverse?"\x9A\x99\x5A\x55":"\x65\x66\xA5\xAA";
|
||||||
|
if(sx1278.setSyncConf(0x53, 4, (const uint8_t *)SYNC)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packet config 1: fixed len, mancecer, no crc, no address filter
|
||||||
|
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
||||||
|
if(sx1278.setPacketConfig(0x28, 0x40)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting Packet config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Serial.print("DFM: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
|
||||||
|
int retval = sx1278.setFrequency(frequency);
|
||||||
|
sx1278.clearIRQFlags();
|
||||||
|
DFM_DBG(Serial.println("Setting SX1278 config for DFM finished\n"); Serial.println());
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define bitpick(value,bitpos) (((value)>>(7-(bitpos)))&0x01)
|
||||||
|
// Input: str: packed data, MSB first
|
||||||
|
void DFM::deinterleave(uint8_t *str, int L, uint8_t *block) {
|
||||||
|
int i, j;
|
||||||
|
for (j = 0; j < B; j++) { // L = 7 (CFG), 13 (DAT1, DAT2)
|
||||||
|
for (i = 0; i < L; i++) {
|
||||||
|
block[B*i+j] = bitpick( str[(L*j+i)/8], (L*j+i)&7 )?0:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DFM::bits2val(const uint8_t *bits, int len) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
val |= (bits[j] << (len-1-j));
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error correction for hamming code
|
||||||
|
// returns 0: ok >0: 1 error was corrected -1: uncorrectable error
|
||||||
|
int DFM::check(uint8_t code[8]) {
|
||||||
|
int i, j;
|
||||||
|
uint32_t synval = 0;
|
||||||
|
uint8_t syndrom[4];
|
||||||
|
int ret=0;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
syndrom[i] = 0;
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
syndrom[i] ^= H[i][j] & code[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synval = bits2val(syndrom, 4);
|
||||||
|
if (synval) {
|
||||||
|
ret = -1;
|
||||||
|
for (j = 0; j < 8; j++) { // 1-bit-error
|
||||||
|
if (synval == He[j]) { // reicht auf databits zu pruefen, d.h.
|
||||||
|
ret = j+1; // (systematischer Code) He[0..3]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else ret = 0;
|
||||||
|
if (ret > 0) code[ret-1] ^= 0x1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extended (8,4) Hamming code
|
||||||
|
// Return number of corrected bits, -1 if uncorrectable error
|
||||||
|
int DFM::hamming(uint8_t *ham, int L, uint8_t *sym) {
|
||||||
|
int i, j;
|
||||||
|
int ret = 0; // DFM: length L = 7 or 13
|
||||||
|
for (i = 0; i < L; i++) { // L bytes (4bit data, 4bit parity)
|
||||||
|
if (use_ecc) {
|
||||||
|
int res = check(ham+8*i);
|
||||||
|
if(ret>=0 && res>=0) ret += res; else ret=-1;
|
||||||
|
}
|
||||||
|
// systematic Hamming code: copy bits 0..3
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
sym[4*i+j] = ham[8*i+j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFM::DFM() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::printRaw(const char *label, int len, int ret, const uint8_t *data)
|
||||||
|
{
|
||||||
|
Serial.print(label); Serial.print("(");
|
||||||
|
Serial.print(ret);
|
||||||
|
Serial.print("):");
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len/2; i++) {
|
||||||
|
char str[10];
|
||||||
|
snprintf(str, 10, "%02X", data[i]);
|
||||||
|
Serial.print(str);
|
||||||
|
}
|
||||||
|
Serial.print(data[i]&0x0F, HEX);
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::decodeCFG(uint8_t *cfg)
|
||||||
|
{
|
||||||
|
static int lowid, highid, idgood=0, type=0;
|
||||||
|
if((cfg[0]>>4)==0x06 && type==0) { // DFM-6 ID
|
||||||
|
lowid = ((cfg[0]&0x0F)<<20) | (cfg[1]<<12) | (cfg[2]<<4) | (cfg[3]&0x0f);
|
||||||
|
Serial.print("DFM-06 ID: "); Serial.print(lowid, HEX);
|
||||||
|
snprintf(sonde.si()->id, 10, "%x", lowid);
|
||||||
|
sonde.si()->validID = true;
|
||||||
|
}
|
||||||
|
if((cfg[0]>>4)==0x0A) { // DMF-9 ID
|
||||||
|
type=9;
|
||||||
|
if(cfg[3]==1) {
|
||||||
|
lowid = (cfg[1]<<8) | cfg[2];
|
||||||
|
idgood |= 1;
|
||||||
|
} else {
|
||||||
|
highid = (cfg[1]<<8) | cfg[2];
|
||||||
|
idgood |= 2;
|
||||||
|
}
|
||||||
|
if(idgood==3) {
|
||||||
|
uint32_t dfmid = (highid<<16) | lowid;
|
||||||
|
Serial.print("DFM-09 ID: "); Serial.print(dfmid);
|
||||||
|
snprintf(sonde.si()->ser, 10, "%d", dfmid);
|
||||||
|
// dxlAPRS sonde number (DF6 (why??) and 5 last digits of serial number as hex number
|
||||||
|
snprintf(sonde.si()->id, 9, "DF6%05X", dfmid&0xfffff);
|
||||||
|
sonde.si()->validID = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bitCount(int x) {
|
||||||
|
int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
|
||||||
|
int m1 = 0xFF;
|
||||||
|
int s4 = (x&m4) + ((x>>1)&m4) + ((x>>2)&m4) + ((x>>3)&m4) + ((x>>4)&m4) + ((x>>5)&m4) + ((x>>6)&m4) + ((x>>7)&m4);
|
||||||
|
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
||||||
|
|
||||||
|
void DFM::decodeDAT(uint8_t *dat)
|
||||||
|
{
|
||||||
|
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
||||||
|
switch(dat[6]) {
|
||||||
|
case 0:
|
||||||
|
Serial.print("Packet counter: "); Serial.print(dat[3]);
|
||||||
|
sonde.si()->frame = dat[3];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int val = (((uint16_t)dat[4])<<8) + (uint16_t)dat[5];
|
||||||
|
Serial.print("UTC-msec: "); Serial.print(val);
|
||||||
|
sonde.si()->sec = val/1000;
|
||||||
|
uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||||
|
sonde.si()->sats = bitCount(tmp); // maybe!?!?!?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
float lat, vh;
|
||||||
|
lat = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||||
|
vh = ((uint16_t)dat[4]<<8) + dat[5];
|
||||||
|
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
||||||
|
Serial.print(", hor-V: "); Serial.print(vh*0.01);
|
||||||
|
sonde.si()->lat = lat*0.0000001;
|
||||||
|
sonde.si()->hs = vh*0.01;
|
||||||
|
sonde.si()->validPos |= 0x11;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
float lon, dir;
|
||||||
|
lon = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + (uint32_t)dat[3];
|
||||||
|
dir = ((uint16_t)dat[4]<<8) + dat[5];
|
||||||
|
Serial.print("GPS-lon: "); Serial.print(lon*0.0000001);
|
||||||
|
Serial.print(", dir: "); Serial.print(dir*0.01);
|
||||||
|
sonde.si()->lon = lon*0.0000001;
|
||||||
|
sonde.si()->dir = dir*0.01;
|
||||||
|
sonde.si()->validPos |= 0x42;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
float alt, vv;
|
||||||
|
alt = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + dat[3];
|
||||||
|
vv = (int16_t)( ((int16_t)dat[4]<<8) | dat[5] );
|
||||||
|
Serial.print("GPS-height: "); Serial.print(alt*0.01);
|
||||||
|
Serial.print(", vv: "); Serial.print(vv*0.01);
|
||||||
|
sonde.si()->alt = alt*0.01;
|
||||||
|
sonde.si()->vs = vv*0.01;
|
||||||
|
sonde.si()->validPos |= 0x0C;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
int y = (dat[0]<<4) + (dat[1]>>4);
|
||||||
|
int m = dat[1]&0x0F;
|
||||||
|
int d = dat[2]>>3;
|
||||||
|
int h = ((dat[2]&0x07)<<2) + (dat[3]>>6);
|
||||||
|
int mi = (dat[3]&0x3F);
|
||||||
|
char buf[100];
|
||||||
|
snprintf(buf, 100, "%04d-%02d-%02d %02d:%02dz", y, m, d, h, mi);
|
||||||
|
Serial.print("Date: "); Serial.print(buf);
|
||||||
|
// convert to unix time
|
||||||
|
int tt = (y-1970)*365 + (y-1969)/4; // days since 1970
|
||||||
|
if(m<=12) { tt += MON[m]; if((y%4)==0 && m>2) tt++; }
|
||||||
|
tt = (tt+d-1)*(60*60*24) + h*3600 + mi*60;
|
||||||
|
sonde.si()->time = tt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.print("(?)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len*4; i++) {
|
||||||
|
//Serial.print(bits[i]?"1":"0");
|
||||||
|
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
||||||
|
}
|
||||||
|
bytes[(i-1)/8] &= 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DFM::receive() {
|
||||||
|
byte data[1000]; // pending data from previous mode may write more than 33 bytes. TODO.
|
||||||
|
for(int i=0; i<2; i++) {
|
||||||
|
sx1278.setPayloadLength(33); // Expect 33 bytes (7+13+13 bytes)
|
||||||
|
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
int e = sx1278.receivePacketTimeout(1000, data);
|
||||||
|
if(e) { return RX_TIMEOUT; } //if timeout... return 1
|
||||||
|
|
||||||
|
Serial.printf("inverse is %d\b", inverse);
|
||||||
|
if(!inverse) { for(int i=0; i<33; i++) { data[i]^=0xFF; } }
|
||||||
|
deinterleave(data, 7, hamming_conf);
|
||||||
|
deinterleave(data+7, 13, hamming_dat1);
|
||||||
|
deinterleave(data+20, 13, hamming_dat2);
|
||||||
|
|
||||||
|
int ret0 = hamming(hamming_conf, 7, block_conf);
|
||||||
|
int ret1 = hamming(hamming_dat1, 13, block_dat1);
|
||||||
|
int ret2 = hamming(hamming_dat2, 13, block_dat2);
|
||||||
|
|
||||||
|
byte byte_conf[4], byte_dat1[7], byte_dat2[7];
|
||||||
|
bitsToBytes(block_conf, byte_conf, 7);
|
||||||
|
bitsToBytes(block_dat1, byte_dat1, 13);
|
||||||
|
bitsToBytes(block_dat2, byte_dat2, 13);
|
||||||
|
|
||||||
|
printRaw("CFG", 7, ret0, byte_conf);
|
||||||
|
printRaw("DAT", 13, ret1, byte_dat1);
|
||||||
|
printRaw("DAT", 13, ret2, byte_dat2);
|
||||||
|
decodeCFG(byte_conf);
|
||||||
|
decodeDAT(byte_dat1);
|
||||||
|
decodeDAT(byte_dat2);
|
||||||
|
}
|
||||||
|
return RX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// moved to a single function in Sonde(). This function can be used for additional
|
||||||
|
// processing here, that takes too long for doing in the RX task loop
|
||||||
|
int DFM::waitRXcomplete() {
|
||||||
|
#if 0
|
||||||
|
int res=0;
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while( rxtask.receiveResult < 0 && millis()-t0 < 2000) { delay(50); }
|
||||||
|
|
||||||
|
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||||
|
res = RX_TIMEOUT;
|
||||||
|
} else if ( rxtask.receiveResult ==0) {
|
||||||
|
res = RX_OK;
|
||||||
|
} else {
|
||||||
|
res = RX_ERROR;
|
||||||
|
}
|
||||||
|
rxtask.receiveResult = -1;
|
||||||
|
Serial.printf("waitRXcomplete returning %d\n", res);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFM dfm = DFM();
|
13
RX_FSK/src/DFM.h → libraries/SondeLib/DFM.h
Normal file → Executable file
13
RX_FSK/src/DFM.h → libraries/SondeLib/DFM.h
Normal file → Executable file
|
@ -15,31 +15,24 @@
|
||||||
#ifndef inttypes_h
|
#ifndef inttypes_h
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#endif
|
#endif
|
||||||
#include "DecoderBase.h"
|
|
||||||
|
|
||||||
#define DFM_NORMAL 0
|
#define DFM_NORMAL 0
|
||||||
#define DFM_INVERSE 1
|
#define DFM_INVERSE 1
|
||||||
|
|
||||||
/* Main class */
|
/* Main class */
|
||||||
class DFM : public DecoderBase
|
class DFM
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int stype;
|
int inverse=0;
|
||||||
char *stypename=NULL;
|
|
||||||
|
|
||||||
void deinterleave(uint8_t *str, int L, uint8_t *block);
|
void deinterleave(uint8_t *str, int L, uint8_t *block);
|
||||||
uint32_t bits2val(const uint8_t *bits, int len);
|
uint32_t bits2val(const uint8_t *bits, int len);
|
||||||
int check(uint8_t code[8]);
|
int check(uint8_t code[8]);
|
||||||
int hamming(uint8_t *ham, int L, uint8_t *sym);
|
int hamming(uint8_t *ham, int L, uint8_t *sym);
|
||||||
void printRaw(const char *prefix, int len, int ret, const uint8_t* data);
|
void printRaw(const char *prefix, int len, int ret, const uint8_t* data);
|
||||||
void finddfname(uint8_t *cfg);
|
|
||||||
void decodeCFG(uint8_t *cfg);
|
void decodeCFG(uint8_t *cfg);
|
||||||
void decodeDAT(uint8_t *dat);
|
void decodeDAT(uint8_t *dat);
|
||||||
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
||||||
int processDFMdata(uint8_t dt);
|
|
||||||
int decodeFrameDFM(uint8_t *data);
|
|
||||||
void killid();
|
|
||||||
|
|
||||||
|
|
||||||
#define B 8
|
#define B 8
|
||||||
#define S 4
|
#define S 4
|
||||||
|
@ -62,7 +55,7 @@ private:
|
||||||
public:
|
public:
|
||||||
DFM();
|
DFM();
|
||||||
// main decoder API
|
// main decoder API
|
||||||
int setup(float frequency, int type);
|
int setup(float frequency, int inverse);
|
||||||
int receive();
|
int receive();
|
||||||
int waitRXcomplete();
|
int waitRXcomplete();
|
||||||
|
|
0
RX_FSK/src/DefaultFonts.c → libraries/SondeLib/DefaultFonts.c
Normal file → Executable file
0
RX_FSK/src/DefaultFonts.c → libraries/SondeLib/DefaultFonts.c
Normal file → Executable file
1262
RX_FSK/src/Display.cpp → libraries/SondeLib/Display.cpp
Normal file → Executable file
1262
RX_FSK/src/Display.cpp → libraries/SondeLib/Display.cpp
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
73
RX_FSK/src/Display.h → libraries/SondeLib/Display.h
Normal file → Executable file
73
RX_FSK/src/Display.h → libraries/SondeLib/Display.h
Normal file → Executable file
|
@ -1,26 +1,14 @@
|
||||||
#ifndef Display_h
|
#ifndef Display_h
|
||||||
#define Display_h
|
#define Display_h
|
||||||
|
|
||||||
#define FONT_LARGE 1
|
#define FONT_LARGE 1
|
||||||
#define FONT_SMALL 0
|
#define FONT_SMALL 0
|
||||||
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <Arduino_GFX_Library.h>
|
//#include <TFT22_ILI9225.h>
|
||||||
|
#include "gfxfont.h"
|
||||||
#include <U8x8lib.h>
|
#include <U8x8lib.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
struct GpsPos {
|
|
||||||
double lat;
|
|
||||||
double lon;
|
|
||||||
int alt;
|
|
||||||
int course;
|
|
||||||
float speed;
|
|
||||||
int sat;
|
|
||||||
int accuracy;
|
|
||||||
int hdop;
|
|
||||||
int valid;
|
|
||||||
};
|
|
||||||
extern struct GpsPos gpsPos;
|
|
||||||
|
|
||||||
#define WIDTH_AUTO 9999
|
#define WIDTH_AUTO 9999
|
||||||
struct DispEntry {
|
struct DispEntry {
|
||||||
|
@ -48,59 +36,44 @@ struct StatInfo {
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CircleInfo { // 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff
|
|
||||||
char type;
|
|
||||||
char top,bul,arr; // what to point to with top, bullet, array
|
|
||||||
uint16_t fgcol, bgcol;
|
|
||||||
uint8_t radius;
|
|
||||||
uint8_t brad;
|
|
||||||
uint16_t bcol;
|
|
||||||
uint8_t awidth;
|
|
||||||
uint16_t acol;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Now starting towards supporting different Display types / libraries
|
// Now starting towards supporting different Display types / libraries
|
||||||
class RawDisplay {
|
class RawDisplay {
|
||||||
public:
|
public:
|
||||||
virtual void begin() = 0;
|
virtual void begin() = 0;
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
virtual void setContrast(uint8_t contrast) = 0;
|
|
||||||
virtual void setFont(uint8_t fontindex) = 0;
|
virtual void setFont(uint8_t fontindex) = 0;
|
||||||
virtual void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip) = 0;
|
virtual void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip) = 0;
|
||||||
virtual void drawString(uint16_t x, uint16_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0;
|
virtual void drawString(uint8_t x, uint8_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0;
|
||||||
virtual void drawTile(uint16_t x, uint16_t y, uint8_t cnt, uint8_t *tile_ptr) = 0;
|
virtual void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) = 0;
|
||||||
virtual void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill) = 0;
|
virtual void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill) = 0;
|
||||||
virtual void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) = 0;
|
virtual void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) = 0;
|
||||||
virtual void welcome() = 0;
|
virtual void welcome() = 0;
|
||||||
virtual void drawIP(uint16_t x, uint16_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0;
|
virtual void drawIP(uint8_t x, uint8_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0;
|
||||||
virtual void drawQS(uint16_t x, uint16_t y, uint8_t len, uint8_t size, uint8_t *stat, uint16_t fg=0xffff, uint16_t bg=0) = 0;
|
virtual void drawQS(uint8_t x, uint8_t y, uint8_t len, uint8_t size, uint8_t *stat, uint16_t fg=0xffff, uint16_t bg=0) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class U8x8Display : public RawDisplay {
|
class U8x8Display : public RawDisplay {
|
||||||
private:
|
private:
|
||||||
U8X8 *u8x8 = NULL; // initialize later after reading config file
|
U8X8 *u8x8 = NULL; // initialize later after reading config file
|
||||||
uint8_t _type;
|
int _type;
|
||||||
const uint8_t **fontlist;
|
const uint8_t **fontlist;
|
||||||
int nfonts;
|
int nfonts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
U8x8Display(uint8_t type = 0) { _type = type; }
|
U8x8Display(int type = 0) { _type = type; }
|
||||||
void begin();
|
void begin();
|
||||||
void clear();
|
void clear();
|
||||||
void setContrast(uint8_t contrast);
|
|
||||||
void setFont(uint8_t fontindex);
|
void setFont(uint8_t fontindex);
|
||||||
void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip);
|
void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip);
|
||||||
void drawString(uint16_t x, uint16_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0);
|
void drawString(uint8_t x, uint8_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0);
|
||||||
void drawTile(uint16_t x, uint16_t y, uint8_t cnt, uint8_t *tile_ptr);
|
void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr);
|
||||||
void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill);
|
void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill);
|
||||||
void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h);
|
void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h);
|
||||||
void welcome();
|
void welcome();
|
||||||
void drawIP(uint16_t x, uint16_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0);
|
void drawIP(uint8_t x, uint8_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0);
|
||||||
void drawQS(uint16_t x, uint16_t y, uint8_t len, uint8_t size, uint8_t *stat, uint16_t fg=0xffff, uint16_t bg=0);
|
void drawQS(uint8_t x, uint8_t y, uint8_t len, uint8_t size, uint8_t *stat, uint16_t fg=0xffff, uint16_t bg=0);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Arduino_GFX MY_ILI9225;
|
|
||||||
|
|
||||||
class Display {
|
class Display {
|
||||||
private:
|
private:
|
||||||
void replaceLayouts(DispInfo *newlayout, int nnew);
|
void replaceLayouts(DispInfo *newlayout, int nnew);
|
||||||
|
@ -109,19 +82,22 @@ private:
|
||||||
int xscale=13, yscale=22;
|
int xscale=13, yscale=22;
|
||||||
int fontsma=0, fontlar=1;
|
int fontsma=0, fontlar=1;
|
||||||
uint16_t colfg, colbg;
|
uint16_t colfg, colbg;
|
||||||
static void circ(uint16_t *bm, int16_t w, int16_t x0, int16_t y0, int16_t r, uint16_t fg, boolean fill, uint16_t bg);
|
static void circ(int x, int y);
|
||||||
static int countEntries(File f);
|
static int countEntries(File f);
|
||||||
void calcGPS();
|
void calcGPS();
|
||||||
|
boolean gpsValid;
|
||||||
|
float gpsLat, gpsLon;
|
||||||
|
int gpsAlt;
|
||||||
int gpsDist; // -1: invalid
|
int gpsDist; // -1: invalid
|
||||||
int gpsDir, gpsBear; // 0..360; -1: invalid
|
int gpsCourse, gpsDir, gpsBear; // 0..360; -1: invalid
|
||||||
boolean gpsCourseOld;
|
boolean gpsCourseOld;
|
||||||
static const int LINEBUFLEN{ 255 };
|
static const int LINEBUFLEN{ 255 };
|
||||||
static char lineBuf[LINEBUFLEN];
|
static char lineBuf[LINEBUFLEN];
|
||||||
static const char *trim(char *s) {
|
static const char *trim(char *s) {
|
||||||
char *ret = s;
|
char *ret = s;
|
||||||
while(*ret && isspace(*ret)) { ret++; }
|
while(*ret && isspace(*ret)) { ret++; }
|
||||||
|
int lastidx;
|
||||||
while(1) {
|
while(1) {
|
||||||
int lastidx;
|
|
||||||
lastidx = strlen(ret)-1;
|
lastidx = strlen(ret)-1;
|
||||||
if(lastidx>=0 && isspace(ret[lastidx]))
|
if(lastidx>=0 && isspace(ret[lastidx]))
|
||||||
ret[lastidx] = 0;
|
ret[lastidx] = 0;
|
||||||
|
@ -131,8 +107,7 @@ private:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
static int getScreenIndex(int index);
|
void initFromFile();
|
||||||
void initFromFile(int index);
|
|
||||||
|
|
||||||
int layoutIdx;
|
int layoutIdx;
|
||||||
DispInfo *layout;
|
DispInfo *layout;
|
||||||
|
@ -140,13 +115,14 @@ public:
|
||||||
DispInfo *layouts;
|
DispInfo *layouts;
|
||||||
int nLayouts;
|
int nLayouts;
|
||||||
static RawDisplay *rdis;
|
static RawDisplay *rdis;
|
||||||
uint16_t dispstate;
|
|
||||||
|
|
||||||
Display();
|
Display();
|
||||||
void init();
|
void init();
|
||||||
static char buf[17];
|
static char buf[17];
|
||||||
static void drawLat(DispEntry *de);
|
static void drawLat(DispEntry *de);
|
||||||
static void drawLon(DispEntry *de);
|
static void drawLon(DispEntry *de);
|
||||||
|
static void drawAz(DispEntry *de);
|
||||||
|
static void drawVBat(DispEntry *de);
|
||||||
static void drawAlt(DispEntry *de);
|
static void drawAlt(DispEntry *de);
|
||||||
static void drawHS(DispEntry *de);
|
static void drawHS(DispEntry *de);
|
||||||
static void drawVS(DispEntry *de);
|
static void drawVS(DispEntry *de);
|
||||||
|
@ -168,16 +144,17 @@ public:
|
||||||
void setIP(const char *ip, bool AP);
|
void setIP(const char *ip, bool AP);
|
||||||
void updateDisplayPos();
|
void updateDisplayPos();
|
||||||
void updateDisplayPos2();
|
void updateDisplayPos2();
|
||||||
|
void updateDisplayAz();
|
||||||
|
void updateDisplayVBat();
|
||||||
void updateDisplayID();
|
void updateDisplayID();
|
||||||
void updateDisplayRSSI();
|
void updateDisplayRSSI();
|
||||||
void updateStat();
|
void updateStat();
|
||||||
void updateDisplayRXConfig();
|
void updateDisplayRXConfig();
|
||||||
void updateDisplayIP();
|
void updateDisplayIP();
|
||||||
void updateDisplay();
|
void updateDisplay();
|
||||||
void dispsavectlON();
|
void updateDisplayVBatt();
|
||||||
void dispsavectlOFF(int rxactive);
|
|
||||||
void setLayout(int layout);
|
void setLayout(int layout);
|
||||||
void setContrast();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Display disp;
|
extern Display disp;
|
529
libraries/SondeLib/M10.cpp
Executable file
529
libraries/SondeLib/M10.cpp
Executable file
|
@ -0,0 +1,529 @@
|
||||||
|
|
||||||
|
/* M10 decoder functions */
|
||||||
|
#include "M10.h"
|
||||||
|
#include "SX1278FSK.h"
|
||||||
|
#include "rsc.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
|
// well...
|
||||||
|
//#include "rs92gps.h"
|
||||||
|
|
||||||
|
#define M10_DEBUG 1
|
||||||
|
|
||||||
|
#if M10_DEBUG
|
||||||
|
#define M10_DBG(x) x
|
||||||
|
#else
|
||||||
|
#define M10_DBG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static byte data1[512];
|
||||||
|
static byte *dataptr=data1;
|
||||||
|
|
||||||
|
static uint8_t rxbitc;
|
||||||
|
static uint16_t rxbyte;
|
||||||
|
static int rxp=0;
|
||||||
|
static int haveNewFrame = 0;
|
||||||
|
static int lastFrame = 0;
|
||||||
|
static int headerDetected = 0;
|
||||||
|
|
||||||
|
int M10::setup(float frequency)
|
||||||
|
{
|
||||||
|
#if M10_DEBUG
|
||||||
|
Serial.println("Setup sx1278 for M10 sonde");
|
||||||
|
#endif
|
||||||
|
//if(!initialized) {
|
||||||
|
//Gencrctab();
|
||||||
|
//initrsc();
|
||||||
|
// not here for now.... get_eph("/brdc.19n");
|
||||||
|
// initialized = true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if(sx1278.ON()!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setFSK()!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting FSJ mode FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setBitrate(9600)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting bitrate 9600bit/s FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#if M10_DEBUG
|
||||||
|
float br = sx1278.getBitrate();
|
||||||
|
Serial.print("Exact bitrate is ");
|
||||||
|
Serial.println(br);
|
||||||
|
#endif
|
||||||
|
if(sx1278.setAFCBandwidth(sonde.config.rs92.rxbw)!=0) {
|
||||||
|
M10_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.rs92.rxbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setRxBandwidth(sonde.config.rs92.rxbw)!=0) {
|
||||||
|
M10_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.rs92.rxbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
||||||
|
if(sx1278.setRxConf(0x1E)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting RX Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
||||||
|
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
||||||
|
|
||||||
|
//const char *SYNC="\x10\xB6\xCA\x11\x22\x96\x12\xF8";
|
||||||
|
//const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
||||||
|
// was 0x57
|
||||||
|
//const char *SYNC="\x99\x9A";
|
||||||
|
#if 1
|
||||||
|
// version 1, working with continuous RX
|
||||||
|
const char *SYNC="\x66\x65";
|
||||||
|
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
//if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
if(sx1278.setPreambleDetect(0x9F)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
// version 2, with per-packet rx start, untested
|
||||||
|
// header is 2a 10 65, i.e. with lsb first
|
||||||
|
// 0 0101 0100 1 0 0000 1000 1 0 1010 0110 1
|
||||||
|
// 10 10011001 10011010 01 10 10101010 01101010 01 10 01100110 10010110 01
|
||||||
|
// preamble 0x6A 0x66 0x6A
|
||||||
|
// i.e. preamble detector on (0x80), preamble detector size 1 (0x00), preample chip errors??? (0x0A)
|
||||||
|
// after 2a2a2a2a2a1065
|
||||||
|
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// sync config: ato restart (01), preamble polarity AA (0), sync on (1), resevered (0), syncsize 2+1 (010) => 0x52
|
||||||
|
const char *SYNC="\x6A\x66\x69";
|
||||||
|
if(sx1278.setSyncConf(0x52, 3, (const uint8_t *)SYNC)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// payload length is ((240 - 7)*10 +6)/8 = 292
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
||||||
|
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
||||||
|
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
||||||
|
M10_DBG(Serial.println("Setting Packet config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("M10: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
int res = sx1278.setFrequency(frequency);
|
||||||
|
// enable RX
|
||||||
|
sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
//sx1278.setPayloadLength(292);
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
|
||||||
|
#if M10_DEBUG
|
||||||
|
M10_DBG(Serial.println("Setting SX1278 config for M10 finished\n"); Serial.println());
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int M10::setFrequency(float frequency) {
|
||||||
|
Serial.print("M10: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
int res = sx1278.setFrequency(frequency);
|
||||||
|
// enable RX
|
||||||
|
sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
uint32_t M10::bits2val(const uint8_t *bits, int len) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
val |= (bits[j] << (len-1-j));
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
M10::M10() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define M10_FRAMELEN 101
|
||||||
|
#define M10_CRCPOS 99
|
||||||
|
|
||||||
|
void M10::printRaw(uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
char buf[3];
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len; i++) {
|
||||||
|
snprintf(buf, 3, "%02X ", data[i]);
|
||||||
|
Serial.print(buf);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int update_checkM10(int c, uint8_t b) {
|
||||||
|
int c0, c1, t, t6, t7, s;
|
||||||
|
c1 = c & 0xFF;
|
||||||
|
// B
|
||||||
|
b = (b >> 1) | ((b & 1) << 7);
|
||||||
|
b ^= (b >> 2) & 0xFF;
|
||||||
|
// A1
|
||||||
|
t6 = ( c & 1) ^ ((c >> 2) & 1) ^ ((c >> 4) & 1);
|
||||||
|
t7 = ((c >> 1) & 1) ^ ((c >> 3) & 1) ^ ((c >> 5) & 1);
|
||||||
|
t = (c & 0x3F) | (t6 << 6) | (t7 << 7);
|
||||||
|
// A2
|
||||||
|
s = (c >> 7) & 0xFF;
|
||||||
|
s ^= (s >> 2) & 0xFF;
|
||||||
|
c0 = b ^ t ^ s;
|
||||||
|
return ((c1 << 8) | c0) & 0xFFFF;
|
||||||
|
}
|
||||||
|
static bool checkM10crc(uint8_t *msg) {
|
||||||
|
int i, cs, cs1;
|
||||||
|
cs = 0;
|
||||||
|
for (i = 0; i < M10_CRCPOS; i++) {
|
||||||
|
cs = update_checkM10(cs, msg[i]);
|
||||||
|
}
|
||||||
|
cs = cs & 0xFFFF;
|
||||||
|
cs1 = (msg[M10_CRCPOS] << 8) | msg[M10_CRCPOS+1];
|
||||||
|
return (cs1 == cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef uint32_t SET256[8];
|
||||||
|
static SET256 sondeudp_VARSET = {0x03BBBBF0UL,0x80600000UL,0x06A001A0UL,
|
||||||
|
0x0000001CUL,0x00000000UL,0x00000000UL,0x00000000UL,
|
||||||
|
0x00000000UL};
|
||||||
|
// VARSET=SET256{4..9,11..13,15..17,19..21,23..25,53..54,63,69,71,72,85,87,89,90,98..100};
|
||||||
|
|
||||||
|
static uint8_t fixcnt[M10_FRAMELEN];
|
||||||
|
static uint8_t fixbytes[M10_FRAMELEN];
|
||||||
|
|
||||||
|
static int32_t getint32(uint8_t *data) {
|
||||||
|
return (int32_t)( data[3]|(data[2]<<8)|(data[1]<<16)|(data[0]<<24) );
|
||||||
|
}
|
||||||
|
static int16_t getint16(uint8_t *data) {
|
||||||
|
return (int16_t)(data[1]|((uint16_t)data[0]<<8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char dez(uint8_t nr) {
|
||||||
|
nr = nr%10;
|
||||||
|
return '0'+nr;
|
||||||
|
}
|
||||||
|
static char hex(uint8_t nr) {
|
||||||
|
nr = nr&0x0f;
|
||||||
|
if(nr<10) return '0'+nr;
|
||||||
|
else return 'A'+nr-10;
|
||||||
|
}
|
||||||
|
const static float DEGMUL = 1.0/0xB60B60;
|
||||||
|
#define VMUL 0.005
|
||||||
|
#ifndef PI
|
||||||
|
#define PI (3.1415926535897932384626433832795)
|
||||||
|
#endif
|
||||||
|
#define RAD (PI/180)
|
||||||
|
|
||||||
|
|
||||||
|
// ret: 1=frame ok; 2=frame with errors; 0=ignored frame (m10dop-alternativ)
|
||||||
|
int M10::decodeframeM10(uint8_t *data) {
|
||||||
|
int repairstep = 16;
|
||||||
|
int repl = 0;
|
||||||
|
bool crcok;
|
||||||
|
// error correction, inspired by oe5dxl's sondeudp
|
||||||
|
do {
|
||||||
|
crcok = checkM10crc(data);
|
||||||
|
if(crcok) break;
|
||||||
|
repl = 0;
|
||||||
|
for(int i=0; i<M10_CRCPOS; i++) {
|
||||||
|
if( ((sondeudp_VARSET[i/32]&(1<<(i%32))) != 1) && (fixcnt[i]>=repairstep) ) {
|
||||||
|
repl++;
|
||||||
|
data[i] = fixbytes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repairstep >>= 1;
|
||||||
|
} while(repairstep>0);
|
||||||
|
if(crcok) {
|
||||||
|
for(int i=0; i<M10_CRCPOS; i++) {
|
||||||
|
if(fixbytes[i]==data[i] &&fixcnt[i]<255) fixcnt[i]++;
|
||||||
|
else { fixcnt[i]=0; fixbytes[i]=data[i]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
||||||
|
|
||||||
|
if(data[1]==0x9F && data[2]==0x20) {
|
||||||
|
Serial.println("Decoding...");
|
||||||
|
// Its a M10
|
||||||
|
// getid...
|
||||||
|
char ids[11];
|
||||||
|
ids[0] = 'M';
|
||||||
|
ids[1] = 'E';
|
||||||
|
ids[2] = hex(data[95]/16);
|
||||||
|
ids[3] = hex(data[95]);
|
||||||
|
ids[4] = hex(data[93]);
|
||||||
|
uint32_t id = data[96] + data[97]*256;
|
||||||
|
ids[5] = hex(id/4096);
|
||||||
|
ids[6] = hex(id/256);
|
||||||
|
ids[7] = hex(id/16);
|
||||||
|
ids[8] = hex(id);
|
||||||
|
ids[9] = 0;
|
||||||
|
strncpy(sonde.si()->id, ids, 10);
|
||||||
|
ids[0] = hex(data[95]/16);
|
||||||
|
ids[1] = dez((data[95]&0x0f)/10);
|
||||||
|
ids[2] = dez((data[95]&0x0f));
|
||||||
|
ids[3] = dez(data[93]);
|
||||||
|
ids[4] = dez(id>>13);
|
||||||
|
id &= 0x1fff;
|
||||||
|
ids[5] = dez(id/1000);
|
||||||
|
ids[6] = dez((id/100)%10);
|
||||||
|
ids[7] = dez((id/10)%10);
|
||||||
|
ids[8] = dez(id%10);
|
||||||
|
strncpy(sonde.si()->ser, ids, 10);
|
||||||
|
sonde.si()->validID = true;
|
||||||
|
Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id);
|
||||||
|
// ID printed on sonde is ...-.-abbbb, with a=id>>13, bbbb=id&0x1fff in decimal
|
||||||
|
// position data
|
||||||
|
sonde.si()->lat = getint32(data+14) * DEGMUL;
|
||||||
|
sonde.si()->lon = getint32(data+18) * DEGMUL;
|
||||||
|
sonde.si()->alt = getint32(data+22) * 0.001;
|
||||||
|
float ve = getint16(data+4)*VMUL;
|
||||||
|
float vn = getint16(data+6)*VMUL;
|
||||||
|
sonde.si()->vs = getint16(data+8) * VMUL;
|
||||||
|
sonde.si()->hs = sqrt(ve*ve+vn*vn);
|
||||||
|
float dir = atan2(vn, ve)*(1.0/RAD);
|
||||||
|
if(dir<0) dir+=360;
|
||||||
|
sonde.si()->dir = dir;
|
||||||
|
sonde.si()->validPos = 0x3f;
|
||||||
|
|
||||||
|
uint32_t gpstime = getint32(data+10);
|
||||||
|
uint16_t gpsweek = getint16(data+32);
|
||||||
|
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
||||||
|
// one week = 7*24*60*60 = 604800 seconds
|
||||||
|
// unix epoch starts jan 1st 1970 0:00
|
||||||
|
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
||||||
|
// subtracting 86400 yields 315878400UL
|
||||||
|
sonde.si()->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
||||||
|
sonde.si()->validTime = true;
|
||||||
|
} else {
|
||||||
|
Serial.printf("data is %02x %02x %02x\n", data[0], data[1], data[2]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return crcok?1:2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t rxdata;
|
||||||
|
static bool rxsearching=true;
|
||||||
|
|
||||||
|
// search for
|
||||||
|
// //101001100110011010011010011001100110100110101010100110101001
|
||||||
|
// //1010011001100110100110100110 0110.0110 1001.1010 1010.1001 1010.1001 => 0x669AA9A9
|
||||||
|
void M10::processM10data(uint8_t dt)
|
||||||
|
{
|
||||||
|
for(int i=0; i<8; i++) {
|
||||||
|
uint8_t d = (dt&0x80)?1:0;
|
||||||
|
dt <<= 1;
|
||||||
|
rxdata = (rxdata<<1) | d;
|
||||||
|
//uint8_t value = ((rxdata>>1)^rxdata)&0x01;
|
||||||
|
//if((rxbitc&1)==1) { rxbyte = (rxbyte>>1) + ((value)<<8); } // mancester decoded data
|
||||||
|
//rxbyte = (rxbyte>>1) | (d<<8);
|
||||||
|
if( (rxbitc&1)==0 ) {
|
||||||
|
// "bit1"
|
||||||
|
rxbyte = (rxbyte<<1) | d;
|
||||||
|
} else {
|
||||||
|
// "bit2" ==> 01 or 10 => 1, otherweise => 0
|
||||||
|
rxbyte = rxbyte ^ d;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if(rxsearching) {
|
||||||
|
if( rxdata == 0xcccca64c || rxdata == 0x333359b3 ) {
|
||||||
|
rxsearching = false;
|
||||||
|
rxbitc = 0;
|
||||||
|
rxp = 0;
|
||||||
|
#if 1
|
||||||
|
int rssi=sx1278.getRSSI();
|
||||||
|
int fei=sx1278.getFEI();
|
||||||
|
int afc=sx1278.getAFC();
|
||||||
|
Serial.print("Test: RSSI="); Serial.print(rssi);
|
||||||
|
Serial.print(" FEI="); Serial.print(fei);
|
||||||
|
Serial.print(" AFC="); Serial.println(afc);
|
||||||
|
sonde.si()->rssi = rssi;
|
||||||
|
sonde.si()->afc = afc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rxbitc = (rxbitc+1)%16; // 16;
|
||||||
|
if(rxbitc == 0) { // got 8 data bit
|
||||||
|
//Serial.printf("%03x ",rxbyte);
|
||||||
|
dataptr[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
||||||
|
#if 0
|
||||||
|
if(rxp==7 && dataptr[6] != 0x65) {
|
||||||
|
Serial.printf("wrong start: %02x\n",dataptr[6]);
|
||||||
|
rxsearching = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(rxp>=M10_FRAMELEN) {
|
||||||
|
rxsearching = true;
|
||||||
|
haveNewFrame = decodeframeM10(dataptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int M10::receive() {
|
||||||
|
unsigned long t0 = millis();
|
||||||
|
Serial.printf("M10::receive() start at %ld\n",t0);
|
||||||
|
while( millis() - t0 < 1000 ) {
|
||||||
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
if ( bitRead(value, 7) ) {
|
||||||
|
Serial.println("FIFO full");
|
||||||
|
}
|
||||||
|
if ( bitRead(value, 4) ) {
|
||||||
|
Serial.println("FIFO overflow");
|
||||||
|
}
|
||||||
|
if ( bitRead(value, 2) == 1 ) {
|
||||||
|
Serial.println("FIFO: ready()");
|
||||||
|
sx1278.clearIRQFlags();
|
||||||
|
}
|
||||||
|
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
||||||
|
byte data = sx1278.readRegister(REG_FIFO);
|
||||||
|
//Serial.printf("%02x",data);
|
||||||
|
processM10data(data);
|
||||||
|
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
} else {
|
||||||
|
if(headerDetected) {
|
||||||
|
t0 = millis(); // restart timer... don't time out if header detected...
|
||||||
|
headerDetected = 0;
|
||||||
|
}
|
||||||
|
if(haveNewFrame) {
|
||||||
|
Serial.printf("M10::receive(): new frame complete after %ldms\n", millis()-t0);
|
||||||
|
printRaw(dataptr, M10_FRAMELEN);
|
||||||
|
int retval = haveNewFrame==1 ? RX_OK: RX_ERROR;
|
||||||
|
haveNewFrame = 0;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.printf("M10::receive() timed out\n");
|
||||||
|
return RX_TIMEOUT; // TODO RX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define M10MAXLEN (240)
|
||||||
|
int M10::waitRXcomplete() {
|
||||||
|
// called after complete...
|
||||||
|
#if 0
|
||||||
|
Serial.printf("decoding frame %d\n", lastFrame);
|
||||||
|
print_frame(lastFrame==1?data1:data2, 240);
|
||||||
|
SondeInfo *si = sonde.sondeList+rxtask.receiveSonde;
|
||||||
|
si->lat = gpx.lat;
|
||||||
|
si->lon = gpx.lon;
|
||||||
|
si->alt = gpx.alt;
|
||||||
|
si->vs = gpx.vU;
|
||||||
|
si->hs = gpx.vH;
|
||||||
|
si->dir = gpx.vD;
|
||||||
|
si->validPos = 0x3f;
|
||||||
|
memcpy(si->id, gpx.id, 9);
|
||||||
|
si->validID = true;
|
||||||
|
|
||||||
|
int res=0;
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while( rxtask.receiveResult == 0xFFFF && millis()-t0 < 2000) { delay(20); }
|
||||||
|
|
||||||
|
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||||
|
res = RX_TIMEOUT;
|
||||||
|
} else if ( rxtask.receiveResult==0) {
|
||||||
|
res = RX_OK;
|
||||||
|
} else {
|
||||||
|
res = RX_ERROR;
|
||||||
|
}
|
||||||
|
rxtask.receiveResult = 0xFFFF;
|
||||||
|
Serial.printf("M10::waitRXcomplete returning %d (%s)\n", res, RXstr[res]);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int oldwaitRXcomplete() {
|
||||||
|
Serial.println("M10: receive frame...\n");
|
||||||
|
sx1278receiveData = true;
|
||||||
|
delay(6000); // done in other task....
|
||||||
|
//sx1278receiveData = false;
|
||||||
|
#if 0
|
||||||
|
//sx1278.setPayloadLength(518-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header)
|
||||||
|
//sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
|
||||||
|
////// test code for continuous reception
|
||||||
|
// sx1278.receive(); /// active FSK RX mode -- already done above...
|
||||||
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
unsigned long previous = millis();
|
||||||
|
|
||||||
|
byte ready=0;
|
||||||
|
uint32_t wait = 8000;
|
||||||
|
// while not yet done or FIFO not yet empty
|
||||||
|
// bit 6: FIFO Empty
|
||||||
|
// bit 2 payload ready
|
||||||
|
int by=0;
|
||||||
|
while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) )
|
||||||
|
{
|
||||||
|
if( bitRead(value, 7) ) { Serial.println("FIFO full"); }
|
||||||
|
if( bitRead(value, 4) ) { Serial.println("FIFO overflow"); }
|
||||||
|
if( bitRead(value,2)==1 ) ready=1;
|
||||||
|
if( bitRead(value, 6) == 0 ) { // FIFO not empty
|
||||||
|
byte data = sx1278.readRegister(REG_FIFO);
|
||||||
|
process8N1data(data);
|
||||||
|
by++;
|
||||||
|
#if 0
|
||||||
|
if(di==1) {
|
||||||
|
int rssi=getRSSI();
|
||||||
|
int fei=getFEI();
|
||||||
|
int afc=getAFC();
|
||||||
|
Serial.print("Test: RSSI="); Serial.println(rssi);
|
||||||
|
Serial.print("Test: FEI="); Serial.println(fei);
|
||||||
|
Serial.print("Test: AFC="); Serial.println(afc);
|
||||||
|
sonde.si()->rssi = rssi;
|
||||||
|
sonde.si()->afc = afc;
|
||||||
|
}
|
||||||
|
if(di>520) {
|
||||||
|
// TODO
|
||||||
|
Serial.println("TOO MUCH DATA");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previous = millis(); // reset timeout after receiving data
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
}
|
||||||
|
Serial.printf("processed %d bytes before end/timeout\n", by);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////
|
||||||
|
#if 0
|
||||||
|
int e = sx1278.receivePacketTimeout(1000, data+8);
|
||||||
|
if(e) { Serial.println("TIMEOUT"); return RX_TIMEOUT; } //if timeout... return 1
|
||||||
|
|
||||||
|
printRaw(data, M10MAXLEN);
|
||||||
|
//for(int i=0; i<M10MAXLEN; i++) { data[i] = reverse(data[i]); }
|
||||||
|
//printRaw(data, MAXLEN);
|
||||||
|
//for(int i=0; i<M10MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
|
||||||
|
//printRaw(data, MAXLEN);
|
||||||
|
//int res = decode41(data, M10MAXLEN);
|
||||||
|
#endif
|
||||||
|
int res=0;
|
||||||
|
return res==0 ? RX_OK : RX_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
M10 m10 = M10();
|
50
RX_FSK/src/M10M20.h → libraries/SondeLib/M10.h
Normal file → Executable file
50
RX_FSK/src/M10M20.h → libraries/SondeLib/M10.h
Normal file → Executable file
|
@ -1,13 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* M10M20.h
|
* M10.h
|
||||||
* Functions for decoding Meteomodem M10M20 sondes with SX127x chips
|
* Functions for decoding Meteomodem M10 sondes with SX127x chips
|
||||||
* Copyright (C) 2019 Hansi Reiser, dl9rdz
|
* Copyright (C) 2019 Hansi Reiser, dl9rdz
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef M10M20_h
|
#ifndef M10_h
|
||||||
#define M10M20_h
|
#define M10_h
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -15,16 +15,46 @@
|
||||||
#ifndef inttypes_h
|
#ifndef inttypes_h
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#endif
|
#endif
|
||||||
#include "DecoderBase.h"
|
|
||||||
|
#if 0
|
||||||
|
struct CONTEXTR9 {
|
||||||
|
char calibdata[512];
|
||||||
|
uint32_t calibok;
|
||||||
|
char mesok;
|
||||||
|
char posok;
|
||||||
|
char framesent;
|
||||||
|
double lat;
|
||||||
|
double lon;
|
||||||
|
double heig;
|
||||||
|
double speed;
|
||||||
|
double dir;
|
||||||
|
double climb;
|
||||||
|
double lastlat;
|
||||||
|
double laslong;
|
||||||
|
double lastalt;
|
||||||
|
double lastspeed;
|
||||||
|
double lastdir;
|
||||||
|
double lastclb;
|
||||||
|
float hrmsc;
|
||||||
|
float vrmsc;
|
||||||
|
double hp;
|
||||||
|
double hyg;
|
||||||
|
double temp;
|
||||||
|
double ozontemp;
|
||||||
|
double ozon;
|
||||||
|
uint32_t goodsats;
|
||||||
|
uint32_t timems;
|
||||||
|
uint32_t framenum;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Main class */
|
/* Main class */
|
||||||
class M10M20 : public DecoderBase
|
class M10
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
void printRaw(uint8_t *data, int len);
|
void printRaw(uint8_t *data, int len);
|
||||||
void processM10data(uint8_t data);
|
void processM10data(uint8_t data);
|
||||||
int decodeframeM10(uint8_t *data);
|
int decodeframeM10(uint8_t *data);
|
||||||
int decodeframeM20(uint8_t *data);
|
|
||||||
#if 0
|
#if 0
|
||||||
void stobyte92(uint8_t byte);
|
void stobyte92(uint8_t byte);
|
||||||
void dogps(const uint8_t *sf, int sf_len,
|
void dogps(const uint8_t *sf, int sf_len,
|
||||||
|
@ -53,14 +83,14 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
M10M20();
|
M10();
|
||||||
int setup(float frequency, int type = 0);
|
int setup(float frequency);
|
||||||
int receive();
|
int receive();
|
||||||
int waitRXcomplete();
|
int waitRXcomplete();
|
||||||
|
|
||||||
//int use_ecc = 1;
|
//int use_ecc = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern M10M20 m10m20;
|
extern M10 m10;
|
||||||
|
|
||||||
#endif
|
#endif
|
556
libraries/SondeLib/RS41.cpp
Executable file
556
libraries/SondeLib/RS41.cpp
Executable file
|
@ -0,0 +1,556 @@
|
||||||
|
|
||||||
|
/* RS41 decoder functions */
|
||||||
|
#include "RS41.h"
|
||||||
|
#include "SX1278FSK.h"
|
||||||
|
#include "rsc.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
|
#define RS41_DEBUG 0
|
||||||
|
|
||||||
|
#if RS41_DEBUG
|
||||||
|
#define RS41_DBG(x) x
|
||||||
|
#else
|
||||||
|
#define RS41_DBG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RS41MAXLEN (320)
|
||||||
|
static byte data[800];
|
||||||
|
static int dpos = 0;
|
||||||
|
|
||||||
|
static uint16_t CRCTAB[256];
|
||||||
|
|
||||||
|
#define X2C_DIVR(a, b) ((b) != 0.0f ? (a)/(b) : (a))
|
||||||
|
#define X2C_DIVL(a, b) ((a)/(b))
|
||||||
|
static uint32_t X2C_LSH(uint32_t a, int32_t length, int32_t n)
|
||||||
|
{
|
||||||
|
uint32_t m;
|
||||||
|
|
||||||
|
m = 0;
|
||||||
|
m = (length == 32) ? 0xFFFFFFFFl : (1 << length) - 1;
|
||||||
|
if (n > 0) {
|
||||||
|
if (n >= (int32_t)length)
|
||||||
|
return 0;
|
||||||
|
return (a << n) & m;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n <= (int32_t)-length)
|
||||||
|
return 0;
|
||||||
|
return (a >> -n) & m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double atang2(double x, double y)
|
||||||
|
{
|
||||||
|
double w;
|
||||||
|
if (fabs(x)>fabs(y)) {
|
||||||
|
w = (double)atan((float)(X2C_DIVL(y,x)));
|
||||||
|
if (x<0.0) {
|
||||||
|
if (y>0.0) w = 3.1415926535898+w;
|
||||||
|
else w = w-3.1415926535898;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (y!=0.0) {
|
||||||
|
w = (double)(1.5707963267949f-atan((float)(X2C_DIVL(x,
|
||||||
|
y))));
|
||||||
|
if (y<0.0) w = w-3.1415926535898;
|
||||||
|
}
|
||||||
|
else w = 0.0;
|
||||||
|
return w;
|
||||||
|
} /* end atang2() */
|
||||||
|
|
||||||
|
|
||||||
|
static void Gencrctab(void)
|
||||||
|
{
|
||||||
|
uint16_t j;
|
||||||
|
uint16_t i;
|
||||||
|
uint16_t crc;
|
||||||
|
for (i = 0U; i<=255U; i++) {
|
||||||
|
crc = (uint16_t)(i*256U);
|
||||||
|
for (j = 0U; j<=7U; j++) {
|
||||||
|
if ((0x8000U & crc)) crc = X2C_LSH(crc,16,1)^0x1021U;
|
||||||
|
else crc = X2C_LSH(crc,16,1);
|
||||||
|
} /* end for */
|
||||||
|
CRCTAB[i] = X2C_LSH(crc,16,-8)|X2C_LSH(crc,16,8);
|
||||||
|
} /* end for */
|
||||||
|
} /* end Gencrctab() */
|
||||||
|
|
||||||
|
int RS41::setup(float frequency)
|
||||||
|
{
|
||||||
|
#if RS41_DEBUG
|
||||||
|
Serial.println("Setup sx1278 for RS41 sonde");
|
||||||
|
#endif
|
||||||
|
if(!initialized) {
|
||||||
|
Gencrctab();
|
||||||
|
initrsc();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sx1278.ON()!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setFSK()!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting FSK mode FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setBitrate(4800)!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting bitrate 4800bit/s FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#if RS41_DEBUG
|
||||||
|
float br = sx1278.getBitrate();
|
||||||
|
Serial.print("Exact bitrate is ");
|
||||||
|
Serial.println(br);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(sx1278.setAFCBandwidth(sonde.config.rs41.agcbw)!=0) {
|
||||||
|
RS41_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.rs41.agcbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setRxBandwidth(sonde.config.rs41.rxbw)!=0) {
|
||||||
|
RS41_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.rs41.rxbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
||||||
|
if(sx1278.setRxConf(0x1E)!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting RX Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
||||||
|
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
||||||
|
|
||||||
|
//const char *SYNC="\x10\xB6\xCA\x11\x22\x96\x12\xF8";
|
||||||
|
const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
||||||
|
if(sx1278.setSyncConf(0x57, 8, (const uint8_t *)SYNC)!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
||||||
|
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
||||||
|
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
||||||
|
RS41_DBG(Serial.println("Setting Packet config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Serial.print("RS41: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
int retval = sx1278.setFrequency(frequency);
|
||||||
|
dpos = 0;
|
||||||
|
|
||||||
|
#if RS41_DEBUG
|
||||||
|
RS41_DBG(Serial.println("Setting SX1278 config for RS41 finished\n"); Serial.println());
|
||||||
|
#endif
|
||||||
|
sx1278.clearIRQFlags();
|
||||||
|
|
||||||
|
// the following is already done in receivePacketTimeout()
|
||||||
|
// sx1278.setPayloadLength(RS41MAXLEN-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header)
|
||||||
|
// sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RS41::bits2val(const uint8_t *bits, int len) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
val |= (bits[j] << (len-1-j));
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS41::RS41() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RS41 reed solomon decoder, from dxlAPRS
|
||||||
|
*/
|
||||||
|
static int32_t reedsolomon41(byte buf[], uint32_t buf_len, uint32_t len2)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
int32_t res1;
|
||||||
|
/*tb1, */
|
||||||
|
int32_t res;
|
||||||
|
char b1[256];
|
||||||
|
char b[256];
|
||||||
|
uint32_t eraspos[24];
|
||||||
|
uint32_t tmp;
|
||||||
|
for (i = 0UL; i<=255UL; i++) {
|
||||||
|
b[i] = 0;
|
||||||
|
b1[i] = 0;
|
||||||
|
} /* end for */
|
||||||
|
tmp = len2;
|
||||||
|
i = 0UL;
|
||||||
|
if (i<=tmp) for (;; i++) {
|
||||||
|
b[230UL-i] = buf[i*2UL+56UL];
|
||||||
|
b1[230UL-i] = buf[i*2UL+57UL];
|
||||||
|
if (i==tmp) break;
|
||||||
|
} /* end for */
|
||||||
|
for (i = 0UL; i<=23UL; i++) {
|
||||||
|
b[254UL-i] = buf[i+8UL];
|
||||||
|
b1[254UL-i] = buf[i+32UL];
|
||||||
|
} /* end for */
|
||||||
|
res = decodersc(b, eraspos, 0);
|
||||||
|
res1 = decodersc(b1, eraspos, 0);
|
||||||
|
if (res>0L && res<=12L) {
|
||||||
|
tmp = len2;
|
||||||
|
i = 0UL;
|
||||||
|
if (i<=tmp) for (;; i++) {
|
||||||
|
buf[i*2UL+56UL] = b[230UL-i];
|
||||||
|
if (i==tmp) break;
|
||||||
|
} /* end for */
|
||||||
|
for (i = 0UL; i<=23UL; i++) {
|
||||||
|
buf[i+8UL] = b[254UL-i];
|
||||||
|
} /* end for */
|
||||||
|
}
|
||||||
|
if (res1>0L && res1<=12L) {
|
||||||
|
tmp = len2;
|
||||||
|
i = 0UL;
|
||||||
|
if (i<=tmp) for (;; i++) {
|
||||||
|
buf[i*2UL+57UL] = b1[230UL-i];
|
||||||
|
if (i==tmp) break;
|
||||||
|
} /* end for */
|
||||||
|
for (i = 0UL; i<=23UL; i++) {
|
||||||
|
buf[i+32UL] = b1[254UL-i];
|
||||||
|
} /* end for */
|
||||||
|
}
|
||||||
|
if (res<0L || res1<0L) return -1L;
|
||||||
|
else return res+res1;
|
||||||
|
return 0;
|
||||||
|
} /* end reedsolomon41() */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char crcrs(const byte frame[], uint32_t frame_len,
|
||||||
|
int32_t from, int32_t to)
|
||||||
|
{
|
||||||
|
uint16_t crc;
|
||||||
|
int32_t i;
|
||||||
|
int32_t tmp;
|
||||||
|
crc = 0xFFFFU;
|
||||||
|
tmp = to-3L;
|
||||||
|
i = from;
|
||||||
|
if (i<=tmp) for (;; i++) {
|
||||||
|
crc = X2C_LSH(crc,16,-8)^CRCTAB[(uint32_t)((crc^(uint16_t)(uint8_t)frame[i])&0xFFU)];
|
||||||
|
if (i==tmp) break;
|
||||||
|
} /* end for */
|
||||||
|
return frame[to-1L]==(char)crc && frame[to-2L]==(char)X2C_LSH(crc,
|
||||||
|
16,-8);
|
||||||
|
} /* end crcrs() */
|
||||||
|
|
||||||
|
static int32_t getint32(const byte frame[], uint32_t frame_len,
|
||||||
|
uint32_t p)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
uint32_t i;
|
||||||
|
n = 0UL;
|
||||||
|
for (i = 3UL;; i--) {
|
||||||
|
n = n*256UL+(uint32_t)(uint8_t)frame[p+i];
|
||||||
|
if (i==0UL) break;
|
||||||
|
} /* end for */
|
||||||
|
return (int32_t)n;
|
||||||
|
} /* end getint32() */
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t getcard16(const byte frame[], uint32_t frame_len,
|
||||||
|
uint32_t p)
|
||||||
|
{
|
||||||
|
return (uint32_t)(uint8_t)frame[p]+256UL*(uint32_t)(uint8_t)
|
||||||
|
frame[p+1UL];
|
||||||
|
} /* end getcard16() */
|
||||||
|
|
||||||
|
|
||||||
|
static int32_t getint16(const byte frame[], uint32_t frame_len,
|
||||||
|
uint32_t p)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
n = (uint32_t)(uint8_t)frame[p]+256UL*(uint32_t)(uint8_t)
|
||||||
|
frame[p+1UL];
|
||||||
|
if (n>=32768UL) return (int32_t)(n-65536UL);
|
||||||
|
return (int32_t)n;
|
||||||
|
} /* end getint16() */
|
||||||
|
|
||||||
|
static void wgs84r(double x, double y, double z,
|
||||||
|
double * lat, double * long0,
|
||||||
|
double * heig)
|
||||||
|
{
|
||||||
|
double sl;
|
||||||
|
double ct;
|
||||||
|
double st;
|
||||||
|
double t;
|
||||||
|
double rh;
|
||||||
|
double xh;
|
||||||
|
double h;
|
||||||
|
h = x*x+y*y;
|
||||||
|
if (h>0.0) {
|
||||||
|
rh = (double)sqrt((float)h);
|
||||||
|
xh = x+rh;
|
||||||
|
*long0 = atang2(xh, y)*2.0;
|
||||||
|
if (*long0>3.1415926535898) *long0 = *long0-6.2831853071796;
|
||||||
|
t = (double)atan((float)(X2C_DIVL(z*1.003364089821,
|
||||||
|
rh)));
|
||||||
|
st = (double)sin((float)t);
|
||||||
|
ct = (double)cos((float)t);
|
||||||
|
*lat = (double)atan((float)
|
||||||
|
(X2C_DIVL(z+4.2841311513312E+4*st*st*st,
|
||||||
|
rh-4.269767270718E+4*ct*ct*ct)));
|
||||||
|
sl = (double)sin((float)*lat);
|
||||||
|
*heig = X2C_DIVL(rh,(double)cos((float)*lat))-(double)(X2C_DIVR(6.378137E+6f,
|
||||||
|
sqrt((float)(1.0-6.6943799901413E-3*sl*sl))));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*lat = 0.0;
|
||||||
|
*long0 = 0.0;
|
||||||
|
*heig = 0.0;
|
||||||
|
}
|
||||||
|
/* lat:=atan(z/(rh*(1.0 - E2))); */
|
||||||
|
/* heig:=sqrt(h + z*z) - EARTHA; */
|
||||||
|
} /* end wgs84r() */
|
||||||
|
|
||||||
|
// returns: 0=ok, -1=error
|
||||||
|
static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
|
||||||
|
{
|
||||||
|
double dir;
|
||||||
|
double vu;
|
||||||
|
double ve;
|
||||||
|
double vn;
|
||||||
|
double vz;
|
||||||
|
double vy;
|
||||||
|
double vx;
|
||||||
|
double heig;
|
||||||
|
double long0;
|
||||||
|
double lat;
|
||||||
|
double z;
|
||||||
|
double y;
|
||||||
|
double x;
|
||||||
|
x = (double)getint32(b, b_len, p)*0.01;
|
||||||
|
y = (double)getint32(b, b_len, p+4UL)*0.01;
|
||||||
|
z = (double)getint32(b, b_len, p+8UL)*0.01;
|
||||||
|
wgs84r(x, y, z, &lat, &long0, &heig);
|
||||||
|
Serial.print(" ");
|
||||||
|
sonde.si()->lat = (float)(X2C_DIVL(lat,1.7453292519943E-2));
|
||||||
|
Serial.print(sonde.si()->lat);
|
||||||
|
Serial.print(" ");
|
||||||
|
sonde.si()->lon = (float)(X2C_DIVL(long0,1.7453292519943E-2));
|
||||||
|
Serial.print(sonde.si()->lon);
|
||||||
|
if (heig<1.E+5 && heig>(-1.E+5)) {
|
||||||
|
Serial.print(" ");
|
||||||
|
Serial.print((uint32_t)heig);
|
||||||
|
Serial.print("m");
|
||||||
|
}
|
||||||
|
/*speed */
|
||||||
|
vx = (double)getint16(b, b_len, p+12UL)*0.01;
|
||||||
|
vy = (double)getint16(b, b_len, p+14UL)*0.01;
|
||||||
|
vz = (double)getint16(b, b_len, p+16UL)*0.01;
|
||||||
|
vn = (-(vx*(double)sin((float)lat)*(double)
|
||||||
|
cos((float)long0))-vy*(double)
|
||||||
|
sin((float)lat)*(double)sin((float)
|
||||||
|
long0))+vz*(double)cos((float)lat);
|
||||||
|
ve = -(vx*(double)sin((float)long0))+vy*(double)
|
||||||
|
cos((float)long0);
|
||||||
|
vu = vx*(double)cos((float)lat)*(double)
|
||||||
|
cos((float)long0)+vy*(double)
|
||||||
|
cos((float)lat)*(double)sin((float)
|
||||||
|
long0)+vz*(double)sin((float)lat);
|
||||||
|
dir = X2C_DIVL(atang2(vn, ve),1.7453292519943E-2);
|
||||||
|
if (dir<0.0) dir = 360.0+dir;
|
||||||
|
sonde.si()->dir = dir;
|
||||||
|
Serial.print(" ");
|
||||||
|
sonde.si()->hs = sqrt((float)(vn*vn+ve*ve))*3.6f;
|
||||||
|
Serial.print(sonde.si()->hs);
|
||||||
|
Serial.print("km/h ");
|
||||||
|
Serial.print(dir);
|
||||||
|
Serial.print("deg ");
|
||||||
|
Serial.print((float)vu);
|
||||||
|
sonde.si()->vs = vu;
|
||||||
|
Serial.print("m/s ");
|
||||||
|
uint8_t sats = getcard16(b, b_len, p+18UL)&255UL;
|
||||||
|
Serial.print(sats);
|
||||||
|
Serial.print("Sats");
|
||||||
|
sonde.si()->sats = sats;
|
||||||
|
sonde.si()->alt = heig;
|
||||||
|
if( 0==(int)(lat*10000) && 0==(int)(long0*10000) ) {
|
||||||
|
if(sonde.si()->validPos) {
|
||||||
|
// we have an old position, so keep previous position and mark it as old
|
||||||
|
sonde.si()->validPos |= 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sonde.si()->validPos = 0x7f;
|
||||||
|
} /* end posrs41() */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// returns: 0: ok, -1: rs or crc error
|
||||||
|
int RS41::decode41(byte *data, int maxlen)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
int crcok = 0;
|
||||||
|
|
||||||
|
int32_t corr = reedsolomon41(data, 560, 131); // try short frame first
|
||||||
|
if(corr<0) {
|
||||||
|
corr = reedsolomon41(data, 560, 230); // try long frame
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
Serial.print("RS result:");
|
||||||
|
Serial.print(corr);
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
int p = 57; // 8 byte header, 48 byte RS
|
||||||
|
while(p<maxlen) { /* why 555? */
|
||||||
|
uint8_t typ = data[p++];
|
||||||
|
uint32_t len = data[p++]+2UL;
|
||||||
|
if(p+len>maxlen) break;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// DEBUG OUTPUT
|
||||||
|
Serial.print("@");
|
||||||
|
Serial.print(p-2);
|
||||||
|
Serial.print(": ID:");
|
||||||
|
Serial.print(typ, HEX);
|
||||||
|
Serial.print(", len=");
|
||||||
|
Serial.print(len);
|
||||||
|
Serial.print(": ");
|
||||||
|
for(int i=0; i<len-1; i++) {
|
||||||
|
char buf[3];
|
||||||
|
snprintf(buf, 4, "%02X|", data[p+i]);
|
||||||
|
Serial.print(buf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// check CRC
|
||||||
|
if(!crcrs(data, 560, p, p+len)) {
|
||||||
|
Serial.println("###CRC ERROR###");
|
||||||
|
} else {
|
||||||
|
crcok = 1;
|
||||||
|
switch(typ) {
|
||||||
|
case 'y': // name
|
||||||
|
{
|
||||||
|
Serial.print("#");
|
||||||
|
uint16_t fnr = data[p]+(data[p+1]<<8);
|
||||||
|
Serial.print(fnr);
|
||||||
|
sonde.si()->frame = fnr;
|
||||||
|
Serial.print("; RS41 ID ");
|
||||||
|
snprintf(buf, 10, "%.8s ", data+p+2);
|
||||||
|
Serial.print(buf);
|
||||||
|
sonde.si()->type=STYPE_RS41;
|
||||||
|
strncpy(sonde.si()->id, (const char *)(data+p+2), 8);
|
||||||
|
sonde.si()->id[8]=0;
|
||||||
|
strncpy(sonde.si()->ser, (const char *)(data+p+2), 8);
|
||||||
|
sonde.si()->ser[8]=0;
|
||||||
|
sonde.si()->validID=true;
|
||||||
|
int calnr = data[p+23];
|
||||||
|
// not sure about this
|
||||||
|
if(calnr==0x31) {
|
||||||
|
uint16_t bt = data[p+30] + 256*data[p+31];
|
||||||
|
sonde.si()->burstKT = bt;
|
||||||
|
}
|
||||||
|
// this should be right...
|
||||||
|
if(calnr==0x02) {
|
||||||
|
uint16_t kt = data[p+31] + 256*data[p+32];
|
||||||
|
sonde.si()->launchKT = kt;
|
||||||
|
}
|
||||||
|
// and this seems fine as well...
|
||||||
|
if(calnr==0x32) {
|
||||||
|
uint16_t cntdown = data[p+24] + (data[p+25]<<8);
|
||||||
|
uint16_t min = cntdown - (cntdown/3600)*3600;
|
||||||
|
Serial.printf("Countdown value: %d\n [%2d:%02d:%02d]", cntdown, cntdown/3600, min/60, min-(min/60)*60);
|
||||||
|
sonde.si()->countKT = cntdown;
|
||||||
|
sonde.si()->crefKT = fnr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: some more data
|
||||||
|
break;
|
||||||
|
case '|': // date
|
||||||
|
{
|
||||||
|
uint32_t gpstime = getint32(data, 560, p+2);
|
||||||
|
uint16_t gpsweek = getint16(data, 560, p);
|
||||||
|
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
||||||
|
// one week = 7*24*60*60 = 604800 seconds
|
||||||
|
// unix epoch starts jan 1st 1970 0:00
|
||||||
|
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
||||||
|
// subtracting 86400 yields 315878400UL
|
||||||
|
sonde.si()->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
||||||
|
sonde.si()->validTime = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '{': // pos
|
||||||
|
posrs41(data+p, len, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}}
|
||||||
|
p += len;
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
return crcok ? 0 : -1;
|
||||||
|
}
|
||||||
|
void RS41::printRaw(uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
char buf[3];
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len; i++) {
|
||||||
|
snprintf(buf, 3, "%02X", data[i]);
|
||||||
|
Serial.print(buf);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RS41::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len*4; i++) {
|
||||||
|
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
||||||
|
}
|
||||||
|
bytes[(i-1)/8] &= 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char lookup[16] = {
|
||||||
|
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||||
|
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };
|
||||||
|
|
||||||
|
static uint8_t reverse(uint8_t n) {
|
||||||
|
return (lookup[n&0x0f] << 4) | lookup[n>>4];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t scramble[64] = {150U,131U,62U,81U,177U,73U,8U,152U,50U,5U,89U,
|
||||||
|
14U,249U,68U,198U,38U,33U,96U,194U,234U,121U,93U,109U,161U,
|
||||||
|
84U,105U,71U,12U,220U,232U,92U,241U,247U,118U,130U,127U,7U,
|
||||||
|
153U,162U,44U,147U,124U,48U,99U,245U,16U,46U,97U,208U,188U,
|
||||||
|
180U,182U,6U,170U,244U,35U,120U,110U,59U,174U,191U,123U,76U,
|
||||||
|
193U};
|
||||||
|
|
||||||
|
|
||||||
|
int RS41::receive() {
|
||||||
|
sx1278.setPayloadLength(RS41MAXLEN-8);
|
||||||
|
int e = sx1278.receivePacketTimeout(1000, data+8);
|
||||||
|
if(e) { Serial.println("TIMEOUT"); return RX_TIMEOUT; }
|
||||||
|
|
||||||
|
for(int i=0; i<RS41MAXLEN; i++) { data[i] = reverse(data[i]); }
|
||||||
|
for(int i=0; i<RS41MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
|
||||||
|
return decode41(data, RS41MAXLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RS41::waitRXcomplete() {
|
||||||
|
// Currently not used. can be used for additinoal post-processing
|
||||||
|
// (required for RS92 to avoid FIFO overrun in rx task)
|
||||||
|
#if 0
|
||||||
|
int res;
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while(rxtask.receiveResult<0 && millis()-t0 < 3000) { delay(50); }
|
||||||
|
|
||||||
|
if(rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||||
|
res = RX_TIMEOUT;
|
||||||
|
} else if (rxtask.receiveResult==0) {
|
||||||
|
res = RX_OK;
|
||||||
|
} else {
|
||||||
|
res = RX_ERROR;
|
||||||
|
}
|
||||||
|
rxtask.receiveResult = -1;
|
||||||
|
Serial.printf("waitRXcomplete returning %d\n", res);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS41 rs41 = RS41();
|
10
RX_FSK/src/RS41.h → libraries/SondeLib/RS41.h
Normal file → Executable file
10
RX_FSK/src/RS41.h → libraries/SondeLib/RS41.h
Normal file → Executable file
|
@ -15,11 +15,9 @@
|
||||||
#ifndef inttypes_h
|
#ifndef inttypes_h
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#endif
|
#endif
|
||||||
#include "Sonde.h"
|
|
||||||
#include "DecoderBase.h"
|
|
||||||
|
|
||||||
/* Main class */
|
/* Main class */
|
||||||
class RS41 : public DecoderBase
|
class RS41
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint32_t bits2val(const uint8_t *bits, int len);
|
uint32_t bits2val(const uint8_t *bits, int len);
|
||||||
|
@ -27,7 +25,6 @@ private:
|
||||||
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
||||||
int decode41(byte *data, int maxlen);
|
int decode41(byte *data, int maxlen);
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define B 8
|
#define B 8
|
||||||
#define S 4
|
#define S 4
|
||||||
uint8_t hamming_conf[ 7*B]; // 7*8=56
|
uint8_t hamming_conf[ 7*B]; // 7*8=56
|
||||||
|
@ -44,7 +41,6 @@ private:
|
||||||
{ 1, 1, 0, 1, 0, 0, 1, 0},
|
{ 1, 1, 0, 1, 0, 0, 1, 0},
|
||||||
{ 1, 1, 1, 0, 0, 0, 0, 1}};
|
{ 1, 1, 1, 0, 0, 0, 0, 1}};
|
||||||
uint8_t He[8] = { 0x7, 0xB, 0xD, 0xE, 0x8, 0x4, 0x2, 0x1}; // Spalten von H:
|
uint8_t He[8] = { 0x7, 0xB, 0xD, 0xE, 0x8, 0x4, 0x2, 0x1}; // Spalten von H:
|
||||||
#endif
|
|
||||||
// 1-bit-error-Syndrome
|
// 1-bit-error-Syndrome
|
||||||
boolean initialized = false;
|
boolean initialized = false;
|
||||||
|
|
||||||
|
@ -52,7 +48,7 @@ public:
|
||||||
RS41();
|
RS41();
|
||||||
// New interface:
|
// New interface:
|
||||||
// setup() is called when channel is activated (sets mode and frequency and activates receiver)
|
// setup() is called when channel is activated (sets mode and frequency and activates receiver)
|
||||||
int setup(float frequency, int type = 0);
|
int setup(float frequency);
|
||||||
// processRXbyte is called by background task for each received byte
|
// processRXbyte is called by background task for each received byte
|
||||||
// should be fast enough to not cause sx127x fifo buffer overflow
|
// should be fast enough to not cause sx127x fifo buffer overflow
|
||||||
// void processRXbyte(uint8_t data);
|
// void processRXbyte(uint8_t data);
|
||||||
|
@ -63,8 +59,6 @@ public:
|
||||||
int waitRXcomplete();
|
int waitRXcomplete();
|
||||||
//int receiveFrame();
|
//int receiveFrame();
|
||||||
|
|
||||||
static int getSubtype(char *buf, int buflen, SondeInfo *si);
|
|
||||||
|
|
||||||
int use_ecc = 1;
|
int use_ecc = 1;
|
||||||
};
|
};
|
||||||
|
|
172
RX_FSK/src/RS92.cpp → libraries/SondeLib/RS92.cpp
Normal file → Executable file
172
RX_FSK/src/RS92.cpp → libraries/SondeLib/RS92.cpp
Normal file → Executable file
|
@ -17,6 +17,7 @@
|
||||||
#define RS92_DBG(x)
|
#define RS92_DBG(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//static uint16_t CRCTAB[256];
|
||||||
uint16_t *CRCTAB = NULL;
|
uint16_t *CRCTAB = NULL;
|
||||||
|
|
||||||
#define X2C_DIVR(a, b) ((b) != 0.0f ? (a)/(b) : (a))
|
#define X2C_DIVR(a, b) ((b) != 0.0f ? (a)/(b) : (a))
|
||||||
|
@ -38,6 +39,27 @@ static uint32_t X2C_LSH(uint32_t a, int32_t length, int32_t n)
|
||||||
return (a >> -n) & m;
|
return (a >> -n) & m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static double atang2(double x, double y)
|
||||||
|
{
|
||||||
|
double w;
|
||||||
|
if (fabs(x)>fabs(y)) {
|
||||||
|
w = (double)atan((float)(X2C_DIVL(y,x)));
|
||||||
|
if (x<0.0) {
|
||||||
|
if (y>0.0) w = 3.1415926535898+w;
|
||||||
|
else w = w-3.1415926535898;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (y!=0.0) {
|
||||||
|
w = (double)(1.5707963267949f-atan((float)(X2C_DIVL(x,
|
||||||
|
y))));
|
||||||
|
if (y<0.0) w = w-3.1415926535898;
|
||||||
|
}
|
||||||
|
else w = 0.0;
|
||||||
|
return w;
|
||||||
|
} /* end atang2() */
|
||||||
|
#endif
|
||||||
|
|
||||||
static void Gencrctab(void)
|
static void Gencrctab(void)
|
||||||
{
|
{
|
||||||
uint16_t j;
|
uint16_t j;
|
||||||
|
@ -68,16 +90,7 @@ static int haveNewFrame = 0;
|
||||||
static int lastFrame = 0;
|
static int lastFrame = 0;
|
||||||
static int headerDetected = 0;
|
static int headerDetected = 0;
|
||||||
|
|
||||||
decoderSetupCfg rs92SetupCfg = {
|
int RS92::setup(float frequency)
|
||||||
.bitrate = 4800,
|
|
||||||
.rx_cfg = 0x1E,
|
|
||||||
.sync_cfg = 0x70,
|
|
||||||
.sync_len = 2,
|
|
||||||
.sync_data = (const uint8_t *)"\x66\x65",
|
|
||||||
.preamble_cfg = 0xA8,
|
|
||||||
};
|
|
||||||
|
|
||||||
int RS92::setup(float frequency, int /*type*/)
|
|
||||||
{
|
{
|
||||||
#if RS92_DEBUG
|
#if RS92_DEBUG
|
||||||
Serial.println("Setup sx1278 for RS92 sonde");
|
Serial.println("Setup sx1278 for RS92 sonde");
|
||||||
|
@ -93,10 +106,6 @@ int RS92::setup(float frequency, int /*type*/)
|
||||||
RS92_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
RS92_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(DecoderBase::setup(rs92SetupCfg, sonde.config.rs92.rxbw, sonde.config.rs92.rxbw)!=0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
if(sx1278.setFSK()!=0) {
|
if(sx1278.setFSK()!=0) {
|
||||||
RS92_DBG(Serial.println("Setting FSJ mode FAILED"));
|
RS92_DBG(Serial.println("Setting FSJ mode FAILED"));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -131,6 +140,7 @@ int RS92::setup(float frequency, int /*type*/)
|
||||||
//const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
//const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
||||||
// was 0x57
|
// was 0x57
|
||||||
//const char *SYNC="\x99\x9A";
|
//const char *SYNC="\x99\x9A";
|
||||||
|
#if 1
|
||||||
// version 1, working with continuous RX
|
// version 1, working with continuous RX
|
||||||
const char *SYNC="\x66\x65";
|
const char *SYNC="\x66\x65";
|
||||||
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
||||||
|
@ -142,7 +152,6 @@ int RS92::setup(float frequency, int /*type*/)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// version 2, with per-packet rx start, untested
|
// version 2, with per-packet rx start, untested
|
||||||
// header is 2a 10 65, i.e. with lsb first
|
// header is 2a 10 65, i.e. with lsb first
|
||||||
|
@ -187,6 +196,19 @@ int RS92::setup(float frequency, int /*type*/)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int RS92::setFrequency(float frequency) {
|
||||||
|
Serial.print("RS92: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
int res = sx1278.setFrequency(frequency);
|
||||||
|
// enable RX
|
||||||
|
sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t RS92::bits2val(const uint8_t *bits, int len) {
|
uint32_t RS92::bits2val(const uint8_t *bits, int len) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
for (int j = 0; j < len; j++) {
|
for (int j = 0; j < len; j++) {
|
||||||
|
@ -426,6 +448,34 @@ void RS92::printRaw(uint8_t *data, int len)
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// I guess this is old copy&paste stuff from RS41??
|
||||||
|
int RS92::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len*4; i++) {
|
||||||
|
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
||||||
|
}
|
||||||
|
bytes[(i-1)/8] &= 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char lookup[16] = {
|
||||||
|
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||||
|
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };
|
||||||
|
|
||||||
|
static uint8_t reverse(uint8_t n) {
|
||||||
|
return (lookup[n&0x0f] << 4) | lookup[n>>4];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t scramble[64] = {150U,131U,62U,81U,177U,73U,8U,152U,50U,5U,89U,
|
||||||
|
14U,249U,68U,198U,38U,33U,96U,194U,234U,121U,93U,109U,161U,
|
||||||
|
84U,105U,71U,12U,220U,232U,92U,241U,247U,118U,130U,127U,7U,
|
||||||
|
153U,162U,44U,147U,124U,48U,99U,245U,16U,46U,97U,208U,188U,
|
||||||
|
180U,182U,6U,170U,244U,35U,120U,110U,59U,174U,191U,123U,76U,
|
||||||
|
193U};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void RS92::stobyte92(uint8_t b)
|
void RS92::stobyte92(uint8_t b)
|
||||||
{
|
{
|
||||||
|
@ -565,7 +615,7 @@ int RS92::waitRXcomplete() {
|
||||||
Serial.printf("decoding frame %d\n", lastFrame);
|
Serial.printf("decoding frame %d\n", lastFrame);
|
||||||
print_frame(lastFrame==1?data1:data2, 240);
|
print_frame(lastFrame==1?data1:data2, 240);
|
||||||
|
|
||||||
SondeData *si = &( (sonde.sondeList+rxtask.receiveSonde)->d );
|
SondeInfo *si = sonde.sondeList+rxtask.receiveSonde;
|
||||||
si->lat = gpx.lat;
|
si->lat = gpx.lat;
|
||||||
si->lon = gpx.lon;
|
si->lon = gpx.lon;
|
||||||
si->alt = gpx.alt;
|
si->alt = gpx.alt;
|
||||||
|
@ -576,14 +626,102 @@ int RS92::waitRXcomplete() {
|
||||||
memcpy(si->id, gpx.id, 9);
|
memcpy(si->id, gpx.id, 9);
|
||||||
memcpy(si->ser, gpx.id, 9);
|
memcpy(si->ser, gpx.id, 9);
|
||||||
si->validID = true;
|
si->validID = true;
|
||||||
si->vframe = si->frame = gpx.frnr;
|
si->frame = gpx.frnr;
|
||||||
si->sats = gpx.k;
|
si->sats = gpx.k;
|
||||||
si->time = (gpx.gpssec/1000) + 86382 + gpx.week*604800 + 315878400UL;
|
si->time = (gpx.gpssec/1000) + 86382 + gpx.week*604800 + 315878400UL;
|
||||||
si->validTime = true;
|
si->validTime = true;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int res=0;
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while( rxtask.receiveResult == 0xFFFF && millis()-t0 < 2000) { delay(20); }
|
||||||
|
|
||||||
|
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||||
|
res = RX_TIMEOUT;
|
||||||
|
} else if ( rxtask.receiveResult==0) {
|
||||||
|
res = RX_OK;
|
||||||
|
} else {
|
||||||
|
res = RX_ERROR;
|
||||||
|
}
|
||||||
|
rxtask.receiveResult = 0xFFFF;
|
||||||
|
Serial.printf("RS92::waitRXcomplete returning %d (%s)\n", res, RXstr[res]);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int oldwaitRXcomplete() {
|
||||||
|
Serial.println("RS92: receive frame...\n");
|
||||||
|
sx1278receiveData = true;
|
||||||
|
delay(6000); // done in other task....
|
||||||
|
//sx1278receiveData = false;
|
||||||
|
#if 0
|
||||||
|
//sx1278.setPayloadLength(518-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header)
|
||||||
|
//sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
|
||||||
|
////// test code for continuous reception
|
||||||
|
// sx1278.receive(); /// active FSK RX mode -- already done above...
|
||||||
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
unsigned long previous = millis();
|
||||||
|
|
||||||
|
byte ready=0;
|
||||||
|
uint32_t wait = 8000;
|
||||||
|
// while not yet done or FIFO not yet empty
|
||||||
|
// bit 6: FIFO Empty
|
||||||
|
// bit 2 payload ready
|
||||||
|
int by=0;
|
||||||
|
while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) )
|
||||||
|
{
|
||||||
|
if( bitRead(value, 7) ) { Serial.println("FIFO full"); }
|
||||||
|
if( bitRead(value, 4) ) { Serial.println("FIFO overflow"); }
|
||||||
|
if( bitRead(value,2)==1 ) ready=1;
|
||||||
|
if( bitRead(value, 6) == 0 ) { // FIFO not empty
|
||||||
|
byte data = sx1278.readRegister(REG_FIFO);
|
||||||
|
process8N1data(data);
|
||||||
|
by++;
|
||||||
|
#if 0
|
||||||
|
if(di==1) {
|
||||||
|
int rssi=getRSSI();
|
||||||
|
int fei=getFEI();
|
||||||
|
int afc=getAFC();
|
||||||
|
Serial.print("Test: RSSI="); Serial.println(rssi);
|
||||||
|
Serial.print("Test: FEI="); Serial.println(fei);
|
||||||
|
Serial.print("Test: AFC="); Serial.println(afc);
|
||||||
|
sonde.si()->rssi = rssi;
|
||||||
|
sonde.si()->afc = afc;
|
||||||
|
}
|
||||||
|
if(di>520) {
|
||||||
|
// TODO
|
||||||
|
Serial.println("TOO MUCH DATA");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previous = millis(); // reset timeout after receiving data
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
}
|
||||||
|
Serial.printf("processed %d bytes before end/timeout\n", by);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////
|
||||||
|
#if 0
|
||||||
|
int e = sx1278.receivePacketTimeout(1000, data+8);
|
||||||
|
if(e) { Serial.println("TIMEOUT"); return RX_TIMEOUT; } //if timeout... return 1
|
||||||
|
|
||||||
|
printRaw(data, RS92MAXLEN);
|
||||||
|
//for(int i=0; i<RS92MAXLEN; i++) { data[i] = reverse(data[i]); }
|
||||||
|
//printRaw(data, MAXLEN);
|
||||||
|
//for(int i=0; i<RS92MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
|
||||||
|
//printRaw(data, MAXLEN);
|
||||||
|
//int res = decode41(data, RS92MAXLEN);
|
||||||
|
#endif
|
||||||
|
int res=0;
|
||||||
|
return res==0 ? RX_OK : RX_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
RS92 rs92 = RS92();
|
RS92 rs92 = RS92();
|
10
RX_FSK/src/RS92.h → libraries/SondeLib/RS92.h
Normal file → Executable file
10
RX_FSK/src/RS92.h → libraries/SondeLib/RS92.h
Normal file → Executable file
|
@ -15,7 +15,6 @@
|
||||||
#ifndef inttypes_h
|
#ifndef inttypes_h
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#endif
|
#endif
|
||||||
#include "DecoderBase.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct CONTEXTR9 {
|
struct CONTEXTR9 {
|
||||||
|
@ -50,12 +49,17 @@ struct CONTEXTR9 {
|
||||||
|
|
||||||
|
|
||||||
/* Main class */
|
/* Main class */
|
||||||
class RS92 : public DecoderBase
|
class RS92
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
void process8N1data(uint8_t data);
|
void process8N1data(uint8_t data);
|
||||||
void stobyte92(uint8_t byte);
|
void stobyte92(uint8_t byte);
|
||||||
void decodeframe92(uint8_t *data);
|
void decodeframe92(uint8_t *data);
|
||||||
|
#if 0
|
||||||
|
void dogps(const uint8_t *sf, int sf_len,
|
||||||
|
struct CONTEXTR9 * cont, uint32_t * timems,
|
||||||
|
uint32_t * gpstime);
|
||||||
|
#endif
|
||||||
uint32_t bits2val(const uint8_t *bits, int len);
|
uint32_t bits2val(const uint8_t *bits, int len);
|
||||||
void printRaw(uint8_t *data, int len);
|
void printRaw(uint8_t *data, int len);
|
||||||
int bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
int bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
||||||
|
@ -80,7 +84,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RS92();
|
RS92();
|
||||||
int setup(float frequency, int type = 0);
|
int setup(float frequency);
|
||||||
int receive();
|
int receive();
|
||||||
int waitRXcomplete();
|
int waitRXcomplete();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user