From 70df6a1f87aa2788c167b6a7e37d17f07985e821 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 26 Jul 2024 22:15:04 +0200 Subject: [PATCH 01/21] [P073] Add support for 74HC595 displays --- docs/source/Plugin/P073.rst | 57 +- .../Plugin/P073_DeviceConfiguration.png | Bin 51028 -> 56893 bytes docs/source/Plugin/P073_DisplayTypes.png | Bin 9626 -> 12740 bytes docs/source/Plugin/P073_NrOfDigitsOptions.png | Bin 0 -> 25305 bytes docs/source/Plugin/P073_commands.repl | 2 +- docs/source/Plugin/_plugin_sets_overview.repl | 96 --- src/_P073_7DGT.ino | 556 +++++++++++------- src/src/PluginStructs/P073_data_struct.cpp | 274 +++++++-- src/src/PluginStructs/P073_data_struct.h | 55 +- 9 files changed, 640 insertions(+), 400 deletions(-) create mode 100644 docs/source/Plugin/P073_NrOfDigitsOptions.png diff --git a/docs/source/Plugin/P073.rst b/docs/source/Plugin/P073.rst index cb6b1536f9..a5a4a88d5e 100644 --- a/docs/source/Plugin/P073.rst +++ b/docs/source/Plugin/P073.rst @@ -24,17 +24,17 @@ Used libraries: |P073_usedlibraries| Description ----------- -The 7 segment display plugin allows to display date, time, temperatures, numbers, text and self-created shapes on a 7 segment LED display, using either a TM1637 or MAX7219 driver. +The 7 segment display plugin allows to display date, time, temperatures, numbers, text and self-created shapes on a 7 segment LED display, using a TM1637, MAX7219 or 74HC595 driver. Depending on the available space in the release, some features may not be available. Currently 3 fonts are available for presenting text on the display, where the character shapes are somewhat different, and a choice can be made on what font is the most appropriate for the intended purpose. The numbers in the fonts are all equal. -When text to be displayed can't fit on the width of the display (4, 6 or 8 digits), scrolling text can be used so longer messages are shown like a ticker-tape display. +When text to be displayed can't fit on the width of the display (2, 3, 4, 5, 6 or 8 digits), scrolling text can be used so longer messages are shown like a ticker-tape display. Optionally, periods in text can be shown on the dots of the display, when available (not all 7 segment display have dots). -For temperature display commands, ``7dt,`` and ``7ddt,,``, the degree symbol after the temperature can be turned off so there's room for 1 more digit of temperature on the display. +For temperature display commands, ``7dt,`` and ``7ddt,,``, the degree symbol after the temperature can be turned off so there's room for 1 more digit of temperature on the display. The degree symbol is turned off for 2 and 3 digit displays. Configuration ^^^^^^^^^^^^^^ @@ -47,14 +47,35 @@ Configuration * **1st/2nd/3rd GPIO**: How the display is connected can be configured here. Description per module type is in the Notes below the GPIO fields. -For the MAX7219 displays, the DIN-Pin and CLK-Pin can be shared when multiple displays are connected, but each display's CS-Pin must be connected to a unique GPIO of the unit. +For the MAX7219 and 74HC595 displays, the DIN-Pin and CLK-Pin can be shared when multiple displays are connected, but each display's CS-Pin must be connected to a unique GPIO of the unit. For TM1637 display possibly the DIN-Pin GPIO's can be shared, but that's untested, so it is more safe to use separate GPIOs for each display. -**Display Type**: Select the type of display that's connected. 4 models are supported: +* **Display Type**: Select the type of display that's connected. 5 models are supported: .. image:: P073_DisplayTypes.png +* **Nr. of digits**: If the **Display Type** *74HC595* is selected, and the page is submitted, this setting is made visible to select the number of digits available in the display used. These are the available options: + +.. image:: P073_NrOfDigitsOptions.png + +* *2*: 2 digits, the smallest available display + +* *2+2*: 2 displays using 2 digits connected sequentially (SDO of first display to SDI of second display), making a total of 4 digits. + +* *3*: 3 digits. The 2 and 3 digits displays use 2 or 3 74HC505 chips sequentially, to control a single digit per chip. + +* *4*: 4 digits. The 4, 6 and 8 digit display use a multiplexed setup, using 2 74HC595 chips per board, 1 controlling the digit leds, and 1 controlling the digit selected. These multiplexed displays need to be refreshed continuously to properly display the intended data, causing some extra load on the ESP. + +* *2+3 / 3+2*: 2 displays with 2 and 3 digits or 3 and 2 digits connected sequentially (SDO to SDI), effectively giving a usable display of 5 digits. + +* *6*: 6 digits, multiplexed display. + +* *3+3*: 6 digits, 2 boards with 3 digits connected sequentially (SDO to SDI). + +* *8*: 8 digits, multiplexed display. This display also supports the ``7ddt`` command for displaying dual temperatures. + + * **Display Output**: Here the type of output can be selected: .. image:: P073_DisplayOutput.png @@ -77,7 +98,7 @@ The Clock and Date outputs are updated every second, and the blinking selections Clock and Date formats are optimized for each Display Type to fill the display efficiently. -* **Brightness**: The brightness level of the display can be set here. 0 is 'Default' brightness, 1..15 from low to high brightness. +* **Brightness**: The brightness level of the display can be set here. 0 is 'Default' brightness, 1..15 from low to high brightness. Displays using 74HC595 ignore this **Brightness** setting! * **Font set**: Select the font set from this list: @@ -108,7 +129,7 @@ Options * **Text show periods as dot**: Enables the use of the display dots when periods are included in ``7dtext,`` command. -* **Hide ° for Temperatures**: Will leave out the degree symbol from the display for temperature commands ``7dt,`` (and ``7ddt,,`` when available), allowing 1 more digit for actual temperature display. +* **Hide ° for Temperatures**: Will leave out the degree symbol from the display for temperature commands ``7dt,`` (and ``7ddt,,`` when available), allowing 1 more digit for actual temperature display. This option is enabled by default on 2 and 3 digit displays. * **Suppress leading 0 on day/hour**: When enabled, will show the hours of the time and days of the date without a leading 0 when < 10. (Not available in all builds for size reasons) @@ -120,21 +141,16 @@ Options (The Scroll options and feature are not included in the Collection builds for size reasons) -Options for MAX7219 - 8 digit -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Options for 8 digit displays (MAX7219/74HC595) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* **Right align Temperature (7dt)**: By default the temperature display on the MAX7219 - 8 digit display, is shown 1 position from the right side. This option enabled right-aligns the temperature. +* **Right align Temperature (7dt)**: By default the temperature display on the 8 digit displays, is shown 1 position from the right side. This option enabled right-aligns the temperature. Commands available ^^^^^^^^^^^^^^^^^^ .. include:: P073_commands.repl -.. Events -.. ~~~~~~ - -.. .. include:: P073_events.repl - Bit to segment mapping for 7dbin command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,16 +158,11 @@ The ``7dbin`` command allows to show any combination of segments on the display .. image:: P073_7Segments.png -The mapping from bits to segments is: ``0Bhabcdefg`` (Based on the segment mapping for MAX7219 driver, for TM1637 the pattern is converted into the correct bit-order) +The mapping from bits to segments is: ``0Bhabcdefg`` (Based on the segment mapping for MAX7219 driver, for TM1637/74HC595 the pattern is converted into the correct bit-order) ESPEasy allows decimal, hexadecimal and binary notation for numbers. This makes creating the desired display pattern easy when using the binary notation (starting with ``0B`` or ``0b``). -Switching on all horizontal segments fot a digit can be done by the command ``7dbin,0b01001001``. This can also be entered in hexadecimal notation: ``7dbin,0x49`` - -.. Supported hardware -.. ------------------ - -.. .. |P073_usedby| +Switching on all horizontal segments for a digit can be done by the command ``7dbin,0b01001001``. This can also be entered in hexadecimal notation: ``7dbin,0x49`` Change log ---------- @@ -186,6 +197,8 @@ Change log |added| 2023-03-29: Optional suppressing of leading 0 for Hour and Day in Time and Date. + |added| 2024-07-26: Support for 74HC595 displays. + .. versionadded:: 1.0 ... diff --git a/docs/source/Plugin/P073_DeviceConfiguration.png b/docs/source/Plugin/P073_DeviceConfiguration.png index 4530bf3fc13a2e3f0cdbe01796d78cbcb26b82e7..4aecb747dab23859eaf655f5bb80a3366857b944 100644 GIT binary patch literal 56893 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 diff --git a/docs/source/Plugin/P073_DisplayTypes.png b/docs/source/Plugin/P073_DisplayTypes.png index 1d938837945e820d1d4b65fa180f021403d2dc24..c69d6a473149eab000b8274e71eee7e083eac8ae 100644 GIT binary patch literal 12740 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
&~QhEw#5v!4>5_MS#L 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 diff --git a/docs/source/Plugin/P073_NrOfDigitsOptions.png b/docs/source/Plugin/P073_NrOfDigitsOptions.png new file mode 100644 index 0000000000000000000000000000000000000000..358a7b8b2059039e56fe7df0433fe28ed38d6f82 GIT binary patch literal 25305 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∓W{TRg@;{UqQoQEA;`DMdk?15A{YN&v?d#2zji=sJijt|T@+HG}eQ?>%BM2&%6?}O76Q$}K6 zaKm?45b7walT5&&`U0uPjU4kl{mns$A+9G$p1uBfnG(ur9eguD479;=r`@(#a2{h7ny^L9|J3$QNvbC!DY z+VrM$@%0#EdkI;$u(W8j$w@{-+1(JF8cqFwrr{DxDnsy4z~+>};c<0q ztIWUvmOj)BlB$;xq!pudcnMuQ#^NAzAh=upZMX8=TCIdCs3@-WQtDj8aC z>_9bklnE40J+7|(-qG0FzTJDjr*c+p6+5ISW8vY|`MtqS!Gi|;@h>uxgNyWsj#1?_ zD^(S$E33R-wn7hadvTA4z&&MB2mKjoctXT`yL4|5-ZcLi;6LAYxAXyVMk`OVcc<8} z(ydiUPLXs?97}u`c)&Oubx0EQgh6%GDjbAh&Upb1Z(!lztl)X|D&MH&W!7ZIgy_fT zlX}allhoBjuk?02E^Jaa-W2>)&XI|G@ihzy(_b|=e}?rv8y}j5^?g0;%N--5i2|75 zN93N~N60S&>yUxfO3#}g9gSMc=2}+f4c})CvK~&hH7eU~=O5a=aOuoOu%ZPP$jfb- zmtBY_J^ij6OkFxL2dp(_XBJSYhLWGpFc7Q<$1bM2^jU5dhE*OEMCD!Agc6^HGud*a zWAc%xIGj|u(MH-X>odv!pi?n4^KxKX zv^*RLG5>KWnR17_uhnlXQ+7_1s%!NvKAT9Z1Vbp3vPAX?8s^4UlTtJFPN9RI;;X0U z>|lbIDM7sb9r5bS?43X3%?}5-cnX-!$HYsz#Z_2_6I4fJ{8^q+XX--amYzprEZp;xYi3!Vko_)11ai8~Mv_bzY!J>0k#barV4k--hMg|;sX zYv3#K$8u|Oq@sfOlLqzVDc1Fb$-XEi{+1X{R;2#1;th+5IkRU~`)Uwed0u?KZFsfV z8k(a5;{eFgibnP1S+T8lI&s$kw#wO>Fd$Kydh7)P_ORmrS>i9jqx0R2ySt@hHV@QV zj=>t`DOd)pNy*vlQ`zzqh^pso%_Ud>>$PssA(Zar$UC7eM8CS{Bb(<_ml zu`FpA6axeLUi`y11!?X9R_@M~q?}&`dP!+1IR&^vYHD6qHZ!u%o*5;jp2T=h$~q(@ zTjUw?KNIOZRvlx0CeeQMz3sSu-9x0A)<`Po`aT|Z0GJ4i9ZbY4jmP&XBmJsbJ$+ck zs0;y!KBfK+Gvi>a5@SI=E*?qBE%S!4EQ6DKpCGA_E=5y+{2RTc+X*BF@K+2F;~ZMpNVHFQTNZY*c=!N$b|nnhg?=xt5-E z3kg(0!&1F3whl*VPWDxFou zQ4UvF=XX?Eleg3BQS$C8b$GQ6*m5IRHkX_MS|K~e;}wZ2JoUu zyfz@iSm=9hR%?uyv+=iAR4Uu}3z4`+tivlV4HIr>;toeY27eYm2K70MNJw+D8jVy@ z4FCC6Wr_ac`S%J-;zRqu*SCjePAQ2UK5vuEJ%UeT*G30pwv2zFJ@u$Rh0GZRh)Cg^ z2`g8ah4CR_h2zxKtqro5A-%3)A^JcX?*KtFqq5kZ+ufNLjU{`9+j}avgq00iLn_BRaa%# zOYxD+v>{{D16k^V=3jCh9f{vxc*t*w-R!b@Qu%gB`ixZ%lMykzS!Aj4XP~SVDD3h2 zzMuY7&xh9mv0TlF_|X;4j)Z=ThYlS%TY5HBT^aRfO(`tAP3-Wv5Yx$cQKN1P(DKMj z@bKM`x&GfFzXlISZNB{wFgeAc#gSvpNSpa?T%q+hjpvmExqL9ok1R7gb%EnxpL_}Q zOL5BV^LL@-OpMC%{$Frp$@Q4@_*(YZS;DHGK@k9-;jses<+hSRFxg=1O&a}{gmDix z`mY`a_V42#JIZb?$nvv4KIKEXImyo#g`T=Rb2u9Gf@~fZ*oQuR0LEP^u$v38`pz`) z2cHEQE&E`cHBzJ8u9880IB{^uV(ge7vqBcsQlbxQEhrS@VpBN zOwLIYz>8s<@fG?K%*_ET{bhSB4c+6v*o9V9xcEqPD&FHw=mQ%SY#-wOCUJydCCac=er}WjL=>2)%Lq&vTJgA zY4*_I z5??=7{5MSGlQMc=$nwp%ci~dKo)^s*lEbs*eY4TSIqb=5a1MJrcV_Ze8j_cX40r?d z7oX7B7+|?6@y|Fg(`LuRdap(*4Sod^IQa@BD3Rv_#nL_sf!Xbmo|UN3j)AoQz7BZ< z9dovin-r?E)_DKfWr!^b82U-bzoCyp5UA}#%7_R(aX<#Y=NX&{)C1Xz{4mv-5|6B> zJ58rpoK3jg#EnCH2BYLO=zg7^@HRBA-$4&|5cDqN)dHpL+3vpm3zru837gO6yb2=Z zZK~vEiO@A?PkjS}Y?I9AYXB#Z1DfD4w}I+_Pu4&sU+}d!%IhnvazV!AVp3QwE~{VP z0}EvA2lF!ll`1ZJ&lXa=pjc=IG?Xg5r&2X%xsuumNHPnEniGzYQ2%DmuTXrmVCO&3 zwex4W33w{iKV~)8?C-_l_2hDmEQ1Ct=qiz<7BSF_WBy@gisB`lXI}=5ZwV@)jn)ea z=*;?W*=N2rVksaUfJ(Vawio<-i;k!y8fQ#?ik9D$C1qXS>jaop%~_v z1LT~hjjtr-$xmn&kh7r`j;%|CLJF3iCr5#iQGc!6u~#If3SOBSn;yP=lKh4DyHZem zLdnw6R`sNAPDG8sjKQ0{l66sgp+mp8q@t(ey6hF-)(WBxGr$*2a&5tq+@7PWNcAd- z{CVUHX1vc&HT|5vCM^DbUplsB6FaFh^;N(~A%MDudV+`P`w`zj#{J;kqO#(A#s^b6 zo~hfmVegG@xAarDBB)Eo3vIOG0JiCCP`hn|U3le-HS3$uTL9^4T($(lve-~e)UFYn z>TXm^qt7B@nx%gt7XPLx^rvto1DIF7EM3UAL!q9VH&!D43_d^&!?o$otfS|X(W_#c zN2A4ot8E(IO({EdJnEGq509vsi%Dq?13WyFJIH%c_)u$=5^DX2m@Cfj;q&0{XTW>?)LIeKg(A#eUS4rM{w>R%`)0qa zf`&{MAoLRMH{EcTMaIQcEr6zzHacnoTIysc?1-Ag6+8i*!+(TyJus}t!(ykA+<0Z@ zChsDV_ZnNKb&i4*x+8kKiR*t84f=~^z7*$+bn{+c`+Df*=B3J}fDMg++L8=TP*23G zXmPBvhpf+OCB0zBS!UwoiYsWI%jlV5wJ&Gb+dUSIQumne2~up|7G4T)4S(R}F?~OG zNz7JkXox^v<6NkjwwFy9m&jA9d|r5y9NT7QiS+N9W()Q40ajF-(C^{Io^4*Ei2X<6 zyP6Vw!`m+5y2G076XYX03Z!!gKBY~YRC*7?B;=$484Q0R=K?2gsG!KX#h0DkbJ)m67znv!i-cbn6_J8mU z^u2azFigaj&U>#}Z2zscXjh2a%SNi$*E(Q0bztkt=##aZ{+RvtD>j+S-ybdqcj+_{ zA^#l_kj+PZxLPR<^bt`dt->6(OWXC>nhvhg($}CkEmPw+a~=^-r6kU9on&>BtSK3D zJiku*1)z?A`s6YM1e3Fs9hZMCHtxyDTfSSY=RJu!c^o?bTD$WMuO`L{Pg4G6?Sv0< z-3VuyDm69BB9dF)5nfNPRmYbfciCv$&@zfY_p!}(SHb%O0s7DGzEt%{+vSXtS6Kj* z(J3`E-BEP@1F;Zy*zFPbEdXjCo|1jylmjD6Nb&XI=n>_FZ&H<-vOn>|iyD1ED&wm=|gSiCO?IFdTL%F51CwC@#*HTFjtZYt*TWjod(K&mVKZ39ttcZSLoDG0 zBy$;`NxPqfsOPD9($wabZ8$&VHLDYzr}cb89uo4lQS_J`bE)wzN>4orv)B}~;#ZmN zK5%n4k}(0x-p&GXZ5Spu%7thF5@A!j%I@o{6zV4y-U;hd7K6_ni|L6jopfnyJuLSZeAg^@%ABy0=pAIXAp+sc* z*TgExF{LSq{)gU>$z&s7Lw98%Q4&suad&J+YDJNB=A$4(yAbXtzdi;bB||WyoC>73vPb`^RbENf-mmCG9f^rtJ+` zp~d%q=kovY-NepSqJaXJ7xeUwu6Xc&w*Wl5LV}zjz#dI%fOmZ%OiCyzUS>5kx7!3j z93;lk$dC{I`44q~;~WRHGroetn{7MK=3W2IrRF9sFqfiP>|yh2!#%Fa|4J=M?-K4i zrYTTHgHjYIgiwRKlE_Rj&vQlt+zb632l0<{${ZmJj!bjqdK#wa1HjDmt;GFf)UCrH z7+N+su&K7zjU8^cn6=4oc((|Ou#$V_h%_3EH{1@@j#x1xX*+0p>wTHpwVTm}k(C*z_+f}G zif)1eEe@;XNRJs$8L^3;0M!f46ez3WIgs2Afg6!n81f;-N0e{Y`sJy;^$vLt;~xkm zG_UGg<9Zwa46MqurS=>h^EtXcVAR*o9mPiTerPcUas$*e?6lUwAe`0k?*d3arrz*n4Ety$ExSebaC_^OW#n!F}C zG%t_P7#+2>qithcU;bBHR~;7R({@FrM0!c-TyO;!Nhyg10g0s>>1FAZMx=zLW0BTf zS^?<>m6n#05Tro_q(SO?;P<}o_0>Q7*RylYJTr68J?B2>Jma5-_@cts1jc=xc5VP} z865k2CW`8!Pt>1@a7Ic09gb`Gw@^}9zWhZr9Sx1c!|fq)W0qqKkmlgr`STJ`I_b!4 zzE^CITRUD#RvR2pHD5yAxzo;PMuKY|NuT>CB)!(e=;V-?rou-CNh3HoLZN`IAuluO z^~~L4LztZXrjdHhhkUxZQO?Xj7}-eg`(uNJCKxDO1 zUC0orGe5sd!~vrZ6p?)hkz-c+J=LivbFx5=*;uQNAJGMgF0>Z3r!}i3>RHI@G}4LB z2f59+R3HH{%TM*#v_l;4uvcB%8r|`|x+Pf88;?m9@Jl??L>7$BTZ@P?dy48ek&h9fPfE3ued|CQP6{O?H zi2B}G8(*x2ZkL?;G5IsptiZQfc`U^`U-^FZV6lwZwdn3h=P}DM!2?;#JLXB zB>9$1pk1g67s1hy3E?WOc>A-l|{70a~2Q z+I2G57U0jU?Z}4wL1Gs~+S3A*Z8&++)OM~sgP=lvKCQe4*#kTp8%oL4?IA$7#gt2= zI>Lo0)|E^%dQQ&-UA;MHNjEcTGrSb?vA%o&-#TTS-V-T^d=@f(%;MHYH=h&v)AD=XA0_f190AJjc9 z*?|?y#Q0_*n@R!gK5y#RrZct&)NeSce=4UGlbNEw{kUa{zg6EZ(}|;lKOn*4Yp3*d z#_c+yiu!80CAJ4*5K5Tle5UhAR=cZn0|j_GTpc~w>vMW66>}YsA2PcEMd@F{^{lWR zOhw_UXI4fmR06TP^~1h}mSF^t@AT@%EF%+kQAEklI(W*-3Qn{W!=NfY=n_p_)nTFH zv0vI{GMz|Bpbn>1Z%UL>8oKwbd~XMv4oh&@O{zT~-X*tW+nv5#8icudcH&->zm2(h za7DcYRWB7M=AID*Tccfp9W-8Hg9N3EjB8Dr`RwkWx{OU6YU+K(o_mF z)r*}->9O*jj`XUHT+U;L<53%so~86{XZ4-4eF!PA5iia~%hVlL!!) zvD^%jtk(<#kE_aer%TWkD&7?R8#L~aWV)mei83E(Hl7veJ0fUB|jp8!Urcu!@E&29$oMe+RYiM0%=6yFl4L&)(3M1M7 z99v8jxPhrweEOmgnq3{+Xzc+Ak3FtnS^%>I28%~S-D?I_C0Yl=79sBCWW5&A6p(;4 z<7{dom8vRjfpoV$6eL`XS}{>k1RA*Y=yy2_hF7Wk!AF@%uiB3Pazyv&geq?XHx zXqq)}8?5i%%$}bx*gf$FMRpo!xNBPwmSF1}B2Q`WX_xU=a`08q=Ih_41TAhxc9sV` zi#Fd841M?{(6nV@gEOv6&fVQza3h<2;zNdw&57rLqI+OAf2VAk5yqlg=6!~E6)M6_ z5H3ja+SHhWqW0c(xQ+$NQ8J(d*0bor)c9+g8|JZ&Ge`wct6&7uB=aaXCvEAan|9xj zw~qG8LDcgjI{ z24}CB_;FVyKvo7s6;-&j%qs7?HZhZvJn7kKZ`aoe(_K|Z7*Hl)3Tv5u&2sH`hK!`O zABtC2kk#^GFhSNX11`B@yl=g-Yde)>f1A#x#W*wgChqdPM{yN!*}1tTa)Go2N%CzF zZsFF$_c($CmG%s%feJ&7Jt%M8V1X|p`=Q5vD3+T8IQbLPIisF>H_MZYxU(B9tT;7- z4HqSXngF*Y*VMk0wI23>spr}yOIU903RSIdMXHpy=goo4P-@nlAI>nEx?p{kbI*Es zpcZ&h7EtR^Fc(WCYt(|&mnt|G@!BHTZL+CYDN~)pfMO9uqNq*j{E3;Rbwb4yEw}w4 z!@txZEC}to=Z9_=JG!g#gG1$qsH$q*NR_>Eq{SN;v}3nuOY1`=xU?KB>@sMT&>`3_ zOP}|=TixB1TFP|1?*l4GTs3J#3ld7XZ*f(5*vZV64C?%|fuiXXm1NGzrJ;Nz_)b2d z78*t0!A7Nb-2Qz^C_UTg2)rAd6k))zg}9Dg!oIQ%rC15YP(=S@_HqM z^AMKYc6O0@pjDI!KLT@6y9BYNXC)qltlgdX+2R=L$C^%P!mb$bE{reTlKF?yl zR73*IHBd@9_-)(_lL!$Tk^rvN{Yvz+tms8%wp5U^ndBqyzjp!6fN1PCGzXP$)4X)3 z2nN}b52O}q8(|MNC8wlom~4FbF<{pMxvLzuVwmz9I0`ch`q6_c4*(%RhA&D1X8Yn{iE|i8D$Q3wC`Wr%wIY7gJAsm9g3j(lhf%)!@T3 z?I}M4<+MI5nzK6c6$|3ZMPu?*a}-7{Mp{oQ=AsX;>Rmvf7A6#qM9WOg*IG>Y7(A3s z^1tn}Q7QWvLLPk6%zKtHb!V)O1wNuzHl{5ix)zRi#KUV4%?*w^1+|e!eSE0!ij}&J ztmEWdLS3a3Q$-dB7a-4*m+0HW;{okxJzT<)^_oSus^pDSX+w%mDKmaOp<{F}6V@%% zT=BFn&n8gG%aM>G?f0EgrY*2Fz%v;U6q4-tNp-~A&@F`WqiGggC5{&%%fF#w!I6Nm z%71d=mQwtFjmg%mp(}wlawsV*HXET}3NoTS0>?^v(dG1~%bbq%wMk9Rw0dchg+{!- zs-Ob$flKrYkh&n-j&nusSW(MYHXSpYVr`?vo9*6%#x5CkEP^{jDj~%w*1Q;-;lm|& zH>n;0(XyvIr+3wR^E9j8^k}eVyz4MdUsZ=cepL3?E>pcif{)|)(V*57M~f8QiE%r7 zzYH%gXksr{nX}FqFLml}vKlu}_G`H4ogJb?X%I`$kb29F#iO+29%h1y&~P3GbDx-b zrFC3oh!ujh@o7CL^*q(AV)VnxF76w}iGT;omiJnZtfIQ$ks>IrZwgkxofA<6|DD~M z^9-Puf4rgGP?wS!o`tu-yG)aU06AMEF_XvLOeBNZZ|!L4d8<;E_{3+K5t}Z z9c)>CKULX=djeIAwb%H0)X{M>B^8aR*TPpP`CY<_7YV`**AWAD`4g&8QAH)-bit!;xO!Sj5U6kK^@NMQIk@B?A97 zX?I2g_^!&@Wddh;&3NvCBQ^YPe@IB|Ek{b&x*~j`G%Oq9u`llqhgZFb*@I$U`vuTv zdR(qJU*z9sHKV`gPDQ?_h83KG6b(VGIy98Vf-dIXO17(A#jj3@OIp{hB0A!z5G zVHW*+T5)>SsrzRwG8;{hQI4(6?e`%s{9ieK#wDa--yaU2$8{yO4*Lqp%5y6s?nRdC z3(gPfcKuADD%OQ!hG&Qa`d##s=vz^jl8{`Q)X?_Le+Kv{ z5%Ya9IB8b3vsoT)U&{2+A0WK*{R>Aghu6LQ`O3U|;iUJ`W620wfmKL^F)hEDyLpq3 zqp5^96LsezdyD?>Z60&&Bg$fEYD{@*ExbFvCCg-L?nmA&zTa}$G<#UI3ys{~rql3Y zEKYjb(H}_?Jd)eYp?j%)V(IO}pZWQe*S^!Voe0GY)KPgm2d>;|YOyhog*BIVOowhR zqUd_(g`Il`W~GS!urluYs=0jZpOW{eIiJ5rw_&j06n;HVz%ab6V!m1=ed+Z|c9gn1 zf|k`{S`Ma`A#(uGhd8KZhnGRST8nV*&=Rp1gLsM88#7nvXILm~>-T=LS}dzuL@^7_ zoeNrQ7DFWhqv6B!dRgqw(cL(7PQ_VPVS3LZW#!7BcK_cDVR5gze04r&SWHnUd}u@5 zd|`F@5;p2BDf+2Nl>GQbS7DX}oWl3ZhFI9^U0;nP#8WorrwoD&xz|^RbJ^?oN2de7 zoh5f1AW!^OIMhs!7z-F&FkSKRI#Ze5m%||#I{GgJtb#v}zKd-Fh~&dxm@fi^^Rgw_ z7~T0a+~aY)Ky2VqdXVj_qaT{cD4r!9le&k-BMW9R}a)`Oo_~ zjz+a~dObHeJg-z*=x4q|7_JZ1)S1((f$x^=n@x=m84U@Fvp zkrvW`!@(gV2o_q6Gp;b@peNMfwcRdqOd>v$Sg$slfg8F_RdZ87zUslN2dvdAZMQgU zWVJV-%Q_}Q+9lkf6?^NL7tYf(jkUD3bcNe4P=DtnbvY98+vNKAn967ljxBj0Y7}fZ z?`KR?bugc=DgMi^Cm7(?a$?pP^1*BkBKgweB$J_Pw*-o|{qOk~oGauMRL5RytS^K_ zN;OwAJvWPUY@NboV|6XSoH~C@+G;Ha8Z*26JMq676NXn|{IHqA@9mjjmsySUe?coE ze>*fU9hvtTljG|whdl?7Ymo|<_}{vs*tS?}Pzx6qf$H!N6C3-JwmF{v-1$3KbAr@} z$vd*=S)yo21GxEW9?jKU+ynjHdW*0;CZ3hV2^zccPb2GA2ehJdNIsjboB }8T*v{4PP{DMh# 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 fbY!SJ*GjF*1LWL4cO},,`` diff --git a/docs/source/Plugin/_plugin_sets_overview.repl b/docs/source/Plugin/_plugin_sets_overview.repl index 71215421c3..cc26eed667 100644 --- a/docs/source/Plugin/_plugin_sets_overview.repl +++ b/docs/source/Plugin/_plugin_sets_overview.repl @@ -90,26 +90,20 @@ Build set: :yellow:`COLLECTION A` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -120,9 +114,6 @@ Build set: :yellow:`COLLECTION A` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -206,26 +197,20 @@ Build set: :yellow:`COLLECTION B` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -236,9 +221,6 @@ Build set: :yellow:`COLLECTION B` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -316,26 +298,20 @@ Build set: :yellow:`COLLECTION C` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -346,9 +322,6 @@ Build set: :yellow:`COLLECTION C` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -423,26 +396,20 @@ Build set: :yellow:`COLLECTION D` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -453,9 +420,6 @@ Build set: :yellow:`COLLECTION D` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -531,26 +495,20 @@ Build set: :yellow:`COLLECTION E` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -561,9 +519,6 @@ Build set: :yellow:`COLLECTION E` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -641,26 +596,20 @@ Build set: :yellow:`COLLECTION F` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -671,9 +620,6 @@ Build set: :yellow:`COLLECTION F` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -750,26 +696,20 @@ Build set: :yellow:`COLLECTION G` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -780,9 +720,6 @@ Build set: :yellow:`COLLECTION G` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P045_page`","P045" @@ -1027,21 +964,16 @@ Build set: :yellow:`ENERGY` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" @@ -1057,9 +989,6 @@ Build set: :yellow:`ENERGY` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P049_page`","P049" @@ -1112,9 +1041,6 @@ Build set: :yellow:`IR` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" @@ -1122,17 +1048,14 @@ Build set: :yellow:`IR` ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" ":ref:`P016_page`","P016" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -1144,9 +1067,6 @@ Build set: :yellow:`IR` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P049_page`","P049" @@ -1187,26 +1107,20 @@ Build set: :yellow:`IRext` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -1217,9 +1131,6 @@ Build set: :yellow:`IRext` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" - ":ref:`P041_page`","P041" - ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" ":ref:`P044_page`","P044" ":ref:`P049_page`","P049" @@ -1261,26 +1172,20 @@ Build set: :yellow:`NEOPIXEL` ":ref:`P004_page`","P004" ":ref:`P005_page`","P005" ":ref:`P006_page`","P006" - ":ref:`P007_page`","P007" - ":ref:`P008_page`","P008" - ":ref:`P009_page`","P009" ":ref:`P010_page`","P010" ":ref:`P011_page`","P011" ":ref:`P012_page`","P012" ":ref:`P013_page`","P013" ":ref:`P014_page`","P014" ":ref:`P015_page`","P015" - ":ref:`P017_page`","P017" ":ref:`P018_page`","P018" ":ref:`P019_page`","P019" ":ref:`P020_page`","P020" ":ref:`P021_page`","P021" - ":ref:`P022_page`","P022" ":ref:`P023_page`","P023" ":ref:`P024_page`","P024" ":ref:`P025_page`","P025" ":ref:`P026_page`","P026" - ":ref:`P027_page`","P027" ":ref:`P028_page`","P028" ":ref:`P029_page`","P029" ":ref:`P031_page`","P031" @@ -1291,7 +1196,6 @@ Build set: :yellow:`NEOPIXEL` ":ref:`P037_page`","P037" ":ref:`P038_page`","P038" ":ref:`P039_page`","P039" - ":ref:`P040_page`","P040" ":ref:`P041_page`","P041" ":ref:`P042_page`","P042" ":ref:`P043_page`","P043" diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 1e3102f1b7..1c9f5c696a 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -10,6 +10,7 @@ // 1 - TM1637 -- 2 pins - 4 digits and dot on each digit (X.X.X.X.) // 2 - TM1637 -- 2 pins - 6 digits and dot on each digit (X.X.X.X.X.X.) // 3 - MAX7219/21 -- 3 pins - 8 digits and dot on each digit (X.X.X.X.X.X.X.X.) +// 4 - 74HC595 xDgt 3 pins - 2,2+2,3,3+2,2+3,4,6,3+3,8 digits and dot on each digit (X.X. .. X.X.X.X.X.X.X.X.) // // Plugin can be setup as: // - Manual -- display is manually updated sending commands @@ -39,34 +40,43 @@ // - "7output,<0-5> -- select display output mode, 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink",3:"Clock 12h - Blink",4:"Clock // 12h - No Blink",5:"Date" // -// History -// 2023-03-30, tonhuisman: Correct 7dtext on 6-digit TM1637 to also swap the dots when swapping the digits -// 2023-03-29, tonhuisman: Add option to suppress the leading zero on day and hour when < 10 -// Disable scrolling for content/commands that don't support that -// 2023-03-28, tonhuisman: Guard scrolling feature to only be used for 7dtext and 7dbin commands, and fix scrolling on 6-digit display -// Fix 7dbin command to also work correctly for TM1637 displays -// 2022-02-03, tonhuisman: Move P073_data_struct to PluginStruct directory, code optimizations, de-duplication -// 2021-10-06, tonhuisman: Store via commands changed output, font and brightness setting in settings variables, but not save them yet. -// 2021-10-05, tonhuisman: Add 7output command for changing the Display Output setting. Not saved, unless the save command is also sent. -// 2021-02-13, tonhuisman: Fixed self-introduced bug of conversion from MAX7219 to TM1637 bit mapping, removed now unused TM1637 character -// maps, moved some logging to DEBUG level -// 2021-01-30, tonhuisman: Added font support for 7Dgt (default), Siekoo, Siekoo with uppercase CHNORUX, dSEG7 fonts. Default/7Dgt comes -// with these special characters: " -^=/_ -// Siekoo comes _without_ AOU with umlauts and Eszett characters, has many extra special characters -// "%@.,;:+*#!?'\"<>\\()|", and optional uppercase "CHNORUX", -// "^" displays as degree symbol and "|" displays overscsore (top-line only). -// 'Merged' fontdata for TM1637 by converting the data for MAX7219 (bits 0-6 are swapped around), to save a little -// space and maintanance burden. -// Added 7dfont, command for changing the font dynamically runtime. NB: The numbers digits are equal for all -// fonts! -// Added Scroll Text option for scrolling texts longer then the display is wide -// Added 7dbin,[,...] for displaying binary formatted data bits clock-wise from left to right, dot, top, -// right 2x, bottom, left 2x, center), scroll-enabled -// 2021-01-10, tonhuisman: Added optional . as dot display (7dtext) -// Added 7ddt,, dual temperature display -// Added optional removal of degree symbol on temperature display -// Added optional right-shift of 7dt, on MAX7219 display (is normally shifted to left by 1 digit, so last -// digit is blank) + +/** History + * 2024-07-24 tonhuisman: Fixed the issue that most extended features where not included in the MAX or ESP32 builds + * 2024-07-20 tonhuisman: Implement 74HC595 7-segment displays (2, 2+2, 3, 2+3, 3+2, 4, 6, 3+3 and 8 digits) + * 2 and 3 digit display use sequential data, 4, 6 and 8 digit displays use multiplexing, requiring continuous + * refreshing of the display content. + * The 2 and 3 digit displays can be coupled (output to input) in sets of max. 2 (2+2, 2+3, 3+2, 3+3), and will be + * seen as a single display of 4, 5 or 6 digits. + * Multiplexed displays can _not_ be coupled, nor can the TM1637 or MAX7219 displays. + * 2023-03-30 tonhuisman: Correct 7dtext on 6-digit TM1637 to also swap the dots when swapping the digits + * 2023-03-29 tonhuisman: Add option to suppress the leading zero on day and hour when < 10 + * Disable scrolling for content/commands that don't support that + * 2023-03-28 tonhuisman: Guard scrolling feature to only be used for 7dtext and 7dbin commands, and fix scrolling on 6-digit display + * Fix 7dbin command to also work correctly for TM1637 displays + * 2022-02-03 tonhuisman: Move P073_data_struct to PluginStruct directory, code optimizations, de-duplication + * 2021-10-06 tonhuisman: Store via commands changed output, font and brightness setting in settings variables, but not save them yet. + * 2021-10-05 tonhuisman: Add 7output command for changing the Display Output setting. Not saved, unless the save command is also sent. + * 2021-02-13 tonhuisman: Fixed self-introduced bug of conversion from MAX7219 to TM1637 bit mapping, removed now unused TM1637 character + * maps, moved some logging to DEBUG level + * 2021-01-30 tonhuisman: Added font support for 7Dgt (default), Siekoo, Siekoo with uppercase CHNORUX, dSEG7 fonts. Default/7Dgt comes + * with these special characters: " -^=/_ + * Siekoo comes _without_ AOU with umlauts and Eszett characters, has many extra special characters + * "%@.,;:+*#!?'\"<>\\()|", and optional uppercase "CHNORUX", + * "^" displays as degree symbol and "|" displays overscsore (top-line only). + * 'Merged' fontdata for TM1637 by converting the data for MAX7219 (bits 0-6 are swapped around), to save a little + * space and maintanance burden. + * Added 7dfont, command for changing the font dynamically runtime. NB: The numbers digits are equal for all + * fonts! + * Added Scroll Text option for scrolling texts longer then the display is wide + * Added 7dbin,[,...] for displaying binary formatted data bits clock-wise from left to right, dot, top, + * right 2x, bottom, left 2x, center), scroll-enabled + * 2021-01-10 tonhuisman: Added optional . as dot display (7dtext) + * Added 7ddt,, dual temperature display + * Added optional removal of degree symbol on temperature display + * Added optional right-shift of 7dt, on MAX7219 display (is normally shifted to left by 1 digit, so last + * digit is blank) + */ # define PLUGIN_073 # define PLUGIN_ID_073 73 @@ -87,18 +97,19 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) switch (function) { case PLUGIN_DEVICE_ADD: { - Device[++deviceCount].Number = PLUGIN_ID_073; - Device[deviceCount].Type = DEVICE_TYPE_TRIPLE; - Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_NONE; - Device[deviceCount].Ports = 0; - Device[deviceCount].PullUpOption = false; - Device[deviceCount].InverseLogicOption = false; - Device[deviceCount].FormulaOption = false; - Device[deviceCount].ValueCount = 0; - Device[deviceCount].SendDataOption = false; - Device[deviceCount].TimerOption = false; - Device[deviceCount].TimerOptional = false; - Device[deviceCount].GlobalSyncOption = true; + Device[++deviceCount].Number = PLUGIN_ID_073; + Device[deviceCount].Type = DEVICE_TYPE_TRIPLE; + Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_NONE; + Device[deviceCount].Ports = 0; + Device[deviceCount].ValueCount = 0; + Device[deviceCount].GlobalSyncOption = true; + + // Device[deviceCount].PullUpOption = false; + // Device[deviceCount].InverseLogicOption = false; + // Device[deviceCount].FormulaOption = false; + // Device[deviceCount].SendDataOption = false; + // Device[deviceCount].TimerOption = false; + // Device[deviceCount].TimerOptional = false; break; } @@ -108,22 +119,48 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) break; } - # ifdef P073_SCROLL_TEXT + # if defined(P073_SCROLL_TEXT) || defined(P073_USE_74HC595) case PLUGIN_SET_DEFAULTS: { - PCONFIG(3) = 10; // Default 10 * 0.1 sec scroll speed + # ifdef P073_SCROLL_TEXT + P073_CFG_SCROLLSPEED = 10; // Default 10 * 0.1 sec scroll speed + # endif // ifdef P073_SCROLL_TEXT + # ifdef P073_USE_74HC595 + P073_CFG_DIGITS = 4; // Default number of digits + # endif // ifdef P073_USE_74HC595 break; } - # endif // P073_SCROLL_TEXT + # endif // if defined(P073_SCROLL_TEXT) || defined(P073_USE_74HC595) case PLUGIN_WEBFORM_LOAD: { addFormNote(F("TM1637: 1st=CLK-Pin, 2nd=DIO-Pin")); addFormNote(F("MAX7219: 1st=DIN-Pin, 2nd=CLK-Pin, 3rd=CS-Pin")); + # ifdef P073_USE_74HC595 + addFormNote(F("74HC595: 1st=SDI-Pin, 2nd=CLK-Pin, 3rd=LOAD-Pin")); + # endif // ifdef P073_USE_74HC595 { const __FlashStringHelper *displtype[] = { F("TM1637 - 4 digit (colon)"), F("TM1637 - 4 digit (dots)"), F("TM1637 - 6 digit"), - F("MAX7219 - 8 digit") }; - addFormSelector(F("Display Type"), F("displtype"), 4, displtype, nullptr, PCONFIG(0)); + F("MAX7219 - 8 digit"), + # ifdef P073_USE_74HC595 + F("74HC595 - 2..8 digit"), + # endif // ifdef P073_USE_74HC595 + }; + addFormSelector(F("Display Type"), F("displtype"), NR_ELEMENTS(displtype), displtype, nullptr, P073_CFG_DISPLAYTYPE); + } + # ifdef P073_USE_74HC595 + + if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { + if (0 == P073_CFG_DIGITS) { + P073_CFG_DIGITS = 4; + } + const __FlashStringHelper *digits[] = { F("2"), F("2+2"), F("3"), F("4"), F("3+2 / 2+3"), F("6"), F("3+3"), F("8") }; + const int digitsOptions[] = { 2, 1, 3, 4, 5, 6, 7, 8 }; + addFormSelector(F("Nr. of digits"), F("dgts"), NR_ELEMENTS(digitsOptions), digits, digitsOptions, P073_CFG_DIGITS); + } else + # endif // ifdef P073_USE_74HC595 + { + P073_CFG_DIGITS = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); } { const __FlashStringHelper *displout[] = { F("Manual"), @@ -132,10 +169,10 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) F("Clock 12h - Blink"), F("Clock 12h - No Blink"), F("Date") }; - addFormSelector(F("Display Output"), F("displout"), 6, displout, nullptr, PCONFIG(1)); + addFormSelector(F("Display Output"), F("displout"), 6, displout, nullptr, P073_CFG_OUTPUTTYPE); } - addFormNumericBox(F("Brightness"), F("brightness"), PCONFIG(2), 0, 15); + addFormNumericBox(F("Brightness"), F("brightness"), P073_CFG_BRIGHTNESS, 0, 15); addUnit(F("0..15")); # ifdef P073_EXTRA_FONTS @@ -144,37 +181,41 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) F("Siekoo"), F("Siekoo with uppercase 'CHNORUX'"), F("dSEG7") }; - addFormSelector(F("Font set"), F("fontset"), 4, fontset, nullptr, PCONFIG(4)); + addFormSelector(F("Font set"), F("fontset"), 4, fontset, nullptr, P073_CFG_FONTSET); addFormNote(F("Check documentation for examples of the font sets.")); } # endif // P073_EXTRA_FONTS addFormSubHeader(F("Options")); - addFormCheckBox(F("Text show periods as dot"), F("periods"), bitRead(PCONFIG_LONG(0), P073_OPTION_PERIOD)); + addFormCheckBox(F("Text show periods as dot"), F("periods"), bitRead(P073_CFG_FLAGS, P073_OPTION_PERIOD)); - addFormCheckBox(F("Hide ° for Temperatures"), F("hide_degree"), bitRead(PCONFIG_LONG(0), P073_OPTION_HIDEDEGREE)); + addFormCheckBox(F("Hide ° for Temperatures"), F("hide_degree"), bitRead(P073_CFG_FLAGS, P073_OPTION_HIDEDEGREE)); # ifdef P073_7DDT_COMMAND addFormNote(F("Commands 7dt,<temp> and 7ddt,<temp1>,<temp2>")); # else // ifdef P073_7DDT_COMMAND addFormNote(F("Command 7dt,<temp>")); # endif // P073_7DDT_COMMAND # ifdef P073_SUPPRESS_ZERO - addFormCheckBox(F("Suppress leading 0 on day/hour"), F("supp0"), bitRead(PCONFIG_LONG(0), P073_OPTION_SUPPRESS0)); + addFormCheckBox(F("Suppress leading 0 on day/hour"), F("supp0"), bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0)); # endif // ifdef P073_SUPPRESS_ZERO # ifdef P073_SCROLL_TEXT - addFormCheckBox(F("Scroll text > display width"), F("scroll_text"), bitRead(PCONFIG_LONG(0), P073_OPTION_SCROLLTEXT)); - addFormCheckBox(F("Scroll text in from right"), F("scroll_full"), bitRead(PCONFIG_LONG(0), P073_OPTION_SCROLLFULL)); + addFormCheckBox(F("Scroll text > display width"), F("scroll_text"), bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLTEXT)); + addFormCheckBox(F("Scroll text in from right"), F("scroll_full"), bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLFULL)); - if (PCONFIG(3) == 0) { PCONFIG(3) = 10; } - addFormNumericBox(F("Scroll speed (0.1 sec/step)"), F("scrollspeed"), PCONFIG(3), 1, 600); + if (P073_CFG_SCROLLSPEED == 0) { P073_CFG_SCROLLSPEED = 10; } + addFormNumericBox(F("Scroll speed (0.1 sec/step)"), F("scrollspeed"), P073_CFG_SCROLLSPEED, 1, 600); addUnit(F("1..600 = 0.1..60 sec/step")); # endif // P073_SCROLL_TEXT + # ifdef P073_USE_74HC595 + addFormSubHeader(F("Options for 8 digit displays (MAX7219/74HC595)")); + # else // ifdef P073_USE_74HC595 addFormSubHeader(F("Options for MAX7219 - 8 digit")); + # endif // ifdef P073_USE_74HC595 - bool bRightAlign = bitRead(PCONFIG_LONG(0), P073_OPTION_RIGHTALIGN); + bool bRightAlign = bitRead(P073_CFG_FLAGS, P073_OPTION_RIGHTALIGN); addFormCheckBox(F("Right-align Temperature (7dt)"), F("temp_rightalign"), bRightAlign); success = true; @@ -182,9 +223,9 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) } case PLUGIN_WEBFORM_SAVE: { - PCONFIG(0) = getFormItemInt(F("displtype")); - PCONFIG(1) = getFormItemInt(F("displout")); - PCONFIG(2) = getFormItemInt(F("brightness")); + P073_CFG_DISPLAYTYPE = getFormItemInt(F("displtype")); + P073_CFG_OUTPUTTYPE = getFormItemInt(F("displout")); + P073_CFG_BRIGHTNESS = getFormItemInt(F("brightness")); uint32_t lSettings = 0; bitWrite(lSettings, P073_OPTION_PERIOD, isFormItemChecked(F("periods"))); bitWrite(lSettings, P073_OPTION_HIDEDEGREE, isFormItemChecked(F("hide_degree"))); @@ -192,15 +233,21 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) # ifdef P073_SCROLL_TEXT bitWrite(lSettings, P073_OPTION_SCROLLTEXT, isFormItemChecked(F("scroll_text"))); bitWrite(lSettings, P073_OPTION_SCROLLFULL, isFormItemChecked(F("scroll_full"))); - PCONFIG(3) = getFormItemInt(F("scrollspeed")); + P073_CFG_SCROLLSPEED = getFormItemInt(F("scrollspeed")); # endif // P073_SCROLL_TEXT # ifdef P073_SUPPRESS_ZERO bitWrite(lSettings, P073_OPTION_SUPPRESS0, isFormItemChecked(F("supp0"))); # endif // ifdef P073_SUPPRESS_ZERO # ifdef P073_EXTRA_FONTS - PCONFIG(4) = getFormItemInt(F("fontset")); + P073_CFG_FONTSET = getFormItemInt(F("fontset")); # endif // P073_EXTRA_FONTS - PCONFIG_LONG(0) = lSettings; + # ifdef P073_USE_74HC595 + + if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { + P073_CFG_DIGITS = getFormItemInt(F("dgts")); + } + # endif // ifdef P073_USE_74HC595 + P073_CFG_FLAGS = lSettings; success = true; break; @@ -222,25 +269,36 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: { + case P073_TM1637_6DGT: tm1637_InitDisplay(CONFIG_PIN1, CONFIG_PIN2); - tm1637_SetPowerBrightness(CONFIG_PIN1, CONFIG_PIN2, PCONFIG(2) / 2, true); + tm1637_SetPowerBrightness(CONFIG_PIN1, CONFIG_PIN2, P073_CFG_BRIGHTNESS / 2, true); - if (PCONFIG(1) == P073_DISP_MANUAL) { + if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { tm1637_ClearDisplay(CONFIG_PIN1, CONFIG_PIN2); } break; - } - case P073_MAX7219_8DGT: { + case P073_MAX7219_8DGT: max7219_InitDisplay(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3); delay(10); // small poweroff/poweron delay - max7219_SetPowerBrightness(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3, PCONFIG(2), true); + max7219_SetPowerBrightness(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3, P073_CFG_BRIGHTNESS, true); - if (PCONFIG(1) == P073_DISP_MANUAL) { + if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { max7219_ClearDisplay(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3); } break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_InitDisplay(); + + if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { + P073_data->ClearBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + } + break; + # endif // ifdef P073_USE_74HC595 } success = true; } @@ -270,7 +328,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) if (P073_data->output == P073_DISP_DATE) { P073_data->FillBufferWithDate(true, 0, 0, 0, # ifdef P073_SUPPRESS_ZERO - bitRead(PCONFIG_LONG(0), P073_OPTION_SUPPRESS0) + bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) # else // ifdef P073_SUPPRESS_ZERO false # endif // ifdef P073_SUPPRESS_ZERO @@ -279,7 +337,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) P073_data->FillBufferWithTime(true, 0, 0, 0, !((P073_data->output == P073_DISP_CLOCK24BLNK) || (P073_data->output == P073_DISP_CLOCK24)), # ifdef P073_SUPPRESS_ZERO - bitRead(PCONFIG_LONG(0), P073_OPTION_SUPPRESS0) + bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) # else // ifdef P073_SUPPRESS_ZERO false # endif // ifdef P073_SUPPRESS_ZERO @@ -293,7 +351,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) break; } case P073_TM1637_6DGT: { - if (PCONFIG(1) == P073_DISP_DATE) { + if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { tm1637_ShowDate6(event); } else { tm1637_ShowTime6(event); @@ -301,7 +359,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) break; } case P073_MAX7219_8DGT: { - if (PCONFIG(1) == P073_DISP_DATE) { + if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { max7219_ShowDate(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); } else { @@ -310,6 +368,12 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) } break; } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: { + // + break; + } + # endif // ifdef P073_USE_74HC595 } break; } @@ -353,15 +417,45 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) P073_data->pin3); break; } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: { + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + } + # endif // ifdef P073_USE_74HC595 } + success = true; } break; } # endif // P073_SCROLL_TEXT + + # ifdef P073_USE_74HC595 + case PLUGIN_FIFTY_PER_SECOND: { + P073_data_struct *P073_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P073_data) { + success = P073_data->plugin_fifty_per_second(event); + } + break; + } + # endif // ifdef P073_USE_74HC595 } return success; } +uint8_t p073_getDefaultDigits(uint8_t displayType) { + const uint8_t digits[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 + + if (displayType < NR_ELEMENTS(digits)) { + return digits[displayType]; + } + return 0; +} + bool p073_plugin_write(struct EventStruct *event, const String & string) { P073_data_struct *P073_data = @@ -415,8 +509,8 @@ bool p073_plugin_write(struct EventStruct *event, return p073_plugin_write_7dbin(event, text); # endif // P073_7DBIN_COMMAND } else { - bool p073_validcmd = false; - bool p073_displayon = false; + bool success = false; + bool displayon = false; if (equals(cmd, F("7don"))) { # ifdef P073_SCROLL_TEXT @@ -425,8 +519,8 @@ bool p073_plugin_write(struct EventStruct *event, # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("7DGT : Display ON")); # endif // ifndef BUILD_NO_DEBUG - p073_displayon = true; - p073_validcmd = true; + displayon = true; + success = true; } else if (equals(cmd, F("7doff"))) { # ifdef P073_SCROLL_TEXT newScroll = currentScroll; // Restore state @@ -434,8 +528,8 @@ bool p073_plugin_write(struct EventStruct *event, # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("7DGT : Display OFF")); # endif // ifndef BUILD_NO_DEBUG - p073_displayon = false; - p073_validcmd = true; + displayon = false; + success = true; } else if (equals(cmd, F("7db"))) { # ifdef P073_SCROLL_TEXT newScroll = currentScroll; // Restore state @@ -449,9 +543,9 @@ bool p073_plugin_write(struct EventStruct *event, } # endif // ifndef BUILD_NO_DEBUG P073_data->brightness = event->Par1; - PCONFIG(2) = event->Par1; - p073_displayon = true; - p073_validcmd = true; + P073_CFG_BRIGHTNESS = event->Par1; + displayon = true; + success = true; } } else if (equals(cmd, F("7output"))) { if ((event->Par1 >= 0) && (event->Par1 < 6)) { // 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink", @@ -462,10 +556,10 @@ bool p073_plugin_write(struct EventStruct *event, addLog(LOG_LEVEL_INFO, concat(F("7DGT : Display output="), event->Par1)); } # endif // ifndef BUILD_NO_DEBUG - P073_data->output = event->Par1; - PCONFIG(1) = event->Par1; - p073_displayon = true; - p073_validcmd = true; + P073_data->output = event->Par1; + P073_CFG_OUTPUTTYPE = event->Par1; + displayon = true; + success = true; # ifdef P073_SCROLL_TEXT if (event->Par1 == 0) { newScroll = currentScroll; } // Restore state @@ -473,7 +567,7 @@ bool p073_plugin_write(struct EventStruct *event, } } - if (p073_validcmd) { + if (success) { # ifdef P073_SCROLL_TEXT P073_data->setScrollEnabled(newScroll); # endif // ifdef P073_SCROLL_TEXT @@ -482,25 +576,49 @@ bool p073_plugin_write(struct EventStruct *event, case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: case P073_TM1637_6DGT: - { tm1637_SetPowerBrightness(P073_data->pin1, P073_data->pin2, - P073_data->brightness / 2, p073_displayon); + P073_data->brightness / 2, displayon); break; - } case P073_MAX7219_8DGT: - { max7219_SetPowerBrightness(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, P073_data->brightness, - p073_displayon); + displayon); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + // 74HC595 don't have a brightness setting + break; + # endif // ifdef P073_USE_74HC595 } } - return p073_validcmd; + return success; } return false; } +void p073_GetDisplayLimits(struct EventStruct *event, int32_t& lLimit, int32_t& uLimit, int8_t offset = 0) { + uint8_t dgts = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); + + # ifdef P073_USE_74HC595 + + if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { + dgts = P073_CFG_DIGITS; + + if (1 == dgts) { + dgts = 4; // Special case + } else + if (7 == dgts) { + dgts = 6; // Special case + } + } + # endif // ifdef P073_USE_74HC595 + dgts -= offset; // Subtract an offset, used for extra symbol + lLimit = -pow10(dgts - 1); // Lowest value we can display - 1 + uLimit = pow10(dgts); // Highest value we can display + 1 + // TODO disable log + addLog(LOG_LEVEL_INFO, strformat(F("P073: limits: %d digits(%d), lower: %d, upper: %d"), dgts, offset, lLimit, uLimit)); +} + bool p073_plugin_write_7dn(struct EventStruct *event, const String & text) { P073_data_struct *P073_data = @@ -517,42 +635,40 @@ bool p073_plugin_write_7dn(struct EventStruct *event, } # endif // ifndef BUILD_NO_DEBUG + int32_t lLimit = 0; + int32_t uLimit = 0; + p073_GetDisplayLimits(event, lLimit, uLimit); + + if (!text.isEmpty()) { + if ((event->Par1 > lLimit) && (event->Par1 < uLimit)) { + P073_data->FillBufferWithNumber(text.c_str()); + } else { + P073_data->FillBufferWithDash(); + } + } + switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - { - if ((event->Par1 > -1000) && (event->Par1 < 10000)) { - P073_data->FillBufferWithNumber(text.c_str()); - } else { - P073_data->FillBufferWithDash(); - } tm1637_ShowBuffer(event, TM1637_4DIGIT, 8); break; - } case P073_TM1637_6DGT: - { - if ((event->Par1 > -100000) && (event->Par1 < 1000000)) { - P073_data->FillBufferWithNumber(text.c_str()); - } else { - P073_data->FillBufferWithDash(); - } tm1637_SwapDigitInBuffer(event, 2); // only needed for 6-digits displays tm1637_ShowBuffer(event, TM1637_6DIGIT, 8); break; - } case P073_MAX7219_8DGT: - { - if (!text.isEmpty()) { - if ((event->Par1 > -10000000) && (event->Par1 < 100000000)) { - P073_data->FillBufferWithNumber(text.c_str()); - } else { - P073_data->FillBufferWithDash(); - } - max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3); + max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, + P073_data->pin3); + break; + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); } break; - } + # endif // ifdef P073_USE_74HC595 } return true; } @@ -580,23 +696,35 @@ bool p073_plugin_write_7dt(struct EventStruct *event, } # endif // ifndef BUILD_NO_DEBUG + int32_t lLimit = 0; + int32_t uLimit = 0; + p073_GetDisplayLimits(event, lLimit, uLimit, P073_data->hideDegree ? 0 : 1); + float lLimitErr = lLimit + 0.1f; + float uLimitErr = uLimit - 1.0f; + float lLimitDec = lLimit / 10.0f; + float uLimitDec = uLimit / 10.0f; + + // TODO disable log + addLog(LOG_LEVEL_INFO, strformat(F("P073: 7dt: lErr: %.1f, uErr: %.1f, lDec: %.1f, uDec: %.1f"), + lLimitErr, uLimitErr, lLimitDec, uLimitDec)); + + if ((p073_temptemp > uLimitErr) || (p073_temptemp < lLimitErr)) { + P073_data->FillBufferWithDash(); + } else { + if ((p073_temptemp < uLimitDec) && (p073_temptemp > lLimitDec)) { + p073_temptemp = roundf(p073_temptemp * 10.0f); + p073_tempflagdot = true; + } + P073_data->FillBufferWithTemp(p073_temptemp); + } + switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: case P073_TM1637_6DGT: - { - if ((p073_temptemp > 999.0f) || (p073_temptemp < -99.9f)) { - P073_data->FillBufferWithDash(); - } else { - if ((p073_temptemp < 100.0f) && (p073_temptemp > -10.0f)) { - p073_temptemp = roundf(p073_temptemp * 10.0f); - p073_tempflagdot = true; - } - P073_data->FillBufferWithTemp(p073_temptemp); - if ((p073_temptemp == 0) && p073_tempflagdot) { - P073_data->showbuffer[5] = 0; - } + if ((p073_temptemp == 0) && p073_tempflagdot) { + P073_data->showbuffer[5] = 0; } if (P073_TM1637_6DGT == P073_data->displayModel) { @@ -605,12 +733,7 @@ bool p073_plugin_write_7dt(struct EventStruct *event, tm1637_ShowTimeTemp4(event, p073_tempflagdot, 4); } break; - } case P073_MAX7219_8DGT: - { - p073_temptemp = roundf(p073_temptemp * 10.0f); - P073_data->FillBufferWithTemp(p073_temptemp); - # ifdef P073_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -620,7 +743,15 @@ bool p073_plugin_write_7dt(struct EventStruct *event, max7219_ShowTemp(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, P073_data->hideDegree ? 6 : 5, -1); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + # endif // ifdef P073_USE_74HC595 } # ifdef P073_DEBUG P073_data->LogBufferContent(F("7dt")); @@ -651,7 +782,7 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Temperature 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); + addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Dual Temperature 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); } switch (P073_data->displayModel) { @@ -669,6 +800,7 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, break; } case P073_MAX7219_8DGT: + case P073_74HC595_2_8DGT: { uint8_t firstDot = -1; // No decimals is no dots uint8_t secondDot = -1; @@ -705,12 +837,23 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, P073_data->FillBufferWithDualTemp(p073_lefttemp, firstDecimals, p073_righttemp, secondDecimals); - bool alignSave = P073_data->rightAlignTempMAX7219; // Save setting - P073_data->rightAlignTempMAX7219 = true; + if (P073_MAX7219_8DGT == P073_data->displayModel) { + bool alignSave = P073_data->rightAlignTempMAX7219; // Save setting + P073_data->rightAlignTempMAX7219 = true; - max7219_ShowTemp(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, firstDot, secondDot); + max7219_ShowTemp(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, firstDot, secondDot); + + P073_data->rightAlignTempMAX7219 = alignSave; // Restore + # ifdef P073_USE_74HC595 + } else + if ((P073_74HC595_2_8DGT == P073_data->displayModel) && (P073_data->digits < 8)) { + P073_data->FillBufferWithDash(); - P073_data->rightAlignTempMAX7219 = alignSave; // Restore + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + # endif // ifdef P073_USE_74HC595 + } break; } @@ -740,7 +883,7 @@ bool p073_plugin_write_7dst(struct EventStruct *event) { P073_data->timesep = true; P073_data->FillBufferWithTime(false, event->Par1, event->Par2, event->Par3, false, # ifdef P073_SUPPRESS_ZERO - bitRead(PCONFIG_LONG(0), P073_OPTION_SUPPRESS0) + bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) # else // ifdef P073_SUPPRESS_ZERO false # endif // ifdef P073_SUPPRESS_ZERO @@ -749,20 +892,23 @@ bool p073_plugin_write_7dst(struct EventStruct *event) { switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - { tm1637_ShowTimeTemp4(event, P073_data->timesep, 0); break; - } case P073_TM1637_6DGT: - { tm1637_ShowTime6(event); break; - } case P073_MAX7219_8DGT: - { max7219_ShowTime(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, P073_data->timesep); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + # endif // ifdef P073_USE_74HC595 } return true; } @@ -780,7 +926,7 @@ bool p073_plugin_write_7dsd(struct EventStruct *event) { } P073_data->FillBufferWithDate(false, event->Par1, event->Par2, event->Par3, # ifdef P073_SUPPRESS_ZERO - bitRead(PCONFIG_LONG(0), P073_OPTION_SUPPRESS0) + bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) # else // ifdef P073_SUPPRESS_ZERO false # endif // ifdef P073_SUPPRESS_ZERO @@ -789,20 +935,23 @@ bool p073_plugin_write_7dsd(struct EventStruct *event) { switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - { tm1637_ShowTimeTemp4(event, P073_data->timesep, 0); break; - } case P073_TM1637_6DGT: - { tm1637_ShowDate6(event); break; - } case P073_MAX7219_8DGT: - { max7219_ShowDate(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + # endif // ifdef P073_USE_74HC595 } return true; } @@ -824,7 +973,7 @@ bool p073_plugin_write_7dtext(struct EventStruct *event, # endif // ifndef BUILD_NO_DEBUG # ifdef P073_SCROLL_TEXT P073_data->setTextToScroll(""); - uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel); + uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel, P073_data->digits); if (P073_data->isScrollEnabled() && (P073_data->getEffectiveTextLength(text) > bufLen)) { P073_data->setTextToScroll(text); @@ -836,22 +985,24 @@ bool p073_plugin_write_7dtext(struct EventStruct *event, switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - { tm1637_ShowBuffer(event, 0, 4); break; - } case P073_TM1637_6DGT: - { tm1637_SwapDigitInBuffer(event, 0); // only needed for 6-digits displays tm1637_ShowBuffer(event, 0, 6); break; - } case P073_MAX7219_8DGT: - { P073_data->dotpos = -1; // avoid to display the dot max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + # endif // ifdef P073_USE_74HC595 } } return true; @@ -868,8 +1019,8 @@ bool p073_plugin_write_7dfont(struct EventStruct *event, } if (!text.isEmpty()) { - String fontArg = parseString(text, 1); - int32_t fontNr = -1; + const String fontArg = parseString(text, 1); + int32_t fontNr = -1; if ((equals(fontArg, F("default"))) || (equals(fontArg, F("7dgt")))) { fontNr = 0; @@ -892,7 +1043,7 @@ bool p073_plugin_write_7dfont(struct EventStruct *event, if ((fontNr >= 0) && (fontNr <= 3)) { P073_data->fontset = fontNr; - PCONFIG(4) = fontNr; + P073_CFG_FONTSET = fontNr; return true; } } @@ -912,10 +1063,10 @@ bool p073_plugin_write_7dbin(struct EventStruct *event, } if (!text.isEmpty()) { - String data; + String data; int32_t byteValue{}; - int arg = 1; - String argValue = parseString(text, arg); + int arg = 1; + String argValue = parseString(text, arg); while (!argValue.isEmpty()) { if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { @@ -927,7 +1078,7 @@ bool p073_plugin_write_7dbin(struct EventStruct *event, argValue = parseString(text, arg); } # ifdef P073_SCROLL_TEXT - const uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel); + const uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel, P073_data->digits); # endif // P073_SCROLL_TEXT if (!data.isEmpty()) { @@ -944,22 +1095,25 @@ bool p073_plugin_write_7dbin(struct EventStruct *event, switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: - { tm1637_ShowBuffer(event, 0, 4); break; - } case P073_TM1637_6DGT: - { tm1637_SwapDigitInBuffer(event, 0); // only needed for 6-digits displays tm1637_ShowBuffer(event, 0, 6, true); break; - } case P073_MAX7219_8DGT: - { P073_data->dotpos = -1; // avoid to display the dot max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); break; - } + # ifdef P073_USE_74HC595 + case P073_74HC595_2_8DGT: + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } + break; + # endif // ifdef P073_USE_74HC595 } } return true; @@ -1068,7 +1222,7 @@ void tm1637_i2cWrite(uint8_t clk_pin, # endif // ifdef P073_DEBUG uint8_t i; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; ++i) { CLK_LOW(); if (bytetoprint & 0b00000001) { @@ -1118,8 +1272,6 @@ void tm1637_InitDisplay(uint8_t clk_pin, CLK_HIGH(); DIO_HIGH(); - // pinMode(dio_pin, INPUT_PULLUP); - // pinMode(clk_pin, OUTPUT); uint8_t bytesToPrint[1] = { 0 }; bytesToPrint[0] = 0x40; @@ -1232,23 +1384,10 @@ void tm1637_SwapDigitInBuffer(struct EventStruct *event, P073_data->showperiods[3 + startPos] = P073_data->showperiods[5 + startPos]; P073_data->showperiods[5 + startPos] = p073_per; - switch (P073_data->dotpos) { - case 2: { - P073_data->dotpos = 4; - break; - } - case 4: { - P073_data->dotpos = 2; - break; - } - case 5: { - P073_data->dotpos = 7; - break; - } - case 7: { - P073_data->dotpos = 5; - break; - } + if (P073_data->dotpos > -1) { + const uint8_t dotPositionSwap[] = { 0, 1, 4, 3, 2, 7, 6, 5, 8 }; + + P073_data->dotpos = dotPositionSwap[P073_data->dotpos]; } } @@ -1273,7 +1412,7 @@ void tm1637_ShowBuffer(struct EventStruct *event, uint8_t p073_datashowpos1; - for (int i = firstPos; i < lastPos; i++) { + for (int i = firstPos; i < lastPos; ++i) { if (useBinaryData) { bytesToPrint[length] = P073_data->showbuffer[i]; } else { @@ -1297,10 +1436,10 @@ void tm1637_ShowBuffer(struct EventStruct *event, # define OP_SHUTDOWN 12 # define OP_DISPLAYTEST 15 -void max7219_spiTransfer(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, +void max7219_spiTransfer(struct EventStruct *event, + uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, ESPEASY_VOLATILE(uint8_t) opcode, ESPEASY_VOLATILE(uint8_t) data) { P073_data_struct *P073_data = @@ -1349,7 +1488,7 @@ void max7219_SetDigit(struct EventStruct *event, # ifdef P073_EXTRA_FONTS - switch (PCONFIG(4)) { + switch (P073_CFG_FONTSET) { case 1: // Siekoo case 2: // Siekoo with uppercase CHNORUX p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); @@ -1358,11 +1497,10 @@ void max7219_SetDigit(struct EventStruct *event, p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); break; default: // Default fontset - # endif // P073_EXTRA_FONTS + p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); + } + # else // ifdef P073_EXTRA_FONTS p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - # ifdef P073_EXTRA_FONTS -} - # endif // P073_EXTRA_FONTS if (showdot) { @@ -1404,7 +1542,7 @@ void max7219_ShowTime(struct EventStruct *event, const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward - for (int8_t i = 5; i >= 0; i--) { + for (int8_t i = 5; i >= 0; --i) { max7219_SetDigit(event, din_pin, clk_pin, cs_pin, idx_list[i], P073_data->showbuffer[i], false); } @@ -1435,7 +1573,7 @@ void max7219_ShowTemp(struct EventStruct *event, const int alignRight = P073_data->rightAlignTempMAX7219 ? 0 : 1; - for (int i = alignRight; i < 8; i++) { + for (int i = alignRight; i < 8; ++i) { const int bufIndex = (7 + alignRight) - i; if (bufIndex < 8) { @@ -1459,7 +1597,7 @@ void max7219_ShowDate(struct EventStruct *event, const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; ++i) { max7219_SetDigit(event, din_pin, clk_pin, cs_pin, i, P073_data->showbuffer[7 - i], dotflags[7 - i]); diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 75771b3c31..8ff939fe75 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -8,23 +8,179 @@ void P073_data_struct::init(struct EventStruct *event) pin1 = CONFIG_PIN1; pin2 = CONFIG_PIN2; pin3 = CONFIG_PIN3; - displayModel = PCONFIG(0); - output = PCONFIG(1); - brightness = PCONFIG(2); - periods = bitRead(PCONFIG_LONG(0), P073_OPTION_PERIOD); - hideDegree = bitRead(PCONFIG_LONG(0), P073_OPTION_HIDEDEGREE); + displayModel = P073_CFG_DISPLAYTYPE; + output = P073_CFG_OUTPUTTYPE; + brightness = P073_CFG_BRIGHTNESS; + periods = bitRead(P073_CFG_FLAGS, P073_OPTION_PERIOD); + hideDegree = bitRead(P073_CFG_FLAGS, P073_OPTION_HIDEDEGREE); # ifdef P073_SCROLL_TEXT - txtScrolling = bitRead(PCONFIG_LONG(0), P073_OPTION_SCROLLTEXT); - scrollFull = bitRead(PCONFIG_LONG(0), P073_OPTION_SCROLLFULL); - setScrollSpeed(PCONFIG(3)); + txtScrolling = bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLTEXT); + scrollFull = bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLFULL); + setScrollSpeed(P073_CFG_SCROLLSPEED); # endif // P073_SCROLL_TEXT - rightAlignTempMAX7219 = bitRead(PCONFIG_LONG(0), P073_OPTION_RIGHTALIGN); + rightAlignTempMAX7219 = bitRead(P073_CFG_FLAGS, P073_OPTION_RIGHTALIGN); timesep = true; # ifdef P073_EXTRA_FONTS - fontset = PCONFIG(4); + fontset = P073_CFG_FONTSET; # endif // P073_EXTRA_FONTS + digits = P073_CFG_DIGITS; + # ifdef P073_USE_74HC595 + + if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits))) { + isSequential = true; + + if (1 == digits) { // 2+2 + digits = 4; + } else + if (7 == digits) { // 3+3 + digits = 6; + } + } + # endif // ifdef P073_USE_74HC595 + + if ((digits > 0) && (digits < 4)) { + hideDegree = true; // Hide degree symbol on small displays + } } +# ifdef P073_USE_74HC595 +bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { + # ifdef P073_DEBUG + counter50++; + # endif // ifdef P073_DEBUG + + if (P073_74HC595_2_8DGT == displayModel) { + if (P073_HC595_MULTIPLEX) { + hc595_ShowBuffer(); + } + return true; + } + return false; +} + +// ==================================== +// ---- 74HC595 specific functions ---- +// ==================================== + +void P073_data_struct::hc595_ShowBuffer() { + const uint8_t hc595digit4[] = { + 0b00001000, // left segment + 0b00000100, + 0b00000010, + 0b00000001, // right segment + }; + const uint8_t hc595digit6[] = { + 0b00010000, // left segment + 0b00100000, + 0b01000000, + 0b00000001, + 0b00000010, + 0b00000100, // right segment + }; + const uint8_t hc595digit8[] = { + 0b00010000, // left segment + 0b00100000, + 0b01000000, + 0b10000000, + 0b00000001, + 0b00000010, + 0b00000100, + 0b00001000, // right segment + }; + + int8_t i = 0; + int8_t stop = digits; + int8_t incr = 1; + int8_t trgr = digits - 1; + + if (P073_HC595_SEQUENTIAL) { + i = digits - 1; + stop = -1; + incr = -1; + trgr = 0; + } + + int8_t oi = i; + + for (; i != stop && i >= 0; i += incr) { + uint8_t value; + uint8_t digit = 0xFF; + # ifdef P073_EXTRA_FONTS + + // 74HC595 uses inverted data, compared to MAX7219/TM1637 + switch (fontset) { + case 1: // Siekoo + case 2: // Siekoo with uppercase CHNORUX + value = ~pgm_read_byte(&(SiekooCharTable[showbuffer[i]])); + break; + case 3: // dSEG7 + value = ~pgm_read_byte(&(Dseg7CharTable[showbuffer[i]])); + break; + default: // Default fontset + value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); + } + # else // ifdef P073_EXTRA_FONTS + value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); + # endif // P073_EXTRA_FONTS + + if (showperiods[i]) { + value &= 0x7F; + } + value = mapMAX7219FontToTM1673Font(value); // Revert bits 6..0 + + shiftOut(pin1, pin2, MSBFIRST, value); // Digit data out + + // 2 and 3 digit modules use sequential digit values (in reversed order) + // 4, 6 and 8 digit modules use multiplexing in LTR order + if (4 == digits) { + digit = hc595digit4[i]; + } else + if ((6 == digits) && !isSequential) { + digit = hc595digit6[i]; + } else + if (8 == digits) { + digit = hc595digit8[i]; + } + + if (digit != 0xFF) { // Select multiplexer digit, 0xFF is invalid + shiftOut(pin1, pin2, MSBFIRST, digit); + } + + if ((P073_HC595_SEQUENTIAL && (i == trgr)) || P073_HC595_MULTIPLEX) { + digitalWrite(pin3, LOW); // Clock data + delay(1); + digitalWrite(pin3, HIGH); + } + } + + # ifdef P073_DEBUG + + if ((counter50 % 100 == 0) || P073_HC595_SEQUENTIAL) { + addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d oi:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), + digits, oi, i, stop, incr, pin1, pin2, pin3)); + } + # endif // ifdef P073_DEBUG +} + +void P073_data_struct::hc595_AdjustBuffer() { + if (digits < 8) { + const uint8_t delta = 8 - digits; + + for (uint8_t i = 0; i < digits; ++i) { + showbuffer[i] = showbuffer[i + delta]; + } + } +} + +void P073_data_struct::hc595_InitDisplay() { + pinMode(pin1, OUTPUT); + pinMode(pin2, OUTPUT); + pinMode(pin3, OUTPUT); + digitalWrite(pin3, HIGH); +} + +# endif // ifdef P073_USE_74HC595 + void P073_data_struct::FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, uint8_t sevendgt_minutes, @@ -115,10 +271,9 @@ void P073_data_struct::FillBufferWithNumber(const String& number) { void P073_data_struct::FillBufferWithTemp(long temperature) { ClearBuffer(); char p073_digit[8]; - bool between10and0 = ((temperature < 10) && (temperature >= 0)); // To have a zero prefix (0.x and -0.x) display between 0.9 and - // -0.9 - bool between0andMinus10 = ((temperature < 0) && (temperature > -10)); // degrees,as all display types use 1 digit for temperatures - // between 10.0 and -10.0 + const bool between10and0 = ((temperature < 10) && (temperature >= 0)); // To have a zero prefix (0.x and -0.x) display between 0.9 + const bool between0andMinus10 = ((temperature < 0) && (temperature > -10)); // and -0.9 degrees,as all display types use 1 digit for + // temperatures between 10.0 and -10.0 String format; if (hideDegree) { @@ -129,7 +284,7 @@ void P073_data_struct::FillBufferWithTemp(long temperature) { sprintf_P(p073_digit, format.c_str(), static_cast(temperature)); int p073_numlenght = strlen(p073_digit); - for (int i = 0; i < p073_numlenght; i++) { + for (int i = 0; i < p073_numlenght; ++i) { showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); } @@ -151,11 +306,11 @@ void P073_data_struct::FillBufferWithDualTemp(long leftTemperature, ClearBuffer(); char p073_digit[8]; String format; - bool leftBetween10and0 = (leftWithDecimal && (leftTemperature < 10) && (leftTemperature >= 0)); + const bool leftBetween10and0 = (leftWithDecimal && (leftTemperature < 10) && (leftTemperature >= 0)); // To have a zero prefix (0.x and -0.x) display between 0.9 and -0.9 degrees, // as all display types use 1 digit for temperatures between 10.0 and -10.0 - bool leftBetween0andMinus10 = (leftWithDecimal && (leftTemperature < 0) && (leftTemperature > -10)); + const bool leftBetween0andMinus10 = (leftWithDecimal && (leftTemperature < 0) && (leftTemperature > -10)); if (hideDegree) { // Include a space for compensation of the degree symbol @@ -168,7 +323,7 @@ void P073_data_struct::FillBufferWithDualTemp(long leftTemperature, // To have a zero prefix (0.x and -0.x) display between 0.9 and -0.9 degrees, // as all display types use 1 digit for temperatures between 10.0 and -10.0 - bool rightBetween0andMinus10 = (rightWithDecimal && (rightTemperature < 0) && (rightTemperature > -10)); + const bool rightBetween0andMinus10 = (rightWithDecimal && (rightTemperature < 0) && (rightTemperature > -10)); if (hideDegree) { format += (rightBetween10and0 ? F(" %02d") : (rightBetween0andMinus10 ? F(" %03d") : rightTemperature < -1000 ? F("----") : F("%4d"))); @@ -178,7 +333,7 @@ void P073_data_struct::FillBufferWithDualTemp(long leftTemperature, sprintf_P(p073_digit, format.c_str(), static_cast(leftTemperature), static_cast(rightTemperature)); const int p073_numlenght = strlen(p073_digit); - for (int i = 0; i < p073_numlenght; i++) { + for (int i = 0; i < p073_numlenght; ++i) { showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); } @@ -207,7 +362,7 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, int p = 0; - for (int i = 0; i < p073_txtlength && p <= 8; i++) { // p <= 8 to allow a period after last digit + for (int i = 0; i < p073_txtlength && p <= 8; ++i) { // p <= 8 to allow a period after last digit if (periods && textToShow.charAt(i) == '.' # ifdef P073_7DBIN_COMMAND @@ -244,20 +399,17 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, } # ifdef P073_SCROLL_TEXT -uint8_t P073_data_struct::getBufferLength(uint8_t displayModel) { - uint8_t bufLen = 0; +uint8_t P073_data_struct::getBufferLength(uint8_t displayModel, + uint8_t digits) { + const uint8_t digitsSet[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 + uint8_t bufLen = 0; - switch (displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - bufLen = 4; - break; - case P073_TM1637_6DGT: - bufLen = 6; - break; - case P073_MAX7219_8DGT: - bufLen = 8; - break; + if (displayModel < NR_ELEMENTS(digitsSet)) { + bufLen = digitsSet[displayModel]; + } + + if (P073_74HC595_2_8DGT == displayModel) { + bufLen = digits; } return bufLen; } @@ -266,7 +418,7 @@ int P073_data_struct::getEffectiveTextLength(const String& text) { const int textLength = text.length(); int p = 0; - for (int i = 0; i < textLength; i++) { + for (int i = 0; i < textLength; ++i) { if (periods && (text.charAt(i) == '.')) { // If setting periods true if (p == 0) { // Text starts with a period, becomes a space with a dot p++; @@ -291,13 +443,13 @@ bool P073_data_struct::NextScroll() { if (scrollCount == 0) { scrollCount = 0xFFFF; // Max value to avoid interference when scrolling long texts result = true; - const int bufToFill = getBufferLength(displayModel); + const int bufToFill = getBufferLength(displayModel, digits); const int p073_txtlength = _textToScroll.length(); ClearBuffer(); int p = 0; - for (int i = scrollPos; i < p073_txtlength && p <= bufToFill; i++) { // p <= bufToFill to allow a period after last digit + for (int i = scrollPos; i < p073_txtlength && p <= bufToFill; ++i) { // p <= bufToFill to allow a period after last digit if (periods && _textToScroll.charAt(i) == '.' # ifdef P073_7DBIN_COMMAND @@ -344,10 +496,10 @@ void P073_data_struct::setTextToScroll(const String& text) { _textToScroll = String(); if (!text.isEmpty()) { - const int bufToFill = getBufferLength(displayModel); + const int bufToFill = getBufferLength(displayModel, digits); _textToScroll.reserve(text.length() + bufToFill + (scrollFull ? bufToFill : 0)); - for (int i = 0; scrollFull && i < bufToFill; i++) { // Scroll text in from the right, so start with all spaces + for (int i = 0; scrollFull && i < bufToFill; ++i) { // Scroll text in from the right, so start with all spaces _textToScroll += # ifdef P073_7DBIN_COMMAND binaryData ? (char)0x00 : @@ -356,7 +508,7 @@ void P073_data_struct::setTextToScroll(const String& text) { } _textToScroll += text; - for (int i = 0; i < bufToFill; i++) { // Scroll text off completely before restarting + for (int i = 0; i < bufToFill; ++i) { // Scroll text off completely before restarting _textToScroll += # ifdef P073_7DBIN_COMMAND binaryData ? (char)0x00 : @@ -408,12 +560,9 @@ void P073_data_struct::LogBufferContent(String prefix) { if (loglevelActiveFor(LOG_LEVEL_INFO) && log.reserve(48)) { - log = prefix; - log += F(" buffer: periods: "); - log += periods ? 't' : 'f'; - log += ' '; + log = strformat(F("%s buffer: periods: %c "), prefix.c_str(), periods ? 't' : 'f'); - for (uint8_t i = 0; i < 8; i++) { + for (uint8_t i = 0; i < 8; ++i) { if (i > 0) { log += ','; } log += formatToHex(showbuffer[i]); log += ','; @@ -437,7 +586,7 @@ void P073_data_struct::ClearBuffer() { # endif // P073_7DBIN_COMMAND 10, sizeof(showbuffer)); - for (uint8_t i = 0; i < 8; i++) { + for (uint8_t i = 0; i < 8; ++i) { showperiods[i] = false; } } @@ -447,8 +596,8 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, uint8_t position = 10; # ifdef P073_EXTRA_FONTS - String specialChars = F(" -^=/_%@.,;:+*#!?'\"<>\\()|"); - String chnorux = F("CHNORUX"); + const String specialChars = F(" -^=/_%@.,;:+*#!?'\"<>\\()|"); + const String chnorux = F("CHNORUX"); switch (fontset) { case 1: // Siekoo @@ -461,7 +610,7 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, } else if (isAlpha(character)) { position = character - (isLowerCase(character) ? 'a' : 'A') + 42; } else { - int idx = specialChars.indexOf(character); + const int idx = specialChars.indexOf(character); if (idx > -1) { position = idx + 10; @@ -493,10 +642,14 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, return position; } +/** + * This function reverts the 7 databits/segmentbits so TM1637 and 74HC595 displays work with fonts designed for MAX7219. + * Dot/colon bit is still bit 8 + */ uint8_t P073_data_struct::mapMAX7219FontToTM1673Font(uint8_t character) { uint8_t newCharacter = character & 0x80; // Keep dot-bit if passed in - for (int b = 0; b < 7; b++) { + for (int b = 0; b < 7; ++b) { if (character & (0x01 << b)) { newCharacter |= (0x40 >> b); } @@ -509,18 +662,17 @@ uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, # ifdef P073_EXTRA_FONTS switch (fontset) { - case 1: // Siekoo - case 2: // Siekoo uppercase CHNORUX - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(SiekooCharTable[index]))); // SiekooTableTM1637[index]; - case 3: // dSEG7 - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(Dseg7CharTable[index]))); // Dseg7TableTM1637[index]; - default: // Standard fontset - # endif // P073_EXTRA_FONTS - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); // CharTableTM1637[index]; - # ifdef P073_EXTRA_FONTS -} // Out of wack because of the conditional compilation ifdef's - - # endif // P073_EXTRA_FONTS + case 1: // Siekoo + case 2: // Siekoo uppercase CHNORUX + return mapMAX7219FontToTM1673Font(pgm_read_byte(&(SiekooCharTable[index]))); + case 3: // dSEG7 + return mapMAX7219FontToTM1673Font(pgm_read_byte(&(Dseg7CharTable[index]))); + default: // Standard fontset + return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); + } + # else // ifdef P073_EXTRA_FONTS + return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); + # endif // ifdef P073_EXTRA_FONTS } #endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 868e43da11..622524e4a3 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -4,10 +4,19 @@ #include "../../_Plugin_Helper.h" #ifdef USES_P073 +# define P073_CFG_DISPLAYTYPE PCONFIG(0) +# define P073_CFG_OUTPUTTYPE PCONFIG(1) +# define P073_CFG_BRIGHTNESS PCONFIG(2) +# define P073_CFG_SCROLLSPEED PCONFIG(3) +# define P073_CFG_FONTSET PCONFIG(4) +# define P073_CFG_DIGITS PCONFIG(5) +# define P073_CFG_FLAGS PCONFIG_ULONG(0) + # define P073_TM1637_4DGTCOLON 0 # define P073_TM1637_4DGTDOTS 1 # define P073_TM1637_6DGT 2 # define P073_MAX7219_8DGT 3 +# define P073_74HC595_2_8DGT 4 # define P073_DISP_MANUAL 0 # define P073_DISP_CLOCK24BLNK 1 @@ -28,17 +37,19 @@ # define P073_SCROLL_TEXT // Enable scrolling of 7dtext by default # define P073_7DBIN_COMMAND // Enable input of binary data via 7dbin,uint8_t,... command # define P073_SUPPRESS_ZERO // Enable Suppress leading zero on day/hour +# define P073_USE_74HC595 // Enable support for 74HC595 based (sequential and multiplexing) displays -# ifndef PLUGIN_SET_COLLECTION +# if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) +# undef P073_7DDT_COMMAND // Optionally activate if .bin file space is problematic, remove the 7ddt command +# undef P073_EXTRA_FONTS // Optionally activate if .bin file space is problematic, remove the font selection and 7dfont command +# undef P073_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature +# undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command +# undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature +// # undef P073_USE_74HC595 // Optionally activate if .bin file space is problematic, remove the support for 74HC595 displays +# else // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) -// # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug -# else // ifndef PLUGIN_SET_COLLECTION -# undef P073_7DDT_COMMAND // Optionally activate if .bin file space is really problematic, to remove the 7ddt command -# undef P073_EXTRA_FONTS // Optionally activate if .bin file space is really problematic, to remove the font selection and 7dfont command -# undef P073_SCROLL_TEXT // Optionally activate if .bin file space is really problematic, to remove the scrolling text feature -# undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is really problematic, to remove the 7dbin command -# undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is really problematic, to remove the Suppress leading zero feature -# endif // ifndef PLUGIN_SET_COLLECTION +# define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug +# endif // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) # define TM1637_POWER_ON 0b10001000 # define TM1637_POWER_OFF 0b10000000 @@ -46,6 +57,9 @@ # define TM1637_4DIGIT 4 # define TM1637_6DIGIT 2 +# define P073_HC595_SEQUENTIAL (isSequential) // Sequential digits +# define P073_HC595_MULTIPLEX (!isSequential) // Multiplexed digits, have to be constantly refreshed + // each char table is specific for each display and maps all numbers/symbols // needed: // - pos 0-9 - Numbers from 0 to 9 @@ -147,6 +161,17 @@ struct P073_data_struct : public PluginTaskData_base { virtual ~P073_data_struct() = default; void init(struct EventStruct *event); + # ifdef P073_USE_74HC595 + bool plugin_fifty_per_second(struct EventStruct *event); + void hc595_ShowBuffer(); + void hc595_AdjustBuffer(); + bool hc595_Sequential() { + return P073_HC595_SEQUENTIAL; + } + + void hc595_InitDisplay(); + + # endif // ifdef P073_USE_74HC595 void FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, @@ -170,7 +195,8 @@ struct P073_data_struct : public PluginTaskData_base { void FillBufferWithString(const String& textToShow, bool useBinaryData = false); # ifdef P073_SCROLL_TEXT - uint8_t getBufferLength(uint8_t displayModel); + uint8_t getBufferLength(uint8_t displayModel, + uint8_t digits); int getEffectiveTextLength(const String& text); bool NextScroll(); void setTextToScroll(const String& text); @@ -203,6 +229,7 @@ struct P073_data_struct : public PluginTaskData_base { uint8_t displayModel = 0; uint8_t output = 0; uint8_t brightness = 0; + uint8_t digits = 4; bool timesep = false; bool shift = false; bool periods = false; @@ -225,7 +252,13 @@ struct P073_data_struct : public PluginTaskData_base { # endif // P073_SCROLL_TEXT # if defined(P073_SCROLL_TEXT) || defined(P073_7DBIN_COMMAND) String _textToScroll; - # endif // P073_SCROLL_TEXT + # endif // if defined(P073_SCROLL_TEXT) || defined(P073_7DBIN_COMMAND) + # ifdef P073_DEBUG + uint32_t counter50 = 0; + # endif // ifdef P073_DEBUG + # ifdef P073_USE_74HC595 + bool isSequential = false; + # endif // ifdef P073_USE_74HC595 }; #endif // ifdef USES_P073 From 06c09b369dd7711d1f6f68dd5bfbc03a385f99ff Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 26 Jul 2024 23:29:45 +0200 Subject: [PATCH 02/21] [P073] Disable debug log --- src/src/PluginStructs/P073_data_struct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 622524e4a3..d113487820 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -45,10 +45,10 @@ # undef P073_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature # undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command # undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature -// # undef P073_USE_74HC595 // Optionally activate if .bin file space is problematic, remove the support for 74HC595 displays +# undef P073_USE_74HC595 // Optionally activate if .bin file space is problematic, remove the support for 74HC595 displays # else // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) -# define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug +// # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug # endif // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) # define TM1637_POWER_ON 0b10001000 From ee029cbd419904a8f46a314bb814c06f7e9506a5 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 27 Jul 2024 16:42:41 +0200 Subject: [PATCH 03/21] [P073] Make build fit again (part 1) --- src/_P073_7DGT.ino | 152 +++++++++------------ src/src/PluginStructs/P073_data_struct.cpp | 116 +++++++++------- src/src/PluginStructs/P073_data_struct.h | 23 +++- 3 files changed, 147 insertions(+), 144 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 1c9f5c696a..b2a6cb5232 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -104,13 +104,6 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].ValueCount = 0; Device[deviceCount].GlobalSyncOption = true; - // Device[deviceCount].PullUpOption = false; - // Device[deviceCount].InverseLogicOption = false; - // Device[deviceCount].FormulaOption = false; - // Device[deviceCount].SendDataOption = false; - // Device[deviceCount].TimerOption = false; - // Device[deviceCount].TimerOptional = false; - break; } @@ -370,7 +363,11 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) } # ifdef P073_USE_74HC595 case P073_74HC595_2_8DGT: { - // + P073_data->hc595_AdjustBuffer(); + + if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing + P073_data->hc595_ShowBuffer(); + } break; } # endif // ifdef P073_USE_74HC595 @@ -447,15 +444,6 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) return success; } -uint8_t p073_getDefaultDigits(uint8_t displayType) { - const uint8_t digits[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 - - if (displayType < NR_ELEMENTS(digits)) { - return digits[displayType]; - } - return 0; -} - bool p073_plugin_write(struct EventStruct *event, const String & string) { P073_data_struct *P073_data = @@ -596,27 +584,20 @@ bool p073_plugin_write(struct EventStruct *event, return false; } -void p073_GetDisplayLimits(struct EventStruct *event, int32_t& lLimit, int32_t& uLimit, int8_t offset = 0) { +void p073_GetDisplayLimits(struct EventStruct *event, int32_t& lLimit, int32_t& uLimit, int8_t offset = 0, uint8_t digits = 0) { uint8_t dgts = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); # ifdef P073_USE_74HC595 if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { - dgts = P073_CFG_DIGITS; - - if (1 == dgts) { - dgts = 4; // Special case - } else - if (7 == dgts) { - dgts = 6; // Special case - } + dgts = digits; } # endif // ifdef P073_USE_74HC595 dgts -= offset; // Subtract an offset, used for extra symbol lLimit = -pow10(dgts - 1); // Lowest value we can display - 1 uLimit = pow10(dgts); // Highest value we can display + 1 // TODO disable log - addLog(LOG_LEVEL_INFO, strformat(F("P073: limits: %d digits(%d), lower: %d, upper: %d"), dgts, offset, lLimit, uLimit)); + // addLog(LOG_LEVEL_INFO, strformat(F("P073: limits: %d digits(%d), lower: %d, upper: %d"), dgts, offset, lLimit, uLimit)); } bool p073_plugin_write_7dn(struct EventStruct *event, @@ -637,7 +618,7 @@ bool p073_plugin_write_7dn(struct EventStruct *event, int32_t lLimit = 0; int32_t uLimit = 0; - p073_GetDisplayLimits(event, lLimit, uLimit); + p073_GetDisplayLimits(event, lLimit, uLimit, 0, P073_data->digits); if (!text.isEmpty()) { if ((event->Par1 > lLimit) && (event->Par1 < uLimit)) { @@ -698,15 +679,15 @@ bool p073_plugin_write_7dt(struct EventStruct *event, int32_t lLimit = 0; int32_t uLimit = 0; - p073_GetDisplayLimits(event, lLimit, uLimit, P073_data->hideDegree ? 0 : 1); + p073_GetDisplayLimits(event, lLimit, uLimit, P073_data->hideDegree ? 0 : 1, P073_data->digits); float lLimitErr = lLimit + 0.1f; float uLimitErr = uLimit - 1.0f; float lLimitDec = lLimit / 10.0f; float uLimitDec = uLimit / 10.0f; // TODO disable log - addLog(LOG_LEVEL_INFO, strformat(F("P073: 7dt: lErr: %.1f, uErr: %.1f, lDec: %.1f, uDec: %.1f"), - lLimitErr, uLimitErr, lLimitDec, uLimitDec)); + // addLog(LOG_LEVEL_INFO, strformat(F("P073: 7dt: lErr: %.1f, uErr: %.1f, lDec: %.1f, uDec: %.1f"), + // lLimitErr, uLimitErr, lLimitDec, uLimitDec)); if ((p073_temptemp > uLimitErr) || (p073_temptemp < lLimitErr)) { P073_data->FillBufferWithDash(); @@ -781,9 +762,12 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, } } + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Dual Temperature 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); } + # endif // ifndef BUILD_NO_DEBUG switch (P073_data->displayModel) { case P073_TM1637_4DGTCOLON: @@ -802,11 +786,9 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, case P073_MAX7219_8DGT: case P073_74HC595_2_8DGT: { - uint8_t firstDot = -1; // No decimals is no dots - uint8_t secondDot = -1; - float hideFactor = P073_data->hideDegree ? 10.0f : 1.0f; - bool firstDecimals = false; - bool secondDecimals = false; + uint8_t firstDot = -1; // No decimals is no dots + uint8_t secondDot = -1; + float hideFactor = P073_data->hideDegree ? 10.0f : 1.0f; if ((p073_lefttemp > 999.99f * hideFactor) || (p073_lefttemp < -99.99f * hideFactor)) { p073_lefttemp = -101.0f * hideFactor; // Triggers on -100 @@ -814,7 +796,6 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, if ((p073_lefttemp < 100.0f * hideFactor) && (p073_lefttemp > -10.0f * hideFactor)) { p073_lefttemp = roundf(p073_lefttemp * 10.0f); firstDot = P073_data->hideDegree ? 2 : 1; - firstDecimals = true; } } @@ -824,7 +805,6 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, if ((p073_righttemp < 100.0f * hideFactor) && (p073_righttemp > -10.0f * hideFactor)) { p073_righttemp = roundf(p073_righttemp * 10.0f); secondDot = P073_data->hideDegree ? 6 : 5; - secondDecimals = true; } } @@ -835,7 +815,7 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, } # endif // ifdef P073_DEBUG - P073_data->FillBufferWithDualTemp(p073_lefttemp, firstDecimals, p073_righttemp, secondDecimals); + P073_data->FillBufferWithDualTemp(p073_lefttemp, firstDot > -1, p073_righttemp, secondDot > -1); if (P073_MAX7219_8DGT == P073_data->displayModel) { bool alignSave = P073_data->rightAlignTempMAX7219; // Save setting @@ -846,8 +826,12 @@ bool p073_plugin_write_7ddt(struct EventStruct *event, P073_data->rightAlignTempMAX7219 = alignSave; // Restore # ifdef P073_USE_74HC595 } else - if ((P073_74HC595_2_8DGT == P073_data->displayModel) && (P073_data->digits < 8)) { - P073_data->FillBufferWithDash(); + + // if (P073_74HC595_2_8DGT == P073_data->displayModel) + { + if (P073_data->digits < 8) { + P073_data->FillBufferWithDash(); + } if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing P073_data->hc595_ShowBuffer(); @@ -921,9 +905,12 @@ bool p073_plugin_write_7dsd(struct EventStruct *event) { return false; } + # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Date=%02d:%02d:%02d"), event->Par1, event->Par2, event->Par3)); } + # endif // ifndef BUILD_NO_DEBUG P073_data->FillBufferWithDate(false, event->Par1, event->Par2, event->Par3, # ifdef P073_SUPPRESS_ZERO bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) @@ -972,8 +959,8 @@ bool p073_plugin_write_7dtext(struct EventStruct *event, } # endif // ifndef BUILD_NO_DEBUG # ifdef P073_SCROLL_TEXT - P073_data->setTextToScroll(""); - uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel, P073_data->digits); + P073_data->setTextToScroll(EMPTY_STRING); + uint8_t bufLen = p073_getDefaultDigits(P073_data->displayModel, P073_data->digits); if (P073_data->isScrollEnabled() && (P073_data->getEffectiveTextLength(text) > bufLen)) { P073_data->setTextToScroll(text); @@ -1078,7 +1065,7 @@ bool p073_plugin_write_7dbin(struct EventStruct *event, argValue = parseString(text, arg); } # ifdef P073_SCROLL_TEXT - const uint8_t bufLen = P073_data->getBufferLength(P073_data->displayModel, P073_data->digits); + const uint8_t bufLen = p073_getDefaultDigits(P073_data->displayModel, P073_data->digits); # endif // P073_SCROLL_TEXT if (!data.isEmpty()) { @@ -1107,7 +1094,6 @@ bool p073_plugin_write_7dbin(struct EventStruct *event, break; # ifdef P073_USE_74HC595 case P073_74HC595_2_8DGT: - P073_data->hc595_AdjustBuffer(); if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing P073_data->hc595_ShowBuffer(); @@ -1239,7 +1225,7 @@ void tm1637_i2cWrite(uint8_t clk_pin, void tm1637_ClearDisplay(uint8_t clk_pin, uint8_t dio_pin) { - uint8_t bytesToPrint[7] = { 0 }; + uint8_t bytesToPrint[7]{}; bytesToPrint[0] = 0xC0; tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 7); @@ -1260,7 +1246,7 @@ void tm1637_SetPowerBrightness(uint8_t clk_pin, brightvalue = TM1637_POWER_OFF | brightvalue; } - uint8_t bytesToPrint[1] = { 0 }; + uint8_t bytesToPrint[1]{}; bytesToPrint[0] = brightvalue; tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 1); } @@ -1272,7 +1258,7 @@ void tm1637_InitDisplay(uint8_t clk_pin, CLK_HIGH(); DIO_HIGH(); - uint8_t bytesToPrint[1] = { 0 }; + uint8_t bytesToPrint[1]{}; bytesToPrint[0] = 0x40; tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 1); @@ -1298,7 +1284,7 @@ void tm1637_ShowDate6(struct EventStruct *event, bool showTime) { if (nullptr == P073_data) { return; } - uint8_t bytesToPrint[7] = { 0 }; + uint8_t bytesToPrint[7]{}; bytesToPrint[0] = 0xC0; bytesToPrint[1] = P073_data->tm1637_getFontChar(P073_data->showbuffer[2], P073_data->fontset); @@ -1325,7 +1311,7 @@ void tm1637_ShowTemp6(struct EventStruct *event, if (nullptr == P073_data) { return; } - uint8_t bytesToPrint[7] = { 0 }; + uint8_t bytesToPrint[7]{}; bytesToPrint[0] = 0xC0; bytesToPrint[1] = tm1637_separator(P073_data->tm1637_getFontChar(P073_data->showbuffer[5], P073_data->fontset), sep); @@ -1347,7 +1333,7 @@ void tm1637_ShowTimeTemp4(struct EventStruct *event, if (nullptr == P073_data) { return; } - uint8_t bytesToPrint[7] = { 0 }; + uint8_t bytesToPrint[5]{}; bytesToPrint[0] = 0xC0; bytesToPrint[1] = P073_data->tm1637_getFontChar(P073_data->showbuffer[0 + bufoffset], P073_data->fontset); @@ -1366,23 +1352,12 @@ void tm1637_SwapDigitInBuffer(struct EventStruct *event, if (nullptr == P073_data) { return; } - uint8_t p073_tmp; // Swap digits - - p073_tmp = P073_data->showbuffer[2 + startPos]; - P073_data->showbuffer[2 + startPos] = P073_data->showbuffer[0 + startPos]; - P073_data->showbuffer[0 + startPos] = p073_tmp; - p073_tmp = P073_data->showbuffer[3 + startPos]; - P073_data->showbuffer[3 + startPos] = P073_data->showbuffer[5 + startPos]; - P073_data->showbuffer[5 + startPos] = p073_tmp; - bool p073_per; // Swap periods + std::swap(P073_data->showbuffer[2 + startPos], P073_data->showbuffer[0 + startPos]); + std::swap(P073_data->showbuffer[3 + startPos], P073_data->showbuffer[5 + startPos]); - p073_per = P073_data->showperiods[2 + startPos]; - P073_data->showperiods[2 + startPos] = P073_data->showperiods[0 + startPos]; - P073_data->showperiods[0 + startPos] = p073_per; - p073_per = P073_data->showperiods[3 + startPos]; - P073_data->showperiods[3 + startPos] = P073_data->showperiods[5 + startPos]; - P073_data->showperiods[5 + startPos] = p073_per; + std::swap(P073_data->showperiods[2 + startPos], P073_data->showperiods[0 + startPos]); + std::swap(P073_data->showperiods[3 + startPos], P073_data->showperiods[5 + startPos]); if (P073_data->dotpos > -1) { const uint8_t dotPositionSwap[] = { 0, 1, 4, 3, 2, 7, 6, 5, 8 }; @@ -1401,7 +1376,7 @@ void tm1637_ShowBuffer(struct EventStruct *event, if (nullptr == P073_data) { return; } - uint8_t bytesToPrint[8] = { 0 }; + uint8_t bytesToPrint[8]{}; bytesToPrint[0] = 0xC0; uint8_t length = 1; @@ -1486,29 +1461,30 @@ void max7219_SetDigit(struct EventStruct *event, bool binaryData = false) { uint8_t p073_tempvalue; - # ifdef P073_EXTRA_FONTS - - switch (P073_CFG_FONTSET) { - case 1: // Siekoo - case 2: // Siekoo with uppercase CHNORUX - p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); - break; - case 3: // dSEG7 - p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); - break; - default: // Default fontset - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - } - # else // ifdef P073_EXTRA_FONTS - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - # endif // P073_EXTRA_FONTS - - if (showdot) { - p073_tempvalue |= 0b10000000; - } - if (binaryData) { p073_tempvalue = dgtvalue; // Overwrite if binary data + } else + { + # ifdef P073_EXTRA_FONTS + + switch (P073_CFG_FONTSET) { + case 1: // Siekoo + case 2: // Siekoo with uppercase CHNORUX + p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); + break; + case 3: // dSEG7 + p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); + break; + default: // Default fontset + p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); + } + # else // ifdef P073_EXTRA_FONTS + p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); + # endif // P073_EXTRA_FONTS + + if (showdot) { + p073_tempvalue |= 0b10000000; + } } max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, dgtpos + 1, p073_tempvalue); } diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 8ff939fe75..e844e29617 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -2,6 +2,24 @@ #ifdef USES_P073 +uint8_t p073_getDefaultDigits(uint8_t displayModel, + uint8_t digits) { + const uint8_t digitsSet[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 + uint8_t bufLen{}; + + if (displayModel < NR_ELEMENTS(digitsSet)) { + bufLen = digitsSet[displayModel]; + } + # ifdef P073_USE_74HC595 + + if (P073_74HC595_2_8DGT == displayModel) { + bufLen = digits; + } + # endif // ifdef P073_USE_74HC595 + + return bufLen; +} + void P073_data_struct::init(struct EventStruct *event) { ClearBuffer(); @@ -100,7 +118,9 @@ void P073_data_struct::hc595_ShowBuffer() { trgr = 0; } - int8_t oi = i; + # ifdef P073_DEBUG + const int8_t oi = i; + # endif // ifdef P073_DEBUG for (; i != stop && i >= 0; i += incr) { uint8_t value; @@ -155,10 +175,10 @@ void P073_data_struct::hc595_ShowBuffer() { # ifdef P073_DEBUG - if ((counter50 % 100 == 0) || P073_HC595_SEQUENTIAL) { - addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d oi:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), - digits, oi, i, stop, incr, pin1, pin2, pin3)); - } + // if ((counter50 % 100 == 0) || P073_HC595_SEQUENTIAL) { + // addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d oi:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), + // digits, oi, i, stop, incr, pin1, pin2, pin3)); + // } # endif // ifdef P073_DEBUG } @@ -202,16 +222,11 @@ void P073_data_struct::FillBufferWithTime(bool sevendgt_now, if (flag12h && (sevendgt_hours == 0)) { sevendgt_hours = 12; // if flag 12h is TRUE and h=0 adjust to h=12 } - showbuffer[0] = static_cast(sevendgt_hours / 10); - showbuffer[1] = sevendgt_hours % 10; - showbuffer[2] = static_cast(sevendgt_minutes / 10); - showbuffer[3] = sevendgt_minutes % 10; - showbuffer[4] = static_cast(sevendgt_seconds / 10); - showbuffer[5] = sevendgt_seconds % 10; - # ifdef P073_SUPPRESS_ZERO - - if (suppressLeading0 && (showbuffer[0] == 0)) { showbuffer[0] = 10; } // set to space - # endif // ifdef P073_SUPPRESS_ZERO + Put4NumbersInBuffer(sevendgt_hours, sevendgt_minutes, sevendgt_seconds, -1 + # ifdef P073_SUPPRESS_ZERO + , suppressLeading0 + # endif // ifdef P073_SUPPRESS_ZERO + ); } void P073_data_struct::FillBufferWithDate(bool sevendgt_now, @@ -232,14 +247,32 @@ void P073_data_struct::FillBufferWithDate(bool sevendgt_now, const uint8_t sevendgt_year1 = static_cast(sevendgt_year0 / 100); const uint8_t sevendgt_year2 = static_cast(sevendgt_year0 % 100); - showbuffer[0] = static_cast(sevendgt_day / 10); - showbuffer[1] = sevendgt_day % 10; - showbuffer[2] = static_cast(sevendgt_month / 10); - showbuffer[3] = sevendgt_month % 10; - showbuffer[4] = static_cast(sevendgt_year1 / 10); - showbuffer[5] = sevendgt_year1 % 10; - showbuffer[6] = static_cast(sevendgt_year2 / 10); - showbuffer[7] = sevendgt_year2 % 10; + Put4NumbersInBuffer(sevendgt_day, sevendgt_month, sevendgt_year1, sevendgt_year2 + # ifdef P073_SUPPRESS_ZERO + , suppressLeading0 + # endif // ifdef P073_SUPPRESS_ZERO + ); +} + +void P073_data_struct::Put4NumbersInBuffer(const uint8_t nr1, + const uint8_t nr2, + const uint8_t nr3, + const int8_t nr4 + # ifdef P073_SUPPRESS_ZERO + , const bool suppressLeading0 + # endif // ifdef P073_SUPPRESS_ZERO + ) { + showbuffer[0] = static_cast(nr1 / 10); + showbuffer[1] = nr1 % 10; + showbuffer[2] = static_cast(nr2 / 10); + showbuffer[3] = nr2 % 10; + showbuffer[4] = static_cast(nr3 / 10); + showbuffer[5] = nr3 % 10; + + if (nr4 > -1) { + showbuffer[6] = static_cast(nr4 / 10); + showbuffer[7] = nr4 % 10; + } # ifdef P073_SUPPRESS_ZERO if (suppressLeading0 && (showbuffer[0] == 0)) { showbuffer[0] = 10; } // set to space @@ -268,7 +301,7 @@ void P073_data_struct::FillBufferWithNumber(const String& number) { } } -void P073_data_struct::FillBufferWithTemp(long temperature) { +void P073_data_struct::FillBufferWithTemp(int temperature) { ClearBuffer(); char p073_digit[8]; const bool between10and0 = ((temperature < 10) && (temperature >= 0)); // To have a zero prefix (0.x and -0.x) display between 0.9 @@ -281,10 +314,10 @@ void P073_data_struct::FillBufferWithTemp(long temperature) { } else { format = (between10and0 ? F(" %02d") : (between0andMinus10 ? F(" %03d") : F("%7d"))); } - sprintf_P(p073_digit, format.c_str(), static_cast(temperature)); - int p073_numlenght = strlen(p073_digit); + sprintf_P(p073_digit, format.c_str(), temperature); + const size_t p073_numlenght = strlen(p073_digit); - for (int i = 0; i < p073_numlenght; ++i) { + for (size_t i = 0; i < p073_numlenght; ++i) { showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); } @@ -299,9 +332,9 @@ void P073_data_struct::FillBufferWithTemp(long temperature) { * FillBufferWithDualTemp() * leftTemperature or rightTempareature < -100.0 then shows dashes */ -void P073_data_struct::FillBufferWithDualTemp(long leftTemperature, +void P073_data_struct::FillBufferWithDualTemp(int leftTemperature, bool leftWithDecimal, - long rightTemperature, + int rightTemperature, bool rightWithDecimal) { ClearBuffer(); char p073_digit[8]; @@ -330,10 +363,10 @@ void P073_data_struct::FillBufferWithDualTemp(long leftTemperature, } else { format += (rightBetween10and0 ? F(" %02d") : (rightBetween0andMinus10 ? F("%03d") : rightTemperature < -100 ? F("----") : F("%3d"))); } - sprintf_P(p073_digit, format.c_str(), static_cast(leftTemperature), static_cast(rightTemperature)); - const int p073_numlenght = strlen(p073_digit); + sprintf_P(p073_digit, format.c_str(), leftTemperature, rightTemperature); + const size_t p073_numlenght = strlen(p073_digit); - for (int i = 0; i < p073_numlenght; ++i) { + for (size_t i = 0; i < p073_numlenght; ++i) { showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); } @@ -399,21 +432,6 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, } # ifdef P073_SCROLL_TEXT -uint8_t P073_data_struct::getBufferLength(uint8_t displayModel, - uint8_t digits) { - const uint8_t digitsSet[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 - uint8_t bufLen = 0; - - if (displayModel < NR_ELEMENTS(digitsSet)) { - bufLen = digitsSet[displayModel]; - } - - if (P073_74HC595_2_8DGT == displayModel) { - bufLen = digits; - } - return bufLen; -} - int P073_data_struct::getEffectiveTextLength(const String& text) { const int textLength = text.length(); int p = 0; @@ -443,7 +461,7 @@ bool P073_data_struct::NextScroll() { if (scrollCount == 0) { scrollCount = 0xFFFF; // Max value to avoid interference when scrolling long texts result = true; - const int bufToFill = getBufferLength(displayModel, digits); + const int bufToFill = p073_getDefaultDigits(displayModel, digits); const int p073_txtlength = _textToScroll.length(); ClearBuffer(); @@ -496,7 +514,7 @@ void P073_data_struct::setTextToScroll(const String& text) { _textToScroll = String(); if (!text.isEmpty()) { - const int bufToFill = getBufferLength(displayModel, digits); + const int bufToFill = p073_getDefaultDigits(displayModel, digits); _textToScroll.reserve(text.length() + bufToFill + (scrollFull ? bufToFill : 0)); for (int i = 0; scrollFull && i < bufToFill; ++i) { // Scroll text in from the right, so start with all spaces diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index d113487820..d30a2f161c 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -154,6 +154,9 @@ static const uint8_t Dseg7CharTable[42] PROGMEM = { # endif // P073_EXTRA_FONTS +uint8_t p073_getDefaultDigits(uint8_t displayModel, + uint8_t digits = 0); + struct P073_data_struct : public PluginTaskData_base { public: @@ -163,14 +166,13 @@ struct P073_data_struct : public PluginTaskData_base { void init(struct EventStruct *event); # ifdef P073_USE_74HC595 bool plugin_fifty_per_second(struct EventStruct *event); + void hc595_InitDisplay(); void hc595_ShowBuffer(); void hc595_AdjustBuffer(); bool hc595_Sequential() { return P073_HC595_SEQUENTIAL; } - void hc595_InitDisplay(); - # endif // ifdef P073_USE_74HC595 void FillBufferWithTime(bool sevendgt_now, @@ -184,19 +186,26 @@ struct P073_data_struct : public PluginTaskData_base { uint8_t sevendgt_month, int sevendgt_year, bool suppressLeading0); + void Put4NumbersInBuffer(const uint8_t nr1, + const uint8_t nr2, + const uint8_t nr3, + const int8_t nr4 + # ifdef P073_SUPPRESS_ZERO + , + const bool suppressLeading0 + # endif // ifdef P073_SUPPRESS_ZERO + ); void FillBufferWithNumber(const String& number); - void FillBufferWithTemp(long temperature); + void FillBufferWithTemp(int temperature); # ifdef P073_7DDT_COMMAND - void FillBufferWithDualTemp(long leftTemperature, + void FillBufferWithDualTemp(int leftTemperature, bool leftWithDecimal, - long rightTemperature, + int rightTemperature, bool rightWithDecimal); # endif // ifdef P073_7DDT_COMMAND void FillBufferWithString(const String& textToShow, bool useBinaryData = false); # ifdef P073_SCROLL_TEXT - uint8_t getBufferLength(uint8_t displayModel, - uint8_t digits); int getEffectiveTextLength(const String& text); bool NextScroll(); void setTextToScroll(const String& text); From 85f0a711339f1566fffbef297aa3034d115f0e93 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 27 Jul 2024 20:27:58 +0200 Subject: [PATCH 04/21] [P073] Make build fit again (part 2) --- src/src/PluginStructs/P073_data_struct.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index d30a2f161c..fe58e1fefa 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -45,12 +45,17 @@ # undef P073_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature # undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command # undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature -# undef P073_USE_74HC595 // Optionally activate if .bin file space is problematic, remove the support for 74HC595 displays # else // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) // # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug # endif // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) +# if defined(ESP8266) +# ifdef P073_USE_74HC595 +# undef P073_USE_74HC595 // Removes the support for 74HC595 displays +# endif // ifdef P073_USE_74HC595 +# endif // if defined(ESP8266) + # define TM1637_POWER_ON 0b10001000 # define TM1637_POWER_OFF 0b10000000 # define TM1637_CLOCKDELAY 40 From 48ffe2219798dc83ebbd13934be5ee51c7188b60 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 28 Jul 2024 13:35:41 +0200 Subject: [PATCH 05/21] [P094] Remove from Collection D for ESP8266 buildsize --- docs/source/Plugin/_plugin_substitutions_p09x.repl | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/Plugin/_plugin_substitutions_p09x.repl b/docs/source/Plugin/_plugin_substitutions_p09x.repl index 9c9dfc7423..0154a7f40f 100644 --- a/docs/source/Plugin/_plugin_substitutions_p09x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p09x.repl @@ -50,7 +50,7 @@ .. |P094_name| replace:: :cyan:`CUL Reader` .. |P094_type| replace:: :cyan:`Communication` .. |P094_typename| replace:: :cyan:`Communication - CUL Reader` -.. |P094_status| replace:: :yellow:`COLLECTION D` +.. |P094_status| replace:: :yellow:`MAX` .. |P094_github| replace:: P094_CULReader.ino .. _P094_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P094_CULReader.ino .. |P094_usedby| replace:: `.` diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 52f7441256..0d6957f536 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1577,7 +1577,9 @@ To create/register a plugin, you have to : #ifdef PLUGIN_SET_COLLECTION_D #define USES_P093 // Mitsubishi Heat Pump - #define USES_P094 // CUL Reader + #ifdef ESP32 + #define USES_P094 // CUL Reader + #endif #ifndef USES_P098 #define USES_P098 // PWM motor #endif From d8173d902ea69466732e425a6bd2c889d651b342 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 28 Jul 2024 13:45:26 +0200 Subject: [PATCH 06/21] [P073] Move most code to PluginStruct files, explicit compile-time defines --- src/_P073_7DGT.ino | 1396 +------------------- src/src/PluginStructs/P073_data_struct.cpp | 1348 ++++++++++++++++++- src/src/PluginStructs/P073_data_struct.h | 209 ++- 3 files changed, 1511 insertions(+), 1442 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index b2a6cb5232..338194e4d5 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -39,9 +39,11 @@ // - "7db,<0-15> -- set brightness to specific value between 0 and 15 // - "7output,<0-5> -- select display output mode, 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink",3:"Clock 12h - Blink",4:"Clock // 12h - No Blink",5:"Date" +// - "7dfont," -- Select the active font by name or number: 0/default, 1/siekoo, 2/siekoo_upper, 3/dseg7 // /** History + * 2024-07-27 tonhuisman: Move most code to P073 PluginStruct and remove now unneeded code, use explicit compile-time defines (0/1) * 2024-07-24 tonhuisman: Fixed the issue that most extended features where not included in the MAX or ESP32 builds * 2024-07-20 tonhuisman: Implement 74HC595 7-segment displays (2, 2+2, 3, 2+3, 3+2, 4, 6, 3+3 and 8 digits) * 2 and 3 digit display use sequential data, 4, 6 and 8 digit displays use multiplexing, requiring continuous @@ -84,13 +86,6 @@ # include "src/PluginStructs/P073_data_struct.h" -void tm1637_ShowDate6(struct EventStruct *event, - bool showTime = false); // Forward declaration for default argument -void tm1637_ShowBuffer(struct EventStruct *event, - uint8_t firstPos, - uint8_t lastPos, - bool useBinaryData = false); - boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; @@ -112,36 +107,36 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) break; } - # if defined(P073_SCROLL_TEXT) || defined(P073_USE_74HC595) + # if P073_SCROLL_TEXT || P073_USE_74HC595 case PLUGIN_SET_DEFAULTS: { - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT P073_CFG_SCROLLSPEED = 10; // Default 10 * 0.1 sec scroll speed - # endif // ifdef P073_SCROLL_TEXT - # ifdef P073_USE_74HC595 + # endif // if P073_SCROLL_TEXT + # if P073_USE_74HC595 P073_CFG_DIGITS = 4; // Default number of digits - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 break; } - # endif // if defined(P073_SCROLL_TEXT) || defined(P073_USE_74HC595) + # endif // if P073_SCROLL_TEXT || P073_USE_74HC595 case PLUGIN_WEBFORM_LOAD: { addFormNote(F("TM1637: 1st=CLK-Pin, 2nd=DIO-Pin")); addFormNote(F("MAX7219: 1st=DIN-Pin, 2nd=CLK-Pin, 3rd=CS-Pin")); - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 addFormNote(F("74HC595: 1st=SDI-Pin, 2nd=CLK-Pin, 3rd=LOAD-Pin")); - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 { const __FlashStringHelper *displtype[] = { F("TM1637 - 4 digit (colon)"), F("TM1637 - 4 digit (dots)"), F("TM1637 - 6 digit"), F("MAX7219 - 8 digit"), - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 F("74HC595 - 2..8 digit"), - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 }; addFormSelector(F("Display Type"), F("displtype"), NR_ELEMENTS(displtype), displtype, nullptr, P073_CFG_DISPLAYTYPE); } - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { if (0 == P073_CFG_DIGITS) { @@ -151,7 +146,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) const int digitsOptions[] = { 2, 1, 3, 4, 5, 6, 7, 8 }; addFormSelector(F("Nr. of digits"), F("dgts"), NR_ELEMENTS(digitsOptions), digits, digitsOptions, P073_CFG_DIGITS); } else - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 { P073_CFG_DIGITS = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); } @@ -168,7 +163,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) addFormNumericBox(F("Brightness"), F("brightness"), P073_CFG_BRIGHTNESS, 0, 15); addUnit(F("0..15")); - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS { const __FlashStringHelper *fontset[4] = { F("Default"), F("Siekoo"), @@ -177,36 +172,36 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) addFormSelector(F("Font set"), F("fontset"), 4, fontset, nullptr, P073_CFG_FONTSET); addFormNote(F("Check documentation for examples of the font sets.")); } - # endif // P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS addFormSubHeader(F("Options")); addFormCheckBox(F("Text show periods as dot"), F("periods"), bitRead(P073_CFG_FLAGS, P073_OPTION_PERIOD)); addFormCheckBox(F("Hide ° for Temperatures"), F("hide_degree"), bitRead(P073_CFG_FLAGS, P073_OPTION_HIDEDEGREE)); - # ifdef P073_7DDT_COMMAND + # if P073_7DDT_COMMAND addFormNote(F("Commands 7dt,<temp> and 7ddt,<temp1>,<temp2>")); - # else // ifdef P073_7DDT_COMMAND + # else // if P073_7DDT_COMMAND addFormNote(F("Command 7dt,<temp>")); - # endif // P073_7DDT_COMMAND - # ifdef P073_SUPPRESS_ZERO + # endif // if P073_7DDT_COMMAND + # if P073_SUPPRESS_ZERO addFormCheckBox(F("Suppress leading 0 on day/hour"), F("supp0"), bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0)); - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT addFormCheckBox(F("Scroll text > display width"), F("scroll_text"), bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLTEXT)); addFormCheckBox(F("Scroll text in from right"), F("scroll_full"), bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLFULL)); if (P073_CFG_SCROLLSPEED == 0) { P073_CFG_SCROLLSPEED = 10; } addFormNumericBox(F("Scroll speed (0.1 sec/step)"), F("scrollspeed"), P073_CFG_SCROLLSPEED, 1, 600); addUnit(F("1..600 = 0.1..60 sec/step")); - # endif // P073_SCROLL_TEXT + # endif // if P073_SCROLL_TEXT - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 addFormSubHeader(F("Options for 8 digit displays (MAX7219/74HC595)")); - # else // ifdef P073_USE_74HC595 + # else // if P073_USE_74HC595 addFormSubHeader(F("Options for MAX7219 - 8 digit")); - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 bool bRightAlign = bitRead(P073_CFG_FLAGS, P073_OPTION_RIGHTALIGN); addFormCheckBox(F("Right-align Temperature (7dt)"), F("temp_rightalign"), bRightAlign); @@ -223,23 +218,23 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) bitWrite(lSettings, P073_OPTION_PERIOD, isFormItemChecked(F("periods"))); bitWrite(lSettings, P073_OPTION_HIDEDEGREE, isFormItemChecked(F("hide_degree"))); bitWrite(lSettings, P073_OPTION_RIGHTALIGN, isFormItemChecked(F("temp_rightalign"))); - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT bitWrite(lSettings, P073_OPTION_SCROLLTEXT, isFormItemChecked(F("scroll_text"))); bitWrite(lSettings, P073_OPTION_SCROLLFULL, isFormItemChecked(F("scroll_full"))); P073_CFG_SCROLLSPEED = getFormItemInt(F("scrollspeed")); - # endif // P073_SCROLL_TEXT - # ifdef P073_SUPPRESS_ZERO + # endif // if P073_SCROLL_TEXT + # if P073_SUPPRESS_ZERO bitWrite(lSettings, P073_OPTION_SUPPRESS0, isFormItemChecked(F("supp0"))); - # endif // ifdef P073_SUPPRESS_ZERO - # ifdef P073_EXTRA_FONTS + # endif // if P073_SUPPRESS_ZERO + # if P073_EXTRA_FONTS P073_CFG_FONTSET = getFormItemInt(F("fontset")); - # endif // P073_EXTRA_FONTS - # ifdef P073_USE_74HC595 + # endif // if P073_EXTRA_FONTS + # if P073_USE_74HC595 if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { P073_CFG_DIGITS = getFormItemInt(F("dgts")); } - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 P073_CFG_FLAGS = lSettings; success = true; @@ -259,47 +254,18 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) if (nullptr != P073_data) { P073_data->init(event); - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - tm1637_InitDisplay(CONFIG_PIN1, CONFIG_PIN2); - tm1637_SetPowerBrightness(CONFIG_PIN1, CONFIG_PIN2, P073_CFG_BRIGHTNESS / 2, true); - - if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { - tm1637_ClearDisplay(CONFIG_PIN1, CONFIG_PIN2); - } - break; - case P073_MAX7219_8DGT: - max7219_InitDisplay(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3); - delay(10); // small poweroff/poweron delay - max7219_SetPowerBrightness(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3, P073_CFG_BRIGHTNESS, true); - - if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { - max7219_ClearDisplay(event, CONFIG_PIN1, CONFIG_PIN2, CONFIG_PIN3); - } - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - P073_data->hc595_InitDisplay(); - - if (P073_CFG_OUTPUTTYPE == P073_DISP_MANUAL) { - P073_data->ClearBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - } - break; - # endif // ifdef P073_USE_74HC595 - } success = true; } break; } case PLUGIN_WRITE: { - success = p073_plugin_write(event, string); + P073_data_struct *P073_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P073_data) { + success = P073_data->p073_plugin_write(event, string); + } break; } @@ -307,129 +273,27 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) P073_data_struct *P073_data = static_cast(getPluginTaskData(event->TaskIndex)); - if ((nullptr == P073_data) || (P073_data->output == P073_DISP_MANUAL)) { - break; - } - - if ((P073_data->output == P073_DISP_CLOCK24BLNK) || - (P073_data->output == P073_DISP_CLOCK12BLNK)) { - P073_data->timesep = !P073_data->timesep; - } else { - P073_data->timesep = true; - } - - if (P073_data->output == P073_DISP_DATE) { - P073_data->FillBufferWithDate(true, 0, 0, 0, - # ifdef P073_SUPPRESS_ZERO - bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) - # else // ifdef P073_SUPPRESS_ZERO - false - # endif // ifdef P073_SUPPRESS_ZERO - ); - } else { - P073_data->FillBufferWithTime(true, 0, 0, 0, !((P073_data->output == P073_DISP_CLOCK24BLNK) || - (P073_data->output == P073_DISP_CLOCK24)), - # ifdef P073_SUPPRESS_ZERO - bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) - # else // ifdef P073_SUPPRESS_ZERO - false - # endif // ifdef P073_SUPPRESS_ZERO - ); + if (nullptr != P073_data) { + success = P073_data->plugin_once_a_second(event); } - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: { - tm1637_ShowTimeTemp4(event, P073_data->timesep, 0); - break; - } - case P073_TM1637_6DGT: { - if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { - tm1637_ShowDate6(event); - } else { - tm1637_ShowTime6(event); - } - break; - } - case P073_MAX7219_8DGT: { - if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { - max7219_ShowDate(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3); - } else { - max7219_ShowTime(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3, P073_data->timesep); - } - break; - } - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: { - P073_data->hc595_AdjustBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - } - # endif // ifdef P073_USE_74HC595 - } break; } - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT case PLUGIN_TEN_PER_SECOND: { P073_data_struct *P073_data = static_cast(getPluginTaskData(event->TaskIndex)); - if (nullptr == P073_data) { - break; - } - - if ((P073_data->output != P073_DISP_MANUAL) || !P073_data->isScrollEnabled()) { - break; + if (nullptr != P073_data) { + success = P073_data->plugin_ten_per_second(event); } - if (P073_data->NextScroll()) { - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: { - tm1637_ShowBuffer(event, 0, 4 - # ifdef P073_7DBIN_COMMAND - , P073_data->binaryData - # endif // ifdef P073_7DBIN_COMMAND - ); - break; - } - case P073_TM1637_6DGT: { - tm1637_SwapDigitInBuffer(event, 0); // only needed for 6-digits displays - tm1637_ShowBuffer(event, 0, 6 - # ifdef P073_7DBIN_COMMAND - , P073_data->binaryData - # endif // ifdef P073_7DBIN_COMMAND - ); - break; - } - case P073_MAX7219_8DGT: { - P073_data->dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3); - break; - } - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: { - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - } - # endif // ifdef P073_USE_74HC595 - } - success = true; - } break; } - # endif // P073_SCROLL_TEXT + # endif // if P073_SCROLL_TEXT - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 case PLUGIN_FIFTY_PER_SECOND: { P073_data_struct *P073_data = static_cast(getPluginTaskData(event->TaskIndex)); @@ -439,1171 +303,9 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) } break; } - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 } return success; } -bool p073_plugin_write(struct EventStruct *event, - const String & string) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return false; - } - - const String cmd = parseString(string, 1); - - if ((cmd.length() < 3) || (cmd[0] != '7')) { return false; } - - # ifdef P073_SCROLL_TEXT - const bool currentScroll = P073_data->isScrollEnabled(); // Save current state - bool newScroll = false; // disable scroll if command changes - P073_data->setScrollEnabled(false); - # endif // ifdef P073_SCROLL_TEXT - - const String text = parseStringToEndKeepCase(string, 2); - - if (equals(cmd, F("7dn"))) { - return p073_plugin_write_7dn(event, text); - } else if (equals(cmd, F("7dt"))) { - return p073_plugin_write_7dt(event, text); - # ifdef P073_7DDT_COMMAND - } else if (equals(cmd, F("7ddt"))) { - return p073_plugin_write_7ddt(event, text); - # endif // ifdef P073_7DDT_COMMAND - } else if (equals(cmd, F("7dst"))) { - return p073_plugin_write_7dst(event); - } else if (equals(cmd, F("7dsd"))) { - return p073_plugin_write_7dsd(event); - } else if (equals(cmd, F("7dtext"))) { - # ifdef P073_SCROLL_TEXT - P073_data->setScrollEnabled(true); // Scrolling allowed for 7dtext command - # endif // ifdef P073_SCROLL_TEXT - return p073_plugin_write_7dtext(event, text); - # ifdef P073_EXTRA_FONTS - } else if (equals(cmd, F("7dfont"))) { - # ifdef P073_SCROLL_TEXT - P073_data->setScrollEnabled(currentScroll); // Restore state - # endif // ifdef P073_SCROLL_TEXT - return p073_plugin_write_7dfont(event, text); - # endif // P073_EXTRA_FONTS - # ifdef P073_7DBIN_COMMAND - } else if (equals(cmd, F("7dbin"))) { - # ifdef P073_SCROLL_TEXT - P073_data->setScrollEnabled(true); // Scrolling allowed for 7dbin command - # endif // ifdef P073_SCROLL_TEXT - return p073_plugin_write_7dbin(event, text); - # endif // P073_7DBIN_COMMAND - } else { - bool success = false; - bool displayon = false; - - if (equals(cmd, F("7don"))) { - # ifdef P073_SCROLL_TEXT - newScroll = currentScroll; // Restore state - # endif // ifdef P073_SCROLL_TEXT - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("7DGT : Display ON")); - # endif // ifndef BUILD_NO_DEBUG - displayon = true; - success = true; - } else if (equals(cmd, F("7doff"))) { - # ifdef P073_SCROLL_TEXT - newScroll = currentScroll; // Restore state - # endif // ifdef P073_SCROLL_TEXT - # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("7DGT : Display OFF")); - # endif // ifndef BUILD_NO_DEBUG - displayon = false; - success = true; - } else if (equals(cmd, F("7db"))) { - # ifdef P073_SCROLL_TEXT - newScroll = currentScroll; // Restore state - # endif // ifdef P073_SCROLL_TEXT - - if ((event->Par1 >= 0) && (event->Par1 < 16)) { - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F("7DGT : Brightness="), event->Par1)); - } - # endif // ifndef BUILD_NO_DEBUG - P073_data->brightness = event->Par1; - P073_CFG_BRIGHTNESS = event->Par1; - displayon = true; - success = true; - } - } else if (equals(cmd, F("7output"))) { - if ((event->Par1 >= 0) && (event->Par1 < 6)) { // 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink", - // 3:"Clock 12h - Blink",4:"Clock 12h - No Blink",5:"Date" - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F("7DGT : Display output="), event->Par1)); - } - # endif // ifndef BUILD_NO_DEBUG - P073_data->output = event->Par1; - P073_CFG_OUTPUTTYPE = event->Par1; - displayon = true; - success = true; - # ifdef P073_SCROLL_TEXT - - if (event->Par1 == 0) { newScroll = currentScroll; } // Restore state - # endif // ifdef P073_SCROLL_TEXT - } - } - - if (success) { - # ifdef P073_SCROLL_TEXT - P073_data->setScrollEnabled(newScroll); - # endif // ifdef P073_SCROLL_TEXT - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - tm1637_SetPowerBrightness(P073_data->pin1, P073_data->pin2, - P073_data->brightness / 2, displayon); - break; - case P073_MAX7219_8DGT: - max7219_SetPowerBrightness(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3, P073_data->brightness, - displayon); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - // 74HC595 don't have a brightness setting - break; - # endif // ifdef P073_USE_74HC595 - } - } - return success; - } - return false; -} - -void p073_GetDisplayLimits(struct EventStruct *event, int32_t& lLimit, int32_t& uLimit, int8_t offset = 0, uint8_t digits = 0) { - uint8_t dgts = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); - - # ifdef P073_USE_74HC595 - - if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { - dgts = digits; - } - # endif // ifdef P073_USE_74HC595 - dgts -= offset; // Subtract an offset, used for extra symbol - lLimit = -pow10(dgts - 1); // Lowest value we can display - 1 - uLimit = pow10(dgts); // Highest value we can display + 1 - // TODO disable log - // addLog(LOG_LEVEL_INFO, strformat(F("P073: limits: %d digits(%d), lower: %d, upper: %d"), dgts, offset, lLimit, uLimit)); -} - -bool p073_plugin_write_7dn(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F("7DGT : Show Number="), event->Par1)); - } - # endif // ifndef BUILD_NO_DEBUG - - int32_t lLimit = 0; - int32_t uLimit = 0; - p073_GetDisplayLimits(event, lLimit, uLimit, 0, P073_data->digits); - - if (!text.isEmpty()) { - if ((event->Par1 > lLimit) && (event->Par1 < uLimit)) { - P073_data->FillBufferWithNumber(text.c_str()); - } else { - P073_data->FillBufferWithDash(); - } - } - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(event, TM1637_4DIGIT, 8); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(event, 2); // only needed for 6-digits displays - tm1637_ShowBuffer(event, TM1637_6DIGIT, 8); - break; - case P073_MAX7219_8DGT: - max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, - P073_data->pin3); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - P073_data->hc595_AdjustBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - return true; -} - -bool p073_plugin_write_7dt(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - float p073_temptemp = 0; - bool p073_tempflagdot = false; - - if (!text.isEmpty()) { - validFloatFromString(text, p073_temptemp); - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F("7DGT : Show Temperature="), p073_temptemp)); - } - # endif // ifndef BUILD_NO_DEBUG - - int32_t lLimit = 0; - int32_t uLimit = 0; - p073_GetDisplayLimits(event, lLimit, uLimit, P073_data->hideDegree ? 0 : 1, P073_data->digits); - float lLimitErr = lLimit + 0.1f; - float uLimitErr = uLimit - 1.0f; - float lLimitDec = lLimit / 10.0f; - float uLimitDec = uLimit / 10.0f; - - // TODO disable log - // addLog(LOG_LEVEL_INFO, strformat(F("P073: 7dt: lErr: %.1f, uErr: %.1f, lDec: %.1f, uDec: %.1f"), - // lLimitErr, uLimitErr, lLimitDec, uLimitDec)); - - if ((p073_temptemp > uLimitErr) || (p073_temptemp < lLimitErr)) { - P073_data->FillBufferWithDash(); - } else { - if ((p073_temptemp < uLimitDec) && (p073_temptemp > lLimitDec)) { - p073_temptemp = roundf(p073_temptemp * 10.0f); - p073_tempflagdot = true; - } - P073_data->FillBufferWithTemp(p073_temptemp); - } - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - - if ((p073_temptemp == 0) && p073_tempflagdot) { - P073_data->showbuffer[5] = 0; - } - - if (P073_TM1637_6DGT == P073_data->displayModel) { - tm1637_ShowTemp6(event, p073_tempflagdot); - } else { - tm1637_ShowTimeTemp4(event, p073_tempflagdot, 4); - } - break; - case P073_MAX7219_8DGT: - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("7DGT : 7dt preprocessed ="), p073_temptemp)); - } - # endif // ifdef P073_DEBUG - - max7219_ShowTemp(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, P073_data->hideDegree ? 6 : 5, -1); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - P073_data->hc595_AdjustBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - # ifdef P073_DEBUG - P073_data->LogBufferContent(F("7dt")); - # endif // ifdef P073_DEBUG - return true; -} - -# ifdef P073_7DDT_COMMAND -bool p073_plugin_write_7ddt(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - float p073_lefttemp = 0.0f; - float p073_righttemp = 0.0f; - bool p073_tempflagdot = false; - - if (!text.isEmpty()) { - validFloatFromString(parseString(text, 1), p073_lefttemp); - - if (text.indexOf(',') > -1) { - validFloatFromString(parseString(text, 2), p073_righttemp); - } - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Dual Temperature 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); - } - # endif // ifndef BUILD_NO_DEBUG - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - case P073_TM1637_6DGT: - { - P073_data->FillBufferWithDash(); - - if (P073_data->displayModel == P073_TM1637_6DGT) { - tm1637_ShowTemp6(event, p073_tempflagdot); - } else { - tm1637_ShowTimeTemp4(event, p073_tempflagdot, 4); - } - break; - } - case P073_MAX7219_8DGT: - case P073_74HC595_2_8DGT: - { - uint8_t firstDot = -1; // No decimals is no dots - uint8_t secondDot = -1; - float hideFactor = P073_data->hideDegree ? 10.0f : 1.0f; - - if ((p073_lefttemp > 999.99f * hideFactor) || (p073_lefttemp < -99.99f * hideFactor)) { - p073_lefttemp = -101.0f * hideFactor; // Triggers on -100 - } else { - if ((p073_lefttemp < 100.0f * hideFactor) && (p073_lefttemp > -10.0f * hideFactor)) { - p073_lefttemp = roundf(p073_lefttemp * 10.0f); - firstDot = P073_data->hideDegree ? 2 : 1; - } - } - - if ((p073_righttemp > 999.99f * hideFactor) || (p073_righttemp < -99.99f * hideFactor)) { - p073_righttemp = -101.0f * hideFactor; - } else { - if ((p073_righttemp < 100.0f * hideFactor) && (p073_righttemp > -10.0f * hideFactor)) { - p073_righttemp = roundf(p073_righttemp * 10.0f); - secondDot = P073_data->hideDegree ? 6 : 5; - } - } - - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("7DGT : 7ddt preprocessed 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); - } - # endif // ifdef P073_DEBUG - - P073_data->FillBufferWithDualTemp(p073_lefttemp, firstDot > -1, p073_righttemp, secondDot > -1); - - if (P073_MAX7219_8DGT == P073_data->displayModel) { - bool alignSave = P073_data->rightAlignTempMAX7219; // Save setting - P073_data->rightAlignTempMAX7219 = true; - - max7219_ShowTemp(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, firstDot, secondDot); - - P073_data->rightAlignTempMAX7219 = alignSave; // Restore - # ifdef P073_USE_74HC595 - } else - - // if (P073_74HC595_2_8DGT == P073_data->displayModel) - { - if (P073_data->digits < 8) { - P073_data->FillBufferWithDash(); - } - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - # endif // ifdef P073_USE_74HC595 - } - - break; - } - } - # ifdef P073_DEBUG - P073_data->LogBufferContent(F("7ddt")); - # endif // ifdef P073_DEBUG - return true; -} - -# endif // ifdef P073_7DDT_COMMAND - -bool p073_plugin_write_7dst(struct EventStruct *event) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Time=%02d:%02d:%02d"), event->Par1, event->Par2, event->Par3)); - } - # endif // ifndef BUILD_NO_DEBUG - P073_data->timesep = true; - P073_data->FillBufferWithTime(false, event->Par1, event->Par2, event->Par3, false, - # ifdef P073_SUPPRESS_ZERO - bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) - # else // ifdef P073_SUPPRESS_ZERO - false - # endif // ifdef P073_SUPPRESS_ZERO - ); - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowTimeTemp4(event, P073_data->timesep, 0); - break; - case P073_TM1637_6DGT: - tm1637_ShowTime6(event); - break; - case P073_MAX7219_8DGT: - max7219_ShowTime(event, P073_data->pin1, P073_data->pin2, P073_data->pin3, P073_data->timesep); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - P073_data->hc595_AdjustBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - return true; -} - -bool p073_plugin_write_7dsd(struct EventStruct *event) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Date=%02d:%02d:%02d"), event->Par1, event->Par2, event->Par3)); - } - # endif // ifndef BUILD_NO_DEBUG - P073_data->FillBufferWithDate(false, event->Par1, event->Par2, event->Par3, - # ifdef P073_SUPPRESS_ZERO - bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0) - # else // ifdef P073_SUPPRESS_ZERO - false - # endif // ifdef P073_SUPPRESS_ZERO - ); - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowTimeTemp4(event, P073_data->timesep, 0); - break; - case P073_TM1637_6DGT: - tm1637_ShowDate6(event); - break; - case P073_MAX7219_8DGT: - max7219_ShowDate(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - P073_data->hc595_AdjustBuffer(); - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - return true; -} - -bool p073_plugin_write_7dtext(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if ((nullptr == P073_data) || (P073_data->output != P073_DISP_MANUAL)) { - return false; - } - - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("7DGT : Show Text="), text)); - } - # endif // ifndef BUILD_NO_DEBUG - # ifdef P073_SCROLL_TEXT - P073_data->setTextToScroll(EMPTY_STRING); - uint8_t bufLen = p073_getDefaultDigits(P073_data->displayModel, P073_data->digits); - - if (P073_data->isScrollEnabled() && (P073_data->getEffectiveTextLength(text) > bufLen)) { - P073_data->setTextToScroll(text); - } else - # endif // P073_SCROLL_TEXT - { - P073_data->FillBufferWithString(text); - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(event, 0, 4); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(event, 0); // only needed for 6-digits displays - tm1637_ShowBuffer(event, 0, 6); - break; - case P073_MAX7219_8DGT: - P073_data->dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - } - return true; -} - -# ifdef P073_EXTRA_FONTS -bool p073_plugin_write_7dfont(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return false; - } - - if (!text.isEmpty()) { - const String fontArg = parseString(text, 1); - int32_t fontNr = -1; - - if ((equals(fontArg, F("default"))) || (equals(fontArg, F("7dgt")))) { - fontNr = 0; - } else if (equals(fontArg, F("siekoo"))) { - fontNr = 1; - } else if (equals(fontArg, F("siekoo_upper"))) { - fontNr = 2; - } else if (equals(fontArg, F("dseg7"))) { - fontNr = 3; - } else if (!validIntFromString(text, fontNr)) { - fontNr = -1; // reset if invalid - } - - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("P037 7dfont,%s -> %d"), fontArg.c_str(), fontNr)); - } - # endif // P073_DEBUG - - if ((fontNr >= 0) && (fontNr <= 3)) { - P073_data->fontset = fontNr; - P073_CFG_FONTSET = fontNr; - return true; - } - } - return false; -} - -# endif // P073_EXTRA_FONTS - -# ifdef P073_7DBIN_COMMAND -bool p073_plugin_write_7dbin(struct EventStruct *event, - const String & text) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return false; - } - - if (!text.isEmpty()) { - String data; - int32_t byteValue{}; - int arg = 1; - String argValue = parseString(text, arg); - - while (!argValue.isEmpty()) { - if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { - data += static_cast(P073_data->displayModel == P073_MAX7219_8DGT ? - byteValue : - P073_data->mapMAX7219FontToTM1673Font(byteValue)); - } - arg++; - argValue = parseString(text, arg); - } - # ifdef P073_SCROLL_TEXT - const uint8_t bufLen = p073_getDefaultDigits(P073_data->displayModel, P073_data->digits); - # endif // P073_SCROLL_TEXT - - if (!data.isEmpty()) { - # ifdef P073_SCROLL_TEXT - P073_data->setTextToScroll(EMPTY_STRING); // Clear any scrolling text - - if (P073_data->isScrollEnabled() && (data.length() > bufLen)) { - P073_data->setBinaryData(data); - } else - # endif // P073_SCROLL_TEXT - { - P073_data->FillBufferWithString(data, true); - - switch (P073_data->displayModel) { - case P073_TM1637_4DGTCOLON: - case P073_TM1637_4DGTDOTS: - tm1637_ShowBuffer(event, 0, 4); - break; - case P073_TM1637_6DGT: - tm1637_SwapDigitInBuffer(event, 0); // only needed for 6-digits displays - tm1637_ShowBuffer(event, 0, 6, true); - break; - case P073_MAX7219_8DGT: - P073_data->dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(event, P073_data->pin1, P073_data->pin2, P073_data->pin3); - break; - # ifdef P073_USE_74HC595 - case P073_74HC595_2_8DGT: - - if (P073_data->hc595_Sequential()) { // Sequential displays don't need continuous refreshing - P073_data->hc595_ShowBuffer(); - } - break; - # endif // ifdef P073_USE_74HC595 - } - } - return true; - } - } - return false; -} - -# endif // P073_7DBIN_COMMAND - -// =================================== -// ---- TM1637 specific functions ---- -// =================================== - -# define CLK_HIGH() digitalWrite(clk_pin, HIGH) -# define CLK_LOW() digitalWrite(clk_pin, LOW) -# define DIO_HIGH() pinMode(dio_pin, INPUT) -# define DIO_LOW() pinMode(dio_pin, OUTPUT) - -void tm1637_i2cStart(uint8_t clk_pin, - uint8_t dio_pin) { - # ifdef P073_DEBUG - addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Start")); - # endif // ifdef P073_DEBUG - DIO_HIGH(); - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - DIO_LOW(); -} - -void tm1637_i2cStop(uint8_t clk_pin, - uint8_t dio_pin) { - # ifdef P073_DEBUG - addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Stop")); - # endif // ifdef P073_DEBUG - CLK_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY); - DIO_LOW(); - delayMicroseconds(TM1637_CLOCKDELAY); - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - DIO_HIGH(); -} - -void tm1637_i2cAck(uint8_t clk_pin, - uint8_t dio_pin) { - # ifdef P073_DEBUG - bool dummyAck = false; - # endif // ifdef P073_DEBUG - - CLK_LOW(); - pinMode(dio_pin, INPUT_PULLUP); - - // DIO_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - - // while(digitalRead(dio_pin)); - # ifdef P073_DEBUG - dummyAck = - # endif // ifdef P073_DEBUG - digitalRead(dio_pin); - - # ifdef P073_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("7DGT : Comm ACK="); - - if (dummyAck == 0) { - log += F("TRUE"); - } else { - log += F("FALSE"); - } - addLogMove(LOG_LEVEL_DEBUG, log); - } - # endif // ifdef P073_DEBUG - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - CLK_LOW(); - pinMode(dio_pin, OUTPUT); -} - -void tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytesToPrint[], - uint8_t length) { - tm1637_i2cStart(clk_pin, dio_pin); - - for (uint8_t i = 0; i < length; ++i) { - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint[i]); - } - tm1637_i2cStop(clk_pin, dio_pin); -} - -void tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint) { - tm1637_i2cWrite(clk_pin, dio_pin, bytetoprint); - tm1637_i2cAck(clk_pin, dio_pin); -} - -void tm1637_i2cWrite(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint) { - # ifdef P073_DEBUG - addLog(LOG_LEVEL_DEBUG, F("7DGT : WriteByte")); - # endif // ifdef P073_DEBUG - uint8_t i; - - for (i = 0; i < 8; ++i) { - CLK_LOW(); - - if (bytetoprint & 0b00000001) { - DIO_HIGH(); - } else { - DIO_LOW(); - } - delayMicroseconds(TM1637_CLOCKDELAY); - bytetoprint = bytetoprint >> 1; - CLK_HIGH(); - delayMicroseconds(TM1637_CLOCKDELAY); - } -} - -void tm1637_ClearDisplay(uint8_t clk_pin, - uint8_t dio_pin) { - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 7); -} - -void tm1637_SetPowerBrightness(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t brightlvl, - bool poweron) { - # ifdef P073_DEBUG - addLog(LOG_LEVEL_INFO, F("7DGT : Set BRIGHT")); - # endif // ifdef P073_DEBUG - uint8_t brightvalue = (brightlvl & 0b111); - - if (poweron) { - brightvalue = TM1637_POWER_ON | brightvalue; - } else { - brightvalue = TM1637_POWER_OFF | brightvalue; - } - - uint8_t bytesToPrint[1]{}; - bytesToPrint[0] = brightvalue; - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 1); -} - -void tm1637_InitDisplay(uint8_t clk_pin, - uint8_t dio_pin) { - pinMode(clk_pin, OUTPUT); - pinMode(dio_pin, OUTPUT); - CLK_HIGH(); - DIO_HIGH(); - - uint8_t bytesToPrint[1]{}; - - bytesToPrint[0] = 0x40; - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 1); - tm1637_ClearDisplay(clk_pin, dio_pin); -} - -uint8_t tm1637_separator(uint8_t value, - bool sep) { - if (sep) { - value |= 0b10000000; - } - return value; -} - -void tm1637_ShowTime6(struct EventStruct *event) { - tm1637_ShowDate6(event, true); // deduplicated -} - -void tm1637_ShowDate6(struct EventStruct *event, bool showTime) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = P073_data->tm1637_getFontChar(P073_data->showbuffer[2], P073_data->fontset); - bytesToPrint[2] = tm1637_separator(P073_data->tm1637_getFontChar(P073_data->showbuffer[1], P073_data->fontset), P073_data->timesep); - bytesToPrint[3] = P073_data->tm1637_getFontChar(P073_data->showbuffer[0], P073_data->fontset); - - if (showTime) { - bytesToPrint[4] = P073_data->tm1637_getFontChar(P073_data->showbuffer[5], P073_data->fontset); - bytesToPrint[5] = P073_data->tm1637_getFontChar(P073_data->showbuffer[4], P073_data->fontset); - } else { - bytesToPrint[4] = P073_data->tm1637_getFontChar(P073_data->showbuffer[7], P073_data->fontset); - bytesToPrint[5] = P073_data->tm1637_getFontChar(P073_data->showbuffer[6], P073_data->fontset); - } - bytesToPrint[6] = tm1637_separator(P073_data->tm1637_getFontChar(P073_data->showbuffer[3], P073_data->fontset), P073_data->timesep); - - tm1637_i2cWrite_ack(P073_data->pin1, P073_data->pin2, bytesToPrint, 7); -} - -void tm1637_ShowTemp6(struct EventStruct *event, - bool sep) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - uint8_t bytesToPrint[7]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = tm1637_separator(P073_data->tm1637_getFontChar(P073_data->showbuffer[5], P073_data->fontset), sep); - bytesToPrint[2] = P073_data->tm1637_getFontChar(P073_data->showbuffer[4], P073_data->fontset); - bytesToPrint[3] = P073_data->tm1637_getFontChar(10, P073_data->fontset); - bytesToPrint[4] = P073_data->tm1637_getFontChar(10, P073_data->fontset); - bytesToPrint[5] = P073_data->tm1637_getFontChar(P073_data->showbuffer[7], P073_data->fontset); - bytesToPrint[6] = P073_data->tm1637_getFontChar(P073_data->showbuffer[6], P073_data->fontset); - - tm1637_i2cWrite_ack(P073_data->pin1, P073_data->pin2, bytesToPrint, 7); -} - -void tm1637_ShowTimeTemp4(struct EventStruct *event, - bool sep, - uint8_t bufoffset) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - uint8_t bytesToPrint[5]{}; - - bytesToPrint[0] = 0xC0; - bytesToPrint[1] = P073_data->tm1637_getFontChar(P073_data->showbuffer[0 + bufoffset], P073_data->fontset); - bytesToPrint[2] = tm1637_separator(P073_data->tm1637_getFontChar(P073_data->showbuffer[1 + bufoffset], P073_data->fontset), sep); - bytesToPrint[3] = P073_data->tm1637_getFontChar(P073_data->showbuffer[2 + bufoffset], P073_data->fontset); - bytesToPrint[4] = P073_data->tm1637_getFontChar(P073_data->showbuffer[3 + bufoffset], P073_data->fontset); - - tm1637_i2cWrite_ack(P073_data->pin1, P073_data->pin2, bytesToPrint, 5); -} - -void tm1637_SwapDigitInBuffer(struct EventStruct *event, - uint8_t startPos) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - std::swap(P073_data->showbuffer[2 + startPos], P073_data->showbuffer[0 + startPos]); - std::swap(P073_data->showbuffer[3 + startPos], P073_data->showbuffer[5 + startPos]); - - std::swap(P073_data->showperiods[2 + startPos], P073_data->showperiods[0 + startPos]); - std::swap(P073_data->showperiods[3 + startPos], P073_data->showperiods[5 + startPos]); - - if (P073_data->dotpos > -1) { - const uint8_t dotPositionSwap[] = { 0, 1, 4, 3, 2, 7, 6, 5, 8 }; - - P073_data->dotpos = dotPositionSwap[P073_data->dotpos]; - } -} - -void tm1637_ShowBuffer(struct EventStruct *event, - uint8_t firstPos, - uint8_t lastPos, - bool useBinaryData) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - uint8_t bytesToPrint[8]{}; - - bytesToPrint[0] = 0xC0; - uint8_t length = 1; - - if (P073_data->dotpos > -1) { - P073_data->showperiods[P073_data->dotpos] = true; - } - - uint8_t p073_datashowpos1; - - for (int i = firstPos; i < lastPos; ++i) { - if (useBinaryData) { - bytesToPrint[length] = P073_data->showbuffer[i]; - } else { - p073_datashowpos1 = tm1637_separator( - P073_data->tm1637_getFontChar(P073_data->showbuffer[i], P073_data->fontset), - P073_data->showperiods[i]); - bytesToPrint[length] = p073_datashowpos1; - } - ++length; - } - tm1637_i2cWrite_ack(P073_data->pin1, P073_data->pin2, bytesToPrint, length); -} - -// ==================================== -// ---- MAX7219 specific functions ---- -// ==================================== - -# define OP_DECODEMODE 9 -# define OP_INTENSITY 10 -# define OP_SCANLIMIT 11 -# define OP_SHUTDOWN 12 -# define OP_DISPLAYTEST 15 - -void max7219_spiTransfer(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - ESPEASY_VOLATILE(uint8_t) opcode, - ESPEASY_VOLATILE(uint8_t) data) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - P073_data->spidata[1] = opcode; - P073_data->spidata[0] = data; - digitalWrite(cs_pin, LOW); - shiftOut(din_pin, clk_pin, MSBFIRST, P073_data->spidata[1]); - shiftOut(din_pin, clk_pin, MSBFIRST, P073_data->spidata[0]); - digitalWrite(cs_pin, HIGH); -} - -void max7219_ClearDisplay(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { - for (int i = 0; i < 8; i++) { - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, i + 1, 0); - } -} - -void max7219_SetPowerBrightness(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - uint8_t brightlvl, - bool poweron) { - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, OP_INTENSITY, brightlvl); - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, OP_SHUTDOWN, poweron ? 1 : 0); -} - -void max7219_SetDigit(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int dgtpos, - uint8_t dgtvalue, - bool showdot, - bool binaryData = false) { - uint8_t p073_tempvalue; - - if (binaryData) { - p073_tempvalue = dgtvalue; // Overwrite if binary data - } else - { - # ifdef P073_EXTRA_FONTS - - switch (P073_CFG_FONTSET) { - case 1: // Siekoo - case 2: // Siekoo with uppercase CHNORUX - p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); - break; - case 3: // dSEG7 - p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); - break; - default: // Default fontset - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - } - # else // ifdef P073_EXTRA_FONTS - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - # endif // P073_EXTRA_FONTS - - if (showdot) { - p073_tempvalue |= 0b10000000; - } - } - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, dgtpos + 1, p073_tempvalue); -} - -void max7219_InitDisplay(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { - pinMode(din_pin, OUTPUT); - pinMode(clk_pin, OUTPUT); - pinMode(cs_pin, OUTPUT); - digitalWrite(cs_pin, HIGH); - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, OP_DISPLAYTEST, 0); - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, OP_SCANLIMIT, 7); // scanlimit setup to max at Init - max7219_spiTransfer(event, din_pin, clk_pin, cs_pin, OP_DECODEMODE, 0); - max7219_ClearDisplay(event, din_pin, clk_pin, cs_pin); - max7219_SetPowerBrightness(event, din_pin, clk_pin, cs_pin, 0, false); -} - -void max7219_ShowTime(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - bool sep) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward - - for (int8_t i = 5; i >= 0; --i) { - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, idx_list[i], P073_data->showbuffer[i], false); - } - - const uint8_t sepChar = P073_data->mapCharToFontPosition(sep ? '-' : ' ', P073_data->fontset); - - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, 2, sepChar, false); - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, 5, sepChar, false); -} - -void max7219_ShowTemp(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int8_t firstDot, - int8_t secondDot) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, 0, 10, false); - - if (firstDot > -1) { P073_data->showperiods[firstDot] = true; } - - if (secondDot > -1) { P073_data->showperiods[secondDot] = true; } - - const int alignRight = P073_data->rightAlignTempMAX7219 ? 0 : 1; - - for (int i = alignRight; i < 8; ++i) { - const int bufIndex = (7 + alignRight) - i; - - if (bufIndex < 8) { - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, i, - P073_data->showbuffer[bufIndex], - P073_data->showperiods[bufIndex]); - } - } -} - -void max7219_ShowDate(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; - - for (int i = 0; i < 8; ++i) { - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, i, - P073_data->showbuffer[7 - i], - dotflags[7 - i]); - } -} - -void max7219_ShowBuffer(struct EventStruct *event, - uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { - P073_data_struct *P073_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr == P073_data) { - return; - } - - if (P073_data->dotpos > -1) { - P073_data->showperiods[P073_data->dotpos] = true; - } - - for (int i = 0; i < 8; i++) { - max7219_SetDigit(event, din_pin, clk_pin, cs_pin, i, - P073_data->showbuffer[7 - i], - P073_data->showperiods[7 - i] - # ifdef P073_7DBIN_COMMAND - , P073_data->binaryData - # endif // P073_7DBIN_COMMAND - ); - } -} - -#endif // USES_P073 +#endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index e844e29617..a2c4fb9fcf 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -10,12 +10,12 @@ uint8_t p073_getDefaultDigits(uint8_t displayModel, if (displayModel < NR_ELEMENTS(digitsSet)) { bufLen = digitsSet[displayModel]; } - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 if (P073_74HC595_2_8DGT == displayModel) { bufLen = digits; } - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 return bufLen; } @@ -31,18 +31,19 @@ void P073_data_struct::init(struct EventStruct *event) brightness = P073_CFG_BRIGHTNESS; periods = bitRead(P073_CFG_FLAGS, P073_OPTION_PERIOD); hideDegree = bitRead(P073_CFG_FLAGS, P073_OPTION_HIDEDEGREE); - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT txtScrolling = bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLTEXT); scrollFull = bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLFULL); setScrollSpeed(P073_CFG_SCROLLSPEED); - # endif // P073_SCROLL_TEXT + # endif // if P073_SCROLL_TEXT rightAlignTempMAX7219 = bitRead(P073_CFG_FLAGS, P073_OPTION_RIGHTALIGN); + suppressLeading0 = bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0); timesep = true; - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS fontset = P073_CFG_FONTSET; - # endif // P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS digits = P073_CFG_DIGITS; - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits))) { isSequential = true; @@ -54,14 +55,49 @@ void P073_data_struct::init(struct EventStruct *event) digits = 6; } } - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 if ((digits > 0) && (digits < 4)) { hideDegree = true; // Hide degree symbol on small displays } + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + case P073_TM1637_6DGT: + tm1637_InitDisplay(pin1, pin2); + tm1637_SetPowerBrightness(pin1, pin2, brightness / 2, true); + + if (output == P073_DISP_MANUAL) { + tm1637_ClearDisplay(pin1, pin2); + } + break; + case P073_MAX7219_8DGT: + max7219_InitDisplay(pin1, pin2, pin3); + delay(10); // small poweroff/poweron delay + max7219_SetPowerBrightness(pin1, pin2, pin3, brightness, true); + + if (output == P073_DISP_MANUAL) { + max7219_ClearDisplay(pin1, pin2, pin3); + } + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_InitDisplay(); + + if (output == P073_DISP_MANUAL) { + ClearBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + } + break; + # endif // if P073_USE_74HC595 + } } -# ifdef P073_USE_74HC595 +# if P073_USE_74HC595 bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { # ifdef P073_DEBUG counter50++; @@ -125,7 +161,7 @@ void P073_data_struct::hc595_ShowBuffer() { for (; i != stop && i >= 0; i += incr) { uint8_t value; uint8_t digit = 0xFF; - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS // 74HC595 uses inverted data, compared to MAX7219/TM1637 switch (fontset) { @@ -139,9 +175,9 @@ void P073_data_struct::hc595_ShowBuffer() { default: // Default fontset value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); } - # else // ifdef P073_EXTRA_FONTS + # else // if P073_EXTRA_FONTS value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); - # endif // P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS if (showperiods[i]) { value &= 0x7F; @@ -199,7 +235,7 @@ void P073_data_struct::hc595_InitDisplay() { digitalWrite(pin3, HIGH); } -# endif // ifdef P073_USE_74HC595 +# endif // if P073_USE_74HC595 void P073_data_struct::FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, @@ -223,9 +259,9 @@ void P073_data_struct::FillBufferWithTime(bool sevendgt_now, sevendgt_hours = 12; // if flag 12h is TRUE and h=0 adjust to h=12 } Put4NumbersInBuffer(sevendgt_hours, sevendgt_minutes, sevendgt_seconds, -1 - # ifdef P073_SUPPRESS_ZERO + # if P073_SUPPRESS_ZERO , suppressLeading0 - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO ); } @@ -248,9 +284,9 @@ void P073_data_struct::FillBufferWithDate(bool sevendgt_now, const uint8_t sevendgt_year2 = static_cast(sevendgt_year0 % 100); Put4NumbersInBuffer(sevendgt_day, sevendgt_month, sevendgt_year1, sevendgt_year2 - # ifdef P073_SUPPRESS_ZERO + # if P073_SUPPRESS_ZERO , suppressLeading0 - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO ); } @@ -258,9 +294,9 @@ void P073_data_struct::Put4NumbersInBuffer(const uint8_t nr1, const uint8_t nr2, const uint8_t nr3, const int8_t nr4 - # ifdef P073_SUPPRESS_ZERO + # if P073_SUPPRESS_ZERO , const bool suppressLeading0 - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO ) { showbuffer[0] = static_cast(nr1 / 10); showbuffer[1] = nr1 % 10; @@ -273,10 +309,10 @@ void P073_data_struct::Put4NumbersInBuffer(const uint8_t nr1, showbuffer[6] = static_cast(nr4 / 10); showbuffer[7] = nr4 % 10; } - # ifdef P073_SUPPRESS_ZERO + # if P073_SUPPRESS_ZERO if (suppressLeading0 && (showbuffer[0] == 0)) { showbuffer[0] = 10; } // set to space - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO } void P073_data_struct::FillBufferWithNumber(const String& number) { @@ -326,7 +362,7 @@ void P073_data_struct::FillBufferWithTemp(int temperature) { } } -# ifdef P073_7DDT_COMMAND +# if P073_7DDT_COMMAND /** * FillBufferWithDualTemp() @@ -383,13 +419,13 @@ void P073_data_struct::FillBufferWithDualTemp(int leftTemperature, // addLog(LOG_LEVEL_INFO, concat(F("7dgt format: "), format)); } -# endif // ifdef P073_7DDT_COMMAND +# endif // if P073_7DDT_COMMAND void P073_data_struct::FillBufferWithString(const String& textToShow, bool useBinaryData) { - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND binaryData = useBinaryData; - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND ClearBuffer(); const int p073_txtlength = textToShow.length(); @@ -398,9 +434,9 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, for (int i = 0; i < p073_txtlength && p <= 8; ++i) { // p <= 8 to allow a period after last digit if (periods && textToShow.charAt(i) == '.' - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND && !binaryData - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND ) { // If setting periods true if (p == 0) { // Text starts with a period, becomes a space with a dot showperiods[p] = true; @@ -418,11 +454,11 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, } } } else if (p < 8) { - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND showbuffer[p] = useBinaryData ? textToShow.charAt(i) : mapCharToFontPosition(textToShow.charAt(i), fontset); - # else // P073_7DBIN_COMMAND + # else // if fP073_7DBIN_COMMAND showbuffer[p] = mapCharToFontPosition(textToShow.charAt(i), fontset); - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND p++; } } @@ -431,7 +467,7 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, # endif // ifdef P073_DEBUG } -# ifdef P073_SCROLL_TEXT +# if P073_SCROLL_TEXT int P073_data_struct::getEffectiveTextLength(const String& text) { const int textLength = text.length(); int p = 0; @@ -470,9 +506,9 @@ bool P073_data_struct::NextScroll() { for (int i = scrollPos; i < p073_txtlength && p <= bufToFill; ++i) { // p <= bufToFill to allow a period after last digit if (periods && _textToScroll.charAt(i) == '.' - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND && !binaryData - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND ) { // If setting periods true if (p == 0) { // Text starts with a period, becomes a space with a dot showperiods[p] = true; @@ -486,13 +522,13 @@ bool P073_data_struct::NextScroll() { p++; } } else if (p < bufToFill) { - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND showbuffer[p] = binaryData ? _textToScroll.charAt(i) : mapCharToFontPosition(_textToScroll.charAt(i), fontset); - # else // P073_7DBIN_COMMAND + # else // if P073_7DBIN_COMMAND showbuffer[p] = mapCharToFontPosition(_textToScroll.charAt(i), fontset); - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND p++; } } @@ -504,7 +540,7 @@ bool P073_data_struct::NextScroll() { scrollCount = _scrollSpeed; // Restart countdown # ifdef P073_DEBUG LogBufferContent(F("nextScroll")); - # endif // P073_DEBUG + # endif // ifdef P073_DEBUG } } return result; @@ -519,26 +555,26 @@ void P073_data_struct::setTextToScroll(const String& text) { for (int i = 0; scrollFull && i < bufToFill; ++i) { // Scroll text in from the right, so start with all spaces _textToScroll += - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND binaryData ? (char)0x00 : - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND ' '; } _textToScroll += text; for (int i = 0; i < bufToFill; ++i) { // Scroll text off completely before restarting _textToScroll += - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND binaryData ? (char)0x00 : - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND ' '; } } scrollCount = _scrollSpeed; scrollPos = 0; - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND binaryData = false; - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND } void P073_data_struct::setScrollSpeed(uint8_t speed) { @@ -555,22 +591,22 @@ void P073_data_struct::setScrollEnabled(bool scroll) { scrollAllowed = scroll; } -# endif // P073_SCROLL_TEXT +# endif // if P073_SCROLL_TEXT -# ifdef P073_7DBIN_COMMAND +# if P073_7DBIN_COMMAND void P073_data_struct::setBinaryData(const String& data) { binaryData = true; - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT setTextToScroll(data); binaryData = true; // is reset in setTextToScroll scrollCount = _scrollSpeed; scrollPos = 0; - # else // P073_SCROLL_TEXT + # else // if P073_SCROLL_TEXT _textToScroll = data; - # endif // P073_SCROLL_TEXT + # endif // if P073_SCROLL_TEXT } -# endif // P073_7DBIN_COMMAND +# endif // if P073_7DBIN_COMMAND # ifdef P073_DEBUG void P073_data_struct::LogBufferContent(String prefix) { @@ -590,7 +626,7 @@ void P073_data_struct::LogBufferContent(String prefix) { } } -# endif // P073_DEBUG +# endif // ifdef P073_DEBUG // in case of error show all dashes void P073_data_struct::FillBufferWithDash() { @@ -599,9 +635,9 @@ void P073_data_struct::FillBufferWithDash() { void P073_data_struct::ClearBuffer() { memset(showbuffer, - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND binaryData ? 0 : - # endif // P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND 10, sizeof(showbuffer)); for (uint8_t i = 0; i < 8; ++i) { @@ -613,7 +649,7 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, uint8_t fontset) { uint8_t position = 10; - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS const String specialChars = F(" -^=/_%@.,;:+*#!?'\"<>\\()|"); const String chnorux = F("CHNORUX"); @@ -637,7 +673,7 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, break; case 3: // dSEG7 (same table size as 7Dgt) default: // Original fontset (7Dgt) - # endif // P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS if (isDigit(character)) { position = character - '0'; @@ -653,10 +689,10 @@ uint8_t P073_data_struct::mapCharToFontPosition(char character, case '_': position = 15; break; } } - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS } - # endif // P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS return position; } @@ -677,7 +713,7 @@ uint8_t P073_data_struct::mapMAX7219FontToTM1673Font(uint8_t character) { uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, uint8_t fontset) { - # ifdef P073_EXTRA_FONTS + # if P073_EXTRA_FONTS switch (fontset) { case 1: // Siekoo @@ -688,9 +724,1203 @@ uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, default: // Standard fontset return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); } - # else // ifdef P073_EXTRA_FONTS + # else // if P073_EXTRA_FONTS return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); - # endif // ifdef P073_EXTRA_FONTS + # endif // if P073_EXTRA_FONTS +} + +bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { + if (output == P073_DISP_MANUAL) { + return false; + } + + if ((output == P073_DISP_CLOCK24BLNK) || + (output == P073_DISP_CLOCK12BLNK)) { + timesep = !timesep; + } else { + timesep = true; + } + + if (output == P073_DISP_DATE) { + FillBufferWithDate(true, 0, 0, 0, + # if P073_SUPPRESS_ZERO + suppressLeading0 + # else // if P073_SUPPRESS_ZERO + false + # endif // if P073_SUPPRESS_ZERO + ); + } else { + FillBufferWithTime(true, 0, 0, 0, !((output == P073_DISP_CLOCK24BLNK) || + (output == P073_DISP_CLOCK24)), + # if P073_SUPPRESS_ZERO + suppressLeading0 + # else // if P073_SUPPRESS_ZERO + false + # endif // if P073_SUPPRESS_ZERO + ); + } + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowTimeTemp4(timesep, 0); + break; + case P073_TM1637_6DGT: + + if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { + tm1637_ShowDate6(); + } else { + tm1637_ShowTime6(); + } + break; + case P073_MAX7219_8DGT: + + if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { + max7219_ShowDate(pin1, pin2, pin3); + } else { + max7219_ShowTime(pin1, pin2, pin3, timesep); + } + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_AdjustBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + return true; +} + +# if P073_SCROLL_TEXT +bool P073_data_struct::plugin_ten_per_second(struct EventStruct *event) { + if ((output != P073_DISP_MANUAL) || !isScrollEnabled()) { + return false; + } + + if (NextScroll()) { + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: { + tm1637_ShowBuffer(0, 4 + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + break; + } + case P073_TM1637_6DGT: { + tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays + tm1637_ShowBuffer(0, 6 + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + break; + } + case P073_MAX7219_8DGT: { + dotpos = -1; // avoid to display the dot + max7219_ShowBuffer(pin1, pin2, pin3); + break; + } + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: { + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + } + # endif // if P073_USE_74HC595 + } + } + return true; +} + +# endif // if P073_SCROLL_TEXT + +const char p073_commands[] PROGMEM = + "7dn|7dt" + # if P073_7DDT_COMMAND + "7ddt|" + # endif // if P073_7DDT_COMMAND + "7dst|7dsd|7dtext|" + # if P073_EXTRA_FONTS + "7dfont|" + # endif // if P073_EXTRA_FONTS + # if P073_7DBIN_COMMAND + "7dbin|" + # endif // if P073_7DBIN_COMMAND + "7don|7doff|7db|7output|" +; +enum class p073_commands_e : int8_t { + invalid = -1, + c7dn = 0, + c7dt, + # if P073_7DDT_COMMAND + c7ddt, + # endif // if P073_7DDT_COMMAND + c7dst, + c7dsd, + c7dtext, + # if P073_EXTRA_FONTS + c7dfont, + # endif // if P073_EXTRA_FONTS + # if P073_7DBIN_COMMAND + c7dbin, + # endif // if P073_7DBIN_COMMAND + c7don, + c7doff, + c7db, + c7output, +}; + +bool P073_data_struct::p073_plugin_write(struct EventStruct *event, + const String & string) { + const String cmd_s = parseString(string, 1); + + if ((cmd_s.length() < 3) || (cmd_s[0] != '7')) { return false; } + + # if P073_SCROLL_TEXT + const bool currentScroll = isScrollEnabled(); // Save current state + bool newScroll = false; // disable scroll if command changes + setScrollEnabled(false); + # endif // if P073_SCROLL_TEXT + + const int cmd_i = GetCommandCode(cmd_s.c_str(), p073_commands); + + if (cmd_i < 0) { return false; } // Fail fast + + const p073_commands_e cmd = static_cast(cmd_i); + + const String text = parseStringToEndKeepCase(string, 2); + bool success = false; + bool displayon = false; + + switch (cmd) { + case p073_commands_e::c7dn: + return plugin_write_7dn(event, text); + case p073_commands_e::c7dt: + return plugin_write_7dt(text); + # if P073_7DDT_COMMAND + case p073_commands_e::c7ddt: + return plugin_write_7ddt(text); + # endif // if P073_7DDT_COMMAND + case p073_commands_e::c7dst: + return plugin_write_7dst(event); + case p073_commands_e::c7dsd: + return plugin_write_7dsd(event); + case p073_commands_e::c7dtext: + # if P073_SCROLL_TEXT + setScrollEnabled(true); // Scrolling allowed for 7dtext command + # endif // if P073_SCROLL_TEXT + return plugin_write_7dtext(text); + # if P073_EXTRA_FONTS + case p073_commands_e::c7dfont: + # if P073_SCROLL_TEXT + setScrollEnabled(currentScroll); // Restore state + # endif // if P073_SCROLL_TEXT + return plugin_write_7dfont(event, text); + # endif // if P073_EXTRA_FONTS + # if P073_7DBIN_COMMAND + case p073_commands_e::c7dbin: + # if P073_SCROLL_TEXT + setScrollEnabled(true); // Scrolling allowed for 7dbin command + # endif // if P073_SCROLL_TEXT + return plugin_write_7dbin(text); + # endif // if P073_7DBIN_COMMAND + case p073_commands_e::c7don: + # if P073_SCROLL_TEXT + newScroll = currentScroll; // Restore state + # endif // if P073_SCROLL_TEXT + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("7DGT : Display ON")); + # endif // ifndef BUILD_NO_DEBUG + displayon = true; + success = true; + break; + case p073_commands_e::c7doff: + # if P073_SCROLL_TEXT + newScroll = currentScroll; // Restore state + # endif // if P073_SCROLL_TEXT + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("7DGT : Display OFF")); + # endif // ifndef BUILD_NO_DEBUG + displayon = false; + success = true; + break; + case p073_commands_e::c7db: + # if P073_SCROLL_TEXT + newScroll = currentScroll; // Restore state + # endif // if P073_SCROLL_TEXT + + if ((event->Par1 >= 0) && (event->Par1 < 16)) { + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : Brightness="), event->Par1)); + } + # endif // ifndef BUILD_NO_DEBUG + brightness = event->Par1; + P073_CFG_BRIGHTNESS = event->Par1; + displayon = true; + success = true; + } + break; + case p073_commands_e::c7output: + + if ((event->Par1 >= 0) && (event->Par1 < 6)) { // 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink", + // 3:"Clock 12h - Blink",4:"Clock 12h - No Blink",5:"Date" + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : Display output="), event->Par1)); + } + # endif // ifndef BUILD_NO_DEBUG + output = event->Par1; + P073_CFG_OUTPUTTYPE = event->Par1; + displayon = true; + success = true; + # if P073_SCROLL_TEXT + + if (event->Par1 == 0) { newScroll = currentScroll; } // Restore state + # endif // if P073_SCROLL_TEXT + } + break; + case p073_commands_e::invalid: + break; + } + + if (success) { + # if P073_SCROLL_TEXT + setScrollEnabled(newScroll); + # endif // if P073_SCROLL_TEXT + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + case P073_TM1637_6DGT: + tm1637_SetPowerBrightness(pin1, pin2, brightness / 2, displayon); + break; + case P073_MAX7219_8DGT: + max7219_SetPowerBrightness(pin1, pin2, pin3, brightness, displayon); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + // 74HC595 don't have a brightness setting + break; + # endif // if P073_USE_74HC595 + } + } + return success; +} + +void P073_data_struct::getDisplayLimits(int32_t& lLimit, + int32_t& uLimit, + int8_t offset, + uint8_t digits) { + uint8_t dgts = p073_getDefaultDigits(displayModel); + + # if P073_USE_74HC595 + + if (P073_74HC595_2_8DGT == displayModel) { + dgts = digits; + } + # endif // if P073_USE_74HC595 + dgts -= offset; // Subtract an offset, used for extra symbol + lLimit = -pow10(dgts - 1); // Lowest value we can display - 1 + uLimit = pow10(dgts); // Highest value we can display + 1 + // TODO disable log + // addLog(LOG_LEVEL_INFO, strformat(F("P073: limits: %d digits(%d), lower: %d, upper: %d"), dgts, offset, lLimit, uLimit)); +} + +bool P073_data_struct::plugin_write_7dn(struct EventStruct *event, + const String & text) { + if (output != P073_DISP_MANUAL) { + return false; + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : Show Number="), event->Par1)); + } + # endif // ifndef BUILD_NO_DEBUG + + int32_t lLimit = 0; + int32_t uLimit = 0; + getDisplayLimits(lLimit, uLimit, 0, digits); + + if (!text.isEmpty()) { + if ((event->Par1 > lLimit) && (event->Par1 < uLimit)) { + FillBufferWithNumber(text.c_str()); + } else { + FillBufferWithDash(); + } + } + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowBuffer(TM1637_4DIGIT, 8); + break; + case P073_TM1637_6DGT: + tm1637_SwapDigitInBuffer(2); // only needed for 6-digits displays + tm1637_ShowBuffer(TM1637_6DIGIT, 8); + break; + case P073_MAX7219_8DGT: + max7219_ShowBuffer(pin1, pin2, pin3); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_AdjustBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + return true; +} + +bool P073_data_struct::plugin_write_7dt(const String& text) { + if (output != P073_DISP_MANUAL) { + return false; + } + + float p073_temptemp = 0; + bool p073_tempflagdot = false; + + if (!text.isEmpty()) { + validFloatFromString(text, p073_temptemp); + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : Show Temperature="), p073_temptemp)); + } + # endif // ifndef BUILD_NO_DEBUG + + int32_t lLimit = 0; + int32_t uLimit = 0; + getDisplayLimits(lLimit, uLimit, hideDegree ? 0 : 1, digits); + float lLimitErr = lLimit + 0.1f; + float uLimitErr = uLimit - 1.0f; + float lLimitDec = lLimit / 10.0f; + float uLimitDec = uLimit / 10.0f; + + // TODO disable log + // addLog(LOG_LEVEL_INFO, strformat(F("P073: 7dt: lErr: %.1f, uErr: %.1f, lDec: %.1f, uDec: %.1f"), + // lLimitErr, uLimitErr, lLimitDec, uLimitDec)); + + if ((p073_temptemp > uLimitErr) || (p073_temptemp < lLimitErr)) { + FillBufferWithDash(); + } else { + if ((p073_temptemp < uLimitDec) && (p073_temptemp > lLimitDec)) { + p073_temptemp = roundf(p073_temptemp * 10.0f); + p073_tempflagdot = true; + } + FillBufferWithTemp(p073_temptemp); + } + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + case P073_TM1637_6DGT: + + if ((p073_temptemp == 0) && p073_tempflagdot) { + showbuffer[5] = 0; + } + + if (P073_TM1637_6DGT == displayModel) { + tm1637_ShowTemp6(p073_tempflagdot); + } else { + tm1637_ShowTimeTemp4(p073_tempflagdot, 4); + } + break; + case P073_MAX7219_8DGT: + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("7DGT : 7dt preprocessed ="), p073_temptemp)); + } + # endif // ifdef P073_DEBUG + + max7219_ShowTemp(pin1, pin2, pin3, hideDegree ? 6 : 5, -1); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_AdjustBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + # ifdef P073_DEBUG + LogBufferContent(F("7dt")); + # endif // ifdef P073_DEBUG + return true; +} + +# if P073_7DDT_COMMAND +bool P073_data_struct::plugin_write_7ddt(const String& text) { + if (output != P073_DISP_MANUAL) { + return false; + } + + float p073_lefttemp = 0.0f; + float p073_righttemp = 0.0f; + bool p073_tempflagdot = false; + + if (!text.isEmpty()) { + validFloatFromString(parseString(text, 1), p073_lefttemp); + + if (text.indexOf(',') > -1) { + validFloatFromString(parseString(text, 2), p073_righttemp); + } + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Dual Temperature 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); + } + # endif // ifndef BUILD_NO_DEBUG + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + case P073_TM1637_6DGT: + { + FillBufferWithDash(); + + if (displayModel == P073_TM1637_6DGT) { + tm1637_ShowTemp6(p073_tempflagdot); + } else { + tm1637_ShowTimeTemp4(p073_tempflagdot, 4); + } + break; + } + case P073_MAX7219_8DGT: + case P073_74HC595_2_8DGT: + { + uint8_t firstDot = -1; // No decimals is no dots + uint8_t secondDot = -1; + float hideFactor = hideDegree ? 10.0f : 1.0f; + + if ((p073_lefttemp > 999.99f * hideFactor) || (p073_lefttemp < -99.99f * hideFactor)) { + p073_lefttemp = -101.0f * hideFactor; // Triggers on -100 + } else { + if ((p073_lefttemp < 100.0f * hideFactor) && (p073_lefttemp > -10.0f * hideFactor)) { + p073_lefttemp = roundf(p073_lefttemp * 10.0f); + firstDot = hideDegree ? 2 : 1; + } + } + + if ((p073_righttemp > 999.99f * hideFactor) || (p073_righttemp < -99.99f * hideFactor)) { + p073_righttemp = -101.0f * hideFactor; + } else { + if ((p073_righttemp < 100.0f * hideFactor) && (p073_righttemp > -10.0f * hideFactor)) { + p073_righttemp = roundf(p073_righttemp * 10.0f); + secondDot = hideDegree ? 6 : 5; + } + } + + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("7DGT : 7ddt preprocessed 1st=%.2f 2nd=%.2f"), p073_lefttemp, p073_righttemp)); + } + # endif // ifdef P073_DEBUG + + FillBufferWithDualTemp(p073_lefttemp, firstDot > -1, p073_righttemp, secondDot > -1); + + if (P073_MAX7219_8DGT == displayModel) { + bool alignSave = rightAlignTempMAX7219; // Save setting + rightAlignTempMAX7219 = true; + + max7219_ShowTemp(pin1, pin2, pin3, firstDot, secondDot); + + rightAlignTempMAX7219 = alignSave; // Restore + # if P073_USE_74HC595 + } else + + // if (P073_74HC595_2_8DGT == P073_data->displayModel) + { + if (digits < 8) { + FillBufferWithDash(); + } + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + # endif // if P073_USE_74HC595 + } + + break; + } + } + # ifdef P073_DEBUG + LogBufferContent(F("7ddt")); + # endif // ifdef P073_DEBUG + return true; +} + +# endif // if P073_7DDT_COMMAND + +bool P073_data_struct::plugin_write_7dst(struct EventStruct *event) { + if (output != P073_DISP_MANUAL) { + return false; + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Time=%02d:%02d:%02d"), event->Par1, event->Par2, event->Par3)); + } + # endif // ifndef BUILD_NO_DEBUG + timesep = true; + FillBufferWithTime(false, event->Par1, event->Par2, event->Par3, false, + # if P073_SUPPRESS_ZERO + suppressLeading0 + # else // if P073_SUPPRESS_ZERO + false + # endif // if P073_SUPPRESS_ZERO + ); + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowTimeTemp4(timesep, 0); + break; + case P073_TM1637_6DGT: + tm1637_ShowTime6(); + break; + case P073_MAX7219_8DGT: + max7219_ShowTime(pin1, pin2, pin3, timesep); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_AdjustBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + return true; +} + +bool P073_data_struct::plugin_write_7dsd(struct EventStruct *event) { + if (output != P073_DISP_MANUAL) { + return false; + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("7DGT : Show Date=%02d:%02d:%02d"), event->Par1, event->Par2, event->Par3)); + } + # endif // ifndef BUILD_NO_DEBUG + FillBufferWithDate(false, event->Par1, event->Par2, event->Par3, + # if P073_SUPPRESS_ZERO + suppressLeading0 + # else // if P073_SUPPRESS_ZERO + false + # endif // if P073_SUPPRESS_ZERO + ); + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowTimeTemp4(timesep, 0); + break; + case P073_TM1637_6DGT: + tm1637_ShowDate6(); + break; + case P073_MAX7219_8DGT: + max7219_ShowDate(pin1, pin2, pin3); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + hc595_AdjustBuffer(); + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + return true; +} + +bool P073_data_struct::plugin_write_7dtext(const String& text) { + if (output != P073_DISP_MANUAL) { + return false; + } + + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("7DGT : Show Text="), text)); + } + # endif // ifndef BUILD_NO_DEBUG + # if P073_SCROLL_TEXT + setTextToScroll(EMPTY_STRING); + uint8_t bufLen = p073_getDefaultDigits(displayModel, digits); + + if (isScrollEnabled() && (getEffectiveTextLength(text) > bufLen)) { + setTextToScroll(text); + } else + # endif // if P073_SCROLL_TEXT + { + FillBufferWithString(text); + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowBuffer(0, 4); + break; + case P073_TM1637_6DGT: + tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays + tm1637_ShowBuffer(0, 6); + break; + case P073_MAX7219_8DGT: + dotpos = -1; // avoid to display the dot + max7219_ShowBuffer(pin1, pin2, pin3); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + } + return true; +} + +# if P073_EXTRA_FONTS +bool P073_data_struct::plugin_write_7dfont(struct EventStruct *event, + const String & text) { + if (!text.isEmpty()) { + const String fontArg = parseString(text, 1); + int32_t fontNr = -1; + + if ((equals(fontArg, F("default"))) || (equals(fontArg, F("7dgt")))) { + fontNr = 0; + } else if (equals(fontArg, F("siekoo"))) { + fontNr = 1; + } else if (equals(fontArg, F("siekoo_upper"))) { + fontNr = 2; + } else if (equals(fontArg, F("dseg7"))) { + fontNr = 3; + } else if (!validIntFromString(text, fontNr)) { + fontNr = -1; // reset if invalid + } + + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("P073 7dfont,%s -> %d"), fontArg.c_str(), fontNr)); + } + # endif // ifdef P073_DEBUG + + if ((fontNr >= 0) && (fontNr <= 3)) { + fontset = fontNr; + P073_CFG_FONTSET = fontNr; + return true; + } + } + return false; +} + +# endif // if P073_EXTRA_FONTS + +# if P073_7DBIN_COMMAND +bool P073_data_struct::plugin_write_7dbin(const String& text) { + if (!text.isEmpty()) { + String data; + int32_t byteValue{}; + int arg = 1; + String argValue = parseString(text, arg); + + while (!argValue.isEmpty()) { + if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { + data += static_cast(displayModel == P073_MAX7219_8DGT ? + byteValue : + mapMAX7219FontToTM1673Font(byteValue)); + } + arg++; + argValue = parseString(text, arg); + } + # if P073_SCROLL_TEXT + const uint8_t bufLen = p073_getDefaultDigits(displayModel, digits); + # endif // if P073_SCROLL_TEXT + + if (!data.isEmpty()) { + # if P073_SCROLL_TEXT + setTextToScroll(EMPTY_STRING); // Clear any scrolling text + + if (isScrollEnabled() && (data.length() > bufLen)) { + setBinaryData(data); + } else + # endif // if P073_SCROLL_TEXT + { + FillBufferWithString(data, true); + + switch (displayModel) { + case P073_TM1637_4DGTCOLON: + case P073_TM1637_4DGTDOTS: + tm1637_ShowBuffer(0, 4); + break; + case P073_TM1637_6DGT: + tm1637_SwapDigitInBuffer(0); // only needed for 6-digits displays + tm1637_ShowBuffer(0, 6, true); + break; + case P073_MAX7219_8DGT: + dotpos = -1; // avoid to display the dot + max7219_ShowBuffer(pin1, pin2, pin3); + break; + # if P073_USE_74HC595 + case P073_74HC595_2_8DGT: + + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing + hc595_ShowBuffer(); + } + break; + # endif // if P073_USE_74HC595 + } + } + return true; + } + } + return false; +} + +# endif // if P073_7DBIN_COMMAND + +// =================================== +// ---- TM1637 specific functions ---- +// =================================== + +# define CLK_HIGH() digitalWrite(clk_pin, HIGH) +# define CLK_LOW() digitalWrite(clk_pin, LOW) +# define DIO_HIGH() pinMode(dio_pin, INPUT) +# define DIO_LOW() pinMode(dio_pin, OUTPUT) + +void P073_data_struct::tm1637_i2cStart(uint8_t clk_pin, + uint8_t dio_pin) { + # ifdef P073_DEBUG + addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Start")); + # endif // ifdef P073_DEBUG + DIO_HIGH(); + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + DIO_LOW(); +} + +void P073_data_struct::tm1637_i2cStop(uint8_t clk_pin, + uint8_t dio_pin) { + # ifdef P073_DEBUG + addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Stop")); + # endif // ifdef P073_DEBUG + CLK_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY); + DIO_LOW(); + delayMicroseconds(TM1637_CLOCKDELAY); + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + DIO_HIGH(); +} + +void P073_data_struct::tm1637_i2cAck(uint8_t clk_pin, + uint8_t dio_pin) { + # ifdef P073_DEBUG + bool dummyAck = false; + # endif // ifdef P073_DEBUG + + CLK_LOW(); + pinMode(dio_pin, INPUT_PULLUP); + + // DIO_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + + // while(digitalRead(dio_pin)); + # ifdef P073_DEBUG + dummyAck = + # endif // ifdef P073_DEBUG + digitalRead(dio_pin); + + # ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + String log = F("7DGT : Comm ACK="); + + if (dummyAck == 0) { + log += F("TRUE"); + } else { + log += F("FALSE"); + } + addLogMove(LOG_LEVEL_DEBUG, log); + } + # endif // ifdef P073_DEBUG + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + CLK_LOW(); + pinMode(dio_pin, OUTPUT); +} + +void P073_data_struct::tm1637_i2cWrite_ack(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytesToPrint[], + uint8_t length) { + tm1637_i2cStart(clk_pin, dio_pin); + + for (uint8_t i = 0; i < length; ++i) { + tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint[i]); + } + tm1637_i2cStop(clk_pin, dio_pin); +} + +void P073_data_struct::tm1637_i2cWrite_ack(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytetoprint) { + tm1637_i2cWrite(clk_pin, dio_pin, bytetoprint); + tm1637_i2cAck(clk_pin, dio_pin); +} + +void P073_data_struct::tm1637_i2cWrite(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytetoprint) { + # ifdef P073_DEBUG + addLog(LOG_LEVEL_DEBUG, F("7DGT : WriteByte")); + # endif // ifdef P073_DEBUG + uint8_t i; + + for (i = 0; i < 8; ++i) { + CLK_LOW(); + + if (bytetoprint & 0b00000001) { + DIO_HIGH(); + } else { + DIO_LOW(); + } + delayMicroseconds(TM1637_CLOCKDELAY); + bytetoprint = bytetoprint >> 1; + CLK_HIGH(); + delayMicroseconds(TM1637_CLOCKDELAY); + } +} + +void P073_data_struct::tm1637_ClearDisplay(uint8_t clk_pin, + uint8_t dio_pin) { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 7); +} + +void P073_data_struct::tm1637_SetPowerBrightness(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t brightlvl, + bool poweron) { + # ifdef P073_DEBUG + addLog(LOG_LEVEL_INFO, F("7DGT : Set BRIGHT")); + # endif // ifdef P073_DEBUG + uint8_t brightvalue = (brightlvl & 0b111); + + if (poweron) { + brightvalue = TM1637_POWER_ON | brightvalue; + } else { + brightvalue = TM1637_POWER_OFF | brightvalue; + } + + const uint8_t byteToPrint = brightvalue; + tm1637_i2cWrite_ack(clk_pin, dio_pin, byteToPrint); +} + +void P073_data_struct::tm1637_InitDisplay(uint8_t clk_pin, + uint8_t dio_pin) { + pinMode(clk_pin, OUTPUT); + pinMode(dio_pin, OUTPUT); + CLK_HIGH(); + DIO_HIGH(); + + const uint8_t byteToPrint = 0x40; + + tm1637_i2cWrite_ack(clk_pin, dio_pin, byteToPrint); + tm1637_ClearDisplay(clk_pin, dio_pin); +} + +uint8_t P073_data_struct::tm1637_separator(uint8_t value, + bool sep) { + if (sep) { + value |= 0b10000000; + } + return value; +} + +void P073_data_struct::tm1637_ShowTime6() { + tm1637_ShowDate6(true); // deduplicated +} + +void P073_data_struct::tm1637_ShowDate6(bool showTime) { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_getFontChar(showbuffer[2], fontset); + bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1], fontset), timesep); + bytesToPrint[3] = tm1637_getFontChar(showbuffer[0], fontset); + + if (showTime) { + bytesToPrint[4] = tm1637_getFontChar(showbuffer[5], fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[4], fontset); + } else { + bytesToPrint[4] = tm1637_getFontChar(showbuffer[7], fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[6], fontset); + } + bytesToPrint[6] = tm1637_separator(tm1637_getFontChar(showbuffer[3], fontset), timesep); + + tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 7); +} + +void P073_data_struct::tm1637_ShowTemp6(bool sep) { + uint8_t bytesToPrint[7]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_separator(tm1637_getFontChar(showbuffer[5], fontset), sep); + bytesToPrint[2] = tm1637_getFontChar(showbuffer[4], fontset); + bytesToPrint[3] = tm1637_getFontChar(10, fontset); + bytesToPrint[4] = tm1637_getFontChar(10, fontset); + bytesToPrint[5] = tm1637_getFontChar(showbuffer[7], fontset); + bytesToPrint[6] = tm1637_getFontChar(showbuffer[6], fontset); + + tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 7); +} + +void P073_data_struct::tm1637_ShowTimeTemp4(bool sep, + uint8_t bufoffset) { + uint8_t bytesToPrint[5]{}; + + bytesToPrint[0] = 0xC0; + bytesToPrint[1] = tm1637_getFontChar(showbuffer[0 + bufoffset], fontset); + bytesToPrint[2] = tm1637_separator(tm1637_getFontChar(showbuffer[1 + bufoffset], fontset), sep); + bytesToPrint[3] = tm1637_getFontChar(showbuffer[2 + bufoffset], fontset); + bytesToPrint[4] = tm1637_getFontChar(showbuffer[3 + bufoffset], fontset); + + tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 5); +} + +void P073_data_struct::tm1637_SwapDigitInBuffer(uint8_t startPos) { + std::swap(showbuffer[2 + startPos], showbuffer[0 + startPos]); + std::swap(showbuffer[3 + startPos], showbuffer[5 + startPos]); + + std::swap(showperiods[2 + startPos], showperiods[0 + startPos]); + std::swap(showperiods[3 + startPos], showperiods[5 + startPos]); + + if (dotpos > -1) { + const uint8_t dotPositionSwap[] = { 0, 1, 4, 3, 2, 7, 6, 5, 8 }; + + dotpos = dotPositionSwap[dotpos]; + } +} + +void P073_data_struct::tm1637_ShowBuffer(uint8_t firstPos, + uint8_t lastPos, + bool useBinaryData) { + uint8_t bytesToPrint[8]{}; + + bytesToPrint[0] = 0xC0; + uint8_t length = 1; + + if (dotpos > -1) { + showperiods[dotpos] = true; + } + + uint8_t p073_datashowpos1; + + for (int i = firstPos; i < lastPos; ++i) { + if (useBinaryData) { + bytesToPrint[length] = showbuffer[i]; + } else { + p073_datashowpos1 = tm1637_separator( + tm1637_getFontChar(showbuffer[i], fontset), + showperiods[i]); + bytesToPrint[length] = p073_datashowpos1; + } + ++length; + } + tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, length); +} + +// ==================================== +// ---- MAX7219 specific functions ---- +// ==================================== + +# define OP_DECODEMODE 9 +# define OP_INTENSITY 10 +# define OP_SCANLIMIT 11 +# define OP_SHUTDOWN 12 +# define OP_DISPLAYTEST 15 + +void P073_data_struct::max7219_spiTransfer(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + ESPEASY_VOLATILE(uint8_t) opcode, + ESPEASY_VOLATILE(uint8_t) data) { + spidata[1] = opcode; + spidata[0] = data; + digitalWrite(cs_pin, LOW); + shiftOut(din_pin, clk_pin, MSBFIRST, spidata[1]); + shiftOut(din_pin, clk_pin, MSBFIRST, spidata[0]); + digitalWrite(cs_pin, HIGH); +} + +void P073_data_struct::max7219_ClearDisplay(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin) { + for (int i = 0; i < 8; i++) { + max7219_spiTransfer(din_pin, clk_pin, cs_pin, i + 1, 0); + } +} + +void P073_data_struct::max7219_SetPowerBrightness(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + uint8_t brightlvl, + bool poweron) { + max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_INTENSITY, brightlvl); + max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SHUTDOWN, poweron ? 1 : 0); +} + +void P073_data_struct::max7219_SetDigit(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + int dgtpos, + uint8_t dgtvalue, + bool showdot, + bool binaryData) { + uint8_t p073_tempvalue; + + if (binaryData) { + p073_tempvalue = dgtvalue; // Overwrite if binary data + } else + { + # if P073_EXTRA_FONTS + + switch (fontset) { + case 1: // Siekoo + case 2: // Siekoo with uppercase CHNORUX + p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); + break; + case 3: // dSEG7 + p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); + break; + default: // Default fontset + p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); + } + # else // if P073_EXTRA_FONTS + p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); + # endif // if P073_EXTRA_FONTS + + if (showdot) { + p073_tempvalue |= 0b10000000; + } + } + max7219_spiTransfer(din_pin, clk_pin, cs_pin, dgtpos + 1, p073_tempvalue); +} + +void P073_data_struct::max7219_InitDisplay(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin) { + pinMode(din_pin, OUTPUT); + pinMode(clk_pin, OUTPUT); + pinMode(cs_pin, OUTPUT); + digitalWrite(cs_pin, HIGH); + max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DISPLAYTEST, 0); + max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SCANLIMIT, 7); // scanlimit setup to max at Init + max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DECODEMODE, 0); + max7219_ClearDisplay(din_pin, clk_pin, cs_pin); + max7219_SetPowerBrightness(din_pin, clk_pin, cs_pin, 0, false); +} + +void P073_data_struct::max7219_ShowTime(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + bool sep) { + const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward + + for (int8_t i = 5; i >= 0; --i) { + max7219_SetDigit(din_pin, clk_pin, cs_pin, idx_list[i], showbuffer[i], false); + } + + const uint8_t sepChar = mapCharToFontPosition(sep ? '-' : ' ', fontset); + + max7219_SetDigit(din_pin, clk_pin, cs_pin, 2, sepChar, false); + max7219_SetDigit(din_pin, clk_pin, cs_pin, 5, sepChar, false); +} + +void P073_data_struct::max7219_ShowTemp(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + int8_t firstDot, + int8_t secondDot) { + max7219_SetDigit(din_pin, clk_pin, cs_pin, 0, 10, false); + + if (firstDot > -1) { showperiods[firstDot] = true; } + + if (secondDot > -1) { showperiods[secondDot] = true; } + + const int alignRight = rightAlignTempMAX7219 ? 0 : 1; + + for (int i = alignRight; i < 8; ++i) { + const int bufIndex = (7 + alignRight) - i; + + if (bufIndex < 8) { + max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + showbuffer[bufIndex], + showperiods[bufIndex]); + } + } +} + +void P073_data_struct::max7219_ShowDate(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin) { + const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; + + for (int i = 0; i < 8; ++i) { + max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + showbuffer[7 - i], + dotflags[7 - i]); + } +} + +void P073_data_struct::max7219_ShowBuffer(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin) { + if (dotpos > -1) { + showperiods[dotpos] = true; + } + + for (int i = 0; i < 8; i++) { + max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + showbuffer[7 - i], + showperiods[7 - i] + # if P073_7DBIN_COMMAND + , binaryData + # endif // if P073_7DBIN_COMMAND + ); + } } #endif // ifdef USES_P073 diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index fe58e1fefa..ae85afdcde 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -32,28 +32,56 @@ # define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display # define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display -# define P073_7DDT_COMMAND // Enable 7ddt by default -# define P073_EXTRA_FONTS // Enable extra fonts -# define P073_SCROLL_TEXT // Enable scrolling of 7dtext by default -# define P073_7DBIN_COMMAND // Enable input of binary data via 7dbin,uint8_t,... command -# define P073_SUPPRESS_ZERO // Enable Suppress leading zero on day/hour -# define P073_USE_74HC595 // Enable support for 74HC595 based (sequential and multiplexing) displays +# ifndef P073_7DDT_COMMAND +# define P073_7DDT_COMMAND 1 // Enable 7ddt by default +# endif // ifndef P073_7DDT_COMMAND +# ifndef P073_EXTRA_FONTS +# define P073_EXTRA_FONTS 1 // Enable extra fonts +# endif // ifndef P073_EXTRA_FONTS +# ifndef P073_SCROLL_TEXT +# define P073_SCROLL_TEXT 1 // Enable scrolling of 7dtext by default +# endif // ifndef P073_SCROLL_TEXT +# ifndef P073_7DBIN_COMMAND +# define P073_7DBIN_COMMAND 1 // Enable input of binary data via 7dbin,uint8_t,... command +# endif // ifndef P073_7DBIN_COMMAND +# ifndef P073_SUPPRESS_ZERO +# define P073_SUPPRESS_ZERO 1 // Enable Suppress leading zero on day/hour +# endif // ifndef P073_SUPPRESS_ZERO +# ifndef P073_USE_74HC595 +# define P073_USE_74HC595 1 // Enable support for 74HC595 based (sequential and multiplexing) displays +# endif // ifndef P073_USE_74HC595 # if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) -# undef P073_7DDT_COMMAND // Optionally activate if .bin file space is problematic, remove the 7ddt command -# undef P073_EXTRA_FONTS // Optionally activate if .bin file space is problematic, remove the font selection and 7dfont command -# undef P073_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature -# undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command -# undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature +# if P073_7DDT_COMMAND +# undef P073_7DDT_COMMAND // Optionally activate if .bin file space is problematic, remove the 7ddt command +# define P073_7DDT_COMMAND 0 +# endif // if P073_7DDT_COMMAND +# if P073_EXTRA_FONTS +# undef P073_EXTRA_FONTS // Optionally activate if .bin file space is problematic, remove the font selection and 7dfont command +# define P073_EXTRA_FONTS 0 +# endif // if P073_EXTRA_FONTS +# if P073_SCROLL_TEXT +# undef P073_SCROLL_TEXT // Optionally activate if .bin file space is problematic, remove the scrolling text feature +# define P073_SCROLL_TEXT 0 +# endif // if P073_SCROLL_TEXT +# if P073_7DBIN_COMMAND +# undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is problematic, remove the 7dbin command +# define P073_7DBIN_COMMAND 0 +# endif // if P073_7DBIN_COMMAND +# if P073_SUPPRESS_ZERO +# undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature +# define P073_SUPPRESS_ZERO 0 +# endif // if P073_SUPPRESS_ZERO # else // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) // # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug # endif // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) # if defined(ESP8266) -# ifdef P073_USE_74HC595 +# if P073_USE_74HC595 # undef P073_USE_74HC595 // Removes the support for 74HC595 displays -# endif // ifdef P073_USE_74HC595 +# define P073_USE_74HC595 0 +# endif // if P073_USE_74HC595 # endif // if defined(ESP8266) # define TM1637_POWER_ON 0b10001000 @@ -84,7 +112,7 @@ static const uint8_t DefaultCharTable[42] PROGMEM = { 0b01111110, 0b01100111, 0b01101011, 0b01100110, 0b01011011, 0b00001111, 0b00111110, 0b00111110, 0b00101010, 0b00110111, 0b00111011, 0b01101101 }; -# ifdef P073_EXTRA_FONTS +# if P073_EXTRA_FONTS // Siekoo alphabet https://www.fakoo.de/siekoo // as the 'over score' character isn't normally available, the pipe "|" is used for that, and for degree the "^"" is used @@ -169,17 +197,16 @@ struct P073_data_struct : public PluginTaskData_base { virtual ~P073_data_struct() = default; void init(struct EventStruct *event); - # ifdef P073_USE_74HC595 - bool plugin_fifty_per_second(struct EventStruct *event); - void hc595_InitDisplay(); - void hc595_ShowBuffer(); - void hc595_AdjustBuffer(); - bool hc595_Sequential() { - return P073_HC595_SEQUENTIAL; - } - - # endif // ifdef P073_USE_74HC595 + bool p073_plugin_write(struct EventStruct *event, + const String & string); + bool plugin_once_a_second(struct EventStruct *event); + # if P073_SCROLL_TEXT + bool plugin_ten_per_second(struct EventStruct *event); + # endif // if P073_SCROLL_TEXT + # if P073_USE_74HC595 + bool plugin_fifty_per_second(struct EventStruct *event); + # endif // if P073_USE_74HC595 void FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, uint8_t sevendgt_minutes, @@ -195,32 +222,32 @@ struct P073_data_struct : public PluginTaskData_base { const uint8_t nr2, const uint8_t nr3, const int8_t nr4 - # ifdef P073_SUPPRESS_ZERO + # if P073_SUPPRESS_ZERO , const bool suppressLeading0 - # endif // ifdef P073_SUPPRESS_ZERO + # endif // if P073_SUPPRESS_ZERO ); void FillBufferWithNumber(const String& number); void FillBufferWithTemp(int temperature); - # ifdef P073_7DDT_COMMAND + # if P073_7DDT_COMMAND void FillBufferWithDualTemp(int leftTemperature, bool leftWithDecimal, int rightTemperature, bool rightWithDecimal); - # endif // ifdef P073_7DDT_COMMAND + # endif // if P073_7DDT_COMMAND void FillBufferWithString(const String& textToShow, bool useBinaryData = false); - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT int getEffectiveTextLength(const String& text); bool NextScroll(); void setTextToScroll(const String& text); void setScrollSpeed(uint8_t speed); bool isScrollEnabled(); void setScrollEnabled(bool scroll); - # endif // ifdef P073_SCROLL_TEXT - # ifdef P073_7DBIN_COMMAND + # endif // if P073_SCROLL_TEXT + # if P073_7DBIN_COMMAND void setBinaryData(const String& data); - # endif // ifdef P073_7DBIN_COMMAND + # endif // if P073_7DBIN_COMMAND # ifdef P073_DEBUG void LogBufferContent(String prefix); # endif // ifdef P073_DEBUG @@ -249,11 +276,12 @@ struct P073_data_struct : public PluginTaskData_base { bool periods = false; bool hideDegree = false; bool rightAlignTempMAX7219 = false; + bool suppressLeading0 = false; uint8_t fontset = 0; - # ifdef P073_7DBIN_COMMAND + # if P073_7DBIN_COMMAND bool binaryData = false; # endif // P073_7DBIN_COMMAND - # ifdef P073_SCROLL_TEXT + # if P073_SCROLL_TEXT bool txtScrolling = false; bool scrollAllowed = false; uint16_t scrollCount = 0; @@ -270,9 +298,118 @@ struct P073_data_struct : public PluginTaskData_base { # ifdef P073_DEBUG uint32_t counter50 = 0; # endif // ifdef P073_DEBUG - # ifdef P073_USE_74HC595 + # if P073_USE_74HC595 bool isSequential = false; - # endif // ifdef P073_USE_74HC595 + # endif // if P073_USE_74HC595 + +private: + + void getDisplayLimits(int32_t& lLimit, + int32_t& uLimit, + int8_t offset = 0, + uint8_t digits = 0); + bool plugin_write_7dn(struct EventStruct *event, + const String & text); + bool plugin_write_7dt(const String& text); + # if P073_7DDT_COMMAND + bool plugin_write_7ddt(const String& text); + # endif // if P073_7DDT_COMMAND + bool plugin_write_7dst(struct EventStruct *event); + bool plugin_write_7dsd(struct EventStruct *event); + bool plugin_write_7dtext(const String& text); + # if P073_EXTRA_FONTS + bool plugin_write_7dfont(struct EventStruct *event, + const String & text); + # endif // if P073_EXTRA_FONTS + # if P073_7DBIN_COMMAND + bool plugin_write_7dbin(const String& text); + # endif // if P073_7DBIN_COMMAND + + // ---- TM1637 specific functions ---- + void tm1637_i2cStart(uint8_t clk_pin, + uint8_t dio_pin); + void tm1637_i2cStop(uint8_t clk_pin, + uint8_t dio_pin); + void tm1637_i2cAck(uint8_t clk_pin, + uint8_t dio_pin); + void tm1637_i2cWrite_ack(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytesToPrint[], + uint8_t length); + void tm1637_i2cWrite_ack(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytetoprint); + void tm1637_i2cWrite(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t bytetoprint); + void tm1637_ClearDisplay(uint8_t clk_pin, + uint8_t dio_pin); + void tm1637_SetPowerBrightness(uint8_t clk_pin, + uint8_t dio_pin, + uint8_t brightlvl, + bool poweron); + void tm1637_InitDisplay(uint8_t clk_pin, + uint8_t dio_pin); + uint8_t tm1637_separator(uint8_t value, + bool sep); + void tm1637_ShowTime6(); + void tm1637_ShowDate6(bool showTime = false); + void tm1637_ShowTemp6(bool sep); + void tm1637_ShowTimeTemp4(bool sep, + uint8_t bufoffset); + void tm1637_SwapDigitInBuffer(uint8_t startPos); + void tm1637_ShowBuffer(uint8_t firstPos, + uint8_t lastPos, + bool useBinaryData = false); + + // ---- MAX7219 specific functions ---- + void max7219_spiTransfer(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + ESPEASY_VOLATILE(uint8_t) opcode, + ESPEASY_VOLATILE(uint8_t) data); + void max7219_ClearDisplay(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin); + void max7219_SetPowerBrightness(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + uint8_t brightlvl, + bool poweron); + void max7219_SetDigit(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + int dgtpos, + uint8_t dgtvalue, + bool showdot, + bool binaryData = false); + void max7219_InitDisplay(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin); + void max7219_ShowTime(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + bool sep); + void max7219_ShowTemp(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin, + int8_t firstDot, + int8_t secondDot); + void max7219_ShowDate(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin); + void max7219_ShowBuffer(uint8_t din_pin, + uint8_t clk_pin, + uint8_t cs_pin); + # if P073_USE_74HC595 + void hc595_InitDisplay(); + void hc595_ShowBuffer(); + void hc595_AdjustBuffer(); + bool hc595_Sequential() { + return P073_HC595_SEQUENTIAL; + } + + # endif // if P073_USE_74HC595 }; #endif // ifdef USES_P073 From 07b95d7fce2c7a840a2dbb4045bacc13366043bf Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 6 Aug 2024 14:30:30 +0200 Subject: [PATCH 07/21] [P073] Make 7-segment font functions publicly available --- src/src/PluginStructs/P073_data_struct.cpp | 77 ++++++++++++++++++++++ src/src/PluginStructs/P073_data_struct.h | 4 ++ 2 files changed, 81 insertions(+) diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index a2c4fb9fcf..e29d34b698 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -20,6 +20,83 @@ uint8_t p073_getDefaultDigits(uint8_t displayModel, return bufLen; } +/** + * Maps an ASCII character to a generic 7-segment usable smaller characterset, + * for easy mapping to different font-sets, see P073_getFontChar() + */ +uint8_t P073_mapCharToFontPosition(char character, + uint8_t fontset) { + uint8_t position = 10; + + # if P073_EXTRA_FONTS + const String specialChars = F(" -^=/_%@.,;:+*#!?'\"<>\\()|"); + const String chnorux = F("CHNORUX"); + + switch (fontset) { + case 1: // Siekoo + case 2: // Siekoo with uppercase 'CHNORUX' + + if ((fontset == 2) && (chnorux.indexOf(character) > -1)) { + position = chnorux.indexOf(character) + 35; + } else if (isDigit(character)) { + position = character - '0'; + } else if (isAlpha(character)) { + position = character - (isLowerCase(character) ? 'a' : 'A') + 42; + } else { + const int idx = specialChars.indexOf(character); + + if (idx > -1) { + position = idx + 10; + } + } + break; + case 3: // dSEG7 (same table size as 7Dgt) + default: // Original fontset (7Dgt) + # endif // if P073_EXTRA_FONTS + + if (isDigit(character)) { + position = character - '0'; + } else if (isAlpha(character)) { + position = character - (isLowerCase(character) ? 'a' : 'A') + 16; + } else { + switch (character) { + case ' ': position = 10; break; + case '-': position = 11; break; + case '^': position = 12; break; // degree + case '=': position = 13; break; + case '/': position = 14; break; + case '_': position = 15; break; + } + } + # if P073_EXTRA_FONTS +} + + # endif // if P073_EXTRA_FONTS + return position; +} + +/** + * Get the 7-segment representation for an index into a specific 7-segment font + * Fonts available depend on the build, but the 'DefaultCharTable' is always available + */ +uint8_t P073_getFontChar(uint8_t index, + uint8_t fontset) { + # if P073_EXTRA_FONTS + + switch (fontset) { + case 1: // Siekoo + case 2: // Siekoo uppercase CHNORUX + return pgm_read_byte(&(SiekooCharTable[index])); + case 3: // dSEG7 + return pgm_read_byte(&(Dseg7CharTable[index])); + default: // Standard fontset + return pgm_read_byte(&(DefaultCharTable[index])); + } + # else // if P073_EXTRA_FONTS + return pgm_read_byte(&(DefaultCharTable[index])); + # endif // if P073_EXTRA_FONTS +} + void P073_data_struct::init(struct EventStruct *event) { ClearBuffer(); diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index ae85afdcde..dff8d87bde 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -189,6 +189,10 @@ static const uint8_t Dseg7CharTable[42] PROGMEM = { uint8_t p073_getDefaultDigits(uint8_t displayModel, uint8_t digits = 0); +uint8_t P073_mapCharToFontPosition(char character, + uint8_t fontset); +uint8_t P073_getFontChar(uint8_t index, + uint8_t fontset); struct P073_data_struct : public PluginTaskData_base { public: From 9759ec6ce5cea7a1c16b28b33ff36c73919411c2 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 6 Aug 2024 16:40:27 +0200 Subject: [PATCH 08/21] [P073] Separate 74HC595 multiplexed displays, code improvements --- src/_P073_7DGT.ino | 76 +++- src/src/PluginStructs/P073_data_struct.cpp | 426 ++++++++------------- src/src/PluginStructs/P073_data_struct.h | 126 +++--- 3 files changed, 268 insertions(+), 360 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 338194e4d5..131514f4a2 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -10,13 +10,13 @@ // 1 - TM1637 -- 2 pins - 4 digits and dot on each digit (X.X.X.X.) // 2 - TM1637 -- 2 pins - 6 digits and dot on each digit (X.X.X.X.X.X.) // 3 - MAX7219/21 -- 3 pins - 8 digits and dot on each digit (X.X.X.X.X.X.X.X.) -// 4 - 74HC595 xDgt 3 pins - 2,2+2,3,3+2,2+3,4,6,3+3,8 digits and dot on each digit (X.X. .. X.X.X.X.X.X.X.X.) +// 4 - 74HC595 xDgt 3 pins - 2,2+2,3,3+2,2+3,4,4+4,6,3+3,3+4,4+3,8 digits and dot on each digit (X.X. .. X.X.X.X.X.X.X.X.) // // Plugin can be setup as: // - Manual -- display is manually updated sending commands // "7dn," (number can be negative or positive, even with decimal) // "7dt," (temperature can be negative or positive and containing decimals) -// "7ddt,," (Dual temperatures on Max7219 (8 digits) only, temperature can be negative or +// "7ddt,," (Dual temperatures on Max7219/74HC595 (8 digits) only, temperature can be negative or // positive and containing decimals) // "7dst,,," (show manual time -not current-, no checks done on numbers validity!) // "7dsd,
,," (show manual date -not current-, no checks done on numbers validity!) @@ -27,11 +27,6 @@ // dSEG7 : https://www.keshikan.net/fonts-e.html // "7dbin,[uint8_t],..." (show data binary formatted, bits clock-wise from left to right, dot, top, right 2x, bottom, // left 2x, center), scroll-enabled -// - Clock-Blink -- display is automatically updated with current time and blinking dot/lines -// - Clock-NoBlink -- display is automatically updated with current time and steady dot/lines -// - Clock12-Blink -- display is automatically updated with current time (12h clock) and blinking dot/lines -// - Clock12-NoBlink -- display is automatically updated with current time (12h clock) and steady dot/lines -// - Date -- display is automatically updated with current date // // Generic commands: // - "7don" -- turn ON the display @@ -39,10 +34,18 @@ // - "7db,<0-15> -- set brightness to specific value between 0 and 15 // - "7output,<0-5> -- select display output mode, 0:"Manual",1:"Clock 24h - Blink",2:"Clock 24h - No Blink",3:"Clock 12h - Blink",4:"Clock // 12h - No Blink",5:"Date" -// - "7dfont," -- Select the active font by name or number: 0/default, 1/siekoo, 2/siekoo_upper, 3/dseg7 +// - Clock-Blink -- display is automatically updated with current time and blinking dot/lines +// - Clock-NoBlink -- display is automatically updated with current time and steady dot/lines +// - Clock12-Blink -- display is automatically updated with current time (12h clock) and blinking dot/lines +// - Clock12-NoBlink -- display is automatically updated with current time (12h clock) and steady dot/lines +// - Date -- display is automatically updated with current date // /** History + * 2024-08-06 tonhuisman: Make 74HC595 multiplexed displays a separate compile-time option, as these require special treatment + * Separate 7-segment font-related functions for re-use by other plugins + * Size reduction by removing now unneeded function pin arguments + * 2024-07-30 tonhuisman: Add support for larger combinations of sequential displays, 2..8 digits * 2024-07-27 tonhuisman: Move most code to P073 PluginStruct and remove now unneeded code, use explicit compile-time defines (0/1) * 2024-07-24 tonhuisman: Fixed the issue that most extended features where not included in the MAX or ESP32 builds * 2024-07-20 tonhuisman: Implement 74HC595 7-segment displays (2, 2+2, 3, 2+3, 3+2, 4, 6, 3+3 and 8 digits) @@ -113,7 +116,11 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) P073_CFG_SCROLLSPEED = 10; // Default 10 * 0.1 sec scroll speed # endif // if P073_SCROLL_TEXT # if P073_USE_74HC595 - P073_CFG_DIGITS = 4; // Default number of digits + # if P073_USE_74HCMULTIPLEX + P073_CFG_DIGITS = 4; // Default number of digits + # else // if P073_USE_74HCMULTIPLEX + P073_CFG_DIGITS = 9; // Default number of digits code, 9 = 4 sequential + # endif // if P073_USE_74HCMULTIPLEX # endif // if P073_USE_74HC595 break; } @@ -123,7 +130,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) addFormNote(F("TM1637: 1st=CLK-Pin, 2nd=DIO-Pin")); addFormNote(F("MAX7219: 1st=DIN-Pin, 2nd=CLK-Pin, 3rd=CS-Pin")); # if P073_USE_74HC595 - addFormNote(F("74HC595: 1st=SDI-Pin, 2nd=CLK-Pin, 3rd=LOAD-Pin")); + addFormNote(F("74HC595: 1st=SDI/DIO-Pin, 2nd=CLK/SCLK-Pin, 3rd=LOAD/RCLK-Pin")); # endif // if P073_USE_74HC595 { const __FlashStringHelper *displtype[] = { F("TM1637 - 4 digit (colon)"), @@ -140,15 +147,55 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) if (P073_74HC595_2_8DGT == P073_CFG_DISPLAYTYPE) { if (0 == P073_CFG_DIGITS) { + # if P073_USE_74HCMULTIPLEX P073_CFG_DIGITS = 4; + # else // if P073_USE_74HCMULTIPLEX + P073_CFG_DIGITS = 9; + # endif // if P073_USE_74HCMULTIPLEX } - const __FlashStringHelper *digits[] = { F("2"), F("2+2"), F("3"), F("4"), F("3+2 / 2+3"), F("6"), F("3+3"), F("8") }; - const int digitsOptions[] = { 2, 1, 3, 4, 5, 6, 7, 8 }; + const __FlashStringHelper *digits[] = { + F("2"), + F("2+2"), + F("3"), + # if P073_USE_74HCMULTIPLEX + F("4 multiplexed"), + # endif // if P073_USE_74HCMULTIPLEX + F("4"), + F("3+2 / 2+3"), + # if P073_USE_74HCMULTIPLEX + F("6 multiplexed"), + # endif // if P073_USE_74HCMULTIPLEX + F("3+3"), + F("3+4 / 4+3"), + F("4+4"), + # if P073_USE_74HCMULTIPLEX + F("8 multiplexed"), + # endif // if P073_USE_74HCMULTIPLEX + }; + const int digitsOptions[] = { + 2, + 1, + 3, + # if P073_USE_74HCMULTIPLEX + 4, + # endif // if P073_USE_74HCMULTIPLEX + 9, + 5, + # if P073_USE_74HCMULTIPLEX + 6, + # endif // if P073_USE_74HCMULTIPLEX + 7, + 11, + 10, + # if P073_USE_74HCMULTIPLEX + 8, + # endif // if P073_USE_74HCMULTIPLEX + }; addFormSelector(F("Nr. of digits"), F("dgts"), NR_ELEMENTS(digitsOptions), digits, digitsOptions, P073_CFG_DIGITS); } else # endif // if P073_USE_74HC595 { - P073_CFG_DIGITS = p073_getDefaultDigits(P073_CFG_DISPLAYTYPE); + P073_CFG_DIGITS = P073_getDefaultDigits(P073_CFG_DISPLAYTYPE); } { const __FlashStringHelper *displout[] = { F("Manual"), @@ -264,7 +311,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P073_data) { - success = P073_data->p073_plugin_write(event, string); + success = P073_data->plugin_write(event, string); } break; } @@ -301,6 +348,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) if (nullptr != P073_data) { success = P073_data->plugin_fifty_per_second(event); } + break; } # endif // if P073_USE_74HC595 diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index e29d34b698..e92086adc9 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -2,7 +2,7 @@ #ifdef USES_P073 -uint8_t p073_getDefaultDigits(uint8_t displayModel, +uint8_t P073_getDefaultDigits(uint8_t displayModel, uint8_t digits) { const uint8_t digitsSet[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 uint8_t bufLen{}; @@ -122,14 +122,23 @@ void P073_data_struct::init(struct EventStruct *event) digits = P073_CFG_DIGITS; # if P073_USE_74HC595 - if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits))) { + if ((digits > 0) && ((digits < 4) || (5 == digits) || (7 == digits) || (9 == digits) || (10 == digits) || (11 == digits))) { isSequential = true; - if (1 == digits) { // 2+2 + if (1 == digits) { // 2+2 digits = 4; } else - if (7 == digits) { // 3+3 + if (9 == digits) { // 4 sequential + digits = 4; + } else + if (10 == digits) { // 4+4 sequential + digits = 8; + } else + if (7 == digits) { // 3+3 digits = 6; + } else + if (11 == digits) { // 3+4/4+3 sequential + digits = 7; } } # endif // if P073_USE_74HC595 @@ -142,20 +151,20 @@ void P073_data_struct::init(struct EventStruct *event) case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: case P073_TM1637_6DGT: - tm1637_InitDisplay(pin1, pin2); - tm1637_SetPowerBrightness(pin1, pin2, brightness / 2, true); + tm1637_InitDisplay(); + tm1637_SetPowerBrightness(brightness / 2, true); if (output == P073_DISP_MANUAL) { - tm1637_ClearDisplay(pin1, pin2); + tm1637_ClearDisplay(); } break; case P073_MAX7219_8DGT: - max7219_InitDisplay(pin1, pin2, pin3); + max7219_InitDisplay(); delay(10); // small poweroff/poweron delay - max7219_SetPowerBrightness(pin1, pin2, pin3, brightness, true); + max7219_SetPowerBrightness(brightness, true); if (output == P073_DISP_MANUAL) { - max7219_ClearDisplay(pin1, pin2, pin3); + max7219_ClearDisplay(); } break; # if P073_USE_74HC595 @@ -194,6 +203,7 @@ bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { // ==================================== void P073_data_struct::hc595_ShowBuffer() { + # if P073_USE_74HCMULTIPLEX const uint8_t hc595digit4[] = { 0b00001000, // left segment 0b00000100, @@ -218,43 +228,27 @@ void P073_data_struct::hc595_ShowBuffer() { 0b00000100, 0b00001000, // right segment }; + # endif // if P073_USE_74HCMULTIPLEX - int8_t i = 0; - int8_t stop = digits; - int8_t incr = 1; - int8_t trgr = digits - 1; + int8_t i = digits - 1; + int8_t stop = -1; + int8_t incr = -1; - if (P073_HC595_SEQUENTIAL) { - i = digits - 1; - stop = -1; - incr = -1; - trgr = 0; - } + # if P073_USE_74HCMULTIPLEX - # ifdef P073_DEBUG - const int8_t oi = i; - # endif // ifdef P073_DEBUG + if (P073_HC595_MULTIPLEX) { + i = dspDgt; + stop = dspDgt + 1; + incr = 1; + } + # endif // if P073_USE_74HCMULTIPLEX for (; i != stop && i >= 0; i += incr) { uint8_t value; uint8_t digit = 0xFF; - # if P073_EXTRA_FONTS // 74HC595 uses inverted data, compared to MAX7219/TM1637 - switch (fontset) { - case 1: // Siekoo - case 2: // Siekoo with uppercase CHNORUX - value = ~pgm_read_byte(&(SiekooCharTable[showbuffer[i]])); - break; - case 3: // dSEG7 - value = ~pgm_read_byte(&(Dseg7CharTable[showbuffer[i]])); - break; - default: // Default fontset - value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); - } - # else // if P073_EXTRA_FONTS - value = ~pgm_read_byte(&(DefaultCharTable[showbuffer[i]])); - # endif // if P073_EXTRA_FONTS + value = ~P073_getFontChar(showbuffer[i], fontset); if (showperiods[i]) { value &= 0x7F; @@ -263,34 +257,46 @@ void P073_data_struct::hc595_ShowBuffer() { shiftOut(pin1, pin2, MSBFIRST, value); // Digit data out - // 2 and 3 digit modules use sequential digit values (in reversed order) + // 2, 3 and some 4 digit modules use sequential digit values (in reversed order) // 4, 6 and 8 digit modules use multiplexing in LTR order - if (4 == digits) { - digit = hc595digit4[i]; - } else - if ((6 == digits) && !isSequential) { - digit = hc595digit6[i]; - } else - if (8 == digits) { - digit = hc595digit8[i]; + # if P073_USE_74HCMULTIPLEX + + if (!isSequential) { + if (4 == digits) { + digit = hc595digit4[i]; + } else + if (6 == digits) { + digit = hc595digit6[i]; + } else + if (8 == digits) { + digit = hc595digit8[i]; + } } if (digit != 0xFF) { // Select multiplexer digit, 0xFF is invalid shiftOut(pin1, pin2, MSBFIRST, digit); } + # endif // if P073_USE_74HCMULTIPLEX - if ((P073_HC595_SEQUENTIAL && (i == trgr)) || P073_HC595_MULTIPLEX) { + if ((P073_HC595_SEQUENTIAL && (0 == i)) || P073_HC595_MULTIPLEX) { digitalWrite(pin3, LOW); // Clock data - delay(1); + // delay(1); digitalWrite(pin3, HIGH); } } + if (i >= digits) { + dspDgt = 0; + } else { + dspDgt = i; + } + # ifdef P073_DEBUG - // if ((counter50 % 100 == 0) || P073_HC595_SEQUENTIAL) { - // addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d oi:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), - // digits, oi, i, stop, incr, pin1, pin2, pin3)); + // TODO disable log + // if ((counter50 % 200 == 0) || P073_HC595_SEQUENTIAL) { + // addLog(LOG_LEVEL_INFO, strformat(F("P073: hc595_ShowBuffer (end) dgt:%d i:%d stop:%d incr:%d pin1: %d pin2: %d pin3: %d"), + // digits, i, stop, incr, pin1, pin2, pin3)); // } # endif // ifdef P073_DEBUG } @@ -408,7 +414,7 @@ void P073_data_struct::FillBufferWithNumber(const String& number) { if (p073_tmpchar == '.') { // dot dotpos = p073_index; } else { - showbuffer[p073_index] = mapCharToFontPosition(p073_tmpchar, fontset); + showbuffer[p073_index] = P073_mapCharToFontPosition(p073_tmpchar, fontset); p073_index--; } } @@ -431,7 +437,7 @@ void P073_data_struct::FillBufferWithTemp(int temperature) { const size_t p073_numlenght = strlen(p073_digit); for (size_t i = 0; i < p073_numlenght; ++i) { - showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); + showbuffer[i] = P073_mapCharToFontPosition(p073_digit[i], fontset); } if (!hideDegree) { @@ -480,7 +486,7 @@ void P073_data_struct::FillBufferWithDualTemp(int leftTemperature, const size_t p073_numlenght = strlen(p073_digit); for (size_t i = 0; i < p073_numlenght; ++i) { - showbuffer[i] = mapCharToFontPosition(p073_digit[i], fontset); + showbuffer[i] = P073_mapCharToFontPosition(p073_digit[i], fontset); } if (!hideDegree) { @@ -532,9 +538,9 @@ void P073_data_struct::FillBufferWithString(const String& textToShow, } } else if (p < 8) { # if P073_7DBIN_COMMAND - showbuffer[p] = useBinaryData ? textToShow.charAt(i) : mapCharToFontPosition(textToShow.charAt(i), fontset); + showbuffer[p] = useBinaryData ? textToShow.charAt(i) : P073_mapCharToFontPosition(textToShow.charAt(i), fontset); # else // if fP073_7DBIN_COMMAND - showbuffer[p] = mapCharToFontPosition(textToShow.charAt(i), fontset); + showbuffer[p] = P073_mapCharToFontPosition(textToShow.charAt(i), fontset); # endif // if P073_7DBIN_COMMAND p++; } @@ -574,7 +580,7 @@ bool P073_data_struct::NextScroll() { if (scrollCount == 0) { scrollCount = 0xFFFF; // Max value to avoid interference when scrolling long texts result = true; - const int bufToFill = p073_getDefaultDigits(displayModel, digits); + const int bufToFill = P073_getDefaultDigits(displayModel, digits); const int p073_txtlength = _textToScroll.length(); ClearBuffer(); @@ -602,9 +608,9 @@ bool P073_data_struct::NextScroll() { # if P073_7DBIN_COMMAND showbuffer[p] = binaryData ? _textToScroll.charAt(i) : - mapCharToFontPosition(_textToScroll.charAt(i), fontset); + P073_mapCharToFontPosition(_textToScroll.charAt(i), fontset); # else // if P073_7DBIN_COMMAND - showbuffer[p] = mapCharToFontPosition(_textToScroll.charAt(i), fontset); + showbuffer[p] = P073_mapCharToFontPosition(_textToScroll.charAt(i), fontset); # endif // if P073_7DBIN_COMMAND p++; } @@ -627,7 +633,7 @@ void P073_data_struct::setTextToScroll(const String& text) { _textToScroll = String(); if (!text.isEmpty()) { - const int bufToFill = p073_getDefaultDigits(displayModel, digits); + const int bufToFill = P073_getDefaultDigits(displayModel, digits); _textToScroll.reserve(text.length() + bufToFill + (scrollFull ? bufToFill : 0)); for (int i = 0; scrollFull && i < bufToFill; ++i) { // Scroll text in from the right, so start with all spaces @@ -722,57 +728,6 @@ void P073_data_struct::ClearBuffer() { } } -uint8_t P073_data_struct::mapCharToFontPosition(char character, - uint8_t fontset) { - uint8_t position = 10; - - # if P073_EXTRA_FONTS - const String specialChars = F(" -^=/_%@.,;:+*#!?'\"<>\\()|"); - const String chnorux = F("CHNORUX"); - - switch (fontset) { - case 1: // Siekoo - case 2: // Siekoo with uppercase 'CHNORUX' - - if ((fontset == 2) && (chnorux.indexOf(character) > -1)) { - position = chnorux.indexOf(character) + 35; - } else if (isDigit(character)) { - position = character - '0'; - } else if (isAlpha(character)) { - position = character - (isLowerCase(character) ? 'a' : 'A') + 42; - } else { - const int idx = specialChars.indexOf(character); - - if (idx > -1) { - position = idx + 10; - } - } - break; - case 3: // dSEG7 (same table size as 7Dgt) - default: // Original fontset (7Dgt) - # endif // if P073_EXTRA_FONTS - - if (isDigit(character)) { - position = character - '0'; - } else if (isAlpha(character)) { - position = character - (isLowerCase(character) ? 'a' : 'A') + 16; - } else { - switch (character) { - case ' ': position = 10; break; - case '-': position = 11; break; - case '^': position = 12; break; // degree - case '=': position = 13; break; - case '/': position = 14; break; - case '_': position = 15; break; - } - } - # if P073_EXTRA_FONTS -} - - # endif // if P073_EXTRA_FONTS - return position; -} - /** * This function reverts the 7 databits/segmentbits so TM1637 and 74HC595 displays work with fonts designed for MAX7219. * Dot/colon bit is still bit 8 @@ -790,20 +745,7 @@ uint8_t P073_data_struct::mapMAX7219FontToTM1673Font(uint8_t character) { uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, uint8_t fontset) { - # if P073_EXTRA_FONTS - - switch (fontset) { - case 1: // Siekoo - case 2: // Siekoo uppercase CHNORUX - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(SiekooCharTable[index]))); - case 3: // dSEG7 - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(Dseg7CharTable[index]))); - default: // Standard fontset - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); - } - # else // if P073_EXTRA_FONTS - return mapMAX7219FontToTM1673Font(pgm_read_byte(&(DefaultCharTable[index]))); - # endif // if P073_EXTRA_FONTS + return mapMAX7219FontToTM1673Font(P073_getFontChar(index, fontset)); } bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { @@ -853,9 +795,9 @@ bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { case P073_MAX7219_8DGT: if (P073_CFG_OUTPUTTYPE == P073_DISP_DATE) { - max7219_ShowDate(pin1, pin2, pin3); + max7219_ShowDate(); } else { - max7219_ShowTime(pin1, pin2, pin3, timesep); + max7219_ShowTime(timesep); } break; # if P073_USE_74HC595 @@ -899,7 +841,7 @@ bool P073_data_struct::plugin_ten_per_second(struct EventStruct *event) { } case P073_MAX7219_8DGT: { dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(pin1, pin2, pin3); + max7219_ShowBuffer(); break; } # if P073_USE_74HC595 @@ -918,7 +860,7 @@ bool P073_data_struct::plugin_ten_per_second(struct EventStruct *event) { # endif // if P073_SCROLL_TEXT const char p073_commands[] PROGMEM = - "7dn|7dt" + "7dn|7dt|" # if P073_7DDT_COMMAND "7ddt|" # endif // if P073_7DDT_COMMAND @@ -953,8 +895,8 @@ enum class p073_commands_e : int8_t { c7output, }; -bool P073_data_struct::p073_plugin_write(struct EventStruct *event, - const String & string) { +bool P073_data_struct::plugin_write(struct EventStruct *event, + const String & string) { const String cmd_s = parseString(string, 1); if ((cmd_s.length() < 3) || (cmd_s[0] != '7')) { return false; } @@ -1078,10 +1020,10 @@ bool P073_data_struct::p073_plugin_write(struct EventStruct *event, case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: case P073_TM1637_6DGT: - tm1637_SetPowerBrightness(pin1, pin2, brightness / 2, displayon); + tm1637_SetPowerBrightness(brightness / 2, displayon); break; case P073_MAX7219_8DGT: - max7219_SetPowerBrightness(pin1, pin2, pin3, brightness, displayon); + max7219_SetPowerBrightness(brightness, displayon); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1097,7 +1039,7 @@ void P073_data_struct::getDisplayLimits(int32_t& lLimit, int32_t& uLimit, int8_t offset, uint8_t digits) { - uint8_t dgts = p073_getDefaultDigits(displayModel); + uint8_t dgts = P073_getDefaultDigits(displayModel); # if P073_USE_74HC595 @@ -1147,7 +1089,7 @@ bool P073_data_struct::plugin_write_7dn(struct EventStruct *event, tm1637_ShowBuffer(TM1637_6DIGIT, 8); break; case P073_MAX7219_8DGT: - max7219_ShowBuffer(pin1, pin2, pin3); + max7219_ShowBuffer(); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1226,7 +1168,7 @@ bool P073_data_struct::plugin_write_7dt(const String& text) { } # endif // ifdef P073_DEBUG - max7219_ShowTemp(pin1, pin2, pin3, hideDegree ? 6 : 5, -1); + max7219_ShowTemp(hideDegree ? 6 : 5, -1); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1321,7 +1263,7 @@ bool P073_data_struct::plugin_write_7ddt(const String& text) { bool alignSave = rightAlignTempMAX7219; // Save setting rightAlignTempMAX7219 = true; - max7219_ShowTemp(pin1, pin2, pin3, firstDot, secondDot); + max7219_ShowTemp(firstDot, secondDot); rightAlignTempMAX7219 = alignSave; // Restore # if P073_USE_74HC595 @@ -1379,7 +1321,7 @@ bool P073_data_struct::plugin_write_7dst(struct EventStruct *event) { tm1637_ShowTime6(); break; case P073_MAX7219_8DGT: - max7219_ShowTime(pin1, pin2, pin3, timesep); + max7219_ShowTime(timesep); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1422,7 +1364,7 @@ bool P073_data_struct::plugin_write_7dsd(struct EventStruct *event) { tm1637_ShowDate6(); break; case P073_MAX7219_8DGT: - max7219_ShowDate(pin1, pin2, pin3); + max7219_ShowDate(); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1450,7 +1392,7 @@ bool P073_data_struct::plugin_write_7dtext(const String& text) { # endif // ifndef BUILD_NO_DEBUG # if P073_SCROLL_TEXT setTextToScroll(EMPTY_STRING); - uint8_t bufLen = p073_getDefaultDigits(displayModel, digits); + const uint8_t bufLen = P073_getDefaultDigits(displayModel, digits); if (isScrollEnabled() && (getEffectiveTextLength(text) > bufLen)) { setTextToScroll(text); @@ -1470,7 +1412,7 @@ bool P073_data_struct::plugin_write_7dtext(const String& text) { break; case P073_MAX7219_8DGT: dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(pin1, pin2, pin3); + max7219_ShowBuffer(); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1540,7 +1482,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { argValue = parseString(text, arg); } # if P073_SCROLL_TEXT - const uint8_t bufLen = p073_getDefaultDigits(displayModel, digits); + const uint8_t bufLen = P073_getDefaultDigits(displayModel, digits); # endif // if P073_SCROLL_TEXT if (!data.isEmpty()) { @@ -1565,7 +1507,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { break; case P073_MAX7219_8DGT: dotpos = -1; // avoid to display the dot - max7219_ShowBuffer(pin1, pin2, pin3); + max7219_ShowBuffer(); break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: @@ -1589,13 +1531,12 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { // ---- TM1637 specific functions ---- // =================================== -# define CLK_HIGH() digitalWrite(clk_pin, HIGH) -# define CLK_LOW() digitalWrite(clk_pin, LOW) -# define DIO_HIGH() pinMode(dio_pin, INPUT) -# define DIO_LOW() pinMode(dio_pin, OUTPUT) +# define CLK_HIGH() digitalWrite(this->pin1, HIGH) +# define CLK_LOW() digitalWrite(this->pin1, LOW) +# define DIO_HIGH() pinMode(this->pin2, INPUT) +# define DIO_LOW() pinMode(this->pin2, OUTPUT) -void P073_data_struct::tm1637_i2cStart(uint8_t clk_pin, - uint8_t dio_pin) { +void P073_data_struct::tm1637_i2cStart() { # ifdef P073_DEBUG addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Start")); # endif // ifdef P073_DEBUG @@ -1605,8 +1546,7 @@ void P073_data_struct::tm1637_i2cStart(uint8_t clk_pin, DIO_LOW(); } -void P073_data_struct::tm1637_i2cStop(uint8_t clk_pin, - uint8_t dio_pin) { +void P073_data_struct::tm1637_i2cStop() { # ifdef P073_DEBUG addLog(LOG_LEVEL_DEBUG, F("7DGT : Comm Stop")); # endif // ifdef P073_DEBUG @@ -1619,23 +1559,18 @@ void P073_data_struct::tm1637_i2cStop(uint8_t clk_pin, DIO_HIGH(); } -void P073_data_struct::tm1637_i2cAck(uint8_t clk_pin, - uint8_t dio_pin) { - # ifdef P073_DEBUG - bool dummyAck = false; - # endif // ifdef P073_DEBUG - +void P073_data_struct::tm1637_i2cAck() { CLK_LOW(); - pinMode(dio_pin, INPUT_PULLUP); + pinMode(pin2, INPUT_PULLUP); // DIO_HIGH(); delayMicroseconds(TM1637_CLOCKDELAY); // while(digitalRead(dio_pin)); # ifdef P073_DEBUG - dummyAck = + const bool dummyAck = # endif // ifdef P073_DEBUG - digitalRead(dio_pin); + digitalRead(pin2); # ifdef P073_DEBUG @@ -1653,31 +1588,25 @@ void P073_data_struct::tm1637_i2cAck(uint8_t clk_pin, CLK_HIGH(); delayMicroseconds(TM1637_CLOCKDELAY); CLK_LOW(); - pinMode(dio_pin, OUTPUT); + pinMode(pin2, OUTPUT); } -void P073_data_struct::tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytesToPrint[], +void P073_data_struct::tm1637_i2cWrite_ack(uint8_t bytesToPrint[], uint8_t length) { - tm1637_i2cStart(clk_pin, dio_pin); + tm1637_i2cStart(); for (uint8_t i = 0; i < length; ++i) { - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint[i]); + tm1637_i2cWrite_ack(bytesToPrint[i]); } - tm1637_i2cStop(clk_pin, dio_pin); + tm1637_i2cStop(); } -void P073_data_struct::tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint) { - tm1637_i2cWrite(clk_pin, dio_pin, bytetoprint); - tm1637_i2cAck(clk_pin, dio_pin); +void P073_data_struct::tm1637_i2cWrite_ack(uint8_t bytetoprint) { + tm1637_i2cWrite(bytetoprint); + tm1637_i2cAck(); } -void P073_data_struct::tm1637_i2cWrite(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint) { +void P073_data_struct::tm1637_i2cWrite(uint8_t bytetoprint) { # ifdef P073_DEBUG addLog(LOG_LEVEL_DEBUG, F("7DGT : WriteByte")); # endif // ifdef P073_DEBUG @@ -1698,17 +1627,14 @@ void P073_data_struct::tm1637_i2cWrite(uint8_t clk_pin, } } -void P073_data_struct::tm1637_ClearDisplay(uint8_t clk_pin, - uint8_t dio_pin) { +void P073_data_struct::tm1637_ClearDisplay() { uint8_t bytesToPrint[7]{}; bytesToPrint[0] = 0xC0; - tm1637_i2cWrite_ack(clk_pin, dio_pin, bytesToPrint, 7); + tm1637_i2cWrite_ack(bytesToPrint, 7); } -void P073_data_struct::tm1637_SetPowerBrightness(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t brightlvl, +void P073_data_struct::tm1637_SetPowerBrightness(uint8_t brightlvl, bool poweron) { # ifdef P073_DEBUG addLog(LOG_LEVEL_INFO, F("7DGT : Set BRIGHT")); @@ -1722,20 +1648,19 @@ void P073_data_struct::tm1637_SetPowerBrightness(uint8_t clk_pin, } const uint8_t byteToPrint = brightvalue; - tm1637_i2cWrite_ack(clk_pin, dio_pin, byteToPrint); + tm1637_i2cWrite_ack(byteToPrint); } -void P073_data_struct::tm1637_InitDisplay(uint8_t clk_pin, - uint8_t dio_pin) { - pinMode(clk_pin, OUTPUT); - pinMode(dio_pin, OUTPUT); +void P073_data_struct::tm1637_InitDisplay() { + pinMode(pin1, OUTPUT); + pinMode(pin2, OUTPUT); CLK_HIGH(); DIO_HIGH(); const uint8_t byteToPrint = 0x40; - tm1637_i2cWrite_ack(clk_pin, dio_pin, byteToPrint); - tm1637_ClearDisplay(clk_pin, dio_pin); + tm1637_i2cWrite_ack(byteToPrint); + tm1637_ClearDisplay(); } uint8_t P073_data_struct::tm1637_separator(uint8_t value, @@ -1767,7 +1692,7 @@ void P073_data_struct::tm1637_ShowDate6(bool showTime) { } bytesToPrint[6] = tm1637_separator(tm1637_getFontChar(showbuffer[3], fontset), timesep); - tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 7); + tm1637_i2cWrite_ack(bytesToPrint, 7); } void P073_data_struct::tm1637_ShowTemp6(bool sep) { @@ -1781,7 +1706,7 @@ void P073_data_struct::tm1637_ShowTemp6(bool sep) { bytesToPrint[5] = tm1637_getFontChar(showbuffer[7], fontset); bytesToPrint[6] = tm1637_getFontChar(showbuffer[6], fontset); - tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 7); + tm1637_i2cWrite_ack(bytesToPrint, 7); } void P073_data_struct::tm1637_ShowTimeTemp4(bool sep, @@ -1794,7 +1719,7 @@ void P073_data_struct::tm1637_ShowTimeTemp4(bool sep, bytesToPrint[3] = tm1637_getFontChar(showbuffer[2 + bufoffset], fontset); bytesToPrint[4] = tm1637_getFontChar(showbuffer[3 + bufoffset], fontset); - tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, 5); + tm1637_i2cWrite_ack(bytesToPrint, 5); } void P073_data_struct::tm1637_SwapDigitInBuffer(uint8_t startPos) { @@ -1834,9 +1759,12 @@ void P073_data_struct::tm1637_ShowBuffer(uint8_t firstPos, showperiods[i]); bytesToPrint[length] = p073_datashowpos1; } - ++length; + length++; } - tm1637_i2cWrite_ack(pin1, pin2, bytesToPrint, length); + # ifdef P073_DEBUG + addLog(LOG_LEVEL_INFO, strformat(F("TM1673: Write bytes: %d buffer %d to %d"), length, firstPos, lastPos)); + # endif // ifdef P073_DEBUG + tm1637_i2cWrite_ack(bytesToPrint, length); } // ==================================== @@ -1849,40 +1777,29 @@ void P073_data_struct::tm1637_ShowBuffer(uint8_t firstPos, # define OP_SHUTDOWN 12 # define OP_DISPLAYTEST 15 -void P073_data_struct::max7219_spiTransfer(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - ESPEASY_VOLATILE(uint8_t) opcode, +void P073_data_struct::max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, ESPEASY_VOLATILE(uint8_t) data) { spidata[1] = opcode; spidata[0] = data; - digitalWrite(cs_pin, LOW); - shiftOut(din_pin, clk_pin, MSBFIRST, spidata[1]); - shiftOut(din_pin, clk_pin, MSBFIRST, spidata[0]); - digitalWrite(cs_pin, HIGH); + digitalWrite(pin3, LOW); + shiftOut(pin1, pin2, MSBFIRST, spidata[1]); + shiftOut(pin1, pin2, MSBFIRST, spidata[0]); + digitalWrite(pin3, HIGH); } -void P073_data_struct::max7219_ClearDisplay(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { +void P073_data_struct::max7219_ClearDisplay() { for (int i = 0; i < 8; i++) { - max7219_spiTransfer(din_pin, clk_pin, cs_pin, i + 1, 0); + max7219_spiTransfer(i + 1, 0); } } -void P073_data_struct::max7219_SetPowerBrightness(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - uint8_t brightlvl, +void P073_data_struct::max7219_SetPowerBrightness(uint8_t brightlvl, bool poweron) { - max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_INTENSITY, brightlvl); - max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SHUTDOWN, poweron ? 1 : 0); + max7219_spiTransfer(OP_INTENSITY, brightlvl); + max7219_spiTransfer(OP_SHUTDOWN, poweron ? 1 : 0); } -void P073_data_struct::max7219_SetDigit(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int dgtpos, +void P073_data_struct::max7219_SetDigit(int dgtpos, uint8_t dgtvalue, bool showdot, bool binaryData) { @@ -1892,66 +1809,43 @@ void P073_data_struct::max7219_SetDigit(uint8_t din_pin, p073_tempvalue = dgtvalue; // Overwrite if binary data } else { - # if P073_EXTRA_FONTS - - switch (fontset) { - case 1: // Siekoo - case 2: // Siekoo with uppercase CHNORUX - p073_tempvalue = pgm_read_byte(&(SiekooCharTable[dgtvalue])); - break; - case 3: // dSEG7 - p073_tempvalue = pgm_read_byte(&(Dseg7CharTable[dgtvalue])); - break; - default: // Default fontset - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - } - # else // if P073_EXTRA_FONTS - p073_tempvalue = pgm_read_byte(&(DefaultCharTable[dgtvalue])); - # endif // if P073_EXTRA_FONTS + p073_tempvalue = P073_getFontChar(dgtvalue, fontset); if (showdot) { p073_tempvalue |= 0b10000000; } } - max7219_spiTransfer(din_pin, clk_pin, cs_pin, dgtpos + 1, p073_tempvalue); + max7219_spiTransfer(dgtpos + 1, p073_tempvalue); } -void P073_data_struct::max7219_InitDisplay(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { - pinMode(din_pin, OUTPUT); - pinMode(clk_pin, OUTPUT); - pinMode(cs_pin, OUTPUT); - digitalWrite(cs_pin, HIGH); - max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DISPLAYTEST, 0); - max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SCANLIMIT, 7); // scanlimit setup to max at Init - max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DECODEMODE, 0); - max7219_ClearDisplay(din_pin, clk_pin, cs_pin); - max7219_SetPowerBrightness(din_pin, clk_pin, cs_pin, 0, false); +void P073_data_struct::max7219_InitDisplay() { + pinMode(pin1, OUTPUT); + pinMode(pin2, OUTPUT); + pinMode(pin3, OUTPUT); + digitalWrite(pin3, HIGH); + max7219_spiTransfer(OP_DISPLAYTEST, 0); + max7219_spiTransfer(OP_SCANLIMIT, 7); // scanlimit setup to max at Init + max7219_spiTransfer(OP_DECODEMODE, 0); + max7219_ClearDisplay(); + max7219_SetPowerBrightness(0, false); } -void P073_data_struct::max7219_ShowTime(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - bool sep) { +void P073_data_struct::max7219_ShowTime(bool sep) { const uint8_t idx_list[] = { 7, 6, 4, 3, 1, 0 }; // Digits in reversed order, as the loop is backward for (int8_t i = 5; i >= 0; --i) { - max7219_SetDigit(din_pin, clk_pin, cs_pin, idx_list[i], showbuffer[i], false); + max7219_SetDigit(idx_list[i], showbuffer[i], false); } - const uint8_t sepChar = mapCharToFontPosition(sep ? '-' : ' ', fontset); + const uint8_t sepChar = P073_mapCharToFontPosition(sep ? '-' : ' ', fontset); - max7219_SetDigit(din_pin, clk_pin, cs_pin, 2, sepChar, false); - max7219_SetDigit(din_pin, clk_pin, cs_pin, 5, sepChar, false); + max7219_SetDigit(2, sepChar, false); + max7219_SetDigit(5, sepChar, false); } -void P073_data_struct::max7219_ShowTemp(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int8_t firstDot, - int8_t secondDot) { - max7219_SetDigit(din_pin, clk_pin, cs_pin, 0, 10, false); +void P073_data_struct::max7219_ShowTemp(int8_t firstDot, + int8_t secondDot) { + max7219_SetDigit(0, 10, false); if (firstDot > -1) { showperiods[firstDot] = true; } @@ -1963,34 +1857,30 @@ void P073_data_struct::max7219_ShowTemp(uint8_t din_pin, const int bufIndex = (7 + alignRight) - i; if (bufIndex < 8) { - max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + max7219_SetDigit(i, showbuffer[bufIndex], showperiods[bufIndex]); } } } -void P073_data_struct::max7219_ShowDate(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { +void P073_data_struct::max7219_ShowDate() { const uint8_t dotflags[8] = { false, true, false, true, false, false, false, false }; for (int i = 0; i < 8; ++i) { - max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + max7219_SetDigit(i, showbuffer[7 - i], dotflags[7 - i]); } } -void P073_data_struct::max7219_ShowBuffer(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin) { +void P073_data_struct::max7219_ShowBuffer() { if (dotpos > -1) { showperiods[dotpos] = true; } for (int i = 0; i < 8; i++) { - max7219_SetDigit(din_pin, clk_pin, cs_pin, i, + max7219_SetDigit(i, showbuffer[7 - i], showperiods[7 - i] # if P073_7DBIN_COMMAND diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index dff8d87bde..5dc2b72f29 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -25,31 +25,34 @@ # define P073_DISP_CLOCK12 4 # define P073_DISP_DATE 5 -# define P073_OPTION_PERIOD 0 // Period as dot -# define P073_OPTION_HIDEDEGREE 1 // Hide degree symbol for temperatures -# define P073_OPTION_RIGHTALIGN 2 // Align 7dt output right on MAX7219 display -# define P073_OPTION_SCROLLTEXT 3 // Scroll text > 8 characters -# define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display -# define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display +# define P073_OPTION_PERIOD 0 // Period as dot +# define P073_OPTION_HIDEDEGREE 1 // Hide degree symbol for temperatures +# define P073_OPTION_RIGHTALIGN 2 // Align 7dt output right on MAX7219 display +# define P073_OPTION_SCROLLTEXT 3 // Scroll text > 8 characters +# define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display +# define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display # ifndef P073_7DDT_COMMAND -# define P073_7DDT_COMMAND 1 // Enable 7ddt by default +# define P073_7DDT_COMMAND 1 // Enable 7ddt by default # endif // ifndef P073_7DDT_COMMAND # ifndef P073_EXTRA_FONTS -# define P073_EXTRA_FONTS 1 // Enable extra fonts +# define P073_EXTRA_FONTS 1 // Enable extra fonts # endif // ifndef P073_EXTRA_FONTS # ifndef P073_SCROLL_TEXT -# define P073_SCROLL_TEXT 1 // Enable scrolling of 7dtext by default +# define P073_SCROLL_TEXT 1 // Enable scrolling of 7dtext by default # endif // ifndef P073_SCROLL_TEXT # ifndef P073_7DBIN_COMMAND -# define P073_7DBIN_COMMAND 1 // Enable input of binary data via 7dbin,uint8_t,... command +# define P073_7DBIN_COMMAND 1 // Enable input of binary data via 7dbin,uint8_t,... command # endif // ifndef P073_7DBIN_COMMAND # ifndef P073_SUPPRESS_ZERO -# define P073_SUPPRESS_ZERO 1 // Enable Suppress leading zero on day/hour +# define P073_SUPPRESS_ZERO 1 // Enable Suppress leading zero on day/hour # endif // ifndef P073_SUPPRESS_ZERO # ifndef P073_USE_74HC595 -# define P073_USE_74HC595 1 // Enable support for 74HC595 based (sequential and multiplexing) displays +# define P073_USE_74HC595 1 // Enable support for 74HC595 based sequential displays # endif // ifndef P073_USE_74HC595 +# ifndef P073_USE_74HCMULTIPLEX +# define P073_USE_74HCMULTIPLEX 1 // Enable support for 74HC595 based multiplexing displays +# endif // ifndef P073_USE_74HCMULTIPLEX # if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) # if P073_7DDT_COMMAND @@ -82,6 +85,10 @@ # undef P073_USE_74HC595 // Removes the support for 74HC595 displays # define P073_USE_74HC595 0 # endif // if P073_USE_74HC595 +# if P073_USE_74HCMULTIPLEX +# undef P073_USE_74HCMULTIPLEX // Removes the support for 74HC595 multiplexed displays +# define P073_USE_74HCMULTIPLEX 0 +# endif // if P073_USE_74HCMULTIPLEX # endif // if defined(ESP8266) # define TM1637_POWER_ON 0b10001000 @@ -187,7 +194,7 @@ static const uint8_t Dseg7CharTable[42] PROGMEM = { # endif // P073_EXTRA_FONTS -uint8_t p073_getDefaultDigits(uint8_t displayModel, +uint8_t P073_getDefaultDigits(uint8_t displayModel, uint8_t digits = 0); uint8_t P073_mapCharToFontPosition(char character, uint8_t fontset); @@ -201,8 +208,8 @@ struct P073_data_struct : public PluginTaskData_base { virtual ~P073_data_struct() = default; void init(struct EventStruct *event); - bool p073_plugin_write(struct EventStruct *event, - const String & string); + bool plugin_write(struct EventStruct *event, + const String & string); bool plugin_once_a_second(struct EventStruct *event); # if P073_SCROLL_TEXT bool plugin_ten_per_second(struct EventStruct *event); @@ -258,8 +265,6 @@ struct P073_data_struct : public PluginTaskData_base { void FillBufferWithDash(); void ClearBuffer(); - uint8_t mapCharToFontPosition(char character, - uint8_t fontset); uint8_t mapMAX7219FontToTM1673Font(uint8_t character); uint8_t tm1637_getFontChar(uint8_t index, uint8_t fontset); @@ -268,9 +273,9 @@ struct P073_data_struct : public PluginTaskData_base { uint8_t showbuffer[8] = { 0 }; bool showperiods[8] = { 0 }; uint8_t spidata[2] = { 0 }; - int8_t pin1 = -1; - int8_t pin2 = -1; - int8_t pin3 = -1; + uint8_t pin1 = 0xFF; + uint8_t pin2 = 0xFF; + uint8_t pin3 = 0xFF; uint8_t displayModel = 0; uint8_t output = 0; uint8_t brightness = 0; @@ -303,7 +308,8 @@ struct P073_data_struct : public PluginTaskData_base { uint32_t counter50 = 0; # endif // ifdef P073_DEBUG # if P073_USE_74HC595 - bool isSequential = false; + int8_t dspDgt = 0; + bool isSequential = false; # endif // if P073_USE_74HC595 private: @@ -330,30 +336,17 @@ struct P073_data_struct : public PluginTaskData_base { # endif // if P073_7DBIN_COMMAND // ---- TM1637 specific functions ---- - void tm1637_i2cStart(uint8_t clk_pin, - uint8_t dio_pin); - void tm1637_i2cStop(uint8_t clk_pin, - uint8_t dio_pin); - void tm1637_i2cAck(uint8_t clk_pin, - uint8_t dio_pin); - void tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytesToPrint[], - uint8_t length); - void tm1637_i2cWrite_ack(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint); - void tm1637_i2cWrite(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t bytetoprint); - void tm1637_ClearDisplay(uint8_t clk_pin, - uint8_t dio_pin); - void tm1637_SetPowerBrightness(uint8_t clk_pin, - uint8_t dio_pin, - uint8_t brightlvl, - bool poweron); - void tm1637_InitDisplay(uint8_t clk_pin, - uint8_t dio_pin); + void tm1637_i2cStart(); + void tm1637_i2cStop(); + void tm1637_i2cAck(); + void tm1637_i2cWrite_ack(uint8_t bytesToPrint[], + uint8_t length); + void tm1637_i2cWrite_ack(uint8_t bytetoprint); + void tm1637_i2cWrite(uint8_t bytetoprint); + void tm1637_ClearDisplay(); + void tm1637_SetPowerBrightness(uint8_t brightlvl, + bool poweron); + void tm1637_InitDisplay(); uint8_t tm1637_separator(uint8_t value, bool sep); void tm1637_ShowTime6(); @@ -367,44 +360,21 @@ struct P073_data_struct : public PluginTaskData_base { bool useBinaryData = false); // ---- MAX7219 specific functions ---- - void max7219_spiTransfer(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - ESPEASY_VOLATILE(uint8_t) opcode, + void max7219_spiTransfer(ESPEASY_VOLATILE(uint8_t) opcode, ESPEASY_VOLATILE(uint8_t) data); - void max7219_ClearDisplay(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin); - void max7219_SetPowerBrightness(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - uint8_t brightlvl, + void max7219_ClearDisplay(); + void max7219_SetPowerBrightness(uint8_t brightlvl, bool poweron); - void max7219_SetDigit(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int dgtpos, + void max7219_SetDigit(int dgtpos, uint8_t dgtvalue, bool showdot, bool binaryData = false); - void max7219_InitDisplay(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin); - void max7219_ShowTime(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - bool sep); - void max7219_ShowTemp(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin, - int8_t firstDot, - int8_t secondDot); - void max7219_ShowDate(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin); - void max7219_ShowBuffer(uint8_t din_pin, - uint8_t clk_pin, - uint8_t cs_pin); + void max7219_InitDisplay(); + void max7219_ShowTime(bool sep); + void max7219_ShowTemp(int8_t firstDot, + int8_t secondDot); + void max7219_ShowDate(); + void max7219_ShowBuffer(); # if P073_USE_74HC595 void hc595_InitDisplay(); void hc595_ShowBuffer(); From fc49d9cb630d39495f1b7c51840027a08648d004 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 6 Aug 2024 16:40:52 +0200 Subject: [PATCH 09/21] [P073] Update documentation --- docs/source/Plugin/P073.rst | 22 +++++++++++------- .../Plugin/P073_DeviceConfiguration.png | Bin 56893 -> 56209 bytes docs/source/Plugin/P073_NrOfDigitsOptions.png | Bin 25305 -> 37708 bytes 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/source/Plugin/P073.rst b/docs/source/Plugin/P073.rst index a5a4a88d5e..991e597cf1 100644 --- a/docs/source/Plugin/P073.rst +++ b/docs/source/Plugin/P073.rst @@ -30,11 +30,11 @@ Depending on the available space in the release, some features may not be availa Currently 3 fonts are available for presenting text on the display, where the character shapes are somewhat different, and a choice can be made on what font is the most appropriate for the intended purpose. The numbers in the fonts are all equal. -When text to be displayed can't fit on the width of the display (2, 3, 4, 5, 6 or 8 digits), scrolling text can be used so longer messages are shown like a ticker-tape display. +When text to be displayed can't fit on the width of the display (2, 3, 4, 5, 6, 7 or 8 digits), scrolling text can be used so longer messages are shown like a ticker-tape display. Scrolling is always from right to left, and optionally starts with an empty display, so text can be read as it scrolls in. Optionally, periods in text can be shown on the dots of the display, when available (not all 7 segment display have dots). -For temperature display commands, ``7dt,`` and ``7ddt,,``, the degree symbol after the temperature can be turned off so there's room for 1 more digit of temperature on the display. The degree symbol is turned off for 2 and 3 digit displays. +For temperature display commands, ``7dt,`` and ``7ddt,,``, the degree symbol after the temperature can be turned off so there's room for 1 more digit of temperature on the display. The degree symbol is always turned off for 2 and 3 digit displays. Configuration ^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ Configuration * **1st/2nd/3rd GPIO**: How the display is connected can be configured here. Description per module type is in the Notes below the GPIO fields. -For the MAX7219 and 74HC595 displays, the DIN-Pin and CLK-Pin can be shared when multiple displays are connected, but each display's CS-Pin must be connected to a unique GPIO of the unit. +For the MAX7219 and 74HC595 displays, the DIN/SDI/DIO-Pin and (S)CLK-Pin can be shared when multiple displays are connected, but each display's CS/LOAD/RCLK-Pin must be connected to a unique GPIO of the unit. For TM1637 display possibly the DIN-Pin GPIO's can be shared, but that's untested, so it is more safe to use separate GPIOs for each display. @@ -59,21 +59,25 @@ For TM1637 display possibly the DIN-Pin GPIO's can be shared, but that's unteste .. image:: P073_NrOfDigitsOptions.png -* *2*: 2 digits, the smallest available display +* *2*: 2 digits, the smallest supported display * *2+2*: 2 displays using 2 digits connected sequentially (SDO of first display to SDI of second display), making a total of 4 digits. * *3*: 3 digits. The 2 and 3 digits displays use 2 or 3 74HC505 chips sequentially, to control a single digit per chip. -* *4*: 4 digits. The 4, 6 and 8 digit display use a multiplexed setup, using 2 74HC595 chips per board, 1 controlling the digit leds, and 1 controlling the digit selected. These multiplexed displays need to be refreshed continuously to properly display the intended data, causing some extra load on the ESP. +* *4 multiplexed*: 4 digits. The 4, 6 and 8 digit display use a multiplexed setup, using 2 74HC595 chips per board, 1 controlling the digit leds, and 1 controlling the digit selected. These multiplexed displays need to be refreshed continuously to properly display the intended data, causing some extra load on the ESP. * *2+3 / 3+2*: 2 displays with 2 and 3 digits or 3 and 2 digits connected sequentially (SDO to SDI), effectively giving a usable display of 5 digits. -* *6*: 6 digits, multiplexed display. +* *6 multiplexed*: 6 digits, multiplexed display. * *3+3*: 6 digits, 2 boards with 3 digits connected sequentially (SDO to SDI). -* *8*: 8 digits, multiplexed display. This display also supports the ``7ddt`` command for displaying dual temperatures. +* *3+4 / 4+3*: 7 digits, 2 boards with 3 and 4 digits connected sequentially (SDO to SDI). + +* *4+4*: 8 digits, 2 boards with 4 digits connected sequentially (SDO to SDI). + +* *8 multiplexed*: 8 digits, multiplexed display. This display, and the 4+4 combination, also supports the ``7ddt`` command for displaying dual temperatures. * **Display Output**: Here the type of output can be selected: @@ -92,11 +96,11 @@ For TM1637 display possibly the DIN-Pin GPIO's can be shared, but that's unteste *Date*: Displays the current date. -*NB: Clock and Date outputs assume the NTP option is enabled in Tools/Advanced.* +*NB: Clock and Date outputs assume a time-source is available, f.e. the via NTP or External Time Source settings in Tools/Advanced, by connecting a GPS module, or via the ESPEasy P2P network.* The Clock and Date outputs are updated every second, and the blinking selections are 1 second on then 1 second off. -Clock and Date formats are optimized for each Display Type to fill the display efficiently. +Clock and Date formats are optimized for each Display Type to fill the display efficiently, but won't properly fit on the 2 and 3 digit displays. * **Brightness**: The brightness level of the display can be set here. 0 is 'Default' brightness, 1..15 from low to high brightness. Displays using 74HC595 ignore this **Brightness** setting! diff --git a/docs/source/Plugin/P073_DeviceConfiguration.png b/docs/source/Plugin/P073_DeviceConfiguration.png index 4aecb747dab23859eaf655f5bb80a3366857b944..a83dbad5e9d0e8ebd7d1026989806f54ca4e7779 100644 GIT binary patch literal 56209 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 literal 56893 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

