From 4f64ed554a8208bc07d0c589e74fc3d5d7ade583 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Sat, 25 Nov 2017 01:14:04 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 + fs/mongoose-os.jpg | Bin 0 -> 10155 bytes include/widget.h | 44 + libs/ili9341/README.md | 3 + libs/ili9341/include/tft.h | 683 ++++++++ libs/ili9341/include/tftspi.h | 211 +++ libs/ili9341/mos.yml | 28 + libs/ili9341/src/DefaultFont.c | 333 ++++ libs/ili9341/src/DejaVuSans18.c | 322 ++++ libs/ili9341/src/DejaVuSans24.c | 331 ++++ libs/ili9341/src/SmallFont.c | 120 ++ libs/ili9341/src/Ubuntu16.c | 331 ++++ libs/ili9341/src/comic24.c | 331 ++++ libs/ili9341/src/def_small.c | 332 ++++ libs/ili9341/src/ili9341.c | 2826 ++++++++++++++++++++++++++++++ libs/ili9341/src/minya24.c | 331 ++++ libs/ili9341/src/tftspi.c | 648 +++++++ libs/ili9341/src/tooney32.c | 331 ++++ libs/lobo-spi/LICENSE | 201 +++ libs/lobo-spi/README.md | 3 + libs/lobo-spi/include/lobo_spi.h | 361 ++++ libs/lobo-spi/mos.yml | 24 + libs/lobo-spi/src/lobo_spi.c | 1175 +++++++++++++ libs/stmpe610/include/stmpe610.h | 135 ++ libs/stmpe610/mos.yml | 26 + libs/stmpe610/src/stmpe610.c | 263 +++ mos.yml | 46 + src/main.c | 61 + src/widget.c | 89 + src/widget_name.c | 80 + src/widget_network.c | 64 + src/widget_time.c | 40 + src/widget_topbar.c | 33 + src/widget_wifi.c | 65 + 34 files changed, 9873 insertions(+) create mode 100644 .gitignore create mode 100755 fs/mongoose-os.jpg create mode 100644 include/widget.h create mode 100644 libs/ili9341/README.md create mode 100644 libs/ili9341/include/tft.h create mode 100644 libs/ili9341/include/tftspi.h create mode 100644 libs/ili9341/mos.yml create mode 100644 libs/ili9341/src/DefaultFont.c create mode 100644 libs/ili9341/src/DejaVuSans18.c create mode 100644 libs/ili9341/src/DejaVuSans24.c create mode 100644 libs/ili9341/src/SmallFont.c create mode 100644 libs/ili9341/src/Ubuntu16.c create mode 100644 libs/ili9341/src/comic24.c create mode 100644 libs/ili9341/src/def_small.c create mode 100644 libs/ili9341/src/ili9341.c create mode 100644 libs/ili9341/src/minya24.c create mode 100644 libs/ili9341/src/tftspi.c create mode 100644 libs/ili9341/src/tooney32.c create mode 100644 libs/lobo-spi/LICENSE create mode 100644 libs/lobo-spi/README.md create mode 100755 libs/lobo-spi/include/lobo_spi.h create mode 100755 libs/lobo-spi/mos.yml create mode 100755 libs/lobo-spi/src/lobo_spi.c create mode 100644 libs/stmpe610/include/stmpe610.h create mode 100644 libs/stmpe610/mos.yml create mode 100644 libs/stmpe610/src/stmpe610.c create mode 100644 mos.yml create mode 100644 src/main.c create mode 100644 src/widget.c create mode 100644 src/widget_name.c create mode 100644 src/widget_network.c create mode 100644 src/widget_time.c create mode 100644 src/widget_topbar.c create mode 100644 src/widget_wifi.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..350abb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +deps/ diff --git a/fs/mongoose-os.jpg b/fs/mongoose-os.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b613a1caf64b15e7bdb28aaff6a035ec02946627 GIT binary patch literal 10155 zcmeHscTiK`w{H+I^j>Tb6%YXdX@UsE@&yD0q<8W~K}rOqccLIgs#2Bu1q7rtqZ`* z0_bA^Ffv>PoZ)3)D?RazVr3H&K6n0t#5Kw5 zQqsyQw^Y?`t3UWlTSxbyp1zs6g{76XjqOusmuIeS?jC;r0f9lmA)(Q)V`Agt-z21^ zXJlq&zyFX^T=KEBto&0&Wqm^_>OUHGFZUZLZA6yJ)g6Pc1%fx&|;Vj=h6QGk1 z|5e3TECTo671edKiYb}m1)uniu?dMQVHW6|2tq&|1D(y3)p|)!T>lJ8R*7i zcBDHMH%ZYl0lV zajmsAM1Nl@&uqTU|?2orS*gm?4?l4YlN8@=ON#ey-XQ%Sxa{6?OKM@}1=LyBtzPa#=x7vG+ye-`&6`N1cY>v2IzK+1X0IN7vOQ^2T;jZ;f8^Kz0mbj%Np7l z#ee*9(YhdE*|koESgM~g)>@xdU4A+Gi^^g1E^w%7;zc=^p1(V4uuTbfFv_nqFYBU? zi1-*fpa)$aZ>2W69`15!3!aqF08Du_KvY9*lk!q5SU}}6vQV}uu6DkYiITM#2=1S? zKUxpz2A56|n|#u7it`V8al$3*GXWGg*uxhz0FRSW($#(^Q012JEH%F;;X3@r@tFka znq8!8*`n>-yaQ%#9-?62_A%39_Z-LDmw9!Jd0dm?i#@&umbS$SRcDc|0hRXF{UK0^ zqvEPjulgzjHsr#MmZ9kAC|$MUub0y15!z0{Gyo13OBGmO!iZj*X@qhASaU0U+-4B` zz+2K_4uH-%aak0_Z5ts550{m<9-z5|30Vud5i`xebvIb3gtN z@hq)k+df+rT1A=5R}nNe*%vA-S)847gxFx_J-D7A65O*?TV5zyFx-Bc@y?nFtNlV_85ZFH@a+%PCW@_Qh64qawLO zVED}7hTcvQ_m*T8&igV!KAVE^;$g3>E+}QRT+NNBsmOe!efSPt)QHgqPpyMH8D{JH{L$MUg?)v|R8Hb;CdJ@}esy4+&WMT%r5XvaRtd$Vt8?LDH3g_{e&ot1IJM%*Q+Xmz3s*Ww$7@N zv}4BYb-0V99|C_&7nE1pxwVGR1ZDHs+RjykJj=Ov$>-CiO)4NP=fi!IY#CdEoXVB! zzx&JD4oQRSwcOo>2v9F9zCetM{vIBJ6@i#9G}_vFd>&RR)P6kc-K(--sAzY8{NeB= zpQx{2UsM834K4Ilq&jWixt~<=>hkJWhg9h41sQ_B1PHFRy6(8+Q8xPuW1d=9h;l3D z+^du<%_nEyB9HGb3=#yVgB#GTpqDjQn`cyNB(nrN_Or&Cn(^XVOZhgdB(m#|J#T;ZFmc54JodY!DuJdso>F->6xy ztku)%va&Ey_lr$849zjCVM{o~M5bW11-VKq?A9@KefVj6LZ8RlxMW6s^f+t47YyJ! zy11TvvA&Jdz!W*wcv8FjD*-b-%TYfp!~AfPBTF0)5ZT(N0jO+n8i3iNnevay#nCt# zfO}5@iMObFzqhv{0kM4%%7x>B?bUWD=#mBP=zhhAKEnW=I;=| z5l{3Sv9&-A9t|aMaWB&VPR|2xhmi*4%X5Ekw}$SJk8#5B#(b+;E@_m-i8PX<0jXmN zVmKr-j(SD|%yQ#|cU)^0tck+C6CO)WfCc;ZMCO{>P~f|G2lS=ugM?2oH`J^FdZ|A3 z&EMnX04yn46xuKEc{3nqahNte1K@?sqoBa>fGl1R^f>k{MakffRdYdik#8R z=*Zj|aUF&^q~0k`Af(QwQdvp+286Z=IRy7vH-(W>8)UWwWoHO8r$htz*t9%5WlT8= zPO`Y9p;;4h9o-hF6Rg1{CT#Jzr~8|6u_3B!Kjul&c|A+Bx4IsbM|7V==WgrR4$)jZ z3Kv*P%`5V3)bv`V0alj%?LvOg0KzVQGev7mRKM^LNA;myZMsi)1ZgQ}+X{ zG($yS7;m^lGUhoGliGOj#F+I{l?9kBXetlfcka;&OI@(;W@|qIHr;WiQ!WCooVal7T zU_bB%c#iR>HE(EU=I5ciq>raonRMmK!mx7VF!!ZYD+tf7AlXDC^jXoTm?xGKUsG(D z#57Axg&9+`I%t3a&}Yf0a95JGJ4DE<_(Oo9*5wInIjzA6|LEtcrt%?Trd^`sP^*H- z;agIbu9k(NW-&C5}0_#I2pz6KLnSockG7!)tBJJZQPtlbom>|bP_^0Mu@n0mr(%(jmQq2gtOC10sWFp5wtSaoD9!n${bOEpH zc)LLvnA_X;W$I0?PW$)s+>?QDDaxntvxV&8ek3vCGgUsxIP$%-d6!_IOlPy86(l&> zfzm=fzXfS1?5l!dE_U7WwV!v#v&&y}=kcHRpLqFNJeIMI#Or2T*HW8|9-8dS-A4;=SD zDpVh145{S=wRsmu>~4bYyN#AtWEr|5T|hsKdm=C31>s3r;_d`dHR2nbweaKVfaFk> z_JfZZXAhp(Fj%iViUBZ8;Nk3)50M;;)NvXBuOl1Qdn( z_e`eH%${@E^rpHmVXV`u;#TJAd1r+fi46LRkT-EJ zX#nS?*N$rYL9xmpt_}C6Pp_4S31xdk5viVQ!C0}SZuYMVb)#Q6_Ms9RE#y%~1JhV+_{RlCBaOY-lf^~bubzH^3 z&4f=SA}c#$S~e=hhO-XtVYlrn)*uLEuZSvvg;+|DH%TCF&nx&}=@rnxQ&6IRn8ZPK z0DD+0rXl13Tm6-_%Up{m6U5PS)t!D)@F2e2ytx??i{d;?jDR{!;69W%_!7d;Ic0mX zCY!vPD|j&lA`6HOSi%s%K5oWvc6@%H`nQ?@xE<8-YM3P-y2N_!7S6?~r$O{gL1^ei zyEfb|5)HzeIT-X6hzESe8xI%?P4|e{nl&vBn<5y5q^$96-<|nwYTA^!I*ikYs;u$aKjCv$^Un63Nl2%%G2?}?s8}uj zEgC@3KVN^iOH2K`rzj0zIMbLL)09RCxR@qvamSVKmM|0lZ!2Ds*`^uUj~GD`TMS+? zKtfabgA;lp9EWfkIy(}%O0j0&`TU|MRHk0VX@&+j8yN}bG$MS$liM^4Yg0%yDIDV^ z<*#dARv57rn=dTaoY%!@%Tzh49|l==o)LEv`;!{vE-C^1cilqS>(7mazb4VVJ!gy4ivZlWES5D0g)=NpRqpZa0F8k~_ z9EEpE7w7GkO3CkepET^=6mU=v%n%cfC_?^3oG?e4(GBJaTmGjtwrb_hXmlrkN7{_R z#QjvB`TIm@OZ)=idFt|G9qfEwAbcu;>K-W-+_Z&8@saP_|>+u{Y2wzdYafJ;2O;uDW>YAeYG%1K55fUlm$-&R`? zGT$1N)z67^$Bl<+&%(F!SF_f4B@wknYDIXC;_o)+tYKMGlaHe zxl!QH5Jlr~-;i&2EWOEsKq^~rMR@qWz#p=@sVbuid0>hoxFnCL@AKR!uu{@UP*(@_#f+ekDP(>>rogC^ZbDV;ZS67*=lnSy+@P`>W9(*KY-Yv-X*5ZtWd88EYck@ zd?$>ax}YP(V{(IX-!&I$vaVeUEQ=giLM-*>!seR1UoQ#~RX+wl5mDJa9Om>`R3NNE z1D@>MoO@d<=9E9nl(eRDKzEf}R5r#Hc?@vn7re+0;@~EF0UueU8Izx%KP;aw?)B9D zql=i|EiT~Q>wP$-OQSbSbuv}-mB%YWY^^%R$G{Hq0UZP(ZeaS)7K?E0(AvgLr2hAI z*`XCFnZZyfRHYQ*>OikjeD)=3k;&zpI}6dtc~PJ&-xu`cG#QpNKk zjo$-dGrdKxG@7iYq(Y_m=UcyVBPZVE&SUZnjx*5R%{p;x>HFGVEYv= zi}&kwWZyrI*DxvF@Uew1O40LCxoO>JZ3nMd-|CsXG+sD^RH+F?_l7>t&PiUaEp%o1 znm#{NrxU&K{-sPZ{&+_ZKhvKxN(ju}XY9_2Iq@uBNDh7PqE`7$V{lOwv4@yCokf)Uf>R*%sNN-v{^Ej$C)QKdK5Z22+Wb~INQeg5 z)sJz|{j64rVuU?iibXX9EcDMrhf9=g2+tTaLFe0#P34QSbX?J&)!_P;^NP1ci<71z zf_N&zm~Z9qUduQY^n2w`u0ni;jr%dV(rf z9PZ1xAJo9Zf+na8{vJ-HruylrO2ir{VH&ejR%YB|9Nl@I$iMu9tcjJq#wn~FYjZ7S zTx!Oy8-Ji@J7Q{Uu;op!%+4I;C;`UQ-U26zT$h#YB+m_kKq zD3lQ+yc2RiT;cd_|862Y#h^(sGzU$bBk_@CDa8TJN5;azV53Qd+jkxL6?a*$gp`Ew zzlOeQzRx+*mqLrgTST;0$VDCpk&XrG=fywWP_EFOg*ObfL~dDQsjQJB1jR1l*FP3k>VL(jvi(V@w9XP$ z`=(D3g}oG&-Rhrwb2XE{7w$1KzO|Hcc>9!s+0#;w91#UlN|imq#`{gtTrIAp_7Roi zss+~JZ*FDIb389Ey4uz%UHbk>sfwkA^QuUpQtM&R_iqIzugdk!ujsJxEnKexTR_1d zmRrGOezE1qS5=s$S)!<#_l;);@!}Wqu?k<3&f9&c>jwOGJkk~{5EFK6Gisl&LCnEE z)C$Y@V9l&Od}5AQ^&r!O%&B8!`cjB0KvYvB@v@1OKC#9tUma}bP+rR(m z-8aK!+^Qocs71~^bq&-_FVaprsdr6Pz4Vi^R1^N29x~`DP*jCOM9c2s^BIT*;(Ah+};sH{#JyGV?%{biq9! z)BQW#xXs}Ha8Ag_pEk13EnIScwT^7D942i1-kA%kT}s~9<#WQTx%Qrb+Vs`U3vGs7 z;a(JihEbTQP+^xaQvWvd$%eR3=0AhTna;xF{qHFfM8Hr{Sc7h~?iaP5-o zK(@sCg9A^U18CwKQ956+arVo4_ap7AafNtJN&>EHHP~K+TEk_x*EZ);bLb%SYp4_S$gr(zj13jbw!)S=ee?%5fP@l zhA8P~(|1>nyboRgh&M6LP~n2xTg}PFZ!BHG!3B9 zg|$D#8k<1=fw0m5u1i2NcgKvEhRi=d)*FJ;@JpMrUb*2X4+kRRK6edjAx@^jT4(5MzI7ykBF$3r`Jw4Gc|8>Gax7VTo6iiRa& zz}v_8M92NC4$15?w_7znmqDSH>+j&CM}60iRc5TZ={0ca!Tu8Vi zMu7|!@ai^h!f`LlVC(JK2A)gCtNp~!;s0~<#@=Ma9wP6 z!-Ri6qo&iA002tkq>QD_vK-34M^zYq=;EXyp$biLALiqH0o zFmNvPb0`h9UKAgY-c{3U^~dd;L;sbA*{X{0_8S-uR+SI7xY3hSW9feTo5v2aBX?Fd z&9WY>M(?UXQWwE=14TqmTcQ}K(op{3=pNe@X`;7He&V?YdAhMrjI+?I&f?o%c^3|0 zL|NAzUR-Jnh=ra$gV;9t-H?U6Dv}es0W5iF@tfE0eyP3fFkmrwX$Lsn3?Zrs-;FcC z3-^MB?+R(!>CIeNl)8J;Bkq700d101x4S7CeWz4gF3V?*n#M*DD~iA zzah-YGG7an0I8|{{G0a++!ccrc`oW5pP=uhA86~Rt1S~g0sV5a=agzq@3!?A4o;Z( z&qW@KAHDc>px3WDkE8x^QM^=EqFK)iJ7ToKWVl6jCTyKDGTJqo`0ab_OE1a?Qu<&3c-xGnG}JK!Q<_YnzcGW3~k{V9)-W>n zfK2_p+bkJXwU&9Z7W_T&xO9nB_j~tLKF#%C%Rva2iBDReWxZP>#yz%(fLQzYA=9{* zA-jF$yKtN@bpBH@in;$uCC+20Bg9YNwrO-TiR)}E*XtKQ+&=Y456W-tMcnUvKsVhC znZ2DjND^9Ha&J1YUkcVDXxa}%-}nv~lmmv#oIRC-!=>-EJ%sN#M+L9soPUcJ_bSSq zOyaq>9HrI|&02AZ?lYqCq(sqCuHH(_sY$>zF$9vJg2KC2tMx31JYv& zo*x$wp|c&SM*EVn{!8c9kr%vboLnp1kM&KV&`*}uA4OxVd7!^_SJ1sOVB)nsvOpU) zvIsxzez?Gn)1C~>DTu!Gx{G(0Pxvuv;ZCnye4bNew~ApP;}md1&BS18{Z_+Vb; z<+o0Tja#h=KIUs>>gSMcqPI zeA?hZ&ye7A8<0d4f2SZZad|Y!tC3s4?HD6h<2>h#Y>6*{wU?JjZR^~FZ#-$?PJ{r$ z`S(}!gtQd#or$$L%iu>1-5D0*Q0-}861Gf+_*9VIe&y~wM-0M(<5tGom5MfO zxpIXUke{0#ik-gw$C*?B-SAnIFd=yUy`klGP;ap7MX&DmKe$E*7d|g=a@5E-mzz6i z(_d^YFe9-=_7t3>#7CZ&%PrFtIgSrtvYa{!dSno|LKG&|Rji}l48r}26UbG92~}^Z wq>oldq`YQHO+dy6!24>?mCc<5owJXQJBzdhtZq*Vm}mq3KmVU~0He+R4>wKmuK)l5 literal 0 HcmV?d00001 diff --git a/include/widget.h b/include/widget.h new file mode 100644 index 0000000..f48a92b --- /dev/null +++ b/include/widget.h @@ -0,0 +1,44 @@ +#ifndef __WIDGET_H +#define __WIDGET_H + +struct widget_t; + +#define EV_WIDGET_NONE 0 +#define EV_WIDGET_CREATE 1 +#define EV_WIDGET_DESTROY 2 +#define EV_WIDGET_DRAW 3 +#define EV_WIDGET_REDRAW 4 +#define EV_WIDGET_TIMER 5 +#define EV_WIDGET_TOUCH_UP 6 +#define EV_WIDGET_TOUCH_DOWN 7 + +typedef void (*widget_event_fn)(int ev, struct widget_t *w, void *ev_data); + +struct widget_t { + uint16_t x, y, w, h; + + uint32_t timer_msec; // 0 to disable + widget_event_fn handler; // Event callback for this widget + void *user_data; // User supplied data + + // Private + mgos_timer_id _timer_id; +}; + +struct widget_t *widget_add(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data); +struct widget_t *widget_find(uint16_t x, uint16_t y); +void widget_remove(struct widget_t *widget); + +void widget_time_ev(int ev, struct widget_t *w, void *ev_data); + +void widget_wifi_ev(int ev, struct widget_t *w, void *ev_data); + +void widget_network_ev(int ev, struct widget_t *w, void *ev_data); +void widget_network_send(); +void widget_network_recv(); + +void widget_topbar_ev(int ev, struct widget_t *w, void *ev_data); + +void widget_name_ev(int ev, struct widget_t *w, void *ev_data); + +#endif // __WIDGET_H diff --git a/libs/ili9341/README.md b/libs/ili9341/README.md new file mode 100644 index 0000000..22ec2dc --- /dev/null +++ b/libs/ili9341/README.md @@ -0,0 +1,3 @@ +# mos-lobo-tft + +TFT lib for mongoose-os based on https://github.com/loboris/ESP32_TFT_library diff --git a/libs/ili9341/include/tft.h b/libs/ili9341/include/tft.h new file mode 100644 index 0000000..8006dfd --- /dev/null +++ b/libs/ili9341/include/tft.h @@ -0,0 +1,683 @@ +/* + * High level TFT functions + * Author: LoBo 04/2017, https://github/loboris + * + */ + +#ifndef _mgos_ili9341_H_ +#define _mgos_ili9341_H_ + +#include +#include "tftspi.h" + +typedef struct { + uint16_t x1; + uint16_t y1; + uint16_t x2; + uint16_t y2; +} dispWin_t; + +typedef struct { + uint8_t *font; + uint8_t x_size; + uint8_t y_size; + uint8_t offset; + uint16_t numchars; + uint16_t size; + uint8_t max_x_size; + uint8_t bitmap; + color_t color; +} Font; + + +//========================================================================================== +// ==== Global variables =================================================================== +//========================================================================================== +extern uint8_t orientation; // current screen orientation +extern uint16_t font_rotate; // current font font_rotate angle (0~395) +extern uint8_t font_transparent; // if not 0 draw fonts transparent +extern uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width +extern uint8_t font_buffered_char; +extern uint8_t font_line_space; // additional spacing between text lines; added to font height +extern uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip +extern color_t _fg; // current foreground color for fonts +extern color_t _bg; // current background for non transparent fonts +extern dispWin_t dispWin; // display clip window +extern float _angleOffset; // angle offset for arc, polygon and line by angle functions +extern uint8_t image_debug; // print debug messages during image decode if set to 1 + +extern Font cfont; // Current font structure + +extern int mgos_ili9341_X; // X position of the next character after mgos_ili9341_print() function +extern int mgos_ili9341_Y; // Y position of the next character after mgos_ili9341_print() function + +extern uint32_t tp_calx; // touch screen X calibration constant +extern uint32_t tp_caly; // touch screen Y calibration constant +// ========================================================================================= + + +// Buffer is created during jpeg decode for sending data +// Total size of the buffer is 2 * (JPG_IMAGE_LINE_BUF_SIZE * 3) +// The size must be multiple of 256 bytes !! +#define JPG_IMAGE_LINE_BUF_SIZE 512 + +// --- Constants for ellipse function --- +#define TFT_ELLIPSE_UPPER_RIGHT 0x01 +#define TFT_ELLIPSE_UPPER_LEFT 0x02 +#define TFT_ELLIPSE_LOWER_LEFT 0x04 +#define TFT_ELLIPSE_LOWER_RIGHT 0x08 + +// Constants for Arc function +// number representing the maximum angle (e.g. if 100, then if you pass in start=0 and end=50, you get a half circle) +// this can be changed with setArcParams function at runtime +#define DEFAULT_ARC_ANGLE_MAX 360 +// rotational offset in degrees defining position of value 0 (-90 will put it at the top of circle) +// this can be changed with setAngleOffset function at runtime +#define DEFAULT_ANGLE_OFFSET -90 + +#define PI 3.14159265359 + +#define MIN_POLIGON_SIDES 3 +#define MAX_POLIGON_SIDES 60 + +// === Color names constants === +extern const color_t ILI9341_BLACK; +extern const color_t ILI9341_NAVY; +extern const color_t ILI9341_DARKGREEN; +extern const color_t ILI9341_DARKCYAN; +extern const color_t ILI9341_MAROON; +extern const color_t ILI9341_PURPLE; +extern const color_t ILI9341_OLIVE; +extern const color_t ILI9341_LIGHTGREY; +extern const color_t ILI9341_DARKGREY; +extern const color_t ILI9341_BLUE; +extern const color_t ILI9341_GREEN; +extern const color_t ILI9341_CYAN; +extern const color_t ILI9341_RED; +extern const color_t ILI9341_MAGENTA; +extern const color_t ILI9341_YELLOW; +extern const color_t ILI9341_WHITE; +extern const color_t ILI9341_ORANGE; +extern const color_t ILI9341_GREENYELLOW; +extern const color_t ILI9341_PINK; + +// === Color invert constants === +#define INVERT_ON 1 +#define INVERT_OFF 0 + +// === Special coordinates constants === +#define CENTER -9003 +#define RIGHT -9004 +#define BOTTOM -9004 + +#define LASTX 7000 +#define LASTY 8000 + +// === Embedded fonts constants === +#define DEFAULT_FONT 0 +#define DEJAVU18_FONT 1 +#define DEJAVU24_FONT 2 +#define UBUNTU16_FONT 3 +#define COMIC24_FONT 4 +#define MINYA24_FONT 5 +#define TOONEY32_FONT 6 +#define SMALL_FONT 7 +#define DEF_SMALL_FONT 8 +#define FONT_7SEG 9 +#define USER_FONT 10 // font will be read from file + + + +// ===== PUBLIC FUNCTIONS ========================================================================= + + +/* + * Draw pixel at given x,y coordinates + * + * Params: + * x: horizontal position + * y: vertical position + * color: pixel color + * sel: if not 0 activate CS before and deactivat after sending pixel data to display + * when sending multiple pixels it is faster to activate the CS first, + * send all pixels an deactivate CS after all pixela was sent +*/ +//------------------------------------------------------------------- +void mgos_ili9341_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel); + +/* + * Read pixel color value from display GRAM at given x,y coordinates + * + * Params: + * x: horizontal position + * y: vertical position + * + * Returns: + * pixel color at x,y +*/ +//------------------------------------------ +color_t mgos_ili9341_readPixel(int16_t x, int16_t y); + +/* + * Draw vertical line at given x,y coordinates + * + * Params: + * x: horizontal start position + * y: vertical start position + * h: line height in pixels + * color: line color +*/ +//--------------------------------------------------------------------- +void mgos_ili9341_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color); + +/* + * Draw horizontal line at given x,y coordinates + * + * Params: + * x: horizontal start position + * y: vertical start position + * w: line width in pixels + * color: line color +*/ +//--------------------------------------------------------------------- +void mgos_ili9341_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color); + +/* + * Draw line on screen + * + * Params: + * x0: horizontal start position + * y0: vertical start position + * x1: horizontal end position + * y1: vertical end position + * color: line color +*/ +//------------------------------------------------------------------------------- +void mgos_ili9341_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color); + + +/* + * Draw line on screen from (x,y) point at given angle + * Line drawing angle starts at lower right quadrant of the screen and is offseted by + * '_angleOffset' global variable (default: -90 degrees) + * + * Params: + * x: horizontal start position + * y: vertical start position + * start: start offset from (x,y) + * len: length of the line + * angle: line angle in degrees + * color: line color +*/ +//----------------------------------------------------------------------------------------------------------- +void mgos_ili9341_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color); + +/* + * Fill given rectangular screen region with color + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * color: fill color +*/ +//--------------------------------------------------------------------------- +void mgos_ili9341_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color); + +/* + * Draw rectangle on screen + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * color: rect line color +*/ +//------------------------------------------------------------------------------ +void mgos_ili9341_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color); + +/* + * Draw rectangle with rounded corners on screen + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * r: corner radius + * color: rectangle color +*/ +//---------------------------------------------------------------------------------------------- +void mgos_ili9341_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color); + +/* + * Fill given rectangular screen region with rounded corners with color + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * r: corner radius + * color: fill color +*/ +//---------------------------------------------------------------------------------------------- +void mgos_ili9341_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color); + +/* + * Fill the whole screen with color + * + * Params: + * color: fill color +*/ +//-------------------------------- +void mgos_ili9341_fillScreen(color_t color); + +/* + * Fill the current clip window with color + * + * Params: + * color: fill color +*/ +//--------------------------------- +void mgos_ili9341_fillWindow(color_t color); + +/* + * Draw triangle on screen + * + * Params: + * x0: first triangle point x position + * y0: first triangle point y position + * x0: second triangle point x position + * y0: second triangle point y position + * x0: third triangle point x position + * y0: third triangle point y position + * color: triangle color +*/ +//----------------------------------------------------------------------------------------------------------------- +void mgos_ili9341_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color); + +/* + * Fill triangular screen region with color + * + * Params: + * x0: first triangle point x position + * y0: first triangle point y position + * x0: second triangle point x position + * y0: second triangle point y position + * x0: third triangle point x position + * y0: third triangle point y position + * color: fill color +*/ +//----------------------------------------------------------------------------------------------------------------- +void mgos_ili9341_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color); + +/* + * Draw circle on screen + * + * Params: + * x: circle center x position + * y: circle center x position + * r: circle radius + * color: circle color +*/ +//------------------------------------------------------------------- +void mgos_ili9341_drawCircle(int16_t x, int16_t y, int radius, color_t color); + +/* + * Fill circle on screen with color + * + * Params: + * x: circle center x position + * y: circle center x position + * r: circle radius + * color: circle fill color +*/ +//------------------------------------------------------------------- +void mgos_ili9341_fillCircle(int16_t x, int16_t y, int radius, color_t color); + +/* + * Draw ellipse on screen + * + * Params: + * x0: ellipse center x position + * y0: ellipse center x position + * rx: ellipse horizontal radius + * ry: ellipse vertical radius + * option: drawing options, multiple options can be combined + 1 (mgos_ili9341_ELLIPSE_UPPER_RIGHT) draw upper right corner + 2 (mgos_ili9341_ELLIPSE_UPPER_LEFT) draw upper left corner + 4 (mgos_ili9341_ELLIPSE_LOWER_LEFT) draw lower left corner + 8 (mgos_ili9341_ELLIPSE_LOWER_RIGHT) draw lower right corner + to draw the whole ellipse use option value 15 (1 | 2 | 4 | 8) + * + * color: circle color +*/ +//------------------------------------------------------------------------------------------------------ +void mgos_ili9341_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option); + +/* + * Fill elliptical region on screen + * + * Params: + * x0: ellipse center x position + * y0: ellipse center x position + * rx: ellipse horizontal radius + * ry: ellipse vertical radius + * option: drawing options, multiple options can be combined + 1 (mgos_ili9341_ELLIPSE_UPPER_RIGHT) fill upper right corner + 2 (mgos_ili9341_ELLIPSE_UPPER_LEFT) fill upper left corner + 4 (mgos_ili9341_ELLIPSE_LOWER_LEFT) fill lower left corner + 8 (mgos_ili9341_ELLIPSE_LOWER_RIGHT) fill lower right corner + to fill the whole ellipse use option value 15 (1 | 2 | 4 | 8) + * + * color: fill color +*/ +//------------------------------------------------------------------------------------------------------ +void mgos_ili9341_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option); + + +/* + * Draw circle arc on screen + * Arc drawing angle starts at lower right quadrant of the screen and is offseted by + * '_angleOffset' global variable (default: -90 degrees) + * + * Params: + * cx: arc center X position + * cy: arc center Y position + * th: thickness of the drawn arc + * ry: arc vertical radius + * start: arc start angle in degrees + * end: arc end angle in degrees + * color: arc outline color + * fillcolor: arc fill color +*/ +//---------------------------------------------------------------------------------------------------------------------------- +void mgos_ili9341_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor); + + +/* + * Draw polygon on screen + * + * Params: + * cx: polygon center X position + * cy: arc center Y position + * sides: number of polygon sides; MAX_POLIGON_SIDES ~ MAX_POLIGON_SIDES (3 ~ 60) + * diameter: diameter of the circle inside which the polygon is drawn + * color: polygon outline color + * fill: polygon fill color; if same as color, polygon is not filled + * deg: polygon rotation angle; 0 ~ 360 + * th: thickness of the polygon outline +*/ +//-------------------------------------------------------------------------------------------------------------- +void mgos_ili9341_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int deg, uint8_t th); + + +//-------------------------------------------------------------------------------------- +//void mgos_ili9341_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor); + + +/* + * Set the font used for writing the text to display. + * + * ------------------------------------------------------------------------------------ + * For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available. + * Character ‘/‘ draws the degree sign. + * ------------------------------------------------------------------------------------ + * + * Params: + * font: font number; use defined font names + * font_file: pointer to font file name; NULL for embeded fonts + */ +//---------------------------------------------------- +void mgos_ili9341_setFont(uint8_t font, const char *font_file); + +void mgos_ili9341_setFontColor(color_t color); + +/* + * Returns current font height & width in pixels. + * + * Params: + * width: pointer to returned font width + * height: pointer to returned font height + */ +//------------------------------------------- +int mgos_ili9341_getfontsize(int *width, int* height); + + +/* + * Returns current font height in pixels. + * + */ +//---------------------- +int mgos_ili9341_getfontheight(); + +/* + * Write text to display. + * + * Rotation of the displayed text depends on 'font_rotate' variable (0~360) + * if 'font_transparent' variable is set to 1, no background pixels will be printed + * + * If the text does not fit the screen width it will be clipped (if text_wrap=0), + * or continued on next line (if text_wrap=1) + * + * Two special characters are allowed in strings: + * ‘\r’ CR (0x0D), clears the display to EOL + * ‘\n’ LF (ox0A), continues to the new line, x=0 + * + * Params: + * st: pointer to null terminated string to be printed + * x: horizontal position of the upper left point in pixels + * Special values can be entered: + * CENTER, centers the text + * RIGHT, right justifies the text + * LASTX, continues from last X position; offset can be used: LASTX+n + * y: vertical position of the upper left point in pixels + * Special values can be entered: + * CENTER, centers the text + * BOTTOM, bottom justifies the text + * LASTY, continues from last Y position; offset can be used: LASTY+n + * + */ +//------------------------------------- +void mgos_ili9341_print(const char *const st, int x, int y); + +/* + * Set atributes for 7 segment vector font + * == 7 segment font must be the current font to this function to have effect == + * + * Params: + * l: 6~40; distance between bars in pixels + * w: 1~12, max l/2; bar width in pixels + * outline: draw font outline if set to 1 + * color: font outline color, only used if outline=1 + * + */ +//------------------------------------------------------------------------- +void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color); + +/* + * Sets the clipping area coordinates. + * All writing to screen is clipped to that area. + * Starting x & y in all functions will be adjusted to the clipping area. + * + * Params: + * x1,y1: upper left point of the clipping area + * x2,y2: bottom right point of the clipping area + * + */ +//---------------------------------------------------------------------- +void mgos_ili9341_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + +/* + * Resets the clipping area to full screen (0,0),(_wodth,_height) + * + */ +//---------------------- +void mgos_ili9341_resetclipwin(); + +/* + * Save current clipping area to temporary variable + * + */ +//--------------------- +void mgos_ili9341_saveClipWin(); + +/* + * Restore current clipping area from temporary variable + * + */ +//------------------------ +void mgos_ili9341_restoreClipWin(); + +/* + * Set the screen rotation + * Also resets the clip window and clears the screen with current background color + * + * Params: + * rot: 0~3; screen rotation; use defined rotation constants: + * PORTRAIT, LANDSCAPE, PORTRAIT_FLIP, LANDSCAPE_FLIP + * + */ +//-------------------------------- +void mgos_ili9341_setRotation(uint8_t rot); + +/* + * Set inverted/normal colors + * + * Params: + * mode: 0 or 1; use defined constants: INVERT_ON or INVERT_OFF + * + */ +//----------------------------------------- +void mgos_ili9341_invertDisplay(const uint8_t mode); + +/* + * Select gamma curve + * Params: + * gamma: gama curve, values 0~3 + */ +//================================= +void mgos_ili9341_setGammaCurve(uint8_t gm); + +/* + * Compare two color structures + * Returns 0 if equal, 1 if not equal + * + * Params: + * c1, c2: colors to be compared + */ +//--------------------------------------------- +int mgos_ili9341_compare_colors(color_t c1, color_t c2); + +/* + * returns the string width in pixels. + * Useful for positions strings on the screen. + */ +//-------------------------------- +int mgos_ili9341_getStringWidth(const char* const str); + + +/* + * Fills the rectangle occupied by string with current background color + */ +void mgos_ili9341_clearStringRect(int x, int y, char *str); + +/* + * Converts the components of a color, as specified by the HSB model, + * to an equivalent set of values for the default RGB model. + + * The color structure that is returned by HSBtoRGB encodes the value of a color as R, G & B component + * + * Params: + * _hue: float; any number, the floor of this number is subtracted from it to create a fraction between 0 and 1. + * This fractional number is then multiplied by 360 to produce the hue angle in the HSB color model. + * _sat: float; 0 ~ 1.0 + * _brightness: float; 0 ~ 1.0 + * +*/ +//---------------------------------------------------------- +color_t HSBtoRGB(float _hue, float _sat, float _brightness); + +/* + * Decodes and displays JPG image + * Limits: + * Baseline only. Progressive and Lossless JPEG format are not supported. + * Image size: Up to 65520 x 65520 pixels + * Color space: YCbCr three components only. Gray scale image is not supported. + * Sampling factor: 4:4:4, 4:2:2 or 4:2:0. + * + * Params: + * x: image left position; constants CENTER & RIGHT can be used; negative value is accepted + * y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted + * scale: image scale factor: 0~3; if scale>0, image is scaled by factor 1/(2^scale) (1/2, 1/4 or 1/8) + * fname: pointer to the name of the file from which the image will be read + * if set to NULL, image will be read from memory buffer pointed to by 'buf' + * buf: pointer to the memory buffer from which the image will be read; used if fname=NULL + * size: size of the memory buffer from which the image will be read; used if fname=NULL & buf!=NULL + * + */ +//----------------------------------------------------------------------------------- +void mgos_ili9341_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size); + +/* + * Decodes and displays BMP image + * Only uncompressed RGB 24-bit with no color space information BMP images can be displayed + * + * Params: + * x: image left position; constants CENTER & RIGHT can be used; negative value is accepted + * y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted + * scale: image scale factor: 0~7; if scale>0, image is scaled by factor 1/(scale+1) + * fname: pointer to the name of the file from which the image will be read + * if set to NULL, image will be read from memory buffer pointed to by 'imgbuf' + * imgbuf: pointer to the memory buffer from which the image will be read; used if fname=NULL + * size: size of the memory buffer from which the image will be read; used if fname=NULL & imgbuf!=NULL + * + */ +//------------------------------------------------------------------------------------- +int mgos_ili9341_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size); + +/* + * Compile font c source file to .fnt file + * which can be used in mgos_ili9341_setFont() function to select external font + * Created file have the same name as source file and extension .fnt + * + * Params: + * fontfile: pointer to c source font file name; must have .c extension + * dbg: if set to 1, prints debug information + * + * Returns: + * 0 on success + * err no on error + * + */ +//------------------------------------------------ +int compile_font_file(char *fontfile, uint8_t dbg); + +/* + * Get all font's characters to buffer + */ +void getFontCharacters(uint8_t *buf); + + +/** + * @brief Set foreground color + */ +void mgos_ili9341_set_fg(const color_t *color); +void mgos_ili9341_set_bg(const color_t *color); + +/** + * @brief Get foreground color + */ +color_t *mgos_ili9341_get_fg(void); +color_t *mgos_ili9341_get_bg(void); + +/** + * @brief MGOS lib init + */ +bool mgos_ili9341_init(void); + + +#endif diff --git a/libs/ili9341/include/tftspi.h b/libs/ili9341/include/tftspi.h new file mode 100644 index 0000000..da74297 --- /dev/null +++ b/libs/ili9341/include/tftspi.h @@ -0,0 +1,211 @@ +/* + * + * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS USING DIRECT TRANSFER MODE + * +*/ + +#ifndef _TFTSPI_H_ +#define _TFTSPI_H_ + +#include "tftspi.h" +#include "lobo_spi.h" +#include "sdkconfig.h" + +// === Screen orientation constants === +#define PORTRAIT 0 +#define LANDSCAPE 1 +#define PORTRAIT_FLIP 2 +#define LANDSCAPE_FLIP 3 + +// ** Set the correct configuration for Adafruit TFT Feather +// --------------------------------------------------------- +#define DEFAULT_TFT_DISPLAY_WIDTH 240 +#define DEFAULT_TFT_DISPLAY_HEIGHT 320 +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 +#define TFT_RGB_BGR 0x08 + +// --------------------------------------------------------- + +// ############################################################## +// #### Global variables #### +// ############################################################## + +// ==== Spi clock for reading data from display memory in Hz ==== +extern uint32_t max_rdclock; + +// ==== Display dimensions in pixels ============================ +extern int _width; +extern int _height; + +// ==== Spi device handles for display and touch screen ========= +extern spi_lobo_device_handle_t disp_spi; + +// ############################################################## + +// 24-bit color type structure +typedef struct __attribute__((__packed__)) { +//typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} color_t ; + +// ==== Display commands constants ==== +#define TFT_INVOFF 0x20 +#define TFT_INVONN 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_MADCTL 0x36 +#define TFT_PTLAR 0x30 +#define TFT_ENTRYM 0xB7 + +#define TFT_CMD_NOP 0x00 +#define TFT_CMD_SWRESET 0x01 +#define TFT_CMD_RDDID 0x04 +#define TFT_CMD_RDDST 0x09 + +#define TFT_CMD_SLPIN 0x10 +#define TFT_CMD_SLPOUT 0x11 +#define TFT_CMD_PTLON 0x12 +#define TFT_CMD_NORON 0x13 + +#define TFT_CMD_RDMODE 0x0A +#define TFT_CMD_RDMADCTL 0x0B +#define TFT_CMD_RDPIXFMT 0x0C +#define TFT_CMD_RDIMGFMT 0x0D +#define TFT_CMD_RDSELFDIAG 0x0F + +#define TFT_CMD_GAMMASET 0x26 + +#define TFT_CMD_FRMCTR1 0xB1 +#define TFT_CMD_FRMCTR2 0xB2 +#define TFT_CMD_FRMCTR3 0xB3 +#define TFT_CMD_INVCTR 0xB4 +#define TFT_CMD_DFUNCTR 0xB6 + +#define TFT_CMD_PWCTR1 0xC0 +#define TFT_CMD_PWCTR2 0xC1 +#define TFT_CMD_PWCTR3 0xC2 +#define TFT_CMD_PWCTR4 0xC3 +#define TFT_CMD_PWCTR5 0xC4 +#define TFT_CMD_VMCTR1 0xC5 +#define TFT_CMD_VMCTR2 0xC7 + +#define TFT_CMD_RDID1 0xDA +#define TFT_CMD_RDID2 0xDB +#define TFT_CMD_RDID3 0xDC +#define TFT_CMD_RDID4 0xDD + +#define TFT_CMD_GMCTRP1 0xE0 +#define TFT_CMD_GMCTRN1 0xE1 + +#define TFT_CMD_POWERA 0xCB +#define TFT_CMD_POWERB 0xCF +#define TFT_CMD_POWER_SEQ 0xED +#define TFT_CMD_DTCA 0xE8 +#define TFT_CMD_DTCB 0xEA +#define TFT_CMD_PRC 0xF7 +#define TFT_CMD_3GAMMA_EN 0xF2 + +#define ST_CMD_VCOMS 0xBB +#define ST_CMD_FRCTRL2 0xC6 +#define ST_CMD_PWCTR1 0xD0 + +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 +#define MADCTL_MH 0x04 + +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_RAMRD 0x2E +#define TFT_CMD_PIXFMT 0x3A + +#define TFT_CMD_DELAY 0x80 + + +// Initialization sequence for ILI7341 +// ==================================== +static const uint8_t ILI9341_init[] = { + 24, // 24 commands in list + TFT_CMD_SWRESET, TFT_CMD_DELAY, // 1: Software reset, no args, w/delay + 250, // 200 ms delay + TFT_CMD_POWERA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + TFT_CMD_POWERB, 3, 0x00, 0XC1, 0X30, + 0xEF, 3, 0x03, 0x80, 0x02, + TFT_CMD_DTCA, 3, 0x85, 0x00, 0x78, + TFT_CMD_DTCB, 2, 0x00, 0x00, + TFT_CMD_POWER_SEQ, 4, 0x64, 0x03, 0X12, 0X81, + TFT_CMD_PRC, 1, 0x20, + TFT_CMD_PWCTR1, 1, 0x23, //Power control VRH[5:0] + TFT_CMD_PWCTR2, 1, 0x10, //Power control SAP[2:0];BT[3:0] + TFT_CMD_VMCTR1, 2, 0x3e, 0x28, //VCM control + TFT_CMD_VMCTR2, 1, 0x86, //VCM control2 + TFT_MADCTL, 1, // Memory Access Control (orientation) + (MADCTL_MX | TFT_RGB_BGR), + // *** INTERFACE PIXEL FORMAT: 0x66 -> 18 bit; 0x55 -> 16 bit + TFT_CMD_PIXFMT, 1, DISP_COLOR_BITS_24, + TFT_INVOFF, 0, + TFT_CMD_FRMCTR1, 2, 0x00, 0x18, + TFT_CMD_DFUNCTR, 4, 0x08, 0x82, 0x27, 0x00, // Display Function Control + TFT_PTLAR, 4, 0x00, 0x00, 0x01, 0x3F, + TFT_CMD_3GAMMA_EN, 1, 0x00, // 3Gamma Function: Disable (0x02), Enable (0x03) + TFT_CMD_GAMMASET, 1, 0x01, //Gamma curve selected (0x01, 0x02, 0x04, 0x08) + TFT_CMD_GMCTRP1, 15, //Positive Gamma Correction + 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, + TFT_CMD_GMCTRN1, 15, //Negative Gamma Correction + 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, + TFT_CMD_SLPOUT, TFT_CMD_DELAY, // Sleep out + 200, // 120 ms delay + TFT_DISPON, TFT_CMD_DELAY, 200, +}; + +// ==== Public functions ========================================================= + +// == Low level functions; usually not used directly == +esp_err_t wait_trans_finish(uint8_t free_line); +void disp_spi_transfer_cmd(int8_t cmd); +void disp_spi_transfer_cmd_data(int8_t cmd, uint8_t *data, uint32_t len); +void drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel); +void send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf); +void mgos_ili9341_pushColorRep(int x1, int y1, int x2, int y2, color_t data, uint32_t len); +int read_data(int x1, int y1, int x2, int y2, int len, uint8_t *buf, uint8_t set_sp); +color_t readPixel(int16_t x, int16_t y); +int touch_get_data(uint8_t type); + + +// Deactivate display's CS line +//======================== +esp_err_t disp_deselect(); + +// Activate display's CS line and configure SPI interface if necessary +//====================== +esp_err_t disp_select(); + + +// Find maximum spi clock for successful read from display RAM +// ** Must be used AFTER the display is initialized ** +//====================== +uint32_t find_rd_speed(); + + +// Change the screen rotation. +// Input: m new rotation value (0 to 3) +//================================= +void _tft_setRotation(uint8_t rot); + + +// Perform display initialization sequence +// Sets orientation to landscape; clears the screen +// * All pins must be configured +// * SPI interface must already be setup +//====================== +void mgos_ili9341_display_init(); + +// =============================================================================== + +#endif diff --git a/libs/ili9341/mos.yml b/libs/ili9341/mos.yml new file mode 100644 index 0000000..9687750 --- /dev/null +++ b/libs/ili9341/mos.yml @@ -0,0 +1,28 @@ +author: Pim van Pelt +type: lib +description: Mongoose-OS ILI9341 for ESP32 +version: 1.0 + +sources: + - src + +includes: + - include + +# filesystem: +# - fs + +config_schema: + - ["ili9341", "o", {title: "ILI9341 settings"}] + - ["ili9341.cs_pin", "i", 15, {title: "TFT CS pin"}] + - ["ili9341.dc_pin", "i", 33, {title: "TFT DC pin"}] + +libs: + - origin: libs/lobo-spi + +tags: + - c + - spi + - hw + +manifest_version: 2017-09-29 diff --git a/libs/ili9341/src/DefaultFont.c b/libs/ili9341/src/DefaultFont.c new file mode 100644 index 0000000..3e3c2a0 --- /dev/null +++ b/libs/ili9341/src/DefaultFont.c @@ -0,0 +1,333 @@ +// Default font + +// ======================================================================== +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ======================================================================== + +// dejavu +// Point Size : 12 +// Memory usage : 1158 bytes +// # characters : 95 + +const unsigned char tft_DefaultFont[] = +{ +0x00, 0x0B, 0x86, 0x04, + +// ' ' +0x20,0x0A,0x00,0x00,0x00,0x04, + +// '!' +0x21,0x01,0x01,0x09,0x02,0x05, +0xFD,0x80, +// '"' +0x22,0x01,0x03,0x03,0x01,0x05, +0xB6,0x80, +// '#' +0x23,0x02,0x08,0x08,0x01,0x0A, +0x12,0x14,0x7F,0x24,0x24,0xFE,0x28,0x48, +// '$' +0x24,0x01,0x06,0x0B,0x02,0x08, +0x21,0xCA,0xA8,0xE0,0xE2,0xAA,0x70,0x82,0x00, +// '%' +0x25,0x01,0x0A,0x09,0x00,0x0B, +0x61,0x24,0x89,0x22,0x50,0x6D,0x82,0x91,0x24,0x49,0x21,0x80, +// '&' +0x26,0x01,0x09,0x09,0x01,0x0A, +0x30,0x24,0x10,0x0C,0x05,0x14,0x4A,0x19,0x8C,0x7B,0x00, +// ''' +0x27,0x01,0x01,0x03,0x01,0x03, +0xE0, +// '(' +0x28,0x00,0x03,0x0B,0x01,0x05, +0x69,0x49,0x24,0x48,0x80, +// ')' +0x29,0x00,0x03,0x0B,0x01,0x05, +0x89,0x12,0x49,0x4A,0x00, +// '*' +0x2A,0x01,0x05,0x06,0x01,0x06, +0x25,0x5C,0xEA,0x90, +// '+' +0x2B,0x03,0x07,0x07,0x01,0x0A, +0x10,0x20,0x47,0xF1,0x02,0x04,0x00, +// ',' +0x2C,0x08,0x01,0x03,0x01,0x04, +0xE0, +// '-' +0x2D,0x06,0x03,0x01,0x01,0x04, +0xE0, +// '.' +0x2E,0x08,0x01,0x02,0x01,0x04, +0xC0, +// '/' +0x2F,0x01,0x04,0x0A,0x00,0x04, +0x11,0x22,0x24,0x44,0x88, +// '0' +0x30,0x01,0x06,0x09,0x01,0x08, +0x79,0x28,0x61,0x86,0x18,0x52,0x78, +// '1' +0x31,0x01,0x05,0x09,0x01,0x08, +0xE1,0x08,0x42,0x10,0x84,0xF8, +// '2' +0x32,0x01,0x07,0x09,0x01,0x08, +0x79,0x18,0x10,0x20,0x82,0x08,0x20,0xFC, +// '3' +0x33,0x01,0x06,0x09,0x01,0x08, +0x7A,0x10,0x41,0x38,0x30,0x63,0x78, +// '4' +0x34,0x01,0x06,0x09,0x01,0x08, +0x18,0x62,0x92,0x4A,0x2F,0xC2,0x08, +// '5' +0x35,0x01,0x06,0x09,0x01,0x08, +0xFA,0x08,0x3C,0x0C,0x10,0x63,0x78, +// '6' +0x36,0x01,0x06,0x09,0x01,0x08, +0x39,0x18,0x3E,0xCE,0x18,0x53,0x78, +// '7' +0x37,0x01,0x06,0x09,0x01,0x08, +0xFC,0x10,0x82,0x10,0x42,0x08,0x40, +// '8' +0x38,0x01,0x06,0x09,0x01,0x08, +0x7B,0x38,0x73,0x7B,0x38,0x73,0x78, +// '9' +0x39,0x01,0x06,0x09,0x01,0x08, +0x7B,0x28,0x61,0xCD,0xD0,0x62,0x70, +// ':' +0x3A,0x04,0x01,0x06,0x01,0x04, +0xCC, +// ';' +0x3B,0x04,0x01,0x07,0x01,0x04, +0xCE, +// '<' +0x3C,0x03,0x08,0x06,0x01,0x0A, +0x03,0x1E,0xE0,0xE0,0x1E,0x03, +// '=' +0x3D,0x05,0x08,0x03,0x01,0x0A, +0xFF,0x00,0xFF, +// '>' +0x3E,0x03,0x08,0x06,0x01,0x0A, +0xC0,0x78,0x07,0x07,0x78,0xC0, +// '?' +0x3F,0x01,0x05,0x09,0x00,0x06, +0x74,0x42,0x22,0x10,0x04,0x20, +// '@' +0x40,0x01,0x0B,0x0B,0x01,0x0D, +0x1F,0x06,0x19,0x01,0x46,0x99,0x13,0x22,0x64,0x54,0x6C,0x40,0x04,0x10,0x7C,0x00, +// 'A' +0x41,0x01,0x08,0x09,0x00,0x08, +0x18,0x18,0x24,0x24,0x24,0x42,0x7E,0x42,0x81, +// 'B' +0x42,0x01,0x06,0x09,0x01,0x08, +0xFA,0x18,0x61,0xFA,0x18,0x61,0xF8, +// 'C' +0x43,0x01,0x06,0x09,0x01,0x08, +0x39,0x18,0x20,0x82,0x08,0x11,0x38, +// 'D' +0x44,0x01,0x07,0x09,0x01,0x09, +0xF9,0x0A,0x0C,0x18,0x30,0x60,0xC2,0xF8, +// 'E' +0x45,0x01,0x06,0x09,0x01,0x08, +0xFE,0x08,0x20,0xFE,0x08,0x20,0xFC, +// 'F' +0x46,0x01,0x05,0x09,0x01,0x07, +0xFC,0x21,0x0F,0xC2,0x10,0x80, +// 'G' +0x47,0x01,0x07,0x09,0x01,0x09, +0x3C,0x86,0x04,0x08,0xF0,0x60,0xA1,0x3C, +// 'H' +0x48,0x01,0x07,0x09,0x01,0x09, +0x83,0x06,0x0C,0x1F,0xF0,0x60,0xC1,0x82, +// 'I' +0x49,0x01,0x01,0x09,0x01,0x03, +0xFF,0x80, +// 'J' +0x4A,0x01,0x03,0x0B,0xFF,0x03, +0x24,0x92,0x49,0x27,0x00, +// 'K' +0x4B,0x01,0x07,0x09,0x01,0x07, +0x85,0x12,0x45,0x0C,0x14,0x24,0x44,0x84, +// 'L' +0x4C,0x01,0x05,0x09,0x01,0x06, +0x84,0x21,0x08,0x42,0x10,0xF8, +// 'M' +0x4D,0x01,0x08,0x09,0x01,0x0A, +0x81,0xC3,0xC3,0xA5,0xA5,0x99,0x99,0x81,0x81, +// 'N' +0x4E,0x01,0x07,0x09,0x01,0x09, +0xC3,0x86,0x8D,0x19,0x31,0x62,0xC3,0x86, +// 'O' +0x4F,0x01,0x07,0x09,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38, +// 'P' +0x50,0x01,0x06,0x09,0x01,0x08, +0xFA,0x38,0x63,0xFA,0x08,0x20,0x80, +// 'Q' +0x51,0x01,0x07,0x0B,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,0x10,0x10, +// 'R' +0x52,0x01,0x07,0x09,0x01,0x08, +0xF9,0x1A,0x14,0x6F,0x91,0x21,0x42,0x82, +// 'S' +0x53,0x01,0x06,0x09,0x01,0x08, +0x7B,0x18,0x30,0x78,0x30,0x63,0x78, +// 'T' +0x54,0x01,0x07,0x09,0x00,0x07, +0xFE,0x20,0x40,0x81,0x02,0x04,0x08,0x10, +// 'U' +0x55,0x01,0x07,0x09,0x01,0x09, +0x83,0x06,0x0C,0x18,0x30,0x60,0xA2,0x38, +// 'V' +0x56,0x01,0x0A,0x09,0xFF,0x08, +0x40,0x90,0x22,0x10,0x84,0x21,0x04,0x81,0x20,0x30,0x0C,0x00, +// 'W' +0x57,0x01,0x0B,0x09,0x00,0x0B, +0x84,0x28,0x89,0x11,0x27,0x22,0xA8,0x55,0x0E,0xE0,0x88,0x11,0x00, +// 'X' +0x58,0x01,0x07,0x09,0x00,0x07, +0xC6,0x88,0xA1,0xC1,0x07,0x0A,0x22,0x82, +// 'Y' +0x59,0x01,0x07,0x09,0x00,0x07, +0x82,0x89,0x11,0x43,0x82,0x04,0x08,0x10, +// 'Z' +0x5A,0x01,0x07,0x09,0x01,0x09, +0xFE,0x04,0x10,0x41,0x04,0x10,0x40,0xFE, +// '[' +0x5B,0x01,0x02,0x0B,0x02,0x05, +0xEA,0xAA,0xAC, +// '\' +0x5C,0x01,0x04,0x0A,0x00,0x04, +0x88,0x44,0x42,0x22,0x11, +// ']' +0x5D,0x01,0x02,0x0B,0x01,0x05, +0xD5,0x55,0x5C, +// '^' +0x5E,0x01,0x08,0x03,0x01,0x0A, +0x18,0x24,0x42, +// '_' +0x5F,0x0C,0x06,0x01,0x00,0x06, +0xFC, +// '`' +0x60,0x00,0x03,0x02,0x01,0x06, +0x44, +// 'a' +0x61,0x03,0x06,0x07,0x01,0x08, +0x7A,0x30,0x5F,0x86,0x37,0x40, +// 'b' +0x62,0x00,0x06,0x0A,0x01,0x08, +0x82,0x08,0x2E,0xCA,0x18,0x61,0xCE,0xE0, +// 'c' +0x63,0x03,0x05,0x07,0x01,0x07, +0x72,0x61,0x08,0x25,0xC0, +// 'd' +0x64,0x00,0x06,0x0A,0x01,0x08, +0x04,0x10,0x5D,0xCE,0x18,0x61,0xCD,0xD0, +// 'e' +0x65,0x03,0x06,0x07,0x01,0x08, +0x39,0x38,0x7F,0x81,0x13,0x80, +// 'f' +0x66,0x00,0x04,0x0A,0x00,0x04, +0x34,0x4F,0x44,0x44,0x44, +// 'g' +0x67,0x03,0x06,0x0A,0x01,0x08, +0x77,0x38,0x61,0x87,0x37,0x41,0x4C,0xE0, +// 'h' +0x68,0x00,0x06,0x0A,0x01,0x08, +0x82,0x08,0x2E,0xC6,0x18,0x61,0x86,0x10, +// 'i' +0x69,0x01,0x01,0x09,0x01,0x03, +0xBF,0x80, +// 'j' +0x6A,0x01,0x02,0x0C,0x00,0x03, +0x45,0x55,0x56, +// 'k' +0x6B,0x00,0x06,0x0A,0x01,0x07, +0x82,0x08,0x22,0x92,0x8E,0x28,0x92,0x20, +// 'l' +0x6C,0x00,0x01,0x0A,0x01,0x03, +0xFF,0xC0, +// 'm' +0x6D,0x03,0x09,0x07,0x01,0x0B, +0xB3,0x66,0x62,0x31,0x18,0x8C,0x46,0x22, +// 'n' +0x6E,0x03,0x06,0x07,0x01,0x08, +0xBB,0x18,0x61,0x86,0x18,0x40, +// 'o' +0x6F,0x03,0x06,0x07,0x01,0x08, +0x7B,0x38,0x61,0x87,0x37,0x80, +// 'p' +0x70,0x03,0x06,0x0A,0x01,0x08, +0xBB,0x28,0x61,0x87,0x3B,0xA0,0x82,0x00, +// 'q' +0x71,0x03,0x06,0x0A,0x01,0x08, +0x77,0x38,0x61,0x87,0x37,0x41,0x04,0x10, +// 'r' +0x72,0x03,0x04,0x07,0x01,0x05, +0xBC,0x88,0x88,0x80, +// 's' +0x73,0x03,0x06,0x07,0x01,0x07, +0x72,0x28,0x1C,0x0A,0x27,0x00, +// 't' +0x74,0x01,0x04,0x09,0x00,0x05, +0x44,0xF4,0x44,0x44,0x30, +// 'u' +0x75,0x03,0x06,0x07,0x01,0x08, +0x86,0x18,0x61,0x86,0x37,0x40, +// 'v' +0x76,0x03,0x08,0x07,0xFF,0x06, +0x42,0x42,0x24,0x24,0x24,0x18,0x18, +// 'w' +0x77,0x03,0x09,0x07,0x00,0x09, +0x88,0xC4,0x57,0x4A,0xA5,0x51,0x10,0x88, +// 'x' +0x78,0x03,0x06,0x07,0x00,0x06, +0x85,0x24,0x8C,0x49,0x28,0x40, +// 'y' +0x79,0x03,0x08,0x0A,0xFF,0x06, +0x42,0x42,0x24,0x24,0x14,0x18,0x08,0x08,0x10,0x60, +// 'z' +0x7A,0x03,0x05,0x07,0x00,0x05, +0xF8,0x44,0x44,0x43,0xE0, +// '{' +0x7B,0x01,0x05,0x0B,0x02,0x08, +0x19,0x08,0x42,0x60,0x84,0x21,0x06, +// '|' +0x7C,0x01,0x01,0x0C,0x02,0x04, +0xFF,0xF0, +// '}' +0x7D,0x01,0x05,0x0B,0x01,0x08, +0xC1,0x08,0x42,0x0C,0x84,0x21,0x30, +// '~' +0x7E,0x04,0x08,0x03,0x01,0x0A, +0x00,0x71,0x8E, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/DejaVuSans18.c b/libs/ili9341/src/DejaVuSans18.c new file mode 100644 index 0000000..b9e6ba9 --- /dev/null +++ b/libs/ili9341/src/DejaVuSans18.c @@ -0,0 +1,322 @@ +// ============================================================================ +// Proportional font Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ============================================================================ + +// DejaVuSans +// Point Size : 18 +// Memory usage : 1828 bytes +// # characters : 95 + +const unsigned char tft_Dejavu18[] = +{ +0x00, 0x12, 0x00, 0x00, + +// ' ' +0x20,0x0E,0x00,0x00,0x00,0x06, + +// '!' +0x21,0x01,0x02,0x0D,0x03,0x07, +0xFF,0xFF,0xC3,0xC0, +// '"' +0x22,0x01,0x06,0x05,0x01,0x08, +0xCF,0x3C,0xF3,0xCC, +// '#' +0x23,0x00,0x0C,0x0E,0x01,0x0F, +0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20, +// '$' +0x24,0x00,0x0A,0x11,0x01,0x0B, +0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00, +// '%' +0x25,0x01,0x0F,0x0D,0x01,0x11, +0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0, +// '&' +0x26,0x01,0x0C,0x0D,0x01,0x0D, +0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70, +// ''' +0x27,0x01,0x02,0x05,0x01,0x04, +0xFF,0xC0, +// '(' +0x28,0x00,0x04,0x10,0x02,0x07, +0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23, +// ')' +0x29,0x00,0x04,0x10,0x01,0x07, +0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C, +// '*' +0x2A,0x01,0x07,0x08,0x01,0x09, +0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88, +// '+' +0x2B,0x02,0x0C,0x0C,0x02,0x0F, +0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60, +// ',' +0x2C,0x0C,0x03,0x04,0x01,0x06, +0x6D,0x40, +// '-' +0x2D,0x08,0x05,0x02,0x01,0x07, +0xFF,0xC0, +// '.' +0x2E,0x0C,0x02,0x02,0x02,0x06, +0xF0, +// '/' +0x2F,0x01,0x06,0x0F,0x00,0x06, +0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00, +// '0' +0x30,0x01,0x09,0x0D,0x01,0x0B, +0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0, +// '1' +0x31,0x01,0x08,0x0D,0x02,0x0B, +0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF, +// '2' +0x32,0x01,0x09,0x0D,0x01,0x0B, +0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0, +// '3' +0x33,0x01,0x09,0x0D,0x01,0x0B, +0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0, +// '4' +0x34,0x01,0x0A,0x0D,0x01,0x0B, +0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00, +// '5' +0x35,0x01,0x08,0x0D,0x01,0x0B, +0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C, +// '6' +0x36,0x01,0x09,0x0D,0x01,0x0B, +0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0, +// '7' +0x37,0x01,0x08,0x0D,0x01,0x0B, +0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30, +// '8' +0x38,0x01,0x09,0x0D,0x01,0x0B, +0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0, +// '9' +0x39,0x01,0x09,0x0D,0x01,0x0B, +0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0, +// ':' +0x3A,0x05,0x02,0x09,0x02,0x06, +0xF0,0x03,0xC0, +// ';' +0x3B,0x05,0x03,0x0B,0x01,0x06, +0x6C,0x00,0x03,0x6A,0x00, +// '<' +0x3C,0x04,0x0B,0x0A,0x02,0x0F, +0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04, +// '=' +0x3D,0x05,0x0B,0x06,0x02,0x0F, +0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0, +// '>' +0x3E,0x04,0x0B,0x0A,0x02,0x0F, +0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00, +// '?' +0x3F,0x01,0x07,0x0D,0x01,0x0A, +0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00, +// '@' +0x40,0x01,0x10,0x10,0x01,0x12, +0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0, +// 'A' +0x41,0x01,0x0C,0x0D,0x00,0x0C, +0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30, +// 'B' +0x42,0x01,0x09,0x0D,0x02,0x0C, +0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0, +// 'C' +0x43,0x01,0x0B,0x0D,0x01,0x0D, +0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC, +// 'D' +0x44,0x01,0x0B,0x0D,0x02,0x0E, +0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0, +// 'E' +0x45,0x01,0x08,0x0D,0x02,0x0B, +0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF, +// 'F' +0x46,0x01,0x08,0x0D,0x02,0x0A, +0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +// 'G' +0x47,0x01,0x0B,0x0D,0x01,0x0E, +0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8, +// 'H' +0x48,0x01,0x0A,0x0D,0x02,0x0E, +0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0, +// 'I' +0x49,0x01,0x02,0x0D,0x02,0x06, +0xFF,0xFF,0xFF,0xC0, +// 'J' +0x4A,0x01,0x05,0x11,0xFF,0x06, +0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0, +// 'K' +0x4B,0x01,0x0B,0x0D,0x02,0x0C, +0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C, +// 'L' +0x4C,0x01,0x08,0x0D,0x02,0x0A, +0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF, +// 'M' +0x4D,0x01,0x0C,0x0D,0x02,0x10, +0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30, +// 'N' +0x4E,0x01,0x0A,0x0D,0x02,0x0E, +0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0, +// 'O' +0x4F,0x01,0x0C,0x0D,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80, +// 'P' +0x50,0x01,0x08,0x0D,0x02,0x0B, +0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0, +// 'Q' +0x51,0x01,0x0C,0x0F,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0, +// 'R' +0x52,0x01,0x0A,0x0D,0x02,0x0D, +0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0, +// 'S' +0x53,0x01,0x0A,0x0D,0x01,0x0B, +0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00, +// 'T' +0x54,0x01,0x0C,0x0D,0x00,0x0C, +0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00, +// 'U' +0x55,0x01,0x0A,0x0D,0x02,0x0E, +0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00, +// 'V' +0x56,0x01,0x0C,0x0D,0x00,0x0C, +0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00, +// 'W' +0x57,0x01,0x11,0x0D,0x01,0x13, +0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0, +// 'X' +0x58,0x01,0x0B,0x0D,0x01,0x0D, +0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E, +// 'Y' +0x59,0x01,0x0C,0x0D,0x00,0x0C, +0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00, +// 'Z' +0x5A,0x01,0x0B,0x0D,0x01,0x0D, +0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE, +// '[' +0x5B,0x00,0x04,0x10,0x01,0x07, +0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF, +// '\' +0x5C,0x01,0x06,0x0F,0x00,0x06, +0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0, +// ']' +0x5D,0x00,0x04,0x10,0x02,0x07, +0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF, +// '^' +0x5E,0x01,0x0B,0x05,0x02,0x0F, +0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06, +// '_' +0x5F,0x10,0x09,0x02,0x00,0x09, +0xFF,0xFF,0xC0, +// '`' +0x60,0x00,0x04,0x03,0x02,0x09, +0xC6,0x30, +// 'a' +0x61,0x04,0x08,0x0A,0x01,0x0A, +0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B, +// 'b' +0x62,0x00,0x09,0x0E,0x02,0x0B, +0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0, +// 'c' +0x63,0x04,0x08,0x0A,0x01,0x09, +0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E, +// 'd' +0x64,0x00,0x09,0x0E,0x01,0x0B, +0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC, +// 'e' +0x65,0x04,0x0A,0x0A,0x01,0x0B, +0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0, +// 'f' +0x66,0x00,0x07,0x0E,0x00,0x06, +0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00, +// 'g' +0x67,0x04,0x09,0x0E,0x01,0x0B, +0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0, +// 'h' +0x68,0x00,0x08,0x0E,0x02,0x0B, +0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, +// 'i' +0x69,0x00,0x02,0x0E,0x02,0x05, +0xF0,0xFF,0xFF,0xF0, +// 'j' +0x6A,0x00,0x04,0x12,0x00,0x05, +0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC, +// 'k' +0x6B,0x00,0x09,0x0E,0x02,0x0A, +0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18, +// 'l' +0x6C,0x00,0x02,0x0E,0x02,0x05, +0xFF,0xFF,0xFF,0xF0, +// 'm' +0x6D,0x04,0x0E,0x0A,0x02,0x11, +0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30, +// 'n' +0x6E,0x04,0x08,0x0A,0x02,0x0B, +0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, +// 'o' +0x6F,0x04,0x0A,0x0A,0x01,0x0B, +0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80, +// 'p' +0x70,0x04,0x09,0x0E,0x02,0x0B, +0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00, +// 'q' +0x71,0x04,0x09,0x0E,0x01,0x0B, +0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C, +// 'r' +0x72,0x04,0x06,0x0A,0x02,0x08, +0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00, +// 's' +0x73,0x04,0x08,0x0A,0x01,0x08, +0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78, +// 't' +0x74,0x01,0x06,0x0D,0x01,0x07, +0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C, +// 'u' +0x75,0x04,0x08,0x0A,0x02,0x0B, +0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B, +// 'v' +0x76,0x04,0x0C,0x0A,0x00,0x0B, +0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60, +// 'w' +0x77,0x04,0x0F,0x0A,0x01,0x10, +0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0, +// 'x' +0x78,0x04,0x0A,0x0A,0x01,0x0B, +0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70, +// 'y' +0x79,0x04,0x0C,0x0E,0x00,0x0B, +0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80, +// 'z' +0x7A,0x04,0x08,0x0A,0x01,0x09, +0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF, +// '{' +0x7B,0x00,0x08,0x11,0x02,0x0B, +0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F, +// '|' +0x7C,0x00,0x02,0x12,0x02,0x06, +0xFF,0xFF,0xFF,0xFF,0xF0, +// '}' +0x7D,0x00,0x08,0x11,0x02,0x0B, +0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0, +// '~' +0x7E,0x05,0x0B,0x05,0x02,0x0F, +0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/DejaVuSans24.c b/libs/ili9341/src/DejaVuSans24.c new file mode 100644 index 0000000..aa7e2f1 --- /dev/null +++ b/libs/ili9341/src/DejaVuSans24.c @@ -0,0 +1,331 @@ +// ======================================================================== +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ======================================================================== + +// dejavu +// Point Size : 24 +// Memory usage : 2724 bytes +// # characters : 95 + +const unsigned char tft_Dejavu24[] = +{ +0x00, 0x17, 0x00, 0x00, + +// ' ' +0x20,0x13,0x00,0x00,0x00,0x08, + +// '!' +0x21,0x01,0x02,0x12,0x04,0x0A, +0xFF,0xFF,0xFF,0x03,0xF0, +// '"' +0x22,0x01,0x06,0x07,0x02,0x0B, +0xCF,0x3C,0xF3,0xCF,0x3C,0xC0, +// '#' +0x23,0x01,0x10,0x12,0x02,0x14, +0x03,0x08,0x03,0x18,0x03,0x18,0x03,0x18,0x02,0x18,0x7F,0xFF,0x7F,0xFF,0x06,0x30,0x04,0x30,0x0C,0x20,0x0C,0x60,0xFF,0xFE,0xFF,0xFE,0x18,0x40,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x10,0xC0, +// '$' +0x24,0x01,0x0B,0x16,0x02,0x0F, +0x04,0x00,0x80,0x10,0x0F,0xC7,0xFD,0xC8,0xB1,0x06,0x20,0xE4,0x0F,0x80,0xFE,0x03,0xE0,0x4E,0x08,0xC1,0x1E,0x27,0xFF,0xC7,0xE0,0x10,0x02,0x00,0x40,0x08,0x00, +// '%' +0x25,0x01,0x14,0x12,0x01,0x17, +0x3C,0x03,0x06,0x60,0x60,0xC3,0x06,0x0C,0x30,0xC0,0xC3,0x1C,0x0C,0x31,0x80,0xC3,0x38,0x0C,0x33,0x00,0x66,0x63,0xC3,0xC6,0x66,0x00,0xCC,0x30,0x1C,0xC3,0x01,0x8C,0x30,0x38,0xC3,0x03,0x0C,0x30,0x60,0xC3,0x06,0x06,0x60,0xC0,0x3C, +// '&' +0x26,0x01,0x10,0x12,0x01,0x13, +0x07,0xC0,0x1F,0xE0,0x38,0x20,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x1C,0x00,0x3E,0x00,0x77,0x06,0xE3,0x86,0xC1,0xCC,0xC0,0xFC,0xC0,0x78,0xE0,0x78,0x70,0xFC,0x3F,0xCE,0x0F,0x87, +// ''' +0x27,0x01,0x02,0x07,0x02,0x07, +0xFF,0xFC, +// '(' +0x28,0x01,0x05,0x15,0x02,0x09, +0x19,0x8C,0xC6,0x31,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x0C,0x61,0x80, +// ')' +0x29,0x01,0x05,0x15,0x02,0x09, +0xC3,0x18,0x63,0x18,0x43,0x18,0xC6,0x31,0x8C,0x46,0x31,0x98,0xCC,0x00, +// '*' +0x2A,0x01,0x0B,0x0A,0x00,0x0C, +0x04,0x00,0x83,0x11,0xBA,0xE1,0xF0,0x3E,0x1D,0x76,0x23,0x04,0x00,0x80, +// '+' +0x2B,0x03,0x10,0x10,0x03,0x14, +0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0xFF,0xFF,0xFF,0xFF,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80, +// ',' +0x2C,0x10,0x03,0x06,0x02,0x08, +0x6D,0xBD,0x80, +// '-' +0x2D,0x0B,0x06,0x02,0x01,0x09, +0xFF,0xF0, +// '.' +0x2E,0x10,0x02,0x03,0x03,0x08, +0xFC, +// '/' +0x2F,0x01,0x08,0x14,0x00,0x08, +0x03,0x07,0x06,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0xE0,0xC0, +// '0' +0x30,0x01,0x0C,0x12,0x02,0x0F, +0x0F,0x03,0xFC,0x70,0xE6,0x06,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x60,0x67,0x0E,0x3F,0xC0,0xF0, +// '1' +0x31,0x01,0x0A,0x12,0x03,0x0F, +0x3C,0x3F,0x0C,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0, +// '2' +0x32,0x01,0x0C,0x12,0x02,0x0F, +0x3F,0x0F,0xF8,0xC1,0xC0,0x0E,0x00,0x60,0x06,0x00,0x60,0x0C,0x01,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFE, +// '3' +0x33,0x01,0x0C,0x12,0x02,0x0F, +0x3F,0x07,0xFC,0x41,0xC0,0x06,0x00,0x60,0x06,0x00,0x60,0x0C,0x1F,0x81,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x78,0x0E,0xFF,0xC3,0xF0, +// '4' +0x34,0x01,0x0D,0x12,0x01,0x0F, +0x01,0xC0,0x1E,0x00,0xB0,0x0D,0x80,0xCC,0x06,0x60,0x63,0x03,0x18,0x30,0xC3,0x06,0x18,0x31,0x81,0x8F,0xFF,0xFF,0xFC,0x03,0x00,0x18,0x00,0xC0,0x06,0x00, +// '5' +0x35,0x01,0x0B,0x12,0x02,0x0F, +0x7F,0xCF,0xF9,0x80,0x30,0x06,0x00,0xC0,0x1F,0xC3,0xFC,0x41,0xC0,0x1C,0x01,0x80,0x30,0x06,0x00,0xC0,0x3C,0x0E,0xFF,0x8F,0xC0, +// '6' +0x36,0x01,0x0C,0x12,0x02,0x0F, +0x07,0xC1,0xFE,0x38,0x27,0x00,0x60,0x0C,0x00,0xCF,0x8D,0xFC,0xF8,0xEF,0x07,0xE0,0x3E,0x03,0xE0,0x36,0x03,0x70,0x77,0x8E,0x3F,0xC0,0xF8, +// '7' +0x37,0x01,0x0B,0x12,0x02,0x0F, +0xFF,0xFF,0xFC,0x03,0x00,0x60,0x1C,0x03,0x00,0x60,0x18,0x03,0x00,0xE0,0x18,0x03,0x00,0xC0,0x18,0x07,0x00,0xC0,0x18,0x06,0x00, +// '8' +0x38,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x87,0xFE,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x3F,0xC3,0xFC,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x7F,0xE1,0xF8, +// '9' +0x39,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x03,0xFC,0x71,0xCE,0x0E,0xC0,0x6C,0x07,0xC0,0x7C,0x07,0xE0,0xF7,0x1F,0x3F,0xB1,0xF3,0x00,0x30,0x06,0x00,0xE4,0x1C,0x7F,0x83,0xE0, +// ':' +0x3A,0x07,0x02,0x0C,0x03,0x08, +0xFC,0x00,0x3F, +// ';' +0x3B,0x07,0x03,0x0F,0x02,0x08, +0x6D,0x80,0x00,0x0D,0xB7,0xB0, +// '<' +0x3C,0x05,0x0F,0x0D,0x03,0x14, +0x00,0x02,0x00,0x3C,0x03,0xF0,0x3F,0x01,0xF8,0x1F,0x80,0x3C,0x00,0x7E,0x00,0x1F,0x80,0x0F,0xC0,0x03,0xF0,0x00,0xF0,0x00,0x20, +// '=' +0x3D,0x08,0x0F,0x07,0x03,0x14, +0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0x80, +// '>' +0x3E,0x05,0x0F,0x0D,0x03,0x14, +0x80,0x01,0xE0,0x01,0xF8,0x00,0x7E,0x00,0x3F,0x00,0x0F,0xC0,0x07,0x80,0x3F,0x03,0xF0,0x1F,0x81,0xF8,0x07,0x80,0x08,0x00,0x00, +// '?' +0x3F,0x01,0x09,0x12,0x02,0x0D, +0x3E,0x3F,0xB0,0xF0,0x30,0x18,0x0C,0x0C,0x0E,0x0E,0x0E,0x06,0x03,0x01,0x80,0x00,0x00,0x30,0x18,0x0C,0x00, +// '@' +0x40,0x02,0x15,0x15,0x02,0x18, +0x00,0xFC,0x00,0x3F,0xF8,0x03,0xC0,0xF0,0x38,0x01,0xC3,0x80,0x07,0x38,0x79,0x99,0x8F,0xEC,0xFC,0x71,0xE3,0xC7,0x07,0x1E,0x30,0x18,0xF1,0x80,0xC7,0x8C,0x06,0x3C,0x70,0x73,0x71,0xC7,0xB9,0x8F,0xEF,0x8E,0x1E,0x70,0x38,0x00,0x00,0xE0,0x04,0x03,0xC0,0xE0,0x0F,0xFE,0x00,0x0F,0x80,0x00, +// 'A' +0x41,0x01,0x10,0x12,0x00,0x10, +0x03,0xC0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x38,0x1C,0x3F,0xFC,0x3F,0xFC,0x60,0x06,0x60,0x06,0x60,0x06,0xC0,0x03, +// 'B' +0x42,0x01,0x0C,0x12,0x02,0x10, +0xFF,0x0F,0xFC,0xC0,0xEC,0x06,0xC0,0x6C,0x06,0xC0,0x6C,0x0C,0xFF,0x8F,0xFC,0xC0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x06,0xFF,0xEF,0xF8, +// 'C' +0x43,0x01,0x0E,0x12,0x01,0x11, +0x07,0xE0,0x7F,0xE3,0xC1,0xDC,0x01,0x60,0x01,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x60,0x01,0x80,0x07,0x00,0x4F,0x07,0x1F,0xF8,0x1F,0x80, +// 'D' +0x44,0x01,0x0F,0x12,0x02,0x12, +0xFF,0x81,0xFF,0xE3,0x01,0xE6,0x00,0xEC,0x00,0xD8,0x01,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0xF8,0x01,0xB0,0x07,0x60,0x3C,0xFF,0xF1,0xFF,0x00, +// 'E' +0x45,0x01,0x0B,0x12,0x02,0x0F, +0xFF,0xFF,0xFF,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xDF,0xFB,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC, +// 'F' +0x46,0x01,0x0A,0x12,0x02,0x0E, +0xFF,0xFF,0xFC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xFF,0xBF,0xEC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x00, +// 'G' +0x47,0x01,0x0F,0x12,0x01,0x13, +0x07,0xE0,0x3F,0xF0,0xE0,0x73,0x80,0x26,0x00,0x1C,0x00,0x30,0x00,0x60,0x00,0xC0,0x7F,0x80,0xFF,0x00,0x1E,0x00,0x36,0x00,0x6C,0x00,0xDC,0x01,0x9E,0x07,0x1F,0xFC,0x0F,0xE0, +// 'H' +0x48,0x01,0x0D,0x12,0x02,0x12, +0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xFF,0xFF,0xFF,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xC0, +// 'I' +0x49,0x01,0x02,0x12,0x02,0x07, +0xFF,0xFF,0xFF,0xFF,0xF0, +// 'J' +0x4A,0x01,0x06,0x17,0xFE,0x07, +0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x1B,0xEF,0x00, +// 'K' +0x4B,0x01,0x0F,0x12,0x02,0x10, +0xC0,0x71,0x81,0xC3,0x07,0x06,0x1C,0x0C,0x70,0x19,0xC0,0x37,0x00,0x7C,0x00,0xF8,0x01,0xB0,0x03,0x38,0x06,0x38,0x0C,0x38,0x18,0x38,0x30,0x38,0x60,0x38,0xC0,0x39,0x80,0x38, +// 'L' +0x4C,0x01,0x0B,0x12,0x02,0x0D, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC, +// 'M' +0x4D,0x01,0x10,0x12,0x02,0x15, +0xE0,0x07,0xF0,0x0F,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xD8,0x1B,0xCC,0x33,0xCC,0x33,0xCC,0x33,0xC6,0x63,0xC6,0x63,0xC7,0xE3,0xC3,0xC3,0xC3,0xC3,0xC1,0x83,0xC0,0x03,0xC0,0x03,0xC0,0x03, +// 'N' +0x4E,0x01,0x0D,0x12,0x02,0x12, +0xE0,0x1F,0x80,0xFC,0x07,0xF0,0x3D,0x81,0xE6,0x0F,0x30,0x78,0xC3,0xC6,0x1E,0x18,0xF0,0xC7,0x83,0x3C,0x19,0xE0,0x6F,0x03,0x78,0x0F,0xC0,0x7E,0x01,0xC0, +// 'O' +0x4F,0x01,0x10,0x12,0x01,0x13, +0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x06,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xE0, +// 'P' +0x50,0x01,0x0B,0x12,0x02,0x0E, +0xFF,0x1F,0xFB,0x07,0x60,0x3C,0x07,0x80,0xF0,0x1E,0x0E,0xFF,0xDF,0xE3,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00, +// 'Q' +0x51,0x01,0x10,0x15,0x01,0x13, +0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x07,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xF0,0x00,0x38,0x00,0x18,0x00,0x0C, +// 'R' +0x52,0x01,0x0D,0x12,0x02,0x11, +0xFF,0x07,0xFE,0x30,0x31,0x80,0xCC,0x06,0x60,0x33,0x01,0x98,0x18,0xFF,0xC7,0xFC,0x30,0x71,0x81,0x8C,0x06,0x60,0x33,0x01,0xD8,0x06,0xC0,0x36,0x00,0xC0, +// 'S' +0x53,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x87,0xFE,0x70,0x6C,0x00,0xC0,0x0C,0x00,0xC0,0x07,0x00,0x7F,0x01,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x3C,0x0E,0xFF,0xE3,0xF8, +// 'T' +0x54,0x01,0x0E,0x12,0x00,0x0F, +0xFF,0xFF,0xFF,0xF0,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00, +// 'U' +0x55,0x01,0x0D,0x12,0x02,0x12, +0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0D,0x80,0xCE,0x0E,0x3F,0xE0,0x7C,0x00, +// 'V' +0x56,0x01,0x10,0x12,0x00,0x10, +0xC0,0x03,0x60,0x06,0x60,0x06,0x60,0x06,0x30,0x0C,0x30,0x0C,0x38,0x1C,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x07,0x60,0x03,0xC0,0x03,0xC0,0x03,0xC0, +// 'W' +0x57,0x01,0x16,0x12,0x01,0x18, +0xC0,0x78,0x0F,0x01,0xE0,0x36,0x07,0x81,0x98,0x1E,0x06,0x60,0xEC,0x19,0x83,0x30,0x63,0x0C,0xC3,0x0C,0x33,0x0C,0x30,0xCE,0x30,0xC6,0x18,0xC1,0x98,0x66,0x06,0x61,0x98,0x19,0x86,0x60,0x6C,0x0D,0x80,0xF0,0x3C,0x03,0xC0,0xF0,0x0F,0x03,0xC0,0x38,0x07,0x00, +// 'X' +0x58,0x01,0x0F,0x12,0x01,0x11, +0x70,0x0E,0x60,0x18,0x60,0x60,0xE1,0xC0,0xC7,0x00,0xCC,0x01,0xF0,0x01,0xE0,0x03,0x80,0x07,0x80,0x1F,0x00,0x37,0x00,0xC6,0x03,0x86,0x0E,0x0E,0x18,0x0C,0x60,0x0D,0xC0,0x1C, +// 'Y' +0x59,0x01,0x0E,0x12,0x00,0x0F, +0xE0,0x1D,0x80,0x63,0x03,0x0E,0x1C,0x18,0x60,0x33,0x00,0xFC,0x01,0xE0,0x07,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00, +// 'Z' +0x5A,0x01,0x0E,0x12,0x01,0x10, +0xFF,0xFF,0xFF,0xF0,0x01,0x80,0x0E,0x00,0x70,0x01,0x80,0x0C,0x00,0x60,0x03,0x80,0x1C,0x00,0x60,0x03,0x00,0x18,0x00,0xE0,0x07,0x00,0x18,0x00,0xFF,0xFF,0xFF,0xF0, +// '[' +0x5B,0x01,0x05,0x15,0x02,0x09, +0xFF,0xF1,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0xFF,0x80, +// '\' +0x5C,0x01,0x08,0x14,0x00,0x08, +0xC0,0xE0,0x60,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x06,0x06,0x06,0x07,0x03, +// ']' +0x5D,0x01,0x05,0x15,0x02,0x09, +0xFF,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC7,0xFF,0x80, +// '^' +0x5E,0x01,0x0F,0x07,0x03,0x14, +0x03,0x80,0x0F,0x80,0x3B,0x80,0xE3,0x83,0x83,0x8E,0x03,0xB8,0x03,0x80, +// '_' +0x5F,0x17,0x0C,0x02,0x00,0x0C, +0xFF,0xFF,0xFF, +// '`' +0x60,0x00,0x06,0x04,0x02,0x0C, +0x60,0xC1,0x83, +// 'a' +0x61,0x06,0x0B,0x0D,0x01,0x0E, +0x3F,0x0F,0xF9,0x03,0x00,0x30,0x06,0x3F,0xDF,0xFF,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6, +// 'b' +0x62,0x01,0x0C,0x12,0x02,0x0F, +0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0xF8,0xFF,0xCF,0x0E,0xE0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xE0,0x6F,0x0E,0xFF,0xCC,0xF8, +// 'c' +0x63,0x06,0x0A,0x0D,0x01,0x0D, +0x0F,0x8F,0xF7,0x05,0x80,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x18,0x07,0x04,0xFF,0x0F,0x80, +// 'd' +0x64,0x01,0x0C,0x12,0x01,0x0F, +0x00,0x30,0x03,0x00,0x30,0x03,0x00,0x31,0xF3,0x3F,0xF7,0x0F,0x60,0x7C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0F,0x3F,0xF1,0xF3, +// 'e' +0x65,0x06,0x0C,0x0D,0x01,0x0E, +0x0F,0x83,0xFC,0x70,0xE6,0x07,0xC0,0x3F,0xFF,0xFF,0xFC,0x00,0xC0,0x06,0x00,0x70,0x23,0xFE,0x0F,0xC0, +// 'f' +0x66,0x01,0x08,0x12,0x01,0x08, +0x0F,0x1F,0x38,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +// 'g' +0x67,0x06,0x0C,0x12,0x01,0x0F, +0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x72,0x0E,0x3F,0xC1,0xF8, +// 'h' +0x68,0x01,0x0B,0x12,0x02,0x0F, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x9F,0x3F,0xF7,0x87,0xE0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0C, +// 'i' +0x69,0x01,0x02,0x12,0x02,0x07, +0xFC,0x3F,0xFF,0xFF,0xF0, +// 'j' +0x6A,0x01,0x05,0x17,0xFF,0x07, +0x18,0xC6,0x00,0x0C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x33,0xFB,0x80, +// 'k' +0x6B,0x01,0x0C,0x12,0x02,0x0E, +0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x1C,0xC3,0x8C,0x70,0xCE,0x0D,0xC0,0xF8,0x0F,0x80,0xDC,0x0C,0xE0,0xC7,0x0C,0x38,0xC1,0xCC,0x0E, +// 'l' +0x6C,0x01,0x02,0x12,0x02,0x06, +0xFF,0xFF,0xFF,0xFF,0xF0, +// 'm' +0x6D,0x06,0x14,0x0D,0x02,0x18, +0xCF,0x87,0xCF,0xFC,0xFE,0xF0,0xF8,0x7E,0x07,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x30, +// 'n' +0x6E,0x06,0x0B,0x0D,0x02,0x0F, +0xCF,0x9F,0xFB,0xC3,0xF0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x06, +// 'o' +0x6F,0x06,0x0C,0x0D,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80, +// 'p' +0x70,0x06,0x0C,0x12,0x02,0x0F, +0xCF,0x8F,0xFC,0xF0,0xEE,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3E,0x06,0xF0,0xEF,0xFC,0xCF,0x8C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00, +// 'q' +0x71,0x06,0x0C,0x12,0x01,0x0F, +0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x30,0x03,0x00,0x30,0x03, +// 'r' +0x72,0x06,0x08,0x0D,0x02,0x0A, +0xCF,0xFF,0xF0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +// 's' +0x73,0x06,0x0B,0x0D,0x01,0x0C, +0x3F,0x0F,0xF3,0x82,0x60,0x0C,0x00,0xF0,0x0F,0xC0,0x3C,0x00,0xC0,0x1A,0x07,0x7F,0xC7,0xF0, +// 't' +0x74,0x02,0x08,0x11,0x00,0x09, +0x30,0x30,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x1F,0x0F, +// 'u' +0x75,0x06,0x0B,0x0D,0x02,0x0F, +0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6, +// 'v' +0x76,0x06,0x0D,0x0D,0x01,0x0F, +0xC0,0x1B,0x01,0x98,0x0C,0xC0,0x63,0x06,0x18,0x30,0x63,0x03,0x18,0x18,0xC0,0x6C,0x03,0x60,0x1F,0x00,0x70,0x00, +// 'w' +0x77,0x06,0x12,0x0D,0x01,0x14, +0xC1,0xE0,0xF0,0x78,0x36,0x1E,0x19,0x87,0x86,0x63,0x31,0x9C,0xCC,0xE3,0x33,0x30,0xCC,0xCC,0x36,0x1B,0x07,0x87,0x81,0xE1,0xE0,0x78,0x78,0x1C,0x0E,0x00, +// 'x' +0x78,0x06,0x0D,0x0D,0x01,0x0F, +0xE0,0x3B,0x83,0x8E,0x38,0x31,0x80,0xD8,0x07,0xC0,0x1C,0x01,0xF0,0x1D,0xC0,0xC6,0x0C,0x18,0xE0,0xEE,0x03,0x80, +// 'y' +0x79,0x06,0x0D,0x12,0x01,0x0F, +0xC0,0x1B,0x01,0x98,0x0C,0xE0,0xE3,0x06,0x18,0x70,0x63,0x03,0x18,0x0D,0x80,0x6C,0x03,0xE0,0x0E,0x00,0x70,0x03,0x00,0x18,0x01,0x80,0x7C,0x03,0xC0,0x00, +// 'z' +0x7A,0x06,0x0B,0x0D,0x01,0x0D, +0xFF,0xFF,0xFC,0x03,0x00,0xE0,0x38,0x0E,0x03,0x80,0xE0,0x38,0x0E,0x01,0x80,0x7F,0xFF,0xFE, +// '{' +0x7B,0x01,0x09,0x16,0x03,0x0F, +0x03,0x83,0xC3,0x81,0x80,0xC0,0x60,0x30,0x18,0x0C,0x0E,0x3E,0x1F,0x01,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0xC0,0x78,0x1C, +// '|' +0x7C,0x01,0x02,0x18,0x03,0x08, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '}' +0x7D,0x01,0x09,0x16,0x03,0x0F, +0xE0,0x78,0x0E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0E,0x03,0xE1,0xF1,0xC0,0xC0,0x60,0x30,0x18,0x0C,0x06,0x07,0x0F,0x07,0x00, +// '~' +0x7E,0x09,0x0F,0x05,0x03,0x14, +0x00,0x00,0x7C,0x05,0xFE,0x1E,0x1F,0xE0,0x0F,0x80, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/SmallFont.c b/libs/ili9341/src/SmallFont.c new file mode 100644 index 0000000..663f59c --- /dev/null +++ b/libs/ili9341/src/SmallFont.c @@ -0,0 +1,120 @@ +// SmallFont.c +// Font type : Full (95 characters) +// Font size : 8x12 pixels +// Memory usage : 1144 bytes + +#if defined(__AVR__) + #include + #define fontdatatype const uint8_t +#elif defined(__PIC32MX__) + #define PROGMEM + #define fontdatatype const unsigned char +#elif defined(__arm__) + #define PROGMEM + #define fontdatatype const unsigned char +#endif + +const unsigned char tft_SmallFont[1144] = +{ +0x08,0x0C,0x20,0x5F, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // +0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, // ! +0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " +0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00, // # +0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00, // $ +0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00, // % +0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00, // & +0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' +0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00, // ( +0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00, // ) +0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00, // * +0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00, // + +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80, // , +0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // - +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, // . +0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00, // / + +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // 0 +0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // 1 +0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, // 2 +0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00, // 3 +0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00, // 4 +0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00, // 5 +0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00, // 6 +0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00, // 7 +0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, // 8 +0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00, // : +0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00, // ; +0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // < +0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, // = +0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // > +0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, // ? + +0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00, // @ +0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00, // A +0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00, // B +0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00, // C +0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00, // D +0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00, // E +0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00, // F +0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00, // G +0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00, // H +0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // I +0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00, // J +0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00, // K +0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00, // L +0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // M +0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00, // N +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // O + +0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00, // P +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00, // Q +0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00, // R +0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00, // S +0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // T +0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, // U +0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00, // V +0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00, // W +0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00, // X +0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // Y +0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00, // Z +0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, // [ +0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00, // +0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, // ] +0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, // _ + +0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00, // a +0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00, // c +0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00, // e +0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00, // f +0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38, // g +0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00, // h +0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, // i +0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0, // j +0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00, // k +0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // l +0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // m +0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00, // n +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00, // o + +0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0, // p +0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C, // q +0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00, // r +0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00, // s +0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00, // t +0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00, // u +0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00, // v +0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00, // w +0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00, // x +0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0, // y +0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00, // z +0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00, // { +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // | +0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00, // } +0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ +}; diff --git a/libs/ili9341/src/Ubuntu16.c b/libs/ili9341/src/Ubuntu16.c new file mode 100644 index 0000000..4f75855 --- /dev/null +++ b/libs/ili9341/src/Ubuntu16.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Ubuntu16.c +// Point Size : 16 +// Memory usage : 1433 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +const unsigned char tft_Ubuntu16[] = +{ +0x00, 0x10, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x0D,0x00,0x00,0x00,0x04, + +// '!' +0x21,0x02,0x01,0x0B,0x01,0x04, +0xFC,0x60, +// '"' +0x22,0x00,0x04,0x04,0x01,0x07, +0x99,0x99, +// '#' +0x23,0x02,0x09,0x0B,0x01,0x0B, +0x11,0x08,0x84,0x5F,0xF2,0x21,0x10,0x89,0xFF,0x44,0x22,0x11,0x00, +// '$' +0x24,0x00,0x07,0x10,0x01,0x09, +0x10,0x20,0xF6,0x08,0x10,0x18,0x08,0x0C,0x0C,0x08,0x3F,0xC2,0x04,0x00, +// '%' +0x25,0x02,0x0C,0x0B,0x01,0x0E, +0x70,0x4D,0x88,0x89,0x08,0x90,0xDA,0x07,0x4E,0x05,0xB0,0x91,0x09,0x11,0x1B,0x20,0xE0, +// '&' +0x26,0x02,0x0A,0x0B,0x01,0x0B, +0x3C,0x18,0x84,0x21,0x08,0x2C,0x0C,0x04,0x8A,0x10,0x83,0x30,0xC7,0xC8, +// ''' +0x27,0x00,0x01,0x04,0x01,0x04, +0xF0, +// '(' +0x28,0x00,0x04,0x10,0x01,0x05, +0x02,0x44,0x48,0x88,0x88,0x84,0x44,0x20, +// ')' +0x29,0x00,0x04,0x10,0x00,0x05, +0x04,0x22,0x21,0x11,0x11,0x12,0x22,0x40, +// '*' +0x2A,0x02,0x09,0x06,0x00,0x08, +0x08,0x24,0x8F,0x83,0x81,0x41,0x10, +// '+' +0x2B,0x05,0x07,0x07,0x01,0x09, +0x10,0x20,0x47,0xF1,0x02,0x04,0x00, +// ',' +0x2C,0x0B,0x02,0x05,0x00,0x04, +0x54,0x80, +// '-' +0x2D,0x08,0x04,0x01,0x01,0x06, +0xF0, +// '.' +0x2E,0x0B,0x01,0x02,0x01,0x04, +0xC0, +// '/' +0x2F,0x00,0x07,0x10,0x00,0x06, +0x02,0x08,0x10,0x20,0x81,0x02,0x08,0x10,0x40,0x81,0x04,0x08,0x10,0x40, +// '0' +0x30,0x02,0x07,0x0B,0x01,0x09, +0x38,0x8B,0x1C,0x18,0x30,0x60,0xC1,0x86,0x88,0xE0, +// '1' +0x31,0x02,0x04,0x0B,0x01,0x09, +0x13,0x59,0x11,0x11,0x11,0x10, +// '2' +0x32,0x02,0x06,0x0B,0x01,0x09, +0x7A,0x30,0x41,0x08,0x21,0x08,0x42,0x0F,0xC0, +// '3' +0x33,0x02,0x07,0x0B,0x01,0x09, +0x78,0x08,0x08,0x10,0x47,0x01,0x01,0x02,0x0B,0xE0, +// '4' +0x34,0x02,0x07,0x0B,0x01,0x09, +0x04,0x18,0x51,0x22,0x48,0xA1,0x7F,0x04,0x08,0x10, +// '5' +0x35,0x02,0x07,0x0B,0x01,0x09, +0x7E,0x81,0x02,0x07,0x81,0x80,0x81,0x02,0x0B,0xE0, +// '6' +0x36,0x02,0x07,0x0B,0x01,0x09, +0x1C,0x61,0x00,0x0F,0x90,0xA0,0xC1,0x82,0x88,0xE0, +// '7' +0x37,0x02,0x07,0x0B,0x01,0x09, +0xFE,0x04,0x10,0x40,0x82,0x04,0x08,0x20,0x40,0x80, +// '8' +0x38,0x02,0x07,0x0B,0x01,0x09, +0x39,0x8A,0x0C,0x14,0x47,0x11,0x41,0x83,0x89,0xE0, +// '9' +0x39,0x02,0x07,0x0B,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x28,0x4F,0x81,0x04,0x11,0xC0, +// ':' +0x3A,0x05,0x01,0x08,0x01,0x04, +0xC3, +// ';' +0x3B,0x05,0x02,0x0B,0x00,0x04, +0x50,0x05,0x48, +// '<' +0x3C,0x05,0x08,0x07,0x01,0x09, +0x02,0x0C,0x30,0x60,0x30,0x0C,0x02, +// '=' +0x3D,0x06,0x07,0x04,0x01,0x09, +0xFE,0x00,0x07,0xF0, +// '>' +0x3E,0x05,0x09,0x07,0x00,0x09, +0x40,0x1C,0x01,0x80,0x70,0x61,0xC1,0x00, +// '?' +0x3F,0x02,0x06,0x0B,0x01,0x07, +0x78,0x30,0x41,0x18,0xC2,0x00,0x00,0x82,0x00, +// '@' +0x40,0x02,0x0D,0x0D,0x01,0x0F, +0x0F,0x81,0x83,0x10,0x0C,0x8F,0xA8,0x84,0xC8,0x26,0x41,0x32,0x09,0x88,0x5A,0x3F,0x90,0x00,0x60,0x00,0xFC,0x00, +// 'A' +0x41,0x02,0x0B,0x0B,0x00,0x0B, +0x04,0x01,0xC0,0x28,0x08,0x81,0x10,0x61,0x08,0x21,0xFC,0x60,0x48,0x0B,0x00,0x80, +// 'B' +0x42,0x02,0x08,0x0B,0x01,0x0A, +0xF8,0x86,0x82,0x82,0x86,0xFC,0x82,0x81,0x81,0x82,0xFC, +// 'C' +0x43,0x02,0x09,0x0B,0x01,0x0B, +0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x01,0x00,0x40,0x30,0x07,0xC0, +// 'D' +0x44,0x02,0x09,0x0B,0x01,0x0B, +0xFC,0x41,0x20,0x50,0x18,0x0C,0x06,0x03,0x01,0x81,0x41,0x3F,0x00, +// 'E' +0x45,0x02,0x07,0x0B,0x01,0x09, +0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x03,0xF8, +// 'F' +0x46,0x02,0x07,0x0B,0x01,0x09, +0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x02,0x00, +// 'G' +0x47,0x02,0x09,0x0B,0x01,0x0B, +0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x03,0x01,0x40,0xB0,0x47,0xE0, +// 'H' +0x48,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xC0,0x60,0x30,0x18,0x0F,0xFE,0x03,0x01,0x80,0xC0,0x60,0x20, +// 'I' +0x49,0x02,0x01,0x0B,0x01,0x03, +0xFF,0xE0, +// 'J' +0x4A,0x02,0x07,0x0B,0x00,0x08, +0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x02,0x09,0xE0, +// 'K' +0x4B,0x02,0x09,0x0B,0x01,0x0A, +0x81,0x41,0x23,0x12,0x0A,0x06,0x02,0xC1,0x10,0x86,0x40,0xA0,0x20, +// 'L' +0x4C,0x02,0x07,0x0B,0x01,0x08, +0x81,0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x03,0xF8, +// 'M' +0x4D,0x02,0x0B,0x0B,0x01,0x0D, +0x40,0x4C,0x19,0x01,0x28,0xA5,0x14,0x94,0xB2,0x9C,0x33,0x84,0x30,0x06,0x00,0x80, +// 'N' +0x4E,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xE0,0x68,0x32,0x19,0x0C,0x46,0x13,0x05,0x82,0xC0,0xE0,0x20, +// 'O' +0x4F,0x02,0x0B,0x0B,0x01,0x0D, +0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x7C,0x00, +// 'P' +0x50,0x02,0x08,0x0B,0x01,0x0A, +0xFC,0x82,0x81,0x81,0x81,0x82,0xFC,0x80,0x80,0x80,0x80, +// 'Q' +0x51,0x02,0x0B,0x0E,0x01,0x0D, +0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x78,0x02,0x00,0x30,0x01,0x80, +// 'R' +0x52,0x02,0x09,0x0B,0x01,0x0A, +0xFC,0x41,0x20,0x50,0x28,0x14,0x13,0xF1,0x08,0x82,0x40,0xA0,0x20, +// 'S' +0x53,0x02,0x08,0x0B,0x01,0x09, +0x3C,0xC2,0x80,0x80,0x40,0x1C,0x06,0x02,0x02,0x06,0x78, +// 'T' +0x54,0x02,0x09,0x0B,0x00,0x09, +0xFF,0x84,0x02,0x01,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00, +// 'U' +0x55,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xA0,0x8F,0x80, +// 'V' +0x56,0x02,0x09,0x0B,0x00,0x09, +0x80,0xE0,0xD0,0x48,0x26,0x21,0x10,0x88,0x28,0x14,0x0E,0x02,0x00, +// 'W' +0x57,0x02,0x0D,0x0B,0x00,0x0D, +0x80,0x0E,0x10,0xD0,0x84,0x8E,0x24,0x51,0x22,0x88,0xA2,0x85,0x14,0x38,0xE0,0xC2,0x04,0x10, +// 'X' +0x58,0x02,0x09,0x0B,0x00,0x09, +0xC1,0xA0,0x88,0x86,0xC1,0x40,0x60,0x70,0x6C,0x22,0x20,0xB0,0x60, +// 'Y' +0x59,0x02,0x09,0x0B,0x00,0x09, +0x80,0xA0,0x90,0x44,0x41,0x40,0xA0,0x20,0x10,0x08,0x04,0x02,0x00, +// 'Z' +0x5A,0x02,0x07,0x0B,0x01,0x09, +0xFE,0x04,0x10,0x41,0x02,0x08,0x00,0x41,0x03,0xF8, +// '[' +0x5B,0x00,0x03,0x10,0x02,0x05, +0xF2,0x49,0x24,0x92,0x49,0x27, +// '\' +0x5C,0x00,0x07,0x10,0x00,0x06, +0x80,0x81,0x02,0x02,0x04,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x81,0x01, +// ']' +0x5D,0x00,0x03,0x10,0x00,0x05, +0xE4,0x92,0x49,0x24,0x92,0x4F, +// '^' +0x5E,0x02,0x07,0x06,0x01,0x09, +0x10,0x70,0xA2,0x24,0x50,0x40, +// '_' +0x5F,0x0F,0x08,0x01,0x00,0x08, +0xFF, +// '`' +0x60,0x01,0x04,0x03,0x01,0x06, +0x86,0x10, +// 'a' +0x61,0x05,0x06,0x08,0x01,0x08, +0x78,0x30,0x5F,0xC6,0x18,0x5F, +// 'b' +0x62,0x01,0x07,0x0C,0x01,0x09, +0x81,0x02,0x04,0x0F,0x90,0xA0,0xC1,0x83,0x06,0x17,0xC0, +// 'c' +0x63,0x05,0x06,0x08,0x01,0x08, +0x3D,0x08,0x20,0x82,0x04,0x0F, +// 'd' +0x64,0x01,0x07,0x0C,0x01,0x09, +0x02,0x04,0x08,0x13,0xE8,0x60,0xC1,0x83,0x05,0x09,0xF0, +// 'e' +0x65,0x05,0x07,0x08,0x01,0x09, +0x3C,0x8A,0x0F,0xF8,0x10,0x10,0x1E, +// 'f' +0x66,0x01,0x05,0x0C,0x01,0x06, +0x7E,0x21,0x0F,0xC2,0x10,0x84,0x21,0x00, +// 'g' +0x67,0x05,0x07,0x0B,0x01,0x09, +0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x0B,0xE0, +// 'h' +0x68,0x01,0x07,0x0C,0x01,0x09, +0x81,0x02,0x04,0x0F,0x90,0xE0,0xC1,0x83,0x06,0x0C,0x10, +// 'i' +0x69,0x01,0x03,0x0C,0x00,0x03, +0x48,0x04,0x92,0x49,0x20, +// 'j' +0x6A,0x01,0x04,0x0F,0xFF,0x03, +0x22,0x00,0x22,0x22,0x22,0x22,0x22,0xC0, +// 'k' +0x6B,0x01,0x06,0x0C,0x01,0x08, +0x82,0x08,0x20,0x8A,0x4A,0x30,0xA2,0x48,0xA1, +// 'l' +0x6C,0x01,0x04,0x0C,0x01,0x04, +0x88,0x88,0x88,0x88,0x88,0x86, +// 'm' +0x6D,0x05,0x0B,0x08,0x01,0x0D, +0xFB,0xD1,0x8E,0x10,0xC2,0x18,0x43,0x08,0x61,0x0C,0x21, +// 'n' +0x6E,0x05,0x07,0x08,0x01,0x09, +0xFD,0x0E,0x0C,0x18,0x30,0x60,0xC1, +// 'o' +0x6F,0x05,0x08,0x08,0x01,0x0A, +0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C, +// 'p' +0x70,0x05,0x07,0x0B,0x01,0x09, +0xF9,0x0A,0x0C,0x18,0x30,0x61,0x7C,0x81,0x02,0x00, +// 'q' +0x71,0x05,0x07,0x0B,0x01,0x09, +0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x04,0x08, +// 'r' +0x72,0x05,0x05,0x08,0x01,0x06, +0xFC,0x21,0x08,0x42,0x10, +// 's' +0x73,0x05,0x05,0x08,0x01,0x07, +0x7C,0x20,0xC3,0x04,0x3E, +// 't' +0x74,0x02,0x05,0x0B,0x01,0x07, +0x84,0x21,0xF8,0x42,0x10,0x84,0x1E, +// 'u' +0x75,0x05,0x07,0x08,0x01,0x09, +0x83,0x06,0x0C,0x18,0x30,0x50,0xBF, +// 'v' +0x76,0x05,0x07,0x08,0x00,0x07, +0x83,0x05,0x12,0x22,0x85,0x0E,0x08, +// 'w' +0x77,0x05,0x0D,0x08,0x00,0x0D, +0x82,0x0C,0x10,0x51,0xC4,0x8A,0x26,0x5B,0x14,0x50,0xE3,0x82,0x08, +// 'x' +0x78,0x05,0x08,0x08,0x00,0x08, +0xC3,0x66,0x24,0x18,0x18,0x24,0x42,0xC3, +// 'y' +0x79,0x05,0x07,0x0B,0x00,0x07, +0x82,0x89,0x12,0x22,0x85,0x04,0x08,0x10,0x43,0x00, +// 'z' +0x7A,0x05,0x06,0x08,0x01,0x08, +0xFC,0x10,0x84,0x21,0x08,0x3F, +// '{' +0x7B,0x00,0x05,0x10,0x00,0x05, +0x19,0x08,0x42,0x10,0x98,0x61,0x08,0x42,0x10,0x83, +// '|' +0x7C,0x00,0x01,0x10,0x02,0x05, +0xFF,0xFF, +// '}' +0x7D,0x00,0x05,0x10,0x00,0x05, +0xC1,0x08,0x42,0x10,0x83,0x31,0x08,0x42,0x10,0x98, +// '~' +0x7E,0x07,0x07,0x02,0x01,0x09, +0x73,0x18, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/comic24.c b/libs/ili9341/src/comic24.c new file mode 100644 index 0000000..2e534c9 --- /dev/null +++ b/libs/ili9341/src/comic24.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// comic.c +// Point Size : 24 +// Memory usage : 2814 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_Comic24[] = +{ +0x00, 0x19, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x15,0x00,0x00,0x00,0x07, + +// '!' +0x21,0x02,0x02,0x14,0x01,0x06, +0xFF,0xFF,0xFF,0xFC,0x2D, +// '"' +0x22,0x03,0x06,0x08,0x02,0x0A, +0xCF,0x3C,0xF3,0xCF,0x3C,0xF3, +// '#' +0x23,0x03,0x14,0x12,0x01,0x14, +0x01,0x81,0x80,0x18,0x18,0x01,0x81,0x80,0x30,0x30,0x03,0x03,0x07,0xFF,0xFF,0x7F,0xFF,0xF0,0x60,0x60,0x06,0x06,0x00,0xC0,0xC0,0x0C,0x0C,0x0F,0xFF,0xFE,0xFF,0xFF,0xE1,0x81,0x80,0x18,0x18,0x03,0x83,0x00,0x30,0x30,0x03,0x03,0x00, +// '$' +0x24,0x00,0x0B,0x19,0x02,0x11, +0x0C,0x01,0x80,0x30,0x0F,0x83,0xFC,0xD9,0xBB,0x06,0x60,0xCC,0x19,0x83,0xB0,0x3F,0x83,0xFC,0x1B,0x83,0x18,0x63,0x0C,0x71,0x9F,0x37,0x7F,0xC3,0xF0,0x18,0x03,0x00,0x60,0x0C,0x00, +// '%' +0x25,0x01,0x11,0x14,0x02,0x14, +0x00,0x00,0x00,0x0C,0x0E,0x0E,0x0F,0x86,0x0C,0x67,0x06,0x33,0x03,0x19,0x80,0xF9,0x80,0x38,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x31,0xE0,0x39,0xF8,0x19,0xCE,0x1C,0xC3,0x0C,0x61,0x86,0x39,0xC6,0x0F,0xC3,0x03,0xC0, +// '&' +0x26,0x03,0x0F,0x13,0x01,0x10, +0x01,0xC0,0x07,0xC0,0x19,0x80,0x33,0x00,0x6E,0x00,0xF8,0x01,0xE0,0x07,0x80,0x1F,0x8C,0x73,0x19,0xC3,0x37,0x07,0xEC,0x07,0xD8,0x07,0x30,0x0E,0x38,0x7E,0x3F,0xEC,0x3F,0x0C,0x00,0x18, +// ''' +0x27,0x03,0x02,0x06,0x03,0x09, +0xFF,0xF0, +// '(' +0x28,0x02,0x07,0x18,0x01,0x09, +0x06,0x1C,0x71,0xC3,0x0E,0x18,0x30,0xE1,0x83,0x06,0x0C,0x18,0x30,0x60,0xE0,0xC1,0x83,0x83,0x83,0x87,0x83, +// ')' +0x29,0x02,0x06,0x18,0x02,0x09, +0xC3,0x86,0x0C,0x30,0x61,0x86,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x61,0x86,0x31,0xCE,0x30, +// '*' +0x2A,0x03,0x0B,0x09,0x01,0x0D, +0x0C,0x01,0x83,0xBF,0xFF,0xF3,0xFC,0x3C,0x0F,0xC3,0x9C,0x61,0x80, +// '+' +0x2B,0x09,0x0A,0x0A,0x00,0x0C, +0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00, +// ',' +0x2C,0x13,0x04,0x06,0x02,0x07, +0x37,0x66,0xEC, +// '-' +0x2D,0x0E,0x08,0x02,0x01,0x0A, +0xFF,0xFF, +// '.' +0x2E,0x12,0x03,0x03,0x02,0x06, +0xFF,0x80, +// '/' +0x2F,0x01,0x0A,0x15,0x01,0x0C, +0x00,0x00,0x30,0x0C,0x06,0x01,0x80,0x60,0x30,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x18,0x0E,0x03,0x00,0xC0,0x00, +// '0' +0x30,0x03,0x0D,0x12,0x01,0x0F, +0x0F,0x80,0xFF,0x0E,0x18,0xE0,0x66,0x03,0x70,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x03,0xB0,0x19,0x81,0xC7,0x1C,0x3F,0xC0,0x7C,0x00, +// '1' +0x31,0x03,0x06,0x12,0x03,0x0B, +0x10,0xC7,0x3C,0xB0,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0xFF,0xF0, +// '2' +0x32,0x03,0x0B,0x12,0x02,0x0F, +0x1F,0x07,0xFB,0xC3,0xE0,0x30,0x06,0x00,0xC0,0x38,0x0E,0x07,0x81,0xE0,0xF8,0x3C,0x07,0x01,0xC0,0x30,0x06,0x00,0xFF,0xDF,0xFC, +// '3' +0x33,0x03,0x0B,0x12,0x02,0x0F, +0x1F,0x0F,0xF9,0xC3,0x80,0x30,0x06,0x00,0xC0,0x78,0x7E,0x0F,0x80,0x78,0x03,0x80,0x30,0x06,0x00,0xF0,0x1F,0x0E,0x7F,0x83,0xE0, +// '4' +0x34,0x03,0x0D,0x12,0x02,0x0F, +0x01,0xC0,0x0E,0x00,0xF0,0x0F,0x80,0x6C,0x07,0x60,0x33,0x03,0x98,0x38,0xC1,0x86,0x1C,0x31,0xFF,0xFF,0xFF,0x80,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00, +// '5' +0x35,0x02,0x0C,0x13,0x02,0x0F, +0x00,0x0F,0xFE,0xFF,0xE6,0x00,0x60,0x0E,0x00,0xEF,0x8F,0xFC,0xF8,0x6E,0x07,0xC0,0x30,0x03,0x00,0x30,0x03,0x00,0x7C,0x06,0xE1,0xE7,0xFC,0x3F,0x00, +// '6' +0x36,0x03,0x0C,0x12,0x01,0x0F, +0x03,0x00,0x70,0x0E,0x01,0xC0,0x38,0x03,0x00,0x60,0x06,0xF8,0xFF,0xEE,0x0E,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0E,0x3F,0xC1,0xF8, +// '7' +0x37,0x02,0x0D,0x13,0x01,0x0F, +0x00,0x07,0xFF,0xFF,0xFE,0x00,0xE0,0x0E,0x00,0x60,0x06,0x00,0x30,0x03,0x80,0x18,0x01,0xC0,0x0C,0x00,0x60,0x07,0x00,0x30,0x03,0x80,0x18,0x00,0xC0,0x04,0x00, +// '8' +0x38,0x02,0x0C,0x13,0x01,0x0F, +0x00,0x00,0xFC,0x3F,0xE3,0x07,0x60,0x36,0x03,0x60,0x37,0x8F,0x3F,0xE1,0xFE,0x38,0xE7,0x07,0x60,0x36,0x03,0x60,0x36,0x03,0x30,0x63,0xFE,0x0F,0x80, +// '9' +0x39,0x03,0x0D,0x13,0x01,0x0F, +0x0F,0x01,0xFE,0x1C,0x38,0xC0,0xCC,0x07,0x60,0x1B,0x00,0xD8,0x06,0xE0,0x73,0x87,0x8F,0xF8,0x3E,0xC0,0x0E,0x00,0x60,0x07,0x00,0xF0,0x1F,0x03,0xE0,0x1C,0x00, +// ':' +0x3A,0x09,0x03,0x0B,0x02,0x07, +0xFF,0x80,0x00,0xFF,0x80, +// ';' +0x3B,0x09,0x04,0x0E,0x02,0x07, +0xEE,0xE0,0x00,0x00,0x03,0x7E,0xCC, +// '<' +0x3C,0x09,0x07,0x0A,0x01,0x09, +0x06,0x1C,0x71,0xC7,0x1E,0x1E,0x0E,0x0E,0x0C, +// '=' +0x3D,0x0A,0x09,0x09,0x01,0x0C, +0xFF,0xFF,0xC0,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x00, +// '>' +0x3E,0x08,0x08,0x0B,0x01,0x0A, +0x60,0x70,0x38,0x3C,0x1E,0x0F,0x06,0x0C,0x38,0x70,0xC0, +// '?' +0x3F,0x04,0x0B,0x12,0x01,0x0D, +0x1E,0x0F,0xE3,0xC6,0x60,0x60,0x06,0x00,0xC0,0x18,0x07,0x01,0xE0,0xF8,0x3E,0x0F,0x01,0x80,0x00,0x00,0x01,0x80,0x30,0x06,0x00, +// '@' +0x40,0x02,0x13,0x14,0x01,0x16, +0x03,0xF8,0x01,0xFF,0xC0,0x78,0x3C,0x1C,0x01,0xC3,0x00,0x1C,0xC1,0xC1,0x98,0xF8,0x1E,0x3C,0x03,0xC6,0x30,0x79,0x8E,0x0F,0x31,0xC1,0xE6,0x78,0x6C,0x7F,0xFC,0xC7,0x3E,0x18,0x00,0x01,0x80,0x00,0x38,0x00,0x03,0xC0,0xE0,0x1F,0xFC,0x00,0xFE,0x00, +// 'A' +0x41,0x03,0x0E,0x12,0x01,0x11, +0x00,0x80,0x07,0x00,0x1C,0x00,0xF0,0x03,0xC0,0x1D,0x80,0x76,0x03,0x98,0x0E,0x20,0x70,0xC1,0xFF,0x0F,0xFC,0x7C,0x19,0xC0,0x67,0x01,0xB8,0x07,0xE0,0x0F,0x00,0x30, +// 'B' +0x42,0x03,0x0B,0x13,0x03,0x0F, +0x7C,0x1F,0xE3,0x0E,0x60,0xEC,0x0D,0x81,0xB0,0x36,0x0E,0xC3,0x9F,0xE3,0xFC,0x61,0xEC,0x0F,0x80,0xF0,0x1E,0x0E,0xC7,0xDF,0xE3,0xF0,0x00, +// 'C' +0x43,0x03,0x0D,0x12,0x01,0x0E, +0x01,0xF8,0x3F,0xC3,0xC6,0x38,0x31,0x80,0x1C,0x01,0xC0,0x0C,0x00,0x60,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x19,0x81,0xCE,0x3C,0x3F,0xC0,0xF8,0x00, +// 'D' +0x44,0x03,0x0D,0x12,0x02,0x11, +0x60,0x07,0xC0,0x37,0x81,0x8F,0x0C,0x1C,0x60,0x73,0x01,0xD8,0x06,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x1B,0x01,0xDC,0x1C,0xFF,0xC1,0xF8,0x00, +// 'E' +0x45,0x03,0x0D,0x12,0x02,0x0F, +0xFF,0xF7,0xFF,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x7E,0xFF,0xF7,0xE0,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0x7F,0xF1,0xFF,0x80, +// 'F' +0x46,0x03,0x0C,0x12,0x02,0x0F, +0xFF,0xCF,0xFF,0xC0,0x7C,0x00,0xC0,0x0C,0x00,0xC0,0x0D,0xFE,0xFF,0xEF,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00, +// 'G' +0x47,0x03,0x0F,0x12,0x01,0x10, +0x03,0xE0,0x0F,0xF0,0x38,0xE0,0xE0,0x03,0x80,0x06,0x00,0x18,0x00,0x30,0x00,0x61,0xFF,0x9F,0xFF,0x3C,0x36,0x00,0x6C,0x01,0x98,0x07,0x30,0x0C,0x30,0x70,0x7F,0xC0,0x3E,0x00, +// 'H' +0x48,0x03,0x0F,0x12,0x02,0x12, +0xC0,0x03,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0xFF,0xFF,0xFF,0xFC,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0C, +// 'I' +0x49,0x03,0x0C,0x12,0x00,0x0D, +0xFF,0xEF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0xFF,0xFF,0xFF, +// 'J' +0x4A,0x03,0x0E,0x12,0x01,0x10, +0x1F,0xFC,0x7F,0xF0,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0xC0,0xC3,0x06,0x0E,0x18,0x1C,0x60,0x3F,0x80,0x3C,0x00, +// 'K' +0x4B,0x03,0x0C,0x12,0x03,0x0F, +0xC0,0x6C,0x0E,0xC1,0xCC,0x38,0xC7,0x0C,0xE0,0xDC,0x0F,0x80,0xF0,0x0F,0x00,0xF8,0x0F,0xC0,0xDE,0x0C,0xF0,0xC7,0x8C,0x1E,0xC0,0xFC,0x07, +// 'L' +0x4C,0x03,0x0B,0x12,0x01,0x0D, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFC, +// 'M' +0x4D,0x03,0x13,0x13,0x01,0x15, +0x0C,0x06,0x01,0x80,0xC0,0x78,0x3C,0x0F,0x07,0x81,0xE0,0xF0,0x3C,0x1E,0x07,0x83,0xC1,0xD8,0xEC,0x3B,0x1D,0x87,0x63,0xB0,0xCC,0xE6,0x38,0xDC,0x47,0x1B,0x8C,0xE3,0xF1,0xB8,0x3C,0x37,0x07,0x86,0xE0,0xF0,0x7C,0x1E,0x0F,0x01,0x81,0x80, +// 'N' +0x4E,0x03,0x11,0x12,0x01,0x13, +0x60,0x01,0x38,0x00,0xDE,0x00,0x6F,0x00,0x37,0xC0,0x1B,0x70,0x0D,0x9C,0x06,0xCF,0x03,0x63,0x81,0xB0,0xE0,0xD8,0x38,0x6C,0x0E,0x36,0x03,0x9B,0x00,0xED,0x80,0x3E,0xC0,0x0F,0x60,0x03,0xB0,0x00,0xC0, +// 'O' +0x4F,0x03,0x11,0x12,0x01,0x13, +0x01,0xF8,0x03,0xFF,0x07,0x81,0xC3,0x00,0x63,0x00,0x1B,0x80,0x0D,0x80,0x07,0xC0,0x03,0xC0,0x01,0xE0,0x00,0xF0,0x00,0xF8,0x00,0x6C,0x00,0x33,0x00,0x31,0xC0,0x38,0x70,0x78,0x1F,0xF8,0x03,0xF0,0x00, +// 'P' +0x50,0x03,0x0B,0x12,0x01,0x0D, +0xFE,0x1F,0xF3,0x0F,0x60,0x7C,0x07,0x80,0xF0,0x1E,0x06,0xC3,0xDF,0xF3,0xF8,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00, +// 'Q' +0x51,0x03,0x14,0x17,0x01,0x15, +0x01,0xF8,0x00,0x7F,0xE0,0x1E,0x07,0x03,0x80,0x18,0x30,0x01,0xC6,0x00,0x0C,0x60,0x00,0xEC,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0x60,0xE0,0xE7,0x0F,0x0C,0x38,0x79,0xC1,0xC3,0xF8,0x0F,0xFF,0x00,0x3F,0x78,0x00,0x03,0xC0,0x00,0x1E,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x20, +// 'R' +0x52,0x02,0x0D,0x13,0x01,0x0F, +0x00,0x03,0xE0,0x3F,0xC1,0x8F,0x0C,0x0E,0x60,0x33,0x00,0xD8,0x06,0xC0,0x36,0x03,0xB0,0x79,0xFF,0x8F,0xF0,0x7F,0x83,0x1F,0x18,0x3C,0xC0,0xF6,0x01,0xF0,0x06, +// 'S' +0x53,0x03,0x0F,0x13,0x01,0x11, +0x01,0xF0,0x07,0xF8,0x18,0x70,0x60,0x01,0x80,0x03,0x00,0x06,0x00,0x0E,0x00,0x0F,0xF0,0x07,0xF0,0x00,0xF0,0x00,0x70,0x00,0x60,0x00,0xD8,0x01,0xB8,0x06,0x78,0x3C,0x7F,0xE0,0x3F,0x00, +// 'T' +0x54,0x02,0x0F,0x13,0x01,0x10, +0x00,0x01,0xFF,0xFD,0xFF,0xF8,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00, +// 'U' +0x55,0x03,0x11,0x12,0x01,0x12, +0x60,0x03,0x30,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x33,0x00,0x19,0x80,0x0C,0xC0,0x06,0x60,0x03,0x30,0x01,0x98,0x01,0xCC,0x00,0xC7,0x00,0x61,0x80,0x70,0xE0,0x30,0x38,0x38,0x0F,0xF8,0x01,0xF0,0x00, +// 'V' +0x56,0x03,0x0E,0x13,0x02,0x10, +0x80,0x0F,0x00,0x3C,0x01,0xB0,0x06,0x60,0x31,0x80,0xC6,0x03,0x0C,0x18,0x30,0x60,0xC1,0x81,0x8C,0x06,0x30,0x0D,0x80,0x36,0x00,0xF8,0x01,0xC0,0x07,0x00,0x08,0x00,0x00,0x00, +// 'W' +0x57,0x03,0x17,0x12,0x01,0x19, +0xC0,0x20,0x0F,0xC0,0x60,0x19,0x81,0xC0,0x23,0x03,0x80,0xC6,0x07,0x01,0x86,0x1E,0x03,0x0C,0x36,0x0C,0x18,0x6C,0x18,0x11,0x98,0x60,0x33,0x30,0xC0,0x66,0x61,0x80,0xD8,0x66,0x01,0xB0,0xCC,0x01,0xC1,0xB0,0x03,0x83,0x60,0x07,0x07,0x80,0x0C,0x07,0x00,0x08,0x0E,0x00, +// 'X' +0x58,0x03,0x10,0x12,0x01,0x11, +0x60,0x03,0x70,0x07,0x38,0x0E,0x1C,0x1C,0x0C,0x1C,0x0E,0x38,0x07,0x70,0x03,0xE0,0x01,0xC0,0x03,0xC0,0x07,0xE0,0x07,0x70,0x0E,0x38,0x1C,0x18,0x38,0x1C,0x70,0x0E,0xE0,0x07,0xC0,0x03, +// 'Y' +0x59,0x03,0x0F,0x13,0x00,0x10, +0x60,0x06,0xE0,0x1D,0xC0,0x31,0xC0,0xE1,0xC1,0x83,0x83,0x03,0x8C,0x07,0x18,0x07,0x70,0x0F,0xC0,0x0F,0x80,0x0F,0x00,0x1C,0x00,0x38,0x00,0x60,0x01,0xC0,0x03,0x00,0x06,0x00,0x08,0x00, +// 'Z' +0x5A,0x03,0x0F,0x12,0x01,0x11, +0xFF,0xFF,0xFF,0xFC,0x00,0xF0,0x03,0x80,0x0E,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x07,0x00,0x1E,0x00,0x38,0x00,0xE0,0x03,0xC0,0x07,0x00,0x1C,0x00,0x70,0x00,0xFF,0xFF,0xFF,0xFC, +// '[' +0x5B,0x01,0x07,0x1A,0x01,0x09, +0x00,0xFD,0xFB,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x3F,0x7E,0x00, +// '\' +0x5C,0x03,0x0B,0x14,0x02,0x0D, +0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x20,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x60, +// ']' +0x5D,0x01,0x07,0x1A,0x02,0x09, +0x01,0xFB,0xF0,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x7E,0xFC,0x00, +// '^' +0x5E,0x02,0x0A,0x06,0x02,0x0E, +0x0C,0x07,0x83,0xF1,0xCE,0xE1,0xF0,0x30, +// '_' +0x5F,0x16,0x0F,0x04,0x00,0x0F, +0x00,0x01,0xFF,0xFF,0xFF,0xF8,0x00,0x00, +// '`' +0x60,0x02,0x05,0x06,0x02,0x0D, +0xC7,0x1C,0x63,0x8C, +// 'a' +0x61,0x09,0x0B,0x0C,0x01,0x0C, +0x0F,0x87,0xF9,0xE3,0x30,0x6E,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xCC,0x39,0xFF,0x9F,0x30, +// 'b' +0x62,0x02,0x0C,0x13,0x01,0x0E, +0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x78,0x7F,0xC7,0x8E,0x60,0x76,0x03,0x60,0x36,0x03,0x60,0x36,0x06,0x70,0xE7,0xFC,0x7F,0x00, +// 'c' +0x63,0x09,0x0A,0x0C,0x01,0x0C, +0x0F,0x07,0xF3,0x0D,0x80,0x60,0x30,0x0C,0x03,0x00,0xC0,0x1C,0x33,0xFC,0x7C, +// 'd' +0x64,0x02,0x0C,0x13,0x01,0x0E, +0x00,0x20,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x61,0xF6,0x3F,0xE7,0x0E,0x60,0x6C,0x06,0xC0,0x6C,0x06,0xC0,0x6E,0x06,0x70,0xE3,0xFE,0x1F,0x60, +// 'e' +0x65,0x09,0x0B,0x0C,0x01,0x0D, +0x1F,0x07,0xF9,0xC7,0x30,0xEC,0x79,0xBE,0x3E,0x07,0x00,0xC0,0x6E,0x1D,0xFF,0x0F,0x80, +// 'f' +0x66,0x02,0x0A,0x14,0x01,0x0C, +0x03,0x83,0xE0,0xE0,0x70,0x18,0x06,0x01,0x83,0xFF,0xFF,0xC6,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60, +// 'g' +0x67,0x09,0x0A,0x13,0x02,0x0D, +0x0F,0x0F,0xF7,0x0D,0x83,0xC0,0xF0,0x3C,0x1F,0x07,0xC1,0xD8,0xF7,0xEC,0xF3,0x00,0xC0,0x30,0x18,0x06,0x03,0xBF,0xC7,0xE0, +// 'h' +0x68,0x02,0x0B,0x13,0x01,0x0E, +0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x1E,0x6F,0xEF,0x8D,0xE1,0xB8,0x36,0x06,0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0x80, +// 'i' +0x69,0x04,0x02,0x11,0x03,0x07, +0xF0,0x3F,0xFF,0xFF,0xC0, +// 'j' +0x6A,0x04,0x08,0x18,0x00,0x0A, +0x03,0x03,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xC3,0xE3,0x77,0x7E,0x1C, +// 'k' +0x6B,0x03,0x0B,0x13,0x02,0x0E, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x36,0x0E,0xC7,0x99,0xE3,0x70,0x7E,0x0F,0xE1,0xCE,0x30,0xE6,0x0E,0xC0,0xF8,0x08,0x00,0x00, +// 'l' +0x6C,0x02,0x02,0x13,0x03,0x07, +0xFF,0xFF,0xFF,0xFF,0xFC, +// 'm' +0x6D,0x09,0x10,0x0C,0x01,0x12, +0x67,0x3C,0x6F,0xFE,0x7D,0xEE,0x79,0x86,0x71,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86, +// 'n' +0x6E,0x09,0x0B,0x0C,0x01,0x0D, +0x63,0x8D,0xF9,0xF1,0xBC,0x37,0x06,0xE0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x30, +// 'o' +0x6F,0x09,0x0C,0x0C,0x01,0x0D, +0x0F,0x81,0xFC,0x38,0xC3,0x06,0x60,0x66,0x06,0x60,0x66,0x06,0x60,0xE3,0x1C,0x1F,0x80,0xF0, +// 'p' +0x70,0x08,0x0A,0x14,0x02,0x0D, +0xC0,0x33,0xCF,0xFB,0xC6,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x7C,0x1B,0xFC,0xFE,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00, +// 'q' +0x71,0x08,0x0A,0x14,0x01,0x0C, +0x00,0x03,0xF3,0xFD,0xE3,0x60,0xF8,0x3C,0x0F,0x03,0xC0,0xF0,0x76,0x1D,0xFF,0x1F,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06, +// 'r' +0x72,0x09,0x09,0x0C,0x01,0x0B, +0xCF,0x6F,0xFE,0x7C,0x3C,0x1E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x00, +// 's' +0x73,0x09,0x09,0x0C,0x02,0x0C, +0x03,0x9F,0xDE,0x7C,0x3E,0x07,0xF0,0xFC,0x07,0x01,0xE0,0xFF,0xC7,0xC0, +// 't' +0x74,0x05,0x0A,0x10,0x00,0x0A, +0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30, +// 'u' +0x75,0x09,0x0B,0x0C,0x01,0x0C, +0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xD8,0x19,0xFF,0x1F,0x60, +// 'v' +0x76,0x09,0x0B,0x0D,0x01,0x0C, +0xC0,0x78,0x1F,0x83,0x30,0x67,0x1C,0x63,0x0C,0xE0,0xD8,0x1E,0x03,0xC0,0x30,0x06,0x00,0x00, +// 'w' +0x77,0x09,0x0F,0x0D,0x01,0x11, +0xC1,0x87,0x83,0x0F,0x0E,0x1E,0x1C,0x66,0x7C,0xCC,0xD9,0x99,0x36,0x36,0x6C,0x7C,0xD8,0x70,0xE0,0xE1,0xC0,0x83,0x80,0x00,0x00, +// 'x' +0x78,0x09,0x0D,0x0D,0x01,0x0E, +0x60,0x1B,0x81,0xCE,0x1C,0x39,0xC0,0xFC,0x03,0xC0,0x3C,0x03,0xF0,0x39,0xC3,0x87,0x38,0x1D,0x80,0x70,0x01,0x80, +// 'y' +0x79,0x09,0x0C,0x13,0x00,0x0D, +0xC0,0x3E,0x07,0x60,0x67,0x0C,0x30,0xC3,0x98,0x19,0x81,0xD8,0x0F,0x00,0xF0,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x30,0x00, +// 'z' +0x7A,0x09,0x0B,0x0C,0x01,0x0D, +0xFF,0xFF,0xFC,0x07,0x00,0xC0,0x30,0x0C,0x03,0x80,0xE0,0x38,0x0E,0x03,0xFF,0xFF,0xF0, +// '{' +0x7B,0x02,0x08,0x18,0x01,0x09, +0x0F,0x1F,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0xE0,0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x38,0x18,0x1F,0x07, +// '|' +0x7C,0x01,0x02,0x18,0x04,0x0A, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '}' +0x7D,0x02,0x08,0x18,0x01,0x09, +0x70,0xF8,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x06,0x07,0x07,0x0E,0x0C,0x0C,0x0C,0x0C,0x0C,0x1C,0x18,0xF8,0xE0, +// '~' +0x7E,0x0B,0x0C,0x05,0x01,0x0E, +0x38,0x37,0xE3,0xE7,0x7C,0x3E,0x01,0xC0, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/def_small.c b/libs/ili9341/src/def_small.c new file mode 100644 index 0000000..54101cd --- /dev/null +++ b/libs/ili9341/src/def_small.c @@ -0,0 +1,332 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// def_small.c +// Point Size : 9 +// Memory usage : 928 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + + +unsigned char tft_def_small[] = +{ +0x00, 0x08, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x08,0x00,0x00,0x00,0x03, + +// '!' +0x21,0x01,0x01,0x07,0x01,0x03, +0xFA, +// '"' +0x22,0x01,0x03,0x02,0x01,0x04, +0xB4, +// '#' +0x23,0x01,0x06,0x07,0x01,0x08, +0x28,0xAF,0xCA,0xFD,0x45,0x00, +// '$' +0x24,0x01,0x06,0x08,0x00,0x06, +0x21,0xEA,0x38,0x38,0xAF,0x08, +// '%' +0x25,0x01,0x08,0x07,0x00,0x09, +0x44,0xA4,0xA8,0x5A,0x15,0x25,0x22, +// '&' +0x26,0x01,0x06,0x07,0x01,0x08, +0x31,0x04,0x19,0x9E,0x66,0xC0, +// ''' +0x27,0x01,0x01,0x02,0x01,0x02, +0xC0, +// '(' +0x28,0x00,0x02,0x08,0x01,0x04, +0x4A,0xA1, +// ')' +0x29,0x00,0x02,0x08,0x01,0x04, +0x85,0x52, +// '*' +0x2A,0x01,0x05,0x04,0x00,0x05, +0xAB,0x9D,0x50, +// '+' +0x2B,0x03,0x05,0x05,0x01,0x08, +0x21,0x3E,0x42,0x00, +// ',' +0x2C,0x07,0x01,0x02,0x01,0x03, +0xC0, +// '-' +0x2D,0x05,0x02,0x01,0x01,0x03, +0xC0, +// '.' +0x2E,0x07,0x01,0x01,0x01,0x03, +0x80, +// '/' +0x2F,0x01,0x03,0x07,0x00,0x03, +0x25,0x25,0x20, +// '0' +0x30,0x01,0x04,0x07,0x01,0x06, +0x69,0x99,0x99,0x60, +// '1' +0x31,0x01,0x03,0x07,0x02,0x06, +0xC9,0x24,0xB8, +// '2' +0x32,0x01,0x05,0x07,0x01,0x06, +0x64,0x84,0x44,0x43,0xC0, +// '3' +0x33,0x01,0x04,0x07,0x01,0x06, +0x69,0x16,0x11,0x60, +// '4' +0x34,0x01,0x05,0x07,0x01,0x06, +0x11,0x94,0xA9,0x7C,0x40, +// '5' +0x35,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8E,0x11,0xE0, +// '6' +0x36,0x01,0x04,0x07,0x01,0x06, +0x7C,0x8E,0x99,0x60, +// '7' +0x37,0x01,0x04,0x07,0x01,0x06, +0xF1,0x22,0x24,0x40, +// '8' +0x38,0x01,0x04,0x07,0x01,0x06, +0x69,0x96,0x99,0x60, +// '9' +0x39,0x01,0x04,0x07,0x01,0x06, +0x69,0x97,0x13,0xE0, +// ':' +0x3A,0x03,0x01,0x05,0x01,0x03, +0x88, +// ';' +0x3B,0x03,0x01,0x06,0x01,0x03, +0x8C, +// '<' +0x3C,0x03,0x06,0x05,0x01,0x08, +0x04,0xEE,0x0E,0x04, +// '=' +0x3D,0x04,0x06,0x03,0x01,0x08, +0xFC,0x0F,0xC0, +// '>' +0x3E,0x03,0x06,0x05,0x01,0x08, +0x81,0xC1,0xDC,0x80, +// '?' +0x3F,0x01,0x04,0x07,0x01,0x05, +0xE1,0x24,0x40,0x40, +// '@' +0x40,0x01,0x08,0x08,0x01,0x0A, +0x3C,0x42,0x9D,0xA5,0xA5,0x9E,0x40,0x38, +// 'A' +0x41,0x01,0x06,0x07,0x00,0x06, +0x30,0xC4,0x92,0x7A,0x18,0x40, +// 'B' +0x42,0x01,0x05,0x07,0x01,0x07, +0xF4,0x63,0xE8,0xC7,0xC0, +// 'C' +0x43,0x01,0x05,0x07,0x01,0x07, +0x72,0x61,0x08,0x25,0xC0, +// 'D' +0x44,0x01,0x05,0x07,0x01,0x07, +0xF4,0xE3,0x18,0xCF,0xC0, +// 'E' +0x45,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8F,0x88,0xF0, +// 'F' +0x46,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8F,0x88,0x80, +// 'G' +0x47,0x01,0x05,0x07,0x01,0x07, +0x76,0x61,0x38,0xE5,0xC0, +// 'H' +0x48,0x01,0x05,0x07,0x01,0x07, +0x8C,0x63,0xF8,0xC6,0x20, +// 'I' +0x49,0x01,0x01,0x07,0x01,0x03, +0xFE, +// 'J' +0x4A,0x01,0x02,0x09,0x00,0x03, +0x55,0x55,0x80, +// 'K' +0x4B,0x01,0x05,0x07,0x01,0x06, +0x8C,0xA9,0x8A,0x4A,0x20, +// 'L' +0x4C,0x01,0x04,0x07,0x01,0x05, +0x88,0x88,0x88,0xF0, +// 'M' +0x4D,0x01,0x06,0x07,0x01,0x08, +0x87,0x3C,0xED,0xB6,0x18,0x40, +// 'N' +0x4E,0x01,0x05,0x07,0x01,0x07, +0x8E,0x73,0x59,0xCE,0x20, +// 'O' +0x4F,0x01,0x05,0x07,0x01,0x07, +0x76,0xE3,0x18,0xED,0xC0, +// 'P' +0x50,0x01,0x04,0x07,0x01,0x06, +0xE9,0x9E,0x88,0x80, +// 'Q' +0x51,0x01,0x05,0x08,0x01,0x07, +0x76,0xE3,0x18,0xE9,0xC2, +// 'R' +0x52,0x01,0x05,0x07,0x01,0x06, +0xE4,0xA5,0xCA,0x4A,0x20, +// 'S' +0x53,0x01,0x06,0x07,0x01,0x07, +0x72,0x28,0x1C,0x0A,0x27,0x00, +// 'T' +0x54,0x01,0x05,0x07,0x00,0x05, +0xF9,0x08,0x42,0x10,0x80, +// 'U' +0x55,0x01,0x05,0x07,0x01,0x07, +0x8C,0x63,0x18,0xC5,0xC0, +// 'V' +0x56,0x01,0x06,0x07,0x00,0x06, +0x86,0x14,0x92,0x48,0xC3,0x00, +// 'W' +0x57,0x01,0x09,0x07,0xFF,0x07, +0x49,0x24,0x8A,0x85,0x43,0xE0,0xA0,0x50, +// 'X' +0x58,0x01,0x06,0x07,0x00,0x06, +0xCD,0x23,0x0C,0x31,0x28,0xC0, +// 'Y' +0x59,0x01,0x05,0x07,0x00,0x05, +0x8A,0x9C,0x42,0x10,0x80, +// 'Z' +0x5A,0x01,0x05,0x07,0x00,0x05, +0xF8,0x44,0x44,0x43,0xE0, +// '[' +0x5B,0x01,0x02,0x08,0x01,0x04, +0xEA,0xAB, +// '\' +0x5C,0x01,0x03,0x07,0x00,0x03, +0x91,0x24,0x48, +// ']' +0x5D,0x01,0x02,0x08,0x01,0x04, +0xD5,0x57, +// '^' +0x5E,0x01,0x06,0x02,0x01,0x08, +0x31,0x20, +// '_' +0x5F,0x09,0x05,0x01,0x00,0x05, +0xF8, +// '`' +0x60,0x00,0x02,0x02,0x01,0x05, +0x90, +// 'a' +0x61,0x03,0x04,0x05,0x01,0x06, +0x61,0x79,0xF0, +// 'b' +0x62,0x00,0x04,0x08,0x01,0x06, +0x88,0x8E,0x99,0x9E, +// 'c' +0x63,0x03,0x04,0x05,0x01,0x06, +0x78,0x88,0x70, +// 'd' +0x64,0x00,0x04,0x08,0x01,0x06, +0x11,0x17,0x99,0x97, +// 'e' +0x65,0x03,0x04,0x05,0x01,0x06, +0x69,0xF8,0x70, +// 'f' +0x66,0x00,0x04,0x08,0x00,0x03, +0x34,0x4E,0x44,0x44, +// 'g' +0x67,0x03,0x04,0x07,0x01,0x06, +0x79,0x99,0x71,0x60, +// 'h' +0x68,0x00,0x04,0x08,0x01,0x06, +0x88,0x8E,0x99,0x99, +// 'i' +0x69,0x01,0x01,0x07,0x01,0x03, +0xBE, +// 'j' +0x6A,0x01,0x02,0x09,0x00,0x03, +0x45,0x55,0x80, +// 'k' +0x6B,0x00,0x04,0x08,0x01,0x05, +0x88,0x89,0xAC,0xA9, +// 'l' +0x6C,0x00,0x01,0x08,0x01,0x03, +0xFF, +// 'm' +0x6D,0x03,0x07,0x05,0x01,0x09, +0xED,0x26,0x4C,0x99,0x20, +// 'n' +0x6E,0x03,0x04,0x05,0x01,0x06, +0xE9,0x99,0x90, +// 'o' +0x6F,0x03,0x04,0x05,0x01,0x06, +0x69,0x99,0x60, +// 'p' +0x70,0x03,0x04,0x07,0x01,0x06, +0xE9,0x99,0xE8,0x80, +// 'q' +0x71,0x03,0x04,0x07,0x01,0x06, +0x79,0x99,0x71,0x10, +// 'r' +0x72,0x03,0x03,0x05,0x01,0x04, +0xF2,0x48, +// 's' +0x73,0x03,0x04,0x05,0x01,0x05, +0x68,0x62,0xE0, +// 't' +0x74,0x02,0x04,0x06,0x00,0x04, +0x4F,0x44,0x47, +// 'u' +0x75,0x03,0x04,0x05,0x01,0x06, +0x99,0x99,0x70, +// 'v' +0x76,0x03,0x07,0x05,0xFF,0x05, +0x44,0x98,0xA1,0xC1,0x00, +// 'w' +0x77,0x03,0x07,0x05,0x00,0x07, +0x93,0x76,0xBA,0x24,0x40, +// 'x' +0x78,0x03,0x05,0x05,0x00,0x05, +0x8A,0x88,0xA8,0x80, +// 'y' +0x79,0x03,0x07,0x07,0xFF,0x05, +0x44,0x88,0xA1,0xC1,0x02,0x18,0x00, +// 'z' +0x7A,0x03,0x04,0x05,0x01,0x06, +0xF1,0x24,0xF0, +// '{' +0x7B,0x01,0x03,0x08,0x01,0x05, +0x69,0x64,0x93, +// '|' +0x7C,0x01,0x01,0x09,0x01,0x03, +0xFF,0x80, +// '}' +0x7D,0x01,0x03,0x08,0x01,0x05, +0xC9,0x34,0x96, +// '~' +0x7E,0x03,0x06,0x03,0x01,0x08, +0x01,0x91,0x80, + +// Terminator +0xFF +}; diff --git a/libs/ili9341/src/ili9341.c b/libs/ili9341/src/ili9341.c new file mode 100644 index 0000000..9952fc2 --- /dev/null +++ b/libs/ili9341/src/ili9341.c @@ -0,0 +1,2826 @@ +/* TFT module + * + * Author: LoBo (loboris@gmail.com, loboris.github) + * + * Module supporting SPI TFT displays based on ILI9341 controllers +*/ + +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "tft.h" +#include "time.h" +#include +#include "rom/tjpgd.h" +#include "esp_heap_caps.h" +#include "tftspi.h" +#include "mgos.h" + +// Define which spi bus to use VSPI_HOST or HSPI_HOST +#define SPI_BUS VSPI_HOST + +#define DEG_TO_RAD 0.01745329252 +#define RAD_TO_DEG 57.295779513 +#define deg_to_rad 0.01745329252 + 3.14159265359 +#define swap(a, b) { int16_t t = a; a = b; b = t; } +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#if !defined(max) +#define max(A,B) ( (A) > (B) ? (A):(B)) +#endif +#if !defined(min) +#define min(A,B) ( (A) < (B) ? (A):(B)) +#endif + +// Embedded fonts +extern uint8_t tft_SmallFont[]; +extern uint8_t tft_DefaultFont[]; +extern uint8_t tft_Dejavu18[]; +extern uint8_t tft_Dejavu24[]; +extern uint8_t tft_Ubuntu16[]; +extern uint8_t tft_Comic24[]; +extern uint8_t tft_minya24[]; +extern uint8_t tft_tooney32[]; +extern uint8_t tft_def_small[]; + +// ==== Color definitions constants ============== +const color_t ILI9341_BLACK = { 0, 0, 0 }; +const color_t ILI9341_NAVY = { 0, 0, 128 }; +const color_t ILI9341_DARKGREEN = { 0, 128, 0 }; +const color_t ILI9341_DARKCYAN = { 0, 128, 128 }; +const color_t ILI9341_MAROON = { 128, 0, 0 }; +const color_t ILI9341_PURPLE = { 128, 0, 128 }; +const color_t ILI9341_OLIVE = { 128, 128, 0 }; +const color_t ILI9341_LIGHTGREY = { 192, 192, 192 }; +const color_t ILI9341_DARKGREY = { 128, 128, 128 }; +const color_t ILI9341_BLUE = { 0, 0, 255 }; +const color_t ILI9341_GREEN = { 0, 255, 0 }; +const color_t ILI9341_CYAN = { 0, 255, 255 }; +const color_t ILI9341_RED = { 252, 0, 0 }; +const color_t ILI9341_MAGENTA = { 252, 0, 255 }; +const color_t ILI9341_YELLOW = { 252, 252, 0 }; +const color_t ILI9341_WHITE = { 252, 252, 252 }; +const color_t ILI9341_ORANGE = { 252, 164, 0 }; +const color_t ILI9341_GREENYELLOW = { 172, 252, 44 }; +const color_t ILI9341_PINK = { 252, 192, 202 }; +// =============================================== + +// ============================================================== +// ==== Set default values of global variables ================== +uint8_t orientation = LANDSCAPE;// screen orientation +uint16_t font_rotate = 0; // font rotation +uint8_t font_transparent = 0; +uint8_t font_forceFixed = 0; +uint8_t text_wrap = 0; // character wrapping to new line +color_t _fg = { 0, 255, 0}; +color_t _bg = { 0, 0, 0}; +uint8_t image_debug = 0; + +float _angleOffset = DEFAULT_ANGLE_OFFSET; + +int TFT_X = 0; +int TFT_Y = 0; + +dispWin_t dispWin = { + .x1 = 0, + .y1 = 0, + .x2 = DEFAULT_TFT_DISPLAY_WIDTH, + .y2 = DEFAULT_TFT_DISPLAY_HEIGHT, +}; + +Font cfont = { + .font = tft_DefaultFont, + .x_size = 0, + .y_size = 0x0B, + .offset = 0, + .numchars = 95, + .bitmap = 1, +}; + +uint8_t font_buffered_char = 1; +uint8_t font_line_space = 0; +// ============================================================== + + +typedef struct { + uint8_t charCode; + int adjYOffset; + int width; + int height; + int xOffset; + int xDelta; + uint16_t dataPtr; +} propFont; + +static dispWin_t dispWinTemp; + +static uint8_t *userfont = NULL; +static int TFT_OFFSET = 0; +static propFont fontChar; +static float _arcAngleMax = DEFAULT_ARC_ANGLE_MAX; + + +// ========================================================================= +// ** All drawings are clipped to 'dispWin' ** +// ** All x,y coordinates in public functions are relative to clip window ** +// =========== : Public functions +// ----------- : Local functions +// ========================================================================= + + +// Compare two colors; return 0 if equal +//============================================ +int mgos_ili9341_compare_colors(color_t c1, color_t c2) +{ + if ((c1.r & 0xFC) != (c2.r & 0xFC)) return 1; + if ((c1.g & 0xFC) != (c2.g & 0xFC)) return 1; + if ((c1.b & 0xFC) != (c2.b & 0xFC)) return 1; + + return 0; +} + +// draw color pixel on screen +//------------------------------------------------------------------------ +static void _drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { + + if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; + drawPixel(x, y, color, sel); +} + +//==================================================================== +void mgos_ili9341_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { + + _drawPixel(x+dispWin.x1, y+dispWin.y1, color, sel); +} + +//=========================================== +color_t mgos_ili9341_readPixel(int16_t x, int16_t y) { + + if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return ILI9341_BLACK; + + return readPixel(x, y); +} + +//-------------------------------------------------------------------------- +static void _drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { + // clipping + if ((x < dispWin.x1) || (x > dispWin.x2) || (y > dispWin.y2)) return; + if (y < dispWin.y1) { + h -= (dispWin.y1 - y); + y = dispWin.y1; + } + if (h < 0) h = 0; + if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; + if (h == 0) h = 1; + mgos_ili9341_pushColorRep(x, y, x, y+h-1, color, (uint32_t)h); +} + +//-------------------------------------------------------------------------- +static void _drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { + // clipping + if ((y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; + if (x < dispWin.x1) { + w -= (dispWin.x1 - x); + x = dispWin.x1; + } + if (w < 0) w = 0; + if ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1; + if (w == 0) w = 1; + + mgos_ili9341_pushColorRep(x, y, x+w-1, y, color, (uint32_t)w); +} + +//====================================================================== +void mgos_ili9341_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { + _drawFastVLine(x+dispWin.x1, y+dispWin.y1, h, color); +} + +//====================================================================== +void mgos_ili9341_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { + _drawFastHLine(x+dispWin.x1, y+dispWin.y1, w, color); +} + +// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer this uses +// the eficient FastH/V Line draw routine for segments of 2 pixels or more +//---------------------------------------------------------------------------------- +static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) +{ + if (x0 == x1) { + if (y0 <= y1) _drawFastVLine(x0, y0, y1-y0, color); + else _drawFastVLine(x0, y1, y0-y1, color); + return; + } + if (y0 == y1) { + if (x0 <= x1) _drawFastHLine(x0, y0, x1-x0, color); + else _drawFastHLine(x1, y0, x0-x1, color); + return; + } + + int steep = 0; + if (abs(y1 - y0) > abs(x1 - x0)) steep = 1; + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx = x1 - x0, dy = abs(y1 - y0); + int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0; + + if (y0 < y1) ystep = 1; + + // Split into steep and not steep for FastH/V separation + if (steep) { + for (; x0 <= x1; x0++) { + dlen++; + err -= dy; + if (err < 0) { + err += dx; + if (dlen == 1) _drawPixel(y0, xs, color, 1); + else _drawFastVLine(y0, xs, dlen, color); + dlen = 0; y0 += ystep; xs = x0 + 1; + } + } + if (dlen) _drawFastVLine(y0, xs, dlen, color); + } + else + { + for (; x0 <= x1; x0++) { + dlen++; + err -= dy; + if (err < 0) { + err += dx; + if (dlen == 1) _drawPixel(xs, y0, color, 1); + else _drawFastHLine(xs, y0, dlen, color); + dlen = 0; y0 += ystep; xs = x0 + 1; + } + } + if (dlen) _drawFastHLine(xs, y0, dlen, color); + } +} + +//============================================================================== +void mgos_ili9341_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) +{ + _drawLine(x0+dispWin.x1, y0+dispWin.y1, x1+dispWin.x1, y1+dispWin.y1, color); +} + +// fill a rectangle +//-------------------------------------------------------------------------------- +static void _fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { + // clipping + if ((x >= dispWin.x2) || (y > dispWin.y2)) return; + + if (x < dispWin.x1) { + w -= (dispWin.x1 - x); + x = dispWin.x1; + } + if (y < dispWin.y1) { + h -= (dispWin.y1 - y); + y = dispWin.y1; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + + if ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1; + if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; + if (w == 0) w = 1; + if (h == 0) h = 1; + mgos_ili9341_pushColorRep(x, y, x+w-1, y+h-1, color, (uint32_t)(h*w)); +} + +//============================================================================ +void mgos_ili9341_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { + _fillRect(x+dispWin.x1, y+dispWin.y1, w, h, color); +} + +//================================== +void mgos_ili9341_fillScreen(color_t color) { + mgos_ili9341_pushColorRep(0, 0, _width-1, _height-1, color, (uint32_t)(_height*_width)); +} + +//================================== +void mgos_ili9341_fillWindow(color_t color) { + mgos_ili9341_pushColorRep(dispWin.x1, dispWin.y1, dispWin.x2, dispWin.y2, + color, (uint32_t)((dispWin.x2-dispWin.x1+1) * (dispWin.y2-dispWin.y1+1))); +} + +// ^^^============= Basics drawing functions ================================^^^ + + +// ================ Graphics drawing functions ================================== + +//----------------------------------------------------------------------------------- +static void _drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { + _drawFastHLine(x1,y1,w, color); + _drawFastVLine(x1+w-1,y1,h, color); + _drawFastHLine(x1,y1+h-1,w, color); + _drawFastVLine(x1,y1,h, color); +} + +//=============================================================================== +void mgos_ili9341_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { + _drawRect(x1+dispWin.x1, y1+dispWin.y1, w, h, color); +} + +//------------------------------------------------------------------------------------------------- +static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, color_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + disp_select(); + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + _drawPixel(x0 + x, y0 + y, color, 0); + _drawPixel(x0 + y, y0 + x, color, 0); + } + if (cornername & 0x2) { + _drawPixel(x0 + x, y0 - y, color, 0); + _drawPixel(x0 + y, y0 - x, color, 0); + } + if (cornername & 0x8) { + _drawPixel(x0 - y, y0 + x, color, 0); + _drawPixel(x0 - x, y0 + y, color, 0); + } + if (cornername & 0x1) { + _drawPixel(x0 - y, y0 - x, color, 0); + _drawPixel(x0 - x, y0 - y, color, 0); + } + } + disp_deselect(); +} + +// Used to do circles and roundrects +//---------------------------------------------------------------------------------------------------------------- +static void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, color_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + int16_t ylm = x0 - r; + + while (x < y) { + if (f >= 0) { + if (cornername & 0x1) _drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color); + if (cornername & 0x2) _drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color); + ylm = x0 - y; + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if ((x0 - x) > ylm) { + if (cornername & 0x1) _drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color); + if (cornername & 0x2) _drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color); + } + } +} + +// Draw a rounded rectangle +//============================================================================================= +void mgos_ili9341_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) +{ + x += dispWin.x1; + y += dispWin.y1; + + // smarter version + _drawFastHLine(x + r, y, w - 2 * r, color); // Top + _drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom + _drawFastVLine(x, y + r, h - 2 * r, color); // Left + _drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right + + // draw four corners + drawCircleHelper(x + r, y + r, r, 1, color); + drawCircleHelper(x + w - r - 1, y + r, r, 2, color); + drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); + drawCircleHelper(x + r, y + h - r - 1, r, 8, color); +} + +// Fill a rounded rectangle +//============================================================================================= +void mgos_ili9341_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) +{ + x += dispWin.x1; + y += dispWin.y1; + + // smarter version + _fillRect(x + r, y, w - 2 * r, h, color); + + // draw four corners + fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); + fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); +} + + + + +//----------------------------------------------------------------------------------------------- +static void _drawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t length, color_t color) +{ + _drawLine( + x, + y, + x + length * cos((angle + _angleOffset) * DEG_TO_RAD), + y + length * sin((angle + _angleOffset) * DEG_TO_RAD), color); +} + +//--------------------------------------------------------------------------------------------------------------- +static void _DrawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t start, uint16_t length, color_t color) +{ + _drawLine( + x + start * cos((angle + _angleOffset) * DEG_TO_RAD), + y + start * sin((angle + _angleOffset) * DEG_TO_RAD), + x + (start + length) * cos((angle + _angleOffset) * DEG_TO_RAD), + y + (start + length) * sin((angle + _angleOffset) * DEG_TO_RAD), color); +} + +//=========================================================================================================== +void mgos_ili9341_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color) +{ + x += dispWin.x1; + y += dispWin.y1; + + if (start == 0) _drawLineByAngle(x, y, angle, len, color); + else _DrawLineByAngle(x, y, angle, start, len, color); +} + + +// Draw a triangle +//-------------------------------------------------------------------------------------------------------------------- +static void _drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + _drawLine(x0, y0, x1, y1, color); + _drawLine(x1, y1, x2, y2, color); + _drawLine(x2, y2, x0, y0, color); +} + +//================================================================================================================ +void mgos_ili9341_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + x0 += dispWin.x1; + y0 += dispWin.y1; + x1 += dispWin.x1; + y1 += dispWin.y1; + x2 += dispWin.x1; + y2 += dispWin.y1; + + _drawLine(x0, y0, x1, y1, color); + _drawLine(x1, y1, x2, y2, color); + _drawLine(x2, y2, x0, y0, color); +} + +// Fill a triangle +//-------------------------------------------------------------------------------------------------------------------- +static void _fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + if (y1 > y2) { + swap(y2, y1); swap(x2, x1); + } + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + + if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if(x1 < a) a = x1; + else if(x1 > b) b = x1; + if(x2 < a) a = x2; + else if(x2 > b) b = x2; + _drawFastHLine(a, y0, b-a+1, color); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1; + int32_t + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if(y1 == y2) last = y1; // Include y1 scanline + else last = y1-1; // Skip it + + for(y=y0; y<=last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + _drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for(; y<=y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + _drawFastHLine(a, y, b-a+1, color); + } +} + +//================================================================================================================ +void mgos_ili9341_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + _fillTriangle( + x0 + dispWin.x1, y0 + dispWin.y1, + x1 + dispWin.x1, y1 + dispWin.y1, + x2 + dispWin.x1, y2 + dispWin.y1, + color); +} + +//==================================================================== +void mgos_ili9341_drawCircle(int16_t x, int16_t y, int radius, color_t color) { + x += dispWin.x1; + y += dispWin.y1; + int f = 1 - radius; + int ddF_x = 1; + int ddF_y = -2 * radius; + int x1 = 0; + int y1 = radius; + + disp_select(); + _drawPixel(x, y + radius, color, 0); + _drawPixel(x, y - radius, color, 0); + _drawPixel(x + radius, y, color, 0); + _drawPixel(x - radius, y, color, 0); + while(x1 < y1) { + if (f >= 0) { + y1--; + ddF_y += 2; + f += ddF_y; + } + x1++; + ddF_x += 2; + f += ddF_x; + _drawPixel(x + x1, y + y1, color, 0); + _drawPixel(x - x1, y + y1, color, 0); + _drawPixel(x + x1, y - y1, color, 0); + _drawPixel(x - x1, y - y1, color, 0); + _drawPixel(x + y1, y + x1, color, 0); + _drawPixel(x - y1, y + x1, color, 0); + _drawPixel(x + y1, y - x1, color, 0); + _drawPixel(x - y1, y - x1, color, 0); + } + disp_deselect(); +} + +//==================================================================== +void mgos_ili9341_fillCircle(int16_t x, int16_t y, int radius, color_t color) { + x += dispWin.x1; + y += dispWin.y1; + + _drawFastVLine(x, y-radius, 2*radius+1, color); + fillCircleHelper(x, y, radius, 3, 0, color); +} + +//---------------------------------------------------------------------------------------------------------------- +static void _draw_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option) +{ + disp_select(); + // upper right + if ( option & TFT_ELLIPSE_UPPER_RIGHT ) _drawPixel(x0 + x, y0 - y, color, 0); + // upper left + if ( option & TFT_ELLIPSE_UPPER_LEFT ) _drawPixel(x0 - x, y0 - y, color, 0); + // lower right + if ( option & TFT_ELLIPSE_LOWER_RIGHT ) _drawPixel(x0 + x, y0 + y, color, 0); + // lower left + if ( option & TFT_ELLIPSE_LOWER_LEFT ) _drawPixel(x0 - x, y0 + y, color, 0); + disp_deselect(); +} + + +//===================================================================================================== +void mgos_ili9341_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option) +{ + x0 += dispWin.x1; + y0 += dispWin.y1; + + uint16_t x, y; + int32_t xchg, ychg; + int32_t err; + int32_t rxrx2; + int32_t ryry2; + int32_t stopx, stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while( stopx >= stopy ) { + _draw_ellipse_section(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if ( 2*err+xchg > 0 ) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while( stopx <= stopy ) { + _draw_ellipse_section(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if ( 2*err+ychg > 0 ) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + +//----------------------------------------------------------------------------------------------------------------------- +static void _draw_filled_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option) +{ + // upper right + if ( option & TFT_ELLIPSE_UPPER_RIGHT ) _drawFastVLine(x0+x, y0-y, y+1, color); + // upper left + if ( option & TFT_ELLIPSE_UPPER_LEFT ) _drawFastVLine(x0-x, y0-y, y+1, color); + // lower right + if ( option & TFT_ELLIPSE_LOWER_RIGHT ) _drawFastVLine(x0+x, y0, y+1, color); + // lower left + if ( option & TFT_ELLIPSE_LOWER_LEFT ) _drawFastVLine(x0-x, y0, y+1, color); +} + +//===================================================================================================== +void mgos_ili9341_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option) +{ + x0 += dispWin.x1; + y0 += dispWin.y1; + + uint16_t x, y; + int32_t xchg, ychg; + int32_t err; + int32_t rxrx2; + int32_t ryry2; + int32_t stopx, stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while( stopx >= stopy ) { + _draw_filled_ellipse_section(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if ( 2*err+xchg > 0 ) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while( stopx <= stopy ) { + _draw_filled_ellipse_section(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if ( 2*err+ychg > 0 ) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + + +// ==== ARC DRAWING =================================================================== + +//--------------------------------------------------------------------------------------------------------------------------------- +static void _fillArcOffsetted(uint16_t cx, uint16_t cy, uint16_t radius, uint16_t thickness, float start, float end, color_t color) +{ + //float sslope = (float)cos_lookup(start) / (float)sin_lookup(start); + //float eslope = (float)cos_lookup(end) / (float)sin_lookup(end); + float sslope = (cos(start/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(start/_arcAngleMax * 2 * PI) * _arcAngleMax) ; + float eslope = (cos(end/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(end/_arcAngleMax * 2 * PI) * _arcAngleMax); + + if (end == 360) eslope = -1000000; + + int ir2 = (radius - thickness) * (radius - thickness); + int or2 = radius * radius; + + disp_select(); + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + int x2 = x * x; + int y2 = y * y; + + if ( + (x2 + y2 < or2 && x2 + y2 >= ir2) && + ( + (y > 0 && start < 180 && x <= y * sslope) || + (y < 0 && start > 180 && x >= y * sslope) || + (y < 0 && start <= 180) || + (y == 0 && start <= 180 && x < 0) || + (y == 0 && start == 0 && x > 0) + ) && + ( + (y > 0 && end < 180 && x >= y * eslope) || + (y < 0 && end > 180 && x <= y * eslope) || + (y > 0 && end >= 180) || + (y == 0 && end >= 180 && x < 0) || + (y == 0 && start == 0 && x > 0) + ) + ) + _drawPixel(cx+x, cy+y, color, 0); + } + } + disp_deselect(); +} + + +//=========================================================================================================================== +void mgos_ili9341_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor) +{ + cx += dispWin.x1; + cy += dispWin.y1; + + if (th < 1) th = 1; + if (th > r) th = r; + + int f = mgos_ili9341_compare_colors(fillcolor, color); + + float astart = fmodf(start, _arcAngleMax); + float aend = fmodf(end, _arcAngleMax); + + astart += _angleOffset; + aend += _angleOffset; + + if (astart < 0) astart += (float)360; + if (aend < 0) aend += (float)360; + + if (aend == 0) aend = (float)360; + + if (astart > aend) { + _fillArcOffsetted(cx, cy, r, th, astart, _arcAngleMax, fillcolor); + _fillArcOffsetted(cx, cy, r, th, 0, aend, fillcolor); + if (f) { + _fillArcOffsetted(cx, cy, r, 1, astart, _arcAngleMax, color); + _fillArcOffsetted(cx, cy, r, 1, 0, aend, color); + _fillArcOffsetted(cx, cy, r-th, 1, astart, _arcAngleMax, color); + _fillArcOffsetted(cx, cy, r-th, 1, 0, aend, color); + } + } + else { + _fillArcOffsetted(cx, cy, r, th, astart, aend, fillcolor); + if (f) { + _fillArcOffsetted(cx, cy, r, 1, astart, aend, color); + _fillArcOffsetted(cx, cy, r-th, 1, astart, aend, color); + } + } + if (f) { + _drawLine(cx + (r-th) * cos(astart * DEG_TO_RAD), cy + (r-th) * sin(astart * DEG_TO_RAD), + cx + (r-1) * cos(astart * DEG_TO_RAD), cy + (r-1) * sin(astart * DEG_TO_RAD), color); + _drawLine(cx + (r-th) * cos(aend * DEG_TO_RAD), cy + (r-th) * sin(aend * DEG_TO_RAD), + cx + (r-1) * cos(aend * DEG_TO_RAD), cy + (r-1) * sin(aend * DEG_TO_RAD), color); + } +} + +//============================================================================================================= +void mgos_ili9341_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int rot, uint8_t th) +{ + cx += dispWin.x1; + cy += dispWin.y1; + + int deg = rot - _angleOffset; + int f = mgos_ili9341_compare_colors(fill, color); + + if (sides < MIN_POLIGON_SIDES) sides = MIN_POLIGON_SIDES; // This ensures the minimum side number + if (sides > MAX_POLIGON_SIDES) sides = MAX_POLIGON_SIDES; // This ensures the maximum side number + + int Xpoints[sides], Ypoints[sides]; // Set the arrays based on the number of sides entered + int rads = 360 / sides; // This equally spaces the points. + + for (int idx = 0; idx < sides; idx++) { + Xpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * diameter; + Ypoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * diameter; + } + + // Draw the polygon on the screen. + if (f) { + for(int idx = 0; idx < sides; idx++) { + if((idx+1) < sides) _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], fill); + else _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], fill); + } + } + + if (th) { + for (int n=0; n 0) { + for (int idx = 0; idx < sides; idx++) { + Xpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * (diameter-n); + Ypoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * (diameter-n); + } + } + for(int idx = 0; idx < sides; idx++) { + if( (idx+1) < sides) + _drawLine(Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], color); // draw the lines + else + _drawLine(Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], color); // finishes the last line to close up the polygon. + } + } + } +} + +/* +// Similar to the Polygon function. +//===================================================================================== +void mgos_ili9341_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor) +{ + cx += dispWin.x1; + cy += dispWin.y1; + + factor = constrain(factor, 1.0, 4.0); + uint8_t sides = 5; + uint8_t rads = 360 / sides; + + int Xpoints_O[sides], Ypoints_O[sides], Xpoints_I[sides], Ypoints_I[sides];//Xpoints_T[5], Ypoints_T[5]; + + for(int idx = 0; idx < sides; idx++) { + // makes the outer points + Xpoints_O[idx] = cx + sin((float)(idx*rads + 72) * deg_to_rad) * diameter; + Ypoints_O[idx] = cy + cos((float)(idx*rads + 72) * deg_to_rad) * diameter; + // makes the inner points + Xpoints_I[idx] = cx + sin((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor); + // 36 is half of 72, and this will allow the inner and outer points to line up like a triangle. + Ypoints_I[idx] = cy + cos((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor); + } + + for(int idx = 0; idx < sides; idx++) { + if((idx+1) < sides) { + if(fill) {// this part below should be self explanatory. It fills in the star. + _fillTriangle(cx,cy,Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color); + _fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color); + } + else { + _drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color); + _drawLine(Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color); + } + } + else { + if(fill) { + _fillTriangle(cx,cy,Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color); + _fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color); + } + else { + _drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color); + _drawLine(Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color); + } + } + } +} +*/ + +// ================ Font and string functions ================================== + +//-------------------------------------------------------- +static int load_file_font(const char * fontfile, int info) +{ + int err = 0; + + if (userfont != NULL) { + free(userfont); + userfont = NULL; + } + + struct stat sb; + + // Open the file + FILE *fhndl = fopen(fontfile, "r"); + if (!fhndl) { + LOG(LL_ERROR, ("Error opening font file '%s'", fontfile)); + err = 1; + goto exit; + } + + // Get file size + if (stat(fontfile, &sb) != 0) { + LOG(LL_ERROR, ("Error getting font file size")); + err = 2; + goto exit; + } + int fsize = sb.st_size; + if (fsize < 30) { + LOG(LL_ERROR, ("Error getting font file size")); + err = 3; + goto exit; + } + + userfont = malloc(fsize+4); + if (userfont == NULL) { + LOG(LL_ERROR, ("Font memory allocation error")); + fclose(fhndl); + err = 4; + goto exit; + } + + int read = fread(userfont, 1, fsize, fhndl); + + fclose(fhndl); + + if (read != fsize) { + LOG(LL_ERROR, ("Font read error")); + err = 5; + goto exit; + } + + userfont[read] = 0; + if (strstr((char *)(userfont+read-8), "RPH_font") == NULL) { + LOG(LL_ERROR, ("Font ID not found")); + err = 6; + goto exit; + } + + // Check size + int size = 0; + int numchar = 0; + int width = userfont[0]; + int height = userfont[1]; + uint8_t first = 255; + uint8_t last = 0; + //int offst = 0; + int pminwidth = 255; + int pmaxwidth = 0; + + if (width != 0) { + // Fixed font + numchar = userfont[3]; + first = userfont[2]; + last = first + numchar - 1; + size = ((width * height * numchar) / 8) + 4; + } + else { + // Proportional font + size = 4; // point at first char data + uint8_t charCode; + int charwidth; + + do { + charCode = userfont[size]; + charwidth = userfont[size+2]; + + if (charCode != 0xFF) { + numchar++; + if (charwidth != 0) size += ((((charwidth * userfont[size+3])-1) / 8) + 7); + else size += 6; + + if (info) { + if (charwidth > pmaxwidth) pmaxwidth = charwidth; + if (charwidth < pminwidth) pminwidth = charwidth; + if (charCode < first) first = charCode; + if (charCode > last) last = charCode; + } + } + else size++; + } while ((size < (read-8)) && (charCode != 0xFF)); + } + + if (size != (read-8)) { + LOG(LL_ERROR, ("Font size error: found %d expected %d)", size, (read-8))); + err = 7; + goto exit; + } + + if (info) { + if (width != 0) { + LOG(LL_INFO, ("Fixed width font size: %d width: %d height: %d characters: %d (%d~%d)", + size, width, height, numchar, first, last)); + } + else { + LOG(LL_INFO, ("Proportional font size: %d width: %d~%d height: %d characters: %d (%d~%d)", + size, pminwidth, pmaxwidth, height, numchar, first, last)); + } + } + +exit: + if (err) { + if (userfont) { + free(userfont); + userfont = NULL; + } + } + return err; +} + +//------------------------------------------------ +int compile_font_file(char *fontfile, uint8_t dbg) +{ + int err = 0; + char outfile[128] = {'\0'}; + size_t len; + struct stat sb; + FILE *ffd = NULL; + FILE *ffd_out = NULL; + char *sourcebuf = NULL; + + len = strlen(fontfile); + + // check here that filename end with ".c". + if ((len < 3) || (len > 125) || (strcmp(fontfile + len - 2, ".c") != 0)) { + LOG(LL_ERROR, ("not a .c file")); + err = 1; + goto exit; + } + + sprintf(outfile, "%s", fontfile); + sprintf(outfile+strlen(outfile)-1, "fon"); + + // Open the source file + if (stat(fontfile, &sb) != 0) { + LOG(LL_ERROR, ("Error opening source file '%s'", fontfile)); + err = 2; + goto exit; + } + // Open the file + ffd = fopen(fontfile, "rb"); + if (!ffd) { + LOG(LL_ERROR, ("Error opening source file '%s'", fontfile)); + err = 3; + goto exit; + } + + // Open the font file + ffd_out= fopen(outfile, "wb"); + if (!ffd_out) { + LOG(LL_ERROR, ("error opening destination file")); + err = 4; + goto exit; + } + + // Get file size + int fsize = sb.st_size; + if (fsize <= 0) { + LOG(LL_ERROR, ("source file size error")); + err = 5; + goto exit; + } + + sourcebuf = malloc(fsize+4); + if (sourcebuf == NULL) { + LOG(LL_ERROR, ("memory allocation error")); + err = 6; + goto exit; + } + char *fbuf = sourcebuf; + + int rdsize = fread(fbuf, 1, fsize, ffd); + fclose(ffd); + ffd = NULL; + + if (rdsize != fsize) { + LOG(LL_ERROR, ("error reading from source file")); + err = 7; + goto exit; + } + + *(fbuf+rdsize) = '\0'; + + fbuf = strchr(fbuf, '{'); // beginning of font data + char *fend = strstr(fbuf, "};"); // end of font data + + if ((fbuf == NULL) || (fend == NULL) || ((fend-fbuf) < 22)) { + LOG(LL_ERROR, ("wrong source file format")); + err = 8; + goto exit; + } + + fbuf++; + *fend = '\0'; + char hexstr[5] = {'\0'}; + int lastline = 0; + + fbuf = strstr(fbuf, "0x"); + int size = 0; + char *nextline; + char *numptr; + + int bptr = 0; + + while ((fbuf != NULL) && (fbuf < fend) && (lastline == 0)) { + nextline = strchr(fbuf, '\n'); // beginning of the next line + if (nextline == NULL) { + nextline = fend-1; + lastline++; + } + else nextline++; + + while (fbuf < nextline) { + numptr = strstr(fbuf, "0x"); + if ((numptr == NULL) || ((fbuf+4) > nextline)) numptr = strstr(fbuf, "0X"); + if ((numptr != NULL) && ((numptr+4) <= nextline)) { + fbuf = numptr; + if (bptr >= 128) { + // buffer full, write to file + if (fwrite(outfile, 1, 128, ffd_out) != 128) goto error; + bptr = 0; + size += 128; + } + memcpy(hexstr, fbuf, 4); + hexstr[4] = 0; + outfile[bptr++] = (uint8_t)strtol(hexstr, NULL, 0); + fbuf += 4; + } + else fbuf = nextline; + } + fbuf = nextline; + } + + if (bptr > 0) { + size += bptr; + if (fwrite(outfile, 1, bptr, ffd_out) != bptr) goto error; + } + + // write font ID + sprintf(outfile, "RPH_font"); + if (fwrite(outfile, 1, 8, ffd_out) != 8) goto error; + + fclose(ffd_out); + ffd_out = NULL; + + // === Test compiled font === + sprintf(outfile, "%s", fontfile); + sprintf(outfile+strlen(outfile)-1, "fon"); + + uint8_t *uf = userfont; // save userfont pointer + userfont = NULL; + if (load_file_font(outfile, 1) != 0) { + LOG(LL_ERROR, ("Error compiling file!")); + err = 10; + } + else { + free(userfont); + LOG(LL_ERROR, ("File compiled successfully.")); + } + userfont = uf; // restore userfont + + goto exit; + +error: + LOG(LL_ERROR, ("error writing to destination file")); + err = 9; + +exit: + if (sourcebuf) free(sourcebuf); + if (ffd) fclose(ffd); + if (ffd_out) fclose(ffd_out); + + return err; +} + + +// ----------------------------------------------------------------------------------------- +// Individual Proportional Font Character Format: +// ----------------------------------------------------------------------------------------- +// Character Code +// yOffset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] +// ----------------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------------------- +// Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1) +// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) +//--------------------------------------------------------------------------------------------- + +//---------------------------------- +void getFontCharacters(uint8_t *buf) +{ + if (cfont.bitmap == 2) { + //For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available. + for (uint8_t n=0; n < 11; n++) { + buf[n] = n + 0x30; + } + buf[11] = '.'; + buf[12] = '-'; + buf[13] = '/'; + buf[14] = '\0'; + return; + } + + if (cfont.x_size > 0) { + for (uint8_t n=0; n < cfont.numchars; n++) { + buf[n] = cfont.offset + n; + } + buf[cfont.numchars] = '\0'; + return; + } + + uint16_t tempPtr = 4; // point at first char data + uint8_t cc, cw, ch, n; + + n = 0; + cc = cfont.font[tempPtr++]; + while (cc != 0xFF) { + cfont.numchars++; + tempPtr++; + cw = cfont.font[tempPtr++]; + ch = cfont.font[tempPtr++]; + tempPtr++; + tempPtr++; + if (cw != 0) { + // packed bits + tempPtr += (((cw * ch)-1) / 8) + 1; + } + buf[n++] = cc; + cc = cfont.font[tempPtr++]; + } + buf[n] = '\0'; +} + +// Set max width & height of the proportional font +//----------------------------- +static void getMaxWidthHeight() +{ + uint16_t tempPtr = 4; // point at first char data + uint8_t cc, cw, ch, cd, cy; + + cfont.numchars = 0; + cfont.max_x_size = 0; + + cc = cfont.font[tempPtr++]; + while (cc != 0xFF) { + cfont.numchars++; + cy = cfont.font[tempPtr++]; + cw = cfont.font[tempPtr++]; + ch = cfont.font[tempPtr++]; + tempPtr++; + cd = cfont.font[tempPtr++]; + cy += ch; + if (cw > cfont.max_x_size) cfont.max_x_size = cw; + if (cd > cfont.max_x_size) cfont.max_x_size = cd; + if (ch > cfont.y_size) cfont.y_size = ch; + if (cy > cfont.y_size) cfont.y_size = cy; + if (cw != 0) { + // packed bits + tempPtr += (((cw * ch)-1) / 8) + 1; + } + cc = cfont.font[tempPtr++]; + } + cfont.size = tempPtr; +} + +// Return the Glyph data for an individual character in the proportional font +//------------------------------------ +static uint8_t getCharPtr(uint8_t c) { + uint16_t tempPtr = 4; // point at first char data + + do { + fontChar.charCode = cfont.font[tempPtr++]; + if (fontChar.charCode == 0xFF) return 0; + + fontChar.adjYOffset = cfont.font[tempPtr++]; + fontChar.width = cfont.font[tempPtr++]; + fontChar.height = cfont.font[tempPtr++]; + fontChar.xOffset = cfont.font[tempPtr++]; + fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset); + fontChar.xDelta = cfont.font[tempPtr++]; + + if (c != fontChar.charCode && fontChar.charCode != 0xFF) { + if (fontChar.width != 0) { + // packed bits + tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1; + } + } + } while ((c != fontChar.charCode) && (fontChar.charCode != 0xFF)); + + fontChar.dataPtr = tempPtr; + if (c == fontChar.charCode) { + if (font_forceFixed > 0) { + // fix width & offset for forced fixed width + fontChar.xDelta = cfont.max_x_size; + fontChar.xOffset = (fontChar.xDelta - fontChar.width) / 2; + } + } + else return 0; + + return 1; +} + +/* +//----------------------- +static void _testFont() { + if (cfont.x_size) { + printf("FONT TEST: fixed font\r\n"); + return; + } + uint16_t tempPtr = 4; // point at first char data + uint8_t c = 0x20; + for (c=0x20; c <0xFF; c++) { + fontChar.charCode = cfont.font[tempPtr++]; + if (fontChar.charCode == 0xFF) break; + if (fontChar.charCode != c) { + printf("FONT TEST: last sequential char: %d, expected %d\r\n", fontChar.charCode, c); + break; + } + c = fontChar.charCode; + fontChar.adjYOffset = cfont.font[tempPtr++]; + fontChar.width = cfont.font[tempPtr++]; + fontChar.height = cfont.font[tempPtr++]; + fontChar.xOffset = cfont.font[tempPtr++]; + fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset); + fontChar.xDelta = cfont.font[tempPtr++]; + + if (fontChar.charCode != 0xFF) { + if (fontChar.width != 0) { + // packed bits + tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1; + } + } + } + printf("FONT TEST: W=%d H=%d last char: %d [%c]; length: %d\r\n", cfont.max_x_size, cfont.y_size, c, c, tempPtr); +} +*/ + +//=================================================== +void mgos_ili9341_setFont(uint8_t font, const char *font_file) +{ + cfont.font = NULL; + + if (font == FONT_7SEG) { + cfont.bitmap = 2; + cfont.x_size = 24; + cfont.y_size = 6; + cfont.offset = 0; + cfont.color = _fg; + } + else { + if (font == USER_FONT) { + if (load_file_font(font_file, 0) != 0) cfont.font = tft_DefaultFont; + else cfont.font = userfont; + } + else if (font == DEJAVU18_FONT) cfont.font = tft_Dejavu18; + else if (font == DEJAVU24_FONT) cfont.font = tft_Dejavu24; + else if (font == UBUNTU16_FONT) cfont.font = tft_Ubuntu16; + else if (font == COMIC24_FONT) cfont.font = tft_Comic24; + else if (font == MINYA24_FONT) cfont.font = tft_minya24; + else if (font == TOONEY32_FONT) cfont.font = tft_tooney32; + else if (font == SMALL_FONT) cfont.font = tft_SmallFont; + else if (font == DEF_SMALL_FONT) cfont.font = tft_def_small; + else cfont.font = tft_DefaultFont; + + cfont.bitmap = 1; + cfont.x_size = cfont.font[0]; + cfont.y_size = cfont.font[1]; + if (cfont.x_size > 0) { + cfont.offset = cfont.font[2]; + cfont.numchars = cfont.font[3]; + cfont.size = cfont.x_size * cfont.y_size * cfont.numchars; + } + else { + cfont.offset = 4; + getMaxWidthHeight(); + } + //_testFont(); + } +} + +void mgos_ili9341_setFontColor(color_t color) +{ + cfont.color = color; +} + +// ----------------------------------------------------------------------------------------- +// Individual Proportional Font Character Format: +// ----------------------------------------------------------------------------------------- +// Character Code +// yOffset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] +// ----------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// Character drawing rectangle is (0, 0) (xDelta-1, cfont.y_size-1) +// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) +//--------------------------------------------------------------------------------------------- + +// print non-rotated proportional character +// character is already in fontChar +//---------------------------------------------- +static int printProportionalChar(int x, int y) { + uint8_t ch = 0; + int i, j, char_width; + + char_width = ((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta); + + if ((font_buffered_char) && (!font_transparent)) { + int len, bufPos; + + // === buffer Glyph data for faster sending === + len = char_width * cfont.y_size; + color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); + if (color_line) { + // fill with background color + for (int n = 0; n < len; n++) { + color_line[n] = _bg; + } + // set character pixels to foreground color + uint8_t mask = 0x80; + for (j=0; j < fontChar.height; j++) { + for (i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = cfont.font[fontChar.dataPtr++]; + } + if ((ch & mask) != 0) { + // visible pixel + bufPos = ((j + fontChar.adjYOffset) * char_width) + (fontChar.xOffset + i); // bufY + bufX + color_line[bufPos] = _fg; + /* + bufY = (j + fontChar.adjYOffset) * char_width; + bufX = fontChar.xOffset + i; + if ((bufX < 0) || (bufX > char_width)) { + printf("[%c] X ERR: %d\r\n", fontChar.charCode, bufX); + } + bufPos = bufY + bufX; + if ((bufPos < len) && (bufPos > 0)) color_line[bufPos] = _fg; + else printf("[%c] ERR: %d > %d W=%d H=%d bufX=%d bufY=%d X=%d Y=%d\r\n", + fontChar.charCode, bufPos, len, char_width, cfont.y_size, bufX, bufY, fontChar.xOffset + i, j + fontChar.adjYOffset); + */ + } + mask >>= 1; + } + } + // send to display in one transaction + disp_select(); + send_data(x, y, x+char_width-1, y+cfont.y_size-1, len, color_line); + disp_deselect(); + free(color_line); + + return char_width; + } + } + + int cx, cy; + + if (!font_transparent) _fillRect(x, y, char_width+1, cfont.y_size, _bg); + + // draw Glyph + uint8_t mask = 0x80; + disp_select(); + for (j=0; j < fontChar.height; j++) { + for (i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = cfont.font[fontChar.dataPtr++]; + } + + if ((ch & mask) !=0) { + cx = (uint16_t)(x+fontChar.xOffset+i); + cy = (uint16_t)(y+j+fontChar.adjYOffset); + _drawPixel(cx, cy, _fg, 0); + } + mask >>= 1; + } + } + disp_deselect(); + + return char_width; +} + +// non-rotated fixed width character +//---------------------------------------------- +static void printChar(uint8_t c, int x, int y) { + uint8_t i, j, ch, fz, mask; + uint16_t k, temp, cx, cy, len; + + // fz = bytes per char row + fz = cfont.x_size/8; + if (cfont.x_size % 8) fz++; + + // get character position in buffer + temp = ((c-cfont.offset)*((fz)*cfont.y_size))+4; + + if ((font_buffered_char) && (!font_transparent)) { + // === buffer Glyph data for faster sending === + len = cfont.x_size * cfont.y_size; + color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); + if (color_line) { + // fill with background color + for (int n = 0; n < len; n++) { + color_line[n] = _bg; + } + // set character pixels to foreground color + for (j=0; j>= 1; + } + } + temp += (fz); + } + // send to display in one transaction + disp_select(); + send_data(x, y, x+cfont.x_size-1, y+cfont.y_size-1, len, color_line); + disp_deselect(); + free(color_line); + + return; + } + } + + if (!font_transparent) _fillRect(x, y, cfont.x_size, cfont.y_size, _bg); + + disp_select(); + for (j=0; j>= 1; + } + } + temp += (fz); + } + disp_deselect(); +} + +// print rotated proportional character +// character is already in fontChar +//--------------------------------------------------- +static int rotatePropChar(int x, int y, int offset) { + uint8_t ch = 0; + double radian = font_rotate * DEG_TO_RAD; + float cos_radian = cos(radian); + float sin_radian = sin(radian); + + uint8_t mask = 0x80; + disp_select(); + for (int j=0; j < fontChar.height; j++) { + for (int i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = cfont.font[fontChar.dataPtr++]; + } + + int newX = (int)(x + (((offset + i) * cos_radian) - ((j+fontChar.adjYOffset)*sin_radian))); + int newY = (int)(y + (((j+fontChar.adjYOffset) * cos_radian) + ((offset + i) * sin_radian))); + + if ((ch & mask) != 0) _drawPixel(newX,newY,_fg, 0); + else if (!font_transparent) _drawPixel(newX,newY,_bg, 0); + + mask >>= 1; + } + } + disp_deselect(); + + return fontChar.xDelta+1; +} + +// rotated fixed width character +//-------------------------------------------------------- +static void rotateChar(uint8_t c, int x, int y, int pos) { + uint8_t i,j,ch,fz,mask; + uint16_t temp; + int newx,newy; + double radian = font_rotate*0.0175; + float cos_radian = cos(radian); + float sin_radian = sin(radian); + int zz; + + if( cfont.x_size < 8 ) fz = cfont.x_size; + else fz = cfont.x_size/8; + temp=((c-cfont.offset)*((fz)*cfont.y_size))+4; + + disp_select(); + for (j=0; j>= 1; + } + } + temp+=(fz); + } + disp_deselect(); + // calculate x,y for the next char + TFT_X = (int)(x + ((pos+1) * cfont.x_size * cos_radian)); + TFT_Y = (int)(y + ((pos+1) * cfont.x_size * sin_radian)); +} + +//---------------------- +static int _7seg_width() +{ + return (2 * (2 * cfont.y_size + 1)) + cfont.x_size; +} + +//----------------------- +static int _7seg_height() +{ + return (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size); +} + +// Returns the string width in pixels. +// Useful for positions strings on the screen. +//=============================== +int mgos_ili9341_getStringWidth(const char* const str) +{ + int strWidth = 0; + + if (cfont.bitmap == 2) strWidth = ((_7seg_width()+2) * strlen(str)) - 2; // 7-segment font + else if (cfont.x_size != 0) strWidth = strlen(str) * cfont.x_size; // fixed width font + else { + // calculate the width of the string of proportional characters + const char *tempStrptr = str; + while (*tempStrptr != 0) { + if (getCharPtr(*tempStrptr++)) { + strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1); + } + } + strWidth--; + } + return strWidth; +} + +//=============================================== +void mgos_ili9341_clearStringRect(int x, int y, char *str) +{ + int w = mgos_ili9341_getStringWidth(str); + int h = mgos_ili9341_getfontheight(); + mgos_ili9341_fillRect(x+dispWin.x1, y+dispWin.y1, w, h, _bg); +} + +//============================================================================== +/** + * bit-encoded bar position of all digits' bcd segments + * + * 6 + * +-----+ + * 3 | . | 2 + * +--5--+ + * 1 | . | 0 + * +--.--+ + * 4 + */ +static const uint16_t font_bcd[] = { + 0x200, // 0010 0000 0000 // - + 0x080, // 0000 1000 0000 // . + 0x06C, // 0100 0110 1100 // /, degree + 0x05f, // 0000 0101 1111, // 0 + 0x005, // 0000 0000 0101, // 1 + 0x076, // 0000 0111 0110, // 2 + 0x075, // 0000 0111 0101, // 3 + 0x02d, // 0000 0010 1101, // 4 + 0x079, // 0000 0111 1001, // 5 + 0x07b, // 0000 0111 1011, // 6 + 0x045, // 0000 0100 0101, // 7 + 0x07f, // 0000 0111 1111, // 8 + 0x07d, // 0000 0111 1101 // 9 + 0x900 // 1001 0000 0000 // : +}; + +//----------------------------------------------------------------------------------------------- +static void barVert(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { + _fillTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, color); + _fillTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, color); + _fillRect(x, y+2*w+1, 2*w+1, l, color); + if (cfont.offset) { + _drawTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, outline); + _drawTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, outline); + _drawRect(x, y+2*w+1, 2*w+1, l, outline); + } +} + +//---------------------------------------------------------------------------------------------- +static void barHor(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { + _fillTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, color); + _fillTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, color); + _fillRect(x+2*w+1, y, l, 2*w+1, color); + if (cfont.offset) { + _drawTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, outline); + _drawTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, outline); + _drawRect(x+2*w+1, y, l, 2*w+1, outline); + } +} + +//-------------------------------------------------------------------------------------------- +static void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, color_t color) { + /* TODO: clipping */ + if (num < 0x2D || num > 0x3A) return; + + int16_t c = font_bcd[num-0x2D]; + int16_t d = 2*w+l+1; + + // === Clear unused segments === + if (!(c & 0x001)) barVert(x+d, y+d, w, l, _bg, _bg); + if (!(c & 0x002)) barVert(x, y+d, w, l, _bg, _bg); + if (!(c & 0x004)) barVert(x+d, y, w, l, _bg, _bg); + if (!(c & 0x008)) barVert(x, y, w, l, _bg, _bg); + if (!(c & 0x010)) barHor(x, y+2*d, w, l, _bg, _bg); + if (!(c & 0x020)) barHor(x, y+d, w, l, _bg, _bg); + if (!(c & 0x040)) barHor(x, y, w, l, _bg, _bg); + + if (!(c & 0x080)) { + // low point + _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg); + if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, _bg); + } + if (!(c & 0x100)) { + // down middle point + _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg); + if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, _bg); + } + if (!(c & 0x800)) { + // up middle point + _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg); + if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, _bg); + } + if (!(c & 0x200)) { + // middle, minus + _fillRect(x+2*w+1, y+d, l, 2*w+1, _bg); + if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, _bg); + } + + // === Draw used segments === + if (c & 0x001) barVert(x+d, y+d, w, l, color, cfont.color); // down right + if (c & 0x002) barVert(x, y+d, w, l, color, cfont.color); // down left + if (c & 0x004) barVert(x+d, y, w, l, color, cfont.color); // up right + if (c & 0x008) barVert(x, y, w, l, color, cfont.color); // up left + if (c & 0x010) barHor(x, y+2*d, w, l, color, cfont.color); // down + if (c & 0x020) barHor(x, y+d, w, l, color, cfont.color); // middle + if (c & 0x040) barHor(x, y, w, l, color, cfont.color); // up + + if (c & 0x080) { + // low point + _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, color); + if (cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, cfont.color); + } + if (c & 0x100) { + // down middle point + _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, color); + if (cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, cfont.color); + } + if (c & 0x800) { + // up middle point + _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, color); + if (cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, cfont.color); + } + if (c & 0x200) { + // middle, minus + _fillRect(x+2*w+1, y+d, l, 2*w+1, color); + if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, cfont.color); + } +} +//============================================================================== + +//====================================== +void mgos_ili9341_print(const char * const st, int x, int y) { + int stl, i, tmpw, tmph, fh; + uint8_t ch; + + if (cfont.bitmap == 0) return; // wrong font selected + + // ** Rotated strings cannot be aligned + if ((font_rotate != 0) && ((x <= CENTER) || (y <= CENTER))) return; + + if ((x < LASTX) || (font_rotate == 0)) TFT_OFFSET = 0; + + if ((x >= LASTX) && (x < LASTY)) x = TFT_X + (x-LASTX); + else if (x > CENTER) x += dispWin.x1; + + if (y >= LASTY) y = TFT_Y + (y-LASTY); + else if (y > CENTER) y += dispWin.y1; + + // ** Get number of characters in string to print + stl = strlen(st); + + // ** Calculate CENTER, RIGHT or BOTTOM position + tmpw = mgos_ili9341_getStringWidth(st); // string width in pixels + fh = cfont.y_size; // font height + if ((cfont.x_size != 0) && (cfont.bitmap == 2)) { + // 7-segment font + fh = (3 * (2 * cfont.y_size + 1)) + (2 * cfont.x_size); // 7-seg character height + } + + if (x == RIGHT) x = dispWin.x2 - tmpw + dispWin.x1; + else if (x == CENTER) x = (((dispWin.x2 - dispWin.x1 + 1) - tmpw) / 2) + dispWin.x1; + + if (y == BOTTOM) y = dispWin.y2 - fh + dispWin.y1; + else if (y==CENTER) y = (((dispWin.y2 - dispWin.y1 + 1) - (fh/2)) / 2) + dispWin.y1; + + if (x < dispWin.x1) x = dispWin.x1; + if (y < dispWin.y1) y = dispWin.y1; + if ((x > dispWin.x2) || (y > dispWin.y2)) return; + + TFT_X = x; + TFT_Y = y; + + // ** Adjust y position + tmph = cfont.y_size; // font height + // for non-proportional fonts, char width is the same for all chars + tmpw = cfont.x_size; + if (cfont.x_size != 0) { + if (cfont.bitmap == 2) { // 7-segment font + tmpw = _7seg_width(); // character width + tmph = _7seg_height(); // character height + } + } + else TFT_OFFSET = 0; // fixed font; offset not needed + + if ((TFT_Y + tmph - 1) > dispWin.y2) return; + + int offset = TFT_OFFSET; + + for (i=0; i (dispWin.y2-tmph)) break; + TFT_X = dispWin.x1; + } + } + + else { // ==== other characters ==== + if (cfont.x_size == 0) { + // for proportional font get character data to 'fontChar' + if (getCharPtr(ch)) tmpw = fontChar.xDelta; + else continue; + } + + // check if character can be displayed in the current line + if ((TFT_X+tmpw) > (dispWin.x2)) { + if (text_wrap == 0) break; + TFT_Y += tmph + font_line_space; + if (TFT_Y > (dispWin.y2-tmph)) break; + TFT_X = dispWin.x1; + } + + // Let's print the character + if (cfont.x_size == 0) { + // == proportional font + if (font_rotate == 0) TFT_X += printProportionalChar(TFT_X, TFT_Y) + 1; + else { + // rotated proportional font + offset += rotatePropChar(x, y, offset); + TFT_OFFSET = offset; + } + } + else { + if (cfont.bitmap == 1) { + // == fixed font + if ((ch < cfont.offset) || ((ch-cfont.offset) > cfont.numchars)) ch = cfont.offset; + if (font_rotate == 0) { + printChar(ch, TFT_X, TFT_Y); + TFT_X += tmpw; + } + else rotateChar(ch, x, y, i); + } + else if (cfont.bitmap == 2) { + // == 7-segment font == + _draw7seg(TFT_X, TFT_Y, ch, cfont.y_size, cfont.x_size, _fg); + TFT_X += (tmpw + 2); + } + } + } + } +} + + +// ================ Service functions ========================================== + +// Change the screen rotation. +// Input: m new rotation value (0 to 3) +//================================= +void mgos_ili9341_setRotation(uint8_t rot) { + if (rot > 3) { + uint8_t madctl = (rot & 0xF8); // for testing, manually set MADCTL register + if (disp_select() == ESP_OK) { + disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); + disp_deselect(); + } + } + else { + orientation = rot; + _tft_setRotation(rot); + } + + dispWin.x1 = 0; + dispWin.y1 = 0; + dispWin.x2 = _width-1; + dispWin.y2 = _height-1; + + mgos_ili9341_fillScreen(_bg); +} + +// Send the command to invert all of the colors. +// Input: i 0 to disable inversion; non-zero to enable inversion +//========================================== +void mgos_ili9341_invertDisplay(const uint8_t mode) { + if ( mode == INVERT_ON ) disp_spi_transfer_cmd(TFT_INVONN); + else disp_spi_transfer_cmd(TFT_INVOFF); +} + +// Select gamma curve +// Input: gamma = 0~3 +//================================== +void mgos_ili9341_setGammaCurve(uint8_t gm) { + uint8_t gamma_curve = 1 << (gm & 0x03); + disp_spi_transfer_cmd_data(TFT_CMD_GAMMASET, &gamma_curve, 1); +} + +//=========================================================== +color_t HSBtoRGB(float _hue, float _sat, float _brightness) { + float red = 0.0; + float green = 0.0; + float blue = 0.0; + + if (_sat == 0.0) { + red = _brightness; + green = _brightness; + blue = _brightness; + } else { + if (_hue == 360.0) { + _hue = 0; + } + + int slice = (int)(_hue / 60.0); + float hue_frac = (_hue / 60.0) - slice; + + float aa = _brightness * (1.0 - _sat); + float bb = _brightness * (1.0 - _sat * hue_frac); + float cc = _brightness * (1.0 - _sat * (1.0 - hue_frac)); + + switch(slice) { + case 0: + red = _brightness; + green = cc; + blue = aa; + break; + case 1: + red = bb; + green = _brightness; + blue = aa; + break; + case 2: + red = aa; + green = _brightness; + blue = cc; + break; + case 3: + red = aa; + green = bb; + blue = _brightness; + break; + case 4: + red = cc; + green = aa; + blue = _brightness; + break; + case 5: + red = _brightness; + green = aa; + blue = bb; + break; + default: + red = 0.0; + green = 0.0; + blue = 0.0; + break; + } + } + + color_t color; + color.r = ((uint8_t)(red * 255.0)) & 0xFC; + color.g = ((uint8_t)(green * 255.0)) & 0xFC; + color.b = ((uint8_t)(blue * 255.0)) & 0xFC; + + return color; +} +//===================================================================== +void mgos_ili9341_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + dispWin.x1 = x1; + dispWin.y1 = y1; + dispWin.x2 = x2; + dispWin.y2 = y2; + + if (dispWin.x2 >= _width) dispWin.x2 = _width-1; + if (dispWin.y2 >= _height) dispWin.y2 = _height-1; + if (dispWin.x1 > dispWin.x2) dispWin.x1 = dispWin.x2; + if (dispWin.y1 > dispWin.y2) dispWin.y1 = dispWin.y2; +} + +//===================== +void mgos_ili9341_resetclipwin() +{ + dispWin.x2 = _width-1; + dispWin.y2 = _height-1; + dispWin.x1 = 0; + dispWin.y1 = 0; +} + +//========================================================================== +void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color) { + if (cfont.bitmap != 2) return; + + if (l < 6) l = 6; + if (l > 40) l = 40; + if (w < 1) w = 1; + if (w > (l/2)) w = l/2; + if (w > 12) w = 12; + + cfont.x_size = l; + cfont.y_size = w; + cfont.offset = outline; + cfont.color = color; +} + +//========================================== +int mgos_ili9341_getfontsize(int *width, int* height) +{ + if (cfont.bitmap == 1) { + if (cfont.x_size != 0) *width = cfont.x_size; // fixed width font + else *width = cfont.max_x_size; // proportional font + *height = cfont.y_size; + } + else if (cfont.bitmap == 2) { + // 7-segment font + *width = _7seg_width(); + *height = _7seg_height(); + } + else { + *width = 0; + *height = 0; + return 0; + } + return 1; +} + +//===================== +int mgos_ili9341_getfontheight() +{ + if (cfont.bitmap == 1) return cfont.y_size; // Bitmap font + else if (cfont.bitmap == 2) return _7seg_height(); // 7-segment font + return 0; +} + +//==================== +void mgos_ili9341_saveClipWin() +{ + dispWinTemp.x1 = dispWin.x1; + dispWinTemp.y1 = dispWin.y1; + dispWinTemp.x2 = dispWin.x2; + dispWinTemp.y2 = dispWin.y2; +} + +//======================= +void mgos_ili9341_restoreClipWin() +{ + dispWin.x1 = dispWinTemp.x1; + dispWin.y1 = dispWinTemp.y1; + dispWin.x2 = dispWinTemp.x2; + dispWin.y2 = dispWinTemp.y2; +} + + +// ================ JPG SUPPORT ================================================ +// User defined device identifier +typedef struct { + FILE *fhndl; // File handler for input function + int x; // image top left point X position + int y; // image top left point Y position + uint8_t *membuff; // memory buffer containing the image + uint32_t bufsize; // size of the memory buffer + uint32_t bufptr; // memory buffer current position + color_t *linbuf[2]; // memory buffer used for display output + uint8_t linbuf_idx; +} JPGIODEV; + + +// User defined call-back function to input JPEG data from file +//--------------------- +static UINT tjd_input ( + JDEC* jd, // Decompression object + BYTE* buff, // Pointer to the read buffer (NULL:skip) + UINT nd // Number of bytes to read/skip from input stream +) +{ + int rb = 0; + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + + if (buff) { // Read nd bytes from the input strem + rb = fread(buff, 1, nd, dev->fhndl); + return rb; // Returns actual number of bytes read + } + else { // Remove nd bytes from the input stream + if (fseek(dev->fhndl, nd, SEEK_CUR) >= 0) return nd; + else return 0; + } +} + +// User defined call-back function to input JPEG data from memory buffer +//------------------------- +static UINT tjd_buf_input ( + JDEC* jd, // Decompression object + BYTE* buff, // Pointer to the read buffer (NULL:skip) + UINT nd // Number of bytes to read/skip from input stream +) +{ + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + if (!dev->membuff) return 0; + if (dev->bufptr >= (dev->bufsize + 2)) return 0; // end of stream + + if ((dev->bufptr + nd) > (dev->bufsize + 2)) nd = (dev->bufsize + 2) - dev->bufptr; + + if (buff) { // Read nd bytes from the input strem + memcpy(buff, dev->membuff + dev->bufptr, nd); + dev->bufptr += nd; + return nd; // Returns number of bytes read + } + else { // Remove nd bytes from the input stream + dev->bufptr += nd; + return nd; + } +} + +// User defined call-back function to output RGB bitmap to display device +//---------------------- +static UINT tjd_output ( + JDEC* jd, // Decompression object of current session + void* bitmap, // Bitmap data to be output + JRECT* rect // Rectangular region to output +) +{ + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + + // ** Put the rectangular into the display device ** + int x; + int y; + int dleft, dtop, dright, dbottom; + BYTE *src = (BYTE*)bitmap; + + int left = rect->left + dev->x; + int top = rect->top + dev->y; + int right = rect->right + dev->x; + int bottom = rect->bottom + dev->y; + + if ((left > dispWin.x2) || (top > dispWin.y2)) return 1; // out of screen area, return + if ((right < dispWin.x1) || (bottom < dispWin.y1)) return 1;// out of screen area, return + + if (left < dispWin.x1) dleft = dispWin.x1; + else dleft = left; + if (top < dispWin.y1) dtop = dispWin.y1; + else dtop = top; + if (right > dispWin.x2) dright = dispWin.x2; + else dright = right; + if (bottom > dispWin.y2) dbottom = dispWin.y2; + else dbottom = bottom; + + if ((dleft > dispWin.x2) || (dtop > dispWin.y2)) return 1; // out of screen area, return + if ((dright < dispWin.x1) || (dbottom < dispWin.y1)) return 1; // out of screen area, return + + uint32_t len = ((dright-dleft+1) * (dbottom-dtop+1)); // calculate length of data + + + if ((len > 0) && (len <= JPG_IMAGE_LINE_BUF_SIZE)) { + uint8_t *dest = (uint8_t *)(dev->linbuf[dev->linbuf_idx]); + + for (y = top; y <= bottom; y++) { + for (x = left; x <= right; x++) { + // Clip to display area + if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) { + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + } + else src += 3; // skip + } + } + wait_trans_finish(1); + send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx]); + dev->linbuf_idx = ((dev->linbuf_idx + 1) & 1); + } + else { + wait_trans_finish(1); + LOG(LL_ERROR, ("Data size error: %d jpg: (%d,%d,%d,%d) disp: (%d,%d,%d,%d)", len, left,top,right,bottom, dleft,dtop,dright,dbottom)); + return 0; // stop decompression + } + + return 1; // Continue to decompression +} + +// tft.jpgimage(X, Y, scale, file_name, buf, size] +// X & Y can be < 0 ! +//================================================================================== +void mgos_ili9341_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size) +{ + JPGIODEV dev; + struct stat sb; + char *work = NULL; // Pointer to the working buffer (must be 4-byte aligned) + UINT sz_work = 3800; // Size of the working buffer (must be power of 2) + JDEC jd; // Decompression object (70 bytes) + JRESULT rc; + + dev.linbuf[0] = NULL; + dev.linbuf[1] = NULL; + dev.linbuf_idx = 0; + + dev.fhndl = NULL; + if (fname == NULL) { + // image from buffer + dev.membuff = buf; + dev.bufsize = size; + dev.bufptr = 0; + } + else { + // image from file + dev.membuff = NULL; + dev.bufsize = 0; + dev.bufptr = 0; + + if (stat(fname, &sb) != 0) { + if (image_debug) LOG(LL_ERROR, ("File error: %ss", strerror(errno))); + goto exit; + } + + dev.fhndl = fopen(fname, "r"); + if (!dev.fhndl) { + if (image_debug) LOG(LL_ERROR, ("Error opening file: %s", strerror(errno))); + goto exit; + } + } + + if (scale > 3) scale = 3; + + work = malloc(sz_work); + if (work) { + if (dev.membuff) rc = jd_prepare(&jd, tjd_buf_input, (void *)work, sz_work, &dev); + else rc = jd_prepare(&jd, tjd_input, (void *)work, sz_work, &dev); + if (rc == JDR_OK) { + if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - (int)(jd.width >> scale)) / 2) + dispWin.x1; + else if (x == RIGHT) x = dispWin.x2 + 1 - (int)(jd.width >> scale); + + if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - (int)(jd.height >> scale)) / 2) + dispWin.y1; + else if (y == BOTTOM) y = dispWin.y2 + 1 - (int)(jd.height >> scale); + + if (x < ((dispWin.x2-1) * -1)) x = (dispWin.x2-1) * -1; + if (y < ((dispWin.y2-1)) * -1) y = (dispWin.y2-1) * -1; + if (x > (dispWin.x2-1)) x = dispWin.x2 - 1; + if (y > (dispWin.y2-1)) y = dispWin.y2-1; + + dev.x = x; + dev.y = y; + + dev.linbuf[0] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA); + if (dev.linbuf[0] == NULL) { + if (image_debug) LOG(LL_ERROR, ("Error allocating line buffer #0")); + goto exit; + } + dev.linbuf[1] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA); + if (dev.linbuf[1] == NULL) { + if (image_debug) LOG(LL_ERROR, ("Error allocating line buffer #1")); + goto exit; + } + + // Start to decode the JPEG file + disp_select(); + rc = jd_decomp(&jd, tjd_output, scale); + disp_deselect(); + + if (rc != JDR_OK) { + if (image_debug) LOG(LL_ERROR, ("Jpg decompression error %d", rc)); + } + if (image_debug) LOG(LL_INFO, ("Jpg size: %dx%d, position; %d,%d, scale: %d, bytes used: %d", jd.width, jd.height, x, y, scale, jd.sz_pool)); + } + else { + if (image_debug) LOG(LL_ERROR, ("jpg prepare error %d", rc)); + } + } + else { + if (image_debug) LOG(LL_ERROR, ("work buffer allocation error")); + } + +exit: + if (work) free(work); // free work buffer + if (dev.linbuf[0]) free(dev.linbuf[0]); + if (dev.linbuf[1]) free(dev.linbuf[1]); + if (dev.fhndl) fclose(dev.fhndl); // close input file +} + + +//==================================================================================== +int mgos_ili9341_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size) +{ + FILE *fhndl = NULL; + struct stat sb; + int i, err=0; + int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen; + int img_pos, img_pix_pos, scan_lines, rd_len; + uint8_t tmpc; + uint16_t wtemp; + uint32_t temp; + int disp_xstart, disp_xend, disp_ystart, disp_yend; + uint8_t buf[56]; + char err_buf[64]; + uint8_t *line_buf[2] = {NULL,NULL}; + uint8_t lb_idx = 0; + uint8_t *scale_buf = NULL; + uint8_t scale_pix; + uint16_t co[3] = {0,0,0}; // RGB sum + uint8_t npix; + + if (scale > 7) scale = 7; + scale_pix = scale+1; // scale factor ( 1~8 ) + + if (fname) { + // * File name is given, reading image from file + if (stat(fname, &sb) != 0) { + sprintf(err_buf, "opening file"); + err = -1; + goto exit; + } + size = sb.st_size; + fhndl = fopen(fname, "r"); + if (!fhndl) { + sprintf(err_buf, "opening file"); + err = -2; + goto exit; + } + + i = fread(buf, 1, 54, fhndl); // read header + } + else { + // * Reading image from buffer + if ((imgbuf) && (size > 54)) { + memcpy(buf, imgbuf, 54); + i = 54; + } + else i = 0; + } + + sprintf(err_buf, "reading header"); + if (i != 54) {err = -3; goto exit;} + + // ** Check image header and get image properties + if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id + + memcpy(&temp, buf+2, 4); // file size + if (temp != size) {err=-5; goto exit;} + + memcpy(&img_pos, buf+10, 4); // start of pixel data + + memcpy(&temp, buf+14, 4); // BMP header size + if (temp != 40) {err=-6; goto exit;} + + memcpy(&wtemp, buf+26, 2); // the number of color planes + if (wtemp != 1) {err=-7; goto exit;} + + memcpy(&wtemp, buf+28, 2); // the number of bits per pixel + if (wtemp != 24) {err=-8; goto exit;} + + memcpy(&temp, buf+30, 4); // the compression method being used + if (temp != 0) {err=-9; goto exit;} + + memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels + memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels + + + // * scale image dimensions + + img_xlen = img_xsize / scale_pix; // image display horizontal size + img_ylen = img_ysize / scale_pix; // image display vertical size + + if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - img_xlen) / 2) + dispWin.x1; + else if (x == RIGHT) x = dispWin.x2 + 1 - img_xlen; + + if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - img_ylen) / 2) + dispWin.y1; + else if (y == BOTTOM) y = dispWin.y2 + 1 - img_ylen; + + if ((x < ((dispWin.x2 + 1) * -1)) || (x > (dispWin.x2 + 1)) || (y < ((dispWin.y2 + 1) * -1)) || (y > (dispWin.y2 + 1))) { + sprintf(err_buf, "out of display area (%d,%d", x, y); + err = -10; + goto exit; + } + + // ** set display and image areas + if (x < dispWin.x1) { + disp_xstart = dispWin.x1; + img_xstart = -x; // image pixel line X offset + img_xlen += x; + } + else { + disp_xstart = x; + img_xstart = 0; + } + if (y < dispWin.y1) { + disp_ystart = dispWin.y1; + img_ystart = -y; // image pixel line Y offset + img_ylen += y; + } + else { + disp_ystart = y; + img_ystart = 0; + } + disp_xend = disp_xstart + img_xlen - 1; + disp_yend = disp_ystart + img_ylen - 1; + if (disp_xend > dispWin.x2) { + disp_xend = dispWin.x2; + img_xlen = disp_xend - disp_xstart + 1; + } + if (disp_yend > dispWin.y2) { + disp_yend = dispWin.y2; + img_ylen = disp_yend - disp_ystart + 1; + } + + if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) { + sprintf(err_buf, "image too small"); + err = -11; + goto exit; + } + + // ** Allocate memory for 2 lines of image pixels + line_buf[0] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA); + if (line_buf[0] == NULL) { + sprintf(err_buf, "allocating line buffer #1"); + err=-12; + goto exit; + } + + line_buf[1] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA); + if (line_buf[1] == NULL) { + sprintf(err_buf, "allocating line buffer #2"); + err=-13; + goto exit; + } + + if (scale) { + // Allocate memory for scale buffer + rd_len = img_xlen * 3 * scale_pix; + scale_buf = malloc(rd_len*scale_pix); + if (scale_buf == NULL) { + sprintf(err_buf, "allocating scale buffer"); + err=-14; + goto exit; + } + } + else rd_len = img_xlen * 3; + + // ** ***************************************************** ** + // ** BMP images are stored in file from LAST to FIRST line ** + // ** ***************************************************** ** + + /* Used variables: + img_xsize horizontal image size in pixels + img_ysize number of image lines + img_xlen image display horizontal scaled size in pixels + img_ylen image display vertical scaled size in pixels + img_xstart first pixel in line to be displayed + img_ystart first image line to be displayed + img_xlen number of pixels in image line to be displayed, starting with 'img_xstart' + img_ylen number of lines in image to be displayed, starting with 'img_ystart' + rd_len length of color data which are read from image line in bytes + */ + + // Set position in image to the first color data (beginning of the LAST line) + img_pos += (img_ystart * (img_xsize*3)); + if (fhndl) { + if (fseek(fhndl, img_pos, SEEK_SET) != 0) { + sprintf(err_buf, "file seek at %d", img_pos); + err = -15; + goto exit; + } + } + + if (image_debug) LOG(LL_INFO, ("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d", + img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0))); + + // * Select the display + disp_select(); + + while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) { + if (img_pos > size) { + sprintf(err_buf, "EOF reached: %d > %d", img_pos, size); + err = -16; + goto exit1; + } + if (scale == 0) { + // Read the line of color data into color buffer + if (fhndl) { + i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file + if (i != (img_xsize*3)) { + sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); + err = -16; + goto exit1; + } + } + else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); + + if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len); + // Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) === + for (i=0; i < rd_len; i += 3) { + tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R + line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R + line_buf[lb_idx][i] = tmpc; // R -> B + line_buf[lb_idx][i+1] &= 0xfc; // G + } + img_pos += (img_xsize*3); + } + else { + // scale image, read 'scale_pix' lines and find the average color + for (scan_lines=0; scan_lines size) break; + if (fhndl) { + i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file + if (i != (img_xsize*3)) { + sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); + err = -17; + goto exit1; + } + } + else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); + img_pos += (img_xsize*3); + + // copy only data which are displayed to scale buffer + memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len); + } + + // Populate display line buffer + for (int n=0;n<(img_xlen*3);n += 3) { + memset(co, 0, sizeof(co)); // initialize color sum + npix = 0; // initialize number of pixels in scale rectangle + + // sum all pixels in scale rectangle + for (int sc_line=0; sc_line RGB-888 (DISPLAY) + line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B + line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G + line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R + } + } + + wait_trans_finish(1); + send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]); + lb_idx = (lb_idx + 1) & 1; // change buffer + + disp_yend--; + } + err = 0; +exit1: + disp_deselect(); +exit: + if (scale_buf) free(scale_buf); + if (line_buf[0]) free(line_buf[0]); + if (line_buf[1]) free(line_buf[1]); + if (fhndl) fclose(fhndl); + if ((err) && (image_debug)) LOG(LL_ERROR, ("Error: %d [%s]", err, err_buf)); + + return err; +} + + + +void mgos_ili9341_set_fg(const color_t *color) +{ + _fg = *color; +// memcpy(_fg, color, 3); +} + +void mgos_ili9341_set_bg(const color_t *color) +{ + _bg = *color; +// memcpy(_bg, color, 3); +} + +color_t *mgos_ili9341_get_fg(void) +{ + return &_fg; +} + +color_t *mgos_ili9341_get_bg(void) +{ + return &_bg; +} + +// Mongoose-OS init +// +bool mgos_ili9341_init(void) { + esp_err_t ret; + + max_rdclock = 8000000; + + gpio_pad_select_gpio(mgos_sys_config_get_ili9341_cs_pin()); + gpio_set_direction(mgos_sys_config_get_ili9341_cs_pin(), GPIO_MODE_OUTPUT); + + gpio_pad_select_gpio(mgos_sys_config_get_ili9341_dc_pin()); + gpio_set_direction(mgos_sys_config_get_ili9341_dc_pin(), GPIO_MODE_OUTPUT); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + + // Add SPI TFT Screen (ILI9341) + spi_lobo_device_handle_t spi; + + spi_lobo_bus_config_t buscfg={ + .miso_io_num=mgos_sys_config_get_spi_miso(), + .mosi_io_num=mgos_sys_config_get_spi_mosi(), + .sclk_io_num=mgos_sys_config_get_spi_sck(), + .quadwp_io_num=-1, + .quadhd_io_num=-1, + .max_transfer_sz = 6*1024, + }; + + spi_lobo_device_interface_config_t devcfg={ + .clock_speed_hz=DEFAULT_SPI_CLOCK, + .mode=0, + .spics_io_num=-1, // we will use external CS pin + .spics_ext_io_num=mgos_sys_config_get_ili9341_cs_pin(), + .flags=SPI_DEVICE_HALFDUPLEX, + }; + + ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &devcfg, &spi); + assert(ret==ESP_OK); + disp_spi = spi; + + ret = spi_lobo_device_select(spi, 1); + assert(ret==ESP_OK); + ret = spi_lobo_device_deselect(spi); + assert(ret==ESP_OK); + + mgos_ili9341_display_init(); + + max_rdclock = find_rd_speed(); + LOG(LL_INFO, ("SPI init ok (cs=%d, speed=%u, rdspeed=%u)", mgos_sys_config_get_ili9341_cs_pin(), spi_lobo_get_speed(spi), max_rdclock)); + + return true; +} + diff --git a/libs/ili9341/src/minya24.c b/libs/ili9341/src/minya24.c new file mode 100644 index 0000000..6bab953 --- /dev/null +++ b/libs/ili9341/src/minya24.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// minya24.c +// Point Size : 24 +// Memory usage : 2807 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_minya24[] = +{ +0x00, 0x15, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x13,0x00,0x00,0x00,0x07, + +// '!' +0x21,0x02,0x05,0x12,0x00,0x05, +0x11,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x42,0x01,0xCE,0x73,0x80, +// '"' +0x22,0x01,0x06,0x08,0x00,0x06, +0x01,0xA6,0xDB,0x6D,0xB6,0xC0, +// '#' +0x23,0x04,0x0C,0x0E,0x00,0x0B, +0x04,0x80,0x6C,0x0C,0x80,0xD8,0x7F,0xE7,0xFE,0x1B,0x01,0xB0,0x7F,0xE7,0xFC,0x12,0x03,0x20,0x32,0x00,0x00, +// '$' +0x24,0x02,0x0A,0x11,0x00,0x0B, +0x04,0x01,0x61,0xF8,0xFE,0x65,0x19,0x06,0x40,0xF0,0x1F,0x01,0xE0,0x4C,0x93,0x7C,0xCF,0xE0,0x60,0x10,0x04,0x00, +// '%' +0x25,0x01,0x0D,0x14,0x01,0x0F, +0x00,0x01,0xC1,0x1F,0x19,0x8C,0xCC,0x6C,0x63,0x61,0x36,0x0F,0xB0,0x1B,0x00,0x18,0x01,0x80,0x0C,0x00,0xCE,0x06,0xF8,0x6C,0x66,0x63,0x33,0x13,0x0F,0x98,0x38,0x00,0x00, +// '&' +0x26,0x02,0x0E,0x11,0x00,0x0D, +0x0E,0x00,0x7C,0x01,0xB0,0x06,0xC0,0x1E,0x00,0x38,0x00,0xC3,0x07,0x8C,0x37,0x60,0xCD,0x86,0x1E,0x18,0x70,0x41,0xE1,0x07,0xC6,0x33,0x9F,0x86,0x38,0x00, +// ''' +0x27,0x02,0x03,0x08,0x00,0x03, +0x6D,0xB6,0xD8, +// '(' +0x28,0x01,0x05,0x14,0x02,0x07, +0x00,0x8E,0x66,0x33,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x8C,0x00, +// ')' +0x29,0x01,0x06,0x15,0x00,0x07, +0x01,0x86,0x0C,0x18,0x61,0x82,0x08,0x30,0xC2,0x08,0x61,0x86,0x30,0xC6,0x10,0x00, +// '*' +0x2A,0x04,0x0A,0x0D,0x01,0x0B, +0x08,0x03,0x04,0xC1,0xF6,0x7F,0x07,0x81,0xC0,0xF8,0x3F,0x1B,0xCC,0xD8,0x30,0x0C,0x00, +// '+' +0x2B,0x06,0x0A,0x0A,0x01,0x0B, +0x00,0x03,0x00,0xC0,0x30,0x7F,0xBF,0xE0,0xC0,0x30,0x0C,0x00,0x00, +// ',' +0x2C,0x10,0x05,0x07,0x00,0x05, +0x33,0x9C,0x63,0x20,0x00, +// '-' +0x2D,0x09,0x07,0x02,0x00,0x07, +0x7D,0xF8, +// '.' +0x2E,0x10,0x04,0x04,0x01,0x05, +0x6E,0xE6, +// '/' +0x2F,0x01,0x0C,0x13,0x00,0x0B, +0x00,0x00,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x30,0x06,0x00,0x40,0x00, +// '0' +0x30,0x08,0x0B,0x0B,0x00,0x0B, +0x0E,0x03,0xE0,0xC6,0x30,0x66,0x0C,0xC0,0x98,0x33,0x06,0x61,0xC7,0xF0,0x7C,0x00, +// '1' +0x31,0x08,0x0A,0x0D,0x00,0x09, +0x04,0x1F,0x03,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x07,0xF9,0xFE,0x00,0x00, +// '2' +0x32,0x06,0x0A,0x0E,0x00,0x0A, +0x0E,0x07,0xC3,0x30,0xCC,0x03,0x01,0x80,0x60,0x30,0x18,0x0C,0x03,0x01,0xF8,0x7F,0xC0,0x20, +// '3' +0x33,0x08,0x09,0x10,0x00,0x08, +0x78,0x3F,0x81,0x81,0x81,0xC0,0xC0,0xE0,0x78,0x06,0x01,0x01,0x80,0xC0,0xE1,0xE0,0xC0,0x00, +// '4' +0x34,0x03,0x0B,0x13,0x00,0x0A, +0x00,0x00,0xC0,0x18,0x03,0x00,0x60,0x08,0x03,0x00,0x60,0x0D,0x83,0x20,0x64,0x18,0x83,0x10,0xC6,0x1F,0xF3,0xFE,0x03,0x00,0x60,0x0C,0x00, +// '5' +0x35,0x09,0x0A,0x0E,0x00,0x0A, +0x3F,0x8F,0xE3,0x00,0x80,0x60,0x1F,0x87,0xF0,0x06,0x01,0x80,0x60,0x19,0x86,0x7F,0x07,0x80, +// '6' +0x36,0x03,0x0A,0x12,0x00,0x0A, +0x00,0x01,0x80,0xE0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x1B,0x87,0xF1,0x86,0x61,0x90,0x66,0x19,0x86,0x3F,0x07,0x80, +// '7' +0x37,0x09,0x0A,0x0E,0x00,0x0A, +0x7F,0x9F,0xF0,0x18,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x01,0x80,0x40,0x10,0x0C,0x00, +// '8' +0x38,0x03,0x0B,0x11,0x00,0x0B, +0x0F,0x07,0xF0,0xC3,0x30,0x66,0x0C,0x63,0x87,0xE0,0xF8,0x39,0xCE,0x19,0x81,0x30,0x34,0x06,0xC1,0x98,0x71,0xFC,0x1F,0x00, +// '9' +0x39,0x07,0x0A,0x11,0x00,0x0A, +0x1E,0x0F,0xC6,0x19,0x86,0x41,0x98,0x66,0x18,0xFE,0x1D,0x80,0x40,0x30,0x0C,0x06,0x03,0x01,0xC0,0x20,0x00,0x00, +// ':' +0x3A,0x0A,0x05,0x0A,0x00,0x05, +0x33,0x9C,0x60,0x00,0xCE,0x71,0x80, +// ';' +0x3B,0x09,0x05,0x0D,0x00,0x06, +0x33,0xDE,0x60,0x00,0x0E,0x73,0x8C,0xC0,0x00, +// '<' +0x3C,0x06,0x0A,0x0C,0x00,0x09, +0x00,0x00,0xE0,0x70,0x38,0x1C,0x1C,0x03,0x00,0x70,0x0E,0x01,0xC0,0x10,0x00, +// '=' +0x3D,0x09,0x08,0x06,0x01,0x0A, +0xFF,0xFE,0x00,0x00,0x7F,0xFF, +// '>' +0x3E,0x06,0x0A,0x0C,0x00,0x09, +0x00,0x18,0x03,0x80,0x70,0x0E,0x00,0xE0,0x30,0x38,0x1C,0x0E,0x02,0x00,0x00, +// '?' +0x3F,0x02,0x09,0x12,0x00,0x09, +0x1E,0x1F,0x98,0x6C,0x30,0x18,0x18,0x38,0x30,0x30,0x18,0x0C,0x02,0x01,0x00,0x00,0x60,0x78,0x3C,0x0C,0x00, +// '@' +0x40,0x02,0x11,0x11,0x00,0x11, +0x01,0xF0,0x03,0xFE,0x03,0x03,0x83,0x00,0xC3,0x04,0x31,0x1F,0x19,0x9F,0x0C,0xCC,0x86,0x4C,0x43,0x24,0x21,0x12,0x39,0x89,0xF7,0x84,0x71,0x83,0x00,0x00,0xC1,0x80,0x3F,0xC0,0x0F,0x80,0x00, +// 'A' +0x41,0x02,0x12,0x13,0x00,0x10, +0x00,0x00,0x01,0xF0,0x00,0x7E,0x00,0x03,0x80,0x01,0xA0,0x00,0x6C,0x00,0x1B,0x00,0x0C,0x40,0x03,0x18,0x01,0x86,0x00,0x61,0x80,0x1F,0xE0,0x0F,0xFC,0x03,0x03,0x01,0x80,0xC0,0x60,0x10,0x18,0x1F,0x9F,0xC7,0xEF,0xF8,0x00, +// 'B' +0x42,0x02,0x0E,0x13,0x00,0x0E, +0x7F,0x81,0xFF,0x81,0x86,0x06,0x18,0x18,0xC0,0x66,0x01,0xFC,0x07,0xFC,0x1C,0x30,0x60,0x61,0x81,0x86,0x06,0x18,0x18,0x60,0x61,0x81,0x06,0x0C,0x18,0xE0,0xFE,0x03,0xE0,0x00, +// 'C' +0x43,0x02,0x0F,0x12,0x00,0x0F, +0x03,0xF0,0x1F,0xE0,0x70,0xC1,0x80,0x83,0x00,0x04,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x06,0x00,0x0E,0x01,0x0E,0x0E,0x0F,0xF8,0x07,0xE0, +// 'D' +0x44,0x02,0x0F,0x13,0x00,0x0F, +0x3F,0xC0,0x7F,0xE0,0x60,0xE0,0xC0,0xC1,0x80,0xC3,0x01,0x86,0x03,0x0C,0x02,0x18,0x04,0x30,0x08,0x60,0x30,0xC0,0x61,0x80,0x83,0x03,0x06,0x0C,0x0C,0x38,0x18,0xE0,0xFF,0x81,0xF8,0x00, +// 'E' +0x45,0x02,0x0D,0x13,0x00,0x0D, +0x3F,0xF1,0xFF,0x86,0x0C,0x30,0x61,0x80,0x0C,0x40,0x62,0x03,0xF0,0x1F,0x80,0xC4,0x06,0x20,0x30,0x01,0x80,0x0C,0x00,0x60,0xC3,0x06,0x7F,0xF3,0xFF,0x80,0x00, +// 'F' +0x46,0x01,0x0E,0x13,0x00,0x0E, +0x00,0x01,0xFF,0xE7,0xFF,0x86,0x06,0x18,0x18,0x63,0x01,0x8C,0x03,0xF0,0x0F,0xC0,0x63,0x01,0x8C,0x06,0x30,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x3F,0x81,0xFE,0x00,0x00,0x00, +// 'G' +0x47,0x01,0x11,0x14,0x00,0x11, +0x00,0x00,0x03,0xC8,0x03,0xFC,0x03,0x0E,0x03,0x03,0x01,0x00,0x01,0x80,0x00,0xC0,0x00,0x60,0x03,0x30,0x3F,0xD8,0x1F,0x0C,0x01,0x86,0x00,0xC3,0x80,0x60,0xC0,0x30,0x70,0x38,0x1C,0x3C,0x07,0xF6,0x01,0xF3,0x80,0x01,0xE0, +// 'H' +0x48,0x01,0x10,0x13,0x00,0x10, +0x00,0x00,0x7C,0x0F,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x08,0x0C,0x08,0x0F,0xF8,0x0F,0xF8,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x1A,0x7C,0x1F,0x7C,0x10, +// 'I' +0x49,0x02,0x08,0x13,0x00,0x08, +0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E, +// 'J' +0x4A,0x01,0x0C,0x14,0x00,0x0B, +0x00,0x00,0x7E,0x07,0xE0,0x18,0x01,0x80,0x18,0x01,0x80,0x18,0x00,0x80,0x08,0x00,0x80,0x18,0x61,0x84,0x18,0x41,0x8C,0x18,0xC3,0x06,0x70,0x7E,0x01,0x80, +// 'K' +0x4B,0x02,0x11,0x13,0x00,0x10, +0x7E,0x7E,0x3F,0x3E,0x06,0x06,0x03,0x06,0x01,0x86,0x00,0xC6,0x00,0x66,0x00,0x37,0x00,0x1F,0x80,0x0E,0x60,0x06,0x10,0x03,0x0C,0x01,0x06,0x00,0x81,0x00,0x60,0x80,0x30,0x66,0x7E,0x1B,0x3F,0x0F,0x80,0x01,0x80, +// 'L' +0x4C,0x02,0x0D,0x11,0x00,0x0D, +0x7E,0x03,0xF0,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x81,0x0C,0x08,0x60,0x4F,0xFF,0x7F,0xF8, +// 'M' +0x4D,0x02,0x14,0x12,0x00,0x13, +0x7C,0x07,0x87,0xC0,0x7C,0x0C,0x06,0x00,0xE0,0xE0,0x0E,0x0E,0x00,0xE0,0xE0,0x1B,0x1E,0x01,0xB1,0x60,0x0B,0x16,0x00,0x9B,0x60,0x09,0xA6,0x00,0x9E,0x60,0x08,0xE6,0x00,0x8C,0x60,0x08,0xC6,0x03,0x8C,0x7E,0x78,0x47,0xE0,0x00,0x00, +// 'N' +0x4E,0x01,0x12,0x13,0x00,0x12, +0x00,0x00,0x1F,0x03,0xF3,0xC0,0x7C,0x38,0x10,0x0E,0x04,0x03,0xC1,0x00,0xB0,0x40,0x26,0x10,0x09,0x84,0x02,0x31,0x00,0x8C,0x40,0x21,0x90,0x08,0x74,0x06,0x0F,0x01,0x81,0xC0,0x60,0x70,0x78,0x0C,0x3E,0x03,0x00,0x00,0x40, +// 'O' +0x4F,0x02,0x11,0x12,0x00,0x11, +0x03,0xE0,0x07,0xFC,0x07,0x07,0x06,0x01,0x82,0x00,0x63,0x00,0x11,0x80,0x0C,0x80,0x06,0x40,0x03,0x20,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x31,0x80,0x30,0xE0,0x18,0x38,0x18,0x0F,0xF8,0x01,0xF0,0x00, +// 'P' +0x50,0x02,0x0C,0x12,0x00,0x0C, +0x7F,0x07,0xFC,0x10,0x61,0x03,0x10,0x31,0x03,0x10,0x31,0x06,0x10,0xE1,0xFC,0x1E,0x01,0x00,0x18,0x01,0x80,0x18,0x01,0x80,0x7E,0x07,0xF0, +// 'Q' +0x51,0x02,0x13,0x15,0x00,0x11, +0x07,0xE0,0x01,0xFE,0x00,0x60,0x70,0x18,0x06,0x06,0x00,0x60,0xC0,0x0C,0x18,0x00,0xC2,0x00,0x18,0x40,0x03,0x08,0x0C,0x61,0x83,0xCC,0x30,0xCD,0x83,0x09,0xE0,0x60,0x3C,0x06,0x07,0x00,0x7F,0xE3,0x07,0xEC,0x40,0x01,0x98,0x00,0x33,0x00,0x03,0xC0,0x00,0x30, +// 'R' +0x52,0x02,0x0F,0x13,0x00,0x0F, +0x7F,0x80,0xFF,0xE0,0x60,0xE0,0xC0,0x61,0x80,0xC3,0x01,0x86,0x07,0x0C,0x1C,0x1F,0xF0,0x3F,0x80,0x66,0x00,0xC4,0x01,0x8C,0x63,0x18,0xC6,0x11,0x8C,0x33,0x7E,0x7C,0xFC,0x70,0x00,0x00, +// 'S' +0x53,0x01,0x0D,0x13,0x00,0x0D, +0x00,0x60,0x7B,0x07,0xF8,0x71,0xC3,0x06,0x18,0x00,0xC0,0x03,0x80,0x0E,0x00,0x1C,0x00,0x78,0x00,0xC0,0x03,0x30,0x19,0x80,0xCC,0x06,0x30,0x70,0xFF,0x03,0xE0, +// 'T' +0x54,0x01,0x0F,0x12,0x00,0x0F, +0x00,0x00,0xFF,0xF9,0xFF,0xF3,0x18,0x66,0x30,0xCC,0x61,0x90,0xC3,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x0F,0xE0,0x1F,0xC0, +// 'U' +0x55,0x02,0x10,0x11,0x00,0x0F, +0x7C,0x7E,0x7C,0x7E,0x30,0x08,0x30,0x08,0x30,0x08,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x10,0x08,0x18,0x18,0x18,0x18,0x0C,0x30,0x0F,0xF0,0x03,0xC0, +// 'V' +0x56,0x01,0x10,0x12,0x00,0x10, +0x00,0x7E,0xFE,0x7E,0x7E,0x18,0x18,0x30,0x18,0x30,0x18,0x20,0x08,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x40,0x0C,0xC0,0x04,0xC0,0x04,0xC0,0x06,0x80,0x07,0x80,0x07,0x80,0x03,0x00,0x03,0x00, +// 'W' +0x57,0x01,0x14,0x13,0x00,0x14, +0x00,0x00,0x0F,0xC4,0xFF,0xF0,0x4F,0xE3,0x06,0x10,0x30,0xE3,0x01,0x8E,0x30,0x18,0xE3,0x01,0x8E,0x30,0x19,0xA3,0x01,0x9A,0x20,0x09,0xA6,0x00,0xD2,0x60,0x0D,0x36,0x00,0xF3,0x40,0x0F,0x34,0x00,0x63,0xC0,0x06,0x1C,0x00,0x61,0x80,0x00,0x18,0x00, +// 'X' +0x58,0x01,0x10,0x13,0x00,0x10, +0x00,0x00,0x7F,0x7F,0x7E,0x7E,0x0C,0x30,0x06,0x20,0x06,0x60,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0x80,0x02,0xC0,0x06,0x40,0x04,0x60,0x0C,0x60,0x18,0x30,0x18,0x30,0x7C,0x30,0xFC,0xFE,0x00,0xFF, +// 'Y' +0x59,0x01,0x11,0x13,0x00,0x10, +0x00,0x00,0x7F,0x3F,0xBF,0x07,0x03,0x03,0x00,0xC1,0x00,0x31,0x80,0x18,0x80,0x06,0xC0,0x01,0xC0,0x00,0xE0,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x07,0x80,0x03,0xF8,0x00,0x7C,0x00, +// 'Z' +0x5A,0x02,0x0E,0x12,0x00,0x0D, +0x7F,0xF9,0xFF,0xE6,0x03,0x18,0x18,0x60,0xC1,0x07,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x30,0xC0,0xC3,0x03,0x1F,0xFE,0x7F,0xF8,0x00,0x60, +// '[' +0x5B,0x01,0x08,0x14,0x01,0x08, +0x00,0x7C,0x7C,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00, +// '\' +0x5C,0x01,0x0A,0x13,0x00,0x0A, +0x00,0x10,0x06,0x01,0x80,0x30,0x0C,0x01,0x80,0x60,0x0C,0x03,0x00,0x60,0x18,0x06,0x00,0xC0,0x30,0x06,0x01,0x80,0x60,0x08, +// ']' +0x5D,0x01,0x08,0x14,0x00,0x08, +0x00,0x7C,0x7E,0x04,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C,0xFC, +// '^' +0x5E,0x03,0x0B,0x0B,0x00,0x0B, +0x00,0x00,0x40,0x18,0x03,0x00,0xF0,0x32,0x0C,0x63,0x86,0x60,0xC0,0x0C,0x00,0x00, +// '_' +0x5F,0x15,0x11,0x02,0xFF,0x0F, +0x7F,0xFF,0x3F,0xFF,0x80, +// '`' +0x60,0x00,0x06,0x07,0x00,0x06, +0x01,0x87,0x0C,0x18,0x20,0x00, +// 'a' +0x61,0x06,0x0C,0x0D,0x00,0x0B, +0x0E,0x03,0xF0,0x31,0x06,0x10,0x23,0x80,0xF8,0x3D,0x87,0x10,0x61,0x0C,0x18,0x63,0xA7,0xFE,0x1C,0xC0, +// 'b' +0x62,0x01,0x0C,0x14,0x00,0x0C, +0x00,0x07,0xC0,0x3C,0x01,0x80,0x18,0x01,0x80,0x18,0x01,0x98,0x1F,0xC1,0xC6,0x18,0x21,0x83,0x10,0x31,0x03,0x18,0x31,0x83,0x18,0x6F,0xC6,0xF7,0xC0,0x30, +// 'c' +0x63,0x06,0x0B,0x0D,0x00,0x0B, +0x06,0x03,0xF0,0xC7,0x31,0xE4,0x1C,0x80,0x30,0x06,0x00,0x60,0x0C,0x01,0xC3,0x1F,0xC0,0xF0, +// 'd' +0x64,0x01,0x0D,0x13,0x00,0x0D, +0x00,0x00,0x1E,0x00,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x01,0x98,0x3E,0x81,0x9C,0x18,0x60,0xC3,0x04,0x08,0x60,0x41,0x02,0x0C,0x30,0x71,0x91,0xFF,0x87,0x1C, +// 'e' +0x65,0x07,0x0B,0x0C,0x00,0x0B, +0x0F,0x03,0xF0,0xC3,0x30,0x66,0x1C,0xDE,0x1E,0x03,0x00,0x60,0x06,0x18,0x7E,0x07,0x80, +// 'f' +0x66,0x02,0x0A,0x12,0x00,0x08, +0x07,0x07,0xE1,0xB8,0x4E,0x10,0x04,0x07,0xE1,0xF8,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x81,0xF8,0x7E,0x00,0x00, +// 'g' +0x67,0x05,0x0A,0x12,0x00,0x0A, +0x00,0x00,0x20,0x18,0x7E,0x3F,0x18,0x64,0x09,0x02,0x61,0x9F,0xC1,0xE0,0x0C,0x01,0x84,0x67,0x19,0x8C,0x7E,0x0F,0x00, +// 'h' +0x68,0x02,0x0E,0x12,0x00,0x0D, +0x78,0x01,0xE0,0x01,0x80,0x06,0x00,0x19,0xC0,0x2F,0x80,0xE6,0x07,0x08,0x18,0x20,0x60,0x81,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x9E,0x7E,0x78,0x00,0x00, +// 'i' +0x69,0x02,0x08,0x11,0x00,0x08, +0x30,0x78,0x78,0x30,0x00,0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7F, +// 'j' +0x6A,0x02,0x09,0x15,0xFE,0x07, +0x06,0x07,0x03,0x81,0xC0,0x00,0xF8,0x7C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x99,0x8F,0xC3,0xC0, +// 'k' +0x6B,0x02,0x0D,0x12,0x00,0x0D, +0x78,0x03,0xC0,0x06,0x00,0x37,0xC1,0xBC,0x0C,0xC0,0x6C,0x03,0xC0,0x1C,0x00,0xC0,0x07,0x00,0x3E,0x01,0xB8,0x08,0x61,0xC1,0xCF,0x07,0x00,0x10,0x00,0x00, +// 'l' +0x6C,0x02,0x08,0x12,0x00,0x08, +0x78,0x78,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00, +// 'm' +0x6D,0x08,0x14,0x0D,0x00,0x14, +0x40,0xC3,0x0F,0xBE,0xF8,0x1E,0x78,0xC1,0xC7,0x0C,0x18,0x20,0xC1,0x82,0x0C,0x10,0x20,0xC1,0x82,0x08,0x18,0x60,0x81,0x84,0x18,0x7E,0x71,0xE7,0xE7,0x9E,0x00,0x00,0x00, +// 'n' +0x6E,0x06,0x0E,0x0E,0x00,0x0D, +0x79,0xC1,0xEF,0x81,0xE6,0x07,0x08,0x18,0x30,0x60,0xC1,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x1E,0x7E,0x78,0x00,0x00, +// 'o' +0x6F,0x08,0x0B,0x0C,0x00,0x0C, +0x0F,0x03,0xF8,0xC3,0x30,0x36,0x06,0x80,0xD0,0x1B,0x03,0x60,0x66,0x18,0xFE,0x07,0x80, +// 'p' +0x70,0x07,0x0B,0x10,0x00,0x0B, +0x07,0x1F,0xF1,0xE3,0x18,0x23,0x06,0x60,0xCC,0x19,0x82,0x30,0xC6,0x18,0xFE,0x1B,0x83,0x00,0x60,0x1C,0x07,0x80, +// 'q' +0x71,0x06,0x0D,0x11,0x00,0x0B, +0x0C,0x01,0xF7,0x0C,0xF8,0xC3,0x04,0x18,0x20,0x41,0x02,0x08,0x10,0x60,0x83,0x04,0x0C,0x60,0x7F,0x01,0xE8,0x00,0xC0,0x06,0xC0,0x1E,0x00,0xE0, +// 'r' +0x72,0x08,0x0A,0x0D,0x00,0x09, +0x77,0x3F,0xE3,0xB8,0xCE,0x33,0x0C,0x03,0x00,0xC0,0x30,0x04,0x07,0xC1,0xF0,0x00,0x00, +// 's' +0x73,0x05,0x0A,0x0E,0x00,0x0A, +0x03,0x00,0xC1,0xF0,0xFC,0x63,0x18,0x47,0x00,0xF8,0x07,0x80,0x64,0x19,0x86,0x7F,0x07,0x80, +// 't' +0x74,0x02,0x09,0x13,0x00,0x09, +0x30,0x18,0x0C,0x06,0x02,0x07,0xE3,0xF8,0x40,0x20,0x10,0x08,0x04,0x02,0x11,0x18,0x84,0x62,0x33,0x0F,0x83,0x00, +// 'u' +0x75,0x06,0x0E,0x0E,0x00,0x0D, +0x00,0x03,0xE7,0xC7,0x9F,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0E,0x7C,0x1F,0xF8,0x3C,0x00, +// 'v' +0x76,0x07,0x0E,0x0D,0x00,0x0D, +0x01,0xFB,0xF3,0xEF,0xC6,0x06,0x18,0x18,0x60,0x31,0x00,0xCC,0x01,0x30,0x06,0x80,0x0A,0x00,0x38,0x00,0xE0,0x01,0x00, +// 'w' +0x77,0x08,0x11,0x0D,0x00,0x11, +0x04,0x1F,0xFF,0x6F,0xBE,0x31,0x83,0x1C,0xC1,0x9E,0x40,0x4D,0x20,0x34,0xB0,0x1A,0x78,0x05,0x3C,0x03,0x8E,0x01,0x86,0x00,0x43,0x00,0x00,0x00, +// 'x' +0x78,0x08,0x0D,0x0D,0x00,0x0D, +0x0C,0xFB,0xE7,0xDE,0x18,0x31,0x80,0xD8,0x03,0x80,0x18,0x01,0xE0,0x19,0x81,0x8C,0x0E,0x7D,0xF3,0xE4,0x00,0x00, +// 'y' +0x79,0x06,0x0F,0x11,0x00,0x0D, +0x7C,0x01,0xF8,0x00,0xC3,0xF0,0xC7,0xE1,0x82,0x01,0x0C,0x03,0x18,0x06,0x20,0x06,0xC0,0x0D,0x00,0x0E,0x00,0x18,0x00,0x30,0x06,0xC0,0x1F,0x00,0x3E,0x00,0x30,0x00, +// 'z' +0x7A,0x08,0x0B,0x0B,0x00,0x0B, +0x7F,0xCF,0xF9,0x86,0x31,0x86,0x60,0x1C,0x07,0x00,0xC6,0x30,0xCF,0xF9,0xFF,0x00, +// '{' +0x7B,0x02,0x09,0x12,0x00,0x08, +0x07,0x07,0x83,0x01,0x01,0x80,0xC0,0x60,0xE0,0x70,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x1F,0x03,0x80, +// '|' +0x7C,0x02,0x03,0x12,0x01,0x05, +0x49,0x24,0x92,0x6D,0xB6,0xDB,0x6C, +// '}' +0x7D,0x02,0x07,0x11,0x00,0x07, +0x30,0xF0,0x20,0x41,0x83,0x02,0x06,0x0E,0x18,0x60,0xC0,0x81,0x83,0x3C,0x78, +// '~' +0x7E,0x09,0x0D,0x04,0x00,0x0D, +0x18,0x03,0xF1,0x98,0xFC,0x83,0xC0, + +// Terminator +0xFF +}; \ No newline at end of file diff --git a/libs/ili9341/src/tftspi.c b/libs/ili9341/src/tftspi.c new file mode 100644 index 0000000..c554720 --- /dev/null +++ b/libs/ili9341/src/tftspi.c @@ -0,0 +1,648 @@ +/* + * Author: LoBo (loboris@gmail.com, loboris.github) + * + * Module supporting SPI TFT displays based on ILI9341 & ILI9488 controllers + * + * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS + * USING DIRECT or DMA SPI TRANSFER MODEs + * +*/ + +#include +#include "tftspi.h" +#include "esp_system.h" +#include "freertos/task.h" +#include "esp_heap_caps.h" +#include "soc/spi_reg.h" +#include "mgos_config.h" + + +// ==================================================== +// ==== Global variables, default values ============== + +// Spi clock for reading data from display memory in Hz +uint32_t max_rdclock = 8000000; + +// Default display dimensions +int _width = DEFAULT_TFT_DISPLAY_WIDTH; +int _height = DEFAULT_TFT_DISPLAY_HEIGHT; + +// Spi device handles for display and touch screen +spi_lobo_device_handle_t disp_spi = NULL; + +// ==================================================== + + +static color_t *trans_cline = NULL; +static uint8_t _dma_sending = 0; + +// RGB to GRAYSCALE constants +// 0.2989 0.5870 0.1140 +#define GS_FACT_R 0.2989 +#define GS_FACT_G 0.4870 +#define GS_FACT_B 0.2140 + + + +// ==== Functions ===================== + +//------------------------------------------------------ +esp_err_t IRAM_ATTR wait_trans_finish(uint8_t free_line) +{ + // Wait for SPI bus ready + while (disp_spi->host->hw->cmd.usr); + if ((free_line) && (trans_cline)) { + free(trans_cline); + trans_cline = NULL; + } + if (_dma_sending) { + //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. + if (disp_spi->host->dma_chan) spi_lobo_dmaworkaround_idle(disp_spi->host->dma_chan); + + // Reset DMA + disp_spi->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST; + disp_spi->host->hw->dma_out_link.start=0; + disp_spi->host->hw->dma_in_link.start=0; + disp_spi->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST); + disp_spi->host->hw->dma_conf.out_data_burst_en=1; + _dma_sending = 0; + } + return ESP_OK; +} + +//------------------------------- +esp_err_t IRAM_ATTR disp_select() +{ + wait_trans_finish(1); + return spi_lobo_device_select(disp_spi, 0); +} + +//--------------------------------- +esp_err_t IRAM_ATTR disp_deselect() +{ + wait_trans_finish(1); + return spi_lobo_device_deselect(disp_spi); +} + +//--------------------------------------------------------------------------------------------------- +static void IRAM_ATTR _spi_transfer_start(spi_lobo_device_handle_t spi_dev, int wrbits, int rdbits) { + // Load send buffer + spi_dev->host->hw->user.usr_mosi_highpart = 0; + spi_dev->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1; + spi_dev->host->hw->user.usr_mosi = 1; + if (rdbits) { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = rdbits; + spi_dev->host->hw->user.usr_miso = 1; + } + else { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = 0; + spi_dev->host->hw->user.usr_miso = 0; + } + // Start transfer + spi_dev->host->hw->cmd.usr = 1; + // Wait for SPI bus ready + while (spi_dev->host->hw->cmd.usr); +} + +// Send 1 byte display command, display must be selected +//------------------------------------------------ +void IRAM_ATTR disp_spi_transfer_cmd(int8_t cmd) { + // Wait for SPI bus ready + while (disp_spi->host->hw->cmd.usr); + + // Set DC to 0 (command mode); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + + disp_spi->host->hw->data_buf[0] = (uint32_t)cmd; + _spi_transfer_start(disp_spi, 8, 0); +} + +// Send command with data to display, display must be selected +//---------------------------------------------------------------------------------- +void IRAM_ATTR disp_spi_transfer_cmd_data(int8_t cmd, uint8_t *data, uint32_t len) { + // Wait for SPI bus ready + while (disp_spi->host->hw->cmd.usr); + + // Set DC to 0 (command mode); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + + disp_spi->host->hw->data_buf[0] = (uint32_t)cmd; + _spi_transfer_start(disp_spi, 8, 0); + + if ((len == 0) || (data == NULL)) return; + + // Set DC to 1 (data mode); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 1); + + uint8_t idx=0, bidx=0; + uint32_t bits=0; + uint32_t count=0; + uint32_t wd = 0; + while (count < len) { + // get data byte from buffer + wd |= (uint32_t)data[count] << bidx; + count++; + bits += 8; + bidx += 8; + if (count == len) { + disp_spi->host->hw->data_buf[idx] = wd; + break; + } + if (bidx == 32) { + disp_spi->host->hw->data_buf[idx] = wd; + idx++; + bidx = 0; + wd = 0; + } + if (idx == 16) { + // SPI buffer full, send data + _spi_transfer_start(disp_spi, bits, 0); + + bits = 0; + idx = 0; + bidx = 0; + } + } + if (bits > 0) _spi_transfer_start(disp_spi, bits, 0); +} + +// Set the address window for display write & read commands, display must be selected +//--------------------------------------------------------------------------------------------------- +static void IRAM_ATTR disp_spi_transfer_addrwin(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2) { + uint32_t wd; + + taskDISABLE_INTERRUPTS(); + // Wait for SPI bus ready + while (disp_spi->host->hw->cmd.usr); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + + disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_CASET; + disp_spi->host->hw->user.usr_mosi_highpart = 0; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + disp_spi->host->hw->user.usr_mosi = 1; + disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0; + disp_spi->host->hw->user.usr_miso = 0; + + disp_spi->host->hw->cmd.usr = 1; // Start transfer + + wd = (uint32_t)(x1>>8); + wd |= (uint32_t)(x1&0xff) << 8; + wd |= (uint32_t)(x2>>8) << 16; + wd |= (uint32_t)(x2&0xff) << 24; + + while (disp_spi->host->hw->cmd.usr); // wait transfer end + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 1); + disp_spi->host->hw->data_buf[0] = wd; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 31; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + + while (disp_spi->host->hw->cmd.usr); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_PASET; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + + wd = (uint32_t)(y1>>8); + wd |= (uint32_t)(y1&0xff) << 8; + wd |= (uint32_t)(y2>>8) << 16; + wd |= (uint32_t)(y2&0xff) << 24; + + while (disp_spi->host->hw->cmd.usr); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 1); + + disp_spi->host->hw->data_buf[0] = wd; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 31; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (disp_spi->host->hw->cmd.usr); + taskENABLE_INTERRUPTS(); +} + +// Set display pixel at given coordinates to given color +//------------------------------------------------------------------------ +void IRAM_ATTR drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) +{ + if (!(disp_spi->cfg.flags & SPI_DEVICE_HALFDUPLEX)) return; + + if (sel) { + if (disp_select()) return; + } + else wait_trans_finish(1); + + uint32_t wd = 0; + color_t _color = color; + + taskDISABLE_INTERRUPTS(); + disp_spi_transfer_addrwin(x, x+1, y, y+1); + + // Send RAM WRITE command + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_RAMWR; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + wd = (uint32_t)_color.r; + wd |= (uint32_t)_color.g << 8; + wd |= (uint32_t)_color.b << 16; + + // Set DC to 1 (data mode); + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 1); + + disp_spi->host->hw->data_buf[0] = wd; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 23; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + taskENABLE_INTERRUPTS(); + if (sel) disp_deselect(); +} + +//----------------------------------------------------------- +static void IRAM_ATTR _dma_send(uint8_t *data, uint32_t size) +{ + //Fill DMA descriptors + spi_lobo_dmaworkaround_transfer_active(disp_spi->host->dma_chan); //mark channel as active + spi_lobo_setup_dma_desc_links(disp_spi->host->dmadesc_tx, size, data, false); + disp_spi->host->hw->user.usr_mosi_highpart=0; + disp_spi->host->hw->dma_out_link.addr=(int)(&disp_spi->host->dmadesc_tx[0]) & 0xFFFFF; + disp_spi->host->hw->dma_out_link.start=1; + disp_spi->host->hw->user.usr_mosi_highpart=0; + + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1; + + _dma_sending = 1; + // Start transfer + disp_spi->host->hw->cmd.usr = 1; +} + +//--------------------------------------------------------------------------- +static void IRAM_ATTR _direct_send(color_t *color, uint32_t len, uint8_t rep) +{ + uint32_t cidx = 0; // color buffer index + uint32_t wd = 0; + int idx = 0; + int bits = 0; + int wbits = 0; + + taskDISABLE_INTERRUPTS(); + color_t _color = color[0]; + + while (len) { + // ** Get color data from color buffer ** + if (rep == 0) { + _color = color[cidx]; + } + + wd |= (uint32_t)_color.r << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + wd |= (uint32_t)_color.g << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + wd |= (uint32_t)_color.b << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + len--; // Decrement colors counter + if (rep == 0) cidx++; // if not repeating color, increment color buffer index + } + if (bits) { + while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // set number of bits to be sent + disp_spi->host->hw->cmd.usr = 1; // Start transfer + } + taskENABLE_INTERRUPTS(); +} + +// ================================================================ +// === Main function to send data to display ====================== +// If rep==true: repeat sending color data to display 'len' times +// If rep==false: send 'len' color data from color buffer to display +// ** Device must already be selected and address window set ** +// ================================================================ +//---------------------------------------------------------------------------------------------- +static void IRAM_ATTR _pushColorRep(color_t *color, uint32_t len, uint8_t rep, uint8_t wait) +{ + if (len == 0) return; + if (!(disp_spi->cfg.flags & SPI_DEVICE_HALFDUPLEX)) return; + + // Send RAM WRITE command + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 0); + disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_RAMWR; + disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + gpio_set_level(mgos_sys_config_get_ili9341_dc_pin(), 1); // Set DC to 1 (data mode); + + if ((len*24) <= 512) { + + _direct_send(color, len, rep); + + } + else if (rep == 0) { + // ==== use DMA transfer ==== + _dma_send((uint8_t *)color, len*3); + } + + else { + // ==== Repeat color, more than 512 bits total ==== + + color_t _color; + uint32_t buf_colors; + int buf_bytes, to_send; + + /* + to_send = len; + while (to_send > 0) { + wait_trans_finish(0); + _direct_send(color, ((to_send > 21) ? 21 : to_send), rep); + to_send -= 21; + } + */ + + buf_colors = ((len > (_width*2)) ? (_width*2) : len); + buf_bytes = buf_colors * 3; + + // Prepare color buffer of maximum 2 color lines + trans_cline = heap_caps_malloc(buf_bytes, MALLOC_CAP_DMA); + if (trans_cline == NULL) return; + + // Prepare fill color + else _color = color[0]; + + // Fill color buffer with fill color + for (uint32_t i=0; i 0) { + wait_trans_finish(0); + _dma_send((uint8_t *)trans_cline, ((to_send > buf_colors) ? buf_bytes : (to_send*3))); + to_send -= buf_colors; + } + } + + if (wait) wait_trans_finish(1); +} + +// Write 'len' color data to TFT 'window' (x1,y2),(x2,y2) +//------------------------------------------------------------------------------------------- +void IRAM_ATTR mgos_ili9341_pushColorRep(int x1, int y1, int x2, int y2, color_t color, uint32_t len) +{ + if (disp_select() != ESP_OK) return; + + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + + _pushColorRep(&color, len, 1, 1); + + disp_deselect(); +} + +// Write 'len' color data to TFT 'window' (x1,y2),(x2,y2) from given buffer +// ** Device must already be selected ** +//----------------------------------------------------------------------------------- +void IRAM_ATTR send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf) +{ + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + _pushColorRep(buf, len, 0, 0); +} + +// Reads 'len' pixels/colors from the TFT's GRAM 'window' +// 'buf' is an array of bytes with 1st byte reserved for reading 1 dummy byte +// and the rest is actually an array of color_t values +//-------------------------------------------------------------------------------------------- +int IRAM_ATTR read_data(int x1, int y1, int x2, int y2, int len, uint8_t *buf, uint8_t set_sp) +{ + spi_lobo_transaction_t t; + uint32_t current_clock = 0; + + memset(&t, 0, sizeof(t)); //Zero out the transaction + memset(buf, 0, len*sizeof(color_t)); + + if (set_sp) { + if (disp_deselect() != ESP_OK) return -1; + // Change spi clock if needed + current_clock = spi_lobo_get_speed(disp_spi); + if (max_rdclock < current_clock) spi_lobo_set_speed(disp_spi, max_rdclock); + } + + if (disp_select() != ESP_OK) return -2; + + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + + // ** GET pixels/colors ** + disp_spi_transfer_cmd(TFT_RAMRD); + + t.length=0; //Send nothing + t.tx_buffer=NULL; + t.rxlength=8*((len*3)+1); //Receive size in bits + t.rx_buffer=buf; + //t.user = (void*)1; + + esp_err_t res = spi_lobo_transfer_data(disp_spi, &t); // Receive using direct mode + + disp_deselect(); + + if (set_sp) { + // Restore spi clock if needed + if (max_rdclock < current_clock) spi_lobo_set_speed(disp_spi, current_clock); + } + + return res; +} + +// Reads one pixel/color from the TFT's GRAM at position (x,y) +//----------------------------------------------- +color_t IRAM_ATTR readPixel(int16_t x, int16_t y) +{ + uint8_t color_buf[sizeof(color_t)+1] = {0}; + + read_data(x, y, x+1, y+1, 1, color_buf, 1); + + color_t color; + color.r = color_buf[1]; + color.g = color_buf[2]; + color.b = color_buf[3]; + return color; +} + +// Find maximum spi clock for successful read from display RAM +// ** Must be used AFTER the display is initialized ** +//====================== +uint32_t find_rd_speed() +{ + esp_err_t ret; + color_t color; + uint32_t max_speed = 1000000; + uint32_t change_speed, cur_speed; + int line_check; + color_t *color_line = NULL; + uint8_t *line_rdbuf = NULL; + cur_speed = spi_lobo_get_speed(disp_spi); + + color_line = malloc(_width*3); + if (color_line == NULL) goto exit; + + line_rdbuf = malloc((_width*3)+1); + if (line_rdbuf == NULL) goto exit; + + color_t *rdline = (color_t *)(line_rdbuf+1); + + // Fill test line with colors + color = (color_t){0xEC,0xA8,0x74}; + for (int x=0; x<_width; x++) { + color_line[x] = color; + } + + // Find maximum read spi clock + for (uint32_t speed=2000000; speed<=cur_speed; speed += 1000000) { + change_speed = spi_lobo_set_speed(disp_spi, speed); + if (change_speed == 0) goto exit; + + memset(line_rdbuf, 0, _width*sizeof(color_t)+1); + + if (disp_select()) goto exit; + // Write color line + send_data(0, _height/2, _width-1, _height/2, _width, color_line); + if (disp_deselect()) goto exit; + + // Read color line + ret = read_data(0, _height/2, _width-1, _height/2, _width, line_rdbuf, 0); + + // Compare + line_check = 0; + if (ret == ESP_OK) { + for (int y=0; y<_width; y++) { + if ((color_line[y].r & 0xFC) != (rdline[y].r & 0xFC)) line_check = 1; + else if ((color_line[y].g & 0xFC) != (rdline[y].g & 0xFC)) line_check = 1; + else if ((color_line[y].b & 0xFC) != (rdline[y].b & 0xFC)) line_check = 1; + if (line_check) break; + } + } + else line_check = ret; + + if (line_check) break; + max_speed = speed; + } + +exit: + if (line_rdbuf) free(line_rdbuf); + if (color_line) free(color_line); + + // restore spi clk + change_speed = spi_lobo_set_speed(disp_spi, cur_speed); + + return max_speed; +} + +//--------------------------------------------------------------------------- +// Companion code to the initialization table. +// Reads and issues a series of LCD commands stored in byte array +//--------------------------------------------------------------------------- +static void commandList(spi_lobo_device_handle_t spi, const uint8_t *addr) { + uint8_t numCommands, numArgs, cmd; + uint16_t ms; + + numCommands = *addr++; // Number of commands to follow + while(numCommands--) { // For each command... + cmd = *addr++; // save command + numArgs = *addr++; // Number of args to follow + ms = numArgs & TFT_CMD_DELAY; // If high bit set, delay follows args + numArgs &= ~TFT_CMD_DELAY; // Mask out delay bit + + disp_spi_transfer_cmd_data(cmd, (uint8_t *)addr, numArgs); + + addr += numArgs; + + if(ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + vTaskDelay(ms / portTICK_RATE_MS); + } + } +} + +//================================== +void _tft_setRotation(uint8_t rot) { + uint8_t rotation = rot & 3; // can't be higher than 3 + uint8_t send = 1; + uint8_t madctl = 0; + uint16_t tmp; + + if ((rotation & 1)) { + // in landscape modes must be width > height + if (_width < _height) { + tmp = _width; + _width = _height; + _height = tmp; + } + } + else { + // in portrait modes must be width < height + if (_width > _height) { + tmp = _width; + _width = _height; + _height = tmp; + } + } + switch (rotation) { + case PORTRAIT: + madctl = (MADCTL_MX | TFT_RGB_BGR); + break; + case LANDSCAPE: + madctl = (MADCTL_MV | TFT_RGB_BGR); + break; + case PORTRAIT_FLIP: + madctl = (MADCTL_MY | TFT_RGB_BGR); + break; + case LANDSCAPE_FLIP: + madctl = (MADCTL_MX | MADCTL_MY | MADCTL_MV | TFT_RGB_BGR); + break; + } + if (send) { + if (disp_select() == ESP_OK) { + disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); + disp_deselect(); + } + } + +} + +// Initialize the display +// ==================== +void mgos_ili9341_display_init() +{ + esp_err_t ret; + + ret = disp_select(); + assert(ret==ESP_OK); + + commandList(disp_spi, ILI9341_init); + + ret = disp_deselect(); + assert(ret==ESP_OK); + + mgos_ili9341_pushColorRep(0, 0, _width-1, _height-1, (color_t){0,0,0}, (uint32_t)(_height*_width)); +} + + diff --git a/libs/ili9341/src/tooney32.c b/libs/ili9341/src/tooney32.c new file mode 100644 index 0000000..753fb2d --- /dev/null +++ b/libs/ili9341/src/tooney32.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// tooney32.c +// Point Size : 32 +// Memory usage : 5470 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_tooney32[] = +{ +0x00, 0x20, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x1E,0x00,0x00,0x00,0x09, + +// '!' +0x21,0x09,0x0B,0x16,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x27,0x00,0xE0,0x1C,0x21,0x84,0x30,0x86,0x10,0xC2,0x18,0x43,0xF0,0x61,0x0C,0x13,0x02,0x60,0x4E,0x09,0xE2,0x1F,0x81,0xE0,0x00,0x00, +// '"' +0x22,0x05,0x0E,0x0A,0xFF,0x0D, +0x04,0x30,0x2D,0x61,0x8C,0x44,0x71,0x31,0x88,0xCE,0x42,0x72,0x18,0xC8,0x7B,0xC0,0xC6,0x00, +// '#' +0x23,0x07,0x18,0x16,0x00,0x18, +0x00,0xFF,0xF8,0x01,0x83,0x08,0x01,0x82,0x08,0x01,0x82,0x08,0x0F,0x06,0x0F,0x10,0x00,0x01,0x30,0x00,0x01,0x30,0x00,0x00,0x20,0x00,0x02,0x7E,0x0C,0x1E,0x7E,0x0C,0x1E,0x60,0x00,0x02,0x60,0x00,0x00,0x40,0x00,0x04,0x40,0x00,0x04,0xC0,0x00,0x04,0xFC,0x10,0x78,0xFC,0x30,0x78,0x08,0x30,0x40,0x18,0x30,0x40,0x1F,0xFF,0x80,0x1F,0xFF,0x80, +// '$' +0x24,0x09,0x0F,0x14,0x00,0x0F, +0x01,0x80,0x04,0xF8,0x18,0x08,0x20,0x10,0xC0,0x41,0x00,0x86,0x01,0x0C,0x12,0x18,0x38,0x30,0x60,0xA0,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x10,0x30,0x20,0x6E,0x40,0xFF,0x81,0x9E,0x00,0x18,0x00, +// '%' +0x25,0x07,0x17,0x16,0x00,0x17, +0x0F,0x81,0xF8,0x20,0x84,0x10,0x80,0x98,0x42,0x00,0x21,0x0C,0x01,0x82,0x18,0x43,0x08,0x30,0x04,0x10,0x70,0x18,0x40,0xE0,0x21,0x00,0xF1,0x82,0x00,0xFF,0x0F,0xC0,0xFC,0x10,0x40,0x18,0x40,0x40,0x21,0x80,0x40,0x82,0x00,0x83,0x0C,0x21,0x04,0x18,0x02,0x18,0x78,0x04,0x21,0x30,0x10,0xC2,0x78,0xC3,0xF8,0x7F,0x07,0xE0,0x7C,0x00, +// '&' +0x26,0x08,0x17,0x17,0x00,0x17, +0x01,0xF6,0x00,0x04,0x1A,0x00,0x10,0x04,0x00,0x40,0x10,0x01,0x00,0x40,0x06,0x00,0x80,0x0C,0x1A,0x00,0x18,0x1F,0xC0,0x30,0x18,0xF8,0x60,0x08,0x09,0x80,0x00,0x33,0x00,0x00,0xCC,0x0C,0x01,0x18,0x3C,0x04,0x30,0x30,0x07,0x60,0x00,0x01,0xE0,0x00,0x07,0xC0,0x00,0x09,0xC0,0x0C,0x23,0xC0,0x38,0x03,0xE1,0xF8,0x03,0xFF,0x70,0x01,0xF8,0x60,0x00, +// ''' +0x27,0x05,0x09,0x0A,0xFF,0x08, +0x06,0x05,0x86,0x23,0x13,0x11,0x90,0x90,0xC8,0x78,0x18,0x00, +// '(' +0x28,0x05,0x0D,0x1D,0x00,0x0D, +0x03,0x00,0x34,0x01,0x90,0x08,0x40,0x81,0x88,0x1C,0xC1,0xC4,0x08,0x60,0x83,0x04,0x10,0x41,0x82,0x0C,0x10,0x60,0x83,0x04,0x18,0x20,0xC0,0x06,0x04,0x38,0x20,0xC0,0x87,0x06,0x38,0x1C,0xE0,0x67,0x86,0x1C,0x60,0x76,0x01,0xE0,0x0E,0x00,0x60,0x00, +// ')' +0x29,0x05,0x0D,0x1D,0x00,0x0D, +0x01,0x00,0x10,0x01,0x20,0x11,0x03,0x04,0x30,0x11,0xE0,0x8F,0x82,0x1C,0x10,0x70,0x81,0x82,0x0E,0x10,0x30,0x81,0x84,0x0C,0x20,0x61,0x02,0x08,0x10,0x01,0x84,0x08,0x20,0x81,0x18,0x11,0x80,0x8E,0x08,0x78,0x80,0xE4,0x03,0xE0,0x0E,0x00,0x30,0x00, +// '*' +0x2A,0x09,0x0C,0x0D,0x01,0x0D, +0x07,0x00,0x88,0x18,0xE4,0x11,0xC0,0x1F,0x8E,0xC0,0x1C,0x11,0xC8,0xBF,0x8E,0x7D,0xC1,0xE0,0x0C,0x00, +// '+' +0x2B,0x09,0x15,0x14,0x00,0x15, +0x00,0x7C,0x00,0x04,0x10,0x00,0x60,0x80,0x07,0x04,0x00,0x38,0x20,0x01,0xC1,0x00,0xFE,0x0F,0xCC,0x00,0x01,0xE0,0x00,0x0F,0x00,0x00,0x78,0x00,0x03,0xFF,0x07,0xFF,0xF8,0x3F,0x7F,0xC1,0xF0,0x0E,0x08,0x00,0x70,0x40,0x03,0x82,0x00,0x1F,0xF0,0x00,0xFE,0x00,0x03,0xE0,0x00, +// ',' +0x2C,0x17,0x09,0x0B,0x00,0x09, +0x1E,0x10,0x98,0x38,0x1C,0x0F,0x0B,0xC4,0xE4,0x32,0x1E,0x0E,0x00, +// '-' +0x2D,0x11,0x09,0x06,0x00,0x09, +0x1B,0x90,0x50,0x39,0x2F,0xE7,0xF0, +// '.' +0x2E,0x16,0x09,0x09,0x00,0x09, +0x1E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00, +// '/' +0x2F,0x09,0x11,0x19,0x00,0x11, +0x00,0x3F,0x80,0x30,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xC1,0x00,0xC0,0x80,0x60,0x00,0x60,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0xFE,0x01,0xFE,0x00,0xFE,0x00,0x00, +// '0' +0x30,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// '1' +0x31,0x09,0x0D,0x16,0x00,0x0D, +0x00,0x30,0x06,0x40,0xC4,0x18,0x43,0x02,0x20,0x13,0xC0,0x9E,0x04,0x30,0x21,0x81,0x0C,0x08,0x60,0x43,0x02,0x18,0x10,0xC0,0x86,0x04,0x30,0x21,0x81,0x98,0x03,0xFF,0xE7,0xFE,0x00,0x00, +// '2' +0x32,0x08,0x12,0x17,0x00,0x12, +0x00,0xF0,0x00,0x81,0x00,0xC0,0x20,0xE0,0x04,0x40,0x01,0x38,0x00,0x2F,0x84,0x08,0xF9,0x82,0x1F,0xE0,0x81,0xF0,0x00,0x1C,0x10,0x06,0x04,0x01,0x03,0x80,0xC0,0xD0,0x20,0x04,0x18,0x01,0x0C,0x00,0x43,0x00,0x11,0x80,0x04,0x60,0x01,0x3F,0xFF,0x4F,0xFF,0xE0,0x00,0x30, +// '3' +0x33,0x08,0x12,0x17,0x00,0x12, +0x0C,0x00,0x05,0xFF,0xE3,0x00,0x08,0xC0,0x02,0x30,0x01,0x0C,0x00,0x43,0x00,0x10,0xC0,0x0C,0x37,0x01,0x0F,0x80,0x23,0xE0,0x08,0x10,0x01,0x0F,0xE0,0x43,0xF8,0x10,0x4E,0x04,0x23,0x01,0x10,0x00,0x08,0x00,0x24,0x00,0x13,0x00,0x08,0xFC,0x0C,0x1F,0xFE,0x00,0xFE,0x00, +// '4' +0x34,0x09,0x12,0x16,0x00,0x12, +0x00,0x0E,0x00,0x04,0x80,0x06,0x20,0x03,0x08,0x01,0x82,0x00,0xC0,0x80,0x40,0x20,0x20,0x08,0x10,0x03,0x88,0x20,0x94,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0xFE,0x09,0xFF,0x83,0x80,0x60,0xC0,0x30,0x10,0x0F,0xF8,0x03,0xFC,0x00,0x00,0x00, +// '5' +0x35,0x08,0x11,0x17,0x00,0x11, +0x00,0x03,0x00,0xFF,0x40,0x80,0x20,0xC0,0x10,0x60,0x08,0x30,0x04,0x30,0x02,0x18,0x1D,0x0C,0x07,0x06,0x01,0x82,0x00,0x43,0x00,0x11,0xFC,0x08,0xFF,0x04,0x17,0x82,0x18,0x01,0x18,0x00,0x08,0x00,0x8C,0x00,0x8C,0x00,0xC7,0xC1,0xC3,0xFF,0x80,0xBF,0x00, +// '6' +0x36,0x08,0x13,0x17,0x00,0x13, +0x00,0x7F,0xC0,0x30,0x08,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x02,0x08,0x0C,0x83,0x00,0x30,0x60,0x01,0x18,0x00,0x13,0x00,0x01,0x60,0x00,0x0C,0x00,0x03,0x80,0xC0,0x78,0x3C,0x0F,0x03,0x01,0x60,0x00,0x0E,0x00,0x08,0xE0,0x02,0x1E,0x00,0x81,0xF0,0x60,0x1F,0xF8,0x00,0xFC,0x00, +// '7' +0x37,0x08,0x12,0x17,0x00,0x12, +0x0C,0x00,0x0D,0xFF,0xF3,0x00,0x04,0xC0,0x02,0x30,0x00,0x8C,0x00,0x43,0x00,0x10,0xDC,0x08,0x3F,0x02,0x0E,0x81,0x00,0x60,0x40,0x10,0x20,0x0C,0x08,0x02,0x04,0x01,0x81,0x00,0x40,0x80,0x30,0x20,0x10,0x10,0x0F,0x04,0x03,0xF1,0x00,0x3F,0x40,0x03,0xE0,0x00,0x30,0x00, +// '8' +0x38,0x08,0x12,0x17,0x00,0x12, +0x01,0xF0,0x00,0x83,0x00,0xC0,0x20,0x20,0x08,0x10,0x01,0x0C,0x18,0x43,0x06,0x10,0xC0,0x04,0x38,0x01,0x0C,0x00,0x42,0x00,0x09,0x80,0x01,0xC0,0x00,0x70,0x3C,0x1C,0x0F,0x07,0x00,0x01,0xE0,0x00,0x9C,0x00,0x27,0x80,0x30,0xF8,0x38,0x1F,0xFC,0x01,0xFC,0x00,0x00,0x00, +// '9' +0x39,0x08,0x13,0x17,0x00,0x13, +0x01,0xF8,0x00,0xC0,0xC0,0x20,0x04,0x08,0x00,0x42,0x00,0x08,0xC0,0x00,0x90,0x18,0x16,0x07,0x81,0xC0,0x60,0x38,0x00,0x07,0x80,0x00,0xF0,0x00,0x17,0x00,0x02,0xF0,0x00,0x0F,0x80,0x10,0xE6,0x02,0x08,0x00,0x83,0x00,0x20,0x40,0x0C,0x10,0x03,0x06,0xC1,0xC0,0xFF,0xE0,0x1F,0xF0,0x00, +// ':' +0x3A,0x0E,0x09,0x11,0x00,0x09, +0x0E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3C,0x19,0x98,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00, +// ';' +0x3B,0x0F,0x09,0x13,0x00,0x09, +0x0E,0x10,0x98,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3E,0x19,0x98,0x38,0x1C,0x0F,0x03,0xC4,0xE4,0x32,0x1E,0x0E,0x00, +// '<' +0x3C,0x0A,0x13,0x13,0x00,0x13, +0x00,0x00,0xC0,0x00,0x64,0x00,0x60,0x80,0x30,0x10,0x38,0x02,0x18,0x03,0x8C,0x01,0xE3,0x01,0xF0,0xE0,0xF8,0x1C,0x06,0x03,0x80,0x18,0x7E,0x00,0xCF,0xF0,0x06,0x7F,0xC0,0x43,0xFE,0x08,0x0F,0xF9,0x00,0x7F,0xE0,0x01,0xF8,0x00,0x0C,0x00, +// '=' +0x3D,0x0D,0x14,0x0E,0x00,0x14, +0x3F,0xFF,0xE6,0x00,0x01,0xE0,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xE6,0x00,0x01,0x60,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF8, +// '>' +0x3E,0x0A,0x13,0x13,0x00,0x13, +0x38,0x00,0x0C,0xC0,0x03,0x87,0x00,0x70,0x18,0x0E,0x00,0xE1,0xF8,0x03,0x3F,0xC0,0x19,0xFF,0x01,0x0F,0xF8,0x20,0x3C,0x04,0x0C,0x00,0x86,0x00,0xE3,0x00,0x78,0xC0,0x7C,0x38,0x3E,0x07,0x3E,0x00,0xFF,0x00,0x1F,0x00,0x03,0x80,0x00,0x00, +// '?' +0x3F,0x08,0x11,0x16,0x00,0x11, +0x00,0xF0,0x01,0x82,0x01,0x00,0x81,0x00,0x23,0x00,0x0B,0x00,0x05,0xC0,0x02,0xF8,0xC1,0x3F,0x40,0x87,0xE0,0x80,0xE0,0x40,0x30,0x40,0x18,0x20,0x0F,0xE0,0x07,0x30,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xE0,0x80,0x78,0x80,0x1F,0x80,0x07,0x80, +// '@' +0x40,0x09,0x16,0x16,0x00,0x16, +0x00,0x3F,0x00,0x06,0x03,0x00,0x23,0xFB,0x01,0x3F,0xFC,0x09,0x81,0xF8,0x48,0x7F,0xE2,0x44,0x13,0xD9,0x23,0x8F,0x41,0x1E,0x1F,0x2C,0x51,0x7C,0xE0,0xC5,0xF3,0x8B,0x06,0xCE,0x28,0x3B,0x38,0xE2,0xEE,0x71,0x4D,0x19,0xE3,0x88,0x73,0xFF,0xD1,0xE7,0x9F,0xA3,0xC7,0xF1,0x07,0xE0,0x38,0x07,0xFF,0x80,0x07,0xF8,0x00, +// 'A' +0x41,0x08,0x19,0x17,0x00,0x19, +0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00, +// 'B' +0x42,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80, +// 'C' +0x43,0x08,0x16,0x17,0x00,0x16, +0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00, +// 'D' +0x44,0x09,0x16,0x15,0xFF,0x15, +0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00, +// 'E' +0x45,0x08,0x11,0x17,0x00,0x11, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08, +// 'F' +0x46,0x08,0x11,0x16,0xFF,0x10, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00, +// 'G' +0x47,0x08,0x16,0x17,0x00,0x16, +0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00, +// 'H' +0x48,0x09,0x16,0x15,0x00,0x16, +0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00, +// 'I' +0x49,0x09,0x0B,0x15,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8, +// 'J' +0x4A,0x09,0x0F,0x16,0x00,0x0F, +0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00, +// 'K' +0x4B,0x08,0x17,0x18,0x00,0x17, +0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00, +// 'L' +0x4C,0x09,0x11,0x16,0x00,0x11, +0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30, +// 'M' +0x4D,0x09,0x20,0x16,0x00,0x1F, +0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00, +// 'N' +0x4E,0x09,0x17,0x15,0x00,0x17, +0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80, +// 'O' +0x4F,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// 'P' +0x50,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00, +// 'Q' +0x51,0x09,0x17,0x1C,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00, +// 'R' +0x52,0x09,0x18,0x17,0x00,0x18, +0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00, +// 'S' +0x53,0x07,0x11,0x19,0x00,0x11, +0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00, +// 'T' +0x54,0x08,0x12,0x16,0x01,0x13, +0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00, +// 'U' +0x55,0x09,0x19,0x16,0xFF,0x18, +0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00, +// 'V' +0x56,0x07,0x19,0x18,0x00,0x19, +0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00, +// 'W' +0x57,0x07,0x20,0x18,0x00,0x20, +0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00, +// 'X' +0x58,0x05,0x19,0x1D,0x00,0x18, +0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00, +// 'Y' +0x59,0x06,0x19,0x1B,0x00,0x19, +0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00, +// 'Z' +0x5A,0x08,0x13,0x17,0xFF,0x12, +0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80, +// '[' +0x5B,0x04,0x0B,0x20,0x00,0x0B, +0x00,0x40,0x19,0xFD,0x60,0x2C,0x05,0x80,0xB0,0x16,0x0E,0xC1,0xD8,0x33,0x04,0x60,0x8C,0x11,0x82,0x30,0x46,0x08,0xC1,0x18,0x23,0x04,0x60,0x8C,0x11,0x82,0xB0,0x76,0x02,0xC0,0x58,0x0B,0x01,0x60,0x2F,0xFD,0xFF,0x80,0x60,0x00, +// '\' +0x5C,0x09,0x11,0x18,0x00,0x11, +0x3F,0x00,0x30,0x40,0x38,0x10,0x1E,0x08,0x0F,0x04,0x03,0x81,0x01,0xE0,0x80,0x70,0x20,0x3C,0x10,0x1E,0x08,0x07,0x02,0x03,0xC1,0x00,0xE0,0x40,0x78,0x20,0x3C,0x08,0x0F,0x04,0x07,0x82,0x01,0xC0,0x80,0xF0,0x40,0x38,0x10,0x1E,0x08,0x0F,0xFC,0x03,0xFC,0x01,0xFC, +// ']' +0x5D,0x04,0x0C,0x1F,0xFF,0x0B, +0x30,0x02,0xFF,0x60,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0xC1,0x7C,0x16,0xC1,0x6C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x13,0xC1,0x6C,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0x01,0x7F,0xE7,0xFE,0x60,0x00, +// '^' +0x5E,0x1E,0x00,0x00,0x00,0x09, + +// '_' +0x5F,0x20,0x10,0x04,0x00,0x10, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '`' +0x60,0x00,0x0A,0x09,0x00,0x0B, +0x00,0x06,0x02,0x61,0x8C,0x60,0xBF,0x17,0xFC,0x3E,0x03,0x00, +// 'a' +0x61,0x08,0x19,0x17,0x00,0x19, +0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00, +// 'b' +0x62,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80, +// 'c' +0x63,0x08,0x16,0x17,0x00,0x16, +0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00, +// 'd' +0x64,0x09,0x16,0x15,0xFF,0x15, +0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00, +// 'e' +0x65,0x08,0x11,0x17,0x00,0x11, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08, +// 'f' +0x66,0x08,0x11,0x16,0xFF,0x10, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00, +// 'g' +0x67,0x08,0x16,0x17,0x00,0x16, +0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00, +// 'h' +0x68,0x09,0x16,0x15,0x00,0x16, +0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00, +// 'i' +0x69,0x09,0x0B,0x15,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8, +// 'j' +0x6A,0x09,0x0F,0x16,0x00,0x0F, +0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00, +// 'k' +0x6B,0x08,0x17,0x18,0x00,0x17, +0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00, +// 'l' +0x6C,0x09,0x11,0x16,0x00,0x11, +0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30, +// 'm' +0x6D,0x09,0x20,0x16,0x00,0x1F, +0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00, +// 'n' +0x6E,0x09,0x17,0x15,0x00,0x17, +0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80, +// 'o' +0x6F,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// 'p' +0x70,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00, +// 'q' +0x71,0x09,0x17,0x1C,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00, +// 'r' +0x72,0x09,0x18,0x17,0x00,0x18, +0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00, +// 's' +0x73,0x07,0x11,0x19,0x00,0x11, +0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00, +// 't' +0x74,0x08,0x12,0x16,0x01,0x13, +0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00, +// 'u' +0x75,0x09,0x19,0x16,0xFF,0x18, +0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00, +// 'v' +0x76,0x07,0x19,0x18,0x00,0x19, +0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00, +// 'w' +0x77,0x07,0x20,0x18,0x00,0x20, +0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00, +// 'x' +0x78,0x05,0x19,0x1D,0x00,0x18, +0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00, +// 'y' +0x79,0x06,0x19,0x1B,0x00,0x19, +0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00, +// 'z' +0x7A,0x08,0x13,0x17,0xFF,0x12, +0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80, +// '{' +0x7B,0x05,0x0D,0x1F,0x01,0x0E, +0x00,0x10,0x0E,0x81,0x04,0x10,0x21,0x81,0x08,0x08,0xC0,0x46,0x0E,0x30,0x71,0x83,0x0C,0x10,0x60,0x84,0x04,0x60,0x23,0x02,0x18,0x08,0xC0,0x47,0x82,0x3C,0x10,0x60,0x83,0x05,0x18,0x38,0xC0,0x46,0x02,0x38,0x11,0xC0,0x87,0x84,0x1F,0xE0,0x7F,0x00,0x30,0x00,0x00, +// '|' +0x7C,0x1E,0x00,0x00,0x00,0x09, + +// '}' +0x7D,0x04,0x0E,0x1F,0x00,0x0F, +0x30,0x00,0xBC,0x06,0x0C,0x18,0x08,0x60,0x21,0x80,0x46,0x01,0x1F,0x04,0x7C,0x11,0xB0,0x44,0xC1,0x03,0x04,0x0C,0x0C,0x30,0x10,0xE0,0x43,0x81,0x04,0x04,0x30,0x70,0xC1,0x03,0x04,0x0C,0x10,0xF0,0x46,0xC1,0x18,0x04,0x60,0x11,0x80,0x86,0x04,0x18,0x60,0x7F,0x81,0xF8,0x06,0x00,0x00, +// '~' +0x7E,0x1E,0x00,0x00,0x00,0x09, + + +// Terminator +0xFF +}; diff --git a/libs/lobo-spi/LICENSE b/libs/lobo-spi/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/libs/lobo-spi/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/libs/lobo-spi/README.md b/libs/lobo-spi/README.md new file mode 100644 index 0000000..1e06a68 --- /dev/null +++ b/libs/lobo-spi/README.md @@ -0,0 +1,3 @@ +# mos-lobo-spi-lib + +SPI lib for mongoose-os based on https://github.com/loboris/ESP32_TFT_library diff --git a/libs/lobo-spi/include/lobo_spi.h b/libs/lobo-spi/include/lobo_spi.h new file mode 100755 index 0000000..d11410e --- /dev/null +++ b/libs/lobo-spi/include/lobo_spi.h @@ -0,0 +1,361 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef _DRIVER_SPI_MASTER_LOBO_H_ +#define _DRIVER_SPI_MASTER_LOBO_H_ + +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/spi_struct.h" + +#include "esp_intr.h" +#include "esp_intr_alloc.h" +#include "rom/lldesc.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +//Maximum amount of bytes that can be put in one DMA descriptor +#define SPI_MAX_DMA_LEN (4096-4) + +/** + * @brief Enum with the three SPI peripherals that are software-accessible in it + */ +typedef enum { + SPI_HOST=0, ///< SPI1, SPI; Cannot be used in this driver! + HSPI_HOST=1, ///< SPI2, HSPI + VSPI_HOST=2 ///< SPI3, VSPI +} spi_lobo_host_device_t; + + +/** + * @brief This is a configuration structure for a SPI bus. + * + * You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the + * GPIO matrix to route the signals. An exception is made when all signals either can be routed through + * the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds. + */ +typedef struct { + int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used. + int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used. + int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used. + int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used. + int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used. + int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0. +} spi_lobo_bus_config_t; + + +#define SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first +#define SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first +#define SPI_DEVICE_BIT_LSBFIRST (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first +#define SPI_DEVICE_3WIRE (1<<2) ///< Use spiq for both sending and receiving data +#define SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative +#define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously +#define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active + +#define SPI_ERR_OTHER_CONFIG 7001 + +typedef struct spi_lobo_transaction_t spi_lobo_transaction_t; +typedef void(*transaction_cb_t)(spi_lobo_transaction_t *trans); + +/** + * @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses. + */ +typedef struct { + uint8_t command_bits; ///< Amount of bits in command phase (0-16) + uint8_t address_bits; ///< Amount of bits in address phase (0-64) + uint8_t dummy_bits; ///< Amount of dummy bits to insert between address and data phase + uint8_t mode; ///< SPI mode (0-3) + uint8_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128. + uint8_t cs_ena_pretrans; ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions. + uint8_t cs_ena_posttrans; ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16) + int clock_speed_hz; ///< Clock speed, in Hz + int spics_io_num; ///< CS GPIO pin for this device, handled by hardware; set to -1 if not used + int spics_ext_io_num; ///< CS GPIO pin for this device, handled by software (spi_lobo_device_select/spi_lobo_device_deselect); only used if spics_io_num=-1 + uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags + transaction_cb_t pre_cb; ///< Callback to be called before a transmission is started. This callback from 'spi_lobo_transfer_data' function. + transaction_cb_t post_cb; ///< Callback to be called after a transmission has completed. This callback from 'spi_lobo_transfer_data' function. + uint8_t selected; ///< **INTERNAL** 1 if the device's CS pin is active +} spi_lobo_device_interface_config_t; + + +#define SPI_TRANS_MODE_DIO (1<<0) ///< Transmit/receive data in 2-bit mode +#define SPI_TRANS_MODE_QIO (1<<1) ///< Transmit/receive data in 4-bit mode +#define SPI_TRANS_MODE_DIOQIO_ADDR (1<<2) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO +#define SPI_TRANS_USE_RXDATA (1<<3) ///< Receive into rx_data member of spi_lobo_transaction_t instead into memory at rx_buffer. +#define SPI_TRANS_USE_TXDATA (1<<4) ///< Transmit tx_data member of spi_lobo_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this. + +/** + * This structure describes one SPI transmission + */ +struct spi_lobo_transaction_t { + uint32_t flags; ///< Bitwise OR of SPI_TRANS_* flags + uint16_t command; ///< Command data. Specific length was given when device was added to the bus. + uint64_t address; ///< Address. Specific length was given when device was added to the bus. + size_t length; ///< Total data length to be transmitted to the device, in bits; if 0, no data is transmitted + size_t rxlength; ///< Total data length to be received from the device, in bits; if 0, no data is received + void *user; ///< User-defined variable. Can be used to store eg transaction ID or data to be used by pre_cb and/or post_cb callbacks. + union { + const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase + uint8_t tx_data[4]; ///< If SPI_USE_TXDATA is set, data set here is sent directly from this variable. + }; + union { + void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase + uint8_t rx_data[4]; ///< If SPI_USE_RXDATA is set, data is received directly to this variable + }; +}; + +#define NO_CS 3 // Number of CS pins per SPI host +#define NO_DEV 6 // Number of spi devices per SPI host; more than 3 devices can be attached to the same bus if using software CS's +#define SPI_SEMAPHORE_WAIT 2000 // Time in ms to wait for SPI mutex + +typedef struct spi_lobo_device_t spi_lobo_device_t; + +typedef struct { + spi_lobo_device_t *device[NO_DEV]; + intr_handle_t intr; + spi_dev_t *hw; + //spi_lobo_transaction_t *cur_trans; + int cur_device; + lldesc_t *dmadesc_tx; + lldesc_t *dmadesc_rx; + bool no_gpio_matrix; + int dma_chan; + int max_transfer_sz; + QueueHandle_t spi_lobo_bus_mutex; + spi_lobo_bus_config_t cur_bus_config; +} spi_lobo_host_t; + +struct spi_lobo_device_t { + spi_lobo_device_interface_config_t cfg; + spi_lobo_host_t *host; + spi_lobo_bus_config_t bus_config; + spi_lobo_host_device_t host_dev; +}; + +typedef spi_lobo_device_t* spi_lobo_device_handle_t; ///< Handle for a device on a SPI bus +typedef spi_lobo_host_t* spi_lobo_host_handle_t; +typedef spi_lobo_device_interface_config_t* spi_lobo_device_interface_config_handle_t; + + +/** + * @brief MGOS lib init + */ +bool mgos_mos_lobo_spi_init(void); + + +/** + * @brief Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks + * up the CS pin to whatever is specified. + * + * This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master + * peripheral and routes it to the indicated GPIO. All SPI master devices have three hw CS pins and can thus control + * up to three devices. Software handled CS pin can also be used for additional devices on the same SPI bus. + * + * ### If selected SPI host device bus is not yet initialized, it is initialized first with 'bus_config' function ### + * + * @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are + * supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz. + * + * @param host SPI peripheral to allocate device on (HSPI or VSPI) + * @param dev_config SPI interface protocol config for the device + * @param bus_config Pointer to a spi_lobo_bus_config_t struct specifying how the host device bus should be initialized + * @param handle Pointer to variable to hold the device handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NOT_FOUND if host doesn't have any free CS slots + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle); + +/** + * @brief Remove a device from the SPI bus. If after removal no other device is attached to the spi bus device, it is freed. + * + * @param handle Device handle to free + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_STATE if device already is freed + * - ESP_OK on success + */ +esp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle); + + +/** + * @brief Return the actuall SPI bus speed for the spi device in Hz + * + * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - actuall SPI clock + */ +uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle); + +/** + * @brief Set the new clock speed for the device, return the actuall SPI bus speed set, in Hz + * This function can be used after the device is initialized + * + * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * @param speed New device spi clock to be set in Hz + * + * @return + * - actuall SPI clock + * - 0 if speed cannot be set + */ +uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed); + +/** + * @brief Select spi device for transmission + * + * It configures spi bus with selected spi device parameters if previously selected device was different than the current + * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to active state (low) + * + * spi bus device's semaphore is taken before selecting the device + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * @param force configure spi bus even if the previous device was the same + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + */ +esp_err_t spi_lobo_device_select(spi_lobo_device_handle_t handle, int force); + +/** + * @brief De-select spi device + * + * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to inactive state (high) + * + * spi bus device's semaphore is given after selecting the device + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + */ +esp_err_t spi_lobo_device_deselect(spi_lobo_device_handle_t handle); + + +/** + * @brief Check if spi bus uses native spi pins + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - true if native spi pins are used + * - false if spi pins are routed through gpio matrix + */ +bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle); + +/** + * @brief Get spi bus native spi pins + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * places spi bus native pins in provided pointers + */ +void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck); + +/** + * @brief Transimit and receive data to/from spi device based on transaction data + * + * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes) + * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes) + * Lengths must be 8-bit multiples! + * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data + * If trans->tx_buffer is NULL or trans->length is 0, only receives data + * If the device is in duplex mode (SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously. + * If the device is in half duplex mode (SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission + * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration + * and IF 'trans->length' and 'trans->rx_length' are NOT both 0 + * If device was not previously selected, it will be selected before transmission and deselected after transmission. + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @param trans Pointer to variable containing the description of the transaction that is executed + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP error code if device cannot be selected + * - ESP_OK on success + * + */ +esp_err_t spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans); + + +/* + * SPI transactions uses the semaphore (taken in select function) to protect the transfer + */ +esp_err_t spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle); +void spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle); + + +/** + * @brief Setup a DMA link chain + * + * This routine will set up a chain of linked DMA descriptors in the array pointed to by + * ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the + * descriptors will point to the corresponding positions in ``buffer`` and linked together. The + * end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes + * of ``data`` being read or written. + * + * @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes + * @param len Length of buffer + * @param data Data buffer to use for DMA transfer + * @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``. + */ +void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx); + +/** + * @brief Check if a DMA reset is requested but has not completed yet + * + * @return True when a DMA reset is requested but hasn't completed yet. False otherwise. + */ +bool spi_lobo_dmaworkaround_reset_in_progress(); + + +/** + * @brief Mark a DMA channel as idle. + * + * A call to this function tells the workaround logic that this channel will + * not be affected by a global SPI DMA reset. + */ +void spi_lobo_dmaworkaround_idle(int dmachan); + +/** + * @brief Mark a DMA channel as active. + * + * A call to this function tells the workaround logic that this channel will + * be affected by a global SPI DMA reset, and a reset like that should not be attempted. + */ +void spi_lobo_dmaworkaround_transfer_active(int dmachan); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/lobo-spi/mos.yml b/libs/lobo-spi/mos.yml new file mode 100755 index 0000000..ee826e8 --- /dev/null +++ b/libs/lobo-spi/mos.yml @@ -0,0 +1,24 @@ +author: Pim van Pelt +type: lib +description: Mongoose-OS ESP32 SPI lib +version: 0.1 +platforms: [ esp32 ] + +sources: + - src + +includes: + - include + +config_schema: + - ["spi", "o", {title: "LoBo SPI settings"}] + - ["spi.mosi", "i", 18, {title: "LoBo SPI MOSI pin"}] + - ["spi.miso", "i", 19, {title: "LoBo SPI MISO pin"}] + - ["spi.sck", "i", 5, {title: "LoBo SPI SCK pin"}] + +tags: + - c + - spi + - hw + +manifest_version: 2017-09-29 diff --git a/libs/lobo-spi/src/lobo_spi.c b/libs/lobo-spi/src/lobo_spi.c new file mode 100755 index 0000000..2a8b646 --- /dev/null +++ b/libs/lobo-spi/src/lobo_spi.c @@ -0,0 +1,1175 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/* +---------------------------------------- +Non DMA version of the spi_master driver +---------------------------------------- +------------------------------------------------------------------------------------ +Based on esp-idf 'spi_master', modified by LoBo (https://github.com/loboris) 03/2017 +------------------------------------------------------------------------------------ + +* Transfers data to SPI device in direct mode, not using DMA +* All configuration options (bus, device, transaction) are the same as in spi_master driver +* Transfers uses the semaphore (taken in select function & given in deselect function) to protect the transfer +* Number of the devices attached to the bus which uses hardware CS can be 3 ('NO_CS') +* Additional devices which uses software CS can be attached to the bus, up to 'NO_DEV' +* 'spi_bus_initialize' & 'spi_bus_remove' functions are removed, spi bus is initiated/removed in spi_lobo_bus_add_device/spi_lobo_bus_remove_device when needed +* 'spi_lobo_bus_add_device' function has added parameter 'bus_config' and automatically initializes spi bus device if not already initialized +* 'spi_lobo_bus_remove_device' automatically removes spi bus device if no other devices are attached to it. +* Devices can have individual bus_configs, so different mosi, miso, sck pins can be configured for each device + Reconfiguring the bus is done automaticaly in 'spi_lobo_device_select' function +* 'spi_lobo_device_select' & 'spi_lobo_device_deselect' functions handles devices configuration changes and software CS +* Some helper functions are added ('spi_lobo_get_speed', 'spi_lobo_set_speed', ...) +* All structures are available in header file for easy creation of user low level spi functions. See **tftfunc.c** source for examples. +* Transimt and receive lenghts are limited only by available memory + + +Main driver's function is 'spi_lobo_transfer_data()' + + * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes) + * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes) + * Lengths must be 8-bit multiples! + * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data + * If trans->tx_buffer is NULL or trans->length is 0, only receives data + * If the device is in duplex mode (SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously. + * If the device is in half duplex mode (SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission + * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration + * and IF 'trans->length' and 'trans->rx_length' are NOT both 0 + * If configured, devices 'pre_cb' callback is called before and 'post_cb' after the transmission + * If device was not previously selected, it will be selected before transmission and deselected after transmission. + +*/ + +/* + Replace this include with + #include "driver/spi_master_lobo.h" + if the driver is located in esp-isf/components +*/ +#include "freertos/FreeRTOS.h" +#include +#include +#include "soc/gpio_sig_map.h" +#include "soc/spi_reg.h" +#include "soc/dport_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "rom/ets_sys.h" +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_err.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "freertos/ringbuf.h" +#include "soc/soc.h" +#include "soc/dport_reg.h" +#include "soc/uart_struct.h" +#include "driver/uart.h" +#include "driver/gpio.h" +#include "driver/periph_ctrl.h" +#include "esp_heap_caps.h" +#include "driver/periph_ctrl.h" +#include "lobo_spi.h" + +#include "mgos.h" +#include "mgos_config.h" + +static spi_lobo_host_t *spihost[3] = {NULL}; + + +static const char *SPI_TAG = "spi_lobo_master"; +#define SPI_CHECK(a, str, ret_val) \ + if (!(a)) { \ + ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +/* + Stores a bunch of per-spi-peripheral data. +*/ +typedef struct { + const uint8_t spiclk_out; //GPIO mux output signals + const uint8_t spid_out; + const uint8_t spiq_out; + const uint8_t spiwp_out; + const uint8_t spihd_out; + const uint8_t spid_in; //GPIO mux input signals + const uint8_t spiq_in; + const uint8_t spiwp_in; + const uint8_t spihd_in; + const uint8_t spics_out[3]; // /CS GPIO output mux signals + const uint8_t spiclk_native; //IO pins of IO_MUX muxed signals + const uint8_t spid_native; + const uint8_t spiq_native; + const uint8_t spiwp_native; + const uint8_t spihd_native; + const uint8_t spics0_native; + const uint8_t irq; //irq source for interrupt mux + const uint8_t irq_dma; //dma irq source for interrupt mux + const periph_module_t module; //peripheral module, for enabling clock etc + spi_dev_t *hw; //Pointer to the hardware registers +} spi_signal_conn_t; + +/* + Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +static const spi_signal_conn_t io_signal[3]={ + { + .spiclk_out=SPICLK_OUT_IDX, + .spid_out=SPID_OUT_IDX, + .spiq_out=SPIQ_OUT_IDX, + .spiwp_out=SPIWP_OUT_IDX, + .spihd_out=SPIHD_OUT_IDX, + .spid_in=SPID_IN_IDX, + .spiq_in=SPIQ_IN_IDX, + .spiwp_in=SPIWP_IN_IDX, + .spihd_in=SPIHD_IN_IDX, + .spics_out={SPICS0_OUT_IDX, SPICS1_OUT_IDX, SPICS2_OUT_IDX}, + .spiclk_native=6, + .spid_native=8, + .spiq_native=7, + .spiwp_native=10, + .spihd_native=9, + .spics0_native=11, + .irq=ETS_SPI1_INTR_SOURCE, + .irq_dma=ETS_SPI1_DMA_INTR_SOURCE, + .module=PERIPH_SPI_MODULE, + .hw=&SPI1 + }, { + .spiclk_out=HSPICLK_OUT_IDX, + .spid_out=HSPID_OUT_IDX, + .spiq_out=HSPIQ_OUT_IDX, + .spiwp_out=HSPIWP_OUT_IDX, + .spihd_out=HSPIHD_OUT_IDX, + .spid_in=HSPID_IN_IDX, + .spiq_in=HSPIQ_IN_IDX, + .spiwp_in=HSPIWP_IN_IDX, + .spihd_in=HSPIHD_IN_IDX, + .spics_out={HSPICS0_OUT_IDX, HSPICS1_OUT_IDX, HSPICS2_OUT_IDX}, + .spiclk_native=14, + .spid_native=13, + .spiq_native=12, + .spiwp_native=2, + .spihd_native=4, + .spics0_native=15, + .irq=ETS_SPI2_INTR_SOURCE, + .irq_dma=ETS_SPI2_DMA_INTR_SOURCE, + .module=PERIPH_HSPI_MODULE, + .hw=&SPI2 + }, { + .spiclk_out=VSPICLK_OUT_IDX, + .spid_out=VSPID_OUT_IDX, + .spiq_out=VSPIQ_OUT_IDX, + .spiwp_out=VSPIWP_OUT_IDX, + .spihd_out=VSPIHD_OUT_IDX, + .spid_in=VSPID_IN_IDX, + .spiq_in=VSPIQ_IN_IDX, + .spiwp_in=VSPIWP_IN_IDX, + .spihd_in=VSPIHD_IN_IDX, + .spics_out={VSPICS0_OUT_IDX, VSPICS1_OUT_IDX, VSPICS2_OUT_IDX}, + .spiclk_native=18, + .spid_native=23, + .spiq_native=19, + .spiwp_native=22, + .spihd_native=21, + .spics0_native=5, + .irq=ETS_SPI3_INTR_SOURCE, + .irq_dma=ETS_SPI3_DMA_INTR_SOURCE, + .module=PERIPH_VSPI_MODULE, + .hw=&SPI3 + } +}; + + +//====================================================================================================== + +#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1)) + +typedef void(*dmaworkaround_cb_t)(void *arg); + +//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to. +//-------------------------------------------------------------------------------------------- +void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx) +{ + int n = 0; + while (len) { + int dmachunklen = len; + if (dmachunklen > SPI_MAX_DMA_LEN) dmachunklen = SPI_MAX_DMA_LEN; + if (isrx) { + //Receive needs DMA length rounded to next 32-bit boundary + dmadesc[n].size = (dmachunklen + 3) & (~3); + dmadesc[n].length = (dmachunklen + 3) & (~3); + } else { + dmadesc[n].size = dmachunklen; + dmadesc[n].length = dmachunklen; + } + dmadesc[n].buf = (uint8_t *)data; + dmadesc[n].eof = 0; + dmadesc[n].sosf = 0; + dmadesc[n].owner = 1; + dmadesc[n].qe.stqe_next = &dmadesc[n + 1]; + len -= dmachunklen; + data += dmachunklen; + n++; + } + dmadesc[n - 1].eof = 1; //Mark last DMA desc as end of stream. + dmadesc[n - 1].qe.stqe_next = NULL; +} + + +/* +Code for workaround for DMA issue in ESP32 v0/v1 silicon +*/ + + +static volatile int dmaworkaround_channels_busy[2] = {0, 0}; +static dmaworkaround_cb_t dmaworkaround_cb; +static void *dmaworkaround_cb_arg; +static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED; +static int dmaworkaround_waiting_for_chan = 0; +static bool spi_periph_claimed[3] = {true, false, false}; +static uint8_t spi_dma_chan_enabled = 0; +static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED; + +//-------------------------------------------------------------------------------------------- +bool IRAM_ATTR spi_lobo_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg) +{ + int otherchan = (dmachan == 1) ? 2 : 1; + bool ret; + portENTER_CRITICAL(&dmaworkaround_mux); + if (dmaworkaround_channels_busy[otherchan-1]) { + //Other channel is busy. Call back when it's done. + dmaworkaround_cb = cb; + dmaworkaround_cb_arg = arg; + dmaworkaround_waiting_for_chan = otherchan; + ret = false; + } else { + //Reset DMA + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + ret = true; + } + portEXIT_CRITICAL(&dmaworkaround_mux); + return ret; +} + +//------------------------------------------------------- +bool IRAM_ATTR spi_lobo_dmaworkaround_reset_in_progress() +{ + return (dmaworkaround_waiting_for_chan != 0); +} + +//----------------------------------------------------- +void IRAM_ATTR spi_lobo_dmaworkaround_idle(int dmachan) +{ + portENTER_CRITICAL(&dmaworkaround_mux); + dmaworkaround_channels_busy[dmachan-1] = 0; + if (dmaworkaround_waiting_for_chan == dmachan) { + //Reset DMA + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + dmaworkaround_waiting_for_chan = 0; + //Call callback + dmaworkaround_cb(dmaworkaround_cb_arg); + + } + portEXIT_CRITICAL(&dmaworkaround_mux); +} + +//---------------------------------------------------------------- +void IRAM_ATTR spi_lobo_dmaworkaround_transfer_active(int dmachan) +{ + portENTER_CRITICAL(&dmaworkaround_mux); + dmaworkaround_channels_busy[dmachan-1] = 1; + portEXIT_CRITICAL(&dmaworkaround_mux); +} + +//Returns true if this peripheral is successfully claimed, false if otherwise. +//----------------------------------------------------- +bool spi_lobo_periph_claim(spi_lobo_host_device_t host) +{ + bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true); + if (ret) periph_module_enable(io_signal[host].module); + return ret; +} + +//Returns true if this peripheral is successfully freed, false if otherwise. +//----------------------------------------------- +bool spi_lobo_periph_free(spi_lobo_host_device_t host) +{ + bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false); + if (ret) periph_module_disable(io_signal[host].module); + return ret; +} + +//----------------------------------------- +bool spi_lobo_dma_chan_claim (int dma_chan) +{ + bool ret = false; + assert( dma_chan == 1 || dma_chan == 2 ); + + portENTER_CRITICAL(&spi_dma_spinlock); + if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) { + // get the channel only when it's not claimed yet. + spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan); + ret = true; + } + periph_module_enable( PERIPH_SPI_DMA_MODULE ); + portEXIT_CRITICAL(&spi_dma_spinlock); + + return ret; +} + +//--------------------------------------- +bool spi_lobo_dma_chan_free(int dma_chan) +{ + assert( dma_chan == 1 || dma_chan == 2 ); + assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) ); + + portENTER_CRITICAL(&spi_dma_spinlock); + spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan); + if ( spi_dma_chan_enabled == 0 ) { + //disable the DMA only when all the channels are freed. + periph_module_disable( PERIPH_SPI_DMA_MODULE ); + } + portEXIT_CRITICAL(&spi_dma_spinlock); + + return true; +} + + +//====================================================================================================== + + +//---------------------------------------------------------------------------------------------------------------- +static esp_err_t spi_lobo_bus_initialize(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, int init) +{ + bool native=true, spi_chan_claimed, dma_chan_claimed; + + if (init > 0) { + /* ToDo: remove this when we have flash operations cooperating with this */ + SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED); + + SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG); + SPI_CHECK(spihost[host]==NULL, "host already in use", ESP_ERR_INVALID_STATE); + } + else { + SPI_CHECK(spihost[host]!=NULL, "host not in use", ESP_ERR_INVALID_STATE); + } + + SPI_CHECK(bus_config->mosi_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->sclk_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->miso_io_num<0 || GPIO_IS_VALID_GPIO(bus_config->miso_io_num), "spiq pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->quadwp_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), "spiwp pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->quadhd_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), "spihd pin invalid", ESP_ERR_INVALID_ARG); + + if (init > 0) { + spi_chan_claimed=spi_lobo_periph_claim(host); + SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE); + + //spihost[host]=malloc(sizeof(spi_lobo_host_t)); + spihost[host]=heap_caps_malloc(sizeof(spi_lobo_host_t), MALLOC_CAP_DMA); + if (spihost[host]==NULL) return ESP_ERR_NO_MEM; + memset(spihost[host], 0, sizeof(spi_lobo_host_t)); + // Create semaphore + spihost[host]->spi_lobo_bus_mutex = xSemaphoreCreateMutex(); + if (!spihost[host]->spi_lobo_bus_mutex) return ESP_ERR_NO_MEM; + } + + spihost[host]->cur_device = -1; + memcpy(&spihost[host]->cur_bus_config, bus_config, sizeof(spi_lobo_bus_config_t)); + + //Check if the selected pins correspond to the native pins of the peripheral + if (bus_config->mosi_io_num >= 0 && bus_config->mosi_io_num!=io_signal[host].spid_native) native=false; + if (bus_config->miso_io_num >= 0 && bus_config->miso_io_num!=io_signal[host].spiq_native) native=false; + if (bus_config->sclk_io_num >= 0 && bus_config->sclk_io_num!=io_signal[host].spiclk_native) native=false; + if (bus_config->quadwp_io_num >= 0 && bus_config->quadwp_io_num!=io_signal[host].spiwp_native) native=false; + if (bus_config->quadhd_io_num >= 0 && bus_config->quadhd_io_num!=io_signal[host].spihd_native) native=false; + + spihost[host]->no_gpio_matrix=native; + if (native) { + //All SPI native pin selections resolve to 1, so we put that here instead of trying to figure + //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway. + if (bus_config->mosi_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], 1); + if (bus_config->miso_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], 1); + if (bus_config->quadwp_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1); + if (bus_config->quadhd_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1); + if (bus_config->sclk_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], 1); + } else { + //Use GPIO + if (bus_config->mosi_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false); + gpio_matrix_in(bus_config->mosi_io_num, io_signal[host].spid_in, false); + } + if (bus_config->miso_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT); + gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false); + gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false); + } + if (bus_config->quadwp_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->quadwp_io_num, io_signal[host].spiwp_out, false, false); + gpio_matrix_in(bus_config->quadwp_io_num, io_signal[host].spiwp_in, false); + } + if (bus_config->quadhd_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->quadhd_io_num, io_signal[host].spihd_out, false, false); + gpio_matrix_in(bus_config->quadhd_io_num, io_signal[host].spihd_in, false); + } + if (bus_config->sclk_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->sclk_io_num, io_signal[host].spiclk_out, false, false); + } + } + periph_module_enable(io_signal[host].module); + spihost[host]->hw=io_signal[host].hw; + + if (init > 0) { + dma_chan_claimed=spi_lobo_dma_chan_claim(init); + if ( !dma_chan_claimed ) { + spi_lobo_periph_free( host ); + SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE); + } + spihost[host]->dma_chan = init; + //See how many dma descriptors we need and allocate them + int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN; + if (dma_desc_ct==0) dma_desc_ct=1; //default to 4k when max is not given + spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN; + + spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); + spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); + if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem; + + //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. + spi_lobo_dmaworkaround_idle(spihost[host]->dma_chan); + + // Reset DMA + spihost[host]->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST; + spihost[host]->hw->dma_out_link.start=0; + spihost[host]->hw->dma_in_link.start=0; + spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST); + spihost[host]->hw->dma_conf.out_data_burst_en=1; + + //Reset timing + spihost[host]->hw->ctrl2.val=0; + + //Disable unneeded ints + spihost[host]->hw->slave.rd_buf_done=0; + spihost[host]->hw->slave.wr_buf_done=0; + spihost[host]->hw->slave.rd_sta_done=0; + spihost[host]->hw->slave.wr_sta_done=0; + spihost[host]->hw->slave.rd_buf_inten=0; + spihost[host]->hw->slave.wr_buf_inten=0; + spihost[host]->hw->slave.rd_sta_inten=0; + spihost[host]->hw->slave.wr_sta_inten=0; + + //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as + //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling + //any transactions that are queued. + spihost[host]->hw->slave.trans_inten=1; + spihost[host]->hw->slave.trans_done=1; + + //Select DMA channel. + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, init, (host * 2)); + } + return ESP_OK; + +nomem: + if (spihost[host]) { + free(spihost[host]->dmadesc_tx); + free(spihost[host]->dmadesc_rx); + } + free(spihost[host]); + spi_lobo_periph_free(host); + return ESP_ERR_NO_MEM; +} + +//--------------------------------------------------------------------------- +static esp_err_t spi_lobo_bus_free(spi_lobo_host_device_t host, int dofree) +{ + if ((host == SPI_HOST) || (host >VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host + + if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE; // host not in use + + if (dofree) { + for (int x=0; xdevice[x] != NULL) return ESP_ERR_INVALID_STATE; // not all devices freed + } + } + if ( spihost[host]->dma_chan > 0 ) { + spi_lobo_dma_chan_free ( spihost[host]->dma_chan ); + } + spihost[host]->hw->slave.trans_inten=0; + spihost[host]->hw->slave.trans_done=0; + spi_lobo_periph_free(host); + + if (dofree) { + vSemaphoreDelete(spihost[host]->spi_lobo_bus_mutex); + free(spihost[host]->dmadesc_tx); + free(spihost[host]->dmadesc_rx); + free(spihost[host]); + spihost[host] = NULL; + } + return ESP_OK; +} + +//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle) +{ + if ((host == SPI_HOST) || (host >VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host + + if (spihost[host] == NULL) { + esp_err_t ret = spi_lobo_bus_initialize(host, bus_config, 1); + if (ret) return ret; + } + + int freecs, maxdev; + int apbclk=APB_CLK_FREQ; + + if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE; + + if (dev_config->spics_io_num >= 0) { + if (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num)) return ESP_ERR_INVALID_ARG; + if (dev_config->spics_ext_io_num > 0) dev_config->spics_ext_io_num = -1; + } + else { + //if ((dev_config->spics_ext_io_num <= 0) || (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_ext_io_num))) return ESP_ERR_INVALID_ARG; + } + + //ToDo: Check if some other device uses the same 'spics_ext_io_num' + + if (dev_config->clock_speed_hz == 0) return ESP_ERR_INVALID_ARG; + if (dev_config->spics_io_num > 0) maxdev = NO_CS; + else maxdev = NO_DEV; + + for (freecs=0; freecsdevice[freecs], NULL, (spi_lobo_device_t *)1)) break; + } + if (freecs == maxdev) return ESP_ERR_NOT_FOUND; + + // The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full + // duplex mode does absolutely nothing on the ESP32. + if ((dev_config->cs_ena_pretrans != 0) && (dev_config->flags & SPI_DEVICE_HALFDUPLEX)) return ESP_ERR_INVALID_ARG; + + // Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. + if (((dev_config->flags & SPI_DEVICE_HALFDUPLEX)==0) && (dev_config->clock_speed_hz > ((apbclk*2)/5)) && (!spihost[host]->no_gpio_matrix)) return ESP_ERR_INVALID_ARG; + + //Allocate memory for device + spi_lobo_device_t *dev=malloc(sizeof(spi_lobo_device_t)); + if (dev==NULL) return ESP_ERR_NO_MEM; + + memset(dev, 0, sizeof(spi_lobo_device_t)); + spihost[host]->device[freecs]=dev; + + if (dev_config->duty_cycle_pos==0) dev_config->duty_cycle_pos=128; + dev->host=spihost[host]; + dev->host_dev = host; + + //We want to save a copy of the dev config in the dev struct. + memcpy(&dev->cfg, dev_config, sizeof(spi_lobo_device_interface_config_t)); + //We want to save a copy of the bus config in the dev struct. + memcpy(&dev->bus_config, bus_config, sizeof(spi_lobo_bus_config_t)); + + //Set CS pin, CS options + if (dev_config->spics_io_num > 0) { + if (spihost[host]->no_gpio_matrix &&dev_config->spics_io_num == io_signal[host].spics0_native && freecs==0) { + //Again, the cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define. + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], 1); + } else { + //Use GPIO matrix + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], PIN_FUNC_GPIO); + gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(dev_config->spics_io_num, io_signal[host].spics_out[freecs], false, false); + } + } + else if (dev_config->spics_ext_io_num >= 0) { + gpio_set_direction(dev_config->spics_ext_io_num, GPIO_MODE_OUTPUT); + gpio_set_level(dev_config->spics_ext_io_num, 1); + } + if (dev_config->flags & SPI_DEVICE_CLK_AS_CS) { + spihost[host]->hw->pin.master_ck_sel |= (1<hw->pin.master_ck_sel &= (1<flags & SPI_DEVICE_POSITIVE_CS) { + spihost[host]->hw->pin.master_cs_pol |= (1<hw->pin.master_cs_pol &= (1<host->device[x] == handle) handle->host->device[x]=NULL; + } + + // Check if all devices are removed from this host and free the bus if yes + for (x=0; xhost_dev]->device[x] !=NULL) break; + } + if (x == NO_DEV) { + free(handle); + spi_lobo_bus_free(handle->host_dev, 1); + } + else free(handle); + + return ESP_OK; +} + +//----------------------------------------------------------------- +static int IRAM_ATTR spi_freq_for_pre_n(int fapb, int pre, int n) { + return (fapb / (pre * n)); +} + +/* + * Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly + * different from the requested frequency. + */ +//----------------------------------------------------------------------------------- +static int IRAM_ATTR spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { + int pre, n, h, l, eff_clk; + + //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. + if (hz>((fapb/4)*3)) { + //Using Fapb directly will give us the best result here. + hw->clock.clkcnt_l=0; + hw->clock.clkcnt_h=0; + hw->clock.clkcnt_n=0; + hw->clock.clkdiv_pre=0; + hw->clock.clk_equ_sysclk=1; + eff_clk=fapb; + } else { + //For best duty cycle resolution, we want n to be as close to 32 as possible, but + //we also need a pre/n combo that gets us as close as possible to the intended freq. + //To do this, we bruteforce n and calculate the best pre to go along with that. + //If there's a choice between pre/n combos that give the same result, use the one + //with the higher n. + int bestn=-1; + int bestpre=-1; + int besterr=0; + int errval; + for (n=1; n<=64; n++) { + //Effectively, this does pre=round((fapb/n)/hz). + pre=((fapb/n)+(hz/2))/hz; + if (pre<=0) pre=1; + if (pre>8192) pre=8192; + errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz); + if (bestn==-1 || errval<=besterr) { + besterr=errval; + bestn=n; + bestpre=pre; + } + } + + n=bestn; + pre=bestpre; + l=n; + //This effectively does round((duty_cycle*n)/256) + h=(duty_cycle*n+127)/256; + if (h<=0) h=1; + + hw->clock.clk_equ_sysclk=0; + hw->clock.clkcnt_n=n-1; + hw->clock.clkdiv_pre=pre-1; + hw->clock.clkcnt_h=h-1; + hw->clock.clkcnt_l=l-1; + eff_clk=spi_freq_for_pre_n(fapb, pre, n); + } + return eff_clk; +} + + + +//------------------------------------------------------------------------------------ +esp_err_t IRAM_ATTR spi_lobo_device_select(spi_lobo_device_handle_t handle, int force) +{ + if (handle == NULL) return ESP_ERR_INVALID_ARG; + + if ((handle->cfg.selected == 1) && (!force)) return ESP_OK; // already selected + + int i; + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + + // find device's host bus + for (i=0; idevice[i] == handle) break; + } + if (i == NO_DEV) return ESP_ERR_INVALID_ARG; + + if (!(xSemaphoreTake(host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE; + + // Check if previously used device's bus device is the same + if (memcmp(&host->cur_bus_config, &handle->bus_config, sizeof(spi_lobo_bus_config_t)) != 0) { + // device has different bus configuration, we need to reconfigure the bus + esp_err_t err = spi_lobo_bus_free(1, 0); + if (err) { + xSemaphoreGive(host->spi_lobo_bus_mutex); + return err; + } + err = spi_lobo_bus_initialize(i, &handle->bus_config, -1); + if (err) { + xSemaphoreGive(host->spi_lobo_bus_mutex); + return err; + } + } + + //Reconfigure according to device settings, but only if the device changed or forced. + if ((force) || (host->device[host->cur_device] != handle)) { + //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have clock scaling working. + int apbclk=APB_CLK_FREQ; + + //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. + if (((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) == 0) && (handle->cfg.clock_speed_hz > ((apbclk*2)/5)) && (!host->no_gpio_matrix)) { + // set speed to 32 MHz + handle->cfg.clock_speed_hz = (apbclk*2)/5; + } + + int effclk=spi_set_clock(host->hw, apbclk, handle->cfg.clock_speed_hz, handle->cfg.duty_cycle_pos); + //Configure bit order + host->hw->ctrl.rd_bit_order=(handle->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0; + host->hw->ctrl.wr_bit_order=(handle->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0; + + //Configure polarity + //SPI iface needs to be configured for a delay in some cases. + int nodelay=0; + int extra_dummy=0; + if (host->no_gpio_matrix) { + if (effclk >= apbclk/2) { + nodelay=1; + } + } else { + if (effclk >= apbclk/2) { + nodelay=1; + extra_dummy=1; //Note: This only works on half-duplex connections. spi_lobo_bus_add_device checks for this. + } else if (effclk >= apbclk/4) { + nodelay=1; + } + } + if (handle->cfg.mode==0) { + host->hw->pin.ck_idle_edge=0; + host->hw->user.ck_out_edge=0; + host->hw->ctrl2.miso_delay_mode=nodelay?0:2; + } else if (handle->cfg.mode==1) { + host->hw->pin.ck_idle_edge=0; + host->hw->user.ck_out_edge=1; + host->hw->ctrl2.miso_delay_mode=nodelay?0:1; + } else if (handle->cfg.mode==2) { + host->hw->pin.ck_idle_edge=1; + host->hw->user.ck_out_edge=1; + host->hw->ctrl2.miso_delay_mode=nodelay?0:1; + } else if (handle->cfg.mode==3) { + host->hw->pin.ck_idle_edge=1; + host->hw->user.ck_out_edge=0; + host->hw->ctrl2.miso_delay_mode=nodelay?0:2; + } + + //Configure bit sizes, load addr and command + host->hw->user.usr_dummy=(handle->cfg.dummy_bits+extra_dummy)?1:0; + host->hw->user.usr_addr=(handle->cfg.address_bits)?1:0; + host->hw->user.usr_command=(handle->cfg.command_bits)?1:0; + host->hw->user1.usr_addr_bitlen=handle->cfg.address_bits-1; + host->hw->user1.usr_dummy_cyclelen=handle->cfg.dummy_bits+extra_dummy-1; + host->hw->user2.usr_command_bitlen=handle->cfg.command_bits-1; + //Configure misc stuff + host->hw->user.doutdin=(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1; + host->hw->user.sio=(handle->cfg.flags & SPI_DEVICE_3WIRE)?1:0; + + host->hw->ctrl2.setup_time=handle->cfg.cs_ena_pretrans-1; + host->hw->user.cs_setup=handle->cfg.cs_ena_pretrans?1:0; + host->hw->ctrl2.hold_time=handle->cfg.cs_ena_posttrans-1; + host->hw->user.cs_hold=(handle->cfg.cs_ena_posttrans)?1:0; + + //Configure CS pin + host->hw->pin.cs0_dis=(i==0)?0:1; + host->hw->pin.cs1_dis=(i==1)?0:1; + host->hw->pin.cs2_dis=(i==2)?0:1; + + host->cur_device = i; + } + + if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) { + gpio_set_level(handle->cfg.spics_ext_io_num, 0); + } + + handle->cfg.selected = 1; + + return ESP_OK; +} + +//--------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_device_deselect(spi_lobo_device_handle_t handle) +{ + if (handle == NULL) return ESP_ERR_INVALID_ARG; + + if (handle->cfg.selected == 0) return ESP_OK; // already deselected + + int i; + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + + for (i=0; idevice[i] == handle) break; + } + if (i == NO_DEV) return ESP_ERR_INVALID_ARG; + + if (host->device[host->cur_device] == handle) { + if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) { + gpio_set_level(handle->cfg.spics_ext_io_num, 1); + } + } + + handle->cfg.selected = 0; + xSemaphoreGive(host->spi_lobo_bus_mutex); + + return ESP_OK; +} + +//-------------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle) +{ + if (!(xSemaphoreTake(handle->host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE; + else return ESP_OK; +} + +//--------------------------------------------------------------------------- +void IRAM_ATTR spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle) +{ + xSemaphoreTake(handle->host->spi_lobo_bus_mutex, portMAX_DELAY); +} + +//---------------------------------------------------------- +uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle) +{ + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + uint32_t speed = 0; + if (spi_lobo_device_select(handle, 0) == ESP_OK) { + if (host->hw->clock.clk_equ_sysclk == 1) speed = 80000000; + else speed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1); + } + spi_lobo_device_deselect(handle); + return speed; +} + +//-------------------------------------------------------------------------- +uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed) +{ + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + uint32_t newspeed = 0; + if (spi_lobo_device_select(handle, 0) == ESP_OK) { + spi_lobo_device_deselect(handle); + handle->cfg.clock_speed_hz = speed; + if (spi_lobo_device_select(handle, 1) == ESP_OK) { + if (host->hw->clock.clk_equ_sysclk == 1) newspeed = 80000000; + else newspeed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1); + } + } + spi_lobo_device_deselect(handle); + + return newspeed; +} + +//------------------------------------------------------------- +bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle) +{ + return handle->host->no_gpio_matrix; +} + +//------------------------------------------------------------------- +void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck) +{ + *sdo = io_signal[host].spid_native; + *sdi = io_signal[host].spiq_native; + *sck = io_signal[host].spiclk_native; +} + +/* +When using 'spi_lobo_transfer_data' function we can have several scenarios: + +A: Send only (trans->rxlength = 0) +B: Receive only (trans->txlength = 0) +C: Send & receive (trans->txlength > 0 & trans->rxlength > 0) +D: No operation (trans->txlength = 0 & trans->rxlength = 0) + +*/ +//---------------------------------------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans) { + if (!handle) return ESP_ERR_INVALID_ARG; + + // *** For now we can only handle 8-bit bytes transmission + if (((trans->length % 8) != 0) || ((trans->rxlength % 8) != 0)) return ESP_ERR_INVALID_ARG; + + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + esp_err_t ret; + uint8_t do_deselect = 0; + const uint8_t *txbuffer = NULL; + uint8_t *rxbuffer = NULL; + + if (trans->flags & SPI_TRANS_USE_TXDATA) { + // Send data from 'trans->tx_data' + txbuffer=(uint8_t*)&trans->tx_data[0]; + } else { + // Send data from 'trans->tx_buffer' + txbuffer=(uint8_t*)trans->tx_buffer; + } + if (trans->flags & SPI_TRANS_USE_RXDATA) { + // Receive data to 'trans->rx_data' + rxbuffer=(uint8_t*)&trans->rx_data[0]; + } else { + // Receive data to 'trans->rx_buffer' + rxbuffer=(uint8_t*)trans->rx_buffer; + } + + // ** Set transmit & receive length in bytes + uint32_t txlen = trans->length / 8; + uint32_t rxlen = trans->rxlength / 8; + + if (txbuffer == NULL) txlen = 0; + if (rxbuffer == NULL) rxlen = 0; + if ((rxlen == 0) && (txlen == 0)) { + // ** NOTHING TO SEND or RECEIVE, return + return ESP_ERR_INVALID_ARG; + } + + // If using 'trans->tx_data' and/or 'trans->rx_data', maximum 4 bytes can be sent/received + if ((txbuffer == &trans->tx_data[0]) && (txlen > 4)) return ESP_ERR_INVALID_ARG; + if ((rxbuffer == &trans->rx_data[0]) && (rxlen > 4)) return ESP_ERR_INVALID_ARG; + + // --- Wait for SPI bus ready --- + while (host->hw->cmd.usr); + + // ** If the device was not selected, select it + if (handle->cfg.selected == 0) { + ret = spi_lobo_device_select(handle, 0); + if (ret) return ret; + do_deselect = 1; // We will deselect the device after the operation ! + } + + // ** Call pre-transmission callback, if any + if (handle->cfg.pre_cb) handle->cfg.pre_cb(trans); + + // Test if operating in full duplex mode + uint8_t duplex = 1; + if (handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) duplex = 0; // Half duplex mode ! + + uint32_t bits, rdbits; + uint32_t wd; + uint8_t bc, rdidx; + uint32_t rdcount = rxlen; // Total number of bytes to read + uint32_t count = 0; // number of bytes transmitted + uint32_t rd_read = 0; // Number of bytes read so far + + host->hw->user.usr_mosi_highpart = 0; // use the whole spi buffer + + // ** Check if address phase will be used + host->hw->user2.usr_command_value=trans->command; + if (handle->cfg.address_bits>32) { + host->hw->addr=trans->address >> 32; + host->hw->slv_wr_status=trans->address & 0xffffffff; + } else { + host->hw->addr=trans->address & 0xffffffff; + } + + // Check if we have to transmit some data + if (txlen > 0) { + host->hw->user.usr_mosi = 1; + uint8_t idx; + bits = 0; // remaining bits to send + idx = 0; // index to spi hw data_buf (16 32-bit words, 64 bytes, 512 bits) + + // ** Transmit 'txlen' bytes + while (count < txlen) { + wd = 0; + for (bc=0;bc<32;bc+=8) { + wd |= (uint32_t)txbuffer[count] << bc; + count++; // Increment sent data count + bits += 8; // Increment bits count + if (count == txlen) break; // If all transmit data pushed to hw spi buffer break from the loop + } + host->hw->data_buf[idx] = wd; + idx++; + if (idx == 16) { + // hw SPI buffer full (all 64 bytes filled, START THE TRANSSACTION + host->hw->mosi_dlen.usr_mosi_dbitlen=bits-1; // Set mosi dbitlen + + if ((duplex) && (rdcount > 0)) { + // In full duplex mode we are receiving while sending ! + host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen + host->hw->user.usr_miso = 1; + } + else { + host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received + host->hw->user.usr_miso = 0; + } + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + if ((duplex) && (rdcount > 0)) { + // *** in full duplex mode transfer received data to input buffer *** + rdidx = 0; + while (bits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { // get max 4 bytes + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + bits -= 8; + if (rdcount == 0) { + bits = 0; + break; // Finished reading data + } + } + } + } + bits = 0; // nothing in hw spi buffer yet + idx = 0; // start from the beginning of the hw spi buffer + } + } + // *** All transmit data are sent or pushed to hw spi buffer + // bits > 0 IF THERE ARE SOME DATA STILL WAITING IN THE HW SPI TRANSMIT BUFFER + if (bits > 0) { + // ** WE HAVE SOME DATA IN THE HW SPI TRANSMIT BUFFER + host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // Set mosi dbitlen + + if ((duplex) && (rdcount > 0)) { + // In full duplex mode we are receiving while sending ! + host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen + host->hw->user.usr_miso = 1; + } + else { + host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received + host->hw->user.usr_miso = 0; + } + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + if ((duplex) && (rdcount > 0)) { + // *** in full duplex mode transfer received data to input buffer *** + rdidx = 0; + while (bits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { // get max 4 bytes + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + bits -= 8; + if (bits == 0) break; + if (rdcount == 0) { + bits = 0; + break; // Finished reading data + } + } + } + } + } + //if (duplex) rdcount = 0; // In duplex mode receive only as many bytes as was transmitted + } + + // ------------------------------------------------------------------------ + // *** If rdcount = 0 we have nothing to receive and we exit the function + // This is true if no data receive was requested, + // or all the data was received in Full duplex mode during the transmission + // ------------------------------------------------------------------------ + if (rdcount > 0) { + // ---------------------------------------------------------------------------------------------------------------- + // *** rdcount > 0, we have to receive some data + // This is true if we operate in Half duplex mode when receiving after transmission is done, + // or not all data was received in Full duplex mode during the transmission (trans->rxlength > trans->txlength) + // ---------------------------------------------------------------------------------------------------------------- + host->hw->user.usr_mosi = 0; // do not send + host->hw->user.usr_miso = 1; // do receive + while (rdcount > 0) { + if (rdcount <= 64) rdbits = rdcount * 8; + else rdbits = 64 * 8; + + // Load receive buffer + host->hw->mosi_dlen.usr_mosi_dbitlen=0; + host->hw->miso_dlen.usr_miso_dbitlen=rdbits-1; + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + // *** transfer received data to input buffer *** + rdidx = 0; + while (rdbits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + rdbits -= 8; + if (rdcount == 0) { + rdbits = 0; + break; + } + } + } + } + } + + // ** Call post-transmission callback, if any + if (handle->cfg.post_cb) handle->cfg.post_cb(trans); + + if (do_deselect) { + // Spi device was selected in this function, we have to deselect it now + ret = spi_lobo_device_deselect(handle); + if (ret) return ret; + } + + return ESP_OK; +} + + +bool mgos_lobo_spi_init(void) { + + + LOG(LL_INFO, ("SPI bus init (miso=%d, mosi=%d, sck=%d)", mgos_sys_config_get_spi_miso(), mgos_sys_config_get_spi_mosi(), mgos_sys_config_get_spi_sck())); + + // Route all used pins to GPIO control + gpio_pad_select_gpio(mgos_sys_config_get_spi_miso()); + gpio_set_direction(mgos_sys_config_get_spi_miso(), GPIO_MODE_INPUT); + gpio_set_pull_mode(mgos_sys_config_get_spi_miso(), GPIO_PULLUP_ONLY); + + gpio_pad_select_gpio(mgos_sys_config_get_spi_mosi()); + gpio_set_direction(mgos_sys_config_get_spi_mosi(), GPIO_MODE_OUTPUT); + + gpio_pad_select_gpio(mgos_sys_config_get_spi_sck()); + gpio_set_direction(mgos_sys_config_get_spi_sck(), GPIO_MODE_OUTPUT); + + return true; +} diff --git a/libs/stmpe610/include/stmpe610.h b/libs/stmpe610/include/stmpe610.h new file mode 100644 index 0000000..cfc6b90 --- /dev/null +++ b/libs/stmpe610/include/stmpe610.h @@ -0,0 +1,135 @@ +/*************************************************** + This is a library for the Adafruit STMPE610 Resistive + touch screen controller breakout + ----> http://www.adafruit.com/products/1571 + + Check out the links above for our tutorials and wiring diagrams + These breakouts use SPI or I2C to communicate + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +/* Adapted for native Mongoose OS by Pim van Pelt +type: lib +description: Mongoose-OS STMPE610 for ESP32 +platforms: [ esp32 ] +version: 1.0 + +sources: + - src + +includes: + - include + +config_schema: + - ["stmpe610", "o", {title: "TouchScreen settings"}] + - ["stmpe610.irq_pin", "i", 23, {title: "Touch IRQ pin"}] + - ["stmpe610.cs_pin", "i", 32, {title: "Touch CS pin"}] + +libs: + - origin: libs/lobo-spi + +tags: + - c + - spi + - hw + +manifest_version: 2017-09-29 diff --git a/libs/stmpe610/src/stmpe610.c b/libs/stmpe610/src/stmpe610.c new file mode 100644 index 0000000..80b47ff --- /dev/null +++ b/libs/stmpe610/src/stmpe610.c @@ -0,0 +1,263 @@ +/* + * Author: LoBo (loboris@gmail.com, loboris.github) + * + * Module supporting STMPE touch screen controller. + * + * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS + * USING DIRECT or DMA SPI TRANSFER MODEs + * +*/ + +#include "mgos.h" +#include "lobo_spi.h" +#include "stmpe610.h" + +#define SPI_BUS VSPI_HOST +#define STMPE_SPI_MODE 1 + +static spi_lobo_device_handle_t s_stmpe610_spi = NULL; +static mgos_stmpe610_event_t s_event_handler = NULL; +static enum mgos_stmpe610_rotation_t s_rotation = STMPE610_PORTRAIT; + +static void IRAM_ATTR _spi_transfer_start(spi_lobo_device_handle_t spi_dev, int wrbits, int rdbits) { + // Load send buffer + spi_dev->host->hw->user.usr_mosi_highpart = 0; + spi_dev->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1; + spi_dev->host->hw->user.usr_mosi = 1; + if (rdbits) { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = rdbits; + spi_dev->host->hw->user.usr_miso = 1; + } + else { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = 0; + spi_dev->host->hw->user.usr_miso = 0; + } + // Start transfer + spi_dev->host->hw->cmd.usr = 1; + // Wait for SPI bus ready + while (spi_dev->host->hw->cmd.usr); +} + +static void IRAM_ATTR stmpe610_write_reg(uint8_t reg, uint8_t val) { + + spi_lobo_device_select(s_stmpe610_spi, 0); + + s_stmpe610_spi->host->hw->data_buf[0] = (val << 8) | reg; + _spi_transfer_start(s_stmpe610_spi, 16, 0); + + spi_lobo_device_deselect(s_stmpe610_spi); +} + +static uint8_t IRAM_ATTR stmpe610_read_byte(uint8_t reg) { + spi_lobo_device_select(s_stmpe610_spi, 0); + + s_stmpe610_spi->host->hw->data_buf[0] = (reg << 8) | (reg | 0x80); + _spi_transfer_start(s_stmpe610_spi, 16, 16); + uint8_t res = s_stmpe610_spi->host->hw->data_buf[0] >> 8; + + spi_lobo_device_deselect(s_stmpe610_spi); + return res; +} + +static uint16_t IRAM_ATTR stmpe610_read_word(uint8_t reg) { + spi_lobo_device_select(s_stmpe610_spi, 0); + + s_stmpe610_spi->host->hw->data_buf[0] = ((((reg+1) << 8) | ((reg+1) | 0x80)) << 16) | (reg << 8) | (reg | 0x80); + _spi_transfer_start(s_stmpe610_spi, 32, 32); + uint16_t res = (uint16_t)(s_stmpe610_spi->host->hw->data_buf[0] & 0xFF00); + res |= (uint16_t)(s_stmpe610_spi->host->hw->data_buf[0] >> 24); + + spi_lobo_device_deselect(s_stmpe610_spi); + return res; +} + +static uint32_t stmpe610_getID() +{ + uint16_t tid = stmpe610_read_word(0); + uint8_t tver = stmpe610_read_byte(2); + return (tid << 8) | tver; +} + + +static uint8_t stmpe610_bufferLength(void) { + return stmpe610_read_byte(STMPE_FIFO_SIZE); +} + + +static uint8_t stmpe610_readData(uint16_t *x, uint16_t *y, uint8_t *z) { + uint8_t samples, cnt; + uint32_t sum_sample_x = 0, sum_sample_y = 0; + uint16_t sum_sample_z = 0; + + samples = cnt = stmpe610_bufferLength(); + LOG(LL_DEBUG, ("Touch sensed with %d samples", samples)); + if (samples == 0) + return 0; + + while (cnt>0) { + uint16_t sample_x, sample_y; + uint8_t sample_z; + + sample_x = stmpe610_read_word(0x4D); + sample_y = stmpe610_read_word(0x4F); + sample_z = stmpe610_read_byte(0x51); + + sum_sample_x += sample_x; + sum_sample_y += sample_y; + sum_sample_z += sample_z; + LOG(LL_DEBUG, ("Sample at (%d,%d) pressure=%d, bufferLength=%d", sample_x, sample_y, sample_z, stmpe610_bufferLength())); + cnt--; + } + *x = sum_sample_x / samples; + *y = sum_sample_y / samples; + *z = sum_sample_z / samples; + + stmpe610_write_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET); // clear FIFO + stmpe610_write_reg(STMPE_FIFO_STA, 0); // unreset + + return samples; +} + +static long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + if (xin_max) x=in_max; + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +static void stmpe610_map_rotation(uint16_t x, uint16_t y, uint16_t *x_out, uint16_t *y_out) { + switch(s_rotation) { + case STMPE610_LANDSCAPE: + *x_out = map(y, 150, 3800, 0, 4095); + *y_out = map(x, 250, 3700, 0, 4095); + break; + case STMPE610_PORTRAIT_FLIP: + *x_out = map(x, 250, 3800, 0, 4095); + *y_out = 4095-map(y, 150, 3700, 0, 4095); + break; + case STMPE610_LANDSCAPE_FLIP: + *x_out = 4095-map(y, 150, 3800, 0, 4095); + *y_out = 4095-map(x, 250, 3700, 0, 4095); + break; + default: // STMPE610_PORTRAIT + *x_out = 4095-map(x, 250, 3800, 0, 4095); + *y_out = map(y, 150, 3700, 0, 4095); + } +} + +static void stmpe610_irq(int pin, void *arg) { + struct mgos_stmpe610_event_data ed; + uint16_t x, y; + uint8_t z; + + if (stmpe610_bufferLength()==0) { + uint8_t i; + LOG(LL_DEBUG, ("Touch DOWN")); + for (i=0; i<10; i++) { + mgos_msleep(5); + if (stmpe610_bufferLength()>0) { + + stmpe610_readData(&x, &y, &z); + LOG(LL_DEBUG, ("Touch DOWN at (%d,%d) pressure=%d, length=%d, iteration=%d", x, y, z, ed.length, i)); + + ed.length=1; + ed.direction = TOUCH_DOWN; + stmpe610_map_rotation(x, y, &ed.x, &ed.y); + ed.z = z; + if (s_event_handler) + s_event_handler(&ed); + break; + } + } + stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints + return; + } + + ed.length = stmpe610_readData(&x, &y, &z); + LOG(LL_DEBUG, ("Touch UP at (%d,%d) pressure=%d, length=%d", x, y, z, ed.length)); + ed.direction = TOUCH_UP; + stmpe610_map_rotation(x, y, &ed.x, &ed.y); + ed.z = z; + if (s_event_handler) + s_event_handler(&ed); + + stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints + (void) pin; + (void) arg; +} + +void mgos_stmpe610_set_handler(mgos_stmpe610_event_t handler) { + s_event_handler = handler; +} + +void mgos_stmpe610_set_rotation(enum mgos_stmpe610_rotation_t rotation) { + s_rotation = rotation; +} + + +bool mgos_stmpe610_init(void) { + esp_err_t ret; + + gpio_pad_select_gpio(mgos_sys_config_get_stmpe610_cs_pin()); + gpio_set_direction(mgos_sys_config_get_stmpe610_cs_pin(), GPIO_MODE_OUTPUT); + + spi_lobo_bus_config_t buscfg={ + .miso_io_num=mgos_sys_config_get_spi_miso(), + .mosi_io_num=mgos_sys_config_get_spi_mosi(), + .sclk_io_num=mgos_sys_config_get_spi_sck(), + .quadwp_io_num=-1, + .quadhd_io_num=-1, + .max_transfer_sz = 6*1024, + }; + + spi_lobo_device_interface_config_t tsdevcfg={ + .clock_speed_hz=1000000, + .mode=STMPE_SPI_MODE, + .spics_io_num=mgos_sys_config_get_stmpe610_cs_pin(), //Touch CS pin + .spics_ext_io_num=-1, //Not using the external CS + .flags = 0, + }; + + ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &tsdevcfg, &s_stmpe610_spi); + assert(ret==ESP_OK); + + ret = spi_lobo_device_select(s_stmpe610_spi, 1); + assert(ret==ESP_OK); + ret = spi_lobo_device_deselect(s_stmpe610_spi); + assert(ret==ESP_OK); + + uint32_t tver = stmpe610_getID(); + if (tver >> 8 != 0x0811) { + LOG(LL_ERROR, ("STMPE SPI init failed, disabling")); + return true; + } + LOG(LL_INFO, ("SPI init ok (cs=%d, speed=%u, ver=%04x, rev=%02x); irq=%d", mgos_sys_config_get_stmpe610_cs_pin(), spi_lobo_get_speed(s_stmpe610_spi), + tver>>8, tver&0xFF, mgos_sys_config_get_stmpe610_irq_pin())); + + stmpe610_write_reg(STMPE_SYS_CTRL1, STMPE_SYS_CTRL1_RESET); + mgos_msleep(10); + + for (uint8_t i=0; i<65; i++) + stmpe610_read_byte(i); + + stmpe610_write_reg(STMPE_SYS_CTRL2, 0x0); // turn on clocks! + stmpe610_write_reg(STMPE_INT_EN, STMPE_INT_EN_TOUCHDET); + stmpe610_write_reg(STMPE_ADC_CTRL1, STMPE_ADC_CTRL1_10BIT | (0x6 << 4)); // 96 clocks per conversion + stmpe610_write_reg(STMPE_ADC_CTRL2, STMPE_ADC_CTRL2_6_5MHZ); + stmpe610_write_reg(STMPE_TSC_CFG, STMPE_TSC_CFG_4SAMPLE | STMPE_TSC_CFG_DELAY_1MS | STMPE_TSC_CFG_SETTLE_5MS); + stmpe610_write_reg(STMPE_TSC_FRACTION_Z, 0x6); + stmpe610_write_reg(STMPE_FIFO_TH, 1); + stmpe610_write_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET); + stmpe610_write_reg(STMPE_FIFO_STA, 0); // unreset + stmpe610_write_reg(STMPE_TSC_I_DRIVE, STMPE_TSC_I_DRIVE_50MA); + stmpe610_write_reg(STMPE_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window + stmpe610_write_reg(STMPE_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable + stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints + stmpe610_write_reg(STMPE_INT_CTRL, STMPE_INT_CTRL_POL_LOW | STMPE_INT_CTRL_EDGE | STMPE_INT_CTRL_ENABLE); + + mgos_gpio_set_mode(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_MODE_INPUT); + mgos_gpio_set_pull(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_PULL_UP); + mgos_gpio_set_int_handler(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_INT_EDGE_NEG, stmpe610_irq, NULL); + mgos_gpio_enable_int(mgos_sys_config_get_stmpe610_irq_pin()); + return true; +} diff --git a/mos.yml b/mos.yml new file mode 100644 index 0000000..21b59c7 --- /dev/null +++ b/mos.yml @@ -0,0 +1,46 @@ +platform: esp32 +author: Pim van Pelt +description: A Mongoose-OS Huzzah32 Featherwing +version: 1.0 + +libs_version: ${mos.version} +modules_version: ${mos.version} +mongoose_os_version: ${mos.version} + +tags: + - c + - hw + +# List of files / directories with C sources. No slashes at the end of dir names. +sources: + - src + +includes: + - include + +# List of dirs. Files from these dirs will be copied to the device filesystem +filesystem: + - fs + +config_schema: + - ["wifi.ap.enable", false] + - ["wifi.sta.enable", true] + - ["wifi.sta.ssid", "dapches-iot"] + - ["wifi.sta.pass", "marielle"] + - ["tft", "o", {title: "TFT settings"}] + - ["tft.orientation", "i", {title: "Orientation; 0=PORTRAIT 1=LANDSCAPE 2=PORTRAIT_FLIP 3=LANDSCAPE_FLIP"}] + - ["tft.orientation", 1 ] + - ["app", "o", {title: "APP settings"}] + - ["app.hostname", "s", {title: "Device hostname"}] + - ["app.hostname", "Mongoose Touch"] + + +# List of libraries used by this app, in order of initialisation +libs: + - origin: https://github.com/mongoose-os-libs/wifi + - origin: libs/lobo-spi + - origin: libs/ili9341 + - origin: libs/stmpe610 + +# Used by the mos tool to catch mos binaries incompatible with this file format +manifest_version: 2017-05-18 diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..fdceba3 --- /dev/null +++ b/src/main.c @@ -0,0 +1,61 @@ +#include +#include + +#include "mgos.h" +#include "tft.h" +#include "stmpe610.h" +#include "widget.h" + +static long map(long x, long in_min, long in_max, long out_min, long out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +static void touch_handler(struct mgos_stmpe610_event_data *ed) { + uint16_t x, y; + struct widget_t *widget; + + if (!ed) return; + + x = map(ed->x, 0, 4095, 0, _width-1); + y = map(ed->y, 0, 4095, 0, _height-1); + LOG(LL_INFO, ("Touch %s at (%d,%d) pressure=%d, length=%d", ed->direction==TOUCH_UP?"UP":"DOWN", x, y, ed->z, ed->length)); + widget = widget_find(x, y); + + if (ed->direction==TOUCH_DOWN) { +// mgos_ili9341_drawCircle(x, y, ed->length, ILI9341_YELLOW); + widget_network_recv(); + if (widget) + widget->handler(EV_WIDGET_TOUCH_DOWN, widget, NULL); + } else { +// mgos_ili9341_drawCircle(x, y, ed->length, ILI9341_BLUE); + widget_network_send(); + if (widget) + widget->handler(EV_WIDGET_TOUCH_UP, widget, NULL); + } +} + +void tft_demo(void) +{ + mgos_ili9341_setRotation(mgos_sys_config_get_tft_orientation()); + mgos_stmpe610_set_rotation(mgos_sys_config_get_tft_orientation()); + mgos_ili9341_setGammaCurve(DEFAULT_GAMMA_CURVE); + mgos_ili9341_setFont(DEFAULT_FONT, NULL); + + mgos_ili9341_jpg_image(CENTER, CENTER, 1, "mongoose-os.jpg", NULL, 0); +// mgos_ili9341_jpg_image(200, 150, 2, "flower.jpg", NULL, 0); + + widget_add(0, 0, 198, 20, 0, widget_name_ev, NULL); + widget_add(198, 0, 22, 20, 0, widget_network_ev, NULL); + widget_add(220, 0, 20, 20, 5000, widget_wifi_ev, NULL); + widget_add(240, 0, 80, 20, 1000, widget_time_ev, NULL); + widget_add(0, 21, 320, 2, 0, widget_topbar_ev, NULL); +} + +enum mgos_app_init_result mgos_app_init(void) +{ + mgos_stmpe610_set_handler(touch_handler); + + tft_demo(); + + return MGOS_APP_INIT_SUCCESS; +} diff --git a/src/widget.c b/src/widget.c new file mode 100644 index 0000000..48e9184 --- /dev/null +++ b/src/widget.c @@ -0,0 +1,89 @@ +#include "mgos.h" +#include "widget.h" + +struct widget_list_t { + struct widget_t *widget; + SLIST_ENTRY(widget_list_t) entries; +}; + +SLIST_HEAD(widget_list, widget_list_t) s_widgets; + +static void widget_event_timer(void *arg) { + struct widget_t *widget = (struct widget_t *) arg; + if (!widget) + return; + if (widget->handler) + widget->handler(EV_WIDGET_TIMER, widget, NULL); +} + +static void widget_destroy(struct widget_t *widget) { + if (!widget) + return; + if (widget->handler) + widget->handler(EV_WIDGET_DESTROY, widget, NULL); + + if (widget->timer_msec) + mgos_clear_timer(widget->_timer_id); + if (widget->user_data) + free(widget->user_data); + free(widget); +} + +struct widget_t *widget_add(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t timer_msec, widget_event_fn handler, void *user_data) { + struct widget_t *widget; + struct widget_list_t *wl; + + widget = (struct widget_t *) calloc(1, sizeof(*widget)); + if (!widget) + return NULL; + widget->x=x; + widget->y=y; + widget->w=w; + widget->h=h; + widget->timer_msec=timer_msec; + widget->handler=handler; + widget->user_data=user_data; + if (timer_msec > 0) + widget->_timer_id = mgos_set_timer(timer_msec, MGOS_TIMER_REPEAT, widget_event_timer, widget); + + wl = (struct widget_list_t *) calloc(1, sizeof(*wl)); + if (!wl) { + widget_destroy(widget); + return NULL; + } + wl->widget = widget; + SLIST_INSERT_HEAD(&s_widgets, wl, entries); + + if (handler) + handler(EV_WIDGET_CREATE, widget, NULL); + return widget; +} + +struct widget_t *widget_find(uint16_t x, uint16_t y) { + struct widget_list_t *wl; + + SLIST_FOREACH(wl, &s_widgets, entries) { + if (wl->widget->x < x && + x < (wl->widget->x+wl->widget->w) && + wl->widget->y < y && + y < (wl->widget->y+wl->widget->h)) + return wl->widget; + } + return NULL; +} + +void widget_remove(struct widget_t *widget) { +// struct widget_list_t *wl, *wlt; + + if (!widget) + return; + +/* + SLIST_FOREACH_SAFE(wl, &s_widgets, entries, wlt) { + if (wl->widget == widget) { + SLIST_REMOVE(&s_widgets, wl, widget_t, entries); + free(wl); + } + } +*/ +} diff --git a/src/widget_name.c b/src/widget_name.c new file mode 100644 index 0000000..2e4c40d --- /dev/null +++ b/src/widget_name.c @@ -0,0 +1,80 @@ +#include "mgos.h" +#include "mgos_config.h" +#include "mgos_wifi.h" +#include "mgos_net.h" +#include "tft.h" +#include "widget.h" + +#define WIDGET_NAME_NAME 0 +#define WIDGET_NAME_IPADDR 1 +#define WIDGET_NAME_SSID 2 +#define WIDGET_NAME_EMPTY 3 + +static uint8_t what = WIDGET_NAME_NAME; + +static void widget_name_render(struct widget_t *w, void *ev_data) { + char namestring[21]; + char *p = NULL; + + + if (!w) + return; + switch (what) { + case WIDGET_NAME_NAME: + sprintf(namestring, "%-20s",mgos_sys_config_get_app_hostname()); + break; + case WIDGET_NAME_IPADDR: { + char ip[16]; + struct mgos_net_event_data evd = { + .if_type = MGOS_NET_IF_TYPE_WIFI, .if_instance = 0, + }; + + mgos_net_get_ip_info(MGOS_NET_IF_TYPE_WIFI, 0, &evd.ip_info); + memset(ip, 0, sizeof(ip)); + mgos_net_ip_to_str(&evd.ip_info.ip, ip); + sprintf(namestring, "%-20s",ip); + break; + } + case WIDGET_NAME_SSID: + p = mgos_wifi_get_connected_ssid(); + sprintf(namestring, "%-20s", p); + free(p); + break; + case WIDGET_NAME_EMPTY: + sprintf(namestring, "%-20s", ""); + break; + default: + sprintf(namestring, "%-20s",mgos_sys_config_get_app_hostname()); + } + + mgos_ili9341_setclipwin(w->x, w->y, w->x+w->w, w->y+w->h); + mgos_ili9341_fillRect(0, 0, w->w, w->h, ILI9341_BLACK); + mgos_ili9341_set_fg(&ILI9341_GREEN); + mgos_ili9341_print(namestring, 2, 4); + mgos_ili9341_resetclipwin(); + + (void) ev_data; +} + +void widget_name_ev(int ev, struct widget_t *w, void *ev_data) { + if (!w) + return; + + switch(ev) { + case EV_WIDGET_CREATE: + case EV_WIDGET_DRAW: + case EV_WIDGET_REDRAW: + case EV_WIDGET_TIMER: + widget_name_render(w, ev_data); + break; + case EV_WIDGET_TOUCH_UP: + what++; + if (what > WIDGET_NAME_EMPTY) what=WIDGET_NAME_NAME; + widget_name_render(w, ev_data); + break; + case EV_WIDGET_TOUCH_DOWN: + case EV_WIDGET_DESTROY: + default: // EV_WIDGET_NONE + break; + } +} diff --git a/src/widget_network.c b/src/widget_network.c new file mode 100644 index 0000000..e134fb5 --- /dev/null +++ b/src/widget_network.c @@ -0,0 +1,64 @@ +#include "mgos.h" +#include "mgos_timers.h" +#include "tft.h" +#include "widget.h" + +static mgos_timer_id send_timer = 0; +static mgos_timer_id recv_timer = 0; +static struct widget_t *widget_network = NULL; + +static void widget_network_render(struct widget_t *w, void *ev_data) { + mgos_ili9341_setclipwin(w->x, w->y, w->x+w->w, w->y+w->h); + // Send + mgos_ili9341_fillTriangle(2, 10, 10, 10, 6, 2, send_timer?ILI9341_YELLOW:ILI9341_DARKGREY); + mgos_ili9341_fillRect(5, 10, 3, 8, send_timer?ILI9341_YELLOW:ILI9341_DARKGREY); + + // Recv + mgos_ili9341_fillTriangle(12, 10, 20, 10, 16, 18, recv_timer?ILI9341_YELLOW:ILI9341_DARKGREY); + mgos_ili9341_fillRect(15, 2, 3, 8, recv_timer?ILI9341_YELLOW:ILI9341_DARKGREY); + mgos_ili9341_resetclipwin(); + + (void) ev_data; +} + +static void widget_network_send_clear(void *arg) { + send_timer=0; + widget_network_ev(EV_WIDGET_REDRAW, widget_network, NULL); +} + +static void widget_network_recv_clear(void *arg) { + recv_timer=0; + widget_network_ev(EV_WIDGET_REDRAW, widget_network, NULL); +} + +void widget_network_send() { + if (!send_timer) + send_timer=mgos_set_timer(100, 0, widget_network_send_clear, NULL); + widget_network_ev(EV_WIDGET_REDRAW, widget_network, NULL); +} + +void widget_network_recv() { + if (!recv_timer) + recv_timer=mgos_set_timer(100, 0, widget_network_recv_clear, NULL); + widget_network_ev(EV_WIDGET_REDRAW, widget_network, NULL); +} + +void widget_network_ev(int ev, struct widget_t *w, void *ev_data) { + if (!w) + return; + + switch(ev) { + case EV_WIDGET_CREATE: + widget_network=w; + case EV_WIDGET_DRAW: + case EV_WIDGET_REDRAW: + widget_network_render(w, ev_data); + break; + case EV_WIDGET_TIMER: + case EV_WIDGET_TOUCH_UP: + case EV_WIDGET_TOUCH_DOWN: + case EV_WIDGET_DESTROY: + default: // EV_WIDGET_NONE + break; + } +} diff --git a/src/widget_time.c b/src/widget_time.c new file mode 100644 index 0000000..3be6737 --- /dev/null +++ b/src/widget_time.c @@ -0,0 +1,40 @@ +#include "mgos.h" +#include "tft.h" +#include "widget.h" + +static void widget_time_render(struct widget_t *w, void *ev_data) { + char tmp_buff[32]; + + time_t now = 3600 + time(0); // TZ=GMT+1 + struct tm* tm_info = gmtime(&now); + + if (!w) + return; + + mgos_ili9341_set_fg(&ILI9341_YELLOW); + sprintf(tmp_buff, " %02d:%02d:%02d", tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec); + mgos_ili9341_setclipwin(w->x, w->y, w->x+w->w, w->y+w->h); + mgos_ili9341_print(tmp_buff, 2, 4); + mgos_ili9341_resetclipwin(); + + (void) ev_data; +} + +void widget_time_ev(int ev, struct widget_t *w, void *ev_data) { + if (!w) + return; + + switch(ev) { + case EV_WIDGET_CREATE: + case EV_WIDGET_DRAW: + case EV_WIDGET_REDRAW: + case EV_WIDGET_TIMER: + widget_time_render(w, ev_data); + break; + case EV_WIDGET_TOUCH_UP: + case EV_WIDGET_TOUCH_DOWN: + case EV_WIDGET_DESTROY: + default: // EV_WIDGET_NONE + break; + } +} diff --git a/src/widget_topbar.c b/src/widget_topbar.c new file mode 100644 index 0000000..739a133 --- /dev/null +++ b/src/widget_topbar.c @@ -0,0 +1,33 @@ +#include "mgos.h" +#include "tft.h" +#include "widget.h" + +static void widget_topbar_render(struct widget_t *w, void *ev_data) { + if (!w) + return; + + mgos_ili9341_setclipwin(w->x, w->y, w->x+w->w, w->y+w->h); + mgos_ili9341_fillRect(0, 0, w->w, w->h, ILI9341_WHITE); + mgos_ili9341_resetclipwin(); + + (void) ev_data; +} + +void widget_topbar_ev(int ev, struct widget_t *w, void *ev_data) { + if (!w) + return; + + switch(ev) { + case EV_WIDGET_CREATE: + case EV_WIDGET_DRAW: + case EV_WIDGET_REDRAW: + case EV_WIDGET_TIMER: + widget_topbar_render(w, ev_data); + break; + case EV_WIDGET_TOUCH_UP: + case EV_WIDGET_TOUCH_DOWN: + case EV_WIDGET_DESTROY: + default: // EV_WIDGET_NONE + break; + } +} diff --git a/src/widget_wifi.c b/src/widget_wifi.c new file mode 100644 index 0000000..c86e667 --- /dev/null +++ b/src/widget_wifi.c @@ -0,0 +1,65 @@ +#include "mgos.h" +#include "tft.h" +#include "widget.h" +#include + +static long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +// Returns a value between 0 and 100% +static uint8_t widget_wifi_signal() { + wifi_ap_record_t info; + + if(0 != esp_wifi_sta_get_ap_info(&info)) + return 0; + + if(info.rssi <= -100) + return 0; + if (info.rssi >= -50) + return 100; + return 2 * (info.rssi + 100); +} + +static void widget_wifi_render(struct widget_t *w, void *ev_data) { + uint8_t x, signal; + + mgos_ili9341_setclipwin(w->x, w->y, w->x+w->w, w->y+w->h); + + mgos_ili9341_fillTriangle(2, 18, 18, 18, 18, 2, ILI9341_DARKGREY); + + // Map signal strength from [0..100] to [0..16] + signal = widget_wifi_signal(); + x = map(signal, 0, 100, 0, 16); + if (x>0) + mgos_ili9341_fillTriangle(2, 18, 2+x, 18, 2+x, 18-x, ILI9341_WHITE); + + // Draw an X in the corner if we don't have an IP address. + if (mgos_wifi_get_status() != MGOS_WIFI_IP_ACQUIRED) { + mgos_ili9341_drawLine(11, 11, 16, 16, ILI9341_RED); + mgos_ili9341_drawLine(11, 16, 16, 11, ILI9341_RED); + } + mgos_ili9341_resetclipwin(); + + (void) ev_data; +} + +void widget_wifi_ev(int ev, struct widget_t *w, void *ev_data) { + if (!w) + return; + + switch(ev) { + case EV_WIDGET_CREATE: + case EV_WIDGET_DRAW: + case EV_WIDGET_REDRAW: + case EV_WIDGET_TIMER: + widget_wifi_render(w, ev_data); + break; + case EV_WIDGET_TOUCH_UP: + case EV_WIDGET_TOUCH_DOWN: + case EV_WIDGET_DESTROY: + default: // EV_WIDGET_NONE + break; + } +}