Last active
October 16, 2020 13:09
DS-D6 Espruino tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Modules.addCached("DSD6OLED",function(){ | |
//modified SSD1306, 128x32 but needs 0xda,0x12 | |
// commands sent when initialising the display | |
var initCmds = new Uint8Array([ | |
0xAe, // 0 disp off | |
0xD5, // 1 clk div | |
0x80, // 2 suggested ratio | |
0xA8, 31, // 3 set multiplex, height-1 | |
0xD3,0x0, // 5 display offset | |
0x40, // 7 start line | |
0x8D, 0x14, // 8 charge pump | |
0x20,0x0, // 10 memory mode - horizontal | |
0xA1, // 12 seg remap 1 | |
0xC0, // 13 comscandec | |
0xDA, 0x12, // 14 set compins, height==64 ? 0x12:0x02, | |
0x81, 0xCF, // 16 set contrast | |
0xD9, 0xF1, // 18 set precharge | |
0xDb, 0x40, // 20 set vcom detect | |
0xA4, // 22 display all on | |
0xA6, // 23 display normal (non-inverted) | |
0xAf // 24 disp on | |
]); | |
// commands sent when sending data to the display | |
var flipCmds = new Uint8Array([ | |
0x21, // columns | |
0, 127, // OLED_WIDTH-1 | |
0x22, // pages | |
0, 3 /* (height>>3)-1 */ | |
]); | |
var rotCmds = Uint8Array([ | |
0x20,0x0, // 10 memory mode - horizontal | |
0xA1, // 12 seg remap 1 | |
0xC0, // 13 comscandec | |
]); | |
var rot; | |
var gfxV; | |
var gfxH; | |
exports.connectSPI = function(spi, dc, rst, callback, options) { | |
if (rst) rst.reset(); | |
var cs = options?options.cs:undefined; | |
var r = options&&options.rotation?options.rotation:90; | |
if (options && options.contrast>=0) initCmds[17] = options.contrast; | |
var oled = {}; | |
gfxV=Graphics.createArrayBuffer(32,128,1,{vertical_byte : false}); | |
gfxH=Graphics.createArrayBuffer(128,32,1,{vertical_byte : true}); | |
oled.isOn=false; | |
oled.init = function(cmdArray){ | |
if (cs) cs.reset(); | |
// configure the OLED | |
digitalWrite(dc,0); // command | |
spi.write(cmdArray); | |
digitalWrite(dc,1); // data | |
if (cs) cs.set(); | |
}; | |
oled.setRotation = function(r){ | |
if (r=== 0){rotCmds[1]=1;rotCmds[2]=0xa1;rotCmds[3]=0xc8;} | |
if (r==180){rotCmds[1]=1;rotCmds[2]=0xa0;rotCmds[3]=0xc0;} | |
if (r== 90){rotCmds[1]=0;rotCmds[2]=0xa1;rotCmds[3]=0xc0;} | |
if (r==270){rotCmds[1]=0;rotCmds[2]=0xa0;rotCmds[3]=0xc8;} | |
oled.gfx=(r%180===0)?gfxV:gfxH; | |
rot=r; | |
oled.init(rotCmds); | |
}; | |
if (rst) digitalPulse(rst,0,20); | |
setTimeout(function() { | |
oled.init(initCmds); | |
oled.setRotation(r); | |
oled.isOn=true; | |
// if there is a callback, call it now(ish) | |
if (callback !== undefined) setTimeout(callback, 10); | |
}, 50); | |
// write to the screen | |
oled.flip = function() { | |
// set how the data is to be sent (whole screen) | |
if (cs) cs.reset(); | |
digitalWrite(dc,0);// command | |
spi.write(flipCmds); | |
digitalWrite(dc,1);// data | |
spi.write(((rot%180===0)?gfxV:gfxH).buffer); | |
if (cs) cs.set(); | |
}; | |
// set contrast, 0..255 | |
oled.setContrast = function(c) { | |
if (cs) cs.reset(); | |
spi.write(0x81,c,dc); | |
if (cs) cs.set(); | |
}; | |
// set off | |
oled.off = function() { | |
if (cs) cs.reset(); | |
spi.write(0xAE,dc); | |
if (cs) cs.set(); | |
oled.isOn=false; | |
}; | |
// set on | |
oled.on = function() { | |
if (cs) cs.reset(); | |
spi.write(0xAF,dc); | |
if (cs) cs.set(); | |
oled.isOn=true; | |
}; | |
// return graphics | |
return oled; | |
}; | |
}); | |
Modules.addCached("DSD6",function(){ | |
// D3 pin is battery voltage | |
// D2 pin is analog charger voltage | |
// with known 5V input 5.0/analogRead(D2) gave me 6.61207596594 | |
// feel free to recalibrate yourself | |
exports.battVoltage=function(){ | |
var v=6.61207596594*analogRead(D3); | |
poke32(0x50000700+3*4,2); // disconnect pin for power saving, otherwise it draws 70uA more | |
return v; | |
}; | |
exports.chargerVoltage=function(){ | |
var v=6.61207596594*analogRead(D2); | |
poke32(0x50000700+2*4,2); // disconnect pin for power saving, otherwise it draws 70uA more | |
return v; | |
}; | |
function vibon(vib){ | |
if(vib.i>=1)D25.set();else analogWrite(D25,vib.i); | |
setTimeout(viboff,vib.on,vib); | |
} | |
function viboff(vib){ | |
D25.reset(); | |
if (vib.c>1){vib.c=vib.c-1;setTimeout(vibon,vib.off,vib);} | |
} | |
exports.vibrate=function(intensity,count,onms,offms){ | |
vibon({i:intensity,c:count,on:onms,off:offms}); | |
}; | |
exports.initOLED=function(rot,f){ | |
require("Font6x8").add(Graphics); | |
require("Font6x12").add(Graphics); | |
require("Font8x12").add(Graphics); | |
require("Font8x16").add(Graphics); | |
var spi=SPI1; //new SPI() | |
spi.setup({mosi:D6,sck:D5,baud:8000000}); | |
if (f===undefined) f=function(){ | |
o.gfx.setFont6x8(); | |
o.gfx.drawString("Espruino on DS-D6",20,12); | |
o.flip(); | |
}; | |
if(rot===undefined) rot=270; | |
var o=require("DSD6OLED").connectSPI(spi,D28,D4,f,{cs:D29,rotation:rot}); | |
exports.OLED=o; | |
}; | |
var tOff=0; // offset to remember total runtime when changing clock | |
var sT=global.setTime; | |
//espruino IDE calls setTime so override it to keep track of change | |
global.setTime=function(t){ | |
var c=getTime(); | |
sT(t); | |
tOff+=getTime()-c; | |
}; | |
//("2019-08-26T14:48:00",2) | |
exports.setClock = function(t, z) { | |
//var c=getTime(); | |
if(z!==void(0))E.setTimeZone(z); | |
setTime(Date.parse(t)/1E3); | |
//tOff+=getTime()-c; | |
}; | |
exports.getUptime = function() { | |
return getTime()-tOff; | |
}; | |
/* | |
var KXREG = { | |
INS1:0x12, | |
INS2:0x13, | |
INS3:0x14, | |
STATUS_REG:0x15, | |
INT_REL:0x17, | |
CNTL1:0x18, | |
CNTL3:0x1a, | |
ODCNTL:0x1b, | |
INC1:0x1c, | |
INC2:0x1d, | |
INC4:0x1f, | |
TILT_TIMER:0x22, | |
WUFC:0x23, | |
ATH:0x30, | |
BUF_CNTL2:0x3b | |
}; | |
exports.ACCREG=KXREG; | |
*/ | |
function accRead(reg,len){i2c.writeTo(0x1f,reg);return i2c.readFrom(0x1f,len);} | |
function accWrite(reg,data){i2c.writeTo(0x1f,reg,data);} | |
//var i2c=new I2C() | |
var i2c=I2C1; | |
exports.initAccel=function(){ | |
i2c.setup({scl:13, sda:14, bitrate:400000}); | |
}; | |
function accRegDump(reg){ | |
val=accRead(reg,1)[0];return val.toString(10)+" 0x"+val.toString(16)+" %"+val.toString(2); | |
} | |
exports.accINSDump=function(){ | |
console.log("INS1:",accRegDump(0x12),"INS2:",accRegDump(0x13),"INS3:",accRegDump(0x14)); | |
}; | |
exports.accelCoords=function(){ | |
coords=new Int16Array(accRead(0x06,6).buffer); | |
return {x:coords[0],y:coords[1],z:coords[2]}; | |
}; | |
exports.accRead=accRead; | |
exports.accWrite=accWrite; | |
exports.accRegDump=accRegDump; | |
}); | |
var w=require("DSD6"); | |
w.initOLED(270); // init and set to landscape mode | |
var o=w.OLED; | |
function setupSerial(s){ | |
if (!s) s=Serial1; | |
s.setup(38400,{rx:D22,tx:D23}); | |
} | |
function resumeConsole(s){ | |
setupSerial(s); | |
setTimeout(()=>{s.setConsole();},50); | |
} | |
function pauseConsole(s){ | |
if (!s) s=Serial1; | |
if(s._options){ | |
Bluetooth.setConsole(1); | |
setTimeout(()=>{ | |
var rx=s._options.rx; | |
s.unsetup(); | |
rx.mode("input_pulldown"); | |
setWatch(()=>{resumeConsole(s);},rx,{edge:'rising',debounce:30});} | |
,500); | |
} | |
} | |
function getAdvertisingName(){ | |
var adv=new Uint8Array(NRF.getAdvertisingData()); | |
//aray of len,type,data records | |
//9=name, see https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/ | |
for (i=0;i<adv.length;i+=adv[i]+1){ | |
if (adv[i+1]==9) return E.toString(new Uint8Array(adv.buffer,i+2,adv[i]-1)); | |
} | |
return ""; | |
} | |
var advertising=true; //by default | |
function setAdvertising(enable){ | |
if (enable===undefined) return advertising; | |
if (enable) NRF.wake(); else NRF.sleep(); | |
advertising=enable; | |
} | |
/* | |
// watch KX023 interrupt pin | |
setWatch(function(s){ | |
if (s.state){w.accINSDump();console.log(s,w.accRegDump(0x17));} | |
},D15,true); | |
*/ | |
//w.vibrate(0.75,8,500,600) | |
//setTClock("2019-01-06T10:35:02",2) | |
// show clock in landscape mode | |
var clockFace = { | |
offms: 6000, | |
show : function(o){ | |
if (!this.run) return; | |
var g=o.gfx; | |
g.setFont6x8();g.clear(); | |
var d=(Date()).toString().split(' '); | |
var dt=d[0]+" "+d[1]+" "+d[2]+" "+d[3]; | |
g.drawString(dt,64-g.stringWidth(dt)/2,0); | |
g.drawString(this.v,0,24); | |
g.setFont8x16(); | |
g.drawString(d[4],64-g.stringWidth(d[4])/2,9); | |
o.flip();o.on(); | |
// schedule refresh on next second | |
this.tid=setTimeout(function(t,o){ | |
t.tid=-1; | |
t.show(o); | |
},1000-Date().getMilliseconds(),this,o); | |
}, | |
tid:-1, | |
run:false, | |
init: function(){ | |
this.v=w.battVoltage().toString().substr(0,5)+"V"; | |
this.run=true; | |
}, | |
exit: function(o){ | |
this.run=false; | |
if (this.tid>=0) clearTimeout(this.tid); | |
this.tid=-1; | |
return true; | |
}, | |
off: function(o){ | |
this.exit(o); | |
} | |
}; | |
var infoFace = { | |
// from https://devzone.nordicsemi.com/f/nordic-q-a/1171/how-do-i-access-softdevice-version-string | |
sdver : { | |
"81":"2.0.0", | |
"88":"2.0.1", | |
"8c":"3.0.0", | |
"91":"3.1.0" | |
}, | |
page: 0, | |
offms: 10000, | |
show: function(o){ | |
var g=o.gfx; | |
g.setFont6x8();g.clear(); | |
switch(this.page){ | |
case 0: | |
var bv=w.battVoltage().toString().substr(0,5)+"V"; | |
var chv=w.chargerVoltage().toString().substr(0,5)+"V"; | |
g.drawString("MAC: "+NRF.getAddress().toUpperCase()+"\nUART: "+((Serial1._options)?"ON, "+Serial1._baudrate:"OFF")+"\nCharger: "+(w.chargerVoltage()>0.5 ? chv:"OFF")+"\nBattery: "+bv); | |
break; | |
case 1: | |
var e=process.env,m=process.memory(); | |
g.drawString("Ver: "+e.VERSION+ | |
" S132-"+this.sdver[peek16(0x300c).toString(16)]+ | |
"\nName: "+getAdvertisingName()+ (advertising?"":" (off)")+ | |
"\nConsole: "+e.CONSOLE+ | |
"\nVars free:"+m.free+" used:"+m.usage); | |
break; | |
} | |
o.flip();o.on(); | |
}, | |
exit: function(o){ | |
this.page++; | |
this.page%=2; //2 pages | |
if (this.page==0) return true; | |
this.show(o); | |
return false ; //allow switch to next face only after all pages are shown | |
}, | |
init: function(){ | |
this.page=0; | |
}, | |
off: function(o){ | |
// toggle advertising if screen goes off on page 1 | |
if (this.page==1) {w.vibrate(1,1,50,0);setAdvertising(!advertising);} | |
} | |
}; | |
var offid=-1; | |
var offms=5000; | |
var fcurr=-1; | |
var fprev=-1; | |
var faces = [ | |
clockFace, | |
infoFace | |
]; | |
function buttonHandler(s){ | |
//var dbl=(s && s.lastTime && (s.time-s.lastTime)<0.5); | |
//if (dbl)console.log("double click"); | |
var fshow=1; | |
if (fcurr<0){ | |
// nothing active, make first one | |
fprev=fcurr; | |
fcurr=0; | |
if (faces[fcurr].init) faces[fcurr].init(); | |
} else { | |
// ask active one to exit | |
if (!faces[fcurr].exit || faces[fcurr].exit(o)){ | |
// ok exit from current face allowed | |
fprev=fcurr; | |
if(o.isOn) { | |
fcurr++; if (fcurr >= faces.length) fcurr=0; | |
} else fcurr=0; | |
if (faces[fcurr].init) faces[fcurr].init(); | |
} else fshow=0; | |
} | |
if (offid>=0) clearTimeout(offid); | |
var foffms=faces[fcurr].offms; | |
offid=setTimeout((f)=>{ | |
if (f>=0 && faces[f].off) faces[f].off(o); | |
o.off();offid=-1;fcurr=-1; | |
},(foffms>0)?foffms:offms,fcurr); | |
if (fshow) faces[fcurr].show(o); | |
} | |
setTimeout(()=>{ | |
o.setContrast(10); | |
o.off(); | |
setWatch(buttonHandler,BTN1,true); | |
},3000); | |
setupSerial();// first set to known state | |
// now pause serial console for power saving, it will be enabled when RX goes high | |
// it should be enough to connect to serial adapter | |
pauseConsole(Serial1); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
these should be just harmless warnings, I have them too, the module is added dynamically via Modules.addCached("DSD6....,. code so the files are not needed