2Aj!kO)lCMQ-KLAt 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∓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 }8T*v{4PP{DMh# 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 fbY!SJ*GjF*1LWL4cO} Date: Tue, 6 Aug 2024 16:48:36 +0200 Subject: [PATCH 10/21] [P073] Disable 74HC595 displays for now --- src/src/PluginStructs/P073_data_struct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 5dc2b72f29..8578effb63 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -51,7 +51,7 @@ # define P073_USE_74HC595 1 // Enable support for 74HC595 based sequential displays # endif // ifndef P073_USE_74HC595 # ifndef P073_USE_74HCMULTIPLEX -# define P073_USE_74HCMULTIPLEX 1 // Enable support for 74HC595 based multiplexing displays +# define P073_USE_74HCMULTIPLEX 0 // Enable support for 74HC595 based multiplexing displays # endif // ifndef P073_USE_74HCMULTIPLEX # if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) From 4700baf4f3a2662fadc76b5c629887ecfea14bf2 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 9 Aug 2024 21:15:59 +0200 Subject: [PATCH 11/21] [P073] Add double-buffering for 74HC595 displays --- src/_P073_7DGT.ino | 1 + src/src/PluginStructs/P073_data_struct.cpp | 66 ++++++++++++++-------- src/src/PluginStructs/P073_data_struct.h | 4 +- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 131514f4a2..81ef69ffb1 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,7 @@ // /** History + * 2024-08-08 tonhuisman: Add double-buffering for 74HC595 displays to improve update-speed * 2024-08-06 tonhuisman: Make 74HC595 multiplexed displays a separate compile-time option, as these require special treatment * Separate 7-segment font-related functions for re-use by other plugins * Size reduction by removing now unneeded function pin arguments diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index e92086adc9..ef6cde17b7 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -173,6 +173,7 @@ void P073_data_struct::init(struct EventStruct *event) if (output == P073_DISP_MANUAL) { ClearBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -210,14 +211,16 @@ void P073_data_struct::hc595_ShowBuffer() { 0b00000010, 0b00000001, // right segment }; - const uint8_t hc595digit6[] = { - 0b00010000, // left segment - 0b00100000, - 0b01000000, - 0b00000001, - 0b00000010, - 0b00000100, // right segment - }; + + // const uint8_t hc595digit6[] = { + // 0b00010000, // left segment + // 0b00100000, + // 0b01000000, + // 0b00000001, + // 0b00000010, + // 0b00000100, // right segment + // }; + const uint8_t hc595digit8[] = { 0b00010000, // left segment 0b00100000, @@ -244,29 +247,19 @@ void P073_data_struct::hc595_ShowBuffer() { # endif // if P073_USE_74HCMULTIPLEX for (; i != stop && i >= 0; i += incr) { - uint8_t value; - uint8_t digit = 0xFF; - - // 74HC595 uses inverted data, compared to MAX7219/TM1637 - value = ~P073_getFontChar(showbuffer[i], fontset); - - if (showperiods[i]) { - value &= 0x7F; - } - value = mapMAX7219FontToTM1673Font(value); // Revert bits 6..0 - - shiftOut(pin1, pin2, MSBFIRST, value); // Digit data out + shiftOut(pin1, pin2, MSBFIRST, outputbuffer[i]); // Digit data out // 2, 3 and some 4 digit modules use sequential digit values (in reversed order) // 4, 6 and 8 digit modules use multiplexing in LTR order # if P073_USE_74HCMULTIPLEX + uint8_t digit = 0xFF; if (!isSequential) { if (4 == digits) { digit = hc595digit4[i]; } else if (6 == digits) { - digit = hc595digit6[i]; + digit = hc595digit8[i + (i > 2 ? 1 : 0)]; } else if (8 == digits) { digit = hc595digit8[i]; @@ -280,7 +273,6 @@ void P073_data_struct::hc595_ShowBuffer() { if ((P073_HC595_SEQUENTIAL && (0 == i)) || P073_HC595_MULTIPLEX) { digitalWrite(pin3, LOW); // Clock data - // delay(1); digitalWrite(pin3, HIGH); } } @@ -301,6 +293,20 @@ void P073_data_struct::hc595_ShowBuffer() { # endif // ifdef P073_DEBUG } +void P073_data_struct::hc595_ToOutputBuffer() { + for (uint8_t i = 0; i < 8; ++i) { + uint8_t value; + + // 74HC595 uses inverted data, compared to MAX7219/TM1637 + value = ~P073_getFontChar(showbuffer[i], fontset); + + if (showperiods[i]) { + value &= 0x7F; + } + outputbuffer[i] = mapMAX7219FontToTM1637Font(value); // Rotate bits 6..0 + } +} + void P073_data_struct::hc595_AdjustBuffer() { if (digits < 8) { const uint8_t delta = 8 - digits; @@ -732,7 +738,7 @@ void P073_data_struct::ClearBuffer() { * This function reverts the 7 databits/segmentbits so TM1637 and 74HC595 displays work with fonts designed for MAX7219. * Dot/colon bit is still bit 8 */ -uint8_t P073_data_struct::mapMAX7219FontToTM1673Font(uint8_t character) { +uint8_t P073_data_struct::mapMAX7219FontToTM1637Font(uint8_t character) { uint8_t newCharacter = character & 0x80; // Keep dot-bit if passed in for (int b = 0; b < 7; ++b) { @@ -745,7 +751,7 @@ uint8_t P073_data_struct::mapMAX7219FontToTM1673Font(uint8_t character) { uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, uint8_t fontset) { - return mapMAX7219FontToTM1673Font(P073_getFontChar(index, fontset)); + return mapMAX7219FontToTM1637Font(P073_getFontChar(index, fontset)); } bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { @@ -803,6 +809,7 @@ bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { # if P073_USE_74HC595 case P073_74HC595_2_8DGT: hc595_AdjustBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -846,6 +853,8 @@ bool P073_data_struct::plugin_ten_per_second(struct EventStruct *event) { } # if P073_USE_74HC595 case P073_74HC595_2_8DGT: { + hc595_ToOutputBuffer(); + if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); } @@ -1094,6 +1103,7 @@ bool P073_data_struct::plugin_write_7dn(struct EventStruct *event, # if P073_USE_74HC595 case P073_74HC595_2_8DGT: hc595_AdjustBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1173,6 +1183,7 @@ bool P073_data_struct::plugin_write_7dt(const String& text) { # if P073_USE_74HC595 case P073_74HC595_2_8DGT: hc595_AdjustBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1274,6 +1285,7 @@ bool P073_data_struct::plugin_write_7ddt(const String& text) { if (digits < 8) { FillBufferWithDash(); } + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1326,6 +1338,7 @@ bool P073_data_struct::plugin_write_7dst(struct EventStruct *event) { # if P073_USE_74HC595 case P073_74HC595_2_8DGT: hc595_AdjustBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1369,6 +1382,7 @@ bool P073_data_struct::plugin_write_7dsd(struct EventStruct *event) { # if P073_USE_74HC595 case P073_74HC595_2_8DGT: hc595_AdjustBuffer(); + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1416,6 +1430,7 @@ bool P073_data_struct::plugin_write_7dtext(const String& text) { break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); @@ -1476,7 +1491,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { data += static_cast(displayModel == P073_MAX7219_8DGT ? byteValue : - mapMAX7219FontToTM1673Font(byteValue)); + mapMAX7219FontToTM1637Font(byteValue)); } arg++; argValue = parseString(text, arg); @@ -1511,6 +1526,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { break; # if P073_USE_74HC595 case P073_74HC595_2_8DGT: + hc595_ToOutputBuffer(); if (hc595_Sequential()) { // Sequential displays don't need continuous refreshing hc595_ShowBuffer(); diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 8578effb63..322e46589a 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -265,7 +265,7 @@ struct P073_data_struct : public PluginTaskData_base { void FillBufferWithDash(); void ClearBuffer(); - uint8_t mapMAX7219FontToTM1673Font(uint8_t character); + uint8_t mapMAX7219FontToTM1637Font(uint8_t character); uint8_t tm1637_getFontChar(uint8_t index, uint8_t fontset); @@ -378,11 +378,13 @@ struct P073_data_struct : public PluginTaskData_base { # if P073_USE_74HC595 void hc595_InitDisplay(); void hc595_ShowBuffer(); + void hc595_ToOutputBuffer(); void hc595_AdjustBuffer(); bool hc595_Sequential() { return P073_HC595_SEQUENTIAL; } + uint8_t outputbuffer[8]{}; # endif // if P073_USE_74HC595 }; From 7210e8eed68b57e89cd8f5fcfb5aa79af7c367a6 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 23 Aug 2024 23:10:31 +0200 Subject: [PATCH 12/21] [P073] Make some functions available externally, fix 74HC595 matrix display (sort-of, still some flickering) --- src/_P073_7DGT.ino | 38 +++++---- src/src/PluginStructs/P073_data_struct.cpp | 95 ++++++++++++++++------ src/src/PluginStructs/P073_data_struct.h | 11 ++- 3 files changed, 99 insertions(+), 45 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 81ef69ffb1..af34ecd2a9 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,8 @@ // /** History + * 2024-08-23 tonhuisman: The 74HC595 Matrix displays mostly work, with the higest possible refresh rate. Still a bit of flickering, + * but that might require adding extra hardware to solve. * 2024-08-08 tonhuisman: Add double-buffering for 74HC595 displays to improve update-speed * 2024-08-06 tonhuisman: Make 74HC595 multiplexed displays a separate compile-time option, as these require special treatment * Separate 7-segment font-related functions for re-use by other plugins @@ -198,28 +200,14 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) { P073_CFG_DIGITS = P073_getDefaultDigits(P073_CFG_DISPLAYTYPE); } - { - const __FlashStringHelper *displout[] = { F("Manual"), - F("Clock 24h - Blink"), - F("Clock 24h - No Blink"), - F("Clock 12h - Blink"), - F("Clock 12h - No Blink"), - F("Date") }; - addFormSelector(F("Display Output"), F("displout"), 6, displout, nullptr, P073_CFG_OUTPUTTYPE); - } + + P073_display_output_selector(F("displout"), P073_CFG_OUTPUTTYPE); addFormNumericBox(F("Brightness"), F("brightness"), P073_CFG_BRIGHTNESS, 0, 15); addUnit(F("0..15")); # if P073_EXTRA_FONTS - { - const __FlashStringHelper *fontset[4] = { F("Default"), - F("Siekoo"), - F("Siekoo with uppercase 'CHNORUX'"), - F("dSEG7") }; - addFormSelector(F("Font set"), F("fontset"), 4, fontset, nullptr, P073_CFG_FONTSET); - addFormNote(F("Check documentation for examples of the font sets.")); - } + P073_font_selector(F("fontset"), P073_CFG_FONTSET); # endif // if P073_EXTRA_FONTS addFormSubHeader(F("Options")); @@ -302,6 +290,13 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) if (nullptr != P073_data) { P073_data->init(event); + # if P073_USE_74HC595 + + if (P073_data->is74HC595Matrix()) { + Scheduler.setPluginTaskTimer(0, event->TaskIndex, 0); + } + # endif // if P073_USE_74HC595 + success = true; } break; @@ -342,12 +337,19 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) # endif // if P073_SCROLL_TEXT # if P073_USE_74HC595 - case PLUGIN_FIFTY_PER_SECOND: { + + case PLUGIN_TASKTIMER_IN: { P073_data_struct *P073_data = static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P073_data) { success = P073_data->plugin_fifty_per_second(event); + + if (success) { + Scheduler.setPluginTaskTimer(1, event->TaskIndex, 0); + } + + // success = false; // Don't send out to (not configurable) Controllers or Rules } break; diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index ef6cde17b7..2dd0e92586 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -97,6 +97,68 @@ uint8_t P073_getFontChar(uint8_t index, # endif // if P073_EXTRA_FONTS } +int32_t P073_parse_7dfont(struct EventStruct *event, + const String & text) { + int32_t fontNr = 0; + + # if P073_EXTRA_FONTS + + if (!text.isEmpty()) { + const String fontArg = parseString(text, 1); + fontNr = -1; + + if ((equals(fontArg, F("default"))) || (equals(fontArg, F("7dgt")))) { + fontNr = 0; + } else if (equals(fontArg, F("siekoo"))) { + fontNr = 1; + } else if (equals(fontArg, F("siekoo_upper"))) { + fontNr = 2; + } else if (equals(fontArg, F("dseg7"))) { + fontNr = 3; + } else if (!validIntFromString(text, fontNr)) { + fontNr = -1; // reset if invalid + } + } + # endif // if P073_EXTRA_FONTS + return fontNr; +} + +void P073_display_output_selector(const __FlashStringHelper *id, int16_t value) { + const __FlashStringHelper *displout[] = { + F("Manual"), + F("Clock 24h - Blink"), + F("Clock 24h - No Blink"), + F("Clock 12h - Blink"), + F("Clock 12h - No Blink"), + F("Date"), + }; + const int disploutOptions[] = { + P073_DISP_MANUAL, + P073_DISP_CLOCK24BLNK, + P073_DISP_CLOCK24, + P073_DISP_CLOCK12BLNK, + P073_DISP_CLOCK12, + P073_DISP_DATE, + }; + + addFormSelector(F("Display Output"), id, NR_ELEMENTS(disploutOptions), displout, disploutOptions, value); +} + +# if P073_EXTRA_FONTS +void P073_font_selector(const __FlashStringHelper *id, int16_t value) { + const __FlashStringHelper *fontset[] = { + F("Default"), + F("Siekoo"), + F("Siekoo with uppercase 'CHNORUX'"), + F("dSEG7"), + }; + + addFormSelector(F("Font set"), id, NR_ELEMENTS(fontset), fontset, nullptr, value); + addFormNote(F("Check documentation for examples of the font sets.")); +} + +# endif // if P073_EXTRA_FONTS + void P073_data_struct::init(struct EventStruct *event) { ClearBuffer(); @@ -199,6 +261,10 @@ bool P073_data_struct::plugin_fifty_per_second(struct EventStruct *event) { return false; } +bool P073_data_struct::is74HC595Matrix() { + return P073_74HC595_2_8DGT == displayModel && P073_HC595_MULTIPLEX; +} + // ==================================== // ---- 74HC595 specific functions ---- // ==================================== @@ -212,15 +278,6 @@ void P073_data_struct::hc595_ShowBuffer() { 0b00000001, // right segment }; - // const uint8_t hc595digit6[] = { - // 0b00010000, // left segment - // 0b00100000, - // 0b01000000, - // 0b00000001, - // 0b00000010, - // 0b00000100, // right segment - // }; - const uint8_t hc595digit8[] = { 0b00010000, // left segment 0b00100000, @@ -254,7 +311,7 @@ void P073_data_struct::hc595_ShowBuffer() { # if P073_USE_74HCMULTIPLEX uint8_t digit = 0xFF; - if (!isSequential) { + if (P073_HC595_MULTIPLEX) { if (4 == digits) { digit = hc595digit4[i]; } else @@ -1446,25 +1503,11 @@ bool P073_data_struct::plugin_write_7dtext(const String& text) { bool P073_data_struct::plugin_write_7dfont(struct EventStruct *event, const String & text) { if (!text.isEmpty()) { - const String fontArg = parseString(text, 1); - int32_t fontNr = -1; - - if ((equals(fontArg, F("default"))) || (equals(fontArg, F("7dgt")))) { - fontNr = 0; - } else if (equals(fontArg, F("siekoo"))) { - fontNr = 1; - } else if (equals(fontArg, F("siekoo_upper"))) { - fontNr = 2; - } else if (equals(fontArg, F("dseg7"))) { - fontNr = 3; - } else if (!validIntFromString(text, fontNr)) { - fontNr = -1; // reset if invalid - } - + int32_t fontNr = P073_parse_7dfont(event, text); # ifdef P073_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("P073 7dfont,%s -> %d"), fontArg.c_str(), fontNr)); + addLog(LOG_LEVEL_INFO, strformat(F("P073 7dfont,%s -> %d"), parseString(text, 1).c_str(), fontNr)); } # endif // ifdef P073_DEBUG diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 322e46589a..5049924943 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -51,7 +51,7 @@ # define P073_USE_74HC595 1 // Enable support for 74HC595 based sequential displays # endif // ifndef P073_USE_74HC595 # ifndef P073_USE_74HCMULTIPLEX -# define P073_USE_74HCMULTIPLEX 0 // Enable support for 74HC595 based multiplexing displays +# define P073_USE_74HCMULTIPLEX 1 // Enable support for 74HC595 based multiplexing displays # endif // ifndef P073_USE_74HCMULTIPLEX # if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) @@ -200,6 +200,14 @@ uint8_t P073_mapCharToFontPosition(char character, uint8_t fontset); uint8_t P073_getFontChar(uint8_t index, uint8_t fontset); +int32_t P073_parse_7dfont(struct EventStruct *event, + const String & text); +void P073_display_output_selector(const __FlashStringHelper *id, + int16_t value); +# if P073_EXTRA_FONTS +void P073_font_selector(const __FlashStringHelper *id, + int16_t value); +# endif // if P073_EXTRA_FONTS struct P073_data_struct : public PluginTaskData_base { public: @@ -217,6 +225,7 @@ struct P073_data_struct : public PluginTaskData_base { # if P073_USE_74HC595 bool plugin_fifty_per_second(struct EventStruct *event); + bool is74HC595Matrix(); # endif // if P073_USE_74HC595 void FillBufferWithTime(bool sevendgt_now, uint8_t sevendgt_hours, From 5c1198210ae29ef222edf0fb9cd246b842bd6122 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 24 Aug 2024 14:45:01 +0200 Subject: [PATCH 13/21] [P073] Fine-tuning and allow to include 74HC595 in ESP8266 Custom builds --- src/Custom-sample.h | 2 ++ src/_P073_7DGT.ino | 6 ++++-- src/src/PluginStructs/P073_data_struct.h | 20 ++++++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 77e4468c6f..c1539799a0 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -439,6 +439,8 @@ static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = { // #define USES_P071 // Kamstrup401 // #define USES_P072 // HDC1000/HDC1008/HDC1010/HDC1050/HDC1080 // #define USES_P073 // 7-segment display +// #define P073_USE_74HC595 1 // Enable 74HC595 displays +// #define P073_USE_74HC595_OVERRIDE 1 // Allow 74HC595 displays feature for ESP8266 builds // #define USES_P074 // TSL2591 // #define USES_P075 // Nextion // #define USES_P076 // HLW8012/BL0937 (Shelly Plug S, Sonoff POW R1, Huafan SS, KMC 70011, Aplic WDP303075, SK03 Outdoor, BlitzWolf SHP, Teckin, Teckin US, Gosund SP1 v23) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index af34ecd2a9..4ed7850b38 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,8 @@ // /** History + * 2024-08-24 tonhuisman: Add compiletime define P073_USE_74HC595_OVERRIDE that, when, set to 1, allows 74HC595 displays to be included + * for ESP8266 builds (f.e. Custom builds), also added to Custom-sample.h * 2024-08-23 tonhuisman: The 74HC595 Matrix displays mostly work, with the higest possible refresh rate. Still a bit of flickering, * but that might require adding extra hardware to solve. * 2024-08-08 tonhuisman: Add double-buffering for 74HC595 displays to improve update-speed @@ -293,7 +295,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) # if P073_USE_74HC595 if (P073_data->is74HC595Matrix()) { - Scheduler.setPluginTaskTimer(0, event->TaskIndex, 0); + Scheduler.setPluginTaskTimer(10, event->TaskIndex, 0); } # endif // if P073_USE_74HC595 @@ -346,7 +348,7 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) success = P073_data->plugin_fifty_per_second(event); if (success) { - Scheduler.setPluginTaskTimer(1, event->TaskIndex, 0); + Scheduler.setPluginTaskTimer(0, event->TaskIndex, 0); } // success = false; // Don't send out to (not configurable) Controllers or Rules diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 5049924943..2046025b6e 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -25,12 +25,16 @@ # define P073_DISP_CLOCK12 4 # define P073_DISP_DATE 5 -# define P073_OPTION_PERIOD 0 // Period as dot -# define P073_OPTION_HIDEDEGREE 1 // Hide degree symbol for temperatures -# define P073_OPTION_RIGHTALIGN 2 // Align 7dt output right on MAX7219 display -# define P073_OPTION_SCROLLTEXT 3 // Scroll text > 8 characters -# define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display -# define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display +# define P073_OPTION_PERIOD 0 // Period as dot +# define P073_OPTION_HIDEDEGREE 1 // Hide degree symbol for temperatures +# define P073_OPTION_RIGHTALIGN 2 // Align 7dt output right on MAX7219 display +# define P073_OPTION_SCROLLTEXT 3 // Scroll text > 8 characters +# define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display +# define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display + +# ifndef P073_USE_74HC595_OVERRIDE +# define P073_USE_74HC595_OVERRIDE 0 +# endif // ifndef P073_USE_74HC595_OVERRIDE # ifndef P073_7DDT_COMMAND # define P073_7DDT_COMMAND 1 // Enable 7ddt by default @@ -80,7 +84,7 @@ // # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug # endif // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) -# if defined(ESP8266) +# if defined(ESP8266) && !P073_USE_74HC595_OVERRIDE # if P073_USE_74HC595 # undef P073_USE_74HC595 // Removes the support for 74HC595 displays # define P073_USE_74HC595 0 @@ -89,7 +93,7 @@ # undef P073_USE_74HCMULTIPLEX // Removes the support for 74HC595 multiplexed displays # define P073_USE_74HCMULTIPLEX 0 # endif // if P073_USE_74HCMULTIPLEX -# endif // if defined(ESP8266) +# endif // if defined(ESP8266) && !P073_USE_74HC595_OVERRIDE # define TM1637_POWER_ON 0b10001000 # define TM1637_POWER_OFF 0b10000000 From 9aca5902535fdfb4f976b0f9c168a909bd808ade Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 1 Sep 2024 15:55:37 +0200 Subject: [PATCH 14/21] [P073] Make P073_revert7bits() available for global use --- src/src/PluginStructs/P073_data_struct.cpp | 35 +++++++++++----------- src/src/PluginStructs/P073_data_struct.h | 2 +- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 2dd0e92586..827d55b775 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -159,6 +159,20 @@ void P073_font_selector(const __FlashStringHelper *id, int16_t value) { # endif // if P073_EXTRA_FONTS +/** + * This function reverts the 7 databits/segmentbits so TM1637 and 74HC595 displays work with fonts designed for MAX7219. + * Dot/colon bit is still bit 8 + */ +uint8_t P073_revert7bits(uint8_t character) { + uint8_t newCharacter = character & 0x80; // Keep dot-bit if passed in + + for (int b = 0; b < 7; ++b) { + if (character & (0x01 << b)) { + newCharacter |= (0x40 >> b); + } + } + return newCharacter; +} void P073_data_struct::init(struct EventStruct *event) { ClearBuffer(); @@ -360,7 +374,7 @@ void P073_data_struct::hc595_ToOutputBuffer() { if (showperiods[i]) { value &= 0x7F; } - outputbuffer[i] = mapMAX7219FontToTM1637Font(value); // Rotate bits 6..0 + outputbuffer[i] = P073_getFontChar(value); // Rotate bits 6..0 } } @@ -791,24 +805,9 @@ void P073_data_struct::ClearBuffer() { } } -/** - * This function reverts the 7 databits/segmentbits so TM1637 and 74HC595 displays work with fonts designed for MAX7219. - * Dot/colon bit is still bit 8 - */ -uint8_t P073_data_struct::mapMAX7219FontToTM1637Font(uint8_t character) { - uint8_t newCharacter = character & 0x80; // Keep dot-bit if passed in - - for (int b = 0; b < 7; ++b) { - if (character & (0x01 << b)) { - newCharacter |= (0x40 >> b); - } - } - return newCharacter; -} - uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, uint8_t fontset) { - return mapMAX7219FontToTM1637Font(P073_getFontChar(index, fontset)); + return P073_getFontChar(P073_getFontChar(index, fontset)); } bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { @@ -1534,7 +1533,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { data += static_cast(displayModel == P073_MAX7219_8DGT ? byteValue : - mapMAX7219FontToTM1637Font(byteValue)); + P073_getFontChar(byteValue)); } arg++; argValue = parseString(text, arg); diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 2046025b6e..cb3a050057 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -212,6 +212,7 @@ void P073_display_output_selector(const __FlashStringHelper *id, void P073_font_selector(const __FlashStringHelper *id, int16_t value); # endif // if P073_EXTRA_FONTS +uint8_t P073_revert7bits(uint8_t character); struct P073_data_struct : public PluginTaskData_base { public: @@ -278,7 +279,6 @@ struct P073_data_struct : public PluginTaskData_base { void FillBufferWithDash(); void ClearBuffer(); - uint8_t mapMAX7219FontToTM1637Font(uint8_t character); uint8_t tm1637_getFontChar(uint8_t index, uint8_t fontset); From a58fec9f9222eb163af73940b6b0d186c9d35c87 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 1 Sep 2024 16:12:33 +0200 Subject: [PATCH 15/21] [P073] Fix copy/paste error --- src/src/PluginStructs/P073_data_struct.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 827d55b775..cad518042d 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -374,7 +374,7 @@ void P073_data_struct::hc595_ToOutputBuffer() { if (showperiods[i]) { value &= 0x7F; } - outputbuffer[i] = P073_getFontChar(value); // Rotate bits 6..0 + outputbuffer[i] = P073_revert7bits(value); // Rotate bits 6..0 } } @@ -807,7 +807,7 @@ void P073_data_struct::ClearBuffer() { uint8_t P073_data_struct::tm1637_getFontChar(uint8_t index, uint8_t fontset) { - return P073_getFontChar(P073_getFontChar(index, fontset)); + return P073_revert7bits(P073_getFontChar(index, fontset)); } bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { @@ -1533,7 +1533,7 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { if (validIntFromString(argValue, byteValue) && (byteValue < 256) && (byteValue > -1)) { data += static_cast(displayModel == P073_MAX7219_8DGT ? byteValue : - P073_getFontChar(byteValue)); + P073_revert7bits(byteValue)); } arg++; argValue = parseString(text, arg); From b3f5363c8a6b91fa351700e3a131525fed0541d7 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 2 Sep 2024 23:22:34 +0200 Subject: [PATCH 16/21] [P073] Use more efficient bit-revert algorithm, as suggested --- src/src/PluginStructs/P073_data_struct.cpp | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index cad518042d..5c97c7605c 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -164,15 +164,24 @@ void P073_font_selector(const __FlashStringHelper *id, int16_t value) { * Dot/colon bit is still bit 8 */ uint8_t P073_revert7bits(uint8_t character) { - uint8_t newCharacter = character & 0x80; // Keep dot-bit if passed in + uint8_t dpBit = character & 0x80; // Keep dot-bit if passed in + uint8_t b = character << 1; // Pre-shift as only 7 bits to revert - for (int b = 0; b < 7; ++b) { - if (character & (0x01 << b)) { - newCharacter |= (0x40 >> b); - } - } - return newCharacter; + // Source: https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious + # ifdef ESP8266 + + // 32 bit 7 operations variant, 64 bit operations is quite slow on ESP8266, but fast on most ESP32 variants + b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + # endif // ifdef ESP8266 + # ifdef ESP32 + + // 64 bit 4 operations variant + b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; + # endif // ifdef ESP32 + + return b | dpBit; // Restore dot-bit } + void P073_data_struct::init(struct EventStruct *event) { ClearBuffer(); From b9e48807dd8419cff7484dd8b94fc608bb38cccf Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 27 Sep 2024 22:00:46 +0200 Subject: [PATCH 17/21] [P073] Add option for time-blinking the second dot instead of the colon --- src/_P073_7DGT.ino | 7 +++++++ src/src/PluginStructs/P073_data_struct.cpp | 14 +++++++++++++- src/src/PluginStructs/P073_data_struct.h | 11 +++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index 4ed7850b38..b0485ca1b9 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,7 @@ // /** History + * 2024-09-27 tonhuisman: Add option to flash dot on second digit instead of the colon for blinking time * 2024-08-24 tonhuisman: Add compiletime define P073_USE_74HC595_OVERRIDE that, when, set to 1, allows 74HC595 displays to be included * for ESP8266 builds (f.e. Custom builds), also added to Custom-sample.h * 2024-08-23 tonhuisman: The 74HC595 Matrix displays mostly work, with the higest possible refresh rate. Still a bit of flickering, @@ -225,6 +226,9 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) # if P073_SUPPRESS_ZERO addFormCheckBox(F("Suppress leading 0 on day/hour"), F("supp0"), bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0)); # endif // if P073_SUPPRESS_ZERO + #if P073_BLINK_DOT + addFormCheckBox(F("Use decimal dot for blink"), F("bldot"), bitRead(P073_CFG_FLAGS, P073_OPTION_BLINK_DOT)); + #endif // if P073_BLINK_DOT # if P073_SCROLL_TEXT addFormCheckBox(F("Scroll text > display width"), F("scroll_text"), bitRead(P073_CFG_FLAGS, P073_OPTION_SCROLLTEXT)); @@ -264,6 +268,9 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) # if P073_SUPPRESS_ZERO bitWrite(lSettings, P073_OPTION_SUPPRESS0, isFormItemChecked(F("supp0"))); # endif // if P073_SUPPRESS_ZERO + #if P073_BLINK_DOT + bitWrite(lSettings, P073_OPTION_BLINK_DOT, isFormItemChecked(F("bldot"))); + #endif // if P073_BLINK_DOT # if P073_EXTRA_FONTS P073_CFG_FONTSET = getFormItemInt(F("fontset")); # endif // if P073_EXTRA_FONTS diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 5c97c7605c..43934b35cf 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -200,7 +200,10 @@ void P073_data_struct::init(struct EventStruct *event) # endif // if P073_SCROLL_TEXT rightAlignTempMAX7219 = bitRead(P073_CFG_FLAGS, P073_OPTION_RIGHTALIGN); suppressLeading0 = bitRead(P073_CFG_FLAGS, P073_OPTION_SUPPRESS0); - timesep = true; + #if P073_BLINK_DOT + blinkdot = bitRead(P073_CFG_FLAGS, P073_OPTION_BLINK_DOT); + #endif // if P073_BLINK_DOT + timesep = true; # if P073_EXTRA_FONTS fontset = P073_CFG_FONTSET; # endif // if P073_EXTRA_FONTS @@ -850,6 +853,15 @@ bool P073_data_struct::plugin_once_a_second(struct EventStruct *event) { ); } + #if P073_BLINK_DOT + + if (blinkdot && + ((output == P073_DISP_CLOCK24BLNK) || + (output == P073_DISP_CLOCK12BLNK))) { + showperiods[1] = timesep; // Blink dot on second digit + } + #endif // if P073_BLINK_DOT + switch (displayModel) { case P073_TM1637_4DGTCOLON: case P073_TM1637_4DGTDOTS: diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index cb3a050057..63770e6d9b 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -31,6 +31,7 @@ # define P073_OPTION_SCROLLTEXT 3 // Scroll text > 8 characters # define P073_OPTION_SCROLLFULL 4 // Scroll text from the right in, starting with a blank display # define P073_OPTION_SUPPRESS0 5 // Suppress leading zero on day/hour of Date/Time display +# define P073_OPTION_BLINK_DOT 6 // Use dot on second digit for flashing instead of colon # ifndef P073_USE_74HC595_OVERRIDE # define P073_USE_74HC595_OVERRIDE 0 @@ -51,6 +52,9 @@ # ifndef P073_SUPPRESS_ZERO # define P073_SUPPRESS_ZERO 1 // Enable Suppress leading zero on day/hour # endif // ifndef P073_SUPPRESS_ZERO +# ifndef P073_BLINK_DOT +# define P073_BLINK_DOT 1 // Use dot for blinking time +# endif // ifndef P073_BLINK_DOT # ifndef P073_USE_74HC595 # define P073_USE_74HC595 1 // Enable support for 74HC595 based sequential displays # endif // ifndef P073_USE_74HC595 @@ -79,6 +83,10 @@ # undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is problematic, remove the Suppress leading zero feature # define P073_SUPPRESS_ZERO 0 # endif // if P073_SUPPRESS_ZERO +# if P073_BLINK_DOT +# undef P073_BLINK_DOT // Optionally activate if .bin file space is problematic, remove the Blink dot feature +# define P073_BLINK_DOT 0 +# endif // if P073_BLINK_DOT # else // if defined(PLUGIN_SET_COLLECTION) && defined(ESP8266) // # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug @@ -300,6 +308,9 @@ struct P073_data_struct : public PluginTaskData_base { bool rightAlignTempMAX7219 = false; bool suppressLeading0 = false; uint8_t fontset = 0; + #if P073_BLINK_DOT + bool blinkdot = false; + #endif // if P073_BLINK_DOT # if P073_7DBIN_COMMAND bool binaryData = false; # endif // P073_7DBIN_COMMAND From 11c2a300f997e8bd60db198ea68353ff5c4a85ef Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 28 Sep 2024 16:39:53 +0200 Subject: [PATCH 18/21] [P073] Use DIRECT_PIN_IO for TM1637 displays for better timing accuracy --- src/_P073_7DGT.ino | 1 + src/src/PluginStructs/P073_data_struct.cpp | 26 +++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index b0485ca1b9..c8fa951eea 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -42,6 +42,7 @@ // /** History + * 2024-09-28 tonhuisman: Switch to using DIRECT_PIN_IO, to get better timing-accuracy for TM1637 displays * 2024-09-27 tonhuisman: Add option to flash dot on second digit instead of the colon for blinking time * 2024-08-24 tonhuisman: Add compiletime define P073_USE_74HC595_OVERRIDE that, when, set to 1, allows 74HC595 displays to be included * for ESP8266 builds (f.e. Custom builds), also added to Custom-sample.h diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index 43934b35cf..d180bd6d7f 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -2,6 +2,8 @@ #ifdef USES_P073 +# include + uint8_t P073_getDefaultDigits(uint8_t displayModel, uint8_t digits) { const uint8_t digitsSet[] = { 4, 4, 6, 8, 0 }; // Fixed except 74HC595 @@ -1610,10 +1612,10 @@ bool P073_data_struct::plugin_write_7dbin(const String& text) { // ---- TM1637 specific functions ---- // =================================== -# define CLK_HIGH() digitalWrite(this->pin1, HIGH) -# define CLK_LOW() digitalWrite(this->pin1, LOW) -# define DIO_HIGH() pinMode(this->pin2, INPUT) -# define DIO_LOW() pinMode(this->pin2, OUTPUT) +# define CLK_HIGH() DIRECT_pinWrite(this->pin1, HIGH) +# define CLK_LOW() DIRECT_pinWrite(this->pin1, LOW) +# define DIO_HIGH() DIRECT_PINMODE_INPUT(this->pin2) +# define DIO_LOW() DIRECT_PINMODE_OUTPUT(this->pin2) //; DIRECT_pinWrite(this->pin2, LOW) void P073_data_struct::tm1637_i2cStart() { # ifdef P073_DEBUG @@ -1649,7 +1651,7 @@ void P073_data_struct::tm1637_i2cAck() { # ifdef P073_DEBUG const bool dummyAck = # endif // ifdef P073_DEBUG - digitalRead(pin2); + DIRECT_pinRead(pin2); # ifdef P073_DEBUG @@ -1667,11 +1669,17 @@ void P073_data_struct::tm1637_i2cAck() { CLK_HIGH(); delayMicroseconds(TM1637_CLOCKDELAY); CLK_LOW(); - pinMode(pin2, OUTPUT); + DIO_LOW(); } void P073_data_struct::tm1637_i2cWrite_ack(uint8_t bytesToPrint[], uint8_t length) { + #ifdef P073_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("7DGT : TM1637 databuffer: 0x"), formatToHex_array(bytesToPrint, length))); + } + #endif // ifdef P073_DEBUG tm1637_i2cStart(); for (uint8_t i = 0; i < length; ++i) { @@ -1731,8 +1739,10 @@ void P073_data_struct::tm1637_SetPowerBrightness(uint8_t brightlvl, } void P073_data_struct::tm1637_InitDisplay() { - pinMode(pin1, OUTPUT); - pinMode(pin2, OUTPUT); + // pinMode(pin1, OUTPUT); + // pinMode(pin2, OUTPUT); + directModeOutput(pin1); + directModeOutput(pin2); CLK_HIGH(); DIO_HIGH(); From 1270445af6641a20325d9605217f57196071ae83 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 28 Sep 2024 16:40:12 +0200 Subject: [PATCH 19/21] [P073] Update documentation --- docs/source/Plugin/P073.rst | 2 ++ .../Plugin/P073_DeviceConfiguration.png | Bin 56209 -> 58188 bytes 2 files changed, 2 insertions(+) diff --git a/docs/source/Plugin/P073.rst b/docs/source/Plugin/P073.rst index 991e597cf1..11185fa0c1 100644 --- a/docs/source/Plugin/P073.rst +++ b/docs/source/Plugin/P073.rst @@ -137,6 +137,8 @@ Options * **Suppress leading 0 on day/hour**: When enabled, will show the hours of the time and days of the date without a leading 0 when < 10. (Not available in all builds for size reasons) +* **Use decimal dot for blink**: When enabled will use the decimal dot on the second digit for blinking, when no colon is available. Not applicable for MAX7219 and TM1637 6-digit displays, as they already use alternative blink options. + * **Scroll text > display width**: Normally the ``7dtext,`` command only show the left n characters the display can hold. This option enables the Scroll Text feature, that will scroll text sent using the ``7dtext`` command (or ``7dbin`` command when available) from right to left when the content is longer than the display can show at once. * **Scroll text in from right**: Normally the Scroll Text feature starts with the display filled with the left part of the text to scroll, with this option enabled, the display starts empty and the text is scrolled in from the right side of the display to the left, until all text is scrolled off. Then the scrolling restarts. diff --git a/docs/source/Plugin/P073_DeviceConfiguration.png b/docs/source/Plugin/P073_DeviceConfiguration.png index a83dbad5e9d0e8ebd7d1026989806f54ca4e7779..dbc458a4449dad470a3bce5aa6733fc561ce435d 100644 GIT binary patch literal 58188 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 literal 56209 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 From 564d9c8378bccca4870509a5ee7fea7728f63d72 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 28 Sep 2024 20:19:38 +0200 Subject: [PATCH 20/21] [P073] Should use the public function --- src/src/PluginStructs/P073_data_struct.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index d180bd6d7f..47aacc98a0 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -1739,10 +1739,8 @@ void P073_data_struct::tm1637_SetPowerBrightness(uint8_t brightlvl, } void P073_data_struct::tm1637_InitDisplay() { - // pinMode(pin1, OUTPUT); - // pinMode(pin2, OUTPUT); - directModeOutput(pin1); - directModeOutput(pin2); + DIRECT_PINMODE_OUTPUT(pin1); + DIRECT_PINMODE_OUTPUT(pin2); CLK_HIGH(); DIO_HIGH(); From 916d84a9203644fc9a7d6d7ba72521bde30417a5 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 1 Oct 2024 22:58:30 +0200 Subject: [PATCH 21/21] [P165] Fix compiler warning --- src/src/PluginStructs/P165_data_struct.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P165_data_struct.cpp b/src/src/PluginStructs/P165_data_struct.cpp index 48d4eebda8..a4b544506a 100644 --- a/src/src/PluginStructs/P165_data_struct.cpp +++ b/src/src/PluginStructs/P165_data_struct.cpp @@ -475,7 +475,7 @@ bool P165_data_struct::plugin_webform_load(struct EventStruct *event) { numberPlan); totalPixels += grpOffs; - const uint8_t strt = grpStart + grpGstrt << 1; + const uint8_t strt = grpStart + (grpGstrt << 1); addRowLabel(F("Starting segment")); addSelector(concat(F("strt"), grp10), NR_ELEMENTS(startPixelOptions),