diff --git a/esp32_fw/.vscode/settings.json b/esp32_fw/.vscode/settings.json
index 5f294ebf..ea185af3 100644
--- a/esp32_fw/.vscode/settings.json
+++ b/esp32_fw/.vscode/settings.json
@@ -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"
+ }
}
\ No newline at end of file
diff --git a/esp32_fw/data/alignment.bmp b/esp32_fw/data/alignment.bmp
new file mode 100644
index 00000000..3e302cbe
Binary files /dev/null and b/esp32_fw/data/alignment.bmp differ
diff --git a/esp32_fw/data/fonts/calibrib50.vlw b/esp32_fw/data/fonts/calibrib50.vlw
new file mode 100644
index 00000000..6c0b0dd1
Binary files /dev/null and b/esp32_fw/data/fonts/calibrib50.vlw differ
diff --git a/esp32_fw/data/fonts/calibrib62.vlw b/esp32_fw/data/fonts/calibrib62.vlw
new file mode 100644
index 00000000..97ea7ad3
Binary files /dev/null and b/esp32_fw/data/fonts/calibrib62.vlw differ
diff --git a/esp32_fw/data/fonts/numbers1-1.vlw b/esp32_fw/data/fonts/numbers1-1.vlw
new file mode 100644
index 00000000..e5e2e87a
Binary files /dev/null and b/esp32_fw/data/fonts/numbers1-1.vlw differ
diff --git a/esp32_fw/data/fonts/numbers1-2.vlw b/esp32_fw/data/fonts/numbers1-2.vlw
new file mode 100644
index 00000000..c6f615be
Binary files /dev/null and b/esp32_fw/data/fonts/numbers1-2.vlw differ
diff --git a/esp32_fw/data/fonts/numbers2-1.vlw b/esp32_fw/data/fonts/numbers2-1.vlw
new file mode 100644
index 00000000..1dbfa21b
Binary files /dev/null and b/esp32_fw/data/fonts/numbers2-1.vlw differ
diff --git a/esp32_fw/data/fonts/numbers2-2.vlw b/esp32_fw/data/fonts/numbers2-2.vlw
new file mode 100644
index 00000000..60ade58b
Binary files /dev/null and b/esp32_fw/data/fonts/numbers2-2.vlw differ
diff --git a/esp32_fw/data/fonts/numbers3-1.vlw b/esp32_fw/data/fonts/numbers3-1.vlw
new file mode 100644
index 00000000..fff661e3
Binary files /dev/null and b/esp32_fw/data/fonts/numbers3-1.vlw differ
diff --git a/esp32_fw/data/fonts/numbers3-2.vlw b/esp32_fw/data/fonts/numbers3-2.vlw
new file mode 100644
index 00000000..1dbfa21b
Binary files /dev/null and b/esp32_fw/data/fonts/numbers3-2.vlw differ
diff --git a/esp32_fw/data/index.html b/esp32_fw/data/index.html
deleted file mode 100644
index 8a65efa4..00000000
--- a/esp32_fw/data/index.html
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/esp32_fw/data/www/index.html b/esp32_fw/data/www/index.html
new file mode 100644
index 00000000..5f91685e
--- /dev/null
+++ b/esp32_fw/data/www/index.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
Solum - alternative proto AP
+
+
+
+
+
+
+
+
+
✖
+
00000000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/esp32_fw/data/www/main.css b/esp32_fw/data/www/main.css
new file mode 100644
index 00000000..1627b3dd
--- /dev/null
+++ b/esp32_fw/data/www/main.css
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/esp32_fw/data/www/main.js b/esp32_fw/data/www/main.js
new file mode 100644
index 00000000..9d53493c
--- /dev/null
+++ b/esp32_fw/data/www/main.js
@@ -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", '
' + htmlEncode(time + ' ' + message) + '');
+ } else {
+ messages.insertAdjacentHTML("afterbegin", '
'+htmlEncode(time+' '+message)+'');
+ }
+}
+
+function htmlEncode(input) {
+ const textArea = document.createElement("textarea");
+ textArea.innerText = input;
+ return textArea.innerHTML.split("
").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')}`;
+}
diff --git a/esp32_fw/include/commstructs.h b/esp32_fw/include/commstructs.h
index bf1f2a24..ac93dba7 100644
--- a/esp32_fw/include/commstructs.h
+++ b/esp32_fw/include/commstructs.h
@@ -56,4 +56,6 @@ struct pendingData {
} __packed;
#define BLOCK_DATA_SIZE 4096
-#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
\ No newline at end of file
+#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
+
+#pragma pack(pop)
\ No newline at end of file
diff --git a/esp32_fw/include/contentmanager.h b/esp32_fw/include/contentmanager.h
new file mode 100644
index 00000000..64fe7a25
--- /dev/null
+++ b/esp32_fw/include/contentmanager.h
@@ -0,0 +1,15 @@
+#include
+
+#include
+#include "makeimage.h"
+#include
+#include "tag_db.h"
+#include
+
+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);
\ No newline at end of file
diff --git a/esp32_fw/include/makeimage.h b/esp32_fw/include/makeimage.h
new file mode 100644
index 00000000..8debd701
--- /dev/null
+++ b/esp32_fw/include/makeimage.h
@@ -0,0 +1,35 @@
+#include
+#include
+
+#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);
+
diff --git a/esp32_fw/include/pendingdata.h b/esp32_fw/include/pendingdata.h
index b4116bfb..1bbc1e9f 100644
--- a/esp32_fw/include/pendingdata.h
+++ b/esp32_fw/include/pendingdata.h
@@ -21,3 +21,5 @@ class pendingdata {
void garbageCollection(void* parameter);
extern std::vector pendingfiles;
+
+#pragma pack(pop)
\ No newline at end of file
diff --git a/esp32_fw/include/tag_db.h b/esp32_fw/include/tag_db.h
new file mode 100644
index 00000000..3c6a77c2
--- /dev/null
+++ b/esp32_fw/include/tag_db.h
@@ -0,0 +1,47 @@
+#include
+#include
+
+#include
+
+#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 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)
\ No newline at end of file
diff --git a/esp32_fw/include/web.h b/esp32_fw/include/web.h
index e40b0795..524234df 100644
--- a/esp32_fw/include/web.h
+++ b/esp32_fw/include/web.h
@@ -1,13 +1,19 @@
-#include
+
+#include
#include
#include
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;
\ No newline at end of file
diff --git a/esp32_fw/platformio.ini b/esp32_fw/platformio.ini
index c22487e0..99d85fe2 100644
--- a/esp32_fw/platformio.ini
+++ b/esp32_fw/platformio.ini
@@ -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
diff --git a/esp32_fw/src/SPIFFSEditor.cpp b/esp32_fw/src/SPIFFSEditor.cpp
index 42e8d375..e301ecbc 100644
--- a/esp32_fw/src/SPIFFSEditor.cpp
+++ b/esp32_fw/src/SPIFFSEditor.cpp
@@ -2,396 +2,9 @@
#include
-// 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);
}
diff --git a/esp32_fw/src/contentmanager.cpp b/esp32_fw/src/contentmanager.cpp
new file mode 100644
index 00000000..25bf46df
--- /dev/null
+++ b/esp32_fw/src/contentmanager.cpp
@@ -0,0 +1,246 @@
+#include "contentmanager.h"
+
+#include
+#include
+#include
+#include "newproto.h"
+#include
+#include
+#include
+
+#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();
+
+ wsLog("Updating " + dst + " mode " + String(taginfo->contentMode));
+ taginfo->nextupdate = now + 600;
+
+ switch (taginfo->contentMode) {
+ case Image:
+
+ filename = cfgobj["filename"].as();
+ if (filename && filename !="null" && !cfgobj["#fetched"].as()) {
+ if (prepareDataAvail(&filename, DATATYPE_IMGRAW, mac, cfgobj["timetolive"].as())) {
+ 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();
+ if (filename && filename != "null" && !cfgobj["#fetched"].as()) {
+ if (prepareDataAvail(&filename, DATATYPE_UPDATE, mac, cfgobj["timetolive"].as())) {
+ 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());
+ cfgobj["#fetched"] = now;
+ }
+ taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as()) ;
+ break;
+ }
+
+ taginfo->modeConfigJson = doc.as();
+}
+
+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;
+}
diff --git a/esp32_fw/src/main.cpp b/esp32_fw/src/main.cpp
index efe79a2d..f9552de1 100644
--- a/esp32_fw/src/main.cpp
+++ b/esp32_fw/src/main.cpp
@@ -3,50 +3,44 @@
#include
#include
+#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() {
diff --git a/esp32_fw/src/makeimage.cpp b/esp32_fw/src/makeimage.cpp
new file mode 100644
index 00000000..1d6762db
--- /dev/null
+++ b/esp32_fw/src/makeimage.cpp
@@ -0,0 +1,430 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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");
+}
\ No newline at end of file
diff --git a/esp32_fw/src/newproto.cpp b/esp32_fw/src/newproto.cpp
index a323b133..727fc0d2 100644
--- a/esp32_fw/src/newproto.cpp
+++ b/esp32_fw/src/newproto.cpp
@@ -1,14 +1,16 @@
-#pragma pack(push, 1)
#include "newproto.h"
#include
#include
+#include
+#include
#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);
}
@@ -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, "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, "
#include
#include
@@ -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) {
diff --git a/esp32_fw/src/tag_db.cpp b/esp32_fw/src/tag_db.cpp
new file mode 100644
index 00000000..794a0a8c
--- /dev/null
+++ b/esp32_fw/src/tag_db.cpp
@@ -0,0 +1,167 @@
+#include "tag_db.h"
+
+#include
+#include
+
+#include
+
+#include "LittleFS.h"
+
+std::vector 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();
+}
+
+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();
+ 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();
+ taginfo->contentMode = static_cast(tag["contentmode"]);
+ taginfo->modeConfigJson = tag["modecfgjson"].as();
+ }
+ } 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;
+}
diff --git a/esp32_fw/src/web.cpp b/esp32_fw/src/web.cpp
index 35c5297a..1f4514d4 100644
--- a/esp32_fw/src/web.cpp
+++ b/esp32_fw/src/web.cpp
@@ -2,6 +2,7 @@
#include
#include
+
#include
#include
#include
@@ -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>(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());
xSemaphoreGive(wsMutex);
}
+void wsErr(String text) {
+ DynamicJsonDocument doc(100);
+ doc["errMsg"] = text;
+ xSemaphoreTake(wsMutex, portMAX_DELAY);
+ ws.textAll(doc.as());
+ 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());
+ 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);
});
diff --git a/tag_fw/Makefile b/tag_fw/Makefile
index 5dec4173..fae0f459 100644
--- a/tag_fw/Makefile
+++ b/tag_fw/Makefile
@@ -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
diff --git a/tag_fw/barcode.c b/tag_fw/barcode.c
new file mode 100644
index 00000000..c431d148
--- /dev/null
+++ b/tag_fw/barcode.c
@@ -0,0 +1,101 @@
+#include
+#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;
+}
diff --git a/tag_fw/barcode.h b/tag_fw/barcode.h
new file mode 100644
index 00000000..f6d784b9
--- /dev/null
+++ b/tag_fw/barcode.h
@@ -0,0 +1,29 @@
+#ifndef _BARCODE_H_
+#define _BARCODE_H_
+
+#include
+
+//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
diff --git a/tag_fw/bitmaps.h b/tag_fw/bitmaps.h
new file mode 100644
index 00000000..d16feecf
--- /dev/null
+++ b/tag_fw/bitmaps.h
@@ -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
+
+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
\ No newline at end of file
diff --git a/tag_fw/board/zbs154v033/board.h b/tag_fw/board/zbs154v033/board.h
index 6e9a87ee..b5683d58 100644
--- a/tag_fw/board/zbs154v033/board.h
+++ b/tag_fw/board/zbs154v033/board.h
@@ -4,27 +4,11 @@
#include
#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
\ No newline at end of file
diff --git a/tag_fw/board/zbs154v033/screen.h b/tag_fw/board/zbs154v033/screen.h
index 2dd805b3..6d1d4997 100644
--- a/tag_fw/board/zbs154v033/screen.h
+++ b/tag_fw/board/zbs154v033/screen.h
@@ -21,7 +21,7 @@
#define SCREEN_DATA_PASSES 2
-
-#endif
+#define SCREEN_LUT_LENGTH 10
+#endif
\ No newline at end of file
diff --git a/tag_fw/board/zbs29v033/board.h b/tag_fw/board/zbs29v033/board.h
index 8951cd17..e63b5e11 100644
--- a/tag_fw/board/zbs29v033/board.h
+++ b/tag_fw/board/zbs29v033/board.h
@@ -4,27 +4,11 @@
#include
#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
\ No newline at end of file
diff --git a/tag_fw/board/zbs29v033/screen.h b/tag_fw/board/zbs29v033/screen.h
index 576238d5..101e5339 100644
--- a/tag_fw/board/zbs29v033/screen.h
+++ b/tag_fw/board/zbs29v033/screen.h
@@ -4,12 +4,6 @@
#include
#include
-
-//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
\ No newline at end of file
diff --git a/tag_fw/board/zbs42v033/board.h b/tag_fw/board/zbs42v033/board.h
index b23787ee..0cf71379 100644
--- a/tag_fw/board/zbs42v033/board.h
+++ b/tag_fw/board/zbs42v033/board.h
@@ -4,27 +4,11 @@
#include
#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
\ No newline at end of file
diff --git a/tag_fw/board/zbs42v033/screen.h b/tag_fw/board/zbs42v033/screen.h
index e02a55d8..5f7891ff 100644
--- a/tag_fw/board/zbs42v033/screen.h
+++ b/tag_fw/board/zbs42v033/screen.h
@@ -4,12 +4,6 @@
#include
#include
-
-//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
\ No newline at end of file
diff --git a/tag_fw/comms.c b/tag_fw/comms.c
index 273f81a2..10c6557c 100644
--- a/tag_fw/comms.c
+++ b/tag_fw/comms.c
@@ -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)
{
diff --git a/tag_fw/comms.h b/tag_fw/comms.h
index 7c1c67b9..c80f0113 100644
--- a/tag_fw/comms.h
+++ b/tag_fw/comms.h
@@ -3,21 +3,16 @@
#include
-#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);
diff --git a/tag_fw/cpu/8051/printf.c b/tag_fw/cpu/8051/printf.c
index 93246c9c..be6dc10c 100644
--- a/tag_fw/cpu/8051/printf.c
+++ b/tag_fw/cpu/8051/printf.c
@@ -1,795 +1,799 @@
-#include
-#include
-#include
#include "printf.h"
-#include "zbs243.h"
+
+#include
+#include
+#include
+
#include "board.h"
+#include "epd.h"
+#include "uart.h"
+#include "zbs243.h"
typedef void (*StrFormatOutputFunc)(uint32_t param /* low byte is data, bits 24..31 is char */) __reentrant;
-static __idata __at (0x00) unsigned char R0;
-static __idata __at (0x01) unsigned char R1;
-static __idata __at (0x02) unsigned char R2;
-static __idata __at (0x03) unsigned char R3;
-static __idata __at (0x04) unsigned char R4;
-static __idata __at (0x05) unsigned char R5;
-static __idata __at (0x06) unsigned char R6;
-static __idata __at (0x07) unsigned char R7;
+static __idata __at(0x00) unsigned char R0;
+static __idata __at(0x01) unsigned char R1;
+static __idata __at(0x02) unsigned char R2;
+static __idata __at(0x03) unsigned char R3;
+static __idata __at(0x04) unsigned char R4;
+static __idata __at(0x05) unsigned char R5;
+static __idata __at(0x06) unsigned char R6;
+static __idata __at(0x07) unsigned char R7;
static uint8_t __xdata mCvtBuf[18];
-
-//callback must be reentrant and callee_saves
+// callback must be reentrant and callee_saves
#pragma callee_saves prvPrintFormat
-void prvPrintFormat(StrFormatOutputFunc formatF, uint16_t formatD, const char __code *fmt, va_list vl) __reentrant __naked
-{
- //formatF is in DPTR
- //sp[0..-1] is return addr
- //sp[-2..-3] is formatD
- //sp[-4..-5] is fmt
- //sp[-6] is vl
-
- __asm__ (
- " push _R7 \n"
- " push DPH \n" //push formatF
- " push DPL \n"
- " mov _R7, sp \n" //save place on stack where we stashed it so we can call it easily
- " push _R4 \n"
- " push _R3 \n"
- " push _R2 \n"
- " push _R1 \n"
- " push _R0 \n"
-
- " mov A, #-12 \n"
- " add A, sp \n"
- " mov R0, A \n"
- //R0 now points to pushed params, for large values, we see high bytes first
- // to get next byte, we need to DECEREMENT R0
-
- " mov DPH, @R0 \n"
- " dec R0 \n"
- " mov DPL, @R0 \n"
- " dec R0 \n"
- " mov _R0, @R0 \n"
- " dec R0 \n"
-
- //now format string is in DPTR, and R0 points to the top byte of whatever was in the first param
-
- //main loop: get a byte of the format string
- "00001$: \n"
- " clr A \n"
- " movc A, @A + DPTR \n"
- " inc DPTR \n"
- //if zero, we're done
- " jz 00098$ \n"
- //if not '%', print it
- " cjne A, #'%', 00097$ \n"
-
- //we got a percent sign - init state for format processing
- " mov R4, #0 \n" //bit flags:
- // 0x01 = '*' = pointer provided instead of value (integers only)
- // 0x02 = '0' = zero-pad (for numbers only)
- // 0x04 = have pad-to length
- // 0x08 = long
- // 0x10 = long long
- // 0x20 = signed print requested. also: need to print a negative (used to reuse hex printing for decimal once converted to bcd)
- " mov R2, #0 \n" //padLen
-
- //loop for format string ingestion
- "00002$: \n"
- " clr A \n"
- " movc A, @A + DPTR \n"
- " inc DPTR \n"
- //if zero, we're done
- " jz 00098$ \n"
- //check for percent sign
- " cjne A, #'%', 00003$ \n"
- //fallthrough to print it and go read next non-format byte
- //print a char in A, go read next format byte
- "00097$: \n"
- " lcall 00060$ \n"
- " sjmp 00001$ \n"
-
- //exit label - placed for easy jumping to
- "00098$: \n"
- " pop _R0 \n"
- " pop _R1 \n"
- " pop _R2 \n"
- " pop _R3 \n"
- " pop _R4 \n"
- " pop DPL \n"
- " pop DPH \n"
- " pop _R7 \n"
- " ret \n"
-
- //continue to process format string - handle %c
- "00003$: \n"
- " cjne A, #'c', 00004$ \n"
- " dec R0 \n" //param is pushed as int (16 bits)
- " mov A, @R0 \n"
- " dec R0 \n"
- " sjmp 00097$ \n" //print and go read next non-format byte
-
- //continue to process format string - handle %m
- "00004$: \n"
- " mov R3, A \n"
- " orl A, #0x20 \n"
- " cjne A, #'m', 00008$ \n"
-
- //sort out which hexch charset to use
- " mov A, R3 \n"
- " anl A, #0x20 \n"
- " rr A \n"
- " mov R1, A \n"
-
- //go, do
- " push DPH \n"
- " push DPL \n"
- " lcall 00090$ \n" //read the short (__xdata) pointer - >DPTR
- " mov R4, #8 \n" //byteSel
- "00005$: \n"
- " push DPH \n"
- " push DPL \n"
- " mov A, R4 \n"
- " dec A \n"
- " add A, DPL \n"
- " mov DPL, A \n"
- " mov A, DPH \n"
- " addc A, #0 \n"
- " mov DPH, A \n"
- " movx A, @DPTR \n"
- " mov R2, A \n"
- " swap A \n"
- " mov R3, #2 \n"
- "00006$: \n"
- " anl A, #0x0f \n"
- " add A, R1 \n"
- " mov DPTR, #00099$ \n"
- " movc A, @A + DPTR \n"
- " lcall 00060$ \n"
- " mov A, R2 \n"
- " djnz R3, 00006$ \n"
- " pop DPL \n"
- " pop DPH \n"
- " djnz R4, 00007$ \n"
- //done with mac addr
-
- "00055$: \n"
- " pop DPL \n"
- " pop DPH \n"
- " sjmp 00001$ \n"
- //print colon and contimue mac addr printing
- "00007$: \n"
- " mov A, #':' \n"
- " lcall 00060$ \n"
- " sjmp 00005$ \n"
-
- //continue to process format string - handle '*'
- "00008$: \n"
- " mov A, R3 \n"
- " cjne A, #'*', 00009$ \n"
- " cjne R2, #0, 00097$ \n" //only valid when no length/padding has been specified yet, else invalid specifier
- " mov A, #0x01 \n" //"pointer mode"
- "00010$: \n"
- " orl A, R4 \n"
- " mov R4, A \n"
- " sjmp 00002$ \n" //get next format specifier now
-
- //continue to process format string - handle '0'
- "00009$: \n"
- " cjne A, #'0', 00011$ \n"
- " cjne R2, #0, 00011$ \n" //setting "zero pad" is only valid when pad length is zero
- " mov A, #0x06 \n" //"have pad length" | "zero-pad"
- " sjmp 00010$ \n" //orr A into R4, get next format specifier now
-
- //continue to process format string - handle '1'...'9'
- "00011$: \n"
- " mov R3, A \n"
- " add A, #-'0' \n"
- " jnc 00012$ \n" //now 0..9 are valid
- " add A, #-10 \n"
- " jc 00012$ \n"
- " add A, #10 \n" //get it back into 1..9 range
- " mov R3, A \n"
- " mov A, #10 \n"
- " mov B, R2 \n"
- " mul AB \n"
- " add A, R3 \n"
- " mov R2, A \n"
- " mov A, #0x04 \n" //"have pad length"
- " sjmp 00010$ \n" //orr A into R4, get next format specifier now
-
- //continue to process format string - handle 'l'
- "00012$: \n"
- " cjne R3, #'l', 00014$ \n"
- " mov A, R4 \n"
- " anl A, #0x08 \n"
- " jz 00013$ \n" //no "long" yet? set that
- //have long - set long log
- " mov A, #0x10 \n" //"long long"
- " sjmp 00010$ \n" //orr A into R4, get next format specifier now
- //first 'l' - set long
- "00013$: \n"
- " mov A, #0x08 \n" //"long"
- " sjmp 00010$ \n" //orr A into R4, get next format specifier now
-
- //continue to process format string - handle 's'
- "00014$: \n"
- " cjne R3, #'s', 00025$ \n"
- " mov A, R4 \n"
- " anl A, #0x08 \n"
- " push DPH \n"
- " push DPL \n"
- " jnz 00015$ \n"
- " lcall 00091$ \n" //get and resolve generic pointer into DPTR
- " sjmp 00016$ \n"
- "00015$: \n" //get short pointer into DPTR, record that it is to XRAM
- " clr PSW.5 \n"
- " clr PSW.1 \n"
- " lcall 00090$ \n"
- "00016$: \n" //pointer to string now in DPTR
- //we have the string pointer in {DPTR,PSW}, let's see if we have padding to do
- " mov A, R4 \n"
- " anl A, #0x04 \n"
- " jnz 00018$ \n"
- //print string with no length restrictions
- "00017$: \n"
- " lcall 00095$ \n"
- " jz 00055$ \n"
- " lcall 00060$ \n"
- " sjmp 00017$ \n"
-
- //print string with length restrictions and/or padding
- "00018$: \n"
- " cjne R2, #0, 00019$ \n" //verify reqested len was not zero
- " sjmp 00055$ \n"
-
- "00019$: \n"
- " lcall 00095$ \n"
- " jz 00020$ \n"
- " lcall 00060$ \n"
- " djnz R2, 00019$ \n"
- //we get here if we ran out of allowable bytes - we're done then
- " ljmp 00055$ \n"
-
- //just a trampoline for range issues
- "00035$: \n"
- " ljmp 00036$ \n"
-
- //we need to pad with spaces
- "00020$: \n"
- " mov A, #' ' \n"
- " lcall 00060$ \n"
- " djnz R2, 00020$ \n"
- " ljmp 00055$ \n"
-
- //continue to process format string - handle 'x'/'X'
- "00025$: \n"
- " mov A, R3 \n"
- " orl A, #0x20 \n"
- " cjne A, #'x', 00035$ \n"
- " push DPH \n"
- " push DPL \n"
- " lcall 00080$ \n" //get pointer to the number in DPTR, length in bytes in B
- //save it
-
- "00070$: \n"
- " push DPH \n"
- " push DPL \n"
-
- //sort out how long it would be if printed, first get a pointer to the highest
- " mov A, B \n"
- " rl A \n"
- " mov R1, A \n"
- " rr A \n"
- " add A, #0xff \n"
- " add A, DPL \n"
- " mov DPL, A \n"
- " mov A, DPH \n"
- " addc A, #0x00 \n"
- " mov DPH, A \n"
- "00026$: \n"
- " lcall 00079$ \n"
- " anl A, #0xf0 \n"
- " jnz 00028$ \n"
- " dec R1 \n"
- " lcall 00079$ \n"
- " jnz 00028$ \n"
- " dec R1 \n"
- //dec DPTR
- " dec DPL \n"
- " mov A, DPL \n"
- " cjne A, #0xff, 00027$ \n"
- " dec DPH \n"
- "00027$: \n"
- " djnz B, 00026$ \n"
-
- //we now know how many digits the number is (in R1), except that it has "0" if the number if zero, we cannot have that
- "00028$: \n"
- " cjne R1, #0, 00029$ \n"
- " inc R1 \n"
- "00029$: \n" //we now finally have the full length of the digits
-
- //if the number is negative (happens when we're printing decimals)
- // the length of it is one more, also in case of zero-padding, we need to print the minus sign here now
- " mov A, R4 \n"
- " anl A, #0x20 \n"
- " jz 00051$ \n"
- " inc R1 \n" //the length is one more
- " mov A, R4 \n"
- " anl A, #02 \n" //if zero-padding, the negative comes now
- " jz 00051$ \n"
- " mov A, #'-' \n"
- " lcall 00060$ \n"
- "00051$: \n"
-
- //sort out if we need padding at all and if there is space
- " mov A, R4 \n"
- " anl A, #0x04 \n"
- " jz 00031$ \n" //no padding requested
- //padding was requested len is in R2
- " mov A, R2 \n"
- " clr C \n"
- " subb A, R1 \n"
- " jc 00031$ \n" //pad-to len < number_len -> no padding needed
- " jz 00031$ \n" //pad-to len == number_len -> no padding needed
- " mov R2, A \n"
-
- //sort out which character to use -> DPL
- " mov A, R4 \n" //fancy way to create space/zero as needed
- " anl A, #0x02 \n"
- " swap A \n"
- " rr A \n"
- " add A, #0x20 \n"
- " mov DPL, A \n"
-
- //pad!
- "00030$: \n"
- " mov A, DPL \n"
- " lcall 00060$ \n"
- " djnz R2, 00030$ \n"
- "00031$: \n"
-
- //if the number is negative (happens when we're printing decimals)
- // we made the length of it is one more, which we need to undo
- // also in case of space-padding, we need to print the minus sign here now
- " mov A, R4 \n"
- " anl A, #0x20 \n"
- " jz 00052$ \n"
- " dec R1 \n" //the length is one less than we had increased it to
- " mov A, R4 \n"
- " anl A, #02 \n" //if space-padding, the negative comes now
- " jnz 00052$ \n"
- " mov A, #'-' \n"
- " lcall 00060$ \n"
- "00052$: \n"
-
- //time to print the number itself
- //sort out which hexch charset to use -> R2
- " mov A, R3 \n"
- " anl A, #0x20 \n"
- " rr A \n"
- " mov R2, A \n"
- //re-get the number pointer
- " pop DPL \n"
- " pop DPH \n"
- //currently DPTR points to the number low byte, R1 is now many digits we expect to print, R2 is the charset selection, R4 and R3 are free
- //let's calculate how many bytes we expect to process -> R4
- " mov A, R1 \n"
- " inc A \n"
- " clr C \n"
- " rrc A \n"
- " mov R4, A \n"
- //let's repoint DPTR to the first byte we'll print in (remember we print 2 digits per byte)
- " dec A \n"
- " add A, DPL \n"
- " mov DPL, A \n"
- " mov A, DPH \n"
- " addc A, #0x00 \n"
- " mov DPH, A \n"
-
- //decide if we need to print just a nibble of the high byte or the whole thing. Free up R1
- " mov A, R1 \n"
- " anl A, #0x01 \n"
- " jz 00032$ \n"
-
- //we're printing just the low nibble of the first byte - set up for it
- " lcall 00079$ \n"
- " mov R1, #1 \n"
- " sjmp 00033$ \n"
-
- //print loop
- "00032$: \n"
- " lcall 00079$ \n"
- " mov R1, #2 \n"
- " mov R3, A \n"
- " swap A \n"
- "00033$: \n"
- " anl A, #0x0f \n"
- " add A, R2 \n"
- " push DPH \n"
- " push DPL \n"
- " mov DPTR, #00099$ \n"
- " movc A, @A + DPTR \n"
- " pop DPL \n"
- " pop DPH \n"
- " lcall 00060$ \n"
- " mov A, R3 \n"
- " djnz R1, 00033$ \n"
-
- //dec DPTR
- " dec DPL \n"
- " mov A, DPL \n"
- " cjne A, #0xff, 00034$ \n"
- " dec DPH \n"
- "00034$: \n"
- " djnz R4, 00032$ \n"
-
- //done!
- " ljmp 00055$ \n"
-
- //continue to process format string - handle 'd'
- "00036$: \n"
- " cjne R3, #'d', 00037$ \n"
- " mov A, #0x20 \n"
- " orl A, R4 \n"
- " mov R4, A \n"
- " sjmp 00040$ \n"
-
- //continue to process format string - handle 'u'
- "00037$: \n"
- " cjne R3, #'u', 00038$ \n"
- " sjmp 00040$ \n"
-
- //no more format strings exist that we can handle - bail
- "00038$: \n"
- " ljmp 00001$ \n"
-
- //handle decimal printing
- "00040$: \n"
- " push DPH \n"
- " push DPL \n"
- " lcall 00080$ \n" //get pointer to the number in DPTR, length in bytes in B
- " push B \n"
-
- //copy the number to the double-dabble storage at proper offset (0 for u64, 4 for u32, 6 for u16)
- //we do this so that the dabble area always starts at the same place...
- " mov A, #8 \n"
- " clr C \n"
- " subb A, B \n"
- " add A, #_mCvtBuf \n"
- " mov R1, A \n"
- " clr A \n"
- " addc A, #(_mCvtBuf >> 8) \n"
- " mov R3, A \n"
- "00041$: \n"
- " lcall 00079$ \n"
- " inc DPTR \n"
- " lcall 00086$ \n"
- " movx @DPTR, A \n"
- " inc DPTR \n"
- " lcall 00086$ \n"
- " djnz B, 00041$ \n"
- //leave DPTR pointing to dabble storage, past the number
- " lcall 00086$ \n"
-
- //we now have the top byte of the number in A, good time to check for negatives, if needed
- " mov B, A \n"
- " mov A, R4 \n"
- " anl A, #0x20 \n"
- " jz 00050$ \n" //unsigned printing requested
- " mov A, B \n"
- " anl A, #0x80 \n"
- " jnz 00043$ \n" //is negative - we need to invert, 0x20 bit in R1 stays
- //positive - 0x20 bit in R1 needs to go
- " mov A, R4 \n"
- " anl A, #~0x20 \n"
- " mov R4, A \n"
- " sjmp 00050$ \n"
-
- //we need to negate the number
- // but first we need a pointer to it, and its size
- "00043$: \n"
- " pop B \n"
- " push B \n"
- " mov A, #8 \n"
- " clr C \n"
- " subb A, B \n"
- " add A, #_mCvtBuf \n"
- " mov DPL, A \n"
- " clr A \n"
- " addc A, #(_mCvtBuf >> 8) \n"
- " mov DPH, A \n"
-
- //ok, now we are ready to negate it
- " clr C \n"
- "00049$: \n"
- " movx A, @DPTR \n"
- " mov R1, A \n"
- " clr A \n"
- " subb A, R1 \n"
- " movx @DPTR, A \n"
- " inc DPTR \n"
- " djnz B, 00049$ \n"
-
- //zero out the rest of the storage (10 bytes)
- "00050$: \n"
- " mov B, #10 \n"
- " clr A \n"
- "00042$: \n"
- " movx @DPTR, A \n"
- " inc DPTR \n"
- " djnz B, 00042$ \n"
-
- //calculate number of dabble steps
- " pop A \n"
- " swap A \n"
- " rr A \n"
- " mov R3, A \n"
-
- //do the thing
- "00044$: \n"
-
- //dabble (10 iters for simplicity)
- " mov DPTR, #(_mCvtBuf + 8) \n"
- " mov B, #10 \n"
- "00046$: \n"
- " movx A, @DPTR \n"
- " mov R1, A \n"
- " anl A, #0x0f \n"
- " add A,#-0x05 \n"
- " mov A, R1 \n"
- " jnc 00047$ \n"
- " add A, #0x03 \n"
- "00047$: \n"
- " mov R1, A \n"
- " anl A, #0xf0 \n"
- " add A,#-0x50 \n"
- " mov A, R1 \n"
- " jnc 00048$ \n"
- " add A, #0x30 \n"
- "00048$: \n"
- " movx @DPTR, A \n"
- " inc DPTR \n"
- " djnz B, 00046$ \n"
-
- //double (18 iters for simplicity)
- " mov DPTR, #_mCvtBuf \n"
- " clr C \n"
- " mov B, #18 \n"
- "00045$: \n"
- " movx A, @DPTR \n"
- " rlc A \n"
- " movx @DPTR, A \n"
- " inc DPTR \n"
- " djnz B, 00045$ \n"
-
- " djnz R3, 00044$ \n"
-
- //dabbling is done, print it now using hex routine
- " mov DPTR, #(_mCvtBuf + 8) \n"
- " mov B, #10 \n"
- " clr PSW.5 \n" //it is now for sure in XRAM
- " ljmp 00070$ \n"
-
- //read short pointer from param stack
- "00090$: \n"
- " mov DPH, @R0 \n"
- "00093$: \n"
- " dec R0 \n"
- " mov DPL, @R0 \n"
- " dec R0 \n"
- " ret \n"
-
- //read and increment pointer of the type provided by 00091$ (in {DPTR,PSW}) into A. clobber nothing
- "00095$: \n"
- " jb PSW.5, 00066$ \n"
- " jb PSW.1, 00067$ \n"
- //XRAM
- " movx A, @DPTR \n"
- " inc DPTR \n"
- " ret \n"
- //CODE
- "00066$: \n"
- " clr A \n"
- " movc A, @A+DPTR \n"
- " inc DPTR \n"
- " ret \n"
- //IRAM
- "00067$: \n"
- " mov DPH, R0 \n"
- " mov R0, DPL \n"
- " mov A, @R0 \n"
- " mov R0, DPH \n"
- " inc DPL \n"
- " ret \n"
-
- //resolve generic pointer on param stack to an pointer in DPTR and flags in PSW.5 and PSW.1
- //PSW.5 will be 0 and PSW.1 will be 0 for XRAM (PDATA goes here too)
- //PSW.5 will be 1 and PSW.1 will be 0 for CODE
- //PSW.5 will be 0 and PSW.1 will be 1 for IRAM
- "00091$: \n"
- " clr PSW.5 \n"
- " clr PSW.1 \n"
- " mov A, @R0 \n"
- " dec R0 \n"
- " jz 00090$ \n" //0x00: pointer type: xdata
- " xrl A, #0x80 \n"
- " jz 00094$ \n" //0x80: pointer type: code
- " xrl A, #0xc0 \n"
- " jz 00092$ \n" //0x40: pointer type: idata
- //pdata
- " mov DPH, _XPAGE \n"
- " sjmp 00093$ \n"
- //idata
- "00092$: \n"
- " setb PSW.1 \n"
- " sjmp 00093$ \n"
- //code
- "00094$: \n"
- " setb PSW.5 \n"
- " sjmp 00090$ \n"
-
- //read the pointer of the type that 00080$ returns (in DPTR) into A. clobber nothing
- "00079$: \n"
- " jnb PSW.5, 00078$ \n"
- " push _R0 \n"
- " mov R0, DPL \n"
- " mov A, @R0 \n"
- " pop _R0 \n"
- " ret \n"
- "00078$: \n"
- " movx A, @DPTR \n"
- " ret \n"
-
- //get pointer to a number, might be pushed or might be pointed to, size might vary. return pointer to number's LOW byte in DPTR
- "00080$: \n"
- " mov A, R4 \n"
- " anl A, #0x01 \n"
- " jnz 00083$ \n"
- //param is itself on stack - now we care about size, but either way, PSW.5 will be 1
- " setb PSW.5 \n"
- " mov B, #0 \n"
- " mov A, R4 \n"
- " anl A, #0x18 \n"
- " jz 00081$ \n"
- " anl A, #0x10 \n"
- " jz 00082$ \n"
- //long long (8 bytes) \n"
- " setb B.2 \n"
- " dec R0 \n"
- " dec R0 \n"
- " dec R0 \n"
- " dec R0 \n"
- //long (4 bytes)
- "00082$: \n"
- " setb B.1 \n"
- " dec R0 \n"
- " dec R0 \n"
- //int (2 bytes) \n"
- "00081$: \n"
- " setb B.0 \n"
- " dec R0 \n"
- " mov DPL, R0 \n"
- " dec R0 \n"
- " inc B \n"
- " ret \n"
- //pointer it on stack itself, number is in xram, but we still need to provide the length
- "00083$: \n"
- " clr PSW.5 \n" //mark as "in xram"
- " mov A, R4 \n"
- " anl A, #0x18 \n"
- " jz 00084$ \n"
- " anl A, #0x10 \n"
- " jz 00085$ \n"
- //long long
- " mov B, #8 \n"
- " ljmp 00090$ \n"
- //long
- "00085$: \n"
- " mov B, #4 \n"
- " ljmp 00090$ \n"
- //int
- "00084$: \n"
- " mov B, #2 \n"
- " ljmp 00090$ \n"
+void prvPrintFormat(StrFormatOutputFunc formatF, uint16_t formatD, const char __code *fmt, va_list vl) __reentrant __naked {
+ // formatF is in DPTR
+ // sp[0..-1] is return addr
+ // sp[-2..-3] is formatD
+ // sp[-4..-5] is fmt
+ // sp[-6] is vl
- //swap R3:R1 <-> DPH:DPL
- "00086$: \n"
- " xch A, DPH \n"
- " xch A, R3 \n"
- " xch A, DPH \n"
- " xch A, DPL \n"
- " xch A, R1 \n"
- " xch A, DPL \n"
- " ret \n"
+ __asm__(
+ " push _R7 \n"
+ " push DPH \n" // push formatF
+ " push DPL \n"
+ " mov _R7, sp \n" // save place on stack where we stashed it so we can call it easily
+ " push _R4 \n"
+ " push _R3 \n"
+ " push _R2 \n"
+ " push _R1 \n"
+ " push _R0 \n"
- /* putchar func
- called via call. char is in A, R7 has pointer to stack as needed
- can clobber B, CANNOT clobber DPTR
- a mess because...8051
- */
- "00060$: \n"
- " push DPH \n"
- " push DPL \n"
- " push _R1 \n"
- " push _R0 \n"
- " mov _R0, R7 \n"
- " mov DPL, @R0 \n"
- " dec R0 \n"
- " mov DPH, @R0 \n" //DPTR is now func ptr
- " dec R0 \n"
- " dec R0 \n"
- " dec R0 \n"
- " dec R0 \n"
- " mov _R1, @R0 \n"
- " dec R0 \n"
- " mov _R0, @R0 \n" //R1:R0 is now "formatD"
- " lcall 00061$ \n" //to set ret addr
- " pop _R0 \n"
- " pop _R1 \n"
- " pop DPL \n"
- " pop DPH \n"
- " ret \n"
- "00061$: \n"
- " push DPL \n"
- " push DPH \n"
- " mov DPL, _R0 \n"
- " mov DPH, _R1 \n"
- " ret \n"
-
- "00099$: \n"
- " .ascii \"01234567\" \n"
- " .ascii \"89ABCDEF\" \n"
- " .ascii \"01234567\" \n"
- " .ascii \"89abcdef\" \n"
- );
- (void)fmt;
- (void)vl;
- (void)formatF;
- (void)formatD;
+ " mov A, #-12 \n"
+ " add A, sp \n"
+ " mov R0, A \n"
+ // R0 now points to pushed params, for large values, we see high bytes first
+ // to get next byte, we need to DECEREMENT R0
+
+ " mov DPH, @R0 \n"
+ " dec R0 \n"
+ " mov DPL, @R0 \n"
+ " dec R0 \n"
+ " mov _R0, @R0 \n"
+ " dec R0 \n"
+
+ // now format string is in DPTR, and R0 points to the top byte of whatever was in the first param
+
+ // main loop: get a byte of the format string
+ "00001$: \n"
+ " clr A \n"
+ " movc A, @A + DPTR \n"
+ " inc DPTR \n"
+ // if zero, we're done
+ " jz 00098$ \n"
+ // if not '%', print it
+ " cjne A, #'%', 00097$ \n"
+
+ // we got a percent sign - init state for format processing
+ " mov R4, #0 \n" // bit flags:
+ // 0x01 = '*' = pointer provided instead of value (integers only)
+ // 0x02 = '0' = zero-pad (for numbers only)
+ // 0x04 = have pad-to length
+ // 0x08 = long
+ // 0x10 = long long
+ // 0x20 = signed print requested. also: need to print a negative (used to reuse hex printing for decimal once converted to bcd)
+ " mov R2, #0 \n" // padLen
+
+ // loop for format string ingestion
+ "00002$: \n"
+ " clr A \n"
+ " movc A, @A + DPTR \n"
+ " inc DPTR \n"
+ // if zero, we're done
+ " jz 00098$ \n"
+ // check for percent sign
+ " cjne A, #'%', 00003$ \n"
+ // fallthrough to print it and go read next non-format byte
+ // print a char in A, go read next format byte
+ "00097$: \n"
+ " lcall 00060$ \n"
+ " sjmp 00001$ \n"
+
+ // exit label - placed for easy jumping to
+ "00098$: \n"
+ " pop _R0 \n"
+ " pop _R1 \n"
+ " pop _R2 \n"
+ " pop _R3 \n"
+ " pop _R4 \n"
+ " pop DPL \n"
+ " pop DPH \n"
+ " pop _R7 \n"
+ " ret \n"
+
+ // continue to process format string - handle %c
+ "00003$: \n"
+ " cjne A, #'c', 00004$ \n"
+ " dec R0 \n" // param is pushed as int (16 bits)
+ " mov A, @R0 \n"
+ " dec R0 \n"
+ " sjmp 00097$ \n" // print and go read next non-format byte
+
+ // continue to process format string - handle %m
+ "00004$: \n"
+ " mov R3, A \n"
+ " orl A, #0x20 \n"
+ " cjne A, #'m', 00008$ \n"
+
+ // sort out which hexch charset to use
+ " mov A, R3 \n"
+ " anl A, #0x20 \n"
+ " rr A \n"
+ " mov R1, A \n"
+
+ // go, do
+ " push DPH \n"
+ " push DPL \n"
+ " lcall 00090$ \n" // read the short (__xdata) pointer - >DPTR
+ " mov R4, #8 \n" // byteSel
+ "00005$: \n"
+ " push DPH \n"
+ " push DPL \n"
+ " mov A, R4 \n"
+ " dec A \n"
+ " add A, DPL \n"
+ " mov DPL, A \n"
+ " mov A, DPH \n"
+ " addc A, #0 \n"
+ " mov DPH, A \n"
+ " movx A, @DPTR \n"
+ " mov R2, A \n"
+ " swap A \n"
+ " mov R3, #2 \n"
+ "00006$: \n"
+ " anl A, #0x0f \n"
+ " add A, R1 \n"
+ " mov DPTR, #00099$ \n"
+ " movc A, @A + DPTR \n"
+ " lcall 00060$ \n"
+ " mov A, R2 \n"
+ " djnz R3, 00006$ \n"
+ " pop DPL \n"
+ " pop DPH \n"
+ " djnz R4, 00007$ \n"
+ // done with mac addr
+
+ "00055$: \n"
+ " pop DPL \n"
+ " pop DPH \n"
+ " sjmp 00001$ \n"
+ // print colon and contimue mac addr printing
+ "00007$: \n"
+ " mov A, #':' \n"
+ " lcall 00060$ \n"
+ " sjmp 00005$ \n"
+
+ // continue to process format string - handle '*'
+ "00008$: \n"
+ " mov A, R3 \n"
+ " cjne A, #'*', 00009$ \n"
+ " cjne R2, #0, 00097$ \n" // only valid when no length/padding has been specified yet, else invalid specifier
+ " mov A, #0x01 \n" //"pointer mode"
+ "00010$: \n"
+ " orl A, R4 \n"
+ " mov R4, A \n"
+ " sjmp 00002$ \n" // get next format specifier now
+
+ // continue to process format string - handle '0'
+ "00009$: \n"
+ " cjne A, #'0', 00011$ \n"
+ " cjne R2, #0, 00011$ \n" // setting "zero pad" is only valid when pad length is zero
+ " mov A, #0x06 \n" //"have pad length" | "zero-pad"
+ " sjmp 00010$ \n" // orr A into R4, get next format specifier now
+
+ // continue to process format string - handle '1'...'9'
+ "00011$: \n"
+ " mov R3, A \n"
+ " add A, #-'0' \n"
+ " jnc 00012$ \n" // now 0..9 are valid
+ " add A, #-10 \n"
+ " jc 00012$ \n"
+ " add A, #10 \n" // get it back into 1..9 range
+ " mov R3, A \n"
+ " mov A, #10 \n"
+ " mov B, R2 \n"
+ " mul AB \n"
+ " add A, R3 \n"
+ " mov R2, A \n"
+ " mov A, #0x04 \n" //"have pad length"
+ " sjmp 00010$ \n" // orr A into R4, get next format specifier now
+
+ // continue to process format string - handle 'l'
+ "00012$: \n"
+ " cjne R3, #'l', 00014$ \n"
+ " mov A, R4 \n"
+ " anl A, #0x08 \n"
+ " jz 00013$ \n" // no "long" yet? set that
+ // have long - set long log
+ " mov A, #0x10 \n" //"long long"
+ " sjmp 00010$ \n" // orr A into R4, get next format specifier now
+ // first 'l' - set long
+ "00013$: \n"
+ " mov A, #0x08 \n" //"long"
+ " sjmp 00010$ \n" // orr A into R4, get next format specifier now
+
+ // continue to process format string - handle 's'
+ "00014$: \n"
+ " cjne R3, #'s', 00025$ \n"
+ " mov A, R4 \n"
+ " anl A, #0x08 \n"
+ " push DPH \n"
+ " push DPL \n"
+ " jnz 00015$ \n"
+ " lcall 00091$ \n" // get and resolve generic pointer into DPTR
+ " sjmp 00016$ \n"
+ "00015$: \n" // get short pointer into DPTR, record that it is to XRAM
+ " clr PSW.5 \n"
+ " clr PSW.1 \n"
+ " lcall 00090$ \n"
+ "00016$: \n" // pointer to string now in DPTR
+ // we have the string pointer in {DPTR,PSW}, let's see if we have padding to do
+ " mov A, R4 \n"
+ " anl A, #0x04 \n"
+ " jnz 00018$ \n"
+ // print string with no length restrictions
+ "00017$: \n"
+ " lcall 00095$ \n"
+ " jz 00055$ \n"
+ " lcall 00060$ \n"
+ " sjmp 00017$ \n"
+
+ // print string with length restrictions and/or padding
+ "00018$: \n"
+ " cjne R2, #0, 00019$ \n" // verify reqested len was not zero
+ " sjmp 00055$ \n"
+
+ "00019$: \n"
+ " lcall 00095$ \n"
+ " jz 00020$ \n"
+ " lcall 00060$ \n"
+ " djnz R2, 00019$ \n"
+ // we get here if we ran out of allowable bytes - we're done then
+ " ljmp 00055$ \n"
+
+ // just a trampoline for range issues
+ "00035$: \n"
+ " ljmp 00036$ \n"
+
+ // we need to pad with spaces
+ "00020$: \n"
+ " mov A, #' ' \n"
+ " lcall 00060$ \n"
+ " djnz R2, 00020$ \n"
+ " ljmp 00055$ \n"
+
+ // continue to process format string - handle 'x'/'X'
+ "00025$: \n"
+ " mov A, R3 \n"
+ " orl A, #0x20 \n"
+ " cjne A, #'x', 00035$ \n"
+ " push DPH \n"
+ " push DPL \n"
+ " lcall 00080$ \n" // get pointer to the number in DPTR, length in bytes in B
+ // save it
+
+ "00070$: \n"
+ " push DPH \n"
+ " push DPL \n"
+
+ // sort out how long it would be if printed, first get a pointer to the highest
+ " mov A, B \n"
+ " rl A \n"
+ " mov R1, A \n"
+ " rr A \n"
+ " add A, #0xff \n"
+ " add A, DPL \n"
+ " mov DPL, A \n"
+ " mov A, DPH \n"
+ " addc A, #0x00 \n"
+ " mov DPH, A \n"
+ "00026$: \n"
+ " lcall 00079$ \n"
+ " anl A, #0xf0 \n"
+ " jnz 00028$ \n"
+ " dec R1 \n"
+ " lcall 00079$ \n"
+ " jnz 00028$ \n"
+ " dec R1 \n"
+ // dec DPTR
+ " dec DPL \n"
+ " mov A, DPL \n"
+ " cjne A, #0xff, 00027$ \n"
+ " dec DPH \n"
+ "00027$: \n"
+ " djnz B, 00026$ \n"
+
+ // we now know how many digits the number is (in R1), except that it has "0" if the number if zero, we cannot have that
+ "00028$: \n"
+ " cjne R1, #0, 00029$ \n"
+ " inc R1 \n"
+ "00029$: \n" // we now finally have the full length of the digits
+
+ // if the number is negative (happens when we're printing decimals)
+ // the length of it is one more, also in case of zero-padding, we need to print the minus sign here now
+ " mov A, R4 \n"
+ " anl A, #0x20 \n"
+ " jz 00051$ \n"
+ " inc R1 \n" // the length is one more
+ " mov A, R4 \n"
+ " anl A, #02 \n" // if zero-padding, the negative comes now
+ " jz 00051$ \n"
+ " mov A, #'-' \n"
+ " lcall 00060$ \n"
+ "00051$: \n"
+
+ // sort out if we need padding at all and if there is space
+ " mov A, R4 \n"
+ " anl A, #0x04 \n"
+ " jz 00031$ \n" // no padding requested
+ // padding was requested len is in R2
+ " mov A, R2 \n"
+ " clr C \n"
+ " subb A, R1 \n"
+ " jc 00031$ \n" // pad-to len < number_len -> no padding needed
+ " jz 00031$ \n" // pad-to len == number_len -> no padding needed
+ " mov R2, A \n"
+
+ // sort out which character to use -> DPL
+ " mov A, R4 \n" // fancy way to create space/zero as needed
+ " anl A, #0x02 \n"
+ " swap A \n"
+ " rr A \n"
+ " add A, #0x20 \n"
+ " mov DPL, A \n"
+
+ // pad!
+ "00030$: \n"
+ " mov A, DPL \n"
+ " lcall 00060$ \n"
+ " djnz R2, 00030$ \n"
+ "00031$: \n"
+
+ // if the number is negative (happens when we're printing decimals)
+ // we made the length of it is one more, which we need to undo
+ // also in case of space-padding, we need to print the minus sign here now
+ " mov A, R4 \n"
+ " anl A, #0x20 \n"
+ " jz 00052$ \n"
+ " dec R1 \n" // the length is one less than we had increased it to
+ " mov A, R4 \n"
+ " anl A, #02 \n" // if space-padding, the negative comes now
+ " jnz 00052$ \n"
+ " mov A, #'-' \n"
+ " lcall 00060$ \n"
+ "00052$: \n"
+
+ // time to print the number itself
+ // sort out which hexch charset to use -> R2
+ " mov A, R3 \n"
+ " anl A, #0x20 \n"
+ " rr A \n"
+ " mov R2, A \n"
+ // re-get the number pointer
+ " pop DPL \n"
+ " pop DPH \n"
+ // currently DPTR points to the number low byte, R1 is now many digits we expect to print, R2 is the charset selection, R4 and R3 are free
+ // let's calculate how many bytes we expect to process -> R4
+ " mov A, R1 \n"
+ " inc A \n"
+ " clr C \n"
+ " rrc A \n"
+ " mov R4, A \n"
+ // let's repoint DPTR to the first byte we'll print in (remember we print 2 digits per byte)
+ " dec A \n"
+ " add A, DPL \n"
+ " mov DPL, A \n"
+ " mov A, DPH \n"
+ " addc A, #0x00 \n"
+ " mov DPH, A \n"
+
+ // decide if we need to print just a nibble of the high byte or the whole thing. Free up R1
+ " mov A, R1 \n"
+ " anl A, #0x01 \n"
+ " jz 00032$ \n"
+
+ // we're printing just the low nibble of the first byte - set up for it
+ " lcall 00079$ \n"
+ " mov R1, #1 \n"
+ " sjmp 00033$ \n"
+
+ // print loop
+ "00032$: \n"
+ " lcall 00079$ \n"
+ " mov R1, #2 \n"
+ " mov R3, A \n"
+ " swap A \n"
+ "00033$: \n"
+ " anl A, #0x0f \n"
+ " add A, R2 \n"
+ " push DPH \n"
+ " push DPL \n"
+ " mov DPTR, #00099$ \n"
+ " movc A, @A + DPTR \n"
+ " pop DPL \n"
+ " pop DPH \n"
+ " lcall 00060$ \n"
+ " mov A, R3 \n"
+ " djnz R1, 00033$ \n"
+
+ // dec DPTR
+ " dec DPL \n"
+ " mov A, DPL \n"
+ " cjne A, #0xff, 00034$ \n"
+ " dec DPH \n"
+ "00034$: \n"
+ " djnz R4, 00032$ \n"
+
+ // done!
+ " ljmp 00055$ \n"
+
+ // continue to process format string - handle 'd'
+ "00036$: \n"
+ " cjne R3, #'d', 00037$ \n"
+ " mov A, #0x20 \n"
+ " orl A, R4 \n"
+ " mov R4, A \n"
+ " sjmp 00040$ \n"
+
+ // continue to process format string - handle 'u'
+ "00037$: \n"
+ " cjne R3, #'u', 00038$ \n"
+ " sjmp 00040$ \n"
+
+ // no more format strings exist that we can handle - bail
+ "00038$: \n"
+ " ljmp 00001$ \n"
+
+ // handle decimal printing
+ "00040$: \n"
+ " push DPH \n"
+ " push DPL \n"
+ " lcall 00080$ \n" // get pointer to the number in DPTR, length in bytes in B
+ " push B \n"
+
+ // copy the number to the double-dabble storage at proper offset (0 for u64, 4 for u32, 6 for u16)
+ // we do this so that the dabble area always starts at the same place...
+ " mov A, #8 \n"
+ " clr C \n"
+ " subb A, B \n"
+ " add A, #_mCvtBuf \n"
+ " mov R1, A \n"
+ " clr A \n"
+ " addc A, #(_mCvtBuf >> 8) \n"
+ " mov R3, A \n"
+ "00041$: \n"
+ " lcall 00079$ \n"
+ " inc DPTR \n"
+ " lcall 00086$ \n"
+ " movx @DPTR, A \n"
+ " inc DPTR \n"
+ " lcall 00086$ \n"
+ " djnz B, 00041$ \n"
+ // leave DPTR pointing to dabble storage, past the number
+ " lcall 00086$ \n"
+
+ // we now have the top byte of the number in A, good time to check for negatives, if needed
+ " mov B, A \n"
+ " mov A, R4 \n"
+ " anl A, #0x20 \n"
+ " jz 00050$ \n" // unsigned printing requested
+ " mov A, B \n"
+ " anl A, #0x80 \n"
+ " jnz 00043$ \n" // is negative - we need to invert, 0x20 bit in R1 stays
+ // positive - 0x20 bit in R1 needs to go
+ " mov A, R4 \n"
+ " anl A, #~0x20 \n"
+ " mov R4, A \n"
+ " sjmp 00050$ \n"
+
+ // we need to negate the number
+ // but first we need a pointer to it, and its size
+ "00043$: \n"
+ " pop B \n"
+ " push B \n"
+ " mov A, #8 \n"
+ " clr C \n"
+ " subb A, B \n"
+ " add A, #_mCvtBuf \n"
+ " mov DPL, A \n"
+ " clr A \n"
+ " addc A, #(_mCvtBuf >> 8) \n"
+ " mov DPH, A \n"
+
+ // ok, now we are ready to negate it
+ " clr C \n"
+ "00049$: \n"
+ " movx A, @DPTR \n"
+ " mov R1, A \n"
+ " clr A \n"
+ " subb A, R1 \n"
+ " movx @DPTR, A \n"
+ " inc DPTR \n"
+ " djnz B, 00049$ \n"
+
+ // zero out the rest of the storage (10 bytes)
+ "00050$: \n"
+ " mov B, #10 \n"
+ " clr A \n"
+ "00042$: \n"
+ " movx @DPTR, A \n"
+ " inc DPTR \n"
+ " djnz B, 00042$ \n"
+
+ // calculate number of dabble steps
+ " pop A \n"
+ " swap A \n"
+ " rr A \n"
+ " mov R3, A \n"
+
+ // do the thing
+ "00044$: \n"
+
+ // dabble (10 iters for simplicity)
+ " mov DPTR, #(_mCvtBuf + 8) \n"
+ " mov B, #10 \n"
+ "00046$: \n"
+ " movx A, @DPTR \n"
+ " mov R1, A \n"
+ " anl A, #0x0f \n"
+ " add A,#-0x05 \n"
+ " mov A, R1 \n"
+ " jnc 00047$ \n"
+ " add A, #0x03 \n"
+ "00047$: \n"
+ " mov R1, A \n"
+ " anl A, #0xf0 \n"
+ " add A,#-0x50 \n"
+ " mov A, R1 \n"
+ " jnc 00048$ \n"
+ " add A, #0x30 \n"
+ "00048$: \n"
+ " movx @DPTR, A \n"
+ " inc DPTR \n"
+ " djnz B, 00046$ \n"
+
+ // double (18 iters for simplicity)
+ " mov DPTR, #_mCvtBuf \n"
+ " clr C \n"
+ " mov B, #18 \n"
+ "00045$: \n"
+ " movx A, @DPTR \n"
+ " rlc A \n"
+ " movx @DPTR, A \n"
+ " inc DPTR \n"
+ " djnz B, 00045$ \n"
+
+ " djnz R3, 00044$ \n"
+
+ // dabbling is done, print it now using hex routine
+ " mov DPTR, #(_mCvtBuf + 8) \n"
+ " mov B, #10 \n"
+ " clr PSW.5 \n" // it is now for sure in XRAM
+ " ljmp 00070$ \n"
+
+ // read short pointer from param stack
+ "00090$: \n"
+ " mov DPH, @R0 \n"
+ "00093$: \n"
+ " dec R0 \n"
+ " mov DPL, @R0 \n"
+ " dec R0 \n"
+ " ret \n"
+
+ // read and increment pointer of the type provided by 00091$ (in {DPTR,PSW}) into A. clobber nothing
+ "00095$: \n"
+ " jb PSW.5, 00066$ \n"
+ " jb PSW.1, 00067$ \n"
+ // XRAM
+ " movx A, @DPTR \n"
+ " inc DPTR \n"
+ " ret \n"
+ // CODE
+ "00066$: \n"
+ " clr A \n"
+ " movc A, @A+DPTR \n"
+ " inc DPTR \n"
+ " ret \n"
+ // IRAM
+ "00067$: \n"
+ " mov DPH, R0 \n"
+ " mov R0, DPL \n"
+ " mov A, @R0 \n"
+ " mov R0, DPH \n"
+ " inc DPL \n"
+ " ret \n"
+
+ // resolve generic pointer on param stack to an pointer in DPTR and flags in PSW.5 and PSW.1
+ // PSW.5 will be 0 and PSW.1 will be 0 for XRAM (PDATA goes here too)
+ // PSW.5 will be 1 and PSW.1 will be 0 for CODE
+ // PSW.5 will be 0 and PSW.1 will be 1 for IRAM
+ "00091$: \n"
+ " clr PSW.5 \n"
+ " clr PSW.1 \n"
+ " mov A, @R0 \n"
+ " dec R0 \n"
+ " jz 00090$ \n" // 0x00: pointer type: xdata
+ " xrl A, #0x80 \n"
+ " jz 00094$ \n" // 0x80: pointer type: code
+ " xrl A, #0xc0 \n"
+ " jz 00092$ \n" // 0x40: pointer type: idata
+ // pdata
+ " mov DPH, _XPAGE \n"
+ " sjmp 00093$ \n"
+ // idata
+ "00092$: \n"
+ " setb PSW.1 \n"
+ " sjmp 00093$ \n"
+ // code
+ "00094$: \n"
+ " setb PSW.5 \n"
+ " sjmp 00090$ \n"
+
+ // read the pointer of the type that 00080$ returns (in DPTR) into A. clobber nothing
+ "00079$: \n"
+ " jnb PSW.5, 00078$ \n"
+ " push _R0 \n"
+ " mov R0, DPL \n"
+ " mov A, @R0 \n"
+ " pop _R0 \n"
+ " ret \n"
+ "00078$: \n"
+ " movx A, @DPTR \n"
+ " ret \n"
+
+ // get pointer to a number, might be pushed or might be pointed to, size might vary. return pointer to number's LOW byte in DPTR
+ "00080$: \n"
+ " mov A, R4 \n"
+ " anl A, #0x01 \n"
+ " jnz 00083$ \n"
+ // param is itself on stack - now we care about size, but either way, PSW.5 will be 1
+ " setb PSW.5 \n"
+ " mov B, #0 \n"
+ " mov A, R4 \n"
+ " anl A, #0x18 \n"
+ " jz 00081$ \n"
+ " anl A, #0x10 \n"
+ " jz 00082$ \n"
+ // long long (8 bytes) \n"
+ " setb B.2 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ // long (4 bytes)
+ "00082$: \n"
+ " setb B.1 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ // int (2 bytes) \n"
+ "00081$: \n"
+ " setb B.0 \n"
+ " dec R0 \n"
+ " mov DPL, R0 \n"
+ " dec R0 \n"
+ " inc B \n"
+ " ret \n"
+ // pointer it on stack itself, number is in xram, but we still need to provide the length
+ "00083$: \n"
+ " clr PSW.5 \n" // mark as "in xram"
+ " mov A, R4 \n"
+ " anl A, #0x18 \n"
+ " jz 00084$ \n"
+ " anl A, #0x10 \n"
+ " jz 00085$ \n"
+ // long long
+ " mov B, #8 \n"
+ " ljmp 00090$ \n"
+ // long
+ "00085$: \n"
+ " mov B, #4 \n"
+ " ljmp 00090$ \n"
+ // int
+ "00084$: \n"
+ " mov B, #2 \n"
+ " ljmp 00090$ \n"
+
+ // swap R3:R1 <-> DPH:DPL
+ "00086$: \n"
+ " xch A, DPH \n"
+ " xch A, R3 \n"
+ " xch A, DPH \n"
+ " xch A, DPL \n"
+ " xch A, R1 \n"
+ " xch A, DPL \n"
+ " ret \n"
+
+ /* putchar func
+ called via call. char is in A, R7 has pointer to stack as needed
+ can clobber B, CANNOT clobber DPTR
+ a mess because...8051
+ */
+ "00060$: \n"
+ " push DPH \n"
+ " push DPL \n"
+ " push _R1 \n"
+ " push _R0 \n"
+ " mov _R0, R7 \n"
+ " mov DPL, @R0 \n"
+ " dec R0 \n"
+ " mov DPH, @R0 \n" // DPTR is now func ptr
+ " dec R0 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ " dec R0 \n"
+ " mov _R1, @R0 \n"
+ " dec R0 \n"
+ " mov _R0, @R0 \n" // R1:R0 is now "formatD"
+ " lcall 00061$ \n" // to set ret addr
+ " pop _R0 \n"
+ " pop _R1 \n"
+ " pop DPL \n"
+ " pop DPH \n"
+ " ret \n"
+ "00061$: \n"
+ " push DPL \n"
+ " push DPH \n"
+ " mov DPL, _R0 \n"
+ " mov DPH, _R1 \n"
+ " ret \n"
+
+ "00099$: \n"
+ " .ascii \"01234567\" \n"
+ " .ascii \"89ABCDEF\" \n"
+ " .ascii \"01234567\" \n"
+ " .ascii \"89abcdef\" \n");
+ (void)fmt;
+ (void)vl;
+ (void)formatF;
+ (void)formatD;
}
#pragma callee_saves prPrvPutchar
-static void prPrvPutchar(uint32_t data) __reentrant
-{
- char ch = data >> 24;
-
- if (ch == '\n')
- dbgUartByte('\r');
- dbgUartByte(ch);
+static void prPrvPutchar(uint32_t data) __reentrant {
+ char ch = data >> 24;
+ if (ch == '\n')
+ uartTx('\r');
+ uartTx(ch);
+}
+#pragma callee_saves epdPutchar
+static void epdPutchar(uint32_t data) __reentrant {
+ char ch = data >> 24;
+ writeCharEPD(ch);
}
-void pr(const char __code *fmt, ...) __reentrant
-{
- va_list vl;
-
- va_start(vl, fmt);
- dbgUartOn();
- prvPrintFormat(prPrvPutchar, 0, fmt, vl);
- dbgUartOff();
- va_end(vl);
+void pr(const char __code *fmt, ...) __reentrant {
+ va_list vl;
+ va_start(vl, fmt);
+ prvPrintFormat(prPrvPutchar, 0, fmt, vl);
+ va_end(vl);
+}
+
+void epdpr(const char __code *fmt, ...) __reentrant {
+ va_list vl;
+ va_start(vl, fmt);
+ prvPrintFormat(epdPutchar, 0, fmt, vl);
+ va_end(vl);
}
#pragma callee_saves prPrvPutS
-static void prPrvPutS(uint32_t data) __reentrant
-{
- char __xdata * __idata *strPP = (char __xdata * __idata *)data;
- char ch = data >> 24;
-
- *(*strPP)++ = ch;
+static void prPrvPutS(uint32_t data) __reentrant {
+ char __xdata *__idata *strPP = (char __xdata *__idata *)data;
+ char ch = data >> 24;
+
+ *(*strPP)++ = ch;
}
-void spr(char __xdata* out, const char __code *fmt, ...) __reentrant
-{
- char __xdata* outStart = out;
-
- va_list vl;
-
- va_start(vl, fmt);
- prvPrintFormat(prPrvPutS, (uint16_t)&out, fmt, vl);
- va_end(vl);
-
- *out = 0;
-}
+void spr(char __xdata *out, const char __code *fmt, ...) __reentrant {
+ char __xdata *outStart = out;
+ va_list vl;
+
+ va_start(vl, fmt);
+ prvPrintFormat(prPrvPutS, (uint16_t)&out, fmt, vl);
+ va_end(vl);
+
+ *out = 0;
+}
diff --git a/tag_fw/drawing.c b/tag_fw/drawing.c
index 1c91b4bc..e752395a 100644
--- a/tag_fw/drawing.c
+++ b/tag_fw/drawing.c
@@ -1,8 +1,10 @@
+#include "drawing.h"
+
#include
+
#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();
diff --git a/tag_fw/epd.c b/tag_fw/epd.c
index 79d08ab1..1aa05b94 100644
--- a/tag_fw/epd.c
+++ b/tag_fw/epd.c
@@ -4,6 +4,7 @@
#include
#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);
-}
\ No newline at end of file
+}
diff --git a/tag_fw/epd.h b/tag_fw/epd.h
index e9eefd7c..b7cfc94b 100644
--- a/tag_fw/epd.h
+++ b/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
\ No newline at end of file
diff --git a/tag_fw/lut.h b/tag_fw/lut.h
index 7e0f8a34..9a09d3ca 100644
--- a/tag_fw/lut.h
+++ b/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,
-};
\ No newline at end of file
+struct waveform10 {
+ struct lut10 lut[5];
+ struct group group[10];
+ uint8_t gatelevel;
+ uint8_t sourcelevel[3];
+ uint8_t dummyline;
+ uint8_t gatewidth;
+} __packed;
\ No newline at end of file
diff --git a/tag_fw/main.c b/tag_fw/main.c
index 997b765a..920d94d6 100644
--- a/tag_fw/main.c
+++ b/tag_fw/main.c
@@ -4,22 +4,140 @@
#include
#include
#include
+
#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();
}
diff --git a/tag_fw/make.bat b/tag_fw/make.bat
index 8f656d19..500df1a7 100644
--- a/tag_fw/make.bat
+++ b/tag_fw/make.bat
@@ -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
diff --git a/tag_fw/powermgt.c b/tag_fw/powermgt.c
new file mode 100644
index 00000000..df441448
--- /dev/null
+++ b/tag_fw/powermgt.c
@@ -0,0 +1,92 @@
+#include "powermgt.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#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;
+}
\ No newline at end of file
diff --git a/tag_fw/powermgt.h b/tag_fw/powermgt.h
new file mode 100644
index 00000000..7f641671
--- /dev/null
+++ b/tag_fw/powermgt.h
@@ -0,0 +1,24 @@
+#ifndef _POWERMGT_H_
+#define _POWERMGT_H_
+#include
+
+// 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
\ No newline at end of file
diff --git a/tag_fw/printf.h b/tag_fw/printf.h
index b04e0590..8ca2eea5 100644
--- a/tag_fw/printf.h
+++ b/tag_fw/printf.h
@@ -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;
diff --git a/tag_fw/proto.h b/tag_fw/proto.h
index 2dd14159..e71224fe 100644
--- a/tag_fw/proto.h
+++ b/tag_fw/proto.h
@@ -1,47 +1,8 @@
#ifndef _PROTO_H_
#define _PROTO_H_
-
+#define __packed
#include
-/*
- 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
\ No newline at end of file
diff --git a/tag_fw/settings.h b/tag_fw/settings.h
new file mode 100644
index 00000000..763a26ef
--- /dev/null
+++ b/tag_fw/settings.h
@@ -0,0 +1,12 @@
+#ifndef SYNCED_H
+#define SYNCED_H
+
+#include
+
+#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
\ No newline at end of file
diff --git a/tag_fw/soc/radioCommon.h b/tag_fw/soc/radioCommon.h
index 61c4f8f5..99937234 100644
--- a/tag_fw/soc/radioCommon.h
+++ b/tag_fw/soc/radioCommon.h
@@ -5,6 +5,10 @@
#include
+//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
diff --git a/tag_fw/soc/zbs243/timer.h b/tag_fw/soc/zbs243/timer.h
index bce2b700..26aa216b 100644
--- a/tag_fw/soc/zbs243/timer.h
+++ b/tag_fw/soc/zbs243/timer.h
@@ -4,7 +4,7 @@
#include
#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);
diff --git a/tag_fw/soc/zbs243/uart.c b/tag_fw/soc/zbs243/uart.c
index c41514c5..5b0c8199 100644
--- a/tag_fw/soc/zbs243/uart.c
+++ b/tag_fw/soc/zbs243/uart.c
@@ -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);
diff --git a/tag_fw/syncedproto.c b/tag_fw/syncedproto.c
index 5be1e4a2..f0aa3d85 100644
--- a/tag_fw/syncedproto.c
+++ b/tag_fw/syncedproto.c
@@ -6,122 +6,23 @@
#include
#include
#include
+
#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();
}
\ No newline at end of file
diff --git a/tag_fw/syncedproto.h b/tag_fw/syncedproto.h
index 718babfb..583296dc 100644
--- a/tag_fw/syncedproto.h
+++ b/tag_fw/syncedproto.h
@@ -3,8 +3,18 @@
#include
-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
\ No newline at end of file
diff --git a/tag_fw/userinterface.c b/tag_fw/userinterface.c
index c9eb1129..b005d802 100644
--- a/tag_fw/userinterface.c
+++ b/tag_fw/userinterface.c
@@ -1,109 +1,285 @@
+
+
#include "userinterface.h"
#include
#include
#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();
-}
\ No newline at end of file
+}
+
+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();
+}
diff --git a/tag_fw/userinterface.h b/tag_fw/userinterface.h
index 548affd7..7b697e72 100644
--- a/tag_fw/userinterface.h
+++ b/tag_fw/userinterface.h
@@ -1,9 +1,11 @@
-
#ifndef _UI_H_
#define _UI_H_
+#include
void showSplashScreen();
void showApplyUpdate();
-
-
+void showScanningWindow();
+void addScanResult(uint8_t channel, uint8_t lqi);
+void showAPFound();
+void showNoAP();
#endif
\ No newline at end of file