mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 14:06:31 +01:00
Merge branch 'development'
This commit is contained in:
54
esp32_fw/.vscode/settings.json
vendored
54
esp32_fw/.vscode/settings.json
vendored
@@ -1,3 +1,55 @@
|
||||
{
|
||||
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}"
|
||||
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"regex": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
}
|
||||
}
|
||||
BIN
esp32_fw/data/alignment.bmp
Normal file
BIN
esp32_fw/data/alignment.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
BIN
esp32_fw/data/fonts/calibrib50.vlw
Normal file
BIN
esp32_fw/data/fonts/calibrib50.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/calibrib62.vlw
Normal file
BIN
esp32_fw/data/fonts/calibrib62.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers1-1.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers1-1.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers1-2.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers1-2.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers2-1.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers2-1.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers2-2.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers2-2.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers3-1.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers3-1.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/numbers3-2.vlw
Normal file
BIN
esp32_fw/data/fonts/numbers3-2.vlw
Normal file
Binary file not shown.
@@ -1,66 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
|
||||
<title>Solum - alternative proto AP</title>
|
||||
<link rel="stylesheet" href="main.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="logo">Solum - alternative proto AP</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="blocks"><ul></ul></div>
|
||||
|
||||
|
||||
<div class="window">
|
||||
|
||||
|
||||
<iframe name="empty" style="border:1px solid darkgrey; width:100%; height:4em;"></iframe>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="send_image" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
Filename:<input name="filename" type="text" placeholder="default.bmp">
|
||||
Next check-in:<input name="ttl" type="text" placeholder="1"> min
|
||||
<input type="submit" value="Send Image">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="send_fw" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
Filename:<input name="filename" type="text" placeholder="update.bin">
|
||||
<input type="submit" value="Send FW Update">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="req_checkin" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
<input type="submit" value="Request Check-in">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="messages">
|
||||
<ul class="messages">
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="jquery.js"></script>
|
||||
<script src="main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
6
esp32_fw/data/jquery.js
vendored
6
esp32_fw/data/jquery.js
vendored
File diff suppressed because one or more lines are too long
BIN
esp32_fw/data/kat-bw29.jpg
Normal file
BIN
esp32_fw/data/kat-bw29.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -1,203 +0,0 @@
|
||||
*{
|
||||
margin:0;
|
||||
padding:0;
|
||||
border:0;
|
||||
list-style-type: none;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
font-weight: 400;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-smooth: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
font-size: 12px;
|
||||
font-family: Helvetica, Arial, Verdana, sans-serif;
|
||||
line-height: 1.5;
|
||||
background-color: #e8f1f9;
|
||||
background-color: #f1f1f1;
|
||||
/*background-image: linear-gradient(315deg, #dde1ee 0%, #e8f1f9 100%);*/
|
||||
}
|
||||
|
||||
header {
|
||||
height: 50px;
|
||||
background-color: #666;
|
||||
|
||||
}
|
||||
.logo {
|
||||
margin: 0 auto;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
text-indent: 100px;
|
||||
overflow:hidden;
|
||||
background: url('p2000.svg') center center no-repeat;
|
||||
background-size: 50px 50px;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
||||
}
|
||||
|
||||
.blocks {
|
||||
padding: 21px 0;
|
||||
overflow-x: auto;
|
||||
text-align:center;
|
||||
}
|
||||
.blocks ul {
|
||||
display:table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.blocks ul li {
|
||||
display:table-cell;
|
||||
vertical-align:top;
|
||||
padding: 0 4px;
|
||||
position: relative;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:before, .blocks ul li:nth-child(6) div.b:after {
|
||||
content:"";
|
||||
position:absolute;
|
||||
margin-left: -5px;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:before {
|
||||
top: -5px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid #c30;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:after {
|
||||
bottom: -5px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 5px solid #c30;
|
||||
}
|
||||
.blocks ul li, .blocks ul li div {
|
||||
|
||||
}
|
||||
.blocks ul li div {
|
||||
width: 80px;
|
||||
padding: 0 4px;
|
||||
|
||||
}
|
||||
.blocks ul li div.b {
|
||||
position:relative;
|
||||
padding: 6px 0;
|
||||
background: #fff;
|
||||
}
|
||||
.blocks ul li div.rxt {
|
||||
background-color: #e5f9ea;
|
||||
}
|
||||
.blocks ul li div.txt {
|
||||
background-color: #f9eae5;
|
||||
}
|
||||
.blocks ul li div.b {
|
||||
|
||||
}
|
||||
.window {
|
||||
margin: 0 auto;
|
||||
max-width: 94%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.actionbox .dst {
|
||||
size:12em;
|
||||
}
|
||||
|
||||
|
||||
.actionbox input {
|
||||
border: solid 1px black;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
input.actionbox {
|
||||
border: solid 1px black;
|
||||
}
|
||||
|
||||
ul.messages {
|
||||
padding: 12px 0;
|
||||
}
|
||||
ul.messages li {
|
||||
line-height: 22px;
|
||||
position: relative;
|
||||
padding: 0 12px;
|
||||
}
|
||||
ul.messages li.new {
|
||||
-webkit-animation-name: new;
|
||||
-webkit-animation-duration: 1400ms;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
-webkit-animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
ul.messages li div.message {
|
||||
padding-left: 58px;
|
||||
}
|
||||
ul.messages li div.date {
|
||||
position: absolute;
|
||||
left: 12px
|
||||
}
|
||||
span.pending {
|
||||
padding-left: 28px;
|
||||
}
|
||||
span.pending:before {
|
||||
content:"";
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
top: 0;
|
||||
left: 12px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background: url('roll.svg') center center no-repeat;
|
||||
background-size: 22px 22px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@media(max-width: 460px) {
|
||||
.messages li div, ul.messages li div.date, ul.messages li div.message {
|
||||
display:block;
|
||||
position:relative;
|
||||
padding: 0;
|
||||
left: auto;
|
||||
}
|
||||
.messages li div.message, li.pending {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
ul.messages {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@-webkit-keyframes new {
|
||||
0% {
|
||||
background-color: rgba(255, 255, 204, 1);
|
||||
}
|
||||
50% {
|
||||
background-color: rgba(255, 255, 204, .5);
|
||||
}
|
||||
100% {
|
||||
background-color: rgba(255, 255, 204, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
$.fn.htmlTo = function(elem) {
|
||||
return this.each(function() {
|
||||
$(elem).html($(this).html());
|
||||
});
|
||||
}
|
||||
|
||||
let socket = new WebSocket("ws://" + location.host + "/ws");
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
let incomingMessage = event.data;
|
||||
showMessage(incomingMessage);
|
||||
};
|
||||
|
||||
socket.onclose = event => console.log(`Closed ${event.code}`);
|
||||
|
||||
function showMessage(message) {
|
||||
$( "<li/>", {
|
||||
"class": "new",
|
||||
html: message
|
||||
}).prependTo( "ul.messages" );
|
||||
}
|
||||
|
||||
|
||||
777
esp32_fw/data/www/edit.html
Normal file
777
esp32_fw/data/www/edit.html
Normal file
@@ -0,0 +1,777 @@
|
||||
<!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>ESP Editor</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<style type="text/css" media="screen">
|
||||
.cm {
|
||||
z-index: 300;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
border: 1px solid #444;
|
||||
background-color: #F5F5F5;
|
||||
display: none;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, .4);
|
||||
font-size: 12px;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm ul {
|
||||
list-style: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cm li {
|
||||
position: relative;
|
||||
min-width: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cm span {
|
||||
color: #444;
|
||||
display: inline-block;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.cm li:hover {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.cm li:hover span {
|
||||
color: #EEE;
|
||||
}
|
||||
|
||||
.tvu ul,
|
||||
.tvu li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tvu li {
|
||||
display: flex;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.tvu input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tvu {
|
||||
font: normal 12px Verdana, Arial, Sans-serif;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
color: #444;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.tvu .icon {
|
||||
padding: 0 0 0 5px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.tvu .filename {
|
||||
padding: 2px 0 0 2px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
flex: 2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tvu .size {
|
||||
padding: 2px 5px 0 5px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.tvu li:hover {
|
||||
background-color:#cccccc;
|
||||
}
|
||||
|
||||
#uploader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: #444;
|
||||
color: #EEE;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #eeeeee;
|
||||
border: 0px;
|
||||
cursor: pointer;
|
||||
padding: 3px 5px;
|
||||
margin: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #ffffff;
|
||||
border: 0px;
|
||||
appearance: none;
|
||||
padding: 2px 5px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.uploadpath {
|
||||
background: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#tree {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#editor,
|
||||
#preview {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 300px;
|
||||
border-left: 1px solid #EEE;
|
||||
}
|
||||
|
||||
#preview {
|
||||
background-color: #EEE;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#loader {
|
||||
position: absolute;
|
||||
top: 36%;
|
||||
right: 40%;
|
||||
}
|
||||
|
||||
.loader {
|
||||
z-index: 10000;
|
||||
border: 8px solid #b5b5b5;
|
||||
/* Grey */
|
||||
border-top: 8px solid #3498db;
|
||||
/* Blue */
|
||||
border-bottom: 8px solid #3498db;
|
||||
/* Blue */
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 2s linear infinite;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
if (typeof XMLHttpRequest === "undefined") {
|
||||
XMLHttpRequest = function () {
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) { }
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) { }
|
||||
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
|
||||
throw new Error("This browser does not support XMLHttpRequest.");
|
||||
};
|
||||
}
|
||||
|
||||
function ge(a) {
|
||||
return document.getElementById(a);
|
||||
}
|
||||
function ce(a) {
|
||||
return document.createElement(a);
|
||||
}
|
||||
|
||||
function sortByKey(array, key) {
|
||||
return array.sort(function (a, b) {
|
||||
var x = a[key]; var y = b[key];
|
||||
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var QueuedRequester = function () {
|
||||
this.queue = [];
|
||||
this.running = false;
|
||||
this.xmlhttp = null;
|
||||
}
|
||||
QueuedRequester.prototype = {
|
||||
_request: function (req) {
|
||||
this.running = true;
|
||||
if (!req instanceof Object) return;
|
||||
var that = this;
|
||||
|
||||
function ajaxCb(x, d) {
|
||||
return function () {
|
||||
if (x.readyState == 4) {
|
||||
ge("loader").style.display = "none";
|
||||
d.callback(x.status, x.responseText);
|
||||
if (that.queue.length === 0) that.running = false;
|
||||
if (that.running) that._request(that.queue.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ge("loader").style.display = "block";
|
||||
|
||||
var p = "";
|
||||
if (req.params instanceof FormData) {
|
||||
p = req.params;
|
||||
} else if (req.params instanceof Object) {
|
||||
for (var key in req.params) {
|
||||
if (p === "")
|
||||
p += (req.method === "GET") ? "?" : "";
|
||||
else
|
||||
p += "&";
|
||||
p += encodeURIComponent(key) + "=" + encodeURIComponent(req.params[key]);
|
||||
};
|
||||
}
|
||||
|
||||
this.xmlhttp = new XMLHttpRequest();
|
||||
this.xmlhttp.onreadystatechange = ajaxCb(this.xmlhttp, req);
|
||||
if (req.method === "GET") {
|
||||
this.xmlhttp.open(req.method, req.url + p, true);
|
||||
this.xmlhttp.send();
|
||||
} else {
|
||||
this.xmlhttp.open(req.method, req.url, true);
|
||||
if (p instanceof String)
|
||||
this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
this.xmlhttp.send(p);
|
||||
}
|
||||
},
|
||||
stop: function () {
|
||||
if (this.running) this.running = false;
|
||||
if (this.xmlhttp && this.xmlhttp.readyState < 4) {
|
||||
this.xmlhttp.abort();
|
||||
}
|
||||
},
|
||||
add: function (method, url, params, callback) {
|
||||
this.queue.push({ url: url, method: method, params: params, callback: callback });
|
||||
if (!this.running) {
|
||||
this._request(this.queue.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var requests = new QueuedRequester();
|
||||
|
||||
function createFileUploader(element, tree, editor) {
|
||||
var xmlHttp;
|
||||
|
||||
var refresh = ce("button");
|
||||
refresh.innerHTML = 'Refresh List';
|
||||
ge(element).appendChild(refresh);
|
||||
|
||||
var path = ce("input");
|
||||
path.id = "upload-path";
|
||||
path.type = "text";
|
||||
path.name = "path";
|
||||
path.classList.add("uploadpath");
|
||||
path.defaultValue = "/";
|
||||
ge(element).appendChild(path);
|
||||
|
||||
var input = ce("input");
|
||||
input.type = "file";
|
||||
input.multiple = false;
|
||||
input.name = "data";
|
||||
input.id = "upload-select";
|
||||
ge(element).appendChild(input);
|
||||
|
||||
/*
|
||||
var mkfile = ce("button");
|
||||
mkfile.innerHTML = 'Create';
|
||||
ge(element).appendChild(mkfile);
|
||||
*/
|
||||
|
||||
var filename = ce("input");
|
||||
filename.id = "editor-filename";
|
||||
filename.type = "text";
|
||||
|
||||
filename.size = 20;
|
||||
ge(element).appendChild(filename);
|
||||
|
||||
var button = ce("button");
|
||||
button.id = "button";
|
||||
button.innerHTML = 'Upload';
|
||||
button.style.display = 'none';
|
||||
ge(element).appendChild(button);
|
||||
|
||||
var savefile = ce("button");
|
||||
savefile.id = "savefile";
|
||||
savefile.innerHTML = ' Save ';
|
||||
savefile.style.display = 'none';
|
||||
ge(element).appendChild(savefile);
|
||||
|
||||
function httpPostProcessRequest(status, responseText) {
|
||||
if (status != 200)
|
||||
alert("ERROR[" + status + "]: " + responseText);
|
||||
else
|
||||
tree.refreshPath(path.value);
|
||||
}
|
||||
function createPath(p) {
|
||||
var formData = new FormData();
|
||||
formData.append("path", p);
|
||||
requests.add("PUT", "/edit", formData, httpPostProcessRequest);
|
||||
}
|
||||
|
||||
/*
|
||||
mkfile.onclick = function (e) {
|
||||
createPath(filename.value);
|
||||
editor.loadUrl(filename.value);
|
||||
path.value = (filename.value);
|
||||
};
|
||||
*/
|
||||
|
||||
savefile.onclick = function (e) {
|
||||
editor.execCommand('saveCommand');
|
||||
};
|
||||
|
||||
refresh.onclick = function (e) {
|
||||
tree.refreshPath(path.value);
|
||||
};
|
||||
|
||||
button.onclick = function (e) {
|
||||
if (input.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append("data", input.files[0], ge("editor-filename").value);
|
||||
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||
var uploadSelect = ge("upload-select");
|
||||
uploadSelect.value = "";
|
||||
};
|
||||
input.onchange = function (e) {
|
||||
if (input.files.length === 0) return;
|
||||
var filename = input.files[0].name;
|
||||
ge("editor-filename").value = path.value + (path.value=="/" ? "" : "/") + filename;
|
||||
button.style.display = 'inline-block';
|
||||
savefile.style.display = 'none';
|
||||
};
|
||||
}
|
||||
|
||||
function createTree(element, editor) {
|
||||
var preview = ge("preview");
|
||||
var treeRoot = ce("div");
|
||||
treeRoot.className = "tvu";
|
||||
ge(element).appendChild(treeRoot);
|
||||
|
||||
function loadDownload(path) {
|
||||
ge('download-frame').src = "/edit?download=" + path;
|
||||
}
|
||||
|
||||
function loadPreview(path) {
|
||||
ge("button").style.display = 'none';
|
||||
ge("savefile").style.display = 'none';
|
||||
|
||||
var edfname = ge("editor-filename");
|
||||
|
||||
var filename = path;
|
||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||
var name = /(.*)\.[^.]+$/.exec(filename)[1];
|
||||
if (typeof name !== undefined) {
|
||||
filename = name;
|
||||
}
|
||||
|
||||
edfname.value = filename + "." + ext;
|
||||
ge("editor").style.display = "none";
|
||||
preview.style.display = "block";
|
||||
preview.innerHTML = '<img src="/edit?edit=' + path + '&_cb=' + Date.now() + '" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
|
||||
}
|
||||
|
||||
function fillFileMenu(el, path) {
|
||||
var list = ce("ul");
|
||||
el.appendChild(list);
|
||||
var action = ce("li");
|
||||
list.appendChild(action);
|
||||
if (isImageFile(path)) {
|
||||
action.innerHTML = "<span>Preview</span>";
|
||||
action.onclick = function (e) {
|
||||
loadPreview(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
} else if (isTextFile(path)) {
|
||||
action.innerHTML = "<span>Edit</span>";
|
||||
action.onclick = function (e) {
|
||||
editor.loadUrl(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
}
|
||||
var download = ce("li");
|
||||
list.appendChild(download);
|
||||
download.innerHTML = "<span>Download</span>";
|
||||
download.onclick = function (e) {
|
||||
loadDownload(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
var delFile = ce("li");
|
||||
list.appendChild(delFile);
|
||||
delFile.innerHTML = "<span>Delete</span>";
|
||||
delFile.onclick = function (e) {
|
||||
httpDelete(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
}
|
||||
|
||||
function showContextMenu(event, path, isfile) {
|
||||
var divContext = ce("div");
|
||||
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
|
||||
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
|
||||
var left = event.clientX + scrollLeft;
|
||||
var top = event.clientY + scrollTop;
|
||||
divContext.className = 'cm';
|
||||
divContext.style.display = 'block';
|
||||
divContext.style.left = left + 'px';
|
||||
divContext.style.top = top + 'px';
|
||||
fillFileMenu(divContext, path);
|
||||
document.body.appendChild(divContext);
|
||||
var width = divContext.offsetWidth;
|
||||
var height = divContext.offsetHeight;
|
||||
divContext.onmouseout = function (e) {
|
||||
if (e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)) {
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(divContext);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createTreeLeaf(path, name, size) {
|
||||
var leaf = ce("li");
|
||||
leaf.id = path + (path != "/" ? "/":"") + name;
|
||||
|
||||
var icon = ce("span");
|
||||
icon.innerHTML = "📄";
|
||||
icon.classList.add("icon");
|
||||
leaf.appendChild(icon);
|
||||
|
||||
var label = ce("span");
|
||||
label.innerHTML = name;
|
||||
label.classList.add("filename");
|
||||
leaf.appendChild(label);
|
||||
|
||||
var filesize = ce("span");
|
||||
filesize.innerHTML = formatBytes(size);
|
||||
filesize.classList.add("size");
|
||||
leaf.appendChild(filesize);
|
||||
|
||||
leaf.onclick = function (e) {
|
||||
if (isTextFile(leaf.id.toLowerCase())) {
|
||||
editor.loadUrl(leaf.id);
|
||||
} else if (isImageFile(leaf.id.toLowerCase())) {
|
||||
loadPreview(leaf.id);
|
||||
}
|
||||
};
|
||||
leaf.oncontextmenu = function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showContextMenu(e, leaf.id, true);
|
||||
};
|
||||
return leaf;
|
||||
}
|
||||
|
||||
function createDirLeaf(path, name, size) {
|
||||
var leaf = ce("li");
|
||||
leaf.id = path + (path != "/" ? "/" : "") + name;
|
||||
|
||||
var icon = ce("span");
|
||||
icon.innerHTML = "📁";
|
||||
icon.classList.add("icon");
|
||||
leaf.appendChild(icon);
|
||||
|
||||
var label = ce("span");
|
||||
label.innerHTML = name;
|
||||
label.classList.add("filename");
|
||||
leaf.appendChild(label);
|
||||
|
||||
var filesize = ce("span");
|
||||
filesize.innerHTML = "";
|
||||
filesize.classList.add("size");
|
||||
leaf.appendChild(filesize);
|
||||
|
||||
leaf.onclick = function (e) {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
if (name == "..") {
|
||||
httpGet(treeRoot, "/");
|
||||
} else {
|
||||
httpGet(treeRoot, "/" + name);
|
||||
}
|
||||
};
|
||||
leaf.oncontextmenu = function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showContextMenu(e, leaf.id, true);
|
||||
};
|
||||
return leaf;
|
||||
}
|
||||
|
||||
function formatBytes(bytes, decimalPlaces = 2) {
|
||||
if (bytes === 0) return '';
|
||||
const k = 1024;
|
||||
const dm = decimalPlaces < 0 ? 0 : decimalPlaces;
|
||||
const sizes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function addList(parent, path, items) {
|
||||
ge("upload-path").value = path
|
||||
ge("editor-filename").value = path
|
||||
sortByKey(items, 'name');
|
||||
var list = ce("ul");
|
||||
parent.appendChild(list);
|
||||
if (path != "/") {
|
||||
list.appendChild(createDirLeaf("/", "..", 0));
|
||||
}
|
||||
var ll = items.length;
|
||||
for (var i = 0; i < ll; i++) {
|
||||
if (items[i].type === "file") {
|
||||
list.appendChild(createTreeLeaf(path, items[i].name, items[i].size));
|
||||
}
|
||||
if (items[i].type === "dir") {
|
||||
list.insertBefore(createDirLeaf(path, items[i].name, items[i].size), list.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isTextFile(path) {
|
||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "txt":
|
||||
case "htm":
|
||||
case "html":
|
||||
case "js":
|
||||
case "css":
|
||||
case "xml":
|
||||
case "json":
|
||||
case "conf":
|
||||
case "ini":
|
||||
case "h":
|
||||
case "c":
|
||||
case "cpp":
|
||||
case "php":
|
||||
case "hex":
|
||||
case "ino":
|
||||
case "pde":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isImageFile(path) {
|
||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "png":
|
||||
case "jpg":
|
||||
case "gif":
|
||||
case "bmp":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.refreshPath = function (path) {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
httpGet(treeRoot, path);
|
||||
};
|
||||
|
||||
function delCb(path) {
|
||||
return function (status, responseText) {
|
||||
if (status != 200) {
|
||||
alert("ERROR[" + status + "]: " + responseText);
|
||||
} else {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
httpGet(treeRoot, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function httpDelete(filename) {
|
||||
var formData = new FormData();
|
||||
formData.append("path", filename);
|
||||
requests.add("DELETE", "/edit", formData, delCb(filename));
|
||||
}
|
||||
|
||||
function getCb(parent, path) {
|
||||
return function (status, responseText) {
|
||||
if (status == 200)
|
||||
addList(parent, path, JSON.parse(responseText));
|
||||
}
|
||||
}
|
||||
|
||||
function httpGet(parent, path) {
|
||||
requests.add("GET", "/edit", { list: path }, getCb(parent, path));
|
||||
}
|
||||
|
||||
httpGet(treeRoot, "/");
|
||||
return this;
|
||||
}
|
||||
|
||||
function createEditor(element, file, lang, theme, type) {
|
||||
function getLangFromFilename(filename) {
|
||||
var lang = "plain";
|
||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "txt": lang = "plain"; break;
|
||||
case "hex": lang = "plain"; break;
|
||||
case "conf": lang = "plain"; break;
|
||||
case "htm": lang = "html"; break;
|
||||
case "js": lang = "javascript"; break;
|
||||
case "h": lang = "c_cpp"; break;
|
||||
case "c": lang = "c_cpp"; break;
|
||||
case "cpp": lang = "c_cpp"; break;
|
||||
case "css":
|
||||
case "scss":
|
||||
case "php":
|
||||
case "html":
|
||||
case "json":
|
||||
case "xml":
|
||||
case "ini": lang = ext;
|
||||
}
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
if (typeof file === "undefined") file = "/index.html";
|
||||
|
||||
if (typeof lang === "undefined") {
|
||||
lang = getLangFromFilename(file);
|
||||
}
|
||||
|
||||
if (typeof theme === "undefined") theme = "textmate";
|
||||
|
||||
if (typeof type === "undefined") {
|
||||
type = "text/" + lang;
|
||||
if (lang === "c_cpp") type = "text/plain";
|
||||
}
|
||||
|
||||
var editor = ace.edit(element);
|
||||
function httpPostProcessRequest(status, responseText) {
|
||||
if (status != 200) alert("ERROR[" + status + "]: " + responseText);
|
||||
}
|
||||
function httpPost(filename, data, type) {
|
||||
var formData = new FormData();
|
||||
formData.append("data", new Blob([data], { type: type }), filename);
|
||||
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||
}
|
||||
function httpGetProcessRequest(status, responseText) {
|
||||
ge("preview").style.display = "none";
|
||||
ge("editor").style.display = "block";
|
||||
if (status == 200)
|
||||
editor.setValue(responseText);
|
||||
else
|
||||
editor.setValue("");
|
||||
editor.clearSelection();
|
||||
}
|
||||
function httpGet(theUrl) {
|
||||
requests.add("GET", "/edit", { edit: theUrl }, httpGetProcessRequest);
|
||||
}
|
||||
|
||||
if (lang !== "plain") editor.getSession().setMode("ace/mode/" + lang);
|
||||
editor.setTheme("ace/theme/" + theme);
|
||||
editor.$blockScrolling = Infinity;
|
||||
editor.getSession().setUseSoftTabs(true);
|
||||
editor.getSession().setTabSize(2);
|
||||
editor.setHighlightActiveLine(true);
|
||||
editor.setShowPrintMargin(false);
|
||||
editor.commands.addCommand({
|
||||
name: 'saveCommand',
|
||||
bindKey: { win: 'Ctrl-S', mac: 'Command-S' },
|
||||
exec: function (editor) {
|
||||
httpPost(file, editor.getValue() + "", type);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.commands.addCommand({
|
||||
name: 'undoCommand',
|
||||
bindKey: { win: 'Ctrl-Z', mac: 'Command-Z' },
|
||||
exec: function (editor) {
|
||||
editor.getSession().getUndoManager().undo(false);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.commands.addCommand({
|
||||
name: 'redoCommand',
|
||||
bindKey: { win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z' },
|
||||
exec: function (editor) {
|
||||
editor.getSession().getUndoManager().redo(false);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.loadUrl = function (filename) {
|
||||
ge("button").style.display = 'none';
|
||||
ge("savefile").style.display = 'inline-block';
|
||||
var edfname = ge("editor-filename");
|
||||
edfname.value = filename;
|
||||
file = filename;
|
||||
lang = getLangFromFilename(file);
|
||||
type = "text/" + lang;
|
||||
if (lang !== "plain") editor.getSession().setMode("ace/mode/" + lang);
|
||||
httpGet(file);
|
||||
};
|
||||
return editor;
|
||||
}
|
||||
function onBodyLoad() {
|
||||
var vars = {};
|
||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { vars[key] = value; });
|
||||
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
|
||||
var tree = createTree("tree", editor);
|
||||
createFileUploader("uploader", tree, editor);
|
||||
if (typeof vars.file === "undefined") vars.file = "/index.htm";
|
||||
editor.loadUrl(vars.file);
|
||||
};
|
||||
</script>
|
||||
<script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script>
|
||||
if (typeof ace.edit == "undefined") {
|
||||
var script = document.createElement('script');
|
||||
script.src = "/ace.js";
|
||||
script.async = false;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="onBodyLoad();">
|
||||
<div id="loader" class="loader"></div>
|
||||
<div id="uploader"></div>
|
||||
<div id="tree"></div>
|
||||
<div id="editor"></div>
|
||||
<div id="preview" style="display:none;"></div>
|
||||
<iframe id=download-frame style='display:none;'></iframe>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
105
esp32_fw/data/www/index.html
Normal file
105
esp32_fw/data/www/index.html
Normal file
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
|
||||
<title>Solum - alternative proto AP</title>
|
||||
<link rel="stylesheet" href="main.css" type="text/css" />
|
||||
<link rel="icon" href="data:,">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<div class="logo">Solum - alternative proto AP</div>
|
||||
</header>
|
||||
|
||||
<div id="configbox">
|
||||
<div class="closebtn">✖</div>
|
||||
<h3 id="cfgmac">00000000</h3>
|
||||
<p>
|
||||
<label for="cfgalias">Alias</label>
|
||||
<input id="cfgalias" type="text">
|
||||
</p>
|
||||
<p>
|
||||
<label for="cfgmodel">Model</label>
|
||||
<select id="cfgmodel">
|
||||
<option value="0">unknown</option>
|
||||
<option value="1">1.54" 152x152px</option>
|
||||
<option value="2">2.9" 296x128px</option>
|
||||
<option value="3">4.2" 400x300px</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="cfgcontent">Content</label>
|
||||
<select id="cfgcontent" onchange="contentselected()">
|
||||
<option value="0">static image</option>
|
||||
<option value="1">current date</option>
|
||||
<option value="2">count days</option>
|
||||
<option value="3">count hours</option>
|
||||
<option value="4" disabled>current weather</option>
|
||||
<option value="6" disabled>memo text</option>
|
||||
<option value="7">image url</option>
|
||||
<option value="5">firmware update</option>
|
||||
</select>
|
||||
</p>
|
||||
<div id="customoptions"></div>
|
||||
<p>
|
||||
<input type="button" value="Save" id="cfgsave">
|
||||
<span id="cfgdelete"><img src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form>
|
||||
<div class="container">
|
||||
|
||||
<div class="window">
|
||||
|
||||
<div class="actionbox">
|
||||
<div>
|
||||
<div class="editbtn"><a href="/edit" target="littlefs" class="filebutton">edit littleFS</a></div>
|
||||
Currently active tags:<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="taglist" class="taglist">
|
||||
<div class="tagcard" id="tagtemplate">
|
||||
<div class="currimg"><img class="tagimg" src=""></div>
|
||||
<div class="mac"></div>
|
||||
<div class="alias"></div>
|
||||
<div class="model"></div>
|
||||
<div class="contentmode"></div>
|
||||
<div class="pending"></div>
|
||||
<div class="lastseen"></div>
|
||||
<div class="nextcheckin"></div>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<div class="warningicon">⚠</div>
|
||||
<div class="configicon"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="logbox">
|
||||
<p>
|
||||
<span>logging</span>
|
||||
<span><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></span>
|
||||
<span id="sysinfo"></span>
|
||||
</p>
|
||||
<ul id="messages" class="messages">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="main.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
277
esp32_fw/data/www/main.css
Normal file
277
esp32_fw/data/www/main.css
Normal file
@@ -0,0 +1,277 @@
|
||||
*{
|
||||
margin:0;
|
||||
padding:0;
|
||||
border:0;
|
||||
list-style-type: none;
|
||||
outline: none;
|
||||
font-weight: 400;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-smooth: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12px;
|
||||
font-family: Helvetica, Arial, Verdana, sans-serif;
|
||||
line-height: 1.5;
|
||||
background-color: #e8f1f9;
|
||||
background-color: #f1f1f1;
|
||||
/*background-image: linear-gradient(315deg, #dde1ee 0%, #e8f1f9 100%);*/
|
||||
}
|
||||
|
||||
header {
|
||||
height: 50px;
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
label {
|
||||
width:100px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 auto;
|
||||
height: 50px;
|
||||
text-indent: 50px;
|
||||
overflow:hidden;
|
||||
background-size: 50px 50px;
|
||||
font-size: 2.5em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.window {
|
||||
margin: 0 auto;
|
||||
max-width: 94%;
|
||||
}
|
||||
|
||||
.actionbox>div:first-child {
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.actionbox p {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.actionbox .columns {
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filebutton {
|
||||
padding:2px 5px;
|
||||
background-color: #cccccc;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.editbtn {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.columns div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
input {
|
||||
border: solid 1px #666666;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
border: 0px;
|
||||
padding: 4px 10px;
|
||||
cursor:pointer;
|
||||
}
|
||||
input[type=button]:hover {
|
||||
background-color:#aaaaaa;
|
||||
}
|
||||
select {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#configbox {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
left: 50px;
|
||||
width: 500px;
|
||||
padding: 15px;
|
||||
background-color: #f0e6d3;
|
||||
z-index: 999;
|
||||
box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63);
|
||||
}
|
||||
|
||||
#configbox p {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#configbox h3 {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#configbox input {
|
||||
border: solid 1px #666666;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#configbox label {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
#cfgdelete {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.closebtn {
|
||||
border: 1px solid black;
|
||||
float: right;
|
||||
width: 19px;
|
||||
height: 20px;
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logbox {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.logbox p {
|
||||
background-color: #ffffff;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.logbox img {
|
||||
vertical-align: bottom;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.logbox #sysinfo {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.taglist {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#tagtemplate {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.tagcard {
|
||||
width: 225px;
|
||||
position: relative;
|
||||
height: 170px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
.tagcard .pending {
|
||||
padding-bottom:15px;
|
||||
}
|
||||
|
||||
.currimg {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.currimg img {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.mac {
|
||||
font-size: 0.9em;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.alias {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.corner {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.configicon {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor:pointer;
|
||||
background-image: url("data: image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAABXklEQVQoz43SP2tUQRQF8N99ecFKFEVh0Y1ZbFQ2xEoIQkoLW0t7C/OVLGzyHay1EAQjRFGrLMkjKSwWsRGV3WvxZvc9XQtnivl35sydc048nfuvVkW0k8XYtT936pVja5jJv/Z7wPZo0wNzLzQSHWnVwTZtqY1su2to3bZhj7dewEYeu+iDawi7bhn7Yl9TWGsikrzksnNxr9zfsIErcaEAMysyZXrvE5mp6w7zc8rMzFJjGNlxFWHmWKMVd2DHsHuadQ+NkcKxZ2pPXC8FHHhu1v91X6ZcUZHYy8xwwyju5wAzJypDFdHka5OiaN1yHDl100BaMyq84cwrs1JjtTBu7E5xIpeebLndOZOlnK859d1bZ0JoHPiRU986ZxYZmdjP8/HRrkfSS2+MTTXlycyawhlHJBOH5k789A6x/H/sZQuMKKNatjGLvkoreUy/lsnsq1mXJOe/Ut6tM38DZpmDFxwTi8EAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.warningicon {
|
||||
display:none;
|
||||
font-size: 1.3em;
|
||||
background-color: yellow;
|
||||
color: black;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.messages {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
ul.messages li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.messages li.new {
|
||||
animation-name: new;
|
||||
animation-duration: 1400ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
@media(max-width: 460px) {
|
||||
.messages li div, ul.messages li div.date, ul.messages li div.message {
|
||||
display:block;
|
||||
position:relative;
|
||||
padding: 0;
|
||||
left: auto;
|
||||
}
|
||||
.messages li div.message, li.pending {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
ul.messages {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes new {
|
||||
0% {
|
||||
background-color: rgba(255, 255, 204, 1);
|
||||
}
|
||||
50% {
|
||||
background-color: rgba(255, 255, 204, .5);
|
||||
}
|
||||
100% {
|
||||
background-color: rgba(255, 255, 204, 0);
|
||||
}
|
||||
}
|
||||
280
esp32_fw/data/www/main.js
Normal file
280
esp32_fw/data/www/main.js
Normal file
@@ -0,0 +1,280 @@
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
const contentModes = ["static image", "current date", "counting days", "counting hours", "current weather", "firmware update", "memo text", "image url"];
|
||||
const models = ["unknown type", "1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
|
||||
const contentModeOptions = [];
|
||||
contentModeOptions[0] = ["filename","timetolive"];
|
||||
contentModeOptions[1] = [];
|
||||
contentModeOptions[2] = ["counter", "thresholdred"];
|
||||
contentModeOptions[3] = ["counter", "thresholdred"];
|
||||
contentModeOptions[4] = ["location"];
|
||||
contentModeOptions[5] = ["filename"];
|
||||
contentModeOptions[6] = ["text"];
|
||||
contentModeOptions[7] = ["url","interval"];
|
||||
|
||||
const imageQueue = [];
|
||||
let isProcessing = false;
|
||||
let servertimediff = 0;
|
||||
|
||||
let socket;
|
||||
connect();
|
||||
setInterval(updatecards, 1000);
|
||||
window.addEventListener("load", function () { loadTags(0) });
|
||||
|
||||
function loadTags(pos) {
|
||||
fetch("/get_db?pos="+pos)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
processTags(data.tags);
|
||||
if (data.continu && data.continu>pos) loadTags(data.continu);
|
||||
})
|
||||
//.catch(error => showMessage('loadTags error: ' + error));
|
||||
}
|
||||
|
||||
function connect() {
|
||||
socket = new WebSocket("ws://" + location.host + "/ws");
|
||||
|
||||
socket.addEventListener("open", (event) => {
|
||||
showMessage("websocket connected");
|
||||
});
|
||||
|
||||
socket.addEventListener("message", (event) => {
|
||||
console.log(event.data);
|
||||
const msg = JSON.parse(event.data);
|
||||
if (msg.logMsg) {
|
||||
showMessage(msg.logMsg,false);
|
||||
}
|
||||
if (msg.errMsg) {
|
||||
showMessage(msg.logMsg,true);
|
||||
}
|
||||
if (msg.tags) {
|
||||
processTags(msg.tags);
|
||||
}
|
||||
if (msg.sys) {
|
||||
$('#sysinfo').innerHTML = 'free heap: ' + msg.sys.heap + ' bytes ┇ db size: ' + msg.sys.dbsize + ' bytes ┇ db record count: ' + msg.sys.recordcount + ' ┇ littlefs free: ' + msg.sys.littlefsfree + ' bytes';
|
||||
servertimediff = (Date.now() / 1000) - msg.sys.currtime;
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener("close", (event) => {
|
||||
showMessage(`websocket closed ${event.code}`);
|
||||
setTimeout(connect, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
function processTags(tagArray) {
|
||||
for (const element of tagArray) {
|
||||
tagmac = element.mac;
|
||||
|
||||
var div = $('#tag' + tagmac);
|
||||
if (div == null) {
|
||||
|
||||
div = $('#tagtemplate').cloneNode(true);
|
||||
div.setAttribute('id', 'tag'+tagmac);
|
||||
div.dataset.mac = tagmac;
|
||||
$('#taglist').appendChild(div);
|
||||
|
||||
$('#tag' + tagmac + ' .mac').innerHTML = tagmac;
|
||||
var img = $('#tag' + tagmac + ' .tagimg');
|
||||
img.addEventListener('error', function handleError() {
|
||||
img.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
div.style.display = 'block';
|
||||
|
||||
let alias = element.alias;
|
||||
if (!alias) alias = tagmac;
|
||||
$('#tag' + tagmac + ' .alias').innerHTML = alias;
|
||||
|
||||
if (div.dataset.hash != element.hash) loadImage(tagmac, '/current/' + tagmac + '.bmp?' + (new Date()).getTime());
|
||||
|
||||
$('#tag' + tagmac + ' .contentmode').innerHTML = contentModes[element.contentmode];
|
||||
$('#tag' + tagmac + ' .model').innerHTML = models[element.model];
|
||||
|
||||
if (element.nextupdate > 1672531200 && element.nextupdate!=3216153600) {
|
||||
var date = new Date(element.nextupdate * 1000);
|
||||
var options = { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };
|
||||
$('#tag' + tagmac + ' .nextupdate').innerHTML = "next update: " + date.toLocaleString('nl-NL', options);
|
||||
} else {
|
||||
$('#tag' + tagmac + ' .nextupdate').innerHTML = "";
|
||||
}
|
||||
|
||||
if (element.nextcheckin > 1672531200) {
|
||||
div.dataset.nextcheckin = element.nextcheckin;
|
||||
} else {
|
||||
div.dataset.nextcheckin = element.lastseen + 1800;
|
||||
}
|
||||
|
||||
div.dataset.lastseen = element.lastseen;
|
||||
div.dataset.hash = element.hash;
|
||||
$('#tag' + tagmac + ' .warningicon').style.display = 'none';
|
||||
|
||||
if (element.pending) $('#tag' + tagmac + ' .pending').innerHTML = "pending update..."; else $('#tag' + tagmac + ' .pending').innerHTML = "";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function updatecards() {
|
||||
document.querySelectorAll('[data-mac]').forEach(item => {
|
||||
let tagmac = item.dataset.mac;
|
||||
|
||||
if (item.dataset.lastseen && item.dataset.lastseen > 1672531200) {
|
||||
let idletime = (Date.now() / 1000) + servertimediff - item.dataset.lastseen;
|
||||
$('#tag' + tagmac + ' .lastseen').innerHTML = "last seen: "+displayTime(Math.floor(idletime))+" ago";
|
||||
if ((Date.now() / 1000) + servertimediff > item.dataset.nextcheckin) $('#tag' + tagmac + ' .warningicon').style.display='inline-block';
|
||||
} else {
|
||||
$('#tag' + tagmac + ' .lastseen').innerHTML = ""
|
||||
}
|
||||
|
||||
if (item.dataset.nextcheckin > 1672531200) {
|
||||
let nextcheckin = item.dataset.nextcheckin - ((Date.now() / 1000) + servertimediff);
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "expecting next checkin: " + displayTime(Math.floor(nextcheckin));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$('#clearlog').onclick = function () {
|
||||
$('#messages').innerHTML='';
|
||||
}
|
||||
|
||||
$('.closebtn').onclick = function (event) {
|
||||
event.target.parentNode.style.display='none';
|
||||
}
|
||||
|
||||
$('#taglist').addEventListener("click", (event) => {
|
||||
let currentElement = event.target;
|
||||
while (currentElement !== $('#taglist')) {
|
||||
if (currentElement.classList.contains("tagcard")) {
|
||||
break;
|
||||
}
|
||||
currentElement = currentElement.parentNode;
|
||||
}
|
||||
if (!currentElement.classList.contains("tagcard")) {
|
||||
return;
|
||||
}
|
||||
const mac = currentElement.dataset.mac;
|
||||
if (event.target.classList.contains("mac")) {
|
||||
$('#dstmac').value=mac;
|
||||
}
|
||||
if (event.target.classList.contains("configicon")) {
|
||||
$('#cfgmac').innerHTML = mac;
|
||||
$('#cfgmac').dataset.mac = mac;
|
||||
fetch("/get_db?mac=" + mac)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
var tagdata = data.tags[0];
|
||||
$('#cfgalias').value = tagdata.alias;
|
||||
$('#cfgcontent').value = tagdata.contentmode;
|
||||
$('#cfgmodel').value = tagdata.model;
|
||||
$('#cfgcontent').dataset.json = tagdata.modecfgjson;
|
||||
contentselected();
|
||||
$('#configbox').style.display = 'block';
|
||||
})
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
}
|
||||
})
|
||||
|
||||
$('#cfgsave').onclick = function () {
|
||||
|
||||
let contentmode = $('#cfgcontent').value;
|
||||
let extraoptions = contentModeOptions[contentmode];
|
||||
let obj={};
|
||||
extraoptions.forEach(element => {
|
||||
obj[element] = $('#opt' + element).value;
|
||||
});
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("mac", $('#cfgmac').dataset.mac);
|
||||
formData.append("alias", $('#cfgalias').value);
|
||||
formData.append("contentmode", contentmode);
|
||||
formData.append("model", $('#cfgmodel').value);
|
||||
formData.append("modecfgjson", JSON.stringify(obj));
|
||||
fetch("/save_cfg", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => showMessage(data))
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
$('#configbox').style.display = 'none';
|
||||
}
|
||||
|
||||
$('#cfgdelete').onclick = function () {
|
||||
let mac = $('#cfgmac').dataset.mac;
|
||||
}
|
||||
|
||||
function contentselected() {
|
||||
let contentmode=$('#cfgcontent').value;
|
||||
let extraoptions = contentModeOptions[contentmode];
|
||||
$('#customoptions').innerHTML="";
|
||||
var obj = {};
|
||||
if ($('#cfgcontent').dataset.json && ($('#cfgcontent').dataset.json!="null")) {
|
||||
obj = JSON.parse($('#cfgcontent').dataset.json);
|
||||
}
|
||||
console.log(obj);
|
||||
extraoptions.forEach(element => {
|
||||
var label = document.createElement("label");
|
||||
label.innerHTML = element;
|
||||
label.setAttribute("for", 'opt' + element);
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.id = 'opt' + element;
|
||||
if (obj[element]) input.value = obj[element];
|
||||
var p = document.createElement("p");
|
||||
p.appendChild(label);
|
||||
p.appendChild(input);
|
||||
$('#customoptions').appendChild(p);
|
||||
});
|
||||
}
|
||||
|
||||
function showMessage(message,iserr) {
|
||||
const messages = $('#messages');
|
||||
var date = new Date(),
|
||||
time = date.toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute:'2-digit', second:'2-digit'});
|
||||
if (iserr) {
|
||||
messages.insertAdjacentHTML("afterbegin", '<li class="new error">' + htmlEncode(time + ' ' + message) + '</li>');
|
||||
} else {
|
||||
messages.insertAdjacentHTML("afterbegin", '<li class="new">'+htmlEncode(time+' '+message)+'</li>');
|
||||
}
|
||||
}
|
||||
|
||||
function htmlEncode(input) {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.innerText = input;
|
||||
return textArea.innerHTML.split("<br>").join("\n");
|
||||
}
|
||||
|
||||
function loadImage(id, imageSrc) {
|
||||
imageQueue.push({ id, imageSrc });
|
||||
if (!isProcessing) {
|
||||
processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function processQueue() {
|
||||
if (imageQueue.length === 0) {
|
||||
isProcessing = false;
|
||||
return;
|
||||
}
|
||||
isProcessing = true;
|
||||
const { id, imageSrc } = imageQueue.shift();
|
||||
const image = $('#tag' + id + ' .tagimg');
|
||||
image.onload = function () {
|
||||
image.style.display = 'block';
|
||||
processQueue();
|
||||
}
|
||||
image.onerror = function () {
|
||||
image.style.display = 'none';
|
||||
processQueue();
|
||||
};
|
||||
image.src = imageSrc;
|
||||
}
|
||||
|
||||
function displayTime(seconds) {
|
||||
let hours = Math.floor(Math.abs(seconds) / 3600);
|
||||
let minutes = Math.floor((Math.abs(seconds) % 3600) / 60);
|
||||
let remainingSeconds = Math.abs(seconds) % 60;
|
||||
return (seconds < 0 ? '-' : '') + (hours > 0 ? `${hours}:${String(minutes).padStart(2, '0')}` : `${minutes}`) + `:${String(remainingSeconds).padStart(2, '0')}`;
|
||||
}
|
||||
@@ -56,4 +56,6 @@ struct pendingData {
|
||||
} __packed;
|
||||
|
||||
#define BLOCK_DATA_SIZE 4096
|
||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
||||
|
||||
#pragma pack(pop)
|
||||
15
esp32_fw/include/contentmanager.h
Normal file
15
esp32_fw/include/contentmanager.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <LittleFS.h>
|
||||
#include "makeimage.h"
|
||||
#include <time.h>
|
||||
#include "tag_db.h"
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
void contentRunner();
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo);
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin);
|
||||
void drawDate(String &filename);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred);
|
||||
bool getImgURL(String &filename, String URL, time_t fetched);
|
||||
char *formatHttpDate(time_t t);
|
||||
35
esp32_fw/include/makeimage.h
Normal file
35
esp32_fw/include/makeimage.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <Arduino.h>
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct BitmapFileHeader {
|
||||
uint8_t sig[2];
|
||||
uint32_t fileSz;
|
||||
uint8_t rfu[4];
|
||||
uint32_t dataOfst;
|
||||
uint32_t headerSz; //40
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint16_t colorplanes; //must be one
|
||||
uint16_t bpp;
|
||||
uint32_t compression;
|
||||
uint32_t dataLen; //may be 0
|
||||
uint32_t pixelsPerMeterX;
|
||||
uint32_t pixelsPerMeterY;
|
||||
uint32_t numColors; //if zero, assume 2^bpp
|
||||
uint32_t numImportantColors;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
enum EinkClut {
|
||||
EinkClutTwoBlacks = 0,
|
||||
EinkClutTwoBlacksAndRed,
|
||||
EinkClutFourBlacks,
|
||||
EinkClutThreeBlacksAndRed,
|
||||
};
|
||||
|
||||
void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout);
|
||||
void jpg2grays(String filein, String fileout);
|
||||
void bmp2grays(String filein, String fileout);
|
||||
|
||||
@@ -21,3 +21,5 @@ class pendingdata {
|
||||
|
||||
void garbageCollection(void* parameter);
|
||||
extern std::vector<pendingdata*> pendingfiles;
|
||||
|
||||
#pragma pack(pop)
|
||||
47
esp32_fw/include/tag_db.h
Normal file
47
esp32_fw/include/tag_db.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#pragma once
|
||||
|
||||
enum contentModes {
|
||||
Image,
|
||||
Today,
|
||||
CountDays,
|
||||
CountHours,
|
||||
Weather,
|
||||
Firmware,
|
||||
Memo,
|
||||
ImageUrl,
|
||||
};
|
||||
|
||||
class tagRecord {
|
||||
public:
|
||||
uint16_t nextCheckinpending;
|
||||
tagRecord() : mac{0}, model(0), alias(""), lastseen(0), nextupdate(0), contentMode(Image), pending(false), button(false), md5{0}, md5pending{0}, CheckinInMinPending(0), expectedNextCheckin(0), modeConfigJson("") {}
|
||||
|
||||
uint8_t mac[6];
|
||||
u_int8_t model;
|
||||
String alias;
|
||||
uint32_t lastseen;
|
||||
uint32_t nextupdate;
|
||||
contentModes contentMode;
|
||||
bool pending;
|
||||
bool button;
|
||||
uint8_t md5[16];
|
||||
uint8_t md5pending[16];
|
||||
uint16_t CheckinInMinPending;
|
||||
uint32_t expectedNextCheckin;
|
||||
String modeConfigJson;
|
||||
static tagRecord* findByMAC(uint8_t mac[6]);
|
||||
};
|
||||
|
||||
extern std::vector<tagRecord*> tagDB;
|
||||
String tagDBtoJson(uint8_t mac[6] = nullptr, uint8_t startPos = 0);
|
||||
void fillNode(JsonObject &tag, tagRecord* &taginfo);
|
||||
void saveDB(String filename);
|
||||
void loadDB(String filename);
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -1,13 +1,19 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include<Arduino.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
void init_web();
|
||||
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
|
||||
extern void webSocketSendProcess(void *parameter);
|
||||
extern void wsString(String text);
|
||||
void wsLog(String text);
|
||||
void wsErr(String text);
|
||||
void wsSendTaginfo(uint8_t mac[6]);
|
||||
void wsSendSysteminfo();
|
||||
|
||||
extern uint64_t swap64(uint64_t x);
|
||||
extern AsyncWebSocket ws;//("/ws");
|
||||
extern AsyncWebSocket ws; //("/ws");
|
||||
|
||||
extern SemaphoreHandle_t wsMutex;
|
||||
extern TaskHandle_t websocketUpdater;
|
||||
@@ -22,5 +22,7 @@ lib_deps =
|
||||
https://github.com/me-no-dev/ESPAsyncWebServer
|
||||
https://github.com/tzapu/WiFiManager.git#feature_asyncwebserver
|
||||
bblanchon/ArduinoJson
|
||||
bodmer/TFT_eSPI
|
||||
https://github.com/Bodmer/TJpg_Decoder.git
|
||||
upload_port = COM5
|
||||
monitor_port = COM5
|
||||
|
||||
@@ -2,396 +2,9 @@
|
||||
|
||||
#include <FS.h>
|
||||
|
||||
// File: edit.htm.gz, Size: 4151
|
||||
#define edit_htm_gz_len 4151
|
||||
const uint8_t edit_htm_gz[] PROGMEM = {
|
||||
0x1F, 0x8B, 0x08, 0x08, 0xB8, 0x94, 0xB1, 0x59, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68,
|
||||
0x74, 0x6D, 0x00, 0xB5, 0x3A, 0x0B, 0x7B, 0xDA, 0xB8, 0xB2, 0x7F, 0xC5, 0x71, 0xCF, 0x66, 0xED,
|
||||
0x83, 0x31, 0x90, 0xA4, 0xD9, 0xD6, 0xC4, 0xC9, 0x42, 0x92, 0x36, 0x6D, 0xF3, 0x6A, 0x80, 0xB6,
|
||||
0x69, 0x4F, 0xEE, 0x7E, 0xC2, 0x16, 0xA0, 0xC6, 0x96, 0x5D, 0x5B, 0x0E, 0x49, 0x59, 0xFE, 0xFB,
|
||||
0x9D, 0x91, 0x6C, 0xB0, 0x09, 0x69, 0x77, 0xCF, 0xBD, 0xBB, 0xDD, 0x2D, 0x92, 0x46, 0x33, 0x9A,
|
||||
0x19, 0xCD, 0x53, 0xDE, 0xBD, 0x8D, 0xA3, 0x8B, 0xC3, 0xFE, 0xF5, 0xE5, 0xB1, 0x36, 0x11, 0x61,
|
||||
0xB0, 0xBF, 0x87, 0x7F, 0x6B, 0x01, 0xE1, 0x63, 0x97, 0xF2, 0xFD, 0x3D, 0xC1, 0x44, 0x40, 0xF7,
|
||||
0x8F, 0x7B, 0x97, 0xDA, 0xB1, 0xCF, 0x44, 0x94, 0xEC, 0x35, 0xD4, 0xCA, 0x5E, 0x2A, 0x1E, 0x02,
|
||||
0xAA, 0x85, 0xD4, 0x67, 0xC4, 0x4D, 0xBD, 0x84, 0xC2, 0x66, 0xDB, 0x0B, 0x67, 0xDF, 0xEB, 0x8C,
|
||||
0xFB, 0xF4, 0xDE, 0xD9, 0x6E, 0x36, 0xDB, 0x71, 0x94, 0x32, 0xC1, 0x22, 0xEE, 0x90, 0x61, 0x1A,
|
||||
0x05, 0x99, 0xA0, 0xED, 0x80, 0x8E, 0x84, 0xF3, 0x3C, 0xBE, 0x6F, 0x0F, 0xA3, 0xC4, 0xA7, 0x89,
|
||||
0xD3, 0x8A, 0xEF, 0x35, 0x00, 0x31, 0x5F, 0x7B, 0xB6, 0xB3, 0xB3, 0xD3, 0x1E, 0x12, 0xEF, 0x76,
|
||||
0x9C, 0x44, 0x19, 0xF7, 0xEB, 0x5E, 0x14, 0x44, 0x89, 0xF3, 0x6C, 0xF4, 0x1C, 0xFF, 0xB4, 0x7D,
|
||||
0x96, 0xC6, 0x01, 0x79, 0x70, 0x78, 0xC4, 0x29, 0xE0, 0xDE, 0xD7, 0xD3, 0x09, 0xF1, 0xA3, 0xA9,
|
||||
0xD3, 0xD4, 0x9A, 0x5A, 0xAB, 0x09, 0x44, 0x92, 0xF1, 0x90, 0x18, 0x4D, 0x0B, 0xFF, 0xD8, 0x3B,
|
||||
0x66, 0x7B, 0x14, 0x71, 0x51, 0x4F, 0xD9, 0x77, 0xEA, 0xB4, 0xB6, 0xE0, 0x34, 0x39, 0x1D, 0x91,
|
||||
0x90, 0x05, 0x0F, 0x4E, 0x4A, 0x78, 0x5A, 0x4F, 0x69, 0xC2, 0x46, 0x6A, 0x79, 0x4A, 0xD9, 0x78,
|
||||
0x22, 0x9C, 0xDF, 0x9A, 0xCD, 0x39, 0xF0, 0xAF, 0x65, 0xC1, 0x2C, 0x60, 0x29, 0x20, 0xA3, 0x78,
|
||||
0xEA, 0x3C, 0x11, 0xC5, 0x4E, 0x53, 0xB1, 0xDE, 0x6C, 0x87, 0x24, 0x19, 0x33, 0x0E, 0x83, 0x98,
|
||||
0xF8, 0x3E, 0xE3, 0x63, 0x47, 0xA1, 0x05, 0x6C, 0xB6, 0x90, 0x36, 0xA1, 0x01, 0x11, 0xEC, 0x8E,
|
||||
0xB6, 0x43, 0xC6, 0xEB, 0x53, 0xE6, 0x8B, 0x89, 0xB3, 0x0B, 0x3C, 0xB6, 0xBD, 0x2C, 0x49, 0x41,
|
||||
0xA6, 0x38, 0x62, 0x5C, 0xD0, 0x44, 0xA2, 0xA5, 0x31, 0xE1, 0xB3, 0x5C, 0x54, 0x54, 0x40, 0x21,
|
||||
0x27, 0xE3, 0x01, 0xE3, 0xB4, 0x3E, 0x0C, 0x22, 0xEF, 0x76, 0x71, 0xD2, 0x6E, 0x7C, 0x9F, 0x9F,
|
||||
0xE5, 0x4C, 0xA2, 0x3B, 0x9A, 0xCC, 0x96, 0xEA, 0x92, 0xD8, 0x15, 0x60, 0x85, 0x34, 0xA5, 0x74,
|
||||
0x6E, 0x8B, 0xBB, 0x0C, 0xA0, 0x96, 0xFC, 0x05, 0x29, 0x17, 0xFC, 0x2F, 0x45, 0x5A, 0x11, 0x5C,
|
||||
0xA1, 0x30, 0x1E, 0x67, 0x62, 0xF6, 0xF8, 0x2A, 0xA3, 0x98, 0x78, 0x4C, 0x3C, 0xA0, 0xFC, 0xB0,
|
||||
0x6D, 0x86, 0xBA, 0x04, 0xAC, 0x24, 0x24, 0x81, 0x86, 0x3A, 0xD7, 0x3E, 0xD0, 0xC4, 0x27, 0x9C,
|
||||
0x58, 0x9D, 0x84, 0x91, 0xC0, 0xEA, 0x2D, 0xB5, 0x5E, 0x0F, 0xA3, 0xEF, 0xF5, 0x0C, 0xC6, 0x30,
|
||||
0x0F, 0xA8, 0x27, 0x94, 0x92, 0xE1, 0x1E, 0x86, 0xB7, 0x4C, 0x3C, 0x06, 0x3C, 0x5A, 0x28, 0xA9,
|
||||
0x4B, 0x2A, 0x69, 0xA2, 0x2E, 0xB0, 0x25, 0xD5, 0x83, 0x1C, 0x4B, 0xC9, 0x95, 0x50, 0xF5, 0x61,
|
||||
0x24, 0x44, 0x14, 0x4A, 0x93, 0x5B, 0x08, 0xAC, 0x49, 0xAB, 0x79, 0xF1, 0xE8, 0x46, 0xD6, 0x6B,
|
||||
0xBF, 0x44, 0xBE, 0x0D, 0x7A, 0x15, 0xCC, 0x23, 0x41, 0x9D, 0x04, 0x6C, 0xCC, 0x9D, 0x90, 0xF9,
|
||||
0x7E, 0x40, 0x4B, 0x56, 0xEB, 0x64, 0x49, 0x60, 0xF8, 0x44, 0x10, 0x87, 0x85, 0x64, 0x4C, 0x1B,
|
||||
0x31, 0x1F, 0x03, 0x34, 0xA5, 0xBB, 0x3B, 0x16, 0xFB, 0xD0, 0xBD, 0xB8, 0x9A, 0x36, 0xDF, 0xBD,
|
||||
0x1E, 0x47, 0x1D, 0xF8, 0xE7, 0xBC, 0x37, 0x98, 0x1C, 0x0F, 0xC6, 0x30, 0xEA, 0xE2, 0xB4, 0xF3,
|
||||
0xFE, 0xB0, 0xF3, 0x1E, 0x7E, 0x0E, 0x5B, 0xB5, 0xAF, 0xA3, 0x6F, 0xB8, 0xD0, 0x7D, 0xED, 0x77,
|
||||
0xFB, 0x83, 0xE3, 0x4E, 0xE7, 0x5D, 0xE3, 0xCD, 0xF9, 0xF4, 0xE3, 0xBB, 0x5D, 0x04, 0x77, 0x83,
|
||||
0xE6, 0xD5, 0x87, 0x49, 0x73, 0xB0, 0xF5, 0x32, 0xF4, 0x4F, 0xFC, 0x89, 0x17, 0x0E, 0x3A, 0xEF,
|
||||
0x3F, 0x5E, 0xDD, 0x5D, 0x87, 0x83, 0x71, 0xEF, 0x63, 0x6B, 0xF2, 0x79, 0xEB, 0x43, 0xEF, 0xF3,
|
||||
0xC7, 0x57, 0xB7, 0xF4, 0xD3, 0xC9, 0xDB, 0xCF, 0xFD, 0x29, 0x20, 0x1C, 0x45, 0xBD, 0xC1, 0x55,
|
||||
0xF7, 0x43, 0x77, 0xFC, 0xB9, 0xEB, 0x1D, 0xDF, 0x0F, 0x83, 0xF3, 0xEE, 0xEB, 0xCE, 0xB0, 0xB3,
|
||||
0xE5, 0x51, 0x3A, 0xEE, 0x5F, 0x75, 0xB3, 0x37, 0xEF, 0x2E, 0xC6, 0x8C, 0x4D, 0x7A, 0x9F, 0xCF,
|
||||
0xFB, 0xDE, 0xE1, 0xF3, 0xD3, 0xC1, 0x49, 0x87, 0x4D, 0xCE, 0xDF, 0x5E, 0x35, 0x6F, 0x5F, 0xBF,
|
||||
0x3B, 0x3C, 0xF2, 0xAE, 0xDF, 0x5E, 0xEF, 0x1E, 0x6D, 0x37, 0x7E, 0xFB, 0xED, 0xCC, 0xBF, 0x60,
|
||||
0xBC, 0x7F, 0xF7, 0xBD, 0x33, 0x3E, 0x9C, 0xBE, 0x78, 0x48, 0xFB, 0x93, 0x37, 0x77, 0xBC, 0xF1,
|
||||
0x21, 0xFA, 0xFA, 0xE6, 0xE1, 0x0C, 0xFE, 0xBB, 0xBC, 0xAC, 0x0D, 0x7B, 0xAD, 0x74, 0xF0, 0xFE,
|
||||
0xCD, 0x87, 0xAD, 0xF4, 0xE5, 0xF3, 0xB8, 0x7B, 0x74, 0x74, 0x17, 0x0E, 0x2F, 0x1B, 0xA1, 0x7F,
|
||||
0x3B, 0x12, 0x2F, 0xB6, 0x45, 0x7C, 0x3D, 0xCE, 0x3E, 0x7F, 0x7B, 0xFE, 0x76, 0xD2, 0xB8, 0xA0,
|
||||
0xE4, 0x7A, 0x52, 0x7B, 0xF8, 0xFE, 0xF0, 0x62, 0xD2, 0x3F, 0xB9, 0x3B, 0x0F, 0xC8, 0xFD, 0xF9,
|
||||
0xB9, 0xF7, 0x3D, 0xAC, 0x05, 0xE4, 0xE5, 0x45, 0x3F, 0x20, 0x49, 0x6B, 0xE0, 0x77, 0x1A, 0xB5,
|
||||
0xC3, 0xAD, 0xCE, 0x8E, 0x48, 0xAE, 0x0E, 0xF9, 0xD1, 0xF6, 0xD7, 0xDE, 0x8B, 0x6E, 0xB7, 0x15,
|
||||
0x0D, 0xBF, 0x6D, 0xBD, 0xBE, 0xDD, 0x7D, 0x3D, 0xD8, 0x7D, 0x3F, 0x7C, 0xDF, 0xE9, 0xED, 0x74,
|
||||
0x07, 0xE4, 0xBA, 0xF7, 0xBE, 0x33, 0xDA, 0x19, 0x4E, 0x26, 0xEF, 0xDE, 0xF5, 0x5F, 0xF9, 0x9D,
|
||||
0xEF, 0x49, 0xE7, 0x62, 0xDA, 0xB9, 0x3F, 0x1E, 0x74, 0x4E, 0x6A, 0xEF, 0x8E, 0xCF, 0x9A, 0xAD,
|
||||
0xDE, 0xF5, 0xF6, 0xF8, 0x6C, 0x77, 0xDA, 0x4D, 0x8F, 0x3B, 0xEF, 0xBB, 0xCD, 0xF1, 0xDB, 0x5A,
|
||||
0x48, 0x3E, 0x47, 0x87, 0xDB, 0xE3, 0x37, 0xBB, 0xEC, 0xF2, 0x9A, 0x74, 0xDE, 0x74, 0xDF, 0xA6,
|
||||
0xEC, 0x2A, 0x3C, 0x19, 0x34, 0x3B, 0x9D, 0xD3, 0x0B, 0xFA, 0xEA, 0x70, 0x9B, 0xBC, 0xDB, 0xF2,
|
||||
0x3E, 0x82, 0xFE, 0x07, 0x9F, 0xE8, 0x6F, 0xB5, 0xCE, 0xF4, 0xA2, 0x19, 0x78, 0x2F, 0x69, 0xFF,
|
||||
0xE4, 0xBA, 0x2F, 0x6F, 0xE7, 0x38, 0x78, 0xD5, 0xBF, 0xED, 0x65, 0xEF, 0xC3, 0xC3, 0x43, 0x53,
|
||||
0xE3, 0x51, 0x3D, 0xA1, 0x31, 0x25, 0xA2, 0x1C, 0xAE, 0x16, 0xFE, 0x01, 0xB6, 0xB5, 0xB4, 0xC2,
|
||||
0xDC, 0x4F, 0x05, 0xBD, 0x17, 0x75, 0x9F, 0x7A, 0x51, 0x42, 0xE4, 0x1E, 0x40, 0xA0, 0x09, 0x9A,
|
||||
0xD8, 0xFC, 0x77, 0x19, 0x3F, 0x35, 0x15, 0x3F, 0x35, 0xC2, 0x7D, 0xCD, 0x28, 0x1C, 0x01, 0x83,
|
||||
0x87, 0x4F, 0xEF, 0x98, 0x47, 0xEB, 0x31, 0xBB, 0xA7, 0x41, 0x5D, 0x22, 0x3B, 0x4D, 0x73, 0x26,
|
||||
0xFD, 0xAD, 0xD8, 0x46, 0x38, 0x98, 0x9A, 0xA4, 0x5A, 0x2C, 0xF8, 0x5F, 0x89, 0x47, 0x21, 0xB0,
|
||||
0x81, 0xCB, 0x84, 0xF8, 0xAB, 0x7C, 0x27, 0x4A, 0xEA, 0xC3, 0x6C, 0x3C, 0x62, 0xF7, 0xE0, 0xD0,
|
||||
0x23, 0xC6, 0x99, 0xA0, 0x5A, 0x2B, 0x9D, 0xFF, 0x5E, 0x90, 0xB9, 0xA5, 0x0F, 0xA3, 0x84, 0x84,
|
||||
0x34, 0xD5, 0xFE, 0x22, 0x99, 0xD9, 0x28, 0x89, 0xC2, 0x65, 0x10, 0x99, 0x8B, 0xA8, 0x34, 0x99,
|
||||
0xCF, 0x9F, 0x65, 0x71, 0x10, 0x11, 0x10, 0x73, 0x4D, 0xE4, 0x50, 0xF1, 0x34, 0x91, 0x6E, 0xB5,
|
||||
0x88, 0xAB, 0xB9, 0x9B, 0x6D, 0xA1, 0x5B, 0x96, 0xDD, 0x7A, 0x6B, 0x67, 0xE9, 0xBA, 0x75, 0xB9,
|
||||
0x17, 0xE3, 0xFD, 0x9A, 0x4C, 0x81, 0xF1, 0xA0, 0x14, 0xEE, 0x9E, 0x09, 0x50, 0xE9, 0x13, 0x87,
|
||||
0xCB, 0x43, 0xF2, 0xC8, 0xB0, 0x60, 0x40, 0x05, 0xEA, 0x96, 0x8C, 0xD4, 0x85, 0x24, 0xB0, 0x6F,
|
||||
0xFE, 0x8C, 0xCA, 0xBC, 0x67, 0x3D, 0x8B, 0x13, 0xB8, 0x0D, 0x3A, 0xFD, 0x11, 0xCD, 0x42, 0xA6,
|
||||
0x2A, 0x6D, 0x45, 0x53, 0x65, 0xBC, 0x5C, 0x84, 0x65, 0xDA, 0x93, 0xBC, 0x16, 0xA4, 0x1F, 0x4B,
|
||||
0x05, 0xE0, 0x05, 0x37, 0xCF, 0x91, 0x9B, 0x1F, 0x6A, 0x75, 0x7B, 0xF7, 0x97, 0x9C, 0x87, 0x9D,
|
||||
0xE6, 0x2F, 0x73, 0x3B, 0xDF, 0x5B, 0xA4, 0xE4, 0x56, 0x13, 0xFE, 0x29, 0x32, 0xEF, 0x8B, 0x25,
|
||||
0x0B, 0xC3, 0xE7, 0xF8, 0xA7, 0x60, 0x10, 0xE9, 0x94, 0x80, 0xDB, 0x3B, 0x2F, 0x5F, 0xF8, 0xC3,
|
||||
0x02, 0x98, 0x0B, 0xF6, 0x24, 0x3C, 0x21, 0x3E, 0xCB, 0x52, 0xE7, 0x79, 0xF3, 0x97, 0x5C, 0x9F,
|
||||
0x5B, 0x3B, 0x28, 0xFB, 0xE2, 0x2E, 0x71, 0xB2, 0xB4, 0xD8, 0x34, 0x66, 0x5C, 0xDB, 0x4A, 0x35,
|
||||
0xBC, 0x6F, 0x92, 0x2C, 0x0C, 0xB3, 0x92, 0xED, 0xE7, 0xBF, 0x2F, 0x4D, 0x13, 0xF7, 0xCF, 0x9A,
|
||||
0xBF, 0xCC, 0x44, 0x02, 0xD9, 0x64, 0x04, 0xB9, 0xC6, 0x49, 0x22, 0x41, 0x04, 0x35, 0x9A, 0xE6,
|
||||
0x1C, 0x84, 0x5B, 0x03, 0xD8, 0xDE, 0x6D, 0xFA, 0x74, 0x6C, 0xCE, 0xE7, 0x7B, 0x0D, 0x99, 0xD7,
|
||||
0xA0, 0x6C, 0xF1, 0x12, 0x16, 0x8B, 0xFD, 0x51, 0xC6, 0x3D, 0xE4, 0x41, 0x1B, 0x53, 0x83, 0x9A,
|
||||
0xB3, 0x84, 0x8A, 0x2C, 0xE1, 0x9A, 0x1F, 0x79, 0x19, 0x1A, 0xBB, 0x3D, 0xA6, 0xE2, 0x58, 0xD9,
|
||||
0x7D, 0xF7, 0xE1, 0x8D, 0x0F, 0x3B, 0xE6, 0x0B, 0x04, 0x6F, 0x2D, 0x02, 0x38, 0x30, 0x9C, 0x97,
|
||||
0xE3, 0x54, 0xF6, 0x43, 0x82, 0x01, 0x22, 0xEF, 0xE8, 0x83, 0x41, 0x2D, 0xB1, 0x40, 0xA4, 0x36,
|
||||
0xAE, 0x1B, 0xC5, 0x2E, 0x80, 0x71, 0x73, 0x76, 0x07, 0x4A, 0x20, 0x2E, 0xFD, 0x22, 0x6E, 0x2C,
|
||||
0xE6, 0x72, 0xF8, 0x69, 0xE7, 0xBB, 0xC9, 0x1E, 0x3B, 0xA8, 0xB7, 0x1C, 0xB2, 0xCF, 0x0E, 0x5A,
|
||||
0xE0, 0x5E, 0x65, 0x6E, 0xE4, 0xB9, 0xAF, 0x58, 0x40, 0x07, 0xB9, 0xC3, 0xE1, 0x31, 0x48, 0x6C,
|
||||
0xB1, 0x85, 0x28, 0xE2, 0x5B, 0xCD, 0xE6, 0x86, 0x4B, 0x0F, 0x48, 0x00, 0x39, 0xCC, 0xD0, 0x8F,
|
||||
0xAF, 0xAE, 0x2E, 0xAE, 0xBE, 0xE8, 0x35, 0x5A, 0xD3, 0x6F, 0x1C, 0x4D, 0xAF, 0x71, 0xD3, 0x11,
|
||||
0x76, 0x42, 0x47, 0x09, 0x4D, 0x27, 0x97, 0x44, 0x4C, 0x8C, 0xD4, 0xBE, 0x23, 0x41, 0x56, 0x16,
|
||||
0x84, 0xA1, 0xDC, 0xC8, 0xA2, 0x70, 0x39, 0x9D, 0x6A, 0xAF, 0x40, 0xCD, 0x47, 0x90, 0xEA, 0xDA,
|
||||
0xC2, 0x26, 0x71, 0x4C, 0xB9, 0x6F, 0xE8, 0x31, 0x20, 0xEA, 0x16, 0x35, 0xAD, 0x84, 0x7E, 0xCB,
|
||||
0x68, 0x2A, 0x52, 0x1B, 0x2C, 0xD7, 0xD0, 0x2F, 0x07, 0x7D, 0xDD, 0xD2, 0x1B, 0xE8, 0x47, 0x3A,
|
||||
0xF0, 0x46, 0xCC, 0x39, 0x52, 0x89, 0x5C, 0xD0, 0xA4, 0x3E, 0xCC, 0xC0, 0xA0, 0xB8, 0x6E, 0xB6,
|
||||
0x23, 0x9B, 0x71, 0x4E, 0x93, 0x93, 0xFE, 0xD9, 0xA9, 0xAB, 0x5F, 0x29, 0x46, 0xB4, 0x53, 0x28,
|
||||
0x48, 0x74, 0x4B, 0x5E, 0x51, 0x7E, 0xC8, 0xE1, 0x84, 0x05, 0xBE, 0x11, 0x99, 0x6D, 0x24, 0xE1,
|
||||
0x49, 0x12, 0xB2, 0x40, 0x01, 0x0A, 0x9E, 0x2D, 0x1E, 0x62, 0xEA, 0xEA, 0x23, 0x50, 0x86, 0x6E,
|
||||
0x79, 0x76, 0x98, 0x05, 0x82, 0xC5, 0x01, 0x75, 0x37, 0x5A, 0x30, 0xE3, 0x60, 0x41, 0xAE, 0x8E,
|
||||
0xB9, 0x19, 0x61, 0xCC, 0x77, 0x75, 0x15, 0xA1, 0xF2, 0xB8, 0xB6, 0xEE, 0x14, 0x4F, 0x9D, 0x92,
|
||||
0x56, 0x4E, 0x49, 0xCB, 0xB8, 0x4A, 0xE0, 0x34, 0x3F, 0x18, 0xC3, 0x3C, 0xCE, 0xD4, 0x51, 0x05,
|
||||
0xCC, 0xA7, 0x23, 0x02, 0x9C, 0x7C, 0x40, 0x6D, 0xBA, 0x7A, 0x63, 0xDD, 0x41, 0xA9, 0x3A, 0xC8,
|
||||
0xAF, 0x6A, 0xC4, 0x2F, 0x6B, 0x44, 0xDD, 0xEE, 0x3A, 0x64, 0x5F, 0x21, 0x07, 0x55, 0xE4, 0xA0,
|
||||
0x8C, 0x7C, 0x28, 0x8D, 0x64, 0x1D, 0x72, 0xA0, 0x90, 0x93, 0x8A, 0x88, 0x89, 0x14, 0x51, 0x85,
|
||||
0xBD, 0x3A, 0x6A, 0x13, 0x05, 0xD2, 0xAD, 0xA4, 0x22, 0x66, 0x62, 0x83, 0x97, 0x92, 0x61, 0x40,
|
||||
0x7D, 0x77, 0xA3, 0x09, 0x33, 0x2C, 0xB6, 0xDD, 0xAD, 0xE6, 0x9A, 0x33, 0x12, 0x75, 0x46, 0x56,
|
||||
0x65, 0x30, 0x2B, 0x33, 0xA8, 0xF5, 0xC8, 0x1D, 0xD5, 0xD6, 0x31, 0x98, 0x99, 0x56, 0x60, 0x47,
|
||||
0xDC, 0x0B, 0x98, 0x77, 0xEB, 0x2E, 0xBD, 0xC5, 0x9C, 0xB1, 0x85, 0x85, 0x5A, 0x5C, 0x06, 0xBA,
|
||||
0x01, 0x94, 0x5E, 0x8B, 0xA5, 0x7C, 0x80, 0xFA, 0x9E, 0x5B, 0xD9, 0x5A, 0x02, 0xDC, 0xA6, 0xF7,
|
||||
0xD4, 0x3B, 0x8C, 0xC2, 0x90, 0xA0, 0xED, 0xA6, 0xC0, 0x41, 0x3E, 0xD1, 0xCD, 0xB9, 0x15, 0xAD,
|
||||
0xC5, 0x79, 0xC2, 0x45, 0x2C, 0x7F, 0x3D, 0x8B, 0x23, 0x03, 0x5C, 0xCE, 0xF5, 0x6C, 0xD4, 0x61,
|
||||
0x6A, 0x83, 0x1E, 0xC7, 0x62, 0xF2, 0x13, 0x17, 0x2A, 0x0C, 0x54, 0xA2, 0x7C, 0x69, 0xDE, 0x58,
|
||||
0x0B, 0x91, 0x56, 0x7C, 0xEA, 0xA2, 0xB7, 0xE2, 0x54, 0xA8, 0xBC, 0x8A, 0x5D, 0x9A, 0x4B, 0x1D,
|
||||
0x94, 0x61, 0xB9, 0xBD, 0x2F, 0xA0, 0xFA, 0x7C, 0x0E, 0xE7, 0x01, 0xFF, 0x13, 0x68, 0xF9, 0xE8,
|
||||
0x5F, 0x17, 0x60, 0xC9, 0xA3, 0x34, 0x78, 0x8B, 0xBB, 0x0D, 0xE3, 0xC0, 0xF9, 0x8F, 0x6D, 0x7C,
|
||||
0xF9, 0x1F, 0xFB, 0xA6, 0x66, 0x9A, 0x07, 0xFF, 0x6A, 0x48, 0x0D, 0x1B, 0xC2, 0xFC, 0xD2, 0xBA,
|
||||
0xB1, 0x08, 0x80, 0xED, 0x7F, 0x9B, 0xFF, 0xB1, 0x25, 0xB8, 0x02, 0x6B, 0xDF, 0x45, 0x90, 0x49,
|
||||
0xF0, 0x24, 0x34, 0xB0, 0x68, 0xA4, 0x91, 0xCD, 0x4D, 0x43, 0xB8, 0xA4, 0x72, 0x8D, 0x35, 0x51,
|
||||
0xD3, 0x6D, 0x88, 0x53, 0x50, 0x5B, 0xAC, 0x04, 0xBF, 0x3E, 0x24, 0x7A, 0x15, 0x5B, 0x17, 0x00,
|
||||
0xC9, 0x3D, 0xCA, 0x0C, 0x3D, 0x22, 0x97, 0x52, 0xCB, 0x0C, 0x02, 0x42, 0xA7, 0x89, 0xE7, 0x2A,
|
||||
0xAD, 0x1D, 0x14, 0x30, 0x17, 0xA2, 0xE0, 0xBC, 0x1C, 0x2D, 0x15, 0xEA, 0xAA, 0xFD, 0x17, 0x0A,
|
||||
0xA3, 0xD6, 0x12, 0x8A, 0x04, 0x31, 0xAD, 0xD8, 0x79, 0xC6, 0x72, 0x75, 0x4C, 0x59, 0xBA, 0x35,
|
||||
0x59, 0x5D, 0x96, 0xAD, 0x04, 0xAE, 0x2F, 0x8D, 0xFE, 0xD7, 0x3D, 0x16, 0x8E, 0xB5, 0x12, 0x3F,
|
||||
0xF8, 0x97, 0xFB, 0x2B, 0x46, 0xE4, 0xCD, 0x3F, 0xBC, 0x21, 0x70, 0x05, 0xA6, 0x41, 0x6D, 0x1E,
|
||||
0x4D, 0x0D, 0xB3, 0xF6, 0xAB, 0xAE, 0x49, 0x8A, 0xAE, 0x1E, 0x92, 0xFB, 0xBC, 0xA7, 0xC4, 0x8C,
|
||||
0xD7, 0xD6, 0x70, 0x5E, 0xB4, 0x28, 0xF9, 0x82, 0xEC, 0xE6, 0x48, 0x26, 0xA2, 0xB6, 0x56, 0x64,
|
||||
0x52, 0xD5, 0xCA, 0xE8, 0x5A, 0x63, 0xFF, 0xD7, 0x4A, 0x40, 0xB7, 0x98, 0xBA, 0x4E, 0x15, 0x8C,
|
||||
0xB3, 0x00, 0x1C, 0x93, 0x3E, 0x1D, 0x69, 0x03, 0x26, 0x03, 0x75, 0x35, 0x46, 0x5A, 0x81, 0xC1,
|
||||
0xCC, 0x03, 0xC3, 0x2B, 0xFB, 0xF3, 0x1E, 0x16, 0xBF, 0xFB, 0x97, 0xAA, 0xAA, 0x81, 0xD4, 0x8B,
|
||||
0x33, 0x5D, 0x59, 0x59, 0xD5, 0x4B, 0xE0, 0xD2, 0x08, 0xA0, 0x5B, 0x8B, 0x3C, 0x3A, 0x8C, 0xFC,
|
||||
0x87, 0x52, 0xF6, 0x4D, 0xBB, 0x0F, 0x87, 0x01, 0x49, 0xD3, 0x73, 0xB8, 0x01, 0x43, 0xF7, 0x42,
|
||||
0x50, 0xB8, 0xB2, 0xC2, 0xFD, 0xE6, 0xE6, 0x66, 0x15, 0x29, 0xA1, 0x21, 0x14, 0xDB, 0x8A, 0x2B,
|
||||
0xF0, 0x49, 0xD3, 0xF1, 0x81, 0x30, 0x18, 0xD2, 0x1A, 0xC6, 0xF0, 0x25, 0xE3, 0x47, 0x5C, 0x71,
|
||||
0xF4, 0xF4, 0x22, 0xA6, 0xFC, 0x33, 0xDC, 0x95, 0x32, 0xCB, 0x1A, 0xAD, 0xA6, 0x68, 0xFA, 0x8F,
|
||||
0xD8, 0x3E, 0xCA, 0x0D, 0x76, 0xC1, 0x7A, 0xBA, 0x56, 0xA1, 0xFC, 0x9F, 0x61, 0xB9, 0x94, 0x28,
|
||||
0xD6, 0x70, 0x9C, 0x40, 0x80, 0x5A, 0xC3, 0x31, 0xC4, 0x1A, 0x41, 0x17, 0xFC, 0x26, 0x6B, 0xF9,
|
||||
0xCD, 0xFE, 0x19, 0x7E, 0x97, 0x76, 0x1E, 0x15, 0x25, 0x91, 0xAA, 0xAF, 0x50, 0x02, 0x9F, 0xDD,
|
||||
0xE9, 0xA6, 0x15, 0xB9, 0x55, 0x0A, 0x50, 0x1B, 0x46, 0x41, 0xD0, 0x8F, 0xE2, 0x83, 0x27, 0xD6,
|
||||
0x9D, 0xC5, 0x7A, 0x31, 0xC8, 0xD9, 0x5C, 0x6E, 0xB1, 0xBC, 0xB5, 0x44, 0x4F, 0xA1, 0xEC, 0x5F,
|
||||
0x4B, 0x15, 0x01, 0x3F, 0x23, 0x8B, 0x7B, 0xAC, 0xD4, 0xA5, 0x36, 0x28, 0x0F, 0x56, 0x3F, 0xD5,
|
||||
0x3C, 0xCB, 0x5F, 0xCC, 0xAE, 0x6B, 0x51, 0x9B, 0xC0, 0x38, 0x57, 0x92, 0x8B, 0x4A, 0xB2, 0xC8,
|
||||
0x13, 0x01, 0xA8, 0x58, 0xC7, 0x2E, 0xC4, 0x4D, 0x6B, 0x7A, 0x7C, 0xBF, 0x5C, 0x83, 0xC2, 0xDF,
|
||||
0xF5, 0xD5, 0x12, 0x33, 0x08, 0xC4, 0xD3, 0x95, 0x4B, 0x29, 0x5F, 0x37, 0x29, 0x8A, 0x0E, 0x62,
|
||||
0x47, 0xA3, 0x51, 0x4A, 0xC5, 0x47, 0x0C, 0x49, 0x56, 0xB2, 0x98, 0x9F, 0xC8, 0x90, 0x04, 0x8C,
|
||||
0x45, 0x3C, 0x8C, 0xB2, 0x94, 0x46, 0x99, 0xA8, 0xA4, 0x16, 0x63, 0x21, 0xCC, 0x5E, 0xFA, 0xE7,
|
||||
0x9F, 0x8B, 0xC9, 0x7E, 0x5A, 0x0B, 0x96, 0xD3, 0xEB, 0x3D, 0xBF, 0x34, 0xD9, 0xF7, 0x6B, 0x89,
|
||||
0xB9, 0x7A, 0xE9, 0xFF, 0x67, 0x4B, 0x21, 0x65, 0x4B, 0xF1, 0xB0, 0x54, 0x2E, 0x62, 0x62, 0x29,
|
||||
0xE6, 0xC9, 0x82, 0x91, 0x97, 0x7C, 0x16, 0x0D, 0x1A, 0x2B, 0x25, 0x55, 0x9E, 0x97, 0x7D, 0x95,
|
||||
0x43, 0x40, 0x59, 0x71, 0xE5, 0x35, 0x11, 0x06, 0x34, 0xE0, 0x63, 0x64, 0xF2, 0x41, 0xEB, 0xA7,
|
||||
0xD1, 0x94, 0x26, 0x87, 0x24, 0xA5, 0x06, 0x24, 0xCD, 0x65, 0xDC, 0x41, 0xA8, 0xE9, 0x04, 0xEB,
|
||||
0x76, 0x6D, 0x6E, 0x12, 0x05, 0xCE, 0x33, 0x77, 0xC4, 0xB1, 0x26, 0x03, 0xF9, 0xB2, 0xCA, 0x09,
|
||||
0xD4, 0xC6, 0xBE, 0x12, 0xA4, 0x3E, 0x52, 0x25, 0xA8, 0x61, 0x5A, 0xD0, 0x76, 0xC0, 0x35, 0x5F,
|
||||
0x26, 0x51, 0x4C, 0xC6, 0xB2, 0x07, 0x83, 0x35, 0x74, 0x0F, 0xA4, 0x66, 0x6D, 0x34, 0x91, 0x60,
|
||||
0xA9, 0x73, 0x29, 0xFC, 0x66, 0xD9, 0xC2, 0x70, 0x4B, 0x57, 0xC9, 0xB0, 0xBD, 0xF4, 0xA5, 0x35,
|
||||
0x59, 0x83, 0xE0, 0x0B, 0x6C, 0x62, 0xE0, 0x1E, 0x68, 0x64, 0xF2, 0x7B, 0x00, 0x77, 0x6B, 0xB6,
|
||||
0xA3, 0x3D, 0xD6, 0x8E, 0x6A, 0x35, 0x53, 0x55, 0xE9, 0xAE, 0x0B, 0x6D, 0x4E, 0x74, 0x23, 0x0B,
|
||||
0x4B, 0x10, 0xAA, 0x9A, 0x59, 0x0C, 0x38, 0x1B, 0x81, 0xAA, 0xBA, 0xC0, 0x11, 0xD6, 0x98, 0x66,
|
||||
0xA9, 0x23, 0xF1, 0x97, 0x1D, 0xC9, 0x13, 0xB5, 0x07, 0x95, 0xF5, 0x05, 0xD4, 0x31, 0xAB, 0x25,
|
||||
0x86, 0x30, 0xD3, 0x29, 0x13, 0xDE, 0x04, 0x03, 0x90, 0x07, 0x5A, 0xD5, 0x05, 0x14, 0xB5, 0x8E,
|
||||
0x1C, 0x4D, 0x44, 0xB8, 0x1C, 0x05, 0xF9, 0xF0, 0x6B, 0x9A, 0x0F, 0xBC, 0xB4, 0x18, 0xDD, 0x97,
|
||||
0x80, 0x50, 0xD2, 0xE6, 0xE0, 0x88, 0x8F, 0xF2, 0x21, 0xF4, 0xB2, 0x05, 0x9D, 0x02, 0x58, 0xFC,
|
||||
0xC6, 0x71, 0x3E, 0x8A, 0x27, 0xC5, 0x68, 0x42, 0xEF, 0x17, 0x78, 0x51, 0x01, 0xF5, 0xA9, 0xEE,
|
||||
0x28, 0x1B, 0xDB, 0x68, 0xCE, 0xF3, 0x41, 0x6B, 0x29, 0x7F, 0xF0, 0xFF, 0x28, 0x7F, 0xCC, 0xC7,
|
||||
0x85, 0x34, 0x71, 0x31, 0x1A, 0xB3, 0x42, 0x96, 0x61, 0x18, 0xFF, 0x90, 0x93, 0xA4, 0xD4, 0x13,
|
||||
0x97, 0x7A, 0x5A, 0xF1, 0xB3, 0xB6, 0x53, 0x98, 0x8E, 0x31, 0xAA, 0xF8, 0xE3, 0xC8, 0xF6, 0xF0,
|
||||
0xF7, 0x3C, 0xF2, 0x65, 0x6D, 0x69, 0x5A, 0xA1, 0x31, 0x82, 0x3A, 0x57, 0x37, 0xCB, 0x7E, 0x9A,
|
||||
0xFD, 0xB7, 0xAD, 0xE8, 0xD1, 0xF1, 0xE9, 0x71, 0xFF, 0xB8, 0x5C, 0x38, 0x23, 0xE7, 0x25, 0x93,
|
||||
0x8A, 0x2B, 0x5D, 0xFA, 0xB2, 0x22, 0x80, 0x02, 0x1B, 0x45, 0x01, 0x7B, 0xDD, 0xDC, 0x54, 0x7E,
|
||||
0xF1, 0xB6, 0x77, 0x71, 0x6E, 0xC7, 0x24, 0x01, 0x8F, 0x24, 0x15, 0xE6, 0xC2, 0x82, 0x44, 0xF9,
|
||||
0xE0, 0xD7, 0xC7, 0xA5, 0x72, 0x5D, 0x7E, 0x61, 0x70, 0xC4, 0xDC, 0x52, 0xA7, 0xA9, 0x7E, 0x78,
|
||||
0xE2, 0x62, 0x5D, 0x99, 0xBF, 0x04, 0x41, 0x72, 0x1A, 0x2D, 0x13, 0x55, 0x11, 0x67, 0x46, 0xE5,
|
||||
0x30, 0x2F, 0xEE, 0xB2, 0x75, 0x0D, 0xD3, 0xC8, 0xB4, 0xC4, 0x84, 0xA5, 0xE5, 0x46, 0xA5, 0x12,
|
||||
0x14, 0xFE, 0xA2, 0xB6, 0xE7, 0x8B, 0x91, 0x24, 0xB7, 0x5A, 0x73, 0xAB, 0x6F, 0x41, 0x2A, 0x3E,
|
||||
0x58, 0x04, 0x23, 0x66, 0x39, 0xDB, 0x16, 0x77, 0xA3, 0x43, 0xEE, 0x61, 0x5C, 0x7F, 0xBA, 0x35,
|
||||
0x78, 0xD2, 0x3C, 0x79, 0x61, 0x9E, 0xFC, 0xB1, 0x7B, 0x2E, 0x1C, 0x45, 0xF9, 0xDA, 0xE2, 0x98,
|
||||
0xF6, 0x10, 0x58, 0xBB, 0x6D, 0x2F, 0x7D, 0x18, 0x20, 0xD2, 0x83, 0xCB, 0x00, 0xF4, 0x63, 0x58,
|
||||
0xFF, 0x4A, 0xEE, 0x88, 0x7A, 0x09, 0xAA, 0xA2, 0xAD, 0x73, 0x54, 0xD8, 0xEE, 0xFD, 0x81, 0xA3,
|
||||
0xF2, 0xCE, 0x65, 0x18, 0x48, 0x97, 0xC3, 0x92, 0x37, 0x8B, 0x75, 0xC1, 0x61, 0x19, 0x31, 0x64,
|
||||
0x6C, 0x00, 0xE3, 0xCD, 0x5D, 0x49, 0x13, 0xD5, 0x1C, 0xB4, 0xF0, 0x1B, 0x08, 0x8A, 0x4F, 0x39,
|
||||
0xCE, 0x9A, 0x38, 0xAD, 0x62, 0x72, 0xC5, 0x23, 0xC8, 0x4A, 0x67, 0x89, 0xC0, 0x6E, 0x10, 0x0D,
|
||||
0x0D, 0x7C, 0x64, 0x9A, 0xA1, 0xB6, 0x1D, 0x3E, 0x37, 0xD7, 0xBC, 0xD9, 0x54, 0xFA, 0x4B, 0x62,
|
||||
0x79, 0xD5, 0xB0, 0x8B, 0x1C, 0x56, 0xCC, 0x75, 0x7D, 0x1F, 0xF4, 0xA3, 0x4E, 0x29, 0xAF, 0x48,
|
||||
0xA4, 0x53, 0xD1, 0x83, 0xC4, 0x86, 0xA2, 0x41, 0xBE, 0x91, 0x40, 0x44, 0x72, 0x4A, 0x33, 0x5D,
|
||||
0xC7, 0xCA, 0xD2, 0x0B, 0x28, 0x49, 0x7A, 0xB2, 0x73, 0x95, 0x49, 0x6B, 0x25, 0x06, 0xFE, 0xC8,
|
||||
0xD7, 0xF0, 0xC7, 0xA1, 0xD0, 0xA3, 0x83, 0x9B, 0x49, 0x2B, 0x83, 0xA4, 0x23, 0x64, 0x83, 0xA9,
|
||||
0x37, 0xE4, 0xBB, 0xA8, 0x2D, 0x2F, 0xCB, 0xB4, 0x16, 0x50, 0x70, 0x71, 0x83, 0xBB, 0x11, 0x30,
|
||||
0x52, 0x5A, 0xC4, 0x9E, 0x94, 0xA8, 0xC7, 0x8F, 0x10, 0x1F, 0x53, 0x4A, 0x20, 0x06, 0x20, 0xA6,
|
||||
0x40, 0xD0, 0xA7, 0x42, 0x8A, 0x54, 0xE6, 0x92, 0x53, 0x2A, 0x20, 0xCA, 0x48, 0xCD, 0xE2, 0xC1,
|
||||
0x85, 0x78, 0xD4, 0x46, 0xD6, 0x80, 0xFD, 0xDC, 0xBD, 0x73, 0x33, 0xDE, 0x90, 0x68, 0x09, 0x56,
|
||||
0x36, 0x3D, 0x9A, 0xA6, 0x52, 0x5C, 0x54, 0xC7, 0x19, 0xF8, 0xA8, 0xA1, 0x03, 0x5A, 0x23, 0x84,
|
||||
0x11, 0x1E, 0x84, 0x8A, 0x01, 0x40, 0x7F, 0x42, 0xC3, 0x1C, 0x22, 0x70, 0x08, 0x20, 0x82, 0xA0,
|
||||
0x7F, 0x49, 0x0D, 0xF7, 0x64, 0x05, 0xC9, 0xF8, 0xD8, 0x6D, 0x35, 0xF0, 0x9D, 0x66, 0x95, 0xEC,
|
||||
0x20, 0xA5, 0xBD, 0x68, 0x24, 0xFA, 0x64, 0x98, 0x1A, 0x50, 0x00, 0xAC, 0xD9, 0x01, 0xA0, 0x1E,
|
||||
0x24, 0x5E, 0x63, 0x2B, 0x3F, 0xEF, 0x04, 0x2A, 0xBB, 0x00, 0xAB, 0xBB, 0x8E, 0x87, 0x5F, 0x39,
|
||||
0x4F, 0x19, 0xA7, 0x39, 0x26, 0x00, 0x7B, 0x93, 0x68, 0x7A, 0x99, 0x30, 0x2E, 0xCE, 0x64, 0x1B,
|
||||
0x6A, 0x6C, 0xB4, 0xE4, 0xF5, 0xA9, 0x87, 0x15, 0x79, 0x3F, 0xC5, 0x8B, 0xCB, 0x0C, 0xF3, 0xBA,
|
||||
0x53, 0x79, 0x77, 0xB1, 0x86, 0x70, 0x21, 0x50, 0x66, 0x38, 0xB3, 0x29, 0x74, 0xB0, 0xFA, 0xA1,
|
||||
0x48, 0x82, 0x7A, 0x4F, 0xB7, 0x42, 0xE2, 0xC1, 0x44, 0xED, 0x81, 0xF9, 0xDC, 0xC2, 0xD8, 0xE1,
|
||||
0x94, 0x83, 0x5A, 0x0A, 0xB5, 0x02, 0x45, 0xC6, 0x95, 0xCD, 0x98, 0x35, 0x1D, 0x6A, 0x58, 0x88,
|
||||
0x61, 0xE0, 0xAF, 0xFE, 0x05, 0x0F, 0x1E, 0x1C, 0xC8, 0x55, 0x3F, 0xE1, 0x23, 0xE3, 0x7E, 0xF4,
|
||||
0x23, 0x3E, 0x3E, 0xAF, 0xF0, 0xF1, 0x79, 0x1D, 0x1F, 0xB4, 0xAA, 0x3C, 0x98, 0x0C, 0x80, 0xEC,
|
||||
0x19, 0xE1, 0x64, 0x4C, 0x13, 0x58, 0xC0, 0x43, 0x50, 0x25, 0x7F, 0x8B, 0xB3, 0x84, 0xFE, 0x98,
|
||||
0xB3, 0xDE, 0x84, 0x8D, 0xC4, 0x23, 0xFE, 0x8A, 0xD5, 0xFF, 0x82, 0x4B, 0x3C, 0x70, 0x3D, 0x97,
|
||||
0x79, 0x6D, 0x5A, 0x49, 0x28, 0x3F, 0x7E, 0x2B, 0x91, 0x7E, 0xE4, 0x42, 0x78, 0xA9, 0x38, 0xC8,
|
||||
0xDF, 0xB7, 0xF4, 0x00, 0xBC, 0x11, 0xF8, 0x29, 0x35, 0x75, 0xBC, 0x0B, 0xA5, 0xFC, 0x29, 0x30,
|
||||
0x64, 0xA8, 0xC0, 0x47, 0xDD, 0xD9, 0xDC, 0x12, 0xAE, 0x01, 0x8A, 0xF1, 0xA3, 0x29, 0xB0, 0xEA,
|
||||
0xC9, 0x02, 0xD7, 0x9E, 0x40, 0x26, 0x04, 0x91, 0xE0, 0x48, 0xC8, 0xA7, 0x8D, 0x2F, 0x07, 0x9B,
|
||||
0x37, 0x35, 0xC8, 0x43, 0x2E, 0xFC, 0x98, 0x2E, 0x0C, 0x36, 0x6F, 0xFE, 0x6D, 0x36, 0xC6, 0xCC,
|
||||
0x5A, 0x76, 0xA4, 0x96, 0x4C, 0xF6, 0xF4, 0x0B, 0xBF, 0x71, 0x09, 0x48, 0x5D, 0x49, 0x78, 0x45,
|
||||
0x34, 0x03, 0x6B, 0x43, 0x61, 0xE1, 0x07, 0xFF, 0x47, 0x09, 0xF8, 0x91, 0x9E, 0x07, 0xCE, 0xBD,
|
||||
0xE6, 0x3D, 0x5E, 0x2F, 0x3E, 0x85, 0xE9, 0x56, 0xE9, 0xC1, 0x4A, 0xC7, 0xEF, 0x53, 0x3A, 0x76,
|
||||
0x59, 0xA2, 0x14, 0x4A, 0x14, 0x59, 0x88, 0x1A, 0x6A, 0x50, 0x0E, 0x51, 0x98, 0x89, 0x17, 0xCD,
|
||||
0x81, 0x02, 0x9B, 0x73, 0x34, 0x5B, 0x3A, 0x02, 0x0F, 0xF4, 0xF5, 0x45, 0xEE, 0xFC, 0x74, 0x76,
|
||||
0x7A, 0x22, 0x44, 0x7C, 0xA5, 0x62, 0x22, 0xD0, 0xAA, 0x2E, 0x2C, 0x2F, 0xCF, 0x9C, 0x89, 0xE4,
|
||||
0xA1, 0x28, 0x75, 0x30, 0x31, 0x28, 0x87, 0xFE, 0x74, 0x31, 0xFC, 0x0A, 0x71, 0xD6, 0xD0, 0xCF,
|
||||
0x52, 0x48, 0x58, 0x5B, 0x36, 0xA2, 0xF7, 0xFB, 0x97, 0xF6, 0xAE, 0xDD, 0x84, 0xBA, 0x00, 0xB4,
|
||||
0x0A, 0x69, 0x19, 0xEE, 0x7D, 0xFE, 0xB7, 0x90, 0xB7, 0xFF, 0x1E, 0x32, 0x83, 0xA8, 0x95, 0x42,
|
||||
0x58, 0x2A, 0xF0, 0xAB, 0xB8, 0x93, 0x24, 0x9A, 0x4A, 0xB4, 0xE3, 0x24, 0xC1, 0x4B, 0xE9, 0x43,
|
||||
0x85, 0xA2, 0x0D, 0x61, 0x31, 0xA5, 0x89, 0xE6, 0x47, 0x34, 0xD5, 0x78, 0x24, 0xB4, 0x34, 0x8B,
|
||||
0x63, 0x68, 0x5C, 0x56, 0xF4, 0x61, 0xEB, 0xC5, 0xEB, 0xCB, 0xFB, 0x8C, 0x66, 0xD4, 0xCF, 0x97,
|
||||
0x69, 0x52, 0xD1, 0x0B, 0x56, 0x50, 0xDF, 0x10, 0xEE, 0x7E, 0xB9, 0xC9, 0xEB, 0xA9, 0x8C, 0x73,
|
||||
0x8C, 0xA2, 0x1B, 0x2D, 0x35, 0x07, 0xE9, 0x26, 0x40, 0xD5, 0xE5, 0x59, 0x10, 0xCC, 0xDB, 0x2B,
|
||||
0xB4, 0xA0, 0xF1, 0x8A, 0x44, 0x24, 0x9F, 0xCB, 0x67, 0x7F, 0xE4, 0xC9, 0xA9, 0xE2, 0x82, 0x50,
|
||||
0xF2, 0x54, 0xA9, 0x36, 0xAD, 0x0D, 0x63, 0x83, 0x6A, 0x8C, 0xA7, 0x82, 0x70, 0x0F, 0xAF, 0x51,
|
||||
0xE9, 0xC2, 0x2C, 0x6A, 0x29, 0xDC, 0xDE, 0x46, 0x5F, 0xCB, 0x6D, 0xE9, 0x89, 0x7C, 0x2A, 0x25,
|
||||
0xE3, 0xAE, 0xAE, 0x63, 0x55, 0x45, 0xB1, 0x3E, 0x25, 0x61, 0x5A, 0x26, 0x5B, 0x54, 0x06, 0x26,
|
||||
0x77, 0x0B, 0x70, 0x9B, 0x06, 0x29, 0x1C, 0xBD, 0x7E, 0x7F, 0xCE, 0x46, 0xD1, 0xCE, 0x11, 0x80,
|
||||
0x69, 0xC5, 0x3E, 0x93, 0xD7, 0xE0, 0x24, 0xCC, 0x73, 0x07, 0x32, 0xE9, 0x4A, 0x03, 0x0E, 0xA9,
|
||||
0x98, 0x44, 0xFE, 0x81, 0x7E, 0xA0, 0x3B, 0x3A, 0xFC, 0xBB, 0x09, 0x35, 0x47, 0xCD, 0xA5, 0xD0,
|
||||
0xA4, 0xFA, 0x74, 0x70, 0xF5, 0x06, 0xC2, 0x53, 0x0C, 0xA5, 0x01, 0x17, 0x50, 0x34, 0xD7, 0x74,
|
||||
0x7C, 0x7A, 0x7D, 0x0C, 0x29, 0xC8, 0x7F, 0x21, 0x37, 0x66, 0xBB, 0xAA, 0x6C, 0xB8, 0xF3, 0xEA,
|
||||
0x75, 0x56, 0x2E, 0x03, 0x7A, 0x61, 0x8C, 0x58, 0x0F, 0x29, 0x7E, 0xFB, 0x7B, 0xF4, 0x9E, 0x8D,
|
||||
0x15, 0xD2, 0x6A, 0x5D, 0x6F, 0xCE, 0x76, 0x90, 0x67, 0x89, 0xD5, 0x43, 0x2C, 0x70, 0x97, 0x1F,
|
||||
0x29, 0x59, 0x95, 0x35, 0xDC, 0xF6, 0x48, 0x10, 0xE0, 0xC7, 0x5A, 0x03, 0x1B, 0x6A, 0x22, 0xB2,
|
||||
0xD4, 0x42, 0x22, 0x29, 0x08, 0x90, 0xD2, 0x3E, 0x84, 0x39, 0xD3, 0x92, 0x65, 0x86, 0xB2, 0xA1,
|
||||
0xBC, 0xFF, 0xC5, 0x9A, 0xA3, 0x64, 0x46, 0xE8, 0xCE, 0xF9, 0x6C, 0x73, 0x53, 0xD8, 0x85, 0x99,
|
||||
0x18, 0x05, 0x52, 0x8A, 0x01, 0x1C, 0x9A, 0x7D, 0x68, 0x2D, 0x8C, 0xB2, 0x90, 0x58, 0xAB, 0x3D,
|
||||
0xD2, 0xB6, 0x51, 0x55, 0x03, 0x54, 0x7C, 0x46, 0x01, 0x03, 0xCE, 0xB2, 0x24, 0x80, 0xA8, 0x8B,
|
||||
0x39, 0xBA, 0xB2, 0x2D, 0xC5, 0xBA, 0xD0, 0x84, 0x0E, 0xEC, 0x67, 0xC8, 0x12, 0x95, 0x97, 0xAD,
|
||||
0xA2, 0x27, 0x12, 0xC5, 0x77, 0x95, 0x9E, 0xC8, 0x6F, 0xE5, 0x84, 0xAA, 0xC8, 0x77, 0x88, 0x2F,
|
||||
0x13, 0x5C, 0xD4, 0xD1, 0x13, 0xA0, 0x24, 0x83, 0x52, 0x34, 0x60, 0x2A, 0x2C, 0x37, 0xEE, 0xEB,
|
||||
0xD3, 0xE9, 0xB4, 0x8E, 0xDF, 0x6A, 0xEB, 0x70, 0x82, 0xB2, 0x02, 0x5F, 0x5F, 0xC7, 0x21, 0x47,
|
||||
0x15, 0x58, 0xF8, 0x6E, 0xE1, 0xAC, 0xBA, 0xE8, 0x42, 0x7F, 0x2B, 0xDE, 0xD4, 0xAA, 0xD2, 0x59,
|
||||
0xE1, 0x73, 0x79, 0xDB, 0x7B, 0x3B, 0x2B, 0x20, 0x32, 0xC4, 0xAF, 0xB2, 0x90, 0x69, 0x20, 0x0D,
|
||||
0x3B, 0xE5, 0x46, 0x56, 0x25, 0x85, 0x65, 0x5C, 0xB0, 0xE3, 0x2C, 0x9D, 0x18, 0x33, 0x60, 0xDD,
|
||||
0x11, 0x96, 0xD2, 0x95, 0x43, 0x2D, 0x65, 0xB7, 0x0E, 0xB7, 0x0A, 0xFB, 0x70, 0x30, 0x83, 0x94,
|
||||
0x79, 0xFB, 0xF3, 0x4F, 0x39, 0x5B, 0xDE, 0xF6, 0x92, 0x62, 0x71, 0xE1, 0xF3, 0xFC, 0xA9, 0x35,
|
||||
0xAF, 0x69, 0xA5, 0xD1, 0xAF, 0xC4, 0x97, 0xBD, 0x46, 0xFE, 0x19, 0x3B, 0xFF, 0x9C, 0xAD, 0x81,
|
||||
0xB1, 0x43, 0x23, 0x2A, 0xDC, 0x4C, 0x8C, 0xEA, 0x2F, 0x34, 0xE6, 0x63, 0x79, 0x29, 0xBF, 0x2D,
|
||||
0xA0, 0x54, 0xA9, 0xD3, 0x68, 0x78, 0x3E, 0xFF, 0x9A, 0x42, 0x19, 0x1D, 0x65, 0xFE, 0x28, 0x20,
|
||||
0x09, 0xC5, 0x82, 0xA3, 0x41, 0xBE, 0x92, 0xFB, 0x46, 0xC0, 0x86, 0x69, 0x03, 0x93, 0x6D, 0xCB,
|
||||
0xDE, 0xB2, 0x77, 0x71, 0x64, 0x7F, 0x4D, 0xF7, 0x57, 0x4F, 0xD8, 0x5F, 0x34, 0x69, 0x58, 0x0B,
|
||||
0xE7, 0xB5, 0xAB, 0x8A, 0x4D, 0x6A, 0x83, 0xFB, 0xC4, 0xA7, 0x70, 0x3D, 0x6F, 0xB3, 0xCC, 0xB6,
|
||||
0x1A, 0xE4, 0x5F, 0x60, 0xD4, 0x31, 0xBA, 0x95, 0x2F, 0x92, 0xF4, 0x81, 0x7B, 0x18, 0x5B, 0x17,
|
||||
0x54, 0x26, 0x70, 0x49, 0xD5, 0x87, 0x34, 0xB9, 0xD3, 0x9C, 0x2F, 0x39, 0xC3, 0xB7, 0x3C, 0xA8,
|
||||
0x03, 0xE4, 0x37, 0x9C, 0x72, 0x39, 0xB0, 0xBF, 0x07, 0x5D, 0x33, 0x2A, 0x41, 0x79, 0xB1, 0x26,
|
||||
0x9B, 0xE6, 0x7C, 0x02, 0x82, 0x01, 0x70, 0xB1, 0xA3, 0x48, 0xCD, 0x2B, 0xCB, 0x98, 0x9B, 0x57,
|
||||
0x96, 0x54, 0xE2, 0x5F, 0x59, 0xCC, 0xDB, 0x9F, 0xFC, 0xDB, 0x4C, 0xF9, 0x7F, 0x5B, 0x28, 0x36,
|
||||
0x32, 0xF9, 0xE1, 0x09, 0xF7, 0x56, 0x3F, 0x45, 0xAD, 0x47, 0x51, 0xBB, 0xF7, 0xFF, 0x17, 0x53,
|
||||
0xE8, 0x9D, 0x36, 0x92, 0x29, 0x00, 0x00};
|
||||
|
||||
#define SPIFFS_MAXLENGTH_FILEPATH 32
|
||||
const char *excludeListFile = "/.exclude.files";
|
||||
|
||||
typedef struct ExcludeListS {
|
||||
char *item;
|
||||
ExcludeListS *next;
|
||||
} ExcludeList;
|
||||
|
||||
static ExcludeList *excludes = NULL;
|
||||
|
||||
static bool matchWild(const char *pattern, const char *testee) {
|
||||
const char *nxPat = NULL;
|
||||
const char *nxTst = NULL;
|
||||
|
||||
while (*testee) {
|
||||
if ((*pattern == '?') || (*pattern == *testee)) {
|
||||
++pattern;
|
||||
++testee;
|
||||
continue;
|
||||
}
|
||||
if (*pattern == '*') {
|
||||
nxPat = pattern++;
|
||||
nxTst = testee;
|
||||
continue;
|
||||
}
|
||||
if (nxPat) {
|
||||
pattern = nxPat + 1;
|
||||
testee = ++nxTst;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
while (*pattern == '*') {
|
||||
++pattern;
|
||||
}
|
||||
return (*pattern == 0);
|
||||
}
|
||||
|
||||
static bool addExclude(const char *item) {
|
||||
size_t len = strlen(item);
|
||||
if (!len) {
|
||||
return false;
|
||||
}
|
||||
ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList));
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
e->item = (char *)malloc(len + 1);
|
||||
if (!e->item) {
|
||||
free(e);
|
||||
return false;
|
||||
}
|
||||
memcpy(e->item, item, len + 1);
|
||||
e->next = excludes;
|
||||
excludes = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void loadExcludeList(fs::FS &_fs, const char *filename) {
|
||||
static char linebuf[SPIFFS_MAXLENGTH_FILEPATH];
|
||||
fs::File excludeFile;
|
||||
if (filename[0] != '/') {
|
||||
excludeFile = _fs.open("/" + ((String)filename), "r");
|
||||
} else {
|
||||
excludeFile = _fs.open(filename, "r");
|
||||
}
|
||||
if (!excludeFile) {
|
||||
// addExclude("/*.js.gz");
|
||||
return;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (excludeFile.isDirectory()) {
|
||||
excludeFile.close();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (excludeFile.size() > 0) {
|
||||
uint8_t idx;
|
||||
bool isOverflowed = false;
|
||||
while (excludeFile.available()) {
|
||||
linebuf[0] = '\0';
|
||||
idx = 0;
|
||||
int lastChar;
|
||||
do {
|
||||
lastChar = excludeFile.read();
|
||||
if (lastChar != '\r') {
|
||||
linebuf[idx++] = (char)lastChar;
|
||||
}
|
||||
} while ((lastChar >= 0) && (lastChar != '\n') && (idx < SPIFFS_MAXLENGTH_FILEPATH));
|
||||
|
||||
if (isOverflowed) {
|
||||
isOverflowed = (lastChar != '\n');
|
||||
continue;
|
||||
}
|
||||
isOverflowed = (idx >= SPIFFS_MAXLENGTH_FILEPATH);
|
||||
linebuf[idx - 1] = '\0';
|
||||
if (!addExclude(linebuf)) {
|
||||
excludeFile.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
excludeFile.close();
|
||||
}
|
||||
|
||||
static bool isExcluded(fs::FS &_fs, const char *filename) {
|
||||
if (excludes == NULL) {
|
||||
loadExcludeList(_fs, excludeListFile);
|
||||
}
|
||||
ExcludeList *e = excludes;
|
||||
while (e) {
|
||||
if (matchWild(e->item, filename)) {
|
||||
return true;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// WEB HANDLER IMPLEMENTATION
|
||||
|
||||
#ifdef ESP32
|
||||
SPIFFSEditor::SPIFFSEditor(const fs::FS &fs, const String &username, const String &password)
|
||||
#else
|
||||
SPIFFSEditor::SPIFFSEditor(const String &username, const String &password, const fs::FS &fs)
|
||||
#endif
|
||||
: _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) {
|
||||
}
|
||||
|
||||
@@ -406,24 +19,20 @@ bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) {
|
||||
if (!request->_tempFile) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (request->_tempFile.isDirectory()) {
|
||||
request->_tempFile.close();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (request->hasParam("download")) {
|
||||
request->_tempFile = _fs.open("/" + request->arg("download"), "r");
|
||||
if (!request->_tempFile) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (request->_tempFile.isDirectory()) {
|
||||
request->_tempFile.close();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
request->addInterestingHeader("If-Modified-Since");
|
||||
return true;
|
||||
@@ -442,46 +51,22 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (request->method() == HTTP_GET) {
|
||||
if (request->hasParam("list")) {
|
||||
const String path = request->getParam("list")->value();
|
||||
#ifdef ESP32
|
||||
|
||||
File dir = _fs.open(path);
|
||||
#else
|
||||
Dir dir = _fs.openDir(path);
|
||||
#endif
|
||||
String output = "[";
|
||||
#ifdef ESP32
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
#else
|
||||
while (dir.next()) {
|
||||
fs::File entry = dir.openFile("r");
|
||||
#endif
|
||||
if (isExcluded(_fs, file.name())) {
|
||||
#ifdef ESP32
|
||||
file = dir.openNextFile();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
output += "{\"type\":\"";
|
||||
output += "file";
|
||||
output += "\",\"name\":\"";
|
||||
output += file.name();
|
||||
output += "\",\"size\":";
|
||||
output += file.size();
|
||||
output += ",\"ver\":";
|
||||
output += file.getLastWrite();
|
||||
output += "}";
|
||||
#ifdef ESP32
|
||||
if (file.isDirectory()) {
|
||||
output += "{\"type\":\"dir\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
} else {
|
||||
output += "{\"type\":\"file\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
#else
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
#ifdef ESP32
|
||||
dir.close();
|
||||
#endif
|
||||
output += "]";
|
||||
request->send(200, "application/json", output);
|
||||
} else if (request->hasParam("edit") || request->hasParam("download")) {
|
||||
@@ -491,8 +76,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (request->header("If-Modified-Since").equals(buildTime)) {
|
||||
request->send(304);
|
||||
} else {
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
AsyncWebServerResponse *response = request->beginResponse(_fs, "/www/edit.html");
|
||||
response->addHeader("Last-Modified", buildTime);
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
246
esp32_fw/src/contentmanager.cpp
Normal file
246
esp32_fw/src/contentmanager.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "contentmanager.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "newproto.h"
|
||||
#include <MD5Builder.h>
|
||||
#include <locale.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "commstructs.h"
|
||||
#include "makeimage.h"
|
||||
#include "web.h"
|
||||
|
||||
void contentRunner() {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
|
||||
if (now >= taginfo->nextupdate || taginfo->button) {
|
||||
uint8_t mac8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
memcpy(mac8 + 2, taginfo->mac, 6);
|
||||
uint8_t src[8];
|
||||
*((uint64_t *)src) = swap64(*((uint64_t *)mac8));
|
||||
|
||||
drawNew(src, taginfo->button, taginfo);
|
||||
taginfo->button = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
char buffer[64];
|
||||
uint8_t src[8];
|
||||
*((uint64_t *)src) = swap64(*((uint64_t *)mac));
|
||||
sprintf(buffer, "%02X%02X%02X%02X%02X%02X\0", src[2], src[3], src[4], src[5], src[6], src[7]);
|
||||
String dst = (String)buffer;
|
||||
|
||||
String filename = "/" + dst + ".bmp";
|
||||
|
||||
struct tm time_info;
|
||||
getLocalTime(&time_info);
|
||||
time_info.tm_hour = 0;
|
||||
time_info.tm_min = 0;
|
||||
time_info.tm_sec = 0;
|
||||
time_info.tm_mday++;
|
||||
time_t midnight = mktime(&time_info);
|
||||
|
||||
DynamicJsonDocument doc(500);
|
||||
deserializeJson(doc, taginfo->modeConfigJson);
|
||||
JsonObject cfgobj = doc.as<JsonObject>();
|
||||
|
||||
wsLog("Updating " + dst + " mode " + String(taginfo->contentMode));
|
||||
taginfo->nextupdate = now + 600;
|
||||
|
||||
switch (taginfo->contentMode) {
|
||||
case Image:
|
||||
|
||||
filename = cfgobj["filename"].as<String>();
|
||||
if (filename && filename !="null" && !cfgobj["#fetched"].as<bool>()) {
|
||||
if (prepareDataAvail(&filename, DATATYPE_IMGRAW, mac, cfgobj["timetolive"].as<int>())) {
|
||||
cfgobj["#fetched"] = true;
|
||||
} else {
|
||||
wsErr("Error accessing " + filename);
|
||||
}
|
||||
taginfo->nextupdate = 3216153600;
|
||||
}
|
||||
break;
|
||||
|
||||
case Today:
|
||||
|
||||
drawDate(filename);
|
||||
// updateTagImage(filename, mac, (midnight - now) / 60 - 10);
|
||||
updateTagImage(filename, mac, 60);
|
||||
taginfo->nextupdate = midnight;
|
||||
break;
|
||||
|
||||
case CountDays:
|
||||
|
||||
if (buttonPressed) cfgobj["counter"] = 0;
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"]);
|
||||
updateTagImage(filename, mac, (buttonPressed?0:60));
|
||||
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
|
||||
taginfo->nextupdate = midnight;
|
||||
break;
|
||||
|
||||
case CountHours:
|
||||
|
||||
if (buttonPressed) cfgobj["counter"] = 0;
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"]);
|
||||
// updateTagImage(&filename, mac, (3600 - now % 3600) / 60);
|
||||
// taginfo->nextupdate = now + 3600 - (now % 3600);
|
||||
updateTagImage(filename, mac, (buttonPressed?0:3));
|
||||
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
|
||||
taginfo->nextupdate = now + 300;
|
||||
break;
|
||||
|
||||
case Weather:
|
||||
|
||||
// https://open-meteo.com/
|
||||
break;
|
||||
|
||||
case Firmware:
|
||||
|
||||
filename = cfgobj["filename"].as<String>();
|
||||
if (filename && filename != "null" && !cfgobj["#fetched"].as<bool>()) {
|
||||
if (prepareDataAvail(&filename, DATATYPE_UPDATE, mac, cfgobj["timetolive"].as<int>())) {
|
||||
cfgobj["#fetched"] = true;
|
||||
} else {
|
||||
wsErr("Error accessing " + filename);
|
||||
}
|
||||
cfgobj["filename"]="";
|
||||
taginfo->nextupdate = 3216153600;
|
||||
taginfo->contentMode = Image;
|
||||
} else {
|
||||
taginfo->nextupdate = now + 300;
|
||||
}
|
||||
break;
|
||||
|
||||
case Memo:
|
||||
break;
|
||||
case ImageUrl:
|
||||
|
||||
if (getImgURL(filename, cfgobj["url"], (time_t)cfgobj["#fetched"])) {
|
||||
updateTagImage(filename, mac, cfgobj["interval"].as<int>());
|
||||
cfgobj["#fetched"] = now;
|
||||
}
|
||||
taginfo->nextupdate = now + 60 * (cfgobj["interval"].as<int>() < 5 ? 5 : cfgobj["interval"].as<int>()) ;
|
||||
break;
|
||||
}
|
||||
|
||||
taginfo->modeConfigJson = doc.as<String>();
|
||||
}
|
||||
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin) {
|
||||
prepareDataAvail(&filename, DATATYPE_IMGRAW, dst, nextCheckin);
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawDate(String &filename) {
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
time_t now;
|
||||
time(&now);
|
||||
struct tm timeinfo;
|
||||
localtime_r(&now, &timeinfo);
|
||||
String Dag[] = {"zondag","maandag","dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"};
|
||||
String Maand[] = {"januari", "februari", "maart", "april", "mei", "juni","juli", "augustus", "september", "oktober", "november", "december"};
|
||||
int weekday_number = timeinfo.tm_wday;
|
||||
int month_number = timeinfo.tm_mon;
|
||||
|
||||
LittleFS.begin();
|
||||
long w = 296, h = 128; // mag staand of liggend
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawDate");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TC_DATUM);
|
||||
spr.loadFont("fonts/calibrib62", LittleFS);
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.drawString(Dag[timeinfo.tm_wday], w / 2, 10);
|
||||
spr.loadFont("fonts/calibrib50", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(String(timeinfo.tm_mday) + " " + Maand[timeinfo.tm_mon], w / 2, 73);
|
||||
spr.unloadFont();
|
||||
|
||||
spr2grays(spr, w, h, filename);
|
||||
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
LittleFS.begin();
|
||||
long w = 296, h = 128;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawNumber");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(MC_DATUM);
|
||||
if (count > thresholdred) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
String font = "fonts/numbers1-2";
|
||||
if (count > 999) font = "fonts/numbers2-2";
|
||||
if (count > 9999) font = "fonts/numbers3-2";
|
||||
spr.loadFont(font, LittleFS);
|
||||
spr.drawString(String(count), w/2, h/2+10);
|
||||
spr.unloadFont();
|
||||
|
||||
spr2grays(spr, w, h, filename);
|
||||
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
bool getImgURL(String &filename, String URL, time_t fetched) {
|
||||
// https://images.klari.net/kat-bw29.jpg
|
||||
|
||||
LittleFS.begin();
|
||||
|
||||
Serial.println("get external " + URL);
|
||||
HTTPClient http;
|
||||
http.begin(URL);
|
||||
http.addHeader("If-Modified-Since", formatHttpDate(fetched));
|
||||
http.setTimeout(5000); //timeout in ms
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
File f = LittleFS.open(filename, "w");
|
||||
if (f) {
|
||||
http.writeToStream(&f);
|
||||
f.close();
|
||||
jpg2grays(filename, filename);
|
||||
}
|
||||
} else {
|
||||
if (httpCode!=304) {
|
||||
wsErr("http " + URL + " " + String(httpCode));
|
||||
} else {
|
||||
wsLog("http " + URL + " " + String(httpCode));
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
return (httpCode == 200);
|
||||
}
|
||||
|
||||
char *formatHttpDate(time_t t) {
|
||||
static char buf[40];
|
||||
struct tm *timeinfo;
|
||||
timeinfo = gmtime(&t);
|
||||
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", timeinfo);
|
||||
return buf;
|
||||
}
|
||||
@@ -3,50 +3,44 @@
|
||||
#include <WiFiManager.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "contentmanager.h"
|
||||
#include "flasher.h"
|
||||
#include "makeimage.h"
|
||||
#include "pendingdata.h"
|
||||
#include "serial.h"
|
||||
#include "soc/rtc_wdt.h"
|
||||
#include "tag_db.h"
|
||||
#include "web.h"
|
||||
|
||||
void freeHeapTask(void* parameter) {
|
||||
void timeTask(void* parameter) {
|
||||
while (1) {
|
||||
//Serial.printf("Free heap=%d\n", ESP.getFreeHeap());
|
||||
vTaskDelay(30000 / portTICK_PERIOD_MS);
|
||||
time_t now;
|
||||
time(&now);
|
||||
tm tm;
|
||||
if (!getLocalTime(&tm)) {
|
||||
Serial.println("Failed to obtain time");
|
||||
} else {
|
||||
if (now % 10 == 0) wsSendSysteminfo();
|
||||
contentRunner();
|
||||
}
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.print(">\n");
|
||||
|
||||
configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "europe.pool.ntp.org", "time.nist.gov");
|
||||
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
|
||||
|
||||
init_web();
|
||||
loadDB("/current/tagDB.json");
|
||||
|
||||
long timezone = 2;
|
||||
byte daysavetime = 1;
|
||||
configTime(0, 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct;
|
||||
delay(2000);
|
||||
tmstruct.tm_year = 0;
|
||||
getLocalTime(&tmstruct, 5000);
|
||||
Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
|
||||
Serial.println("");
|
||||
|
||||
// WiFiManager wm;
|
||||
xTaskCreate(freeHeapTask, "print free heap", 10000, NULL, 2, NULL);
|
||||
xTaskCreate(timeTask, "timed tasks", 10000, NULL, 2, NULL);
|
||||
xTaskCreate(zbsRxTask, "zbsRX Process", 10000, NULL, 2, NULL);
|
||||
xTaskCreate(garbageCollection, "pending-data cleanup", 5000, NULL, 1, NULL);
|
||||
xTaskCreate(webSocketSendProcess, "ws", 5000, NULL,configMAX_PRIORITIES-10, NULL);
|
||||
|
||||
/*
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
wm.setConfigPortalTimeout(180);
|
||||
bool res = wm.autoConnect("ESP32ZigbeeBase", "password"); // password protected ap
|
||||
if (!res) {
|
||||
Serial.println("Failed to connect");
|
||||
ESP.restart();
|
||||
}
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
*/
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
430
esp32_fw/src/makeimage.cpp
Normal file
430
esp32_fw/src/makeimage.cpp
Normal file
@@ -0,0 +1,430 @@
|
||||
#include <Arduino.h>
|
||||
#include <FS.h>
|
||||
#include <LittleFS.h>
|
||||
#include <TFT_eSPI.h>
|
||||
#include <TJpg_Decoder.h>
|
||||
#include <makeimage.h>
|
||||
#include <web.h>
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
bool spr_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) {
|
||||
spr.pushImage(x, y, w, h, bitmap);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void jpg2grays(String filein, String fileout) {
|
||||
TJpgDec.setJpgScale(1);
|
||||
TJpgDec.setCallback(spr_output);
|
||||
uint16_t w = 0, h = 0;
|
||||
TJpgDec.getFsJpgSize(&w, &h, filein);
|
||||
Serial.println("jpeg conversion " + String(w) + "x" + String(h));
|
||||
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in jpg2grays");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
TJpgDec.drawFsJpg(0, 0, filein);
|
||||
|
||||
spr2grays(spr, w, h, fileout);
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
static uint32_t repackPackedVals(uint32_t val, uint32_t pixelsPerPackedUnit, uint32_t packedMultiplyVal) {
|
||||
uint32_t ret = 0, i;
|
||||
for (i = 0; i < pixelsPerPackedUnit; i++) {
|
||||
ret = ret * packedMultiplyVal + val % packedMultiplyVal;
|
||||
val /= packedMultiplyVal;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) {
|
||||
// based on bmp2grays function by Dmitry.GR
|
||||
|
||||
long t = millis();
|
||||
LittleFS.begin();
|
||||
|
||||
fs::File f_out = LittleFS.open(fileout, "w");
|
||||
|
||||
uint32_t c, rowBytesOut, rowBytesIn, outBpp, i, numRows, pixelsPerPackedUnit = 1, packedMultiplyVal = 0x01000000, packedOutBpp = 0;
|
||||
uint32_t numGrays, extraColor = 0;
|
||||
struct BitmapFileHeader hdr;
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
enum EinkClut clutType;
|
||||
uint8_t clut[256][3];
|
||||
bool dither = false, rotated = false;
|
||||
int skipBytes;
|
||||
|
||||
clutType = EinkClutTwoBlacksAndRed;
|
||||
|
||||
if (w > h) {
|
||||
hdr.width = h;
|
||||
hdr.height = w;
|
||||
rotated = true;
|
||||
} else {
|
||||
hdr.width = w;
|
||||
hdr.height = h;
|
||||
}
|
||||
hdr.bpp = 24;
|
||||
hdr.sig[0] = 'B';
|
||||
hdr.sig[1] = 'M';
|
||||
hdr.colorplanes = 1;
|
||||
|
||||
switch (clutType) {
|
||||
case EinkClutTwoBlacks:
|
||||
numGrays = 2;
|
||||
outBpp = 1;
|
||||
break;
|
||||
|
||||
case EinkClutTwoBlacksAndRed:
|
||||
extraColor = 0xff0000;
|
||||
numGrays = 2;
|
||||
outBpp = 2;
|
||||
break;
|
||||
|
||||
case EinkClutFourBlacks:
|
||||
numGrays = 4;
|
||||
outBpp = 2;
|
||||
break;
|
||||
|
||||
case EinkClutThreeBlacksAndRed:
|
||||
numGrays = 3;
|
||||
extraColor = 0xff0000;
|
||||
outBpp = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
packedOutBpp = outBpp;
|
||||
|
||||
rowBytesIn = (hdr.width * hdr.bpp + 31) / 32 * 4;
|
||||
rowBytesOut = ((hdr.width + pixelsPerPackedUnit - 1) / pixelsPerPackedUnit) * packedOutBpp;
|
||||
rowBytesOut = (rowBytesOut + 31) / 32 * 4;
|
||||
|
||||
numRows = hdr.height < 0 ? -hdr.height : hdr.height;
|
||||
hdr.bpp = outBpp;
|
||||
hdr.numColors = 1 << outBpp;
|
||||
hdr.numImportantColors = 1 << outBpp;
|
||||
hdr.dataOfst = sizeof(struct BitmapFileHeader) + 4 * hdr.numColors;
|
||||
hdr.dataLen = numRows * rowBytesOut;
|
||||
hdr.fileSz = hdr.dataOfst + hdr.dataLen;
|
||||
hdr.headerSz = 40;
|
||||
hdr.compression = 0;
|
||||
|
||||
f_out.write((uint8_t *)&hdr, sizeof(hdr));
|
||||
|
||||
// emit & record grey clut entries
|
||||
for (i = 0; i < numGrays; i++) {
|
||||
uint32_t val = 255 * i / (numGrays - 1);
|
||||
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
|
||||
clut[i][0] = val;
|
||||
clut[i][1] = val;
|
||||
clut[i][2] = val;
|
||||
}
|
||||
|
||||
if (extraColor) {
|
||||
f_out.write((extraColor >> 0) & 0xff); // B
|
||||
f_out.write((extraColor >> 8) & 0xff); // G
|
||||
f_out.write((extraColor >> 16) & 0xff); // R
|
||||
f_out.write(0x00); // A
|
||||
|
||||
clut[i][0] = (extraColor >> 0) & 0xff;
|
||||
clut[i][1] = (extraColor >> 8) & 0xff;
|
||||
clut[i][2] = (extraColor >> 16) & 0xff;
|
||||
}
|
||||
|
||||
// pad clut to size
|
||||
for (i = numGrays + (extraColor ? 1 : 0); i < hdr.numColors; i++) {
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
}
|
||||
|
||||
while (numRows--) {
|
||||
uint32_t pixelValsPackedSoFar = 0, numPixelsPackedSoFar = 0, valSoFar = 0, bytesIn = 0, bytesOut = 0, bitsSoFar = 0;
|
||||
|
||||
for (c = 0; c < hdr.width; c++, bytesIn += 3) {
|
||||
int64_t bestDist = 0x7fffffffffffffffll;
|
||||
uint8_t bestIdx = 0;
|
||||
int32_t ditherFudge = 0;
|
||||
uint16_t color565;
|
||||
if (rotated) {
|
||||
color565 = spr.readPixel(hdr.height - 1 - numRows, c);
|
||||
} else {
|
||||
color565 = spr.readPixel(c, numRows);
|
||||
}
|
||||
|
||||
uint8_t red = ((color565 >> 11) & 0x1F) * 8;
|
||||
uint8_t green = ((color565 >> 5) & 0x3F) * 4;
|
||||
uint8_t blue = (color565 & 0x1F) * 8;
|
||||
|
||||
if (dither)
|
||||
ditherFudge = (rand() % 255 - 127) / (int)numGrays;
|
||||
|
||||
for (i = 0; i < hdr.numColors; i++) {
|
||||
int64_t dist = 0;
|
||||
|
||||
dist += (blue - clut[i][0] + ditherFudge) * (blue - clut[i][0] + ditherFudge) * 4750ll;
|
||||
dist += (green - clut[i][1] + ditherFudge) * (green - clut[i][1] + ditherFudge) * 47055ll;
|
||||
dist += (red - clut[i][2] + ditherFudge) * (red - clut[i][2] + ditherFudge) * 13988ll;
|
||||
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
bestIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// pack pixels as needed
|
||||
pixelValsPackedSoFar = pixelValsPackedSoFar * packedMultiplyVal + bestIdx;
|
||||
if (++numPixelsPackedSoFar != pixelsPerPackedUnit)
|
||||
continue;
|
||||
|
||||
numPixelsPackedSoFar = 0;
|
||||
|
||||
// it is easier to display when low val is first pixel. currently last pixel is low - reverse this
|
||||
pixelValsPackedSoFar = repackPackedVals(pixelValsPackedSoFar, pixelsPerPackedUnit, packedMultiplyVal);
|
||||
|
||||
valSoFar = (valSoFar << packedOutBpp) | pixelValsPackedSoFar;
|
||||
pixelValsPackedSoFar = 0;
|
||||
bitsSoFar += packedOutBpp;
|
||||
|
||||
if (bitsSoFar >= 8) {
|
||||
f_out.write(valSoFar >> (bitsSoFar -= 8));
|
||||
valSoFar &= (1 << bitsSoFar) - 1;
|
||||
bytesOut++;
|
||||
}
|
||||
}
|
||||
|
||||
// see if we have unfinished pixel packages to write
|
||||
if (numPixelsPackedSoFar) {
|
||||
while (numPixelsPackedSoFar++ != pixelsPerPackedUnit)
|
||||
pixelValsPackedSoFar *= packedMultiplyVal;
|
||||
|
||||
// it is easier to display when low val is first pixel. currently last pixel is low - reverse this
|
||||
pixelValsPackedSoFar = repackPackedVals(pixelValsPackedSoFar, pixelsPerPackedUnit, packedMultiplyVal);
|
||||
|
||||
valSoFar = (valSoFar << packedOutBpp) | pixelValsPackedSoFar;
|
||||
pixelValsPackedSoFar = 0;
|
||||
bitsSoFar += packedOutBpp;
|
||||
|
||||
if (bitsSoFar >= 8) {
|
||||
f_out.write(valSoFar >> (bitsSoFar -= 8));
|
||||
valSoFar &= (1 << bitsSoFar) - 1;
|
||||
bytesOut++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bitsSoFar) {
|
||||
valSoFar <<= 8 - bitsSoFar; // left-align it as is expected
|
||||
f_out.write(valSoFar);
|
||||
bytesOut++;
|
||||
}
|
||||
|
||||
while (bytesOut++ < rowBytesOut)
|
||||
f_out.write(0);
|
||||
}
|
||||
f_out.close();
|
||||
Serial.println(millis() - t);
|
||||
Serial.println("finished writing BMP");
|
||||
}
|
||||
|
||||
void bmp2grays(String filein, String fileout) {
|
||||
// based on bmp2grays function by Dmitry.GR
|
||||
|
||||
long t = millis();
|
||||
LittleFS.begin();
|
||||
|
||||
fs::File f_in = LittleFS.open(filein, "r");
|
||||
fs::File f_out = LittleFS.open(fileout, "w");
|
||||
|
||||
uint32_t c, rowBytesOut, rowBytesIn, outBpp, i, numRows, pixelsPerPackedUnit = 1, packedMultiplyVal = 0x01000000, packedOutBpp = 0;
|
||||
uint32_t numGrays, extraColor = 0;
|
||||
struct BitmapFileHeader hdr;
|
||||
enum EinkClut clutType;
|
||||
uint8_t clut[256][3];
|
||||
bool dither = false;
|
||||
int skipBytes;
|
||||
|
||||
clutType = EinkClutTwoBlacksAndRed;
|
||||
|
||||
f_in.read((uint8_t *)&hdr, sizeof(hdr));
|
||||
|
||||
if (hdr.sig[0] != 'B' || hdr.sig[1] != 'M' || hdr.headerSz < 40 || hdr.colorplanes != 1 || hdr.bpp != 24 || hdr.compression) {
|
||||
Serial.println("BITMAP HEADER INVALID, use uncompressed 24 bits RGB");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (clutType) {
|
||||
case EinkClutTwoBlacks:
|
||||
numGrays = 2;
|
||||
outBpp = 1;
|
||||
break;
|
||||
|
||||
case EinkClutTwoBlacksAndRed:
|
||||
extraColor = 0xff0000;
|
||||
numGrays = 2;
|
||||
outBpp = 2;
|
||||
break;
|
||||
|
||||
case EinkClutFourBlacks:
|
||||
numGrays = 4;
|
||||
outBpp = 2;
|
||||
break;
|
||||
|
||||
case EinkClutThreeBlacksAndRed:
|
||||
numGrays = 3;
|
||||
extraColor = 0xff0000;
|
||||
outBpp = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
packedOutBpp = outBpp;
|
||||
|
||||
skipBytes = hdr.dataOfst - sizeof(hdr);
|
||||
if (skipBytes < 0) {
|
||||
fprintf(stderr, "file header was too short!\n");
|
||||
exit(-1);
|
||||
}
|
||||
f_in.read(NULL, skipBytes);
|
||||
|
||||
rowBytesIn = (hdr.width * hdr.bpp + 31) / 32 * 4;
|
||||
rowBytesOut = ((hdr.width + pixelsPerPackedUnit - 1) / pixelsPerPackedUnit) * packedOutBpp;
|
||||
rowBytesOut = (rowBytesOut + 31) / 32 * 4;
|
||||
|
||||
numRows = hdr.height < 0 ? -hdr.height : hdr.height;
|
||||
hdr.bpp = outBpp;
|
||||
hdr.numColors = 1 << outBpp;
|
||||
hdr.numImportantColors = 1 << outBpp;
|
||||
hdr.dataOfst = sizeof(struct BitmapFileHeader) + 4 * hdr.numColors;
|
||||
hdr.dataLen = numRows * rowBytesOut;
|
||||
hdr.fileSz = hdr.dataOfst + hdr.dataLen;
|
||||
hdr.headerSz = 40;
|
||||
hdr.compression = 0;
|
||||
|
||||
f_out.write((uint8_t *)&hdr, sizeof(hdr));
|
||||
|
||||
// emit & record grey clut entries
|
||||
for (i = 0; i < numGrays; i++) {
|
||||
uint32_t val = 255 * i / (numGrays - 1);
|
||||
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
f_out.write(val);
|
||||
|
||||
clut[i][0] = val;
|
||||
clut[i][1] = val;
|
||||
clut[i][2] = val;
|
||||
}
|
||||
|
||||
// if there is a color CLUT entry, emit that
|
||||
if (extraColor) {
|
||||
f_out.write((extraColor >> 0) & 0xff); // B
|
||||
f_out.write((extraColor >> 8) & 0xff); // G
|
||||
f_out.write((extraColor >> 16) & 0xff); // R
|
||||
f_out.write(0x00); // A
|
||||
|
||||
clut[i][0] = (extraColor >> 0) & 0xff;
|
||||
clut[i][1] = (extraColor >> 8) & 0xff;
|
||||
clut[i][2] = (extraColor >> 16) & 0xff;
|
||||
}
|
||||
|
||||
// pad clut to size
|
||||
for (i = numGrays + (extraColor ? 1 : 0); i < hdr.numColors; i++) {
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
f_out.write(0x00);
|
||||
}
|
||||
|
||||
while (numRows--) {
|
||||
uint32_t pixelValsPackedSoFar = 0, numPixelsPackedSoFar = 0, valSoFar = 0, bytesIn = 0, bytesOut = 0, bitsSoFar = 0;
|
||||
|
||||
for (c = 0; c < hdr.width; c++, bytesIn += 3) {
|
||||
int64_t bestDist = 0x7fffffffffffffffll;
|
||||
uint8_t rgb[3], bestIdx = 0;
|
||||
int32_t ditherFudge = 0;
|
||||
|
||||
f_in.read(rgb, sizeof(rgb));
|
||||
|
||||
if (dither)
|
||||
ditherFudge = (rand() % 255 - 127) / (int)numGrays;
|
||||
|
||||
for (i = 0; i < hdr.numColors; i++) {
|
||||
int64_t dist = 0;
|
||||
|
||||
dist += (rgb[0] - clut[i][0] + ditherFudge) * (rgb[0] - clut[i][0] + ditherFudge) * 4750ll;
|
||||
dist += (rgb[1] - clut[i][1] + ditherFudge) * (rgb[1] - clut[i][1] + ditherFudge) * 47055ll;
|
||||
dist += (rgb[2] - clut[i][2] + ditherFudge) * (rgb[2] - clut[i][2] + ditherFudge) * 13988ll;
|
||||
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
bestIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// pack pixels as needed
|
||||
pixelValsPackedSoFar = pixelValsPackedSoFar * packedMultiplyVal + bestIdx;
|
||||
if (++numPixelsPackedSoFar != pixelsPerPackedUnit)
|
||||
continue;
|
||||
|
||||
numPixelsPackedSoFar = 0;
|
||||
|
||||
// it is easier to display when low val is first pixel. currently last pixel is low - reverse this
|
||||
pixelValsPackedSoFar = repackPackedVals(pixelValsPackedSoFar, pixelsPerPackedUnit, packedMultiplyVal);
|
||||
|
||||
valSoFar = (valSoFar << packedOutBpp) | pixelValsPackedSoFar;
|
||||
pixelValsPackedSoFar = 0;
|
||||
bitsSoFar += packedOutBpp;
|
||||
|
||||
if (bitsSoFar >= 8) {
|
||||
f_out.write(valSoFar >> (bitsSoFar -= 8));
|
||||
valSoFar &= (1 << bitsSoFar) - 1;
|
||||
bytesOut++;
|
||||
}
|
||||
}
|
||||
|
||||
// see if we have unfinished pixel packages to write
|
||||
if (numPixelsPackedSoFar) {
|
||||
while (numPixelsPackedSoFar++ != pixelsPerPackedUnit)
|
||||
pixelValsPackedSoFar *= packedMultiplyVal;
|
||||
|
||||
// it is easier to display when low val is first pixel. currently last pixel is low - reverse this
|
||||
pixelValsPackedSoFar = repackPackedVals(pixelValsPackedSoFar, pixelsPerPackedUnit, packedMultiplyVal);
|
||||
|
||||
valSoFar = (valSoFar << packedOutBpp) | pixelValsPackedSoFar;
|
||||
pixelValsPackedSoFar = 0;
|
||||
bitsSoFar += packedOutBpp;
|
||||
|
||||
if (bitsSoFar >= 8) {
|
||||
f_out.write(valSoFar >> (bitsSoFar -= 8));
|
||||
valSoFar &= (1 << bitsSoFar) - 1;
|
||||
bytesOut++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bitsSoFar) {
|
||||
valSoFar <<= 8 - bitsSoFar; // left-align it as is expected
|
||||
f_out.write(valSoFar);
|
||||
bytesOut++;
|
||||
}
|
||||
|
||||
while (bytesIn++ < rowBytesIn)
|
||||
f_in.read(NULL, 1);
|
||||
while (bytesOut++ < rowBytesOut)
|
||||
f_out.write(0);
|
||||
}
|
||||
f_in.close();
|
||||
f_out.close();
|
||||
Serial.println(millis() - t);
|
||||
Serial.println("finished writing BMP2");
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
#pragma pack(push, 1)
|
||||
#include "newproto.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
#include <makeimage.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "LittleFS.h"
|
||||
#include "commstructs.h"
|
||||
#include "pendingdata.h"
|
||||
#include "serial.h"
|
||||
#include "settings.h"
|
||||
#include "tag_db.h"
|
||||
#include "web.h"
|
||||
|
||||
extern void sendBlock(const void* data, const uint16_t len);
|
||||
@@ -29,7 +31,7 @@ bool checkCRC(void* p, uint8_t len) {
|
||||
return ((uint8_t*)p)[0] == total;
|
||||
}
|
||||
|
||||
uint8_t* getDataForFile(File* file) {
|
||||
uint8_t* getDataForFile(fs::File* file) {
|
||||
uint8_t* ret = nullptr;
|
||||
ret = (uint8_t*)malloc(file->size());
|
||||
if (ret) {
|
||||
@@ -48,15 +50,51 @@ void prepareCancelPending(uint64_t ver) {
|
||||
}
|
||||
|
||||
bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin) {
|
||||
|
||||
if (nextCheckin > 1440) {
|
||||
//to prevent very long sleeps of the tag
|
||||
nextCheckin = 0;
|
||||
}
|
||||
|
||||
*filename = "/" + *filename;
|
||||
if (!LittleFS.exists(*filename)) return false;
|
||||
File file = LittleFS.open(*filename);
|
||||
fs::File file = LittleFS.open(*filename);
|
||||
|
||||
if (file.size() == 0) {
|
||||
Serial.print("opened a file with size 0??\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filename->endsWith(".bmp") || filename->endsWith(".BMP")) {
|
||||
struct BitmapFileHeader hdr;
|
||||
file.read((uint8_t*)&hdr, sizeof(hdr));
|
||||
if (hdr.width == 296 && hdr.height == 128) {
|
||||
//sorry, can't rotate
|
||||
Serial.println("when using BMP files, remember to only use 128px width and 296px height");
|
||||
wsErr("when using BMP files, remember to only use 128px width and 296px height");
|
||||
return false;
|
||||
}
|
||||
if (hdr.sig[0] == 'B' && hdr.sig[1] == 'M' && hdr.bpp == 24) {
|
||||
Serial.println("converting 24bpp bmp to grays");
|
||||
char fileout[64];
|
||||
sprintf(fileout, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
bmp2grays(*filename,(String)fileout);
|
||||
*filename = (String)fileout;
|
||||
file.close();
|
||||
file = LittleFS.open(*filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (filename->endsWith(".jpg") || filename->endsWith(".JPG")) {
|
||||
Serial.println("converting jpg to grays");
|
||||
char fileout[64];
|
||||
sprintf(fileout, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
jpg2grays(*filename, (String)fileout);
|
||||
*filename = (String)fileout;
|
||||
file.close();
|
||||
file = LittleFS.open(*filename);
|
||||
}
|
||||
|
||||
uint8_t md5bytes[16];
|
||||
{
|
||||
MD5Builder md5;
|
||||
@@ -66,6 +104,20 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
md5.getBytes(md5bytes);
|
||||
}
|
||||
|
||||
uint8_t src[8];
|
||||
*((uint64_t*)src) = swap64(*((uint64_t*)dst));
|
||||
uint8_t mac[6];
|
||||
memcpy(mac, src + 2, sizeof(mac));
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
if (memcmp(md5bytes, taginfo->md5pending, 16) == 0) {
|
||||
Serial.println("new image is the same as current image. not updating tag.");
|
||||
wsSendTaginfo(mac);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// the message that will be sent to the AP to tell the tag there is data pending
|
||||
struct pendingData pending = {0};
|
||||
memcpy(pending.targetMac, dst, 8);
|
||||
@@ -84,10 +136,38 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
pendinginfo->len = pending.availdatainfo.dataSize;
|
||||
pendinginfo->data = nullptr;
|
||||
pendinginfo->timeout = PENDING_TIMEOUT;
|
||||
// pendinginfo->data = getDataForFile(&file);
|
||||
file.close();
|
||||
pendinginfo->timeout = 1800;
|
||||
//pendinginfo->data = getDataForFile(&file);
|
||||
pendinginfo->timeout = 1800; // ***fixme... a tag can sleep for a long time when ttl is used.
|
||||
pendingfiles.push_back(pendinginfo);
|
||||
|
||||
if (dataType != DATATYPE_UPDATE) {
|
||||
char dst_path[64];
|
||||
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X.pending\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
fs::File dstfile = LittleFS.open(dst_path, "w");
|
||||
//int bytes_written = dstfile.write(pendinginfo->data, pendinginfo->len);
|
||||
file.seek(0);
|
||||
const int chunkSize = 512;
|
||||
uint8_t buffer[chunkSize];
|
||||
size_t bytesRead = 0;
|
||||
while ((bytesRead = file.read(buffer, chunkSize)) > 0) {
|
||||
dstfile.write(buffer, bytesRead);
|
||||
}
|
||||
dstfile.close();
|
||||
|
||||
wsLog("new image pending: " + String(dst_path));
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->pending = true;
|
||||
taginfo->CheckinInMinPending = nextCheckin + 1;
|
||||
memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes));
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsLog("firmware upload pending");
|
||||
}
|
||||
file.close();
|
||||
|
||||
wsSendTaginfo(mac);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,7 +185,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
} else {
|
||||
if (pd->data == nullptr) {
|
||||
// not cached. open file, cache the data
|
||||
File file = LittleFS.open(pd->filename);
|
||||
fs::File file = LittleFS.open(pd->filename);
|
||||
if (!file) {
|
||||
Serial.print("Dunno how this happened... File pending but deleted in the meantime?\n");
|
||||
}
|
||||
@@ -129,7 +209,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
sendBlock(pd->data + (br->blockId * BLOCK_DATA_SIZE), len);
|
||||
char buffer[64];
|
||||
sprintf(buffer, "< Block Request received for MD5 %llu, block %d\n\0", br->ver, br->blockId);
|
||||
wsString((String)buffer);
|
||||
wsLog((String)buffer);
|
||||
Serial.printf("<BlockId=%d\n", br->blockId);
|
||||
}
|
||||
|
||||
@@ -138,14 +218,60 @@ void processXferComplete(struct espXferComplete* xfc) {
|
||||
uint8_t src[8];
|
||||
*((uint64_t*)src) = swap64(*((uint64_t*)xfc->src));
|
||||
sprintf(buffer, "< %02X%02X%02X%02X%02X%02X reports xfer complete\n\0", src[2], src[3], src[4], src[5], src[6], src[7]);
|
||||
wsString((String)buffer);
|
||||
wsLog((String)buffer);
|
||||
Serial.print(buffer);
|
||||
uint8_t mac[6];
|
||||
memcpy(mac, src + 2, sizeof(mac));
|
||||
|
||||
char src_path[64];
|
||||
char dst_path[64];
|
||||
char tmp_path[64];
|
||||
sprintf(src_path, "/current/%02X%02X%02X%02X%02X%02X.pending\0", src[2], src[3], src[4], src[5], src[6], src[7]);
|
||||
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X.bmp\0", src[2], src[3], src[4], src[5], src[6], src[7]);
|
||||
sprintf(tmp_path, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", src[2], src[3], src[4], src[5], src[6], src[7]);
|
||||
if (LittleFS.exists(dst_path)) {
|
||||
LittleFS.remove(dst_path);
|
||||
}
|
||||
LittleFS.rename(src_path, dst_path);
|
||||
if (LittleFS.exists(tmp_path)) {
|
||||
LittleFS.remove(tmp_path);
|
||||
}
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->pending = false;
|
||||
taginfo->expectedNextCheckin = now + 60 * taginfo->CheckinInMinPending + 30;
|
||||
memcpy(taginfo->md5, taginfo->md5pending, sizeof(taginfo->md5pending));
|
||||
}
|
||||
wsSendTaginfo(mac);
|
||||
}
|
||||
|
||||
void processDataReq(struct espAvailDataReq* eadr) {
|
||||
char buffer[64];
|
||||
uint8_t src[8];
|
||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X button: %02X\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0], eadr->adr.buttonState);
|
||||
wsString((String)buffer);
|
||||
*((uint64_t*)src) = swap64(*((uint64_t*)eadr->src));
|
||||
|
||||
tagRecord* taginfo = nullptr;
|
||||
uint8_t mac[6];
|
||||
memcpy(mac, src + 2, sizeof(mac));
|
||||
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo == nullptr) {
|
||||
taginfo = new tagRecord;
|
||||
memcpy(taginfo->mac, src + 2, sizeof(taginfo->mac));
|
||||
taginfo->pending = false;
|
||||
tagDB.push_back(taginfo);
|
||||
}
|
||||
time_t now;
|
||||
time(&now);
|
||||
taginfo->lastseen = now;
|
||||
taginfo->expectedNextCheckin = now + 300;
|
||||
taginfo->button = (eadr->adr.buttonState == 1);
|
||||
|
||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X\n\0", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
Serial.print(buffer);
|
||||
wsSendTaginfo(mac);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#pragma pack(push, 1)
|
||||
#include <Arduino.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <LittleFS.h>
|
||||
@@ -139,7 +138,6 @@ void SerialRXLoop() {
|
||||
}
|
||||
if (strncmp(cmdbuffer, "BST>", 4) == 0) {
|
||||
Serial.print(">SYNC BURST\n");
|
||||
wsString(">SYNC BURST");
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
if (strncmp(cmdbuffer, "XFC>", 4) == 0) {
|
||||
|
||||
167
esp32_fw/src/tag_db.cpp
Normal file
167
esp32_fw/src/tag_db.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "tag_db.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "LittleFS.h"
|
||||
|
||||
std::vector<tagRecord*> tagDB;
|
||||
|
||||
tagRecord* tagRecord::findByMAC(uint8_t mac[6]) {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* tag = nullptr;
|
||||
tag = tagDB.at(c);
|
||||
if (memcmp(tag->mac, mac, 6) == 0) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String tagDBtoJson(uint8_t mac[6], uint8_t startPos) {
|
||||
DynamicJsonDocument doc(2500);
|
||||
JsonArray tags = doc.createNestedArray("tags");
|
||||
|
||||
for (int16_t c = startPos; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
|
||||
bool select = false;
|
||||
if (mac) {
|
||||
if (memcmp(taginfo->mac, mac, 6) == 0) {
|
||||
select = true;
|
||||
}
|
||||
} else {
|
||||
select = true;
|
||||
}
|
||||
if (select) {
|
||||
JsonObject tag = tags.createNestedObject();
|
||||
fillNode(tag, taginfo);
|
||||
if (mac) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (doc.capacity()-doc.memoryUsage() < doc.memoryUsage()/(c+1) + 100) {
|
||||
doc["continu"] = c+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return doc.as<String>();
|
||||
}
|
||||
|
||||
void fillNode(JsonObject &tag, tagRecord* &taginfo) {
|
||||
char buffer[16];
|
||||
sprintf(buffer, "%02X%02X%02X%02X%02X%02X\0", taginfo->mac[0], taginfo->mac[1], taginfo->mac[2], taginfo->mac[3], taginfo->mac[4], taginfo->mac[5]);
|
||||
tag["mac"] = (String)buffer;
|
||||
char hex[7];
|
||||
sprintf(hex, "%02x%02x%02x\0", taginfo->md5[0], taginfo->md5[1], taginfo->md5[2]);
|
||||
tag["hash"] = hex;
|
||||
tag["lastseen"] = taginfo->lastseen;
|
||||
tag["nextupdate"] = taginfo->nextupdate;
|
||||
tag["nextcheckin"] = taginfo->expectedNextCheckin;
|
||||
tag["model"] = taginfo->model;
|
||||
tag["pending"] = taginfo->pending;
|
||||
tag["button"] = taginfo->button;
|
||||
tag["alias"] = taginfo->alias;
|
||||
tag["contentmode"] = taginfo->contentMode;
|
||||
tag["modecfgjson"] = taginfo->modeConfigJson;
|
||||
}
|
||||
|
||||
void saveDB(String filename) {
|
||||
DynamicJsonDocument doc(2500);
|
||||
|
||||
long t = millis();
|
||||
|
||||
LittleFS.begin();
|
||||
fs::File file = LittleFS.open(filename, "w");
|
||||
if (!file) {
|
||||
Serial.println("saveDB: Failed to open file");
|
||||
return;
|
||||
}
|
||||
|
||||
file.write('[');
|
||||
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
doc.clear();
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
|
||||
JsonObject tag = doc.createNestedObject();
|
||||
fillNode(tag, taginfo);
|
||||
if (c > 0) {
|
||||
file.write(',');
|
||||
}
|
||||
serializeJson(doc, file);
|
||||
}
|
||||
file.write(']');
|
||||
|
||||
file.close();
|
||||
Serial.println(millis() - t);
|
||||
Serial.println("finished writing DB");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void loadDB(String filename) {
|
||||
StaticJsonDocument<400> doc;
|
||||
|
||||
Serial.println("start reading DB from file");
|
||||
long t = millis();
|
||||
|
||||
LittleFS.begin();
|
||||
fs::File readfile = LittleFS.open(filename, "r");
|
||||
if (!readfile) {
|
||||
Serial.println("loadDB: Failed to open file");
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
bool parsing = true;
|
||||
|
||||
if (readfile.find("[")) {
|
||||
while (parsing) {
|
||||
DeserializationError err = deserializeJson(doc, readfile);
|
||||
if (!err) {
|
||||
JsonObject tag = doc[0];
|
||||
String dst = tag["mac"].as<String>();
|
||||
uint8_t mac[12];
|
||||
if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo == nullptr) {
|
||||
taginfo = new tagRecord;
|
||||
memcpy(taginfo->mac, mac, sizeof(taginfo->mac));
|
||||
tagDB.push_back(taginfo);
|
||||
}
|
||||
//taginfo->lastseen = (uint32_t)tag["lastseen"];
|
||||
taginfo->lastseen = 0;
|
||||
taginfo->nextupdate = (uint32_t)tag["nextupdate"];
|
||||
taginfo->expectedNextCheckin = (uint16_t)tag["nextcheckin"];
|
||||
if (taginfo->expectedNextCheckin < now - 1800) {
|
||||
taginfo->expectedNextCheckin = now + 1800;
|
||||
}
|
||||
taginfo->model = (uint8_t)tag["model"];
|
||||
taginfo->pending = false;
|
||||
taginfo->button = false;
|
||||
taginfo->alias = tag["alias"].as<String>();
|
||||
taginfo->contentMode = static_cast<contentModes>(tag["contentmode"]);
|
||||
taginfo->modeConfigJson = tag["modecfgjson"].as<String>();
|
||||
}
|
||||
} else {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(err.c_str());
|
||||
parsing = false;
|
||||
}
|
||||
parsing = parsing && readfile.find(",");
|
||||
}
|
||||
}
|
||||
|
||||
readfile.close();
|
||||
Serial.println(millis() - t);
|
||||
Serial.println("finished reading file");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
@@ -14,6 +15,7 @@
|
||||
#include "commstructs.h"
|
||||
#include "newproto.h"
|
||||
#include "settings.h"
|
||||
#include "tag_db.h"
|
||||
|
||||
extern uint8_t data_to_send[];
|
||||
|
||||
@@ -53,62 +55,15 @@ void webSocketSendProcess(void *parameter) {
|
||||
// sendStatus(STATUS_WIFI_ACTIVITY);
|
||||
DynamicJsonDocument doc(1500);
|
||||
if (ulNotificationValue & 2) { // WS_SEND_MODE_STATUS) {
|
||||
/* doc["rxActive"] = status.rxActive;
|
||||
doc["txActive"] = status.txActive;
|
||||
doc["freq"] = status.freq;
|
||||
doc["txMode"] = status.currentmode;
|
||||
*/
|
||||
}
|
||||
/*
|
||||
JsonArray statusframes = doc.createNestedArray("frames");
|
||||
for (uint8_t c = 0; c < STATUSFRAMELISTSIZE; c++) {
|
||||
if (statusframearr[c]) {
|
||||
JsonObject statusframe = statusframes.createNestedObject();
|
||||
statusframe["frame"] = statusframearr[c]->frameno;
|
||||
statusframe["isTX"] = statusframearr[c]->isTX;
|
||||
statusframe["freq"] = statusframearr[c]->freq;
|
||||
statusframe["txSkipped"] = statusframearr[c]->txCancelled;
|
||||
switch (statusframearr[c]->rxtype) {
|
||||
case flexsynctype::SYNC_FLEX_1600:
|
||||
statusframe["rxType"] = "FLEX_1600";
|
||||
break;
|
||||
case flexsynctype::SYNC_FLEX_3200_2:
|
||||
statusframe["rxType"] = "FLEX_3200_2";
|
||||
break;
|
||||
case flexsynctype::SYNC_FLEX_3200_4:
|
||||
statusframe["rxType"] = "FLEX_3200_4";
|
||||
break;
|
||||
case flexsynctype::SYNC_FLEX_6400:
|
||||
statusframe["rxType"] = "FLEX_3200_4";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (statusframearr[c]->txformat) {
|
||||
case txframe::FORMAT_FLEX:
|
||||
statusframe["txType"] = "FLEX";
|
||||
break;
|
||||
case txframe::FORMAT_POCSAG:
|
||||
statusframe["txType"] = "POCSAG";
|
||||
break;
|
||||
case txframe::FORMAT_IDLE:
|
||||
statusframe["txType"] = "IDLE";
|
||||
break;
|
||||
case txframe::FORMAT_BLOCKED:
|
||||
statusframe["txType"] = "BLOCKED";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
size_t len = measureJson(doc);
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
auto buffer = std::make_shared<std::vector<uint8_t>>(len);
|
||||
serializeJson(doc, buffer->data(), len);
|
||||
// ws.textAll((char*)buffer->data());
|
||||
ws.textAll("ohai");
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
}
|
||||
@@ -188,16 +143,59 @@ void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType
|
||||
}
|
||||
}
|
||||
|
||||
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
|
||||
void wsString(String text) {
|
||||
void wsLog(String text) {
|
||||
DynamicJsonDocument doc(100);
|
||||
doc["logMsg"] = text;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(text);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsErr(String text) {
|
||||
DynamicJsonDocument doc(100);
|
||||
doc["errMsg"] = text;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsSendSysteminfo() {
|
||||
DynamicJsonDocument doc(250);
|
||||
JsonObject sys = doc.createNestedObject("sys");
|
||||
time_t now;
|
||||
time(&now);
|
||||
sys["currtime"] = now;
|
||||
sys["heap"] = ESP.getFreeHeap();
|
||||
sys["recordcount"] = tagDB.size();
|
||||
sys["dbsize"] = tagDB.size() * sizeof(tagRecord);
|
||||
sys["littlefsfree"] = LittleFS.totalBytes() - LittleFS.usedBytes();
|
||||
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsSendTaginfo(uint8_t mac[6]) {
|
||||
|
||||
String json = "";
|
||||
json = tagDBtoJson(mac);
|
||||
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(json);
|
||||
xSemaphoreGive(wsMutex);
|
||||
|
||||
}
|
||||
|
||||
void init_web() {
|
||||
LittleFS.begin(true);
|
||||
|
||||
if (!LittleFS.exists("/current")) {
|
||||
LittleFS.mkdir("/current");
|
||||
}
|
||||
if (!LittleFS.exists("/temp")) {
|
||||
LittleFS.mkdir("/temp");
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiManager wm;
|
||||
bool res;
|
||||
@@ -214,87 +212,20 @@ void init_web() {
|
||||
ws.onEvent(onEvent);
|
||||
server.addHandler(&ws);
|
||||
|
||||
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", String(ESP.getFreeHeap()));
|
||||
});
|
||||
|
||||
server.on("/reboot", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
request->send(200, "text/plain", "OK Reboot");
|
||||
ESP.restart();
|
||||
});
|
||||
|
||||
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.htm");
|
||||
|
||||
server.serveStatic("/current", LittleFS, "/current/");
|
||||
server.serveStatic("/", LittleFS, "/www/").setDefaultFile("index.html");
|
||||
|
||||
server.on(
|
||||
"/imgupload", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
request->send(200);
|
||||
},
|
||||
doImageUpload);
|
||||
|
||||
server.on("/send_image", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
String filename;
|
||||
String dst;
|
||||
uint16_t nextCheckin;
|
||||
if (request->hasParam("filename", true) && request->hasParam("dst", true)) {
|
||||
filename = request->getParam("filename", true)->value();
|
||||
dst = request->getParam("dst", true)->value();
|
||||
nextCheckin = request->getParam("ttl",true)->value().toInt();
|
||||
uint8_t mac_addr[12]; // I expected this to return like 8 values, but if I make the array 8 bytes long, things die.
|
||||
mac_addr[0] = 0x00;
|
||||
mac_addr[1] = 0x00;
|
||||
if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X",
|
||||
&mac_addr[2],
|
||||
&mac_addr[3],
|
||||
&mac_addr[4],
|
||||
&mac_addr[5],
|
||||
&mac_addr[6],
|
||||
&mac_addr[7]) != 6) {
|
||||
request->send(200, "text/plain", "Something went wrong trying to parse the mac address");
|
||||
} else {
|
||||
*((uint64_t *)mac_addr) = swap64(*((uint64_t *)mac_addr));
|
||||
if (prepareDataAvail(&filename, DATATYPE_IMGRAW, mac_addr, nextCheckin)) {
|
||||
request->send(200, "text/plain", "Sending to " + dst);
|
||||
} else {
|
||||
request->send(200, "text/plain", "Couldn't find filename :(");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
request->send(200, "text/plain", "Didn't get the required filename + dst");
|
||||
return;
|
||||
});
|
||||
|
||||
server.on("/send_fw", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
String filename;
|
||||
String dst;
|
||||
if (request->hasParam("filename", true) && request->hasParam("dst", true)) {
|
||||
filename = request->getParam("filename", true)->value();
|
||||
dst = request->getParam("dst", true)->value();
|
||||
uint8_t mac_addr[12]; // I expected this to return like 8 values, but if I make the array 8 bytes long, things die.
|
||||
mac_addr[0] = 0x00;
|
||||
mac_addr[1] = 0x00;
|
||||
if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X",
|
||||
&mac_addr[2],
|
||||
&mac_addr[3],
|
||||
&mac_addr[4],
|
||||
&mac_addr[5],
|
||||
&mac_addr[6],
|
||||
&mac_addr[7]) != 6) {
|
||||
request->send(200, "text/plain", "Something went wrong trying to parse the mac address");
|
||||
} else {
|
||||
*((uint64_t *)mac_addr) = swap64(*((uint64_t *)mac_addr));
|
||||
if (prepareDataAvail(&filename, DATATYPE_UPDATE, mac_addr, 0)) {
|
||||
request->send(200, "text/plain", "Sending FW to " + dst);
|
||||
} else {
|
||||
request->send(200, "text/plain", "Couldn't find filename :(");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
request->send(200, "text/plain", "Didn't get the required filename + dst");
|
||||
return;
|
||||
});
|
||||
|
||||
server.on("/req_checkin", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
String filename;
|
||||
String dst;
|
||||
@@ -323,60 +254,53 @@ void init_web() {
|
||||
return;
|
||||
});
|
||||
|
||||
server.on("/get_db", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
String json = "";
|
||||
if (request->hasParam("mac")) {
|
||||
String dst = request->getParam("mac")->value();
|
||||
uint8_t mac[6];
|
||||
if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])==6) {
|
||||
json = tagDBtoJson(mac);
|
||||
}
|
||||
} else {
|
||||
uint8_t startPos=0;
|
||||
if (request->hasParam("pos")) {
|
||||
startPos = atoi(request->getParam("pos")->value().c_str());
|
||||
}
|
||||
json = tagDBtoJson(nullptr,startPos);
|
||||
}
|
||||
request->send(200, "application/json", json);
|
||||
});
|
||||
|
||||
server.on("/save_cfg", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("mac", true)) {
|
||||
String dst = request->getParam("mac", true)->value();
|
||||
uint8_t mac[6];
|
||||
if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->alias = request->getParam("alias", true)->value();
|
||||
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
|
||||
taginfo->contentMode = (contentModes)atoi(request->getParam("contentmode", true)->value().c_str());
|
||||
taginfo->model = atoi(request->getParam("model", true)->value().c_str());
|
||||
taginfo->nextupdate = 0;
|
||||
wsSendTaginfo(mac);
|
||||
saveDB("/current/tagDB.json");
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
} else {
|
||||
request->send(200, "text/plain", "Error while saving: mac not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
});
|
||||
|
||||
server.onNotFound([](AsyncWebServerRequest *request) {
|
||||
if (request->url() == "/" || request->url() == "index.htm") {
|
||||
request->send(200, "text/html", "-");
|
||||
return;
|
||||
}
|
||||
Serial.printf("NOT_FOUND: ");
|
||||
|
||||
switch (request->method()) {
|
||||
case HTTP_GET:
|
||||
Serial.printf("GET");
|
||||
break;
|
||||
case HTTP_POST:
|
||||
Serial.printf("POST");
|
||||
break;
|
||||
case HTTP_DELETE:
|
||||
Serial.printf("DELETE");
|
||||
break;
|
||||
case HTTP_PUT:
|
||||
Serial.printf("PUT");
|
||||
break;
|
||||
case HTTP_PATCH:
|
||||
Serial.printf("PATCH");
|
||||
break;
|
||||
case HTTP_HEAD:
|
||||
Serial.printf("HEAD");
|
||||
break;
|
||||
case HTTP_OPTIONS:
|
||||
Serial.printf("OPTIONS");
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.printf("UNKNOWN");
|
||||
break;
|
||||
}
|
||||
Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
|
||||
|
||||
if (request->contentLength()) {
|
||||
Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
|
||||
Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
|
||||
}
|
||||
for (int i = 0; i < request->headers(); i++) {
|
||||
AsyncWebHeader *h = request->getHeader(i);
|
||||
Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
|
||||
}
|
||||
for (int i = 0; i < request->params(); i++) {
|
||||
AsyncWebParameter *p = request->getParam(i);
|
||||
if (p->isFile()) {
|
||||
Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
|
||||
} else if (p->isPost()) {
|
||||
Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
} else {
|
||||
Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
}
|
||||
}
|
||||
request->send(404);
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ BUILD ?= zbs29v033
|
||||
SOURCES += main.c eeprom.c drawing.c
|
||||
SOURCES += comms.c
|
||||
SOURCES += syncedproto.c epd.c userinterface.c
|
||||
|
||||
SOURCES += powermgt.c barcode.c
|
||||
|
||||
all: #make sure it is the first target
|
||||
|
||||
|
||||
101
tag_fw/barcode.c
Normal file
101
tag_fw/barcode.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <stdbool.h>
|
||||
#include "barcode.h"
|
||||
#include "asmUtil.h"
|
||||
|
||||
//code128 generator (c) 2021 Dmitry Grinberg https://dmitry.gr
|
||||
//non-commercial use only, contact licensing@dmitry.gr for other options
|
||||
|
||||
#pragma nogcse
|
||||
|
||||
static const uint16_t __code mCode128[] = {
|
||||
0b00110011011, 0b00110110011, 0b01100110011, 0b00011001001, 0b00110001001, 0b00110010001, 0b00010011001, 0b00100011001,
|
||||
0b00100110001, 0b00010010011, 0b00100010011, 0b00100100011, 0b00111001101, 0b00111011001, 0b01110011001, 0b00110011101,
|
||||
0b00110111001, 0b01100111001, 0b01001110011, 0b00111010011, 0b01110010011, 0b00100111011, 0b00101110011, 0b01110110111,
|
||||
0b00110010111, 0b00110100111, 0b01100100111, 0b00100110111, 0b00101100111, 0b01001100111, 0b00011011011, 0b01100011011,
|
||||
0b01101100011, 0b00011000101, 0b00011010001, 0b01100010001, 0b00010001101, 0b00010110001, 0b01000110001, 0b00010001011,
|
||||
0b00010100011, 0b01000100011, 0b00011101101, 0b01110001101, 0b01110110001, 0b00011011101, 0b01100011101, 0b01101110001,
|
||||
0b01101110111, 0b01110001011, 0b01110100011, 0b00010111011, 0b01000111011, 0b01110111011, 0b00011010111, 0b01100010111,
|
||||
0b01101000111, 0b00010110111, 0b01000110111, 0b01011000111, 0b01011110111, 0b01000010011, 0b01010001111, 0b00001100101,
|
||||
0b00110000101, 0b00001101001, 0b01100001001, 0b00110100001, 0b01100100001, 0b00001001101, 0b00100001101, 0b00001011001,
|
||||
0b01000011001, 0b00101100001, 0b01001100001, 0b01001000011, 0b00001010011, 0b01011101111, 0b00101000011, 0b01011110001,
|
||||
0b00111100101, 0b00111101001, 0b01111001001, 0b00100111101, 0b00101111001, 0b01001111001, 0b00100101111, 0b00101001111,
|
||||
0b01001001111, 0b01111011011, 0b01101111011, 0b01101101111, 0b00011110101, 0b01111000101, 0b01111010001, 0b00010111101,
|
||||
0b01000111101, 0b00010101111, 0b01000101111, 0b01111011101, 0b01110111101, 0b01111010111, 0b01110101111
|
||||
};
|
||||
|
||||
|
||||
#define CODE128_START_B (0b00001001011)
|
||||
#define CODE128_STOP (0b1101011100011)
|
||||
|
||||
#define CODE128_IDX_START_A (103)
|
||||
#define CODE128_IDX_START_B (104)
|
||||
#define CODE128_IDX_START_C (105)
|
||||
#define CODE128_IDX_CODE_STOP (106)
|
||||
|
||||
|
||||
enum BarCodeState {
|
||||
BarCodeInit,
|
||||
BarCodeEmittingChar,
|
||||
BarCodeEmittingChecksum,
|
||||
BarCodeEmittingStop,
|
||||
BarCodeDone,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
__bit barcodeIsDone(struct BarcodeInfo __xdata *bci)
|
||||
{
|
||||
return bci->state == BarCodeDone;
|
||||
}
|
||||
|
||||
__bit barcodeNextBar(struct BarcodeInfo __xdata *bci)
|
||||
{
|
||||
uint8_t t;
|
||||
__bit ret;
|
||||
|
||||
if (!bci->barsLeft) switch (bci->state) {
|
||||
case BarCodeInit:
|
||||
bci->curBars = CODE128_START_B;
|
||||
bci->barsLeft = 11;
|
||||
bci->state = BarCodeEmittingChar;
|
||||
bci->csum = CODE128_IDX_START_B;
|
||||
break;
|
||||
|
||||
case BarCodeEmittingChar:
|
||||
t = charsPrvDerefAndIncGenericPtr(&bci->str);
|
||||
if (t) {
|
||||
t -= 0x20;
|
||||
if (t >= 0x60)
|
||||
t = '?' - 0x20;
|
||||
bci->csum = mathPrvMod16x8(mathPrvMul8x8(++bci->csumMul, t) + bci->csum, 103);
|
||||
}
|
||||
else {
|
||||
|
||||
bci->state = BarCodeEmittingChecksum;
|
||||
t = bci->csum;
|
||||
}
|
||||
bci->curBars = mCode128[t];
|
||||
bci->barsLeft = 11;
|
||||
break;
|
||||
|
||||
case BarCodeEmittingChecksum:
|
||||
bci->state = BarCodeEmittingStop;
|
||||
bci->curBars = CODE128_STOP;
|
||||
bci->barsLeft = 13;
|
||||
break;
|
||||
|
||||
case BarCodeEmittingStop:
|
||||
bci->state = BarCodeDone;
|
||||
//fallthrough
|
||||
|
||||
case BarCodeDone:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = bci->curBars & 1;
|
||||
bci->curBars >>= 1;
|
||||
bci->barsLeft--;
|
||||
return ret;
|
||||
}
|
||||
29
tag_fw/barcode.h
Normal file
29
tag_fw/barcode.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef _BARCODE_H_
|
||||
#define _BARCODE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//code128 generator (c) 2021 Dmitry Grinberg https://dmitry.gr
|
||||
//non-commercial use only, contact licensing@dmitry.gr for other options
|
||||
|
||||
|
||||
struct BarcodeInfo { //zero-init this except the string ptr
|
||||
const char *str;
|
||||
uint16_t curBars;
|
||||
uint8_t barsLeft;
|
||||
uint8_t state;
|
||||
uint8_t csum;
|
||||
uint8_t csumMul;
|
||||
};
|
||||
|
||||
#define barcodeWidth(nChars) (11 * (nChars) + 11 /*start */+ 11 /*check sum */ + 13 /* stop */)
|
||||
|
||||
#pragma callee_saves barcodeIsDone
|
||||
__bit barcodeIsDone(struct BarcodeInfo __xdata *bci);
|
||||
|
||||
#pragma callee_saves barcodeNextBar
|
||||
__bit barcodeNextBar(struct BarcodeInfo __xdata *bci);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
210
tag_fw/bitmaps.h
Normal file
210
tag_fw/bitmaps.h
Normal file
@@ -0,0 +1,210 @@
|
||||
#ifndef _BITMAPS_H_
|
||||
#define _BITMAPS_H_
|
||||
|
||||
// images generated by https://lvgl.io/tools/imageconverter, prepended with width, height. "CF_INDEXED_1_BIT"-mode, little-endian
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint8_t __code solum[] = {
|
||||
128, 26,
|
||||
0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0xfc,
|
||||
0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x03, 0xfc,
|
||||
0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x07, 0xfc,
|
||||
0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x0f, 0xfc,
|
||||
0x00, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xc0, 0x78, 0x03, 0x80, 0x1c, 0x01, 0xff, 0x80, 0x0f, 0xf8,
|
||||
0x00, 0xff, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x78, 0x07, 0xc0, 0x3e, 0x01, 0xff, 0x80, 0x1f, 0xf8,
|
||||
0x01, 0xfe, 0x00, 0x00, 0x03, 0xff, 0xf8, 0xf8, 0x07, 0xc0, 0x3e, 0x01, 0xff, 0x80, 0x3e, 0xf8,
|
||||
0x01, 0xfe, 0x03, 0xfe, 0x0f, 0xe1, 0xfc, 0xf8, 0x0f, 0x80, 0x7c, 0x03, 0xef, 0x80, 0x7d, 0xf8,
|
||||
0x01, 0xfe, 0x00, 0x7f, 0x0f, 0x80, 0xfc, 0xf8, 0x0f, 0x80, 0x7c, 0x03, 0xef, 0x80, 0x7d, 0xf0,
|
||||
0x01, 0xff, 0x80, 0x3f, 0x9f, 0x00, 0x7c, 0xf0, 0x0f, 0x80, 0x7c, 0x03, 0xe7, 0xc0, 0xf9, 0xf0,
|
||||
0x00, 0x7f, 0xf0, 0x3f, 0xbf, 0x00, 0x7d, 0xf0, 0x0f, 0x00, 0x78, 0x03, 0xe7, 0xc1, 0xf1, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x3f, 0xbe, 0x00, 0x7d, 0xf0, 0x1f, 0x00, 0xf8, 0x07, 0xc7, 0xc3, 0xf3, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x7f, 0xbc, 0x00, 0x7d, 0xe0, 0x1f, 0x00, 0xf8, 0x07, 0xc7, 0xc3, 0xe3, 0xe0,
|
||||
0x00, 0x00, 0x01, 0xff, 0x7c, 0x00, 0x7f, 0xe0, 0x1f, 0x00, 0xf0, 0x07, 0xc3, 0xc7, 0xc3, 0xe0,
|
||||
0x00, 0x00, 0x03, 0xff, 0x7c, 0x00, 0x7f, 0xe0, 0x1e, 0x01, 0xf0, 0x07, 0xc3, 0xef, 0x87, 0xe0,
|
||||
0x00, 0x00, 0x0f, 0xfc, 0x7c, 0x00, 0xfb, 0xe0, 0x3e, 0x01, 0xf0, 0x0f, 0x83, 0xef, 0x87, 0xc0,
|
||||
0x00, 0x00, 0x3f, 0xf8, 0x7c, 0x01, 0xfb, 0xc0, 0x3e, 0x01, 0xe0, 0x0f, 0x83, 0xff, 0x07, 0xc0,
|
||||
0x00, 0x00, 0xff, 0xf0, 0x7c, 0x01, 0xf7, 0xc0, 0x3e, 0x03, 0xe0, 0x0f, 0x83, 0xfe, 0x07, 0xc0,
|
||||
0x00, 0x07, 0xff, 0xc0, 0x7e, 0x07, 0xe7, 0xc0, 0x3e, 0x07, 0xc0, 0x0f, 0x81, 0xfe, 0x0f, 0xc0,
|
||||
0x00, 0x3f, 0xff, 0x00, 0x3f, 0x9f, 0xc7, 0xff, 0xbf, 0x9f, 0xc0, 0x1f, 0x01, 0xfc, 0x0f, 0x80,
|
||||
0x01, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0x87, 0xff, 0x9f, 0xff, 0x80, 0x1f, 0x01, 0xf8, 0x0f, 0x80,
|
||||
0x1f, 0xff, 0xf0, 0x00, 0x0f, 0xfe, 0x07, 0xff, 0x8f, 0xfe, 0x00, 0x1f, 0x01, 0xf0, 0x1f, 0x80,
|
||||
};
|
||||
|
||||
static const uint8_t __code hacked[] = {
|
||||
112, 56,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x03, 0xff, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x87, 0xff, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x87, 0xc3, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0x83, 0xf8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x81, 0xfb, 0x8f, 0x03, 0xfc,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x03, 0x81, 0xf3, 0x8f, 0x03, 0xfe,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x07, 0x81, 0xe7, 0x8f, 0x07, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x07, 0x81, 0xc7, 0x8f, 0x07, 0x9f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x07, 0x81, 0xc7, 0x87, 0x8f, 0x8f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x07, 0x01, 0xcf, 0x07, 0x9f, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x0f, 0x01, 0xef, 0x07, 0xff, 0x00,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe1, 0xf8, 0x0f, 0x01, 0xff, 0x03, 0xfe, 0x00,
|
||||
0x38, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0x0f, 0x01, 0xfe, 0x03, 0xfc, 0x00,
|
||||
0x38, 0x07, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x7c, 0x1e, 0x00, 0xff, 0xf0, 0x00, 0x00,
|
||||
0x3c, 0x07, 0x80, 0x00, 0x00, 0x01, 0xe0, 0x3e, 0x1e, 0x00, 0xff, 0xf0, 0x00, 0x00,
|
||||
0x3c, 0x07, 0x80, 0x00, 0x00, 0x03, 0xe0, 0x1f, 0x1e, 0x00, 0x3f, 0xf0, 0x00, 0x00,
|
||||
0x3e, 0x07, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x1f, 0x9f, 0xe0, 0x1f, 0xc0, 0x00, 0x00,
|
||||
0x1e, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x1f, 0x03, 0xc0, 0x00, 0x00, 0x07, 0x80, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x0f, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xfc, 0xff, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x0f, 0x01, 0xe0, 0x07, 0xc0, 0x07, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0f, 0x81, 0xfc, 0x07, 0xf8, 0x07, 0x80, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x81, 0xfc, 0x0f, 0xf8, 0x07, 0x80, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x80, 0xfc, 0x0f, 0x7c, 0x07, 0xc0, 0x78, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0xc0, 0xfc, 0x0f, 0x7e, 0x03, 0xe0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xc3, 0xfc, 0x0e, 0x3e, 0x03, 0xf3, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xdf, 0xfc, 0x0e, 0x3f, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xff, 0xfe, 0x0e, 0x1f, 0x80, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xff, 0x9e, 0x0f, 0x1f, 0x80, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1e, 0x0f, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0xf0, 0x1f, 0x0f, 0xbf, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xf0, 0x0f, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x0f, 0x87, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x07, 0x83, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x38, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x38, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1e, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t __code receive[] = {
|
||||
56, 56,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xe0,
|
||||
0x00, 0x00, 0x7f, 0x80, 0x00, 0x7f, 0xf0,
|
||||
0x00, 0x00, 0xfe, 0x00, 0x03, 0xff, 0xf0,
|
||||
0x00, 0x01, 0xfc, 0x00, 0x0f, 0xff, 0xf0,
|
||||
0x00, 0x01, 0xf8, 0x00, 0x3f, 0xff, 0xf0,
|
||||
0x00, 0x03, 0xf8, 0x00, 0xff, 0xff, 0x80,
|
||||
0x00, 0x07, 0xf0, 0x01, 0xff, 0xe0, 0x00,
|
||||
0x00, 0x0f, 0xe0, 0x03, 0xff, 0x00, 0x00,
|
||||
0x00, 0x0f, 0xc0, 0x0f, 0xf8, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x80, 0x1f, 0xf0, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x80, 0x3f, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x3f, 0x00, 0x3f, 0x80, 0x00, 0x00,
|
||||
0x00, 0x3f, 0x00, 0x7f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7e, 0x00, 0xfe, 0x00, 0x07, 0xe0,
|
||||
0x00, 0x7e, 0x01, 0xfc, 0x00, 0x1f, 0xf0,
|
||||
0x00, 0xfc, 0x01, 0xf8, 0x00, 0x7f, 0xf0,
|
||||
0x00, 0xfc, 0x03, 0xf0, 0x01, 0xff, 0xf0,
|
||||
0x00, 0xf8, 0x03, 0xf0, 0x03, 0xff, 0xf0,
|
||||
0x01, 0xf8, 0x07, 0xe0, 0x07, 0xff, 0x00,
|
||||
0x01, 0xf8, 0x07, 0xe0, 0x0f, 0xf0, 0x00,
|
||||
0x01, 0xf0, 0x0f, 0xc0, 0x1f, 0xe0, 0x00,
|
||||
0x01, 0xf0, 0x0f, 0xc0, 0x3f, 0x80, 0x00,
|
||||
0x03, 0xf0, 0x0f, 0x80, 0x3f, 0x00, 0x00,
|
||||
0x03, 0xf0, 0x1f, 0x80, 0x7e, 0x00, 0x00,
|
||||
0x03, 0xe0, 0x1f, 0x80, 0x7e, 0x00, 0x00,
|
||||
0x03, 0xe0, 0x1f, 0x00, 0xfc, 0x01, 0xe0,
|
||||
0x03, 0xe0, 0x1f, 0x00, 0xfc, 0x07, 0xf8,
|
||||
0x03, 0xe0, 0x1f, 0x00, 0xf8, 0x0f, 0xfc,
|
||||
0x03, 0xe0, 0x3f, 0x00, 0xf8, 0x0f, 0xfc,
|
||||
0x03, 0xe0, 0x3f, 0x01, 0xf8, 0x1f, 0xfe,
|
||||
0x03, 0xe0, 0x3f, 0x01, 0xf8, 0x1f, 0xfe,
|
||||
0x03, 0xe0, 0x3f, 0x01, 0xf8, 0x1f, 0xfe,
|
||||
0x03, 0xc0, 0x3e, 0x01, 0xf0, 0x1f, 0xfe,
|
||||
0x01, 0xc0, 0x1e, 0x00, 0xf0, 0x0f, 0xfc,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
static const uint8_t __code failed[] = {
|
||||
48, 48,
|
||||
0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x03, 0xff, 0xff, 0xe0, 0x00,
|
||||
0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00,
|
||||
0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00,
|
||||
0x00, 0x7f, 0xf0, 0x0f, 0xfe, 0x00,
|
||||
0x00, 0xff, 0x80, 0x01, 0xff, 0x00,
|
||||
0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80,
|
||||
0x03, 0xf8, 0x00, 0x00, 0x1f, 0xc0,
|
||||
0x07, 0xf0, 0x00, 0x00, 0x3f, 0xe0,
|
||||
0x0f, 0xe0, 0x00, 0x00, 0x7f, 0xf0,
|
||||
0x0f, 0xc0, 0x00, 0x00, 0xff, 0xf0,
|
||||
0x1f, 0x80, 0x00, 0x01, 0xff, 0xf8,
|
||||
0x1f, 0x00, 0x00, 0x03, 0xff, 0xf8,
|
||||
0x3f, 0x00, 0x00, 0x07, 0xfe, 0xfc,
|
||||
0x3e, 0x00, 0x00, 0x0f, 0xfc, 0x7c,
|
||||
0x7e, 0x00, 0x00, 0x1f, 0xf8, 0x7e,
|
||||
0x7c, 0x00, 0x00, 0x3f, 0xf0, 0x3e,
|
||||
0x7c, 0x00, 0x00, 0x7f, 0xe0, 0x3e,
|
||||
0xfc, 0x00, 0x00, 0xff, 0xc0, 0x3f,
|
||||
0xf8, 0x00, 0x01, 0xff, 0x80, 0x1f,
|
||||
0xf8, 0x00, 0x03, 0xff, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0x07, 0xfe, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0x0f, 0xfc, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0x1f, 0xf8, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0x3f, 0xf0, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0x7f, 0xe0, 0x00, 0x1f,
|
||||
0xf8, 0x00, 0xff, 0xc0, 0x00, 0x1f,
|
||||
0xfc, 0x01, 0xff, 0x80, 0x00, 0x3f,
|
||||
0x7c, 0x03, 0xff, 0x00, 0x00, 0x3e,
|
||||
0x7c, 0x07, 0xfe, 0x00, 0x00, 0x3e,
|
||||
0x7e, 0x0f, 0xfc, 0x00, 0x00, 0x7e,
|
||||
0x3e, 0x1f, 0xf8, 0x00, 0x00, 0x7c,
|
||||
0x3f, 0x3f, 0xf0, 0x00, 0x00, 0xfc,
|
||||
0x3f, 0x7f, 0xe0, 0x00, 0x00, 0xfc,
|
||||
0x1f, 0xff, 0xc0, 0x00, 0x01, 0xf8,
|
||||
0x0f, 0xff, 0x80, 0x00, 0x03, 0xf0,
|
||||
0x0f, 0xff, 0x00, 0x00, 0x07, 0xf0,
|
||||
0x07, 0xfe, 0x00, 0x00, 0x0f, 0xe0,
|
||||
0x03, 0xfc, 0x00, 0x00, 0x1f, 0xc0,
|
||||
0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80,
|
||||
0x00, 0xff, 0x80, 0x01, 0xff, 0x00,
|
||||
0x00, 0x7f, 0xf0, 0x0f, 0xfe, 0x00,
|
||||
0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00,
|
||||
0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00,
|
||||
0x00, 0x03, 0xff, 0xff, 0xe0, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -4,27 +4,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "spi.h"
|
||||
#include "uart.h"
|
||||
|
||||
//colors for ui messages
|
||||
#define UI_MSG_MAGNIFY1 1
|
||||
#define UI_MSG_MAGNIFY2 1
|
||||
#define UI_MSG_MAGNIFY3 1
|
||||
#define UI_MSG_BACK_COLOR 4
|
||||
#define UI_MSG_FORE_COLOR_1 0
|
||||
#define UI_MSG_FORE_COLOR_2 5
|
||||
#define UI_MSG_FORE_COLOR_3 5
|
||||
#define UI_BARCODE_VERTICAL
|
||||
|
||||
#define eepromByte spiByte
|
||||
#define eepromPrvSelect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 0; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
#define eepromPrvDeselect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 1; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
|
||||
//debug uart (enable only when needed, on some boards it inhibits eeprom access)
|
||||
#define dbgUartOn()
|
||||
#define dbgUartOff()
|
||||
#define dbgUartByte uartTx
|
||||
|
||||
//eeprom map
|
||||
#define EEPROM_SETTINGS_AREA_START (0x01000UL)
|
||||
#define EEPROM_SETTINGS_AREA_LEN (0x03000UL)
|
||||
@@ -35,19 +19,10 @@
|
||||
//till end of eeprom really. do not put anything after - it will be erased at pairing time!!!
|
||||
#define EEPROM_PROGRESS_BYTES (128)
|
||||
|
||||
//radio cfg
|
||||
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
|
||||
#define RADIO_NUM_CHANNELS (1)
|
||||
|
||||
//hw types
|
||||
#define HW_TYPE_NORMAL HW_TYPE_154_INCH_ZBS_033
|
||||
#define HW_TYPE_CYCLING HW_TYPE_154_INCH_ZBS_033_FRAME_MODE
|
||||
|
||||
|
||||
|
||||
|
||||
#include "../boardCommon.h"
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
|
||||
#endif
|
||||
#define SCREEN_LUT_LENGTH 10
|
||||
|
||||
|
||||
#endif
|
||||
@@ -4,27 +4,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "spi.h"
|
||||
#include "uart.h"
|
||||
|
||||
//colors for ui messages
|
||||
#define UI_MSG_MAGNIFY1 1
|
||||
#define UI_MSG_MAGNIFY2 1
|
||||
#define UI_MSG_MAGNIFY3 1
|
||||
#define UI_MSG_BACK_COLOR 4
|
||||
#define UI_MSG_FORE_COLOR_1 0
|
||||
#define UI_MSG_FORE_COLOR_2 5
|
||||
#define UI_MSG_FORE_COLOR_3 5
|
||||
#define UI_BARCODE_VERTICAL
|
||||
|
||||
#define eepromByte spiByte
|
||||
#define eepromPrvSelect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 0; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
#define eepromPrvDeselect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 1; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
|
||||
//debug uart (enable only when needed, on some boards it inhibits eeprom access)
|
||||
#define dbgUartOn()
|
||||
#define dbgUartOff()
|
||||
#define dbgUartByte uartTx
|
||||
|
||||
//eeprom map
|
||||
#define EEPROM_SETTINGS_AREA_START (0x01000UL)
|
||||
#define EEPROM_SETTINGS_AREA_LEN (0x03000UL)
|
||||
@@ -35,19 +19,10 @@
|
||||
//till end of eeprom really. do not put anything after - it will be erased at pairing time!!!
|
||||
#define EEPROM_PROGRESS_BYTES (128)
|
||||
|
||||
//radio cfg
|
||||
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
|
||||
#define RADIO_NUM_CHANNELS (1)
|
||||
|
||||
//hw types
|
||||
#define HW_TYPE_NORMAL HW_TYPE_29_INCH_ZBS_026
|
||||
#define HW_TYPE_CYCLING HW_TYPE_29_INCH_ZBS_026_FRAME_MODE
|
||||
|
||||
|
||||
|
||||
|
||||
#include "../boardCommon.h"
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -4,12 +4,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
//i hate globals, but for 8051 this makes life a lot easier, sorry :(
|
||||
extern uint8_t __xdata mScreenVcom;
|
||||
extern int8_t __xdata mCurTemperature;
|
||||
|
||||
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 296
|
||||
|
||||
@@ -27,22 +21,7 @@ extern int8_t __xdata mCurTemperature;
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
void screenShutdown(void);
|
||||
|
||||
void screenTest(void);
|
||||
|
||||
__bit screenTxStart(__bit forPartial);
|
||||
|
||||
void screenEndPass(void); //at end of each pass
|
||||
|
||||
#pragma callee_saves screenByteTx
|
||||
void screenByteTx(uint8_t byte);
|
||||
void screenTxEnd(void);
|
||||
|
||||
void screenSleep(void);
|
||||
|
||||
extern uint8_t __xdata mScreenRow[]; //320 bytes used as temp by many on cc where memory is tight
|
||||
|
||||
#endif
|
||||
#define SCREEN_LUT_LENGTH 7
|
||||
|
||||
|
||||
#endif
|
||||
@@ -4,27 +4,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "spi.h"
|
||||
#include "uart.h"
|
||||
|
||||
//colors for ui messages
|
||||
#define UI_MSG_MAGNIFY1 1
|
||||
#define UI_MSG_MAGNIFY2 1
|
||||
#define UI_MSG_MAGNIFY3 1
|
||||
#define UI_MSG_BACK_COLOR 4
|
||||
#define UI_MSG_FORE_COLOR_1 0
|
||||
#define UI_MSG_FORE_COLOR_2 5
|
||||
#define UI_MSG_FORE_COLOR_3 5
|
||||
#define UI_BARCODE_VERTICAL
|
||||
|
||||
#define eepromByte spiByte
|
||||
#define eepromPrvSelect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 0; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
#define eepromPrvDeselect() do { __asm__("nop\nnop\nnop\n"); P1_1 = 1; __asm__("nop\nnop\nnop\n"); } while(0)
|
||||
|
||||
//debug uart (enable only when needed, on some boards it inhibits eeprom access)
|
||||
#define dbgUartOn()
|
||||
#define dbgUartOff()
|
||||
#define dbgUartByte uartTx
|
||||
|
||||
//eeprom map
|
||||
#define EEPROM_SETTINGS_AREA_START (0x01000UL)
|
||||
#define EEPROM_SETTINGS_AREA_LEN (0x03000UL)
|
||||
@@ -35,19 +19,10 @@
|
||||
//till end of eeprom really. do not put anything after - it will be erased at pairing time!!!
|
||||
#define EEPROM_PROGRESS_BYTES (128)
|
||||
|
||||
//radio cfg
|
||||
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
|
||||
#define RADIO_NUM_CHANNELS (1)
|
||||
|
||||
//hw types
|
||||
#define HW_TYPE_NORMAL HW_TYPE_42_INCH_ZBS_026
|
||||
#define HW_TYPE_CYCLING HW_TYPE_42_INCH_ZBS_026_FRAME_MODE
|
||||
|
||||
|
||||
|
||||
|
||||
#include "../boardCommon.h"
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -4,12 +4,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
//i hate globals, but for 8051 this makes life a lot easier, sorry :(
|
||||
extern uint8_t __xdata mScreenVcom;
|
||||
extern int8_t __xdata mCurTemperature;
|
||||
|
||||
|
||||
#define SCREEN_WIDTH 400
|
||||
#define SCREEN_HEIGHT 300
|
||||
|
||||
@@ -27,24 +21,7 @@ extern int8_t __xdata mCurTemperature;
|
||||
|
||||
#define SCREEN_DATA_PASSES 2
|
||||
|
||||
void screenShutdown(void);
|
||||
|
||||
|
||||
void screenTest(void);
|
||||
|
||||
__bit screenTxStart(__bit forPartial);
|
||||
|
||||
void screenEndPass(void); //at end of each pass
|
||||
|
||||
#pragma callee_saves screenByteTx
|
||||
void screenByteTx(uint8_t byte);
|
||||
void screenTxEnd(void);
|
||||
|
||||
void screenSleep(void);
|
||||
|
||||
|
||||
extern uint8_t __xdata mScreenRow[]; //320 bytes used as temp by many on cc where memory is tight
|
||||
|
||||
#endif
|
||||
#define SCREEN_LUT_LENGTH 7
|
||||
|
||||
|
||||
#endif
|
||||
@@ -21,34 +21,8 @@
|
||||
|
||||
static uint8_t __xdata mCommsBuf[127];
|
||||
static uint8_t __xdata mSeq = 0;
|
||||
static uint8_t __xdata mLastLqi = 0;
|
||||
static int8_t __xdata mLastRSSI = 0;
|
||||
|
||||
|
||||
struct MacFrameFromMaster {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint16_t from;
|
||||
};
|
||||
|
||||
struct MacFrameNormal {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint8_t src[8];
|
||||
};
|
||||
|
||||
struct MacFrameBcast {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t dstPan;
|
||||
uint16_t dstAddr;
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
};
|
||||
uint8_t __xdata mLastLqi = 0;
|
||||
int8_t __xdata mLastRSSI = 0;
|
||||
|
||||
uint8_t commsGetLastPacketLQI(void)
|
||||
{
|
||||
|
||||
@@ -3,21 +3,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define COMMS_MAX_RADIO_WAIT_MSEC 200
|
||||
|
||||
#define COMMS_IV_SIZE (4) //zeroes except these 4 counter bytes
|
||||
#define COMMS_MAX_RADIO_WAIT_MSEC 200
|
||||
|
||||
#define COMMS_RX_ERR_NO_PACKETS (-1)
|
||||
#define COMMS_RX_ERR_INVALID_PACKET (-2)
|
||||
#define COMMS_RX_ERR_MIC_FAIL (-3)
|
||||
|
||||
#define COMMS_MAX_PACKET_SZ (127)
|
||||
|
||||
#pragma callee_saves commsGetLastPacketLQI
|
||||
uint8_t commsGetLastPacketLQI(void);
|
||||
|
||||
#pragma callee_saves commsGetLastPacketRSSI
|
||||
int8_t commsGetLastPacketRSSI(void);
|
||||
extern uint8_t __xdata mLastLqi;
|
||||
extern int8_t __xdata mLastRSSI;
|
||||
|
||||
int8_t commsRxUnencrypted(void __xdata *data);
|
||||
bool commsTxUnencrypted(const void __xdata *packetP, uint8_t len);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,10 @@
|
||||
#include "drawing.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "printf.h"
|
||||
@@ -318,10 +320,9 @@ static void drawPrvDecodeImageOnce(void) {
|
||||
}
|
||||
}
|
||||
|
||||
extern uint8_t blockXferBuffer[];
|
||||
static uint8_t __xdata prev, step = 0;
|
||||
|
||||
void ByteDecode(uint8_t byte) {
|
||||
static uint8_t __xdata prev, step = 0;
|
||||
prev <<= 2;
|
||||
prev |= (mColorMap[mPassNo][byte >> 4] << 1) | mColorMap[mPassNo][byte & 0x0f];
|
||||
if (++step == 4) {
|
||||
@@ -341,15 +342,19 @@ void drawImageAtAddress(uint32_t addr) {
|
||||
return;
|
||||
drawPrvLoadAndMapClut(clutAddr);
|
||||
|
||||
//screenTxStart(false);
|
||||
epdSetup();
|
||||
mPassNo = 0;
|
||||
beginFullscreenImage();
|
||||
beginWriteFramebuffer(EPD_COLOR_BLACK);
|
||||
prev = 0;
|
||||
step = 0;
|
||||
drawPrvDecodeImageOnce();
|
||||
endWriteFramebuffer();
|
||||
mPassNo++;
|
||||
beginFullscreenImage();
|
||||
beginWriteFramebuffer(EPD_COLOR_RED);
|
||||
prev = 0;
|
||||
step = 0;
|
||||
drawPrvDecodeImageOnce();
|
||||
endWriteFramebuffer();
|
||||
|
||||
|
||||
225
tag_fw/epd.c
225
tag_fw/epd.c
@@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "barcode.h"
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
#include "font.h"
|
||||
@@ -64,16 +65,24 @@
|
||||
P2_2 = 1; \
|
||||
} while (0)
|
||||
|
||||
static uint8_t __xdata currentLUT = 0x00; // Current selected LUT
|
||||
static bool __idata epdPr = false; // wheter or not we copy the pr("") output to the EPD
|
||||
static uint8_t __xdata epdCharSize = 1; // character size, 1 or 2 (doubled)
|
||||
static bool __xdata directionY = true; // print direction, X or Y (true)
|
||||
static uint8_t __xdata rbuffer[32]; // used to rotate bits around
|
||||
static uint16_t __xdata fontCurXpos = 0; // current X value we're working with
|
||||
static uint16_t __xdata fontCurYpos = 0; // current Y value we're working with
|
||||
extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done
|
||||
|
||||
static uint8_t __xdata epdCharSize = 1; // character size, 1 or 2 (doubled)
|
||||
static bool __xdata directionY = true; // print direction, X or Y (true)
|
||||
static uint8_t __xdata rbuffer[32]; // used to rotate bits around
|
||||
static uint16_t __xdata fontCurXpos = 0; // current X value we're working with
|
||||
static uint16_t __xdata fontCurYpos = 0; // current Y value we're working with
|
||||
static uint8_t __xdata currentLut = 0;
|
||||
|
||||
static bool __xdata isInited = false;
|
||||
struct waveform __xdata waveform;
|
||||
|
||||
uint8_t waveformbuffer[120];
|
||||
#if (SCREEN_LUT_LENGTH == 10)
|
||||
struct waveform10* __xdata waveform = (struct waveform10*)waveformbuffer; // holds the LUT/waveform
|
||||
#endif
|
||||
#if (SCREEN_LUT_LENGTH == 7)
|
||||
struct waveform* __xdata waveform = (struct waveform*)waveformbuffer; // holds the LUT/waveform
|
||||
#endif
|
||||
|
||||
#pragma callee_saves epdBusySleep
|
||||
#pragma callee_saves epdBusyWait
|
||||
@@ -189,13 +198,12 @@ void epdEnterSleep() {
|
||||
P2_0 = 1;
|
||||
timerDelay(50);
|
||||
shortCommand(CMD_SOFT_RESET2);
|
||||
epdBusyWait(133300);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 10);
|
||||
shortCommand1(CMD_ENTER_SLEEP, 0x03);
|
||||
isInited = false;
|
||||
}
|
||||
void epdSetup() {
|
||||
epdReset();
|
||||
currentLUT = 0;
|
||||
shortCommand1(CMD_ANALOG_BLK_CTRL, 0x54);
|
||||
shortCommand1(CMD_DIGITAL_BLK_CTRL, 0x3B);
|
||||
shortCommand2(CMD_UNKNOWN_1, 0x04, 0x63);
|
||||
@@ -219,8 +227,9 @@ void epdSetup() {
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1 (i2C)
|
||||
// shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB9); // mode 2?
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(1333000UL);
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND);
|
||||
isInited = true;
|
||||
currentLut = EPD_LUT_DEFAULT;
|
||||
}
|
||||
static uint8_t epdGetStatus() {
|
||||
uint8_t sta;
|
||||
@@ -238,11 +247,11 @@ uint16_t epdGetBattery(void) {
|
||||
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, SCREEN_CMD_CLOCK_ON | SCREEN_CMD_ANALOG_ON);
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(133300);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
|
||||
for (val = 3; val < 8; val++) {
|
||||
shortCommand1(CMD_SETUP_VOLT_DETECT, val);
|
||||
epdBusyWait(133300);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
if (epdGetStatus() & 0x10) { // set if voltage is less than threshold ( == 1.9 + val / 10)
|
||||
voltage = 1850 + mathPrvMul8x8(val, 100);
|
||||
break;
|
||||
@@ -251,30 +260,109 @@ uint16_t epdGetBattery(void) {
|
||||
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1);
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(133300);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
|
||||
if (!isInited)
|
||||
epdEnterSleep();
|
||||
return voltage;
|
||||
}
|
||||
|
||||
void loadFixedTempOTPLUT() {
|
||||
shortCommand1(0x18, 0x48); // external temp sensor
|
||||
shortCommand2(0x1A, 0x05, 0x00); // < temp register
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1 (i2C)
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND);
|
||||
}
|
||||
static void writeLut() {
|
||||
commandBegin(CMD_WRITE_LUT);
|
||||
for (uint8_t i = 0; i < (SCREEN_LUT_LENGTH * 10); i++)
|
||||
epdSend(waveformbuffer[i]);
|
||||
commandEnd();
|
||||
}
|
||||
static void readLut() {
|
||||
commandReadBegin(0x33);
|
||||
uint16_t checksum = 0;
|
||||
uint16_t ident = 0;
|
||||
uint16_t shortl = 0;
|
||||
for (uint16_t c = 0; c < ((SCREEN_LUT_LENGTH * 10) + 6); c++) {
|
||||
waveformbuffer[c] = epdReadByte();
|
||||
}
|
||||
commandReadEnd();
|
||||
}
|
||||
static void lutGroupDisable(uint8_t group) {
|
||||
memset(&(waveform->group[group]), 0x00, 5);
|
||||
}
|
||||
static void lutGroupSpeedup(uint8_t group, uint8_t speed) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
waveform->group[group].phaselength[i] = 1 + (waveform->group[group].phaselength[i] / speed);
|
||||
}
|
||||
}
|
||||
static void lutGroupRepeat(uint8_t group, uint8_t repeat) {
|
||||
waveform->group[group].repeat = repeat;
|
||||
}
|
||||
static void lutGroupRepeatReduce(uint8_t group, uint8_t factor) {
|
||||
waveform->group[group].repeat = waveform->group[group].repeat / factor;
|
||||
}
|
||||
void selectLUT(uint8_t lut) {
|
||||
if (lut == currentLUT) return;
|
||||
// lut = 1;
|
||||
if (currentLut == lut) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentLut != EPD_LUT_DEFAULT) {
|
||||
// load the 'default' LUT for the current temperature in the EPD lut register
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND);
|
||||
}
|
||||
|
||||
currentLut = lut;
|
||||
|
||||
// if we're going to be using the default LUT, we're done here.
|
||||
if (lut == EPD_LUT_DEFAULT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// download the current LUT from the waveform buffer
|
||||
readLut();
|
||||
|
||||
switch (lut) {
|
||||
case 0:
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(1333000UL);
|
||||
case EPD_LUT_NO_REPEATS:
|
||||
lutGroupDisable(LUTGROUP_NEGATIVE);
|
||||
lutGroupDisable(LUTGROUP_FASTBLINK);
|
||||
lutGroupRepeat(LUTGROUP_SLOWBLINK, 0);
|
||||
lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
lutGroupSpeedup(LUTGROUP_IMPROVE_SHARPNESS, 2);
|
||||
lutGroupRepeatReduce(LUTGROUP_IMPROVE_SHARPNESS, 2);
|
||||
lutGroupSpeedup(LUTGROUP_IMPROVE_REDS, 2);
|
||||
lutGroupRepeatReduce(LUTGROUP_IMPROVE_REDS, 2);
|
||||
break;
|
||||
case 1:
|
||||
commandBegin(CMD_WRITE_LUT);
|
||||
for (uint8_t i = 0; i < 70; i++)
|
||||
epdSend(lutorig[i]);
|
||||
commandEnd();
|
||||
case EPD_LUT_FAST_NO_REDS:
|
||||
lutGroupDisable(LUTGROUP_NEGATIVE);
|
||||
lutGroupDisable(LUTGROUP_FASTBLINK);
|
||||
lutGroupDisable(LUTGROUP_SLOWBLINK);
|
||||
//lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
|
||||
break;
|
||||
case EPD_LUT_FAST:
|
||||
lutGroupDisable(LUTGROUP_NEGATIVE);
|
||||
lutGroupDisable(LUTGROUP_FASTBLINK);
|
||||
lutGroupDisable(LUTGROUP_SLOWBLINK);
|
||||
lutGroupRepeat(LUTGROUP_SET, 0);
|
||||
//lutGroupSpeedup(LUTGROUP_SET, 2);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
|
||||
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
|
||||
break;
|
||||
}
|
||||
currentLUT = lut;
|
||||
|
||||
#if (SCREEN_LUT_LENGTH == 10)
|
||||
lutGroupDisable(LUTGROUP_UNUSED);
|
||||
lutGroupDisable(LUTGROUP_UNKNOWN);
|
||||
lutGroupDisable(LUTGROUP_UNUSED3);
|
||||
lutGroupDisable(LUTGROUP_UNUSED4);
|
||||
#endif
|
||||
writeLut();
|
||||
}
|
||||
|
||||
void setWindowX(uint16_t start, uint16_t end) {
|
||||
@@ -284,8 +372,8 @@ void setWindowY(uint16_t start, uint16_t end) {
|
||||
commandBegin(CMD_WINDOW_Y_SIZE);
|
||||
epdSend((start)&0xff);
|
||||
epdSend((start) >> 8);
|
||||
epdSend((end)&0xff); // was end-1
|
||||
epdSend((end) >> 8); // was end-1
|
||||
epdSend((end - 1) & 0xff);
|
||||
epdSend((end - 1) >> 8);
|
||||
commandEnd();
|
||||
}
|
||||
void setPosXY(uint16_t x, uint16_t y) {
|
||||
@@ -316,10 +404,11 @@ void clearScreen() {
|
||||
setWindowX(0, SCREEN_WIDTH);
|
||||
setWindowY(0, SCREEN_HEIGHT);
|
||||
setPosXY(0, 0);
|
||||
shortCommand1(CMD_DATA_ENTRY_MODE, 3); // was 3
|
||||
shortCommand1(CMD_WRITE_PATTERN_BW, 0x66);
|
||||
epdBusyWait(133300UL);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
shortCommand1(CMD_WRITE_PATTERN_RED, 0x66);
|
||||
epdBusyWait(133300UL);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
}
|
||||
void draw() {
|
||||
shortCommand1(0x22, 0xCF);
|
||||
@@ -332,6 +421,9 @@ void drawNoWait() {
|
||||
// shortCommand1(0x22, SCREEN_CMD_REFRESH);
|
||||
shortCommand(0x20);
|
||||
}
|
||||
void epdWaitRdy() {
|
||||
epdBusyWait(TIMER_TICKS_PER_SECOND * 120);
|
||||
}
|
||||
void drawLineHorizontal(bool color, uint16_t x1, uint16_t x2, uint16_t y) {
|
||||
setWindowX(x1, x2);
|
||||
setWindowY(y, y + 1);
|
||||
@@ -340,9 +432,8 @@ void drawLineHorizontal(bool color, uint16_t x1, uint16_t x2, uint16_t y) {
|
||||
} else {
|
||||
shortCommand1(CMD_WRITE_PATTERN_BW, 0xE6);
|
||||
}
|
||||
epdBusyWait(133300UL);
|
||||
epdBusyWait(TIMER_TICKS_PER_MS * 100);
|
||||
}
|
||||
|
||||
void drawLineVertical(bool color, uint16_t x, uint16_t y1, uint16_t y2) {
|
||||
setWindowY(y1, y2);
|
||||
setWindowX(x, x + 8);
|
||||
@@ -354,7 +445,7 @@ void drawLineVertical(bool color, uint16_t x, uint16_t y1, uint16_t y2) {
|
||||
commandBegin(CMD_WRITE_FB_BW);
|
||||
}
|
||||
uint8_t __xdata c = 0x80;
|
||||
c>>=(x%8);
|
||||
c >>= (x % 8);
|
||||
for (; y1 < y2; y1++) {
|
||||
epdSend(c);
|
||||
}
|
||||
@@ -378,7 +469,43 @@ void beginWriteFramebuffer(bool color) {
|
||||
void endWriteFramebuffer() {
|
||||
commandEnd();
|
||||
}
|
||||
|
||||
void loadRawBitmap(uint8_t* bmp, uint16_t x, uint16_t y, bool color) {
|
||||
uint16_t xsize = bmp[0] / 8;
|
||||
if (bmp[0] % 8) xsize++;
|
||||
uint16_t size = xsize * bmp[1];
|
||||
setWindowX(x, x + (xsize * 8));
|
||||
setWindowY(y, bmp[1] + y);
|
||||
setPosXY(x, y);
|
||||
shortCommand1(CMD_DATA_ENTRY_MODE, 3);
|
||||
if (color) {
|
||||
commandBegin(CMD_WRITE_FB_RED);
|
||||
} else {
|
||||
commandBegin(CMD_WRITE_FB_BW);
|
||||
}
|
||||
bmp += 2;
|
||||
while (size--) {
|
||||
epdSend(*(bmp++));
|
||||
}
|
||||
commandEnd();
|
||||
}
|
||||
void printBarcode(const uint8_t* string, uint16_t x, uint16_t y) {
|
||||
setWindowY(y, 1);
|
||||
setWindowX(x, x + 8);
|
||||
setPosXY(x, y);
|
||||
shortCommand1(CMD_DATA_ENTRY_MODE, 1);
|
||||
commandBegin(CMD_WRITE_FB_BW);
|
||||
struct BarcodeInfo __xdata bci = {
|
||||
.str = string,
|
||||
};
|
||||
while (!barcodeIsDone(&bci)) {
|
||||
if (barcodeNextBar(&bci)) {
|
||||
epdSend(0xFF);
|
||||
} else {
|
||||
epdSend(0x00);
|
||||
}
|
||||
}
|
||||
commandEnd();
|
||||
}
|
||||
// stuff for printing text
|
||||
static void pushXFontBytesToEPD(uint8_t byte1, uint8_t byte2) {
|
||||
if (epdCharSize == 1) {
|
||||
@@ -464,9 +591,6 @@ static void pushYFontBytesToEPD(uint8_t byte1, uint8_t byte2) {
|
||||
}
|
||||
}
|
||||
void writeCharEPD(uint8_t c) {
|
||||
if (!epdPr) {
|
||||
return;
|
||||
}
|
||||
// Writes a single character to the framebuffer
|
||||
bool empty = true;
|
||||
for (uint8_t i = 0; i < 20; i++) {
|
||||
@@ -508,6 +632,7 @@ void writeCharEPD(uint8_t c) {
|
||||
pushXFontBytesToEPD(0x00, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Print text to the EPD. Origin is top-left
|
||||
void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool color) {
|
||||
directionY = direction;
|
||||
@@ -526,7 +651,7 @@ void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool c
|
||||
rbuffer[1] = 0;
|
||||
}
|
||||
|
||||
setWindowY(y, 0);
|
||||
setWindowY(y, 1);
|
||||
if (epdCharSize == 2) {
|
||||
setWindowX(x, x + 32 + extra);
|
||||
setPosXY(x, y);
|
||||
@@ -550,7 +675,6 @@ void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool c
|
||||
memset(rbuffer, 0, 32);
|
||||
}
|
||||
|
||||
epdPr = true;
|
||||
if (color) {
|
||||
commandBegin(CMD_WRITE_FB_RED);
|
||||
} else {
|
||||
@@ -564,29 +688,8 @@ void epdPrintEnd() {
|
||||
}
|
||||
}
|
||||
commandEnd();
|
||||
epdPr = false;
|
||||
}
|
||||
|
||||
void loadFixedTempLUT() {
|
||||
shortCommand1(0x18, 0x48);
|
||||
shortCommand2(0x1A, 0x05, 0x00); // < temp register
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1 (i2C)
|
||||
shortCommand(CMD_ACTIVATION);
|
||||
epdBusyWait(1333000UL);
|
||||
}
|
||||
static void readLut() {
|
||||
commandReadBegin(0x33);
|
||||
uint16_t checksum = 0;
|
||||
uint16_t ident = 0;
|
||||
uint16_t shortl = 0;
|
||||
for (uint16_t c = 0; c < 76; c++) {
|
||||
((uint8_t*)&waveform)[c] = epdReadByte();
|
||||
}
|
||||
commandReadEnd();
|
||||
}
|
||||
|
||||
extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done
|
||||
|
||||
extern uint8_t __xdata blockXferBuffer[];
|
||||
|
||||
void readRam() {
|
||||
@@ -612,4 +715,4 @@ void readRam() {
|
||||
void lutTest() {
|
||||
readLut();
|
||||
dump((uint8_t*)&waveform, 96);
|
||||
}
|
||||
}
|
||||
|
||||
16
tag_fw/epd.h
16
tag_fw/epd.h
@@ -11,11 +11,18 @@
|
||||
#define EPD_SIZE_DOUBLE true
|
||||
#define EPD_COLOR_RED true
|
||||
#define EPD_COLOR_BLACK false
|
||||
|
||||
#define EPD_LOAD_CUSTOM_LUT true
|
||||
#define EPD_LOAD_OTP_LUT false
|
||||
#define EPD_MODE_NORMAL 0x00
|
||||
#define EPD_MODE_INVERT 0x08
|
||||
#define EPD_MODE_IGNORE 0x04
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
|
||||
|
||||
#define epdSelect() \
|
||||
do { \
|
||||
P1_7 = 0; \
|
||||
@@ -38,12 +45,15 @@ void clearWindow(bool color);
|
||||
void clearScreen();
|
||||
void draw();
|
||||
void drawNoWait();
|
||||
void epdWaitRdy();
|
||||
void drawLineHorizontal(bool color, uint16_t x1, uint16_t x2, uint16_t y);
|
||||
void drawLineVertical(bool color, uint16_t x, uint16_t y1, uint16_t y2);
|
||||
|
||||
void beginFullscreenImage();
|
||||
void beginWriteFramebuffer(bool color);
|
||||
void endWriteFramebuffer();
|
||||
void loadRawBitmap(uint8_t* bmp, uint16_t x, uint16_t y, bool color);
|
||||
void printBarcode(const uint8_t* string, uint16_t x, uint16_t y);
|
||||
|
||||
void selectLUT(uint8_t lut);
|
||||
|
||||
@@ -52,10 +62,12 @@ void ByteDecode(uint8_t byte);
|
||||
void epdPrintBegin(uint16_t x, uint16_t y, bool direction, bool fontsize, bool red);
|
||||
void epdPrintEnd();
|
||||
|
||||
|
||||
void beginFullscreenImage();
|
||||
void beginWriteFramebuffer(bool color);
|
||||
|
||||
void lutTest();
|
||||
|
||||
// for printf.c
|
||||
void writeCharEPD(uint8_t c);
|
||||
|
||||
#endif
|
||||
158
tag_fw/lut.h
158
tag_fw/lut.h
@@ -1,5 +1,21 @@
|
||||
#define __packed
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
#define LUTGROUP_NEGATIVE 0
|
||||
#define LUTGROUP_FASTBLINK 1
|
||||
#define LUTGROUP_SLOWBLINK 2
|
||||
#define LUTGROUP_SET 3
|
||||
#define LUTGROUP_IMPROVE_SHARPNESS 4
|
||||
#define LUTGROUP_IMPROVE_REDS 5
|
||||
#define LUTGROUP_UNUSED 6
|
||||
|
||||
#if (SCREEN_LUT_LENGTH == 10)
|
||||
#define LUTGROUP_UNKNOWN 7
|
||||
#define LUTGROUP_UNUSED3 8
|
||||
#define LUTGROUP_UNUSED4 9
|
||||
#endif
|
||||
|
||||
struct vgroup {
|
||||
uint8_t A : 2;
|
||||
uint8_t B : 2;
|
||||
@@ -11,143 +27,29 @@ struct lut {
|
||||
struct vgroup group[7];
|
||||
} __packed;
|
||||
|
||||
struct lut10 {
|
||||
struct vgroup group[10];
|
||||
} __packed;
|
||||
|
||||
struct group {
|
||||
uint8_t phaselength[4];
|
||||
uint8_t repeat;
|
||||
} __packed;
|
||||
|
||||
struct waveform {
|
||||
struct lut elut[5];
|
||||
struct group egroup[7];
|
||||
struct lut lut[5];
|
||||
struct group group[7];
|
||||
uint8_t gatelevel;
|
||||
uint8_t sourcelevel[3];
|
||||
uint8_t dummyline;
|
||||
uint8_t gatewidth;
|
||||
} __packed;
|
||||
|
||||
static const uint8_t __code lut154[] = {
|
||||
// lut0 (KEEP) voltages
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut1 (W2B) voltages
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut2 (B2W) voltages
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut3 (unused) voltages
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut4 (vcom) voltages
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group0 phase lengths and repeat count
|
||||
0x40, 0x0, 0x00, 0x00, 0x00,
|
||||
// group1 not used
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group2 not used
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group3 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group4 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group5 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group6 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
static const uint8_t __code lut29[] = {
|
||||
// lut0 (KEEP) voltages
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut1 (W2B) voltages
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut2 (B2W) voltages
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut3 (unused) voltages
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// lut4 (vcom) voltages
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group0 phase lengths and repeat count
|
||||
// 0x10, 0x02, 0x00, 0x00, 0x03 - 1,
|
||||
0x05, 0x02, 0x00, 0x00, 0x00,
|
||||
|
||||
// 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// group1 not used
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group2 not used
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group3 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group4 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group5 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// group6 phase lengths and repeat count
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t __code lutSHA[] = {
|
||||
// Voltages and other settings? Timing?
|
||||
0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0,
|
||||
0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0,
|
||||
0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0,
|
||||
0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
// Update program
|
||||
//
|
||||
// Top three lines are the main program (bottom 4 have unknown function)
|
||||
// Line 1: Negative image
|
||||
// Line 2: White/Black flashing
|
||||
// Line 3: Positive image
|
||||
//
|
||||
// Line construction
|
||||
// First two bytes denote Intensity (range 0x00 to 0x0F)
|
||||
// Second two bytes denote lenght of each 'pulse' (range 0x00 to 0xFF)
|
||||
// Last byte denotes number of repeats (0 = line runs 1 time, range 0x00 to 0xFF)
|
||||
// If you don't want a line to do anything, set all bytes to 0x0.
|
||||
// This way you can make a quick update cycle between two screens.
|
||||
// Maybe not as pretty/crisp but nice and fast is also awesome!
|
||||
|
||||
// Negative image
|
||||
// first two bytes negative image, length white pulse (0-FF), length black pulse (0-FF), last byte repeats
|
||||
|
||||
0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
//0xF, 0xF, 0x0, 0x0, 0x0,
|
||||
|
||||
// White or black flash
|
||||
// white flash intensity, black flash intensity, length white pulse (0-FF), length black pulse (0-FF), repeats
|
||||
|
||||
//0x0, 0x0, 0x0, 0x0, 0x00,
|
||||
0xF, 0xF, 0x1, 0x1, 0x00,
|
||||
//0xF, 0xF, 0x0, 0x0, 0x02,
|
||||
|
||||
|
||||
// Positive image
|
||||
// first byte or second byte positive image (don't know why you need both), rest same as above
|
||||
|
||||
0xF, 0xF, 0x0, 0x0, 0x0,
|
||||
|
||||
// Unknown what lines below actually do.
|
||||
// They seem to be programs to, but have no visible effect on dislay.
|
||||
0x0F, 0x0F, 0x0, 0x0, 0x0,
|
||||
0x0F, 0x0F, 0x0, 0x0, 0x0,
|
||||
0x0F, 0x0F, 0x0, 0x0, 0x0,
|
||||
0x0F, 0x0F, 0x0, 0x0, 0x0,
|
||||
};
|
||||
|
||||
|
||||
static const uint8_t __code lutorig[] = {
|
||||
0x00, 0x66, 0x21, 0x45, 0x40, 0x00, 0x00,
|
||||
0x15, 0x66, 0x21, 0xA8, 0x20, 0xA0, 0x00,
|
||||
0xA0, 0x66, 0x21, 0x85, 0x2B, 0x2F, 0x00,
|
||||
0xA0, 0x66, 0x21, 0x85, 0x2B, 0x2F, 0x00,
|
||||
0x00, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00,
|
||||
//0x04, 0x49, 0x2F, 0x2A, 0x00,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x02, 0x04, 0x01, 0x03, 0x00, // was 11 repeat
|
||||
0x01, 0x14, 0x01, 0x14, 0x00, // was 3 repeat
|
||||
0x02, 0x0A, 0x03, 0x0A, 0x00, // was 2 repeat
|
||||
0x06, 0x04, 0x04, 0x20, 0x00, // was 3 rpeat
|
||||
0x04, 0x04, 0x02, 0x26, 0x00, // was 3 repeat
|
||||
0x00, 0x00, 0x00, 0x00, 0x0,
|
||||
};
|
||||
struct waveform10 {
|
||||
struct lut10 lut[5];
|
||||
struct group group[10];
|
||||
uint8_t gatelevel;
|
||||
uint8_t sourcelevel[3];
|
||||
uint8_t dummyline;
|
||||
uint8_t gatewidth;
|
||||
} __packed;
|
||||
136
tag_fw/main.c
136
tag_fw/main.c
@@ -4,22 +4,140 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "comms.h" // for mLastLqi and mLastRSSI
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "screen.h"
|
||||
#include "sleep.h"
|
||||
#include "timer.h"
|
||||
#include "wdt.h"
|
||||
#include "syncedproto.h"
|
||||
#include "timer.h"
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
|
||||
//#define DEBUG_MODE
|
||||
|
||||
void main(void){
|
||||
uint8_t showChannelSelect() {
|
||||
uint8_t __xdata result[16];
|
||||
memset(result, 0, sizeof(result));
|
||||
showScanningWindow();
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
for (uint8_t c = 11; c < 27; c++) {
|
||||
if (probeChannel(c)) {
|
||||
if (mLastLqi > result[c - 11]) result[c - 11] = mLastLqi;
|
||||
pr("Channel: %d - LQI: %d RSSI %d\n", c, mLastLqi, mLastRSSI);
|
||||
}
|
||||
}
|
||||
epdWaitRdy();
|
||||
for (uint8_t c = 0; c < 16; c++) {
|
||||
addScanResult(11 + c, result[c]);
|
||||
}
|
||||
drawNoWait();
|
||||
}
|
||||
uint8_t __xdata highestLqi = 0;
|
||||
uint8_t __xdata highestSlot = 0;
|
||||
for (uint8_t c = 0; c < sizeof(result); c++) {
|
||||
if (result[c] > highestLqi) {
|
||||
highestSlot = c + 11;
|
||||
highestLqi = result[c];
|
||||
}
|
||||
}
|
||||
epdWaitRdy();
|
||||
mLastLqi = highestLqi;
|
||||
return highestSlot;
|
||||
}
|
||||
|
||||
void mainProtocolLoop(void) {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
boardInit();
|
||||
|
||||
if (!boardGetOwnMac(mSelfMac)) {
|
||||
pr("failed to get MAC. Aborting\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
}
|
||||
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
|
||||
pr("BOOTED> (UI 0.03-1)\n\n");
|
||||
|
||||
if (!eepromInit()) {
|
||||
pr("failed to init eeprom\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
initializeProto();
|
||||
}
|
||||
eepromDeepPowerDown();
|
||||
// initialize Powers-saving-attempt-array with the default value;
|
||||
initPowerSaving();
|
||||
#ifndef DEBUG_MODE
|
||||
// show the splashscreen
|
||||
showSplashScreen();
|
||||
|
||||
eepromDeepPowerDown();
|
||||
initRadio();
|
||||
|
||||
currentChannel = showChannelSelect();
|
||||
if (currentChannel == 0) {
|
||||
// couldn't find an AP :()
|
||||
showNoAP();
|
||||
} else {
|
||||
radioSetChannel(currentChannel);
|
||||
// Found an AP.
|
||||
showAPFound();
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_MODE
|
||||
initRadio();
|
||||
currentChannel = 11;
|
||||
#endif
|
||||
epdEnterSleep();
|
||||
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
|
||||
while (1) {
|
||||
radioRxEnable(true, true);
|
||||
|
||||
struct AvailDataInfo *__xdata avail = getAvailDataInfo();
|
||||
if (avail == NULL) {
|
||||
// no data :(
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
if (doDataDownload(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
}
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
mainProtocolLoop();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
@echo off
|
||||
del fs154.bin
|
||||
del fw29.bin
|
||||
del fw42.bin
|
||||
makeit clean
|
||||
makeit
|
||||
makeit BUILD=zbs154v033 CPU=8051 SOC=zbs243
|
||||
pause
|
||||
ren main.bin fw154.bin
|
||||
makeit clean
|
||||
makeit BUILD=zbs29v033 CPU=8051 SOC=zbs243
|
||||
pause
|
||||
ren main.bin fw29.bin
|
||||
makeit clean
|
||||
makeit BUILD=zbs42v033 CPU=8051 SOC=zbs243
|
||||
pause
|
||||
ren main.bin fw42.bin
|
||||
|
||||
del /s *.asm
|
||||
del /s *.lst
|
||||
del /s *.rst
|
||||
|
||||
92
tag_fw/powermgt.c
Normal file
92
tag_fw/powermgt.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "powermgt.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "eeprom.h"
|
||||
#include "epd.h"
|
||||
#include "i2c.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "sleep.h"
|
||||
#include "syncedproto.h"
|
||||
#include "timer.h"
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
uint16_t __xdata dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
|
||||
uint8_t __xdata dataReqAttemptArrayIndex = 0;
|
||||
uint8_t __xdata dataReqLastAttempt = 0;
|
||||
uint16_t __xdata nextCheckInFromAP = 0;
|
||||
|
||||
void initPowerSaving() {
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
dataReqAttemptArr[c] = INTERVAL_BASE;
|
||||
}
|
||||
}
|
||||
|
||||
// init/sleep
|
||||
void initAfterWake() {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
// partialInit();
|
||||
boardInit();
|
||||
epdEnterSleep();
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
initRadio();
|
||||
}
|
||||
void doSleep(uint32_t __xdata t) {
|
||||
if (t > 1000) pr("s=%lu\n ", t / 1000);
|
||||
powerPortsDownForSleep();
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// Button setup on TEST pin 1.0 (input pullup)
|
||||
P1FUNC &= ~(1 << 0);
|
||||
P1DIR |= (1 << 0);
|
||||
P1PULL |= (1 << 0);
|
||||
P1LVLSEL |= (1 << 0);
|
||||
P1INTEN = (1 << 0);
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
#endif
|
||||
|
||||
// sleepy
|
||||
sleepForMsec(t);
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
P1INTEN = 0;
|
||||
#endif
|
||||
|
||||
initAfterWake();
|
||||
}
|
||||
uint16_t getNextSleep() {
|
||||
uint16_t __xdata curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
|
||||
curval *= dataReqLastAttempt;
|
||||
curval /= DATA_REQ_MAX_ATTEMPTS;
|
||||
curval += INTERVAL_BASE;
|
||||
dataReqAttemptArr[dataReqAttemptArrayIndex % POWER_SAVING_SMOOTHING] = curval;
|
||||
dataReqAttemptArrayIndex++;
|
||||
|
||||
uint16_t avg = 0;
|
||||
bool noNetwork = true;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
avg += dataReqAttemptArr[c];
|
||||
if (dataReqAttemptArr[c] != INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
noNetwork = false;
|
||||
}
|
||||
}
|
||||
if (noNetwork == true) return INTERVAL_NO_SIGNAL;
|
||||
avg /= POWER_SAVING_SMOOTHING;
|
||||
return avg;
|
||||
}
|
||||
24
tag_fw/powermgt.h
Normal file
24
tag_fw/powermgt.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _POWERMGT_H_
|
||||
#define _POWERMGT_H_
|
||||
#include <stdint.h>
|
||||
|
||||
// power saving algorithm
|
||||
#define INTERVAL_BASE 40 // interval (in seconds) (when 1 packet is sent/received) for target current (7.2µA)
|
||||
#define INTERVAL_AT_MAX_ATTEMPTS 600 // interval (in seconds) (at max attempts) for target average current
|
||||
#define INTERVAL_NO_SIGNAL 1800 // interval (in seconds) when no answer for POWER_SAVING_SMOOTHING attempts,
|
||||
// (INTERVAL_AT_MAX_ATTEMPTS * POWER_SAVING_SMOOTHING) seconds
|
||||
#define DATA_REQ_RX_WINDOW_SIZE 5UL // How many milliseconds we should wait for a packet during the data_request.
|
||||
// If the AP holds a long list of data for tags, it may need a little more time to lookup the mac address
|
||||
#define DATA_REQ_MAX_ATTEMPTS 14 // How many attempts (at most) we should do to get something back from the AP
|
||||
#define POWER_SAVING_SMOOTHING 8 // How many samples we should use to smooth the data request interval
|
||||
#define MINIMUM_INTERVAL 45 // IMPORTANT: Minimum interval for check-in; this determines overal battery life!
|
||||
|
||||
extern void initAfterWake();
|
||||
extern void doSleep(uint32_t __xdata t);
|
||||
extern uint16_t getNextSleep();
|
||||
extern void initPowerSaving();
|
||||
|
||||
extern uint16_t __xdata nextCheckInFromAP;
|
||||
extern uint8_t __xdata dataReqLastAttempt;
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,9 @@
|
||||
#pragma callee_saves pr
|
||||
void pr(const char __code *fmt, ...) __reentrant;
|
||||
|
||||
#pragma callee_saves epdpr
|
||||
void epdpr(const char __code *fmt, ...) __reentrant;
|
||||
|
||||
#pragma callee_saves spr
|
||||
void spr(char __xdata* out, const char __code *fmt, ...) __reentrant;
|
||||
|
||||
|
||||
241
tag_fw/proto.h
241
tag_fw/proto.h
@@ -1,47 +1,8 @@
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
|
||||
#define __packed
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
All communications are direct from tag to station, EXCEPT association (tag will broadcast).
|
||||
All comms shall be encrypted and authenticated with AES-CCM. Shared key shall be burned into the firmware.
|
||||
Master shall provision new key at association. All non-bcast packets shall have pan id compression.
|
||||
Master may skip "from" field. Tag checking in confirms it got the master's provisioning reply.
|
||||
|
||||
Sadly filtering on MZ100 fails for long addr with no src addr. so short addr for src is used
|
||||
|
||||
T = tag, S = station
|
||||
|
||||
PACKET TYPE USE PAYLOAD STRUCT NOTES
|
||||
ASSOC_REQ T2bcast TagInfo tag's info and assoc request (encrypted with shared key)
|
||||
ASSOC_RESP S2T AssocInfo tag's association info (encrypted with shared key)
|
||||
CHECKIN T2S CheckinInfo tag checking in occasionally
|
||||
CHECKOUT S2T PendingInfo station's checkin reply telling tag what we have for it
|
||||
CHUNK_REQ T2S ChunkReqInfo tag requesting a piece of data
|
||||
CHUNK_RESP S2T ChunkInfo station provides chunk
|
||||
|
||||
*/
|
||||
|
||||
#define PROTO_PRESHARED_KEY {0x34D906D3, 0xE3E5298E, 0x3429BF58, 0xC1022081}
|
||||
|
||||
#define PROTO_PAN_ID (0x4447) //PAN ID compression shall be used
|
||||
|
||||
#define PKT_ASSOC_REQ (0xF0)
|
||||
#define PKT_ASSOC_RESP (0xF1)
|
||||
#define PKT_CHECKIN (0xF2)
|
||||
#define PKT_CHECKOUT (0xF3)
|
||||
#define PKT_CHUNK_REQ (0xF4)
|
||||
#define PKT_CHUNK_RESP (0xF5)
|
||||
|
||||
#define PROTO_VER_0 (0)
|
||||
#define PROTO_VER_CURRENT (PROTO_VER_0)
|
||||
|
||||
#define PROTO_COMPR_TYPE_LZ (0x0001)
|
||||
#define PROTO_COMPR_TYPE_BITPACK (0x0002)
|
||||
|
||||
#define PROTO_MAX_DL_LEN (88)
|
||||
|
||||
enum TagScreenType {
|
||||
TagScreenEink_BW_1bpp,
|
||||
TagScreenEink_BW_2bpp,
|
||||
@@ -72,111 +33,135 @@ enum TagScreenType {
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
struct TagState {
|
||||
uint64_t swVer;
|
||||
uint16_t hwType;
|
||||
uint16_t batteryMv;
|
||||
#define PROTO_PAN_ID (0x4447) //PAN ID compression shall be used
|
||||
|
||||
|
||||
#define RADIO_MAX_PACKET_LEN (125) //useful payload, not including the crc
|
||||
|
||||
#define ADDR_MODE_NONE (0)
|
||||
#define ADDR_MODE_SHORT (2)
|
||||
#define ADDR_MODE_LONG (3)
|
||||
|
||||
#define FRAME_TYPE_BEACON (0)
|
||||
#define FRAME_TYPE_DATA (1)
|
||||
#define FRAME_TYPE_ACK (2)
|
||||
#define FRAME_TYPE_MAC_CMD (3)
|
||||
|
||||
#define SHORT_MAC_UNUSED (0x10000000UL) //for radioRxFilterCfg's myShortMac
|
||||
|
||||
|
||||
|
||||
struct MacFcs {
|
||||
uint8_t frameType : 3;
|
||||
uint8_t secure : 1;
|
||||
uint8_t framePending : 1;
|
||||
uint8_t ackReqd : 1;
|
||||
uint8_t panIdCompressed : 1;
|
||||
uint8_t rfu1 : 1;
|
||||
uint8_t rfu2 : 2;
|
||||
uint8_t destAddrType : 2;
|
||||
uint8_t frameVer : 2;
|
||||
uint8_t srcAddrType : 2;
|
||||
} __packed ;
|
||||
|
||||
struct MacFrameFromMaster {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint16_t from;
|
||||
} __packed;
|
||||
|
||||
struct TagInfo {
|
||||
uint8_t protoVer; //PROTO_VER_*
|
||||
struct TagState state;
|
||||
uint8_t rfu1[1]; //shall be ignored for now
|
||||
uint16_t screenPixWidth;
|
||||
uint16_t screenPixHeight;
|
||||
uint16_t screenMmWidth;
|
||||
uint16_t screenMmHeight;
|
||||
uint16_t compressionsSupported; //COMPR_TYPE_* bitfield
|
||||
uint16_t maxWaitMsec; //how long tag will wait for packets before going to sleep
|
||||
uint8_t screenType; //enum TagScreenType
|
||||
uint8_t rfu[11]; //shall be zero for now
|
||||
struct MacFrameNormal {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
|
||||
struct AssocInfo {
|
||||
uint32_t checkinDelay; //space between checkins, in msec
|
||||
uint32_t retryDelay; //if download fails mid-way wait thi smany msec to retry (IFF progress was made)
|
||||
uint16_t failedCheckinsTillBlank; //how many fails till we go blank
|
||||
uint16_t failedCheckinsTillDissoc; //how many fails till we dissociate
|
||||
uint32_t newKey[4];
|
||||
uint8_t rfu[8]; //shall be zero for now
|
||||
struct MacFrameBcast {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t dstPan;
|
||||
uint16_t dstAddr;
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
|
||||
#define CHECKIN_TEMP_OFFSET 0x7f
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
||||
#define PKT_BLOCK_REQUEST_ACK 0xE9
|
||||
#define PKT_BLOCK_REQUEST 0xE4
|
||||
#define PKT_BLOCK_PART 0xE8
|
||||
#define PKT_XFER_COMPLETE 0xEA
|
||||
#define PKT_XFER_COMPLETE_ACK 0xEB
|
||||
#define PKT_CANCEL_XFER 0xEC
|
||||
|
||||
struct CheckinInfo {
|
||||
struct TagState state;
|
||||
uint8_t lastPacketLQI; //zero if not reported/not supported to be reported
|
||||
int8_t lastPacketRSSI; //zero if not reported/not supported to be reported
|
||||
uint8_t temperature; //zero if not reported/not supported to be reported. else, this minus CHECKIN_TEMP_OFFSET is temp in degrees C
|
||||
uint8_t rfu[6]; //shall be zero for now
|
||||
struct AvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t lastPacketLQI; // zero if not reported/not supported to be reported
|
||||
int8_t lastPacketRSSI; // zero if not reported/not supported to be reported
|
||||
uint8_t temperature; // zero if not reported/not supported to be reported. else, this minus CHECKIN_TEMP_OFFSET is temp in degrees C
|
||||
uint16_t batteryMv;
|
||||
uint8_t softVer;
|
||||
uint8_t hwType;
|
||||
uint8_t protoVer;
|
||||
uint8_t buttonState;
|
||||
} __packed;
|
||||
|
||||
struct PendingInfo {
|
||||
uint64_t imgUpdateVer;
|
||||
uint32_t imgUpdateSize;
|
||||
uint64_t osUpdateVer; //version of OS update avail
|
||||
uint32_t osUpdateSize;
|
||||
uint8_t rfu[8]; //shall be zero for now
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define DATATYPE_IMG 1
|
||||
#define DATATYPE_IMGRAW 2
|
||||
#define DATATYPE_UPDATE 3
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer;
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint16_t nextCheckIn;
|
||||
} __packed;
|
||||
|
||||
struct ChunkReqInfo {
|
||||
uint64_t versionRequested;
|
||||
uint32_t offset;
|
||||
uint8_t len;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu[6]; //shall be zero for now
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
uint8_t blockPart;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct ChunkInfo {
|
||||
uint32_t offset;
|
||||
uint8_t osUpdatePlz : 1;
|
||||
uint8_t rfu; //shall be zero for now
|
||||
uint8_t data[]; //no data means request is out of bounds of this version no longer exists
|
||||
struct blockData {
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct burstMacData {
|
||||
uint16_t offset;
|
||||
uint8_t targetMac[8];
|
||||
} __packed;
|
||||
|
||||
#define BLOCK_PART_DATA_SIZE 99
|
||||
#define BLOCK_MAX_PARTS 42
|
||||
#define BLOCK_DATA_SIZE 4096UL
|
||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
||||
#define BLOCK_REQ_PARTS_BYTES 6
|
||||
|
||||
struct blockRequest {
|
||||
uint8_t checksum;
|
||||
uint64_t ver;
|
||||
uint8_t blockId;
|
||||
uint8_t type;
|
||||
uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES];
|
||||
} __packed;
|
||||
|
||||
struct blockRequestAck {
|
||||
uint8_t checksum;
|
||||
uint16_t pleaseWaitMs;
|
||||
} __packed;
|
||||
|
||||
#define MACFMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define MACCVT(x) ((const uint8_t*)(x))[7], ((const uint8_t*)(x))[6], ((const uint8_t*)(x))[5], ((const uint8_t*)(x))[4], ((const uint8_t*)(x))[3], ((const uint8_t*)(x))[2], ((const uint8_t*)(x))[1], ((const uint8_t*)(x))[0]
|
||||
|
||||
|
||||
#define VERSION_SIGNIFICANT_MASK (0x0000ffffffffffffull)
|
||||
|
||||
#define HW_TYPE_42_INCH_SAMSUNG (1)
|
||||
#define HW_TYPE_42_INCH_SAMSUNG_ROM_VER_OFST (0xEFF8)
|
||||
|
||||
#define HW_TYPE_74_INCH_DISPDATA (2)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_FRAME_MODE (3)
|
||||
#define HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_ZBD_EPOP50 (4)
|
||||
#define HW_TYPE_ZBD_EPOP50_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_ZBD_EPOP900 (5)
|
||||
#define HW_TYPE_ZBD_EPOP900_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_29_INCH_DISPDATA (6)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_FRAME_MODE (7)
|
||||
#define HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST (0x008b)
|
||||
|
||||
#define HW_TYPE_29_INCH_ZBS_026 (8)
|
||||
#define HW_TYPE_29_INCH_ZBS_026_FRAME_MODE (9)
|
||||
|
||||
#define HW_TYPE_154_INCH_ZBS_033 (18)
|
||||
#define HW_TYPE_154_INCH_ZBS_033_FRAME_MODE (19)
|
||||
|
||||
#define HW_TYPE_42_INCH_ZBS_026 (28)
|
||||
#define HW_TYPE_42_INCH_ZBS_026_FRAME_MODE (29)
|
||||
|
||||
#define HW_TYPE_29_INCH_ZBS_025 (10)
|
||||
#define HW_TYPE_29_INCH_ZBS_025_FRAME_MODE (11)
|
||||
|
||||
#define HW_TYPE_29_INCH_ZBS_ROM_VER_OFST (0x008b)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
12
tag_fw/settings.h
Normal file
12
tag_fw/settings.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef SYNCED_H
|
||||
#define SYNCED_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FW_VERSION 012 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-rf15" // suffix, like -RC1 or whatever.
|
||||
#define HAS_BUTTON // uncomment to enable reading a push button (connect between 'TEST' en 'GND' on the tag, along with a 100nF capacitor in parallel).
|
||||
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
|
||||
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
//radio cfg
|
||||
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
|
||||
#define RADIO_NUM_CHANNELS (15)
|
||||
|
||||
|
||||
#define RADIO_MAX_PACKET_LEN (125) //useful payload, not including the crc
|
||||
|
||||
@@ -20,22 +24,6 @@
|
||||
#define SHORT_MAC_UNUSED (0x10000000UL) //for radioRxFilterCfg's myShortMac
|
||||
|
||||
|
||||
|
||||
struct MacFcs {
|
||||
|
||||
uint8_t frameType : 3;
|
||||
uint8_t secure : 1;
|
||||
uint8_t framePending : 1;
|
||||
uint8_t ackReqd : 1;
|
||||
uint8_t panIdCompressed : 1;
|
||||
uint8_t rfu1 : 1;
|
||||
uint8_t rfu2 : 2;
|
||||
uint8_t destAddrType : 2;
|
||||
uint8_t frameVer : 2;
|
||||
uint8_t srcAddrType : 2;
|
||||
};
|
||||
|
||||
|
||||
void radioInit(void);
|
||||
bool radioTx(const void __xdata* packet); //waits for tx end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define TIMER_TICKS_PER_SECOND (16000000 / 12) //overflows every 53 minutes
|
||||
|
||||
#define TIMER_TICKS_PER_MS 1333UL
|
||||
//this is a requirement by SDCC. is this prototype is missing when compiling main(), we get no irq handler
|
||||
void T0_ISR(void) __interrupt (1);
|
||||
|
||||
|
||||
@@ -12,10 +12,7 @@ void uartInit(void) {
|
||||
UARTSTA = 0x12; // also set the "empty" bit else we wait forever for it to go up
|
||||
}
|
||||
|
||||
extern void writeCharEPD(uint8_t c);
|
||||
|
||||
void uartTx(uint8_t val) {
|
||||
writeCharEPD(val);
|
||||
while (!(UARTSTA & (1 << 1)))
|
||||
;
|
||||
UARTSTA &= ~(1 << 1);
|
||||
|
||||
@@ -6,122 +6,23 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "drawing.h"
|
||||
#include "eeprom.h"
|
||||
#include "i2c.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "proto.h"
|
||||
#include "radio.h"
|
||||
#include "epd.h"
|
||||
#include "userinterface.h"
|
||||
#include "settings.h"
|
||||
#include "sleep.h"
|
||||
#include "timer.h"
|
||||
#include "userinterface.h"
|
||||
#include "wdt.h"
|
||||
|
||||
struct MacFrameFromMaster {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint16_t from;
|
||||
} __packed;
|
||||
|
||||
struct MacFrameNormal {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t pan;
|
||||
uint8_t dst[8];
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
|
||||
struct MacFrameBcast {
|
||||
struct MacFcs fcs;
|
||||
uint8_t seq;
|
||||
uint16_t dstPan;
|
||||
uint16_t dstAddr;
|
||||
uint16_t srcPan;
|
||||
uint8_t src[8];
|
||||
} __packed;
|
||||
|
||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
||||
#define PKT_BLOCK_REQUEST_ACK 0xE9
|
||||
#define PKT_BLOCK_REQUEST 0xE4
|
||||
#define PKT_BLOCK_PART 0xE8
|
||||
#define PKT_XFER_COMPLETE 0xEA
|
||||
#define PKT_XFER_COMPLETE_ACK 0xEB
|
||||
#define PKT_CANCEL_XFER 0xEC
|
||||
|
||||
struct AvailDataReq {
|
||||
uint8_t checksum;
|
||||
uint8_t lastPacketLQI; // zero if not reported/not supported to be reported
|
||||
int8_t lastPacketRSSI; // zero if not reported/not supported to be reported
|
||||
uint8_t temperature; // zero if not reported/not supported to be reported. else, this minus CHECKIN_TEMP_OFFSET is temp in degrees C
|
||||
uint16_t batteryMv;
|
||||
uint8_t softVer;
|
||||
uint8_t hwType;
|
||||
uint8_t protoVer;
|
||||
uint8_t buttonState;
|
||||
} __packed;
|
||||
|
||||
#define DATATYPE_NOUPDATE 0
|
||||
#define DATATYPE_IMG 1
|
||||
#define DATATYPE_IMGRAW 2
|
||||
#define DATATYPE_UPDATE 3
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer;
|
||||
uint32_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint16_t nextCheckIn;
|
||||
} __packed;
|
||||
|
||||
struct blockPart {
|
||||
uint8_t checksum;
|
||||
uint8_t blockId;
|
||||
uint8_t blockPart;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct blockData {
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct burstMacData {
|
||||
uint16_t offset;
|
||||
uint8_t targetMac[8];
|
||||
} __packed;
|
||||
|
||||
#define BLOCK_PART_DATA_SIZE 99
|
||||
#define BLOCK_MAX_PARTS 42
|
||||
#define BLOCK_DATA_SIZE 4096UL
|
||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
||||
#define BLOCK_REQ_PARTS_BYTES 6
|
||||
|
||||
struct blockRequest {
|
||||
uint8_t checksum;
|
||||
uint64_t ver;
|
||||
uint8_t blockId;
|
||||
uint8_t type;
|
||||
uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES];
|
||||
} __packed;
|
||||
|
||||
struct blockRequestAck {
|
||||
uint8_t checksum;
|
||||
uint16_t pleaseWaitMs;
|
||||
} __packed;
|
||||
|
||||
#define TIMER_TICKS_PER_MS 1333UL
|
||||
// #define DEBUGBLOCKS
|
||||
|
||||
// download-stuff
|
||||
bool __xdata dataPending = true;
|
||||
uint8_t __xdata blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
|
||||
@@ -131,7 +32,7 @@ uint16_t __xdata dataRemaining = 0;
|
||||
bool __xdata curXferComplete = false;
|
||||
bool __xdata requestPartialBlock = false;
|
||||
|
||||
//uint8_t __xdata *tempBuffer = blockXferBuffer;
|
||||
// uint8_t __xdata *tempBuffer = blockXferBuffer;
|
||||
uint8_t __xdata curImgSlot = 0;
|
||||
uint32_t __xdata curHighSlotId = 0;
|
||||
uint8_t __xdata nextImgSlot = 0;
|
||||
@@ -148,24 +49,7 @@ uint8_t __xdata APmac[8] = {0};
|
||||
uint16_t __xdata APsrcPan = 0;
|
||||
uint8_t __xdata mSelfMac[8] = {0};
|
||||
uint8_t __xdata seq = 0;
|
||||
|
||||
// power saving algorithm
|
||||
#define INTERVAL_BASE 40 // interval (in seconds) (when 1 packet is sent/received) for target current (7.2µA)
|
||||
#define INTERVAL_AT_MAX_ATTEMPTS 600 // interval (in seconds) (at max attempts) for target average current
|
||||
#define INTERVAL_NO_SIGNAL 1800 // interval (in seconds) when no answer for POWER_SAVING_SMOOTHING attempts,
|
||||
// (INTERVAL_AT_MAX_ATTEMPTS * POWER_SAVING_SMOOTHING) seconds
|
||||
#define DATA_REQ_RX_WINDOW_SIZE 5UL // How many milliseconds we should wait for a packet during the data_request.
|
||||
// If the AP holds a long list of data for tags, it may need a little more time to lookup the mac address
|
||||
#define DATA_REQ_MAX_ATTEMPTS 14 // How many attempts (at most) we should do to get something back from the AP
|
||||
#define POWER_SAVING_SMOOTHING 8 // How many samples we should use to smooth the data request interval
|
||||
#define MINIMUM_INTERVAL 45 // IMPORTANT: Minimum interval for check-in; this determines overal battery life!
|
||||
|
||||
#define HAS_BUTTON // uncomment to enable reading a push button (connect between 'TEST' en 'GND' on the tag, along with a 100nF capacitor in parallel).
|
||||
|
||||
uint16_t __xdata dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
|
||||
uint8_t __xdata dataReqAttemptArrayIndex = 0;
|
||||
uint8_t __xdata dataReqLastAttempt = 0;
|
||||
uint16_t __xdata nextCheckInFromAP = 0;
|
||||
uint8_t __xdata currentChannel = 0;
|
||||
|
||||
// buffer we use to prepare/read packets
|
||||
// static uint8_t __xdata mRxBuf[130];
|
||||
@@ -224,11 +108,15 @@ void addCRC(void *p, uint8_t len) {
|
||||
((uint8_t *)p)[0] = total;
|
||||
}
|
||||
|
||||
// init/sleep
|
||||
// radio stuff
|
||||
void initRadio() {
|
||||
radioInit();
|
||||
radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
if (currentChannel >= 11 && currentChannel <= 25) {
|
||||
radioSetChannel(currentChannel);
|
||||
} else {
|
||||
radioSetChannel(RADIO_FIRST_CHANNEL);
|
||||
}
|
||||
radioSetTxPower(10);
|
||||
}
|
||||
void killRadio() {
|
||||
@@ -242,58 +130,14 @@ void killRadio() {
|
||||
RADIO_command = 0xC5;
|
||||
CFGPAGE = cfgPg;
|
||||
}
|
||||
void initAfterWake() {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
// partialInit();
|
||||
boardInit();
|
||||
epdEnterSleep();
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
initRadio();
|
||||
}
|
||||
void doSleep(uint32_t __xdata t) {
|
||||
if (t > 1000) pr("s=%lu\n ", t / 1000);
|
||||
powerPortsDownForSleep();
|
||||
bool probeChannel(uint8_t channel) {
|
||||
radioRxEnable(false, true);
|
||||
radioRxFlush();
|
||||
radioSetChannel(channel);
|
||||
radioRxEnable(true, true);
|
||||
getAvailDataInfo();
|
||||
return(dataReqLastAttempt != DATA_REQ_MAX_ATTEMPTS);
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
// Button setup on TEST pin 1.0 (input pullup)
|
||||
P1FUNC &= ~(1 << 0);
|
||||
P1DIR |= (1 << 0);
|
||||
P1PULL |= (1 << 0);
|
||||
P1LVLSEL |= (1 << 0);
|
||||
P1INTEN = (1 << 0);
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
#endif
|
||||
|
||||
// sleepy
|
||||
sleepForMsec(t);
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
P1INTEN = 0;
|
||||
#endif
|
||||
|
||||
initAfterWake();
|
||||
}
|
||||
uint16_t getNextSleep() {
|
||||
uint16_t __xdata curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
|
||||
curval *= dataReqLastAttempt;
|
||||
curval /= DATA_REQ_MAX_ATTEMPTS;
|
||||
curval += INTERVAL_BASE;
|
||||
dataReqAttemptArr[dataReqAttemptArrayIndex % POWER_SAVING_SMOOTHING] = curval;
|
||||
dataReqAttemptArrayIndex++;
|
||||
|
||||
uint16_t avg = 0;
|
||||
bool noNetwork = true;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
avg += dataReqAttemptArr[c];
|
||||
if (dataReqAttemptArr[c] != INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
noNetwork = false;
|
||||
}
|
||||
}
|
||||
if (noNetwork == true) return INTERVAL_NO_SIGNAL;
|
||||
avg /= POWER_SAVING_SMOOTHING;
|
||||
return avg;
|
||||
}
|
||||
|
||||
// data xfer stuff
|
||||
@@ -311,7 +155,7 @@ void sendAvailDataReq() {
|
||||
txframe->seq = seq++;
|
||||
txframe->dstPan = 0xFFFF;
|
||||
txframe->dstAddr = 0xFFFF;
|
||||
txframe->srcPan = 0x4447;
|
||||
txframe->srcPan = PROTO_PAN_ID;
|
||||
// TODO: send some meaningful data
|
||||
availreq->softVer = 1;
|
||||
if (P1CHSTA && (1 << 0)) {
|
||||
@@ -573,7 +417,6 @@ uint32_t getHighSlotId() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
// #define DEBUGBLOCKS
|
||||
// Main download function
|
||||
bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
// this is the main function for the download process
|
||||
@@ -835,86 +678,7 @@ bool doDataDownload(struct AvailDataInfo *__xdata avail) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// main loop;
|
||||
void mainProtocolLoop(void) {
|
||||
clockingAndIntsInit();
|
||||
timerInit();
|
||||
boardInit();
|
||||
|
||||
if (!boardGetOwnMac(mSelfMac)) {
|
||||
pr("failed to get MAC. Aborting\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
/*
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
mSelfMac[c] = c + 5;
|
||||
}
|
||||
*/
|
||||
// really... if I do the call below, it'll cost me 8 bytes IRAM. Not the kind of 'optimization' I ever dreamed of doing
|
||||
// pr("MAC>%02X%02X%02X%02X%02X%02X%02X%02X\n", mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3], mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7]);
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
}
|
||||
|
||||
irqsOn();
|
||||
boardInitStage2();
|
||||
|
||||
pr("BOOTED> (UI 0.03-1)\n\n");
|
||||
|
||||
if (!eepromInit()) {
|
||||
pr("failed to init eeprom\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
getNumSlots();
|
||||
curHighSlotId = getHighSlotId();
|
||||
}
|
||||
|
||||
// initialize attempt-array with the default value;
|
||||
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
|
||||
dataReqAttemptArr[c] = INTERVAL_BASE;
|
||||
}
|
||||
|
||||
// show the splashscreen
|
||||
showSplashScreen();
|
||||
|
||||
epdEnterSleep();
|
||||
eepromDeepPowerDown();
|
||||
initRadio();
|
||||
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
|
||||
while (1) {
|
||||
radioRxEnable(true, true);
|
||||
|
||||
struct AvailDataInfo *__xdata avail = getAvailDataInfo();
|
||||
if (avail == NULL) {
|
||||
// no data :(
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
if (doDataDownload(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
}
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
}
|
||||
void initializeProto() {
|
||||
getNumSlots();
|
||||
curHighSlotId = getHighSlotId();
|
||||
}
|
||||
@@ -3,8 +3,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void mainProtocolLoop(void);
|
||||
extern uint8_t __xdata mSelfMac[];
|
||||
|
||||
extern uint8_t __xdata mSelfMac[8];
|
||||
extern uint8_t __xdata currentChannel;
|
||||
extern uint8_t __xdata APmac[];
|
||||
|
||||
extern void initRadio();
|
||||
extern void killRadio();
|
||||
|
||||
|
||||
extern struct AvailDataInfo *__xdata getAvailDataInfo();
|
||||
extern bool doDataDownload(struct AvailDataInfo *__xdata avail);
|
||||
extern void initializeProto();
|
||||
extern struct AvailDataInfo *__xdata getAvailDataInfo();
|
||||
bool probeChannel(uint8_t channel);
|
||||
#endif
|
||||
@@ -1,109 +1,285 @@
|
||||
|
||||
|
||||
#include "userinterface.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "bitmaps.h"
|
||||
#include "board.h"
|
||||
#include "comms.h"
|
||||
#include "cpu.h"
|
||||
#include "epd.h"
|
||||
#include "font.h"
|
||||
#include "lut.h"
|
||||
#include "printf.h"
|
||||
#include "screen.h"
|
||||
#include "settings.h"
|
||||
#include "sleep.h"
|
||||
#include "spi.h"
|
||||
#include "syncedproto.h" // for APmac / Channel
|
||||
#include "timer.h"
|
||||
|
||||
extern uint8_t mSelfMac[];
|
||||
extern uint8_t __xdata mSelfMac[8];
|
||||
extern uint8_t __xdata currentChannel;
|
||||
extern uint8_t __xdata APmac[];
|
||||
|
||||
static const uint8_t __code fwVersion = FW_VERSION;
|
||||
static const char __code fwVersionSuffix[] = FW_VERSION_SUFFIX;
|
||||
|
||||
void showSplashScreen() {
|
||||
epdSetup();
|
||||
lutTest();
|
||||
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
selectLUT(1);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
drawLineHorizontal(EPD_COLOR_BLACK, 33, 1);
|
||||
epdPrintBegin(0, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("Booting!");
|
||||
selectLUT(1);
|
||||
epdPrintBegin(12, 2, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Starting!");
|
||||
epdPrintEnd();
|
||||
|
||||
loadRawBitmap(solum, 8, 34, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(hacked, 32, 46, EPD_COLOR_RED);
|
||||
|
||||
epdPrintBegin(5, 136, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr("%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr("%02X%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(2, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs154v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
draw();
|
||||
timerDelay(1333000);
|
||||
#endif
|
||||
|
||||
#if (SCREEN_WIDTH == 128) // 2.9"
|
||||
selectLUT(1);
|
||||
selectLUT(EPD_LUT_NO_REPEATS);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
|
||||
epdPrintBegin(0, 200, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("Booting!");
|
||||
epdPrintBegin(0, 295, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Starting!");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(0, 294, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("=");
|
||||
epdPrintBegin(80, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs29v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(32, 150, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("-TESTING-");
|
||||
epdPrintBegin(105, 270, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(115, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
pr("MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
pr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
pr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
pr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
uint8_t __xdata buffer[17];
|
||||
spr(buffer, "%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
spr(buffer + 4, "%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
spr(buffer + 8, "%02X%02X", mSelfMac[3], mSelfMac[2]);
|
||||
spr(buffer + 12, "%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
printBarcode(buffer, 120, 284);
|
||||
|
||||
epdPrintBegin(68, 294, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
pr("MAC64: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
pr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
pr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
pr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
drawLineVertical(EPD_COLOR_RED, 64, 10, 286);
|
||||
drawLineVertical(EPD_COLOR_BLACK, 65, 10, 286);
|
||||
loadRawBitmap(solum, 0, 0, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(hacked, 16, 12, EPD_COLOR_RED);
|
||||
// lutTest();
|
||||
// drawLineVertical(EPD_COLOR_RED, 64, 10, 286);
|
||||
// drawLineVertical(EPD_COLOR_BLACK, 65, 10, 286);
|
||||
|
||||
draw();
|
||||
timerDelay(1333000);
|
||||
// timerDelay(TIMER_TICKS_PER_SECOND * 4);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 400) // 2.9"
|
||||
selectLUT(1);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
|
||||
epdPrintBegin(64, 150, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("TEST");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(300, 296, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_RED);
|
||||
pr("Booting!Y");
|
||||
epdPrintEnd();
|
||||
epdpr("Booting!Y");
|
||||
epdpr();
|
||||
|
||||
epdPrintBegin(0, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("BootingX!");
|
||||
epdpr("Starting!");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(16, 284, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
pr("MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
pr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
pr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
pr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintBegin(16, 252, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("zbs42v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(16, 284, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
loadRawBitmap(solum, 256, 10, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(hacked, 264, 22, EPD_COLOR_RED);
|
||||
|
||||
loadRawBitmap(solum, 253, 72, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(hacked, 261, 82, EPD_COLOR_RED);
|
||||
|
||||
draw();
|
||||
timerDelay(1333000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void showApplyUpdate() {
|
||||
epdSetup();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
|
||||
selectLUT(1);
|
||||
clearScreen();
|
||||
setColorMode(EPD_MODE_IGNORE, EPD_MODE_NORMAL);
|
||||
epdPrintBegin(8, 60, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
pr("Updating!");
|
||||
epdpr("Updating!");
|
||||
epdPrintEnd();
|
||||
drawNoWait();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t __xdata resultcounter = 0;
|
||||
|
||||
void showScanningWindow() {
|
||||
epdSetup();
|
||||
setColorMode(EPD_MODE_NORMAL, EPD_MODE_INVERT);
|
||||
selectLUT(EPD_LUT_FAST_NO_REDS);
|
||||
clearScreen();
|
||||
#if (SCREEN_WIDTH == 128) // 2.9"
|
||||
epdPrintBegin(2, 275, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Scanning for APs");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(40, 262, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("Channel - Quality");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(receive, 36, 24, EPD_COLOR_BLACK);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
loadRawBitmap(receive, 96, 28, EPD_COLOR_BLACK);
|
||||
epdPrintBegin(3, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Scanning...");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
draw();
|
||||
selectLUT(EPD_LUT_FAST);
|
||||
resultcounter = 0;
|
||||
}
|
||||
|
||||
void addScanResult(uint8_t channel, uint8_t lqi) {
|
||||
if (channel == 11) resultcounter = 0;
|
||||
#if (SCREEN_WIDTH == 128)
|
||||
epdPrintBegin(56 + ((resultcounter % 4) * 16), 282 - (47 * (resultcounter / 4)), EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("%d-%d", channel, lqi);
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
epdPrintBegin(4 + (47 * (resultcounter / 8)), 31 + (15 * (resultcounter % 8)), EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("%d-%d", channel, lqi);
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
resultcounter++;
|
||||
}
|
||||
|
||||
void showAPFound() {
|
||||
selectLUT(EPD_LUT_FAST_NO_REDS);
|
||||
clearScreen();
|
||||
#if (SCREEN_WIDTH == 128)
|
||||
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Waiting for data...");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(48, 278, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Found the following AP:");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(64, 293, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("AP MAC: %02X:%02X", APmac[7], APmac[6]);
|
||||
epdpr(":%02X:%02X", APmac[5], APmac[4]);
|
||||
epdpr(":%02X:%02X", APmac[3], APmac[2]);
|
||||
epdpr(":%02X:%02X", APmac[1], APmac[0]);
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(80, 293, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Ch: %d RSSI: %d LQI: %d", currentChannel, mLastRSSI, mLastLqi);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(103, 258, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Tag MAC: %02X:%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr(":%02X:%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr(":%02X:%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
uint8_t __xdata buffer[17];
|
||||
spr(buffer, "%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
spr(buffer + 4, "%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
spr(buffer + 8, "%02X%02X", mSelfMac[3], mSelfMac[2]);
|
||||
spr(buffer + 12, "%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
printBarcode(buffer, 120, 253);
|
||||
loadRawBitmap(receive, 36, 14, EPD_COLOR_BLACK);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
epdPrintBegin(25, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("Waiting");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(3, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("for data...");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(5, 64, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("AP MAC:");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(5, 80, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("%02X%02X", APmac[7], APmac[6]);
|
||||
epdpr("%02X%02X", APmac[5], APmac[4]);
|
||||
epdpr("%02X%02X", APmac[3], APmac[2]);
|
||||
epdpr("%02X%02X", APmac[1], APmac[0]);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(5, 96, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Ch:%d rssi:%d lqi:%d", currentChannel, mLastRSSI, mLastLqi);
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(5, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("Tag MAC:");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(5, 136, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_RED);
|
||||
epdpr("%02X%02X", mSelfMac[7], mSelfMac[6]);
|
||||
epdpr("%02X%02X", mSelfMac[5], mSelfMac[4]);
|
||||
epdpr("%02X%02X", mSelfMac[3], mSelfMac[2]);
|
||||
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
draw();
|
||||
}
|
||||
|
||||
void showNoAP() {
|
||||
selectLUT(EPD_LUT_NO_REPEATS);
|
||||
clearScreen();
|
||||
#if (SCREEN_WIDTH == 128) // 1.54"
|
||||
epdPrintBegin(0, 285, EPD_DIRECTION_Y, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("No AP found :(");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(48, 285, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("We'll try again in a");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(64, 285, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("little while...");
|
||||
epdPrintEnd();
|
||||
loadRawBitmap(receive, 36, 24, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(failed, 42, 26, EPD_COLOR_RED);
|
||||
#endif
|
||||
#if (SCREEN_WIDTH == 152) // 1.54"
|
||||
epdPrintBegin(40, 0, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("No AP");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(22, 32, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
|
||||
epdpr("found :(");
|
||||
epdPrintEnd();
|
||||
|
||||
epdPrintBegin(8, 76, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("We'll try again in");
|
||||
epdPrintEnd();
|
||||
epdPrintBegin(25, 92, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
|
||||
epdpr("a little while");
|
||||
epdPrintEnd();
|
||||
#endif
|
||||
draw();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
|
||||
#ifndef _UI_H_
|
||||
#define _UI_H_
|
||||
#include <stdint.h>
|
||||
|
||||
void showSplashScreen();
|
||||
void showApplyUpdate();
|
||||
|
||||
|
||||
void showScanningWindow();
|
||||
void addScanResult(uint8_t channel, uint8_t lqi);
|
||||
void showAPFound();
|
||||
void showNoAP();
|
||||
#endif
|
||||
Reference in New Issue
Block a user