From 131878133d305a16c413b4309869ff1b295bd8e9 Mon Sep 17 00:00:00 2001 From: eworc778 Date: Sun, 10 Aug 2025 17:49:52 +0100 Subject: [PATCH] Initial commit; Added previously untracked files. --- code.py | 430 +++++++++++++++++++++ lib/adafruit_ahtx0.mpy | Bin 0 -> 1277 bytes lib/adafruit_bus_device/__init__.py | 0 lib/adafruit_bus_device/i2c_device.mpy | Bin 0 -> 1138 bytes lib/adafruit_bus_device/spi_device.mpy | Bin 0 -> 793 bytes lib/adafruit_hid/__init__.mpy | Bin 0 -> 761 bytes lib/adafruit_hid/consumer_control.mpy | Bin 0 -> 612 bytes lib/adafruit_hid/consumer_control_code.mpy | Bin 0 -> 354 bytes lib/adafruit_hid/keyboard.mpy | Bin 0 -> 1211 bytes lib/adafruit_hid/keyboard_layout_base.mpy | Bin 0 -> 1271 bytes lib/adafruit_hid/keyboard_layout_us.mpy | Bin 0 -> 330 bytes lib/adafruit_hid/keycode.mpy | Bin 0 -> 1729 bytes lib/adafruit_hid/mouse.mpy | Bin 0 -> 834 bytes lib/adafruit_register/__init__.py | 0 lib/adafruit_register/i2c_bcd_alarm.mpy | Bin 0 -> 1465 bytes lib/adafruit_register/i2c_bcd_datetime.mpy | Bin 0 -> 938 bytes lib/adafruit_register/i2c_bit.mpy | Bin 0 -> 649 bytes lib/adafruit_register/i2c_bits.mpy | Bin 0 -> 904 bytes lib/adafruit_register/i2c_struct.mpy | Bin 0 -> 888 bytes lib/adafruit_register/i2c_struct_array.mpy | Bin 0 -> 880 bytes lib/keyboard_layout_win_uk.mpy | Bin 0 -> 545 bytes lib/keycode_win_uk.mpy | Bin 0 -> 1640 bytes lib/lcd/__init__.py | 0 lib/lcd/i2c_pcf8574_interface.py | 95 +++++ lib/lcd/lcd.py | 289 ++++++++++++++ lib/rgb1602/__init__.py | 1 + lib/rgb1602/colours.py | 164 ++++++++ lib/rgb1602/display.py | 307 +++++++++++++++ lib/rgb1602/examples.py | 45 +++ lib/waveshare_lcd1602.py | 234 +++++++++++ macros/archinstall.mcr | 194 ++++++++++ macros/syntax.mcr | 0 macros/test.mcr | 59 +++ settings.toml | 0 34 files changed, 1818 insertions(+) create mode 100644 code.py create mode 100644 lib/adafruit_ahtx0.mpy create mode 100644 lib/adafruit_bus_device/__init__.py create mode 100644 lib/adafruit_bus_device/i2c_device.mpy create mode 100644 lib/adafruit_bus_device/spi_device.mpy create mode 100644 lib/adafruit_hid/__init__.mpy create mode 100644 lib/adafruit_hid/consumer_control.mpy create mode 100644 lib/adafruit_hid/consumer_control_code.mpy create mode 100644 lib/adafruit_hid/keyboard.mpy create mode 100644 lib/adafruit_hid/keyboard_layout_base.mpy create mode 100644 lib/adafruit_hid/keyboard_layout_us.mpy create mode 100644 lib/adafruit_hid/keycode.mpy create mode 100644 lib/adafruit_hid/mouse.mpy create mode 100644 lib/adafruit_register/__init__.py create mode 100644 lib/adafruit_register/i2c_bcd_alarm.mpy create mode 100644 lib/adafruit_register/i2c_bcd_datetime.mpy create mode 100644 lib/adafruit_register/i2c_bit.mpy create mode 100644 lib/adafruit_register/i2c_bits.mpy create mode 100644 lib/adafruit_register/i2c_struct.mpy create mode 100644 lib/adafruit_register/i2c_struct_array.mpy create mode 100644 lib/keyboard_layout_win_uk.mpy create mode 100644 lib/keycode_win_uk.mpy create mode 100644 lib/lcd/__init__.py create mode 100644 lib/lcd/i2c_pcf8574_interface.py create mode 100644 lib/lcd/lcd.py create mode 100644 lib/rgb1602/__init__.py create mode 100644 lib/rgb1602/colours.py create mode 100644 lib/rgb1602/display.py create mode 100644 lib/rgb1602/examples.py create mode 100644 lib/waveshare_lcd1602.py create mode 100644 macros/archinstall.mcr create mode 100644 macros/syntax.mcr create mode 100644 macros/test.mcr create mode 100644 settings.toml diff --git a/code.py b/code.py new file mode 100644 index 0000000..70b09b4 --- /dev/null +++ b/code.py @@ -0,0 +1,430 @@ +import busio +import board +from board import * +from rainbowio import colorwheel +import waveshare_LCD1602 +from digitalio import DigitalInOut, Direction, Pull +import time +import board +import usb_hid +from adafruit_hid.keyboard import Keyboard +from keyboard_layout_win_uk import KeyboardLayout +from keycode_win_uk import Keycode +"""Default I2C ports on boards that have one""" +i2c = busio.I2C(GP19, GP18) + +buttonOne = DigitalInOut(board.GP0) +buttonOne.pull = Pull.UP + +buttonTwo = DigitalInOut(board.GP1) +buttonTwo.pull = Pull.UP + +buttonThree = DigitalInOut(board.GP2) +buttonThree.pull = Pull.UP + +kbd = Keyboard(usb_hid.devices) +layout = KeyboardLayout(kbd) + + +lcd = waveshare_LCD1602.LCD1602(i2c, 16, 2) +lcd.setCursor(0,0) + + +def macro_parser(macroFileName=(str)): + + file = open("macros/" + macroFileName, 'r') + + clearScr = 1 + lineToShow = "" + holdingKeys = 0 + sendCombo = 0 + keysToPress = [] + for line in file: + print(line) + + + line = line.replace("\n", "") + workingLine = line + + sleepingTime = 0 + + if line == "HOLD": + + holdingKeys = 1 + + if line == "RELEASE": + + if holdingKeys == 1: + + sendCombo = 1 + + if sendCombo == 1: + + if len(keysToPress) == 1: + + kbd.send(keysToPress[0]) + + + + kbd.release_all() + + elif len(keysToPress) == 2: + + kbd.send(keysToPress[0], keysToPress[1]) + + + + kbd.release_all() + + elif len(keysToPress) == 3: + + kbd.send(keysToPress[0], keysToPress[1], keysToPress[2]) + + + + kbd.release_all() + + elif len(keysToPress) == 4: + + kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3]) + + + + kbd.release_all() + + elif len(keysToPress) == 5: + + kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4]) + + kbd.release_all() + + elif len(keysToPress) == 6: + + kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4], keysToPress[5]) + + + + kbd.release_all() + + sendCombo = 0 + + holdingKeys = 0 + + keysToPress = [] + + if line == "super": + + if holdingKeys == 1: + + keysToPress.append(Keycode.WINDOWS) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.WINDOWS) + + if line == "escape": + + if holdingKeys == 1: + + keysToPress.append(Keycode.ESCAPE) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.ESCAPE) + + if line == "tab": + + if holdingKeys == 1: + + keysToPress.append(Keycode.TAB) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.TAB) + + + + + if line == "windows": + + if holdingKeys == 1: + + keysToPress.append(Keycode.WINDOWS) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.WINDOWS) + + if line == "ctrl": + + if holdingKeys == 1: + + keysToPress.append(Keycode.LEFT_CONTROL) + else: + time.sleep(0.1) + + kbd.send(Keycode.LEFT_CONTROL) + + + if line == "shift": + + if holdingKeys == 1: + + keysToPress.append(Keycode.LEFT_SHIFT) + else: + time.sleep(0.1) + + kbd.send(Keycode.LEFT_SHIFT) + + if line.startswith("LCD_SHOW \""): + + line = line.replace("LCD_SHOW \"", "\"") + + line = line.replace('"', "") + + lineToShow = line + + clearScr = 0 + + if line.startswith("#"): + pass + + if line == "": + pass + + if line.startswith("WAIT"): + + line = line.replace("WAIT", "") + line = line.replace(" ", "") + + sleepingTime = line + + + + clearScr = 1 + + if line.startswith('"') and line.endswith('"'): + + lineLength = len(line) + + tempLine = "" + + currentLine = line + + for i in range(0, lineLength): + + if i == 0: + pass + + elif i != (lineLength - 1): + + tempLine = tempLine + currentLine[i] + + line = tempLine + + if holdingKeys == 0: + + layout.write(line) + + line = currentLine + + if len(tempLine) == 1: + + if holdingKeys == 1: + + keysToPress.append(layout.keycodes(tempLine)[0]) + + + if line == "downarrow": + if holdingKeys == 1: + + keysToPress.append(Keycode.DOWN_ARROW) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.DOWN_ARROW) + + + elif line == "uparrow": + + if holdingKeys == 1: + + keysToPress.append(Keycode.UP_ARROW) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.UP_ARROW) + + + elif line == "leftarrow": + if holdingKeys == 1: + + keysToPress.append(Keycode.LEFT_ARROW) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.LEFT_ARROW) + elif line == "space": + if holdingKeys == 1: + + keysToPress.append(Keycode.SPACE) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.SPACE) + + elif line == "capslock": + if holdingKeys == 1: + + keysToPress.append(Keycode.CAPS_LOCK) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.CAPS_LOCK) + + + elif line == "rightarrow": + if holdingKeys == 1: + + keysToPress.append(Keycode.RIGHT_ARROW) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.RIGHT_ARROW) + + elif line == "forwardslash": + if holdingKeys == 1: + + keysToPress.append(Keycode.FORWARD_SLASH) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.FORWARD_SLASH) + + + elif line == "backslash": + if holdingKeys == 1: + + keysToPress.append(Keycode.BACKSLASH) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.BACKSLASH) + + elif line == "backspace": + if holdingKeys == 1: + + keysToPress.append(Keycode.BACKSPACE) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.BACKSPACE) + + + elif line == "enter": + if holdingKeys == 1: + + keysToPress.append(Keycode.ENTER) + + else: + + time.sleep(0.1) + + kbd.send(Keycode.ENTER) + + + print("KEYS_PRESSED: " + str(len(keysToPress))) + + if clearScr == 1 and workingLine.startswith("WAIT "): + lcd.clear() + + lcd.setCursor(0,1) + lcd.printout("> "+workingLine) + lcd.setCursor(0,0) + lcd.printout(lineToShow) + print(lineToShow) + + if lineToShow != "": + + lineToShow = "" + else: + lcd.clear() + + lcd.setCursor(0,1) + lcd.printout("> "+workingLine) + + + time.sleep(float(sleepingTime)) + time.sleep(0.5) + +while True: + + if not buttonOne.value: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Install Arch") + time.sleep(1) + + lcd.clear() + + macro_parser("archinstall.mcr") + + lcd.clear() + + elif not buttonTwo.value: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Macro Syntax") + time.sleep(1) + lcd.clear() + + macro_parser("syntax.mcr") + + lcd.clear() + + elif not buttonThree.value: + lcd.clear() + lcd.setCursor(0,0) + lcd.printout("Test Macro") + time.sleep(1) + lcd.clear() + + macro_parser("test.mcr") + + + lcd.clear() + + lcd.setCursor(0,0) + + lcd.printout("Kico v4") + + lcd.setCursor(0,1) + + lcd.printout("Hit a key!") + diff --git a/lib/adafruit_ahtx0.mpy b/lib/adafruit_ahtx0.mpy new file mode 100644 index 0000000000000000000000000000000000000000..6edfd11ecaf2a0d72b36ef76aa99d79bef2f0d5d GIT binary patch literal 1277 zcmZWoU2ocE6n$?!?!-v6$_uT+=3*t2g`b8l0uT(DArE=w7N!$=@ z^hgGHaR~FDmLSntY4(iU`TW9#xP~GZ%}S-%J!$L9of_lRH@zH z*IJr+2*5M|tf}t9At=>V?j4qfUC6DLY|1qSd5(o&@jRj!@?|!gNv2Z^h|Y$5Mn_e9 z33m}U>Gbp8mR(jPG+8~3?w&1UE8>-Q`+HVsu85k>llKxDaS70()~tw6vfDyHkM-0P z7ee1%vzg#dT>}wd(b$_R$To3#fI>ABEc0)uSW7PJ~t4`MG}sc?XF?xvH;RN{ImnJ8xC zh|XJ#pKP653_jW-@H__Yz*-u;sD{y1`V*Vp{$6PG!T5WDcB_6u2SNd-qs1)HAHL!L z_y$zjfs1S^^@)n5qpBEkQ{-tZwT&!hcI4qHg#YmXN{FZ+kpF<9(;jjbOCl?@U{9I3 zahXqg$c2;lIQa!9|7}XlxTncaFs@{3B~eUm$G+k|ag5HAt@y1gPO1M-(XlzQ6%9p4 zw!(CDXv;s*>>p`98_nHj7BAk~Llg&ZU&H^2IQa9m6$wKaC#}EZ^$XkKo}O{=9jSZUd~LAEuO6ttq+GxKJ9J+)p*-a^Q~r+SZI9B z(j0Q`V3gmgnx!&bX4}~?bo{Re`fn8%a*USA)(oF^DGF;b$edRDXnl!;`)Kf5{%U?! zk}%#T7DMS6r$Is(Tf{UlUM+Gc&RD8`&?R2tYAVOsl?}%+?YTnXf#z(ql)P#@ESx2& zaPur%3te@0y6Wazc9$j3F73g{G&lD05*>RnU{Pez*khU}mFHoI!8Z~U5RhPWCCA;J z0SRJvr&vbewNgW{tjur{Jo%@Gm*Bwn#Eq7NZAZ2oh8^}cL~kgp8k+vq9bvZToe4;p zpS_e~XM^Z0Ub&&^j#2EBAW{rU5H0pg6BwJ8p%C0OtX{QiDui~?VNitF1v)$V{RDK} zk$%<=M9>U~tf9+g<-i_i2TN5vDh3B$I{X+9!sM z!)B+%{pJcGanzI3w2X(?)8q=_4vYVYg@0V$<9l@dN~;O4VficFL71-o7hPB!_5=Mt zqOiyEtors9-LE8LL)4&BCY$*o3nzb*_4|jj%~6T_!xe_aT#xiTf1Y4=(m6tjW0W{S ziC<9SLwP^Y6D)cKVWL?#$5|1&))4#5SR5h(eUqMod7!Q!h{&nB(g7-vA7bcM@luFTh$7GNz7)2G!rT3@^baj5K;xL>_zv+URL5TiXr zjMn3DJqdi^S~Eb?eEuAo)upKdwkhQu~|xWyCfw$sa~VZrKWc#cm4t> C?oTWL literal 0 HcmV?d00001 diff --git a/lib/adafruit_bus_device/spi_device.mpy b/lib/adafruit_bus_device/spi_device.mpy new file mode 100644 index 0000000000000000000000000000000000000000..1d0812f7c29fbac6764c2b956a6bf91ab1784451 GIT binary patch literal 793 zcmYL{QBM;=5Xa|Q3R+rw?bY)_8)yJ&C{3#f4f3-^h*#wz^R~LK>PweNTP{PJo##jk8WFto6Kfz_CNERo81MUXC(0=o*spPf>Kd7 zOQV7Gbf4&HHgW|)Dap3kw?fRhK^8an&Tr3BX@sk z#v^honB%N`l~TjHlg%<#)mAfDf114*L3aLP77Ln**-VN}T4i+$w$-bWVM*;dDbB@S z$DGNLS65&9Aq>|1odJ9AdPjey!radAAS1@?n`R@nLetsCjL1+1TZzbWK zEA_McI&!7KV`d+jePZ_Bl|)?C3}lfS!SsVGgF5f{;0kgaMtDDhfjFge5UX=ypbxY~HF2 zGqQ_S$r=G7P-qh2c#qI9R;85^*erqS4|AB?EfGrKxm6aP#dZ8D!GVi~;V9dWNU+m4 zTe<#QKgjJX@u-RSNMBk==yuxjh4z2%Vt!tq*5_0ep*Tq~I0_M3uYp#v zkaim;Z2P{Xs%;W@$m{#JTuGt}K4TGGsMmK0^OJ4e4R`C8u)=PV!t`&b*C9WV#^@s#wj zb$X0eC&8y)SxKm~gHa^5_h;r9@0IiY%!e~m;i9Ui4T-88@15G>F*4lva@cKs7i4Ad zK)W_8VYy_!7J<{1C82!D<(uMjfy)&oPdgY#T6SKtjSYSx(qr5h;c`aFXu~2Y50wjX z5~N_tw^GJ#7zEg5*fY-$jTwHzjWNFYS;)jP2YA<&b4pIjiPASepFaEA{B~&DGH7Ud z(MH$Jg2Dw-S}NV3BNPk9=>^2>-#}}INymd?x?p+_aMxk3FGc|hqVU2&Z)c|U#-EMO fEIFiuJ;*|sPAzddfgc5S`5jhBi2M)-0%rT9-&Ds!)hb6jg{rqy#DIsZj%M4wW(XwzWuX<6XBz z2x$!zsa1cB!(ZXRk-x&GMu^MI?7o>dZ)OJN!j}1M_h}21zT-J3apH6P%=ezTVZf3( zjcpn5IGnYk#amM-qfT>fw)UHyi3eg_zrz-cARXa`KaXZ~P6O_6KMb&XPGcqm@%rnp zp(b>A(gXu0Iy~&5E~2uu!g!pxoS;-ACw}1B9zFM6x`XO~8i=6js18EY4(Nx32Dkqe zzKHzbv{96xBv2FfZY7nVz58$|JNzD&#B>kA@x(&f=HTxD(y#P)3j~c_gqZcI^V#&7 z8HC(qNfd=Kr=IBt=D?3#IsN{EpM`;GwLh9+Y|g?98mC8h8wlTQ_OJ9ye2GC$L4asQ z0vqEUbnqMq=oTVyZ57B`6jR2mB2i;HqYk5E7fR{yr-XGyY>RsreW+EJnvpQ)l-iLr zH`?0mBh^&y&uN(OAKmXLdt|P5pC2LLO%3{Ax)M2bsbj8*p6}mZ-KM zGw`y9rqcCbn&)l&V{=1~rn@hUvLarIss*(zqZT>td)p6qsFhxhGK|HtSDI${fk7CR m$H^OJxGYI?Iz4S|8(0@dqS6L&m|;b{$uLT#SvS`I&-??$`K_`5 literal 0 HcmV?d00001 diff --git a/lib/adafruit_hid/consumer_control_code.mpy b/lib/adafruit_hid/consumer_control_code.mpy new file mode 100644 index 0000000000000000000000000000000000000000..618edcabf0c692818004173ef8d3b000ce4f4d09 GIT binary patch literal 354 zcmZ{gu}i~16o)S@Vi1KW@)QRRHxws@TCMAOxoT>2iFcP)r)zC0M%0wp4sHoJ`bT>a zTXc{&ydU51d&{FMwF7tPY@yZeC>cHE^K_;k)8u%Zy}r#~Cb>3YmS@jqCzGS;`_L_H zq?*WS&>zF>N}#51)xf$LBkKbp&#HfJ6n4Y?XV50v0R&DR&>k+Eur3%4g@?-%*zFLh zbSD%8Qh`?04Sa6mDeOy1xaRCuX(b4~#^o6_zF8z#-w$KC;BBy_3L{*e!y4-{s&E;= zcGM$xIwG-TxV#5Dh?NOX;P%5_95C%MDpnFyX@stZ%Wg;*B9VrfEVcq7Ri?3OGgnh#>@1)K+U?FYc<~rMrt$ zp18!pa;*M<{)N8n+Bi}llQ@<7nmkyMs>*Sl|`4s&t?1ATy1KuE6B96PML%Yn$z!%aPwxd+HG2f@yx!Y+?c(($Sw^ZKl7V&ioUSo+IVc<6-IP z33-vdK=k9`W}$wfzsOohp-#2!pJiV5DkSYP)B69EXaWrn&N6R$75%tJvyF9pcK_<_ z*o>R}M1^cDFGRxOP$U$ItcSwD=Vsj_{wYf7Hu#_YMFkWL?+H02>8qst^!TLo>%)wd zq%V_)l${z3IT`*=B~gTO4*Rc8M{=I^D(Oi=#t8{5Vz->fPseaAW$cj^6(9yAFa>4lfivo@k@fh(FHnzINCz8enm3z-H!@F{&l QQqtchMi671lkt)H7cn=7od5s; literal 0 HcmV?d00001 diff --git a/lib/adafruit_hid/keyboard_layout_base.mpy b/lib/adafruit_hid/keyboard_layout_base.mpy new file mode 100644 index 0000000000000000000000000000000000000000..7ffdc066db50f8e46c2a98308207f05c1bad74fb GIT binary patch literal 1271 zcmbtTT~8uc7(NG<1(CJGhoeQ?PGm(u3rHz#OfOJJh1DV;W<#@^!vLd@9UU?Zx@2Sa zV6~}fe?%`f>BZg*pg*8%_YdseY%gq+{sGc|(0BN_>1{I??|HwT_jx~N-DLQT`#!qF zA#*|~3kOQ0s**~z9C{`;i?X1Ui6k`ThDwS;T@2Qm1&&%g;U|3BE24x4QO25U)Fd&0 zXKZS-Ry{tPHL^J0Vwmk=K6scBR^RvN0eWml-oN;JH2(;rrvOoxM6m{e7PWdL_JbH} zEVvx}l4S`w5tVvXJ|@J2ScVWqtjUDrBA9tNDzVdNxCR8H1{P;Z7}r-Ss#>eBghGc^ zwbCdCOY%`@)Lv+H)aQCtDM7#Krdojli6kF{@QYbX0#E+@aiQSl2H$*PKJJar(+8Kf zE9T03Ie$5U>}ZMwK1LR~=URw$?In_%IkLI4y46=#cXC_Vp(>2L>%08MT;Un02K#Hh4X2D+_M-`tG-D$rM;1 zWiNtQWKRe1-WQm)kyE9riWyxqu;^99$m$y?$z`z~xyOcyP?S%^<;d5iil7ixCPQb$ z#B$_6woD1#Pq-b(K11Vl47IgsKbR1@!snIO_|tI{-6<3vru@F(BI@uHRCAhK)|w*L z>zZ>ahVyOB`ALswDM&8S#_;dg^aF3Fpj>yM_+8A9 zUz4c=opz&G*ZEZ-i3j@rTg_#<`SG6{&FSeupabzYbFG&>oop|P0dY)6grMuRj>7@Y zS01Aa90)L3L zEW$rkkEdjA*dZsJ2vtcaN+Ne4E1bRqp# z_^0SOb@;sc96bI-|KkMGTy_}in-2YhAMiEkd_MxFZD0!W6y$*BBD#geOx^M0wCh6O zXwC)LM+ZcYpVBQ^c!Fwt*9#cHvu5dsb>P|UH)PS7{{Kc=(wuwINq?p0;F5m<4H#<9 z&+mBKa96;1zog&L9ZVHOd%r~cXJ~HaBJN2uy(z>Og1%Ain~noL)109w{=i${6vkm7 OCFrBGf7|V+jr|LgxqOEJ literal 0 HcmV?d00001 diff --git a/lib/adafruit_hid/keyboard_layout_us.mpy b/lib/adafruit_hid/keyboard_layout_us.mpy new file mode 100644 index 0000000000000000000000000000000000000000..7b3398c97002fdb745dab2ddc33b92b19814a973 GIT binary patch literal 330 zcmZ=}Ws+BD43LmuV0TGONlYs$%`Az}$V}1CPOVJJPb^A_&q=JzFD;2LE!HcjOi*ZG zFX)@j&?und4VCu+OFJbNr)n`uYoO~&0*cEpi!nxq7%>Papy~+?7GySI7GoA<6q7-f z2~1{StYHvg=Ir5b5K>?eWDpl)5EEb)V~|p25L0jrcJ}m)5Al!pc8zrQcX16&W@Jce zWPkxJZ4DR`Mr(o?I`g(HSh#43$+G23*O}>>Td2#)D<~={tEj4NHr}SUeaHNk*0%PJ z&aUpB-oE|`6DLicGIiSY88c_io-b`DN1ZXRAfegQ!tVG&U=aS2H& NX&Kq|8#iqA0RU^>U9SKD literal 0 HcmV?d00001 diff --git a/lib/adafruit_hid/keycode.mpy b/lib/adafruit_hid/keycode.mpy new file mode 100644 index 0000000000000000000000000000000000000000..8a5c6318459ce9f7cb95c397ca4b4d3f7c6178e2 GIT binary patch literal 1729 zcmb7_S#ujj5XV-mCqU~Z$o zvAz4^;8OR@p#R9(t;@Zg{?^=u%j-qTXhBKKPqs$6vVhc5PfOj%XRc*Z6Ibq`sfUXH z`>E`|;&4)F>>Vop>!}>7{5^BHm^_up8`)8I?2mPn-QVsvXD_$s?YDYeo6_zD4e}G9 z&AtRee;Gve6%fX&AZo9HkgtQNzX780CWz)05awGTPQDGI^$rN@Dv0*GAnf-*IPZgS zKLD}xAqejp2>&Ax!N(xNPe3ex3ZnBFh?UPltX>DPb_3FmEpI|P=r~_MHfVZMehHbn z6MA2H<0z^vb4X2tTY?V;5*3JrY*mR%$oF^A2@3V(wj;_&XYmt**`)~ z`iAbxpP*3Hjh64~hWweg(W}2eK8mWknxBpQUm@Ez?a=>?mo0_5<^K*dmaGTes>h3E zfJb1~Q~M@~`M9p7`%NrC)^$R=h6_;eW!p3y%dxQx*`?44Brd{C!_${#S2qlPPdo}) z!)dp5JO(*edZtsu<1kxyypHbGx_(sh1Qhu7{jTL0EqoO2s?XzNY)kk!+XZ}rZ5f|r zyNFM*J&IIeIfkUO97n3MoIo-lU7tUKR8u;SB$bws>M-MarX6&BgF9{`H2~OkENiqQ zHTg(-=u0FMa;EJ|FF-m8nWod`Tni>$y&=1yi)2BrCN0V5q&B1_cY$muM8h?w!=)X7 zQSWrmb2>;aOh>(q!zGwj^SW{9K|XZHfe-h!2Ov(kR_G(GBoiWlkXB(jp1@opttBA?igYTO9+8UlbW%?ti}cK1 z%50d?Rfpu>u{b2eab?jL4xr6yr<;dPEOx0qCx4 znT8&ij3R9-LOYV*@N`mOL^{$L#l!;AKxrB2Ii-t8XO%Ko=ae#8=an*A&nsoNc34Zy z)&-@^)(c9RtzD&D@1oK&4*87H_ck0mV8Zy)O~x(`H)0n2rdbc7>!=(YZbE*Mw-Pq^1A> literal 0 HcmV?d00001 diff --git a/lib/adafruit_hid/mouse.mpy b/lib/adafruit_hid/mouse.mpy new file mode 100644 index 0000000000000000000000000000000000000000..4eb453279f86e6a7162d4c157a484759db47157c GIT binary patch literal 834 zcmY*W%TF3X9G*cGL4{pdr}AhZXq1An4H9}qMT=Hz5yXnUMSThJXJo(cruy0qc@UyATwx7DCYS*-W77#51jzIAcEOV z2W6qS?dqXT5_g(w(xys@;L;G-V8Qs0sGg*kAb5}r0>-qW4hrcIjOPG66qyJdc*aG> zJlcsI4>#GS5l5QVr{hfnV8Imx5YvNzLq=$Mej&-vt|ybLcN%D9ZShv@GCe|$mBnau zd0uNjL1=bn?zWb_K(2+=wT+pzs8)#kVPYB}zy={Ql`B}1f;wcbU=e2}9PB|z3;C=l z2KC646NTJELWsX7G2M&$3#DBg>_ZM-!c?JRiB}6Oco{T=AR6RFp&(T0e*JRn8yo?w zlX!`7FOvb*(H6tir0h24%hbq>sgpDqb5$tdQmxt!J%-ANgYr?8H0iA%aulM~!3r*y zDk?7k$L8+0NCp}BxvMO>NrnPIu^Gv|_14e(DTNyjgR}Lx|1;ceCn0!zZDxRr_Q<&Y^2V$=rE<&>>TQ-+ud5R z_0oZ@(~EcQvy1m9=NBJZ? yAgAb7bc|}%5f;wUK(#+D`umr|(?|(BfMMQ1P`7m5%M3ed%7VIUg&F}YnWj#IY>A&bY&=c zRZU#GI(BVzcyvOQKO7&5Um2EJ*1~C{keMy9Y+f%EZ49f!IiqO8d@!TwbUTmnEtvgz zqhRM|OQ#M9+y}{FWpa2lF*VWWVY}lAd5A_o0f8jn<`ruY7$wbktV=oDp0nPIMzgw| zD^B;OjeN9Th3HVd90}b_Ls`a3b`Daki}Zrel@9J$J2`e!MD9KJ?%%KX(g>l4fFAdd zlQs0Ke_roaQRh0_=JkBtLry&K-#?E6=(qs2@(8FcnRFta@pDK(0VTqWpJN2Ss%EjR zs!%IfT6C$Tk*6&Fw8)4k;3b!(ApAm+a0o4KRpdsp>in^_T%BKTExWBkPP4#|me1nQ z;A)IONl8*J1Sf*GF9eg}o^V!*i)e{&p^cQm zxAin0X+s;8machIx3OyHZ~>Y{%jgB$aQOg)#`=w-t>Qw)VOhPPS~L=8;BLc|a^o{) z)7c`AU7nZUB`)uECZT^`kr%R;u%|ZTEp+5MY6i0KD#ko6Z;>aUxmqLc$Tdon%Qpd3 zr92@|DZ$yTQ-rEYl|sQP>8Y}=q7-?0aRhZ12BXj;9qFAJw1+T?t7uzLFTy7K$avX88n_r84dEY6WfbnhjP z%Dda~Msn|&v&}_Y1j{yyXj7BdBB+d+z)@dG>0FI zW#gxN$b(at&-MpHJtL9R*{i3OE~RTc5*8QUkEFU0hi)y$nDPs`nQ-WQrzgf>fL#7a zjB)lz{3!W&gX@R>Yl-RdHX`yw?afUb>YvehUks<-Y^)Hi2{;-{=tqd*9`<&F8^PF0m>K6Di zP)k!KwN`#E^KUJF@S$Idnh64gu-MR!JOs*}ay#LC)St5E;RU#ScsIsKWbiMzlS+9v z6>lY+monfgy~!MCF+(~FlWCAVcIw& J&X_fN>0gIl`5piO literal 0 HcmV?d00001 diff --git a/lib/adafruit_register/i2c_bcd_datetime.mpy b/lib/adafruit_register/i2c_bcd_datetime.mpy new file mode 100644 index 0000000000000000000000000000000000000000..161a81bbe7f82e19e095a2c220ddbd7abb0ed654 GIT binary patch literal 938 zcmX|9ZBN=z6uyPA;xq^?c8D|Lm}p1_Ss}QW4>-}dEc+n7u$Z`9OM8*dKuLSi@QGFd zr&+T9VD_Fw#Ox?XSP#};KTTkP>f+02n{F9 z%gB9->=qM70oGiOFTVP;u#Pyi@*~aIp^0L>R3duU<{7haz2-GdJM`j&kRwHEV69XF zidBzk*&*h}4uyvY29_Y~WFw6J+yrAMx=IPAWl{wTB}J`L&E|O! z?e}SQib++m{C>5H2g0mO%e9x^|HjP+1%v8!nPSInE^71R=essPbH00~S8O z_jCY)7eIrwZS%8zfY{amVj((nD$Yg~r%rl0N-Za~MrjKgdQN|P_txg8`)Q`xjE`j) z$I6SRTJgIN9@?mpb~+o0&YE9S$z-&UPNtR+w|LD@&kU8J>+(zx{kC~`hH)+zek<5#4qg2RRv9NP literal 0 HcmV?d00001 diff --git a/lib/adafruit_register/i2c_bit.mpy b/lib/adafruit_register/i2c_bit.mpy new file mode 100644 index 0000000000000000000000000000000000000000..d097614a34f9a7ee312c9f27e74785c926192834 GIT binary patch literal 649 zcmYjO(QXn!6uq;AQjm~km))+|q$I7iZOjt4q(My-fut`c6-rT4%?RuOqn0JRLo08) zwGUPM6^$RT1z&vj5Bvh-57gAe_~>jAV=|N6b2ImxbI+8*!a~NYX=#Y$8)l~7+>S3_JtCGq|p@xfQ4> zzMKrG6_1~QYgA6TmrTkNPNjU?trw+9BOElsU%&6x$0_*8%MBDLPa;s@^bJUh@=4x} c{r@)xs0x39%GVMo?3O@+Ob*CoCIY8_0R9}qA^-pY literal 0 HcmV?d00001 diff --git a/lib/adafruit_register/i2c_bits.mpy b/lib/adafruit_register/i2c_bits.mpy new file mode 100644 index 0000000000000000000000000000000000000000..1d865a8ccc0aa88830c70cc76945b6441e2d8a34 GIT binary patch literal 904 zcmZva-%b-j6vk(|!Gbif-NmJ}Bs3_rfVNsTh{QysL@qE&0r7u^ZFgu_VVCSoK@17I z3IPJ~A&3vKg~9`9@d5PG8>7Yx6SWEt;4BJqVX~W?nap?2?|kPZD?CkMdo&OP-X29& zCd|A>k%_Y!q1cRTi400>l*Fdz#(S-*R=hR<_>&i6mtx(LgwPB&iDu{sodyz*m~7fW zXfy$N-|+1|CX+o998GxG@uqw9b22A!sSNaxD>+K1Nl!eU)o3oCj%AFg_+k0@)kBV? zW@Z@A&>YRND#L%NVoYP-;e%ZDx@gs|iK{&DgL;V}a1sdG!$a-dNGFhhKh+LLI-yj9 zP!>~!5*{}sZkWmd?s?_ACD;i3UaMp9T(sqEqy^Z8vc0!eb^<(W8ciwWu_HpexUye< z-(P77;Noeo4Dpr|sGBrqF`=$E0_e4izhvkHeChne1U5IB#v0pp0>UIoqY2FeML$XsCfZZHczM}>rv8-G6}{iw8Hu#UuD7*;f>`GcR>d<~1`h#e%hSyQ7J(Hz#<7!_61so{wAtQEe-$Ww%M)#iCkM}#USwYwHQcT*1@S|tI@3xK&) zAwzr5T9CP2NAxGXmcX0X-43j7%W!ua4c3A;#g#I9xO3}Usqgzj(Gi<|IAX)k(m~W; zWfh;XYWrVG#SCDkoG{XlYS>Tbrt#AFGT+`3vaUs<-K>lAtv90m9UT$CoUZ=#svw32 zUbsDk98q+ELpJ+d!vEuik~|ybynVpU$x!wj=Y#+F8s2^^6*oVWgb?ci4T`LTW_y7_ zSL}=xS3Z~ezAkLlftRdg7j)fVOU1w&z{V3GwAHWQvwX+*G6AFp_5${YYG8$x1p)}m K0RPc=!NzatoGV8F literal 0 HcmV?d00001 diff --git a/lib/adafruit_register/i2c_struct.mpy b/lib/adafruit_register/i2c_struct.mpy new file mode 100644 index 0000000000000000000000000000000000000000..c9bc8776dc21ad52a7507d0e07a23dfb973a4012 GIT binary patch literal 888 zcmZ{hZ*S5-9LImxia0i)v|T}#DG6c2#lXbM)Flox<9wvDvCSnjXIG9<6-wG;6Cbt2 zC(HIKmc4*7de!ctt`P_PlyPN6XPh}wdOsi`Rt7}kfkwe3# z#3~vk9oy9E>a@`5eW*B7uNKJZ-02-~s&g~J4+RO42Zbkv$BKgS5wUE;Y-5}SMZip_ zV`5w@Az@}~q@r>Ps+BlF*=}oAZ*s;9>CHD2(*&>b3SZR`Z?82e?buI?#Y2NOy9Wi` zY!$~*i_gcI*9}W&+28hPlLgqkZct!%+{&$VD1J8UL`cP`Kmw8qOUEmaE`b7x>Jr*| zh?E${hlFBW;{2`cZ>u`+Ze>-3MA*sXR^ZZ0K~02;D@wAUYoB%7_)0tpYGw3GMP6#= zpxbB=Yv4)9*?c@X2WI1&k5 zp~jru%dHiDZy?>?i2C{9!jt$i@=b%faX9yBFGkOn8STtT_&u9DUt}>r=UaE`Btf>E@({gfBGRY*xkeu~rL-(?LV^lig8^FbIvT_2> hzkqlze)igl{L|Jih+fRaP{`S1E*TX_P$~@Pe*hs}_G$nC literal 0 HcmV?d00001 diff --git a/lib/adafruit_register/i2c_struct_array.mpy b/lib/adafruit_register/i2c_struct_array.mpy new file mode 100644 index 0000000000000000000000000000000000000000..0df98b3ac9aa3983959a93b71652c1ae09f1974e GIT binary patch literal 880 zcmZva;ZD;~6vt0H28@l-b+s%w17VCziJR0i(U=I#2-znmQ!>HamG+KRS-Z4%m}yK} zq92U-62=GUHl9Fy13#Gf7{mwgwv3n<`=M#>IsKpi{r^rW%+Aiahg=%Q%8I5mtd35Q zg%5O_V5^`@Dzb^yQ3+BkOX=p@-TImn*;>S(mcXf8ja?K)hMQQ<-_5UzB0@*lvUSry zC<7vgs8-uVs46ksJlZfjhPEB(t^0B^D>7Ay<-~u^Dk{U;51NFu?R$m7fliv8{k&?n z3YQKG>z7tbx}{RfkGrHvXFeGk&(nY0Cd`K>Pp&u-T>lWobzFx8OpDZ1NQ4;)L`X;s zHGF^x+V38Fg7-Pe{q< zjXAe+ODo_BksfWQT}i=5so^7C#hU`04TQzlmQFAtO>9s`il!UH?Dx62*&zrUn#*yz zLD?%7af|QST4nDApA^K7(N@$~s9~8c-%H;uhK7S(f&@q>oMLWyi4IQC!DsxKzz6-l zxZgi;``dRyH7`k@%?bE^D!|u4k@3|pf`dKyvKonl5OwZ@A4Z_=E{uz_p_4U-`wzs* z4QBf`BgRoc5>Xx2&3PBpDn2y|462k-e2BuQSkBOfD)s24xL~u9uF3h<@q3>B9kwY~ecIa7HW`i3f L<8(ntw~hY*LUsch literal 0 HcmV?d00001 diff --git a/lib/keyboard_layout_win_uk.mpy b/lib/keyboard_layout_win_uk.mpy new file mode 100644 index 0000000000000000000000000000000000000000..3889e63053f840e71c8fbb2d5f1648a405377998 GIT binary patch literal 545 zcmZ=}Ws+BDjF1pvU^mK6txU>KEJ}&bNvzB-Er~DB%!@D0)+?xVNGMQEWoQsk@rJ7K z0V{AyEKb#8ly*u?NlYs$%`Az}$V|~gHzWzDNQPOAF;ba9Oe{XWEVZaOGe0jrUYSu$ zAU?h*wIDw}KE#MgKnB%pL3R^nG3LNzCdOi313d#hL*2xjf{a8xgJRo^l9GaAD}DX+ z%#w`KB)#PPTz$XPqQsQ^WPRt%qGX^$3Mxx7fOf!4jE6Y4SP!V9*+4*xk-LXip|w#} zNnK491k^nl1R2D|7{mma#TcZ3?o@CLcJ}m)5Al!pc8zrQcX0(eR>aTM)g|81C&WES zhf}FhL8(zWX`xcXL7k)yrN+#p8A^>+Nj*x9xk;0h8jF)!lo}J0lp0Ny8g-JCfTUWI zn1qL?yN7E~JlJd<1~DmTe_tn0KcJyNOM-zuWk_mdfB`LS4Hy$fYl0X$^X3~aT(rbw z+4809%yi8y)aB$A6qS@!RMj>cZ`0epV@peGTYE=mS9ecuU;l)OlO|7@I&J!lnX_ik znX7MTuz0O03o9Et2PYRd4=*3TfS{1Dh^Uyjgrt#@D{dUw4?+@!$9UOSD+VPiX> z{5F<2OUr$g`=&sF_TTAWfy6(+n_b5UD&~jxy*IP(n>X{m(JJ?oM@|kC$tmeL-Dw^A zoo35>slD$V>}0x!tDCEHE$Ng5;CU~$di{21-}6pIAnAF%R=4AM&JsyZl*6aHa&;#99rS0(Zhig z0sbcq*TtAiqZ6!SQb9T)JqQvc?*nP(Wgzk^Kyt4FQC z*MVGo3rP8GAlf@XD(?c(-veU255)WcNcBS?)<;0>kAXO!0C8^sS^E@7?K2>kJ_oY? z1&|FoY(P}j9Lg&YWqO{Thhv3B`UKh~`Xt(AdI4>gK81FLK8^M?<*Nv1D3=k=Ql3LN zN4Wyg!r}tud4Y?RGl5H#Zwp+eye%+G`SSu-DBlr?WV-^9ZBHQ5?F&S{4&oB>bp;~d z3j&d^ClLAi0<(1JL$v6sUqaN-*>@1N)l0uZ)RA*vp{*I;Lad;!v2PFz*P{F)#7ahm z{RlB#)!9!F+hCSKhg%TGTPRxeG{hC7QjvdvI8%!y=O&`=FzYvnS5)1#=?cURR`IaV z62wi}wHaN6c-1u=_C3UHw#IZitfN;_3(hS>Q&!m55O+!zW0bc5WYg4CMRrs}r@RTN zoUD{>O}0zFjC_$n&p}F&P21B9r7R9P5tM};8g2?-cPvArT!TcOY0N?9Doo{#n(oP# zWz>F$1gpBTX8(+ijYN!|g_(k3)nqI01-sEKOcyPAjd`-7;29}bA))Fvv(R$Km^Lj{cRX7`LFqRkVKK+GP;^_6vV>&A3Jri! zBubwTQp1d}PF@7SEe%ZzCAkbKn^jcB&onV2?N-lgvPx# literal 0 HcmV?d00001 diff --git a/lib/lcd/__init__.py b/lib/lcd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/lcd/i2c_pcf8574_interface.py b/lib/lcd/i2c_pcf8574_interface.py new file mode 100644 index 0000000..08e3a22 --- /dev/null +++ b/lib/lcd/i2c_pcf8574_interface.py @@ -0,0 +1,95 @@ +# Copyright (C) 2017 Dan Halbert +# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Low-level interface to PCF8574.""" + +import busio +import board +import microcontroller +from adafruit_bus_device.i2c_device import I2CDevice + +from .lcd import LCD_4BITMODE, LCD_BACKLIGHT, LCD_NOBACKLIGHT, PIN_ENABLE + + +class I2CPCF8574Interface: + + # Bit values to turn backlight on/off. Indexed by a boolean. + _BACKLIGHT_VALUES = (LCD_NOBACKLIGHT, LCD_BACKLIGHT) + + def __init__(self, i2c, address): + """ + CharLCD via PCF8574 I2C port expander. + + Pin mapping:: + + 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + D7 | D6 | D5 | D4 | BL | EN | RW | RS + + :param address: The I2C address of your LCD. + """ + self.address = address + + self._backlight_pin_state = LCD_BACKLIGHT + + self.i2c = i2c + self.i2c_device = I2CDevice(self.i2c, self.address) + self.data_buffer = bytearray(1) + + def deinit(self): + self.i2c.deinit() + + @property + def data_bus_mode(self): + return LCD_4BITMODE + + @property + def backlight(self): + return self._backlight_pin_state == LCD_BACKLIGHT + + @backlight.setter + def backlight(self, value): + self._backlight_pin_state = self._BACKLIGHT_VALUES[value] + with self.i2c_device: + self._i2c_write(self._backlight_pin_state) + + # Low level commands + + def send(self, value, rs_mode): + """Send the specified value to the display in 4-bit nibbles. + The rs_mode is either ``_RS_DATA`` or ``_RS_INSTRUCTION``.""" + self._write4bits(rs_mode | (value & 0xF0) | self._backlight_pin_state) + self._write4bits(rs_mode | ((value << 4) & 0xF0) | self._backlight_pin_state) + + def _write4bits(self, value): + """Pulse the `enable` flag to process value.""" + with self.i2c_device: + self._i2c_write(value & ~PIN_ENABLE) + # This 1us delay is probably unnecessary, given the time needed + # to execute the statements. + microcontroller.delay_us(1) + self._i2c_write(value | PIN_ENABLE) + microcontroller.delay_us(1) + self._i2c_write(value & ~PIN_ENABLE) + # Wait for command to complete. + microcontroller.delay_us(100) + + def _i2c_write(self, value): + self.data_buffer[0] = value + self.i2c_device.write(self.data_buffer) diff --git a/lib/lcd/lcd.py b/lib/lcd/lcd.py new file mode 100644 index 0000000..4788841 --- /dev/null +++ b/lib/lcd/lcd.py @@ -0,0 +1,289 @@ +# Copyright (C) 2017 Dan Halbert +# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time +from micropython import const + +# Commands +_LCD_CLEARDISPLAY = const(0x01) +_LCD_RETURNHOME = const(0x02) +_LCD_ENTRYMODESET = const(0x04) +_LCD_DISPLAYCONTROL = const(0x08) +_LCD_CURSORSHIFT = const(0x10) +_LCD_FUNCTIONSET = const(0x20) +_LCD_SETCGRAMADDR = const(0x40) +_LCD_SETDDRAMADDR = const(0x80) + +# Flags for display entry mode +_LCD_ENTRYRIGHT = const(0x00) +_LCD_ENTRYLEFT = const(0x02) +_LCD_ENTRYSHIFTINCREMENT = const(0x01) +_LCD_ENTRYSHIFTDECREMENT = const(0x00) + +# Flags for display on/off control +_LCD_DISPLAYON = const(0x04) +_LCD_DISPLAYOFF = const(0x00) +_LCD_CURSORON = const(0x02) +_LCD_CURSOROFF = const(0x00) +_LCD_BLINKON = const(0x01) +_LCD_BLINKOFF = const(0x00) + +# Flags for display/cursor shift +_LCD_DISPLAYMOVE = const(0x08) +_LCD_CURSORMOVE = const(0x00) +_LCD_MOVERIGHT = const(0x04) +_LCD_MOVELEFT = const(0x00) + +# Flags for function set +_LCD_8BITMODE = const(0x10) +LCD_4BITMODE = const(0x00) +_LCD_2LINE = const(0x08) +_LCD_1LINE = const(0x00) +_LCD_5x10DOTS = const(0x04) +_LCD_5x8DOTS = const(0x00) + +# Flags for backlight control +LCD_BACKLIGHT = const(0x08) +LCD_NOBACKLIGHT = const(0x00) + +# Flags for RS pin modes +_RS_INSTRUCTION = const(0x00) +_RS_DATA = const(0x01) + +# Pin bitmasks +PIN_ENABLE = const(0x4) +PIN_READ_WRITE = const(0x2) +PIN_REGISTER_SELECT = const(0x1) + +class CursorMode: + HIDE = const(_LCD_CURSOROFF | _LCD_BLINKOFF) + LINE = const(_LCD_CURSORON | _LCD_BLINKOFF) + BLINK = const(_LCD_CURSOROFF | _LCD_BLINKON) + +MICROSECOND = 1e-6 +MILLISECOND = 1e-3 + +class LCD(object): + + def __init__(self, interface, num_cols=20, num_rows=4, char_height=8): + """ + Character LCD controller. + + :param interface: Communication interface, such as I2CInterface + :param num_rows: Number of display rows (usually 1, 2 or 4). Default: 4. + :param num_cols: Number of columns per row (usually 16 or 20). Default 20. + :param char_height: Some 1 line displays allow a font height of 10px. + Allowed: 8 or 10. Default: 8. + """ + self.interface = interface + + if char_height not in (8, 10): + raise ValueError('The ``char_height`` argument should be either 8 or 10.') + self.char_height = char_height + + self.num_rows = num_rows + self.num_cols = num_cols + + # get row addresses (varies based on display size) + self._row_offsets = (0x00, 0x40, self.num_cols, 0x40 + self.num_cols) + + # Setup initial display configuration + displayfunction = self.interface.data_bus_mode | _LCD_5x8DOTS + if self.num_rows == 1: + displayfunction |= _LCD_1LINE + elif self.num_rows in (2, 4): + # LCD only uses two lines on 4 row displays + displayfunction |= _LCD_2LINE + if self.char_height == 10: + # For some 1 line displays you can select a 10px font. + displayfunction |= _LCD_5x10DOTS + + # Choose 4 or 8 bit mode + self.command(0x03) + time.sleep(4.5*MILLISECOND) + self.command(0x03) + time.sleep(4.5*MILLISECOND) + self.command(0x03) + if self.interface.data_bus_mode == LCD_4BITMODE: + # Hitachi manual page 46 + time.sleep(100*MICROSECOND) + self.command(0x02) + elif self.interface.data_bus_mode == _LCD_8BITMODE: + # Hitachi manual page 45 + self.command(0x30) + time.sleep(4.5*MILLISECOND) + self.command(0x30) + time.sleep(100*MICROSECOND) + self.command(0x30) + else: + raise ValueError('Invalid data bus mode: {}'.format(self.interface.data_bus_mode)) + + # Write configuration to display + self.command(_LCD_FUNCTIONSET | displayfunction) + time.sleep(50*MICROSECOND) + + # Configure entry mode. Define internal fields. + self.command(_LCD_ENTRYMODESET | _LCD_ENTRYLEFT) + time.sleep(50*MICROSECOND) + + # Configure display mode. Define internal fields. + self._display_mode = _LCD_DISPLAYON + self._cursor_mode = CursorMode.HIDE + self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode) + time.sleep(50*MICROSECOND) + + self.clear() + + def close(self): + self.interface.deinit() + + def set_backlight(self, value): + self.interface.backlight = value + + def set_display_enabled(self, value): + self._display_mode = _LCD_DISPLAYON if value else _LCD_DISPLAYOFF + self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode) + time.sleep(50*MICROSECOND) + + def set_cursor_mode(self, value): + self._cursor_mode = value + self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode) + time.sleep(50*MICROSECOND) + + def cursor_pos(self): + """The cursor position as a 2-tuple (row, col).""" + return (self._row, self._col) + + def set_cursor_pos(self, row, col): + if not (0 <= row < self.num_rows): + raise ValueError('row should be in range 0-{}'.format(self.num_rows - 1)) + if not (0 <= col < self.num_cols): + raise ValueError('col should be in range 0-{}'.format(self.num_cols - 1)) + self._row = row + self._col = col + self.command(_LCD_SETDDRAMADDR | self._row_offsets[row] + col) + time.sleep(50*MICROSECOND) + + def print(self, string): + """ + Write the specified unicode string to the display. + A newline ('\n') will advance to the left side of the next row. + Lines that are too long automatically continue on next line. + + Only characters with an ``ord()`` value between 0 and 255 are currently + supported. + + """ + for char in string: + if char == '\n': + # Advance to next row, at left side. Wrap around to top row if at bottom. + self.set_cursor_pos((self._row + 1) % self.num_rows, 0) + else: + self.write(ord(char)) + + + def clear(self): + """Overwrite display with blank characters and reset cursor position.""" + self.command(_LCD_CLEARDISPLAY) + time.sleep(2*MILLISECOND) + self.home() + + def home(self): + """Set cursor to initial position and reset any shifting.""" + self.command(_LCD_RETURNHOME) + self._row = 0 + self._col = 0 + time.sleep(2*MILLISECOND) + + def shift_display(self, amount): + """Shift the display. Use negative amounts to shift left and positive + amounts to shift right.""" + if amount == 0: + return + direction = _LCD_MOVERIGHT if amount > 0 else _LCD_MOVELEFT + for i in range(abs(amount)): + self.command(_LCD_CURSORSHIFT | _LCD_DISPLAYMOVE | direction) + time.sleep(50*MICROSECOND) + + def create_char(self, location, bitmap): + """Create a new character. + + The HD44780 supports up to 8 custom characters (location 0-7). + + :param location: The place in memory where the character is stored. + Values need to be integers between 0 and 7. + :type location: int + :param bitmap: The bitmap containing the character. This should be a + bytearray of 8 numbers, each representing a 5 pixel row. + :type bitmap: bytearray + :raises AssertionError: Raised when an invalid location is passed in or + when bitmap has an incorrect size. + + Example: + + .. sourcecode:: python + + >>> smiley = bytearray( + ... 0b00000, + ... 0b01010, + ... 0b01010, + ... 0b00000, + ... 0b10001, + ... 0b10001, + ... 0b01110, + ... 0b00000, + ... ) + >>> lcd.create_char(0, smiley) + + """ + if not (0 <= location <= 7): + raise ValueError('Only locations 0-7 are valid.') + if len(bitmap) != 8: + raise ValueError('Bitmap should have exactly 8 rows.') + + # Store previous position + save_row = self._row + save_col = self._col + + # Write character to CGRAM + self.command(_LCD_SETCGRAMADDR | location << 3) + for row in bitmap: + self.interface.send(row, _RS_DATA) + + # Restore cursor pos + self.set_cursor_pos(save_row, save_col) + + def command(self, value): + """Send a raw command to the LCD.""" + self.interface.send(value, _RS_INSTRUCTION) + + def write(self, value): + """Write a raw character byte to the LCD.""" + self.interface.send(value, _RS_DATA) + if self._col < self.num_cols - 1: + # Char was placed on current line. No need to reposition cursor. + self._col += 1 + else: + # At end of line: go to left side next row. Wrap around to first row if on last row. + self._row = (self._row + 1) % self.num_rows + self._col = 0 + + self.set_cursor_pos(self._row, self._col) + diff --git a/lib/rgb1602/__init__.py b/lib/rgb1602/__init__.py new file mode 100644 index 0000000..04f7efa --- /dev/null +++ b/lib/rgb1602/__init__.py @@ -0,0 +1 @@ +from rgb1602.display import Screen diff --git a/lib/rgb1602/colours.py b/lib/rgb1602/colours.py new file mode 100644 index 0000000..498181c --- /dev/null +++ b/lib/rgb1602/colours.py @@ -0,0 +1,164 @@ +CSS_COLOURS: dict[str, tuple[int, int, int]] = { + "aliceblue": (240, 248, 255), + "antiquewhite": (250, 235, 215), + "aqua": (0, 255, 255), + "aquamarine": (127, 255, 212), + "azure": (240, 255, 255), + "beige": (245, 245, 220), + "bisque": (255, 228, 196), + "black": (0, 0, 0), + "blanchedalmond": (255, 235, 205), + "blue": (0, 0, 255), + "blueviolet": (138, 43, 226), + "brown": (165, 42, 42), + "burlywood": (222, 184, 135), + "cadetblue": (95, 158, 160), + "chartreuse": (127, 255, 0), + "chocolate": (210, 105, 30), + "coral": (255, 127, 80), + "cornflowerblue": (100, 149, 237), + "cornsilk": (255, 248, 220), + "crimson": (220, 20, 60), + "cyan": (0, 255, 255), + "darkblue": (0, 0, 139), + "darkcyan": (0, 139, 139), + "darkgoldenrod": (184, 134, 11), + "darkgray": (169, 169, 169), + "darkgreen": (0, 100, 0), + "darkgrey": (169, 169, 169), + "darkkhaki": (189, 183, 107), + "darkmagenta": (139, 0, 139), + "darkolivegreen": (85, 107, 47), + "darkorange": (255, 140, 0), + "darkorchid": (153, 50, 204), + "darkred": (139, 0, 0), + "darksalmon": (233, 150, 122), + "darkseagreen": (143, 188, 143), + "darkslateblue": (72, 61, 139), + "darkslategray": (47, 79, 79), + "darkslategrey": (47, 79, 79), + "darkturquoise": (0, 206, 209), + "darkviolet": (148, 0, 211), + "deeppink": (255, 20, 147), + "deepskyblue": (0, 191, 255), + "dimgray": (105, 105, 105), + "dimgrey": (105, 105, 105), + "dodgerblue": (30, 144, 255), + "firebrick": (178, 34, 34), + "floralwhite": (255, 250, 240), + "forestgreen": (34, 139, 34), + "fuchsia": (255, 0, 255), + "gainsboro": (220, 220, 220), + "ghostwhite": (248, 248, 255), + "gold": (255, 215, 0), + "goldenrod": (218, 165, 32), + "gray": (128, 128, 128), + "green": (0, 128, 0), + "greenyellow": (173, 255, 47), + "grey": (128, 128, 128), + "honeydew": (240, 255, 240), + "hotpink": (255, 105, 180), + "indianred": (205, 92, 92), + "indigo": (75, 0, 130), + "ivory": (255, 255, 240), + "khaki": (240, 230, 140), + "lavender": (230, 230, 250), + "lavenderblush": (255, 240, 245), + "lawngreen": (124, 252, 0), + "lemonchiffon": (255, 250, 205), + "lightblue": (173, 216, 230), + "lightcoral": (240, 128, 128), + "lightcyan": (224, 255, 255), + "lightgoldenrodyellow": (250, 250, 210), + "lightgray": (211, 211, 211), + "lightgreen": (144, 238, 144), + "lightgrey": (211, 211, 211), + "lightpink": (255, 182, 193), + "lightsalmon": (255, 160, 122), + "lightseagreen": (32, 178, 170), + "lightskyblue": (135, 206, 250), + "lightslategray": (119, 136, 153), + "lightslategrey": (119, 136, 153), + "lightsteelblue": (176, 196, 222), + "lightyellow": (255, 255, 224), + "lime": (0, 255, 0), + "limegreen": (50, 205, 50), + "linen": (250, 240, 230), + "magenta": (255, 0, 255), + "maroon": (128, 0, 0), + "mediumaquamarine": (102, 205, 170), + "mediumblue": (0, 0, 205), + "mediumorchid": (186, 85, 211), + "mediumpurple": (147, 112, 219), + "mediumseagreen": (60, 179, 113), + "mediumslateblue": (123, 104, 238), + "mediumspringgreen": (0, 250, 154), + "mediumturquoise": (72, 209, 204), + "mediumvioletred": (199, 21, 133), + "midnightblue": (25, 25, 112), + "mintcream": (245, 255, 250), + "mistyrose": (255, 228, 225), + "moccasin": (255, 228, 181), + "navajowhite": (255, 222, 173), + "navy": (0, 0, 128), + "oldlace": (253, 245, 230), + "olive": (128, 128, 0), + "olivedrab": (107, 142, 35), + "orange": (255, 165, 0), + "orangered": (255, 69, 0), + "orchid": (218, 112, 214), + "palegoldenrod": (238, 232, 170), + "palegreen": (152, 251, 152), + "paleturquoise": (175, 238, 238), + "palevioletred": (219, 112, 147), + "papayawhip": (255, 239, 213), + "peachpuff": (255, 218, 185), + "peru": (205, 133, 63), + "pink": (255, 192, 203), + "plum": (221, 160, 221), + "powderblue": (176, 224, 230), + "purple": (128, 0, 128), + "rebeccapurple": (102, 51, 153), + "red": (255, 0, 0), + "rosybrown": (188, 143, 143), + "royalblue": (65, 105, 225), + "saddlebrown": (139, 69, 19), + "salmon": (250, 128, 114), + "sandybrown": (244, 164, 96), + "seagreen": (46, 139, 87), + "seashell": (255, 245, 238), + "sienna": (160, 82, 45), + "silver": (192, 192, 192), + "skyblue": (135, 206, 235), + "slateblue": (106, 90, 205), + "slategray": (112, 128, 144), + "slategrey": (112, 128, 144), + "snow": (255, 250, 250), + "springgreen": (0, 255, 127), + "steelblue": (70, 130, 180), + "tan": (210, 180, 140), + "teal": (0, 128, 128), + "thistle": (216, 191, 216), + "tomato": (255, 99, 71), + "turquoise": (64, 224, 208), + "violet": (238, 130, 238), + "wheat": (245, 222, 179), + "white": (255, 255, 255), + "whitesmoke": (245, 245, 245), + "yellow": (255, 255, 0), + "yellowgreen": (154, 205, 50), +} +CSS_COLORS = CSS_COLOURS + +WAVESHARE_COLOURS = { + "Deep violet": (148, 0, 110), + "Purple": (255, 0, 255), + "Blue and white": (144, 249, 15), + "Light blue": (0, 128, 60), + "Yellow": (255, 209, 0), + "Ghost white": (248, 248, 60), + "Dark blue": (80, 80, 145), + "Red": (255, 0, 0), + "Cyan": (0, 255, 0), +} +WAVESHARE_COLORS = WAVESHARE_COLOURS diff --git a/lib/rgb1602/display.py b/lib/rgb1602/display.py new file mode 100644 index 0000000..78985cc --- /dev/null +++ b/lib/rgb1602/display.py @@ -0,0 +1,307 @@ +# This file converted from MicroPython to CircuitPython +# by robjwells. Original copyright Waveshare. + +from time import sleep + +from adafruit_bus_device.i2c_device import I2CDevice +from adafruit_register.i2c_struct import UnaryStruct +from busio import I2C +from microcontroller import Pin + +from rgb1602.colours import CSS_COLOURS + + +class Constants: + # Device I2C Addresses + LCD_ADDRESS = 0x7C >> 1 + RGB_ADDRESS = 0x3e >> 1 + + # fmt: off + # CGRAM and DDRAM commands but also their memory addresses + LCD_COMMAND_REG = 0x80 + LCD_SETDDRAMADDR = 0x80 # 0b1_______ Display Data RAM + LCD_SETCGRAMADDR = 0x40 # 0b_1______ Character Generator RAM + LCD_DATA_REG = 0x40 + + # RGB registers + REG_RED = 0x04 # 0b_1__ pwm2 + REG_GREEN = 0x03 # 0b__11 pwm1 + REG_BLUE = 0x02 # 0b__1_ pwm0 + + REG_MODE1 = 0x00 # 0b____ + REG_MODE2 = 0x01 # 0b___1 + REG_OUTPUT = 0x08 # 0b1___ + + # Commands -- bits of an 8-bit word + LCD_CLEARDISPLAY = 0x01 # 0b_______1 + LCD_RETURNHOME = 0x02 # 0b______1_ + + LCD_ENTRYMODESET = 0x04 # 0b_____1__ + # Used with bits I/D SH: + # I/D: 0x02 for entry left, 0x00 for entry right + # SH: 0x01 for shift increment, 0x00 for decrement + # See "flags for display entry mode" + + LCD_DISPLAYCONTROL = 0x08 # 0b____1___ + # Used with bits DCB: + # D: display on/off, + # C: cursor on/off, + # B: blink cursor on/off + # These are listed below as "flags for display on/off control" + + LCD_CURSORSHIFT = 0x10 # 0b___1____ + # Cursor or Display Shift + # Uses bits S/C R/L - -: + # S/C: 0x08 for screen or 0x00 for cursor + # R/L: 0x04 for right or 0x00 for left + + LCD_FUNCTIONSET = 0x20 # 0b__1_____ + # Sets number of display lines, and display font type. + # The documentation doesn't mention 8/4 bit mode. + + # flags for display entry mode + LCD_ENTRYRIGHT = 0x00 # 0b00 + LCD_ENTRYLEFT = 0x02 # 0b10 + LCD_ENTRYSHIFTINCREMENT = 0x01 # 0b01 + LCD_ENTRYSHIFTDECREMENT = 0x00 # 0b00 + + # flags for display on/off control + LCD_DISPLAYON = 0x04 # 0b1__ + LCD_CURSORON = 0x02 # 0b_1_ + LCD_BLINKON = 0x01 # 0b__1 + + LCD_DISPLAYOFF = 0x00 # 0b000 + LCD_CURSOROFF = 0x00 # 0b000 + LCD_BLINKOFF = 0x00 # 0b000 + + # flags for display/cursor shift + LCD_DISPLAYMOVE = 0x08 # 0b1000 + LCD_CURSORMOVE = 0x00 # 0b0000 + LCD_MOVERIGHT = 0x04 # 0b0100 + LCD_MOVELEFT = 0x00 # 0b0000 + + # flags for function set + + # I think the modes relate the to the number of bits + # sent down the wire at a time, _not_ the colour + # depth (as I thought originally). + LCD_8BITMODE = 0x10 # 0b10000 + LCD_4BITMODE = 0x00 # 0b00000 + + # Number of lines on the display + LCD_2LINE = 0x08 # 0b01000 + LCD_1LINE = 0x00 # 0b00000 + LCD_5x8DOTS = 0x00 # 0b00000 + + # fmt: on + + +class LCDControl: + def __init__(self, i2c: I2CDevice): + self.i2c_device = i2c # Required by UnaryStruct + + command_register = UnaryStruct(Constants.LCD_COMMAND_REG, " None: + self.i2c_device = i2c + + REG_RED = UnaryStruct(Constants.REG_RED, " 0x20 (DMBLNK to 1, ie blinky mode) + self._set_rgb_register("REG_MODE2", 0x20) + self.set_white() + + def _command(self, cmd: int): + assert 0 <= cmd <= 255, f"Command {cmd} out of range." + self._lcd.command_register = cmd + + def _write_byte(self, data: int) -> None: + assert 0 <= data <= 255, f"Command {data} out of range." + self._lcd.data_register = data + + def _set_rgb_register(self, reg: str, data: int) -> None: + assert reg in ( + "REG_RED", + "REG_BLUE", + "REG_GREEN", + "REG_MODE1", + "REG_MODE2", + "REG_OUTPUT", + ), f"Register {reg} is not a known register." + assert 0 <= data <= 255, f"Data {data} is out of range." + setattr(self._rgb, reg, data) + + def _set_rgb_mode(self, mode: int, value: int) -> None: + assert 0 <= value <= 0xFF, "Value not in range." + if mode == 1: + self._set_rgb_register("REG_MODE1", value) + elif mode == 2: + self._set_rgb_register("REG_MODE2", value) + else: + raise ValueError(f"Unknown mode: {repr(mode)}") + + def set_rgb(self, r: int, g: int, b: int): + assert 0 <= r <= 255, f"Red value {r} out of range." + assert 0 <= g <= 255, f"Green value {g} out of range." + assert 0 <= b <= 255, f"Blue value {b} out of range." + + self._set_rgb_register("REG_RED", r) + self._set_rgb_register("REG_GREEN", g) + self._set_rgb_register("REG_BLUE", b) + self.current_colour = (r, g, b) + + def position_cursor(self, *, col: int, row: int): + assert ( + 0 <= col < self.COLS + ), f"Column {col} is out of bounds (max {self.COLS - 1})." + assert ( + 0 <= row < self.ROWS + ), f"Row {row} is out of bounds (max {self.ROWS - 1})." + + if row == 0: + col |= 0x80 + else: + col |= 0xC0 + + assert self._i2c.try_lock(), "Could not lock" + self._i2c.writeto( + Constants.LCD_ADDRESS, bytearray([Constants.LCD_SETDDRAMADDR, col]) + ) + self._i2c.unlock() + + def clear(self): + self._command(Constants.LCD_CLEARDISPLAY) + sleep(0.002) + + def write_bytes(self, arg: bytes): + for byte in arg: + self._write_byte(byte) + + def write_at_position(self, text: str | bytes, *, col: int, row: int) -> None: + self.position_cursor(col=col, row=row) + self.write_bytes(self._ensure_bytes(text)) + + @staticmethod + def _ensure_bytes(s: str | bytes) -> bytes: + if isinstance(s, bytes): + return s + # Not JIS X 0213 but close enough if you’re careful. + return bytes(s, "jisx0213") + + def update( + self, first_line: str | bytes, second_line: str | bytes | None = None + ) -> None: + first = self._ensure_bytes(first_line) + self.clear() + self.write_bytes(first[: self.COLS]) + if second_line is not None: + self.position_cursor(col=0, row=1) + second = self._ensure_bytes(second_line) + self.write_bytes(second[: self.COLS]) + + def set_white(self) -> None: + self.set_css_colour("white") + + def set_css_colour(self, colour_name: str) -> None: + self.set_rgb(*CSS_COLOURS[colour_name]) + + def set_css_color(self, color_name: str) -> None: + self.set_css_colour(color_name) + + def set_backlight_power(self, on: bool) -> None: + data = 0xFF if on else 0x00 + self._set_rgb_register("REG_OUTPUT", data) + + @staticmethod + def special_char(c: str) -> bytes: + if c == "\\": + raise ValueError("\\ (backslash) is not in the character set.") + elif ord(c) < ord("}"): + # Everything matches ASCII up to }, except for \ -> ¥. + return c.encode("ascii") + + chars = { + "→": b"\x7E", + "←": b"\x7F", + "•": b"\xA5", + "☐": b"\xDB", + "°": b"\xDF", + "alpha": b"\xE0", + "beta": b"\xE2", + "epsilon": b"\xE3", + "mu": b"\xE4", + "sigma": b"\xE5", + "rho": b"\xE6", + "√": b"\xE8", + "theta": b"\xF2", + "omega": b"\xF4", + "SIGMA": b"\xF6", + "pi": b"\xF7", + "÷": b"\xFD", + "block": b"\xFF", + } + + try: + return chars[c] + except KeyError: + raise ValueError(f"Character {repr(c)} is not a registered special character.") diff --git a/lib/rgb1602/examples.py b/lib/rgb1602/examples.py new file mode 100644 index 0000000..c281df1 --- /dev/null +++ b/lib/rgb1602/examples.py @@ -0,0 +1,45 @@ +from time import sleep + +from rgb1602.colours import CSS_COLOURS, WAVESHARE_COLOURS +from rgb1602.display import Screen + + +def _show_colours( + screen: Screen, + delay: int, + colours: dict[str, tuple[int, int, int]], + colour_set_name: str, +) -> None: + original_rgb = screen.current_colour + for colour_name, rgb in sorted(colours.items()): + screen.set_rgb(*rgb) + screen.update(colour_set_name, colour_name) + sleep(delay) + screen.set_rgb(*original_rgb) + + +def show_css_colours(screen: Screen, delay: int = 2) -> None: + _show_colours(screen, delay, CSS_COLOURS, "CSS named colour") + + +def show_waveshare_colours(screen: Screen, delay: int = 2) -> None: + _show_colours(screen, delay, WAVESHARE_COLOURS, "Waveshare") + + +def show_discoloration_sample(screen: Screen) -> None: + from math import sin + + screen.update(f"Waveshare", "Hello, world!") + t = 0 + while True: + r = int((abs(sin(3.14 * t / 180))) * 255) + g = int((abs(sin(3.14 * (t + 60) / 180))) * 255) + b = int((abs(sin(3.14 * (t + 120) / 180))) * 255) + t = (t + 3) % 360 + + screen.set_rgb(r, g, b) + screen.write_at_position( + str(t).encode() + screen.special_char("°") + b" ", col=10, row=0 + ) + + sleep(0.3) diff --git a/lib/waveshare_lcd1602.py b/lib/waveshare_lcd1602.py new file mode 100644 index 0000000..6b97667 --- /dev/null +++ b/lib/waveshare_lcd1602.py @@ -0,0 +1,234 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) Waveshare +# SPDX-FileCopyrightText: Copyright (c) 2022 Neradoc +# +# SPDX-License-Identifier: MIT +# +# In order to keep basic compatibility with the orifinal library, ignore "bad" names. +# pylint: disable=invalid-name +""" +`waveshare_lcd1602` +================================================================================ + +Drive for Waveshare's I2C character display LCD1602. +A port of Waveshare's RGB1602 Micropython library. + +* Author(s): Neradoc + +Implementation Notes +-------------------- + +**Hardware:** + +* `Waveshare LCD1602 RGB Module `_ + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://circuitpython.org/downloads +* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice +""" + +import time +from adafruit_bus_device.i2c_device import I2CDevice + +try: + from typing import Union + import busio +except ImportError: + pass + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/Neradoc/Circuitpython_Waveshare_LCD1602.git" + +# Device I2C Arress +LCD_ADDRESS = 0x7C >> 1 +RGB_ADDRESS = 0xC0 >> 1 + +# color define + +REG_RED = 0x04 +REG_GREEN = 0x03 +REG_BLUE = 0x02 +REG_MODE1 = 0x00 +REG_MODE2 = 0x01 +REG_OUTPUT = 0x08 +LCD_CLEARDISPLAY = 0x01 +LCD_RETURNHOME = 0x02 +LCD_ENTRYMODESET = 0x04 +LCD_DISPLAYCONTROL = 0x08 +LCD_CURSORSHIFT = 0x10 +LCD_FUNCTIONSET = 0x20 +LCD_SETCGRAMADDR = 0x40 +LCD_SETDDRAMADDR = 0x80 + +# flags for display entry mode +LCD_ENTRYRIGHT = 0x00 +LCD_ENTRYLEFT = 0x02 +LCD_ENTRYSHIFTINCREMENT = 0x01 +LCD_ENTRYSHIFTDECREMENT = 0x00 + +# flags for display on/off control +LCD_DISPLAYON = 0x04 +LCD_DISPLAYOFF = 0x00 +LCD_CURSORON = 0x02 +LCD_CURSOROFF = 0x00 +LCD_BLINKON = 0x01 +LCD_BLINKOFF = 0x00 + +# flags for display/cursor shift +LCD_DISPLAYMOVE = 0x08 +LCD_CURSORMOVE = 0x00 +LCD_MOVERIGHT = 0x04 +LCD_MOVELEFT = 0x00 + +# flags for function set +LCD_8BITMODE = 0x10 +LCD_4BITMODE = 0x00 +LCD_2LINE = 0x08 +LCD_1LINE = 0x00 +LCD_5X8DOTS = 0x00 + + +class LCD1602: + """ + Setup a new RGB LCD1602 display + + :param busio.I2C i2c: I2C bus object to use. + :param int columns: The number of columns on the display. + :param int rows: The number of rows on the display. + """ + + def __init__(self, i2c: busio.I2C, columns: int, rows: int): + self.lcd_device = I2CDevice(i2c, LCD_ADDRESS) + #self.rgb_device = I2CDevice(i2c, RGB_ADDRESS) + self._row = rows + self._col = columns + + self._showfunction = LCD_4BITMODE | LCD_1LINE | LCD_5X8DOTS + self.begin(self._row, self._col) + + def command(self, cmd: int): + """ + Send a command. + + :param int cmd: The command code. + """ + with self.lcd_device: + self.lcd_device.write(bytes([0x80]) + chr(cmd)) + + def write(self, data: int): + """ + Write a data byte. + + :param int data: The data byte to write. + """ + with self.lcd_device: + self.lcd_device.write(bytes([0x40]) + chr(data)) + + def setReg(self, reg, data): + """ + Set the value of a register. + + :param int reg: The register to write to. + :param int data: The data byte to write. + """ + #with self.rgb_device: + # self.rgb_device.write(bytes([reg]) + chr(data)) + + def setRGB(self, r, g, b): + """ + Set the color of the RGB backlight. + + :param int r: Red byte. + :param int g: Green byte. + :param int b: Blue byte. + """ + self.setReg(REG_RED, r) + self.setReg(REG_GREEN, g) + self.setReg(REG_BLUE, b) + + def setCursor(self, col, row): + """ + Place the cursor on the display. + + :param int col: The column. + :param int row: The row. + """ + if row == 0: + col |= 0x80 + else: + col |= 0xC0 + with self.lcd_device: + self.lcd_device.write(bytearray([0x80, col])) + + def clear(self): + """Clear the display.""" + self.command(LCD_CLEARDISPLAY) + time.sleep(0.002) + + def printout(self, arg: Union[str, int]): + """ + Print a string to the display. Ints are converted to strings. + + :param str|int arg: The string or int to printout. + """ + if isinstance(arg, int): + arg = str(arg) + + for x in bytearray(arg, "utf-8"): + self.write(x) + + def display(self): + """Turn on the display.""" + self._showcontrol |= LCD_DISPLAYON + self.command(LCD_DISPLAYCONTROL | self._showcontrol) + + def begin(self, columns: int, rows: int): # pylint: disable=unused-argument + """ + Initial configuration, called from init. + + :param int columns: The number of columns on the display. + :param int rows: The number of rows on the display. + """ + if rows > 1: + self._showfunction |= LCD_2LINE + + self._numlines = rows + self._currline = 0 + + time.sleep(0.05) + + # Send function set command sequence + self.command(LCD_FUNCTIONSET | self._showfunction) + # delayMicroseconds(4500); # wait more than 4.1ms + time.sleep(0.005) + # second try + self.command(LCD_FUNCTIONSET | self._showfunction) + # delayMicroseconds(150); + time.sleep(0.005) + # third go + self.command(LCD_FUNCTIONSET | self._showfunction) + # finally, set # lines, font size, etc. + self.command(LCD_FUNCTIONSET | self._showfunction) + # turn the display on with no cursor or blinking default + self._showcontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF + self.display() + # clear it off + self.clear() + # Initialize to default text direction (for romance languages) + self._showmode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT + # set the entry mode + self.command(LCD_ENTRYMODESET | self._showmode) + # backlight init + self.setReg(REG_MODE1, 0) + # set LEDs controllable by both PWM and GRPPWM registers + self.setReg(REG_OUTPUT, 0xFF) + # set MODE2 values + # 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode) + self.setReg(REG_MODE2, 0x20) + self.setColorWhite() + + def setColorWhite(self): + """Set the color of the RGB backlight to white.""" + self.setRGB(255, 255, 255) diff --git a/macros/archinstall.mcr b/macros/archinstall.mcr new file mode 100644 index 0000000..be5bdc5 --- /dev/null +++ b/macros/archinstall.mcr @@ -0,0 +1,194 @@ +# First Boot + +"loadkeys uk" +WAIT 1 +enter +WAIT 1 +"archinstall" +WAIT 1 +enter +WAIT 10 + + +# Locales + +downarrow +enter +WAIT 1 +enter +forwardslash +"uk" +enter +WAIT 1 +downarrow +enter +forwardslash +"en_gb." +downarrow +enter +WAIT 1 +downarrow +downarrow +enter + +# Mirrors + +downarrow +enter +enter +forwardslash +"kin" +enter +WAIT 5 +downarrow +downarrow +downarrow +downarrow +enter +WAIT 1 + +# Partitions + +# EXT4 Main Drive + +downarrow +enter +enter +enter +space +enter +downarrow +enter + +# Encryption + +downarrow +downarrow +enter +enter +enter +downarrow +enter +LCD_SHOW "Password? (5s)" +WAIT 5 +enter +LCD_SHOW "Password? (5s)" +WAIT 5 +enter +downarrow +enter +space +enter +downarrow +downarrow +enter +downarrow +enter + +# Bootloader + +downarrow +downarrow +enter +WAIT 1 + +# Pick GRUB + +forwardslash +"grub" +enter + + +# Hostname +downarrow +enter +WAIT 1 + +# Clear out pre-filled hostname + +backspace +backspace +backspace +backspace +backspace +backspace +backspace +backspace +backspace +backspace + +# Entering new hostname + +LCD_SHOW "Hostname? (5s)" +WAIT 5 +enter + +# Users + +downarrow +downarrow +enter +enter + +# Prompt for username + password + +LCD_SHOW "Username? (5s)" +WAIT 5 +enter +LCD_SHOW "Password? (5s)" +WAIT 5 +enter +LCD_SHOW "Password? (5s)" +WAIT 5 +enter +enter +downarrow +downarrow +enter + +# Profile + +downarrow +enter +enter +forwardslash +"Min" +enter +WAIT 1 +downarrow +enter + +# Audio servers + +downarrow +enter +downarrow +downarrow +enter + +# Networking + +downarrow +downarrow +enter +enter + +# Time and Date + +downarrow +downarrow +enter +forwardslash +"london" +enter +WAIT 1 +downarrow +enter +enter + +# Install + +downarrow +downarrow +enter +enter \ No newline at end of file diff --git a/macros/syntax.mcr b/macros/syntax.mcr new file mode 100644 index 0000000..e69de29 diff --git a/macros/test.mcr b/macros/test.mcr new file mode 100644 index 0000000..b6d7cca --- /dev/null +++ b/macros/test.mcr @@ -0,0 +1,59 @@ +LCD_SHOW "Hi" + +# test comment + +WAIT 3 + +HOLD + +super + +"d" + +RELEASE + +"text editor" + +enter + +HOLD + +ctrl + +"n" + +RELEASE + +tab + +forwardslash + +space + +backslash + +HOLD + +shift + +"a" + +RELEASE + +enter + +capslock + +"caps" + +capslock + +enter + +"lowercase" + +backspace + +enter + +"sentence longer than 16 chars..." diff --git a/settings.toml b/settings.toml new file mode 100644 index 0000000..e69de29