21_OWLCD.pm 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153
  1. ########################################################################################
  2. #
  3. # OWLCD.pm
  4. #
  5. # FHEM module to commmunicate with the 1-Wire LCD hardware
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. #
  9. # $Id: 21_OWLCD.pm 15339 2017-10-29 08:14:07Z phenning $
  10. #
  11. ########################################################################################
  12. #
  13. # define <name> OWLCD <ROM_ID> or FF.<ROM_ID>
  14. #
  15. # where <name> may be replaced by any name string
  16. #
  17. # <ROM_ID> is a 12 character (6 byte) 1-Wire ROM ID
  18. # without Family ID, e.g. A2D90D000800
  19. #
  20. # get <name> id => FF.ROM_ID.CRC
  21. # get <name> gpio => current state of the gpio pins (15 = all off, 0 = all on)
  22. # get <name> counter => four values (16 Bit) of the gpio counter
  23. # get <name> version => firmware version of the LCD adapter
  24. # get <name> memory <page> => get one of the internal memory pages 0..6
  25. # get <name> version => OWX version number
  26. #
  27. # set <name> alert red|yellow|beep|none => set one of the alert states (gpio pins)
  28. # set <name> icon <num> on|off|blink => set one of the icons 0..14
  29. # set <name> icon 15 0..6 => set icon no. 15 in one of its values
  30. # set <name> line <line> <string(s)> => set one of the display lines 0..3
  31. # set <name> memory <page> <string(s) => set one of the internal memory pages 0..6
  32. # set <name> gpio => state of the gpio pins 0..7
  33. # set <name> backlight on|off => set backlight on or off
  34. # set <name> lcd on|off => set LCD power on or off
  35. # set <name> reset => reset the display
  36. # set <name> test => display a test content
  37. #
  38. # attr <name> lcdgeometry => LCD geometry values are 0-32-64-96 or 0-64-20-84
  39. #
  40. # Careful: Not ASCII ! strange Codepage
  41. ########################################################################################
  42. #
  43. # This programm is free software; you can redistribute it and/or modify
  44. # it under the terms of the GNU General Public License as published by
  45. # the Free Software Foundation; either version 2 of the License, or
  46. # (at your option) any later version.
  47. #
  48. # The GNU General Public License can be found at
  49. # http://www.gnu.org/copyleft/gpl.html.
  50. # A copy is found in the textfile GPL.txt and important notices to the license
  51. # from the author is found in LICENSE.txt distributed with these scripts.
  52. #
  53. # This script is distributed in the hope that it will be useful,
  54. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  55. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  56. # GNU General Public License for more details.
  57. #
  58. ########################################################################################
  59. package main;
  60. use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
  61. use Time::HiRes qw(gettimeofday);
  62. use strict;
  63. use warnings;
  64. #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
  65. BEGIN {
  66. if (!grep(/FHEM\/lib$/,@INC)) {
  67. foreach my $inc (grep(/FHEM$/,@INC)) {
  68. push @INC,$inc."/lib";
  69. };
  70. };
  71. };
  72. use GPUtils qw(:all);
  73. use ProtoThreads;
  74. no warnings 'deprecated';
  75. sub Log3($$$);
  76. my $owx_version="7.01";
  77. #-- controller may be HD44780 or KS0073
  78. # these values can be changed by attribute for different display
  79. # geometries or memory maps
  80. my $lcdcontroller = "KS0073";
  81. my $lcdlines = 4;
  82. my $lcdchars = 20;
  83. my @lcdpage = (0,32,64,96);
  84. #-- declare variables
  85. my %gets = (
  86. "id" => ":noArg",
  87. "memory" => ":noArg",
  88. "gpio" => ":noArg",
  89. "counter" => ":noArg",
  90. "version" => ":noArg"
  91. #"register" => "",
  92. #"data" => ""
  93. );
  94. my %sets = (
  95. "icon" => "",
  96. "line" => "",
  97. "memory" => "",
  98. "gpio" => "",
  99. "gpiobit" => "",
  100. "backlight" => "",
  101. "lcd" => "",
  102. "reset" => "",
  103. "test" => "",
  104. "initialize" => ""
  105. );
  106. my %updates = ();
  107. ########################################################################################
  108. #
  109. # The following subroutines are independent of the bus interface
  110. #
  111. # Prefix = OWLCD
  112. #
  113. ########################################################################################
  114. #
  115. # OWLCD_Initialize
  116. #
  117. # Parameter hash = hash of device addressed
  118. #
  119. ########################################################################################
  120. sub OWLCD_Initialize ($) {
  121. my ($hash) = @_;
  122. $hash->{DefFn} = "OWLCD_Define";
  123. $hash->{UndefFn} = "OWLCD_Undef";
  124. $hash->{GetFn} = "OWLCD_Get";
  125. $hash->{SetFn} = "OWLCD_Set";
  126. $hash->{NotifyFn} = "OWLCD_Notify";
  127. $hash->{InitFn} = "OWLCD_Init";
  128. $hash->{AttrFn} = "OWLCD_Attr";
  129. my $attlist = "IODev do_not_notify:0,1 showtime:0,1 ".
  130. "lcdgeometry:0-32-64-96,0-64-20-84 lcdcontroller:KS0073,HD44780 ".
  131. $readingFnAttributes;
  132. $hash->{AttrList} = $attlist;
  133. #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer
  134. main::LoadModule("OWX");
  135. }
  136. #########################################################################################
  137. #
  138. # OWLCD_Define - Implements DefFn function
  139. #
  140. # Parameter hash = hash of device addressed, def = definition string
  141. #
  142. #########################################################################################
  143. sub OWLCD_Define ($$) {
  144. my ($hash, $def) = @_;
  145. #-- define <name> OWLCD <ROM_ID>
  146. my @a = split("[ \t][ \t]*", $def);
  147. my ($name,$fam,$id,$crc,$ret);
  148. #-- default
  149. $name = $a[0];
  150. $ret = "";
  151. #-- check syntaxeverywhere, everytime
  152. return "OWLCD: Wrong syntax, must be define <name> OWLCD <id>"
  153. if(int(@a) !=3 );
  154. #-- check id
  155. if( $a[2] =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  156. $id = $a[2];
  157. } elsif( $a[2] =~ m/^FF\.[0-9|a-f|A-F]{12}$/ ) {
  158. $id = substr($a[2],3);
  159. } else {
  160. return "OWLCD: $a[0] ID $a[2] invalid, specify a 12 digit or 2.12 digit value";
  161. }
  162. #-- 1-Wire ROM identifier in the form "FF.XXXXXXXXXXXX.YY"
  163. # determine CRC Code - only if this is a direct interface
  164. $crc = defined($hash->{IODev}->{INTERFACE}) ? sprintf("%02x",OWX_CRC("FF.".$id."00")) : "00";
  165. #-- Define device internals
  166. $hash->{ROM_ID} = "FF.".$id.$crc;
  167. $hash->{OW_ID} = $id;
  168. $hash->{OW_FAMILY} = "FF";
  169. $hash->{PRESENT} = 0;
  170. $hash->{ERRCOUNT} = 0;
  171. #-- Couple to I/O device
  172. AssignIoPort($hash);
  173. if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
  174. return "OWLCD: Warning, no 1-Wire I/O device found for $name.";
  175. } else {
  176. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; #-- false for now
  177. }
  178. $modules{OWLCD}{defptr}{$id} = $hash;
  179. $hash->{STATE} = "Defined";
  180. Log3 $name,3, "OWLCD: Device $name defined.";
  181. $hash->{NOTIFYDEV} = "global";
  182. if ($main::init_done) {
  183. return OWLCD_Init($hash);
  184. }
  185. return undef;
  186. }
  187. ########################################################################################
  188. #
  189. # OWLCD_Notify - Implements Notify function
  190. #
  191. # Parameter hash = hash of device addressed
  192. #
  193. ########################################################################################
  194. sub OWLCD_Notify ($$) {
  195. my ($hash,$dev) = @_;
  196. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  197. OWLCD_Init($hash);
  198. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  199. }
  200. }
  201. ########################################################################################
  202. #
  203. # OWLCD_Init - Implements Init function
  204. #
  205. # Parameter hash = hash of device addressed
  206. #
  207. ########################################################################################
  208. sub OWLCD_Init($) {
  209. my ($hash) = @_;
  210. #-- Initialization reading according to interface type
  211. my $interface= $hash->{IODev}->{TYPE};
  212. #-- OWX interface
  213. if( $interface eq "OWX" ){
  214. OWXLCD_InitializeDevice($hash);
  215. #-- set backlight on
  216. OWXLCD_SetFunction($hash,"bklon",0);
  217. #-- erase all icons
  218. OWXLCD_SetIcon($hash,0,0);
  219. #-- erase alarm state
  220. OWXLCD_SetFunction($hash,"gpio",15);
  221. } elsif ( $interface eq "OWX_ASYNC" ) {
  222. eval {
  223. OWXLCD_InitializeDevice($hash);
  224. #-- set backlight on
  225. OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetFunction($hash,"bklon",0));
  226. #-- erase all icons
  227. OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetIcon($hash,0,0));
  228. #-- erase alarm state
  229. OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetFunction($hash,"gpio",15));
  230. };
  231. return GP_Catch($@) if $@;
  232. #-- Unknown interface
  233. }else{
  234. return "OWLCD: Wrong IODev type $interface";
  235. }
  236. $hash->{STATE} = "Initialized";
  237. return undef;
  238. }
  239. #######################################################################################
  240. #
  241. # OWLCD_Attr - Set one attribute value for device
  242. #
  243. # Parameter hash = hash of device addressed
  244. # a = argument array
  245. #
  246. ########################################################################################
  247. sub OWLCD_Attr(@) {
  248. my ($do,$name,$key,$value) = @_;
  249. my $hash = $defs{$name};
  250. my $ret;
  251. if ( $do eq "set") {
  252. ARGUMENT_HANDLER: {
  253. $key eq "IODev" and do {
  254. AssignIoPort($hash,$value);
  255. if( defined($hash->{IODev}) ) {
  256. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  257. if ($main::init_done) {
  258. return OWLCD_Init($hash);
  259. }
  260. }
  261. last;
  262. };
  263. $key eq "lcdgeometry" and do {
  264. if( $value eq "0-32-64-96" ){
  265. @lcdpage = (0,32,64,96);
  266. }elsif( $value eq "0-64-20-84" ){
  267. @lcdpage = (0,64,20,84);
  268. }
  269. last;
  270. };
  271. $key eq "lcdcontroller" and do {
  272. if( $value eq "KS0073," ){
  273. $lcdcontroller = "KS0073";
  274. }elsif( $value eq "HD44780" ){
  275. $lcdcontroller = "HD44780";
  276. }
  277. last;
  278. };
  279. };
  280. #} elsif ( $do eq "del" ) {
  281. # ARGUMENT_HANDLER: {
  282. # #-- empty so far
  283. # }
  284. }
  285. return $ret;
  286. }
  287. ########################################################################################
  288. #
  289. # OWLCD_Get - Implements GetFn function
  290. #
  291. # Parameter hash = hash of device addressed, a = argument array
  292. #
  293. ########################################################################################
  294. sub OWLCD_Get($@) {
  295. my ($hash, @a) = @_;
  296. my $reading = $a[1];
  297. my $name = $hash->{NAME};
  298. my $model = $hash->{OW_MODEL};
  299. my $master = $hash->{IODev};
  300. my $interface = $hash->{IODev}->{TYPE};
  301. my $value = undef;
  302. my $ret = "";
  303. my $offset;
  304. my $factor;
  305. #-- check syntax
  306. return "OWLCD: Get argument is missing @a"
  307. if(int(@a) < 2);
  308. #-- check argument
  309. my $msg = "OWLCD: Get with unknown argument $a[1], choose one of ";
  310. $msg .= "$_$gets{$_} " foreach (keys%gets);
  311. return $msg
  312. if(!defined($gets{$a[1]}));
  313. #-- get id
  314. if($a[1] eq "id") {
  315. $value = $hash->{ROM_ID};
  316. return "$name.id => $value";
  317. }
  318. #-- get gpio states
  319. if($a[1] eq "gpio") {
  320. #-- OWX interface
  321. if( $interface eq "OWX" ){
  322. $value = OWXLCD_Get($hash,"gpio");
  323. #-- process result
  324. if( $master->{ASYNCHRONOUS} ){
  325. #return "OWLCD: $name getting gpio, please wait for completion";
  326. return undef;
  327. }else{
  328. return "$name.gpio => $value";
  329. }
  330. }elsif( $interface eq "OWX_ASYNC" ){
  331. eval {
  332. $ret = OWX_ASYNC_RunToCompletion($hash,OWXLCD_PT_Get($hash,"gpio"));
  333. };
  334. $ret = GP_Catch($@) if $@;
  335. return $ret if $ret;
  336. return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"gpio","");
  337. #-- OWFS interface
  338. }elsif( $interface eq "OWServer" ){
  339. #-- Unknown interface
  340. }else{
  341. return "OWLCD: Get with wrong IODev type $interface";
  342. }
  343. }
  344. #-- get counters
  345. if($a[1] eq "counter") {
  346. #-- OWX interface
  347. if( $interface eq "OWX" ){
  348. $value = OWXLCD_Get($hash,"counter");
  349. #-- process result
  350. if( $master->{ASYNCHRONOUS} ){
  351. #return "OWLCD: $name getting counter, please wait for completion";
  352. return undef;
  353. }else{
  354. return "$name.counter => $value";
  355. }
  356. }elsif( $interface eq "OWX_ASYNC" ){
  357. eval {
  358. $ret = OWX_ASYNC_RunToCompletion($hash,OWXLCD_PT_Get($hash,"counter"));
  359. };
  360. $ret = GP_Catch($@) if $@;
  361. return $ret if $ret;
  362. return "$name.counter => ".main::ReadingsVal($hash->{NAME},"counter","");
  363. #-- OWFS interface
  364. }elsif( $interface eq "OWServer" ){
  365. #-- Unknown interface
  366. }else{
  367. return "OWLCD: Get with wrong IODev type $interface";
  368. }
  369. }
  370. #-- get version
  371. if($a[1] eq "version") {
  372. #-- OWX interface
  373. if( $interface eq "OWX" ){
  374. $value = OWXLCD_Get($hash,"version");
  375. #-- process result
  376. if( $master->{ASYNCHRONOUS} ){
  377. #return "OWLCD: $name getting version, please wait for completion";
  378. return undef;
  379. }else{
  380. return "$name.version => $owx_version (LCD firmware $value)";
  381. }
  382. }elsif( $interface eq "OWX_ASYNC" ){
  383. eval {
  384. $ret = OWX_ASYNC_RunToCompletion($hash,OWXLCD_PT_Get($hash,"version"));
  385. };
  386. $ret = GP_Catch($@) if $@;
  387. return $ret if $ret;
  388. return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"version","");
  389. #-- OWFS interface
  390. }elsif( $interface eq "OWServer" ){
  391. #-- Unknown interface
  392. }else{
  393. return "OWLCD: Get with wrong IODev type $interface";
  394. }
  395. }
  396. #-- get EEPROM content
  397. if($a[1] eq "memory") {
  398. my $page = (defined $a[2] and $a[2] =~ m/\d/) ? int($a[2]) : 0;
  399. #-- OWX interface
  400. if( $interface eq "OWX" ){
  401. $value = OWXLCD_GetMemory($hash,$page);
  402. #-- process result
  403. if( $master->{ASYNCHRONOUS} ){
  404. #return "OWLCD: $name memory page $page, please wait for completion";
  405. return undef;
  406. }else{
  407. return "$name $reading $page => $value";
  408. }
  409. }elsif( $interface eq "OWX_ASYNC" ){
  410. eval {
  411. $ret = OWX_ASYNC_RunToCompletion($hash,OWXLCD_PT_GetMemory($hash,$page));
  412. };
  413. $ret = GP_Catch($@) if $@;
  414. return $ret if $ret;
  415. return "$name $reading $page => ".main::ReadingsVal($hash->{NAME},"memory$page","");
  416. #-- OWFS interface
  417. }elsif( $interface eq "OWServer" ){
  418. #-- Unknown interface
  419. }else{
  420. return "OWLCD: Get with wrong IODev type $interface";
  421. }
  422. }
  423. }
  424. #######################################################################################
  425. #
  426. # OWLCD_Set - Set one value for device
  427. #
  428. # Parameter hash = hash of device addressed
  429. # a = argument array
  430. #
  431. ########################################################################################
  432. sub OWLCD_Set($@) {
  433. my ($hash, @a) = @_;
  434. my $interface = $hash->{IODev}->{TYPE};
  435. my $key = $a[1];
  436. my $value = $a[2];
  437. my ($line,$icon,$i);
  438. #-- for the selector: which values are possible
  439. return join(" ", keys %sets)
  440. if ( (@a == 2) && !(($key eq "reset") || ($key eq "test") || ($key eq "initialize")) );
  441. #-- check argument
  442. if( !defined($sets{$a[1]}) ){
  443. return "OWLCD: Set with unknown argument $a[1]";
  444. }
  445. #-- check syntax for setting line
  446. if( $key eq "line" ){
  447. return "OWLCD: Set needs one or two parameters when setting line value: <#line> <string>"
  448. if( int(@a)<3 );
  449. $line = ($a[2] =~ m/\d/) ? $a[2] : 0;
  450. $value = $a[3];
  451. if( defined($value) ){
  452. for( $i=4; $i< int(@a); $i++){
  453. $value .= " ".$a[$i];
  454. }
  455. }else{
  456. $value="";
  457. }
  458. #-- check syntax for setting memory
  459. } elsif( $key eq "memory" ){
  460. return "OWLCD: Set needs two parameters when setting memory page 0/1: <#page> <string>"
  461. if( int(@a)<4 );
  462. $line = ($a[2] =~ m/\d/) ? int($a[2]) : 0;
  463. $value = $a[3];
  464. for( $i=4; $i< int(@a); $i++){
  465. $value .= " ".$a[$i];
  466. }
  467. #-- check syntax for setting icon
  468. } elsif ( $key eq "icon" ){
  469. if( ($a[2] ne "0") && ($a[2] ne "none") ){
  470. return "OWLCD: Set needs two parameters when setting icon 0-16 value: <#icon> on/off/blink (resp. 0..5/off/blink for #16)"
  471. if( (int(@a)!=4) );
  472. $icon = ($a[2] =~ m/\d\d?/) ? $a[2] : 0;
  473. $value = $a[3];
  474. } else {
  475. return "OWLCD: Set needs only one parameter when resetting icons"
  476. if( (int(@a)!=3) );
  477. $icon = 0;
  478. $value = "OFF";
  479. }
  480. #-- check syntax for setting gpiobit
  481. } elsif ( $key eq "gpiobit" ){
  482. return "OWLCD: Set needs two parameters when setting gpiobit 1-3 value: <#bit> on/off"
  483. if( (int(@a)!=4) );
  484. return "OWLCD: Set gpiobit 1-3 value: <#bit> on/off only possible for bits 1-3"
  485. if( $a[2]>3 || $a[2]<1 );
  486. #-- check syntax for reset and test and initialize
  487. } elsif ( ($key eq "reset") || ($key eq "test") || ($key eq "initialize")){
  488. return "OWLCD: Set needs no parameters when setting $key value"
  489. if( int(@a)!=2 );
  490. #-- other syntax
  491. } else {
  492. return "OWLCD: Set needs one parameter when setting $key value"
  493. if( int(@a)!=3 );
  494. }
  495. #-- define vars
  496. my $name = $hash->{NAME};
  497. my $model = $hash->{OW_MODEL};
  498. #-- set gpio ports from all off = to all on = 7
  499. if($key eq "gpio") {
  500. #-- check value and write to device
  501. return "OWLCD: Set with wrong target value for gpio port, must be 0 <= gpio <= 7"
  502. if( ! ((int($value) >= 0) && (int($value) <= 7)) );
  503. #-- OWX interface
  504. if( $interface eq "OWX" ){
  505. return OWXLCD_SetFunction($hash, "gpio", int($value));
  506. }elsif( $interface eq "OWX_ASYNC" ){
  507. eval {
  508. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", int($value)) );
  509. };
  510. return GP_Catch($@) if $@;
  511. }
  512. }
  513. #-- set single gpio bit from all off = 1 on = 0
  514. # contribution from ext323
  515. if($key eq "gpiobit") {
  516. my $bit = $a[2];
  517. $value = lc($a[3]);
  518. $value =~ s/on/0/;
  519. $value =~ s/off/1/;
  520. my $vold = $value;
  521. #-- check value and write to device
  522. return "OWLCD: Set with wrong gpio bit number $bit, must be 1 <= bit <= 3"
  523. if( ($bit < 1) || ($bit > 3) );
  524. return "OWLCD: Set with wrong gpio bit value $value, must be 0=ON or 1=OFF"
  525. if( $value !~ /[01]/ );
  526. if( $value == 1 ){
  527. $value = 1<<($bit-1) | ReadingsVal($name,"gpio",0);
  528. }else{
  529. $value = ~(1<<($bit-1)) & ReadingsVal($name,"gpio",0);
  530. }
  531. #-- OWX interface
  532. if( $interface eq "OWX" ){
  533. OWXLCD_SetFunction($hash,"gpio",$value);
  534. }
  535. }
  536. #-- set LCD ON or OFF
  537. if($key eq "lcd") {
  538. #-- check value and write to device
  539. if( uc($value) eq "ON"){
  540. #-- OWX interface
  541. if( $interface eq "OWX" ){
  542. return OWXLCD_SetFunction($hash, "lcdon", 0);
  543. }elsif( $interface eq "OWX_ASYNC" ){
  544. eval {
  545. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "lcdon", 0) );
  546. };
  547. return GP_Catch($@) if $@;
  548. }
  549. }elsif( uc($value) eq "OFF" ){
  550. #-- OWX interface
  551. if( $interface eq "OWX" ){
  552. return OWXLCD_SetFunction($hash, "lcdoff", 0);
  553. }elsif( $interface eq "OWX_ASYNC" ){
  554. eval {
  555. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "lcdoff", 0) );
  556. };
  557. return GP_Catch($@) if $@;
  558. }
  559. } else {
  560. return "OWLCD: Set with wrong value for lcd, must be on/off"
  561. }
  562. }
  563. #-- set LCD Backlight ON or OFF
  564. if($key eq "backlight") {
  565. #-- check value and write to device
  566. if( uc($value) eq "ON"){
  567. #-- OWX interface
  568. if( $interface eq "OWX" ){
  569. return OWXLCD_SetFunction($hash, "bklon", 0);
  570. }elsif( $interface eq "OWX_ASYNC" ){
  571. eval {
  572. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "bklon", 0) );
  573. };
  574. return GP_Catch($@) if $@;
  575. }
  576. }elsif( uc($value) eq "OFF" ){
  577. #-- OWX interface
  578. if( $interface eq "OWX" ){
  579. return OWXLCD_SetFunction($hash, "bkloff", 0);
  580. }elsif( $interface eq "OWX_ASYNC" ){
  581. eval {
  582. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "bkloff", 0) );
  583. };
  584. return GP_Catch($@) if $@;
  585. }
  586. } else {
  587. return "OWLCD: Set with wrong value for backlight, must be on/off"
  588. }
  589. }
  590. #-- reset
  591. if($key eq "reset") {
  592. #-- OWX interface
  593. if( $interface eq "OWX" ){
  594. OWXLCD_SetFunction($hash,"reset",0);
  595. OWXLCD_SetIcon($hash,0,0);
  596. OWXLCD_SetFunction($hash,"gpio",15);
  597. }elsif( $interface eq "OWX_ASYNC" ){
  598. eval {
  599. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "reset", 0) );
  600. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 0, 0) );
  601. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 15) );
  602. };
  603. return GP_Catch($@) if $@;
  604. }
  605. }
  606. #-- set icon
  607. if($key eq "icon") {
  608. return "OWLCD: Wrong icon type, choose 0..16"
  609. if( ( 0 > $icon ) || ($icon > 16) );
  610. #-- check value and write to device
  611. if( $icon == 16 ){
  612. if( uc($value) eq "OFF" ){
  613. #-- OWX interface
  614. if( $interface eq "OWX" ){
  615. return OWXLCD_SetIcon($hash, 16, 0);
  616. }elsif( $interface eq "OWX_ASYNC" ){
  617. eval {
  618. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, 0) );
  619. };
  620. return GP_Catch($@) if $@;
  621. }
  622. }elsif( uc($value) eq "BLINK" ){
  623. #-- OWX interface
  624. if( $interface eq "OWX" ){
  625. return OWXLCD_SetIcon($hash, 16, 6);
  626. }elsif( $interface eq "OWX_ASYNC" ){
  627. eval {
  628. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, 6) );
  629. };
  630. }
  631. }elsif( ((int($value) > 0) && (int($value) < 6)) ){
  632. #-- OWX interface
  633. if( $interface eq "OWX" ){
  634. return OWXLCD_SetIcon($hash, 16, int($value));
  635. }elsif( $interface eq "OWX_ASYNC" ){
  636. eval {
  637. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, int($value)) );
  638. };
  639. return GP_Catch($@) if $@;
  640. }
  641. } else {
  642. return "OWLCD: Set with wrong value for icon #16, must be 0..5/off/blink"
  643. }
  644. }else{
  645. if( uc($value) eq "OFF"){
  646. #-- OWX interface
  647. if( $interface eq "OWX" ){
  648. return OWXLCD_SetIcon($hash, $icon, 0);
  649. }elsif( $interface eq "OWX_ASYNC" ){
  650. eval {
  651. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, $icon, 0) );
  652. };
  653. return GP_Catch($@) if $@;
  654. }
  655. }elsif( uc($value) eq "ON" ){
  656. #-- OWX interface
  657. if( $interface eq "OWX" ){
  658. return OWXLCD_SetIcon($hash, $icon, 1);
  659. }elsif( $interface eq "OWX_ASYNC" ){
  660. eval {
  661. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, $icon, 1) );
  662. };
  663. return GP_Catch($@) if $@;
  664. }
  665. }elsif( uc($value) eq "BLINK" ){
  666. #-- OWX interface
  667. if( $interface eq "OWX" ){
  668. return OWXLCD_SetIcon($hash, $icon, 2);
  669. }elsif( $interface eq "OWX_ASYNC" ){
  670. eval {
  671. OWX_ASYNC_Schedule( $hash, &OWXLCD_PT_SetIcon($hash, $icon, 2) );
  672. };
  673. return GP_Catch($@) if $@;
  674. }
  675. } else {
  676. return "OWLCD: Set with wrong value for icon $icon, must be on/off/blink"
  677. }
  678. }
  679. }
  680. #-- set a single LCD line
  681. if($key eq "line") {
  682. $value = OWXLCD_Trans($value);
  683. return "OWLCD: Wrong line number, choose 0..".$lcdlines
  684. if( ( 0 > $line ) || ($line > ($lcdlines-1)) );
  685. return "OWLCD: Wrong line length, must be <= ".$lcdchars
  686. if( length($value) > $lcdchars );
  687. #-- check value and write to device
  688. #-- OWX interface
  689. if( $interface eq "OWX" ){
  690. return OWXLCD_SetLine($hash,$line,$value);
  691. }elsif( $interface eq "OWX_ASYNC" ){
  692. eval {
  693. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash, $line, $value) );
  694. };
  695. return GP_Catch($@) if $@;
  696. }
  697. }
  698. #-- set memory page 0..6
  699. if($key eq "memory") {
  700. return "OWLCD: Wrong page number, choose 0..6"
  701. if( (0 > $line) || ($line > 6) );
  702. return "OWLCD: Wrong line length, must be <=16 "
  703. if( length($value) > 16 );
  704. #-- write to device
  705. #-- OWX interface
  706. if( $interface eq "OWX" ){
  707. return OWXLCD_SetMemory($hash,$line,$value);
  708. }elsif( $interface eq "OWX_ASYNC" ){
  709. eval {
  710. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetMemory($hash, $line, $value) );
  711. };
  712. return GP_Catch($@) if $@;
  713. }
  714. }
  715. #-- start test
  716. if($key eq "test") {
  717. #-- OWX interface
  718. if( $interface eq "OWX" ){
  719. OWXLCD_SetLine($hash,0,"Hallo Welt");
  720. OWXLCD_SetLine($hash,1,"Mary had a big lamb");
  721. OWXLCD_SetLine($hash,2,"Solar 4.322 kW ");
  722. OWXLCD_SetLine($hash,3,"\x5B\x5C\x5E\x7B\x7C\x7E\xBE");
  723. return undef;
  724. }elsif( $interface eq "OWX_ASYNC" ){
  725. eval {
  726. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,0,"Hallo Welt"));
  727. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,1,"Mary had a big lamb"));
  728. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,2,"Solar 4.322 kW "));
  729. OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,3,"\x5B\x5C\x5E\x7B\x7C\x7E\xBE"));
  730. };
  731. return GP_Catch($@) if $@;
  732. }
  733. }
  734. #-- start initialize
  735. if($key eq "initialize") {
  736. OWXLCD_InitializeDevice($hash);
  737. return undef;
  738. }
  739. }
  740. ########################################################################################
  741. #
  742. # OWLCD_Undef - Implements UndefFn function
  743. #
  744. # Parameter hash = hash of device addressed
  745. #
  746. ########################################################################################
  747. sub OWLCD_Undef ($) {
  748. my ($hash) = @_;
  749. delete($modules{OWLCD}{defptr}{$hash->{OW_ID}});
  750. RemoveInternalTimer($hash);
  751. return undef;
  752. }
  753. ########################################################################################
  754. #
  755. # OWXLCD_InitializeDevice - initialize the display
  756. #
  757. # Parameter hash = hash of device addressed
  758. #
  759. ########################################################################################
  760. sub OWXLCD_InitializeDevice($) {
  761. my ($hash) = @_;
  762. my $owx_dev = $hash->{ROM_ID};
  763. my $master = $hash->{IODev};
  764. my $interface = $hash->{IODev}->{TYPE};
  765. my ($i,$data,$select, $res);
  766. #-- supposedly we do not need to do anything with a HD44780
  767. if( $lcdcontroller eq "HD44780"){
  768. return undef;
  769. #-- need some additional sequence for KS0073
  770. }elsif ( $lcdcontroller eq "KS0073"){
  771. #-- Function Set: 4 bit data size, RE => 0 = \x20
  772. #OWXLCD_Byte($hash,"register",32);
  773. #-- Entry Mode Set: cursor auto increment = \x06
  774. #OWXLCD_Byte($hash,"register",6);
  775. if( $interface eq "OWX" ){
  776. #-- Function Set: 4 bit data size, RE => 1, blink Enable = \x26
  777. OWXLCD_Byte($hash,"register",38);
  778. #-- Ext. Function Set: 4 line mode = \x09
  779. OWXLCD_Byte($hash,"register",9);
  780. #-- Function Set: 4 bit data size, RE => 0 = \x20
  781. OWXLCD_Byte($hash,"register",32);
  782. #-- Display ON/OFF: display on, cursor off, blink off = \x0C
  783. OWXLCD_Byte($hash,"register",12);
  784. #-- Clear Display
  785. OWXLCD_Byte($hash,"register",1);
  786. return undef;
  787. }elsif( $interface eq "OWX_ASYNC" ){
  788. eval {
  789. OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",38));
  790. OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register", 9));
  791. OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",32));
  792. OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",12));
  793. OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register", 1));
  794. };
  795. return GP_Catch($@) if $@;
  796. }
  797. #-- or else
  798. } else {
  799. return "OWXLCD: Wrong LCD controller type";
  800. }
  801. }
  802. ########################################################################################
  803. #
  804. # OWXLCD_BinValues - Process reading from one device - translate binary into raw
  805. #
  806. # Parameter hash = hash of device addressed
  807. # context = mode for evaluating the binary data
  808. # proc = processing instruction, also passed to OWX_Read.
  809. # bitwise interpretation !!
  810. # if 0, nothing special
  811. # if 1 = bit 0, a reset will be performed not only before, but also after
  812. # the last operation in OWX_Read
  813. # if 2 = bit 1, the initial reset of the bus will be suppressed
  814. # if 8 = bit 3, the fillup of the data with 0xff will be suppressed
  815. # if 16= bit 4, the insertion will be at the top of the queue
  816. # owx_dev = ROM ID of slave device
  817. # crcpart = part of the data that needs to be part of the CRC check
  818. # numread = number of bytes to receive
  819. # res = result string
  820. #
  821. #
  822. ########################################################################################
  823. sub OWXLCD_BinValues($$$$$$$) {
  824. my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_;
  825. my ($ret,@data,$select);
  826. my $change = 0;
  827. my $master = $hash->{IODev};
  828. my $name = $hash->{NAME};
  829. my $msg;
  830. OWX_WDBGL($name,5,"OWLCD: $name: BinValues called with context $context and data ",$res);
  831. #=============== setline 2nd step ===============================
  832. if( $context eq "setline" ) {
  833. #-- issue the copy scratchpad to LCD command \x48
  834. #### master slave context proc owx_dev data crcpart numread startread callback delay
  835. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  836. OWX_Qomplex($master, $hash, "sptolcd", 24, $owx_dev, "\x48", 0, -3, 0, undef, 0.01);
  837. #=============== seteeprom 2nd step ===============================
  838. }elsif( $context eq "seteeprom" ) {
  839. #-- issue the copy scratchpad to EEPROM command \x39
  840. #### master slave context proc owx_dev data crcpart numread startread callback delay
  841. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  842. OWX_Qomplex($master, $hash, "sptoeeprom", 24, $owx_dev,"\x39", 0, -9, 0, undef, 0.01);
  843. #=============== eraseicon 2nd step ===============================
  844. }elsif( $context eq "eraseicon.1" ) {
  845. #-- SEGRAM addres to 0 = \x40,
  846. $select = "\x10\x40";
  847. #-- write 16 zeros to scratchpad
  848. $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  849. #### master slave context proc owx_dev data crcpart numread startread callback delay
  850. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  851. OWX_Qomplex($master, $hash, "eraseicon.2", 24, $owx_dev, $select, 0, 5, 0, \&OWXLCD_BinValues, 0.01);
  852. #=============== eraseicon 3rd step ===============================
  853. }elsif( $context eq "eraseicon.2" ) {
  854. #-- issue the copy scratchpad to LCD command \x48
  855. #### master slave context proc owx_dev data crcpart numread startread callback delay
  856. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  857. OWX_Qomplex($master, $hash, "endicon", 24, $owx_dev,"\x48", 0, 0, 0, \&OWXLCD_BinValues, 0.01);
  858. #=============== seticon 2nd step ===============================
  859. }elsif( $context eq "seticon.1" ) {
  860. #-- SEGRAM addres to 0 = \x40 + icon address
  861. $select = substr($crcpart,0,2);
  862. #### master slave context proc owx_dev data crcpart numread startread callback delay
  863. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  864. OWX_Qomplex($master, $hash, "seticon.2", 24, $owx_dev, $select,$crcpart, 1, 0, \&OWXLCD_BinValues, 0.01);
  865. #=============== seticon 2nd step ===============================
  866. }elsif( $context eq "seticon.2" ) {
  867. #-- data
  868. $select = substr($crcpart,2);
  869. #### master slave context proc owx_dev data crcpart numread startread callback delay
  870. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  871. OWX_Qomplex($master, $hash, "endicon", 24, $owx_dev, $select, 0, 1, 0, \&OWXLCD_BinValues, 0.01);
  872. #=============== endicon ===============================
  873. }elsif( $context eq "endicon" ) {
  874. #-- issue the return to normal state command
  875. #### master slave context proc owx_dev data crcpart numread startread callback delay
  876. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  877. OWX_Qomplex($master, $hash, "normal", 24, $owx_dev, "\x10\x20", 0, 1, 0, undef, 0.01);
  878. #=============== prepare some get values ===============================
  879. }elsif ( $context =~ /^get\.prep\.(\d+)/ ) {
  880. my $len = $1;
  881. #-- command hidden in crcpart, issueing read scratchpad command
  882. #### master slave context proc owx_dev data crcpart numread startread callback delay
  883. # 16 ensures entry at top of queue, 8 prevents fillup, 1 for final reset
  884. OWX_Qomplex($master, $hash, "get.".$crcpart, 0, $owx_dev, "\xBE", 0, $len+1, 10, \&OWXLCD_BinValues, 0.01);
  885. #=============== gpio ports ===============================
  886. }elsif ( $context eq "get.gpio" ) {
  887. @data= split(//,$res);
  888. $ret = ord($data[0]) & 7;
  889. readingsSingleUpdate($hash,"gpio",$ret,1);
  890. #=============== gpio single bit ===============================
  891. }elsif ( $context =~ /^get\.gpiobit\.(\d+)\.(\d+)/ ) {
  892. $ret = ord($res) & 7;
  893. my $bit = $1;
  894. my $val = $2;
  895. my $tar;
  896. if( $val == 0){
  897. $tar = $ret & (15-(1<<($bit-1)));
  898. }else{
  899. $tar = $ret | (1<<($bit-1)&15);
  900. }
  901. OWXLCD_SetFunction($hash,"gpio",$tar);
  902. #=============== gpio counters ===============================
  903. }elsif ( $context eq "get.counter" ) {
  904. for( my $i=0; $i<4; $i++){
  905. $data[$i] = ord(substr($res,2*$i+1,1))*256+ord(substr($res,2*$i,1));
  906. }
  907. $ret = join(" ",@data);
  908. readingsSingleUpdate($hash,"counter",$ret,1);
  909. #=============== version ===============================
  910. }elsif ( $context eq "get.version" ) {
  911. #TODO format version, raw value is unreadable
  912. readingsSingleUpdate($hash,"version",$res,1);
  913. #=============== memory ===============================
  914. }elsif ( $context =~ /^get\.memory\.([\d]+)$/ ) {
  915. readingsSingleUpdate($hash,"memory$1",unpack("H*",$res),1);
  916. }
  917. return undef;
  918. }
  919. ########################################################################################
  920. #
  921. # OWXLCD_Byte - write a single byte to the LCD device
  922. #
  923. # Parameter hash = hash of device addressed
  924. # cmd = register or data
  925. # byte = byte
  926. #
  927. ########################################################################################
  928. sub OWXLCD_Byte($$$) {
  929. my ($hash,$cmd,$byte) = @_;
  930. my $master = $hash->{IODev};
  931. my $interface = $hash->{IODev}->{TYPE};
  932. my $owx_dev = $hash->{ROM_ID};
  933. my $owx_rnf = substr($owx_dev,3,12);
  934. my $owx_f = substr($owx_dev,0,2);
  935. my ($select, $select2, $res, $res2, $res3, @data);
  936. #=============== write to LCD register ===============================
  937. if ( $cmd eq "register" ) {
  938. #-- issue the read LCD register command \x10
  939. $select = sprintf("\x10%c",$byte);
  940. #=============== write to LCD data ===============================
  941. }elsif ( $cmd eq "data" ) {
  942. #-- issue the read LCD data command \x12
  943. $select = sprintf("\x12%c",$byte);
  944. #=============== wrong value requested ===============================
  945. } else {
  946. return "OWXLCD: Wrong byte write attempt";
  947. }
  948. #-- write to device
  949. if( !$master->{ASYNCHRONOUS} ){
  950. OWX_Reset($master);
  951. $res=OWX_Complex($master,$owx_dev,$select,0);
  952. #-- process results
  953. if( $res eq 0 ){
  954. return "OWLCD: Device $owx_dev not accessible for writing a byte";
  955. }
  956. }else{
  957. #### master slave context proc owx_dev data crcpart numread startread callback delay
  958. OWX_Qomplex($master, $hash, "writebyte", 8, $owx_dev,$select, 0, 1, 0, undef, 0.01);
  959. }
  960. return undef;
  961. }
  962. ########################################################################################
  963. #
  964. # OWXLCD_Get - get values from the LCD device
  965. #
  966. # Parameter hash = hash of device addressed
  967. # cmd = command string
  968. #
  969. ########################################################################################
  970. sub OWXLCD_Get(@) {
  971. my ($hash,$cmd) = @_;
  972. my $owx_dev = $hash->{ROM_ID};
  973. my $master = $hash->{IODev};
  974. my $interface = $hash->{IODev}->{TYPE};
  975. my ($select, $select2, $len, $addr, $res, $res2);
  976. #=============== fill scratch with gpio ports ===============================
  977. if ( $cmd =~ /^gpio.*/ ) {
  978. #-- issue the read GPIO command \x22 (1 byte)
  979. $select = "\x22";
  980. $len = 1;
  981. #=============== fill scratch with gpio counters ===============================
  982. }elsif ( $cmd eq "counter" ) {
  983. #-- issue the read counter command \x23 (8 bytes)
  984. $select = "\x23";
  985. $len = 8;
  986. #=============== fill scratch with version ===============================
  987. }elsif ( $cmd eq "version" ) {
  988. #-- issue the read version command \x41
  989. $select = "\x41";
  990. $len = 16;
  991. } else {
  992. return "OWXLCD: Wrong get attempt";
  993. }
  994. #-- write to device
  995. if( !$master->{ASYNCHRONOUS} ){
  996. OWX_Reset($master);
  997. $res=OWX_Complex($master,$owx_dev,$select,0);
  998. OWX_WDBGL($owx_dev,4,"OWXLCD_Get called OWX_Complex 1 w. result ",$res);
  999. #-- process results
  1000. if( $res eq 0 ){
  1001. return "OWLCD: Device $owx_dev not accessible for reading";
  1002. }
  1003. #-- issue the read scratchpad command \xBE
  1004. $select2 = "\xBE";
  1005. #-- write to device
  1006. OWX_Reset($master);
  1007. $res=OWX_Complex($master,$owx_dev,$select2,$len);
  1008. OWX_WDBGL($owx_dev,4,"OWXLCD_Get called OWX_Complex 2 w. result ",$res);
  1009. #-- process results
  1010. if( $res eq 0 ){
  1011. return "OWLCD: Device $owx_dev not accessible for reading in 2nd step";
  1012. }
  1013. OWXLCD_BinValues($hash, "get.".$cmd, 1, $owx_dev, "\xBE", $len, substr($res,10));
  1014. return main::ReadingsVal($hash->{NAME},$cmd,"");
  1015. }else{
  1016. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1017. OWX_Qomplex($master, $hash, "get.prep.".$len, 8, $owx_dev, $select, $cmd, 0, 0, \&OWXLCD_BinValues, undef);
  1018. return undef;
  1019. }
  1020. }
  1021. ########################################################################################
  1022. #
  1023. # OWXLCD_GetMemory - get memory page from LCD device (EXPERIMENTAL)
  1024. #
  1025. # Parameter hash = hash of device addressed
  1026. # page = memory page address
  1027. #
  1028. ########################################################################################
  1029. sub OWXLCD_GetMemory($$) {
  1030. my ($hash,$page) = @_;
  1031. my $master = $hash->{IODev};
  1032. my $interface = $hash->{IODev}->{TYPE};
  1033. my $owx_dev = $hash->{ROM_ID};
  1034. my $owx_rnf = substr($owx_dev,3,12);
  1035. my $owx_f = substr($owx_dev,0,2);
  1036. my ($select, $res, $res2, $res3);
  1037. #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E
  1038. #Log 1," page read is ".$page;
  1039. $select = sprintf("\4E%c\x10\x37",$page);
  1040. #-- write to device
  1041. #-- OLD OWX interface
  1042. if( !$master->{ASYNCHRONOUS} ){
  1043. OWX_Reset($master);
  1044. $res=OWX_Complex($master,$owx_dev,$select,0);
  1045. #-- process results
  1046. if( $res eq 0 ){
  1047. return "OWLCD: Device $owx_dev not accessible for reading";
  1048. }
  1049. #-- issue the match ROM command \x55 and the read scratchpad command \xBE
  1050. $select = "\xBE";
  1051. #-- write to device
  1052. OWX_Reset($master);
  1053. $res=OWX_Complex($master,$owx_dev,$select,16);
  1054. #-- process results
  1055. if( $res eq 0 ){
  1056. return "OWLCD: Device $owx_dev not accessible for reading in 2nd step";
  1057. }
  1058. OWXLCD_BinValues($hash, "get.memory.$page", 1, $owx_dev, $select, 16, substr($res,11,16));
  1059. #-- process results (10 bytes or more have been sent)
  1060. #$res2 = substr($res,11,16);
  1061. #return $res2;
  1062. return main::ReadingsVal($hash->{NAME},"memory$page","");
  1063. #-- NEW OWX interface
  1064. }else{
  1065. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1066. OWX_Qomplex($master, $hash, "get.prep.16", 8, $owx_dev, $select, "memory.$page", -2, 0, \&OWXLCD_BinValues, 0.01);
  1067. return undef;
  1068. }
  1069. }
  1070. ########################################################################################
  1071. #
  1072. # OWXLCD_SetFunction - write state and values of the LCD device
  1073. #
  1074. # Parameter hash = hash of device addressed
  1075. # cmd = command string
  1076. # value = data value
  1077. #
  1078. ########################################################################################
  1079. sub OWXLCD_SetFunction($$$) {
  1080. my ($hash,$cmd,$value) = @_;
  1081. #-- ID of the device, hash of the busmaster
  1082. my $owx_dev = $hash->{ROM_ID};
  1083. my $master = $hash->{IODev};
  1084. my ($select, $res, $res2, $res3, @data);
  1085. my $context = "setfunction";
  1086. my $len = 0;
  1087. #=============== set gpio ports ===============================
  1088. if ( $cmd eq "gpio" ) {
  1089. #-- issue the write GPIO command
  1090. # \x21 followed by the data value (= integer 0 - 7)
  1091. $select = sprintf("\x21%c",$value);
  1092. $len = 1;
  1093. readingsSingleUpdate($hash,"gpio",$value,1);
  1094. #=============== switch LCD on ===============================
  1095. }elsif ( $cmd eq "lcdon" ) {
  1096. #-- issue the lcd on cmd
  1097. $select = "\x03";
  1098. #=============== switch LCD off ===============================
  1099. }elsif ( $cmd eq "lcdoff" ) {
  1100. #-- issue the lcd off cmd
  1101. $select = "\x05";
  1102. #=============== switch LCD backlight on ===============================
  1103. }elsif ( $cmd eq "bklon" ) {
  1104. #-- issue the backlight on cmd
  1105. $select = "\x08";
  1106. #=============== switch LCD backlight off ===============================
  1107. }elsif ( $cmd eq "bkloff" ) {
  1108. #-- issue the backlight off cmd
  1109. $select = "\x07";
  1110. #=============== reset ===============================
  1111. }elsif ( $cmd eq "reset" ) {
  1112. #-- issue the clear LCD command
  1113. $select = "\x49";
  1114. #=============== wrong write attempt ===============================
  1115. } else {
  1116. return "OWXLCD: Wrong function selected";
  1117. }
  1118. #-- OLD OWX interface
  1119. if( !$master->{ASYNCHRONOUS} ){
  1120. #-- write to device
  1121. OWX_Reset($master);
  1122. $res=OWX_Complex($master,$owx_dev,$select,0);
  1123. #-- process results
  1124. if( $res eq 0 ){
  1125. return "OWLCD: Device $owx_dev not accessible for writing";
  1126. }
  1127. #-- NEW OWX interface
  1128. }else{
  1129. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1130. OWX_Qomplex($master, $hash, $context, 8, $owx_dev, $select, 0, $len, 0, undef, 0.01);
  1131. }
  1132. return undef;
  1133. }
  1134. ########################################################################################
  1135. #
  1136. # OWXLCD_SetIcon - set one of the icons
  1137. #
  1138. # Parameter hash = hash of device addressed
  1139. # icon = address of the icon used = 0,1 .. 16 (0 = all off)
  1140. # value = data value: 0 = off, 1 = on, 2 = blink
  1141. # for battery icon 16: 0 = off, 1 = empty ... 5 = full, 6 = empty blink
  1142. #
  1143. ########################################################################################
  1144. sub OWXLCD_SetIcon($$$) {
  1145. my ($hash,$icon,$value) = @_;
  1146. #-- ID of the device, hash of the busmaster
  1147. my $owx_dev = $hash->{ROM_ID};
  1148. my $master = $hash->{IODev};
  1149. my ($i,$data,$select, $res);
  1150. #-- only for KS0073
  1151. if ( $lcdcontroller eq "KS0073"){
  1152. #-- write 16 zeros to erase all icons
  1153. if( $icon == 0){
  1154. #-- 4 bit data size, RE => 1, blink Enable = \x26
  1155. $select = "\x10\x26";
  1156. #-- OLD OWX interface
  1157. if( !$master->{ASYNCHRONOUS} ){
  1158. OWX_Reset($master);
  1159. $res=OWX_Complex($master,$owx_dev,$select,0);
  1160. #-- SEGRAM addres to 0 = \x40,
  1161. $select = "\x10\x40";
  1162. #-- write 16 zeros to scratchpad
  1163. $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  1164. OWX_Reset($master);
  1165. $res=OWX_Complex($master,$owx_dev,$select,0);
  1166. #-- issue the copy scratchpad to LCD command \x48
  1167. $select="\x48";
  1168. OWX_Reset($master);
  1169. $res=OWX_Complex($master,$owx_dev,$select,0);
  1170. #-- return to normal state
  1171. $select = "\x10\x20";
  1172. OWX_Reset($master);
  1173. $res=OWX_Complex($master,$owx_dev,$select,0);
  1174. #-- NEW OWX interface
  1175. }else{
  1176. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1177. OWX_Qomplex($master, $hash, "eraseicon.1", 8, $owx_dev, $select, 0, 1, 0, \&OWXLCD_BinValues, 0.01);
  1178. }
  1179. } else {
  1180. #-- determine data value
  1181. if( int($icon) != 16 ){
  1182. if( $value == 0 ){
  1183. $data = 0;
  1184. } elsif ( $value == 1) {
  1185. $data = 16;
  1186. } elsif ( $value == 2) {
  1187. $data = 80;
  1188. } else {
  1189. return "OWXLCD: Wrong data value $value for icon $icon";
  1190. }
  1191. } else {
  1192. if( $value == 0 ){
  1193. $data = 0;
  1194. } elsif ( $value == 1) {
  1195. $data = 16;
  1196. } elsif ( $value == 2) {
  1197. $data = 24;
  1198. } elsif ( $value == 3) {
  1199. $data = 28;
  1200. } elsif ( $value == 4) {
  1201. $data = 30;
  1202. } elsif ( $value == 5) {
  1203. $data = 31;
  1204. } elsif ( $value == 6) {
  1205. $data = 80;
  1206. } else {
  1207. return "OWXLCD: Wrong data value $value for icon $icon";
  1208. }
  1209. }
  1210. #-- 4 bit data size, RE => 1, blink Enable = \x26
  1211. $select = "\x10\x26";
  1212. if( !$master->{ASYNCHRONOUS} ){
  1213. OWX_Reset($master);
  1214. $res=OWX_Complex($master,$owx_dev,$select,0);
  1215. #-- SEGRAM addres to 0 = \x40 + icon address
  1216. $select = sprintf("\x10%c",63+$icon);
  1217. OWX_Reset($master);
  1218. $res=OWX_Complex($master,$owx_dev,$select,0);
  1219. #-- data
  1220. $select = sprintf("\x12%c",$data);
  1221. OWX_Reset($master);
  1222. $res=OWX_Complex($master,$owx_dev,$select,0);
  1223. #-- return to normal state
  1224. $select = "\x10\x20";
  1225. OWX_Reset($master);
  1226. $res=OWX_Complex($master,$owx_dev,$select,0);
  1227. }else{
  1228. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1229. OWX_Qomplex($master, $hash, "seticon.1", 8, $owx_dev, $select, sprintf("\x10%c",63+$icon).sprintf("\x12%c",$data), 1, 0, \&OWXLCD_BinValues, 0.01);
  1230. }
  1231. }
  1232. #-- or else
  1233. } else {
  1234. return "OWXLCD: Wrong LCD controller type";
  1235. }
  1236. }
  1237. ########################################################################################
  1238. #
  1239. # OWXLCD_SetLine - set one of the display lines
  1240. #
  1241. # Parameter hash = hash of device addressed
  1242. # line = line number (0..3)
  1243. # msg = data string to be written
  1244. #
  1245. ########################################################################################
  1246. sub OWXLCD_SetLine($$$) {
  1247. my ($hash,$line,$msg) = @_;
  1248. #-- ID of the device, hash of the busmaster
  1249. my $owx_dev = $hash->{ROM_ID};
  1250. my $master = $hash->{IODev};
  1251. my ($select, $res, $res2, $res3, $i, $msgA, $msgB);
  1252. $res2 = "";
  1253. $line = int($line);
  1254. $msg = defined($msg) ? $msg : "";
  1255. $msg = OWXLCD_Trans($msg);
  1256. #-- split if longer than 16 bytes, fill each with blanks
  1257. # has already been checked to be <= $lcdchars
  1258. if( $lcdchars > 16 ){
  1259. if( length($msg) > 16 ) {
  1260. $msgA = substr($msg,0,16);
  1261. $msgB = substr($msg,16,length($msg)-16);
  1262. for($i = 0;$i<$lcdchars-length($msg);$i++){
  1263. $msgB .= "\x20";
  1264. }
  1265. } else {
  1266. $msgA = $msg;
  1267. for($i = 0;$i<16-length($msg);$i++){
  1268. $msgA .= "\x20";
  1269. }
  1270. for($i = 0;$i<$lcdchars-16;$i++){
  1271. $msgB .= "\x20";
  1272. }
  1273. }
  1274. }else{
  1275. $msgA = $msg;
  1276. for($i = 0;$i<$lcdchars-length($msg);$i++){
  1277. $msgA .= "\x20";
  1278. }
  1279. $msgB = undef;
  1280. }
  1281. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1282. # followed by LCD page address and the text
  1283. $select=sprintf("\x4E%c",$lcdpage[$line]).$msgA;
  1284. #-- OLD OWX interface
  1285. if( !$master->{ASYNCHRONOUS} ){
  1286. OWX_Reset($master);
  1287. $res=OWX_Complex($master,$owx_dev,$select,0);
  1288. #-- issue the copy scratchpad to LCD command \x48
  1289. OWX_Reset($master);
  1290. $res3=OWX_Complex($master,$owx_dev,"\x48",0);
  1291. #-- NEW OWX interface
  1292. }else{
  1293. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1294. # 8= do not fill w. ff, 1=reset after
  1295. OWX_Qomplex($master, $hash, "setline", 8, $owx_dev, $select, 0, length($msgA)+1, 11, \&OWXLCD_BinValues, 0.01);
  1296. }
  1297. #-- if second string available:
  1298. if( defined($msgB) ) {
  1299. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1300. # followed by LCD page address and the text
  1301. $select=sprintf("\x4E%c",$lcdpage[$line]+16).$msgB;
  1302. #-- OLD OWX interface
  1303. if( !$master->{ASYNCHRONOUS} ){
  1304. select(undef,undef,undef,0.05);
  1305. OWX_Reset($master);
  1306. $res2=OWX_Complex($master,$owx_dev,$select,0);
  1307. #-- issue the copy scratchpad to LCD command \x48
  1308. $select="\x48";
  1309. OWX_Reset($master);
  1310. $res3=OWX_Complex($master,$owx_dev,$select,0);
  1311. #-- NEW OWX interface
  1312. }else{
  1313. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1314. # 8= do not fill w. ff
  1315. OWX_Qomplex($master, $hash, "setline", 8, $owx_dev, $select, 0, length($msgB)+1, 11, \&OWXLCD_BinValues, 0.05);
  1316. }
  1317. }
  1318. #-- process results
  1319. if( !$master->{ASYNCHRONOUS} ){
  1320. if( ($res eq 0) || ($res2 eq 0) || ($res3 eq 0) ){
  1321. return "OWLCD: Device $owx_dev not accessible for writing";
  1322. }
  1323. }
  1324. return undef;
  1325. }
  1326. ########################################################################################
  1327. #
  1328. # OWXLCD_Trans - String translation helper
  1329. #
  1330. # Parameter msg = data string to be written
  1331. #
  1332. ########################################################################################
  1333. sub OWXLCD_Trans($) {
  1334. my ($msg) = @_;
  1335. #-- replace umlaut chars for special codepage of KS0073
  1336. if( $lcdcontroller eq "KS0073") {
  1337. $msg =~ s/ä/\x7B/g;
  1338. $msg =~ s/ö/\x7C/g;
  1339. $msg =~ s/ü/\x7E/g;
  1340. $msg =~ s/Ä/\x5B/g;
  1341. $msg =~ s/Ö/\x5C/g;
  1342. $msg =~ s/Ü/\x5E/g;
  1343. $msg =~ s/ß/\xBE/g;
  1344. $msg =~ s/°/\x80/g;
  1345. #-- replace umlaut chars for special codepage of HD44780
  1346. }elsif( $lcdcontroller eq "HD44780") {
  1347. $msg =~ s/ä/\xE1/g;
  1348. $msg =~ s/ö/\xEF/g;
  1349. $msg =~ s/ü/\xF5/g;
  1350. $msg =~ s/Ü/\x03/g;
  1351. $msg =~ s/Ö/\x02/g;
  1352. $msg =~ s/Ä/\x01/g;
  1353. $msg =~ s/ß/\xE2/g;
  1354. $msg =~ s/°/\xDF/g;
  1355. }
  1356. #-- replace other special chars
  1357. $msg =~s/_/\xC4/g;
  1358. return $msg;
  1359. }
  1360. ########################################################################################
  1361. #
  1362. # OWXLCD_SetMemory - set internal nonvolatile memory
  1363. #
  1364. # Parameter hash = hash of device addressed
  1365. # page = page number (0..14)
  1366. # msg = data string to be written
  1367. #
  1368. ########################################################################################
  1369. sub OWXLCD_SetMemory($$$) {
  1370. my ($hash,$page,$msg) = @_;
  1371. #-- ID of the device, hash of the busmaster
  1372. my $owx_dev = $hash->{ROM_ID};
  1373. my $master = $hash->{IODev};
  1374. my ($select, $res, $res2, $res3, $i, $msgA);
  1375. $page = int($page);
  1376. $msg = defined($msg) ? $msg : "";
  1377. #-- fillup with blanks
  1378. $msgA = $msg;
  1379. for($i = 0;$i<16-length($msg);$i++){
  1380. $msgA .= "\x20";
  1381. }
  1382. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1383. # followed by LCD page address and the text
  1384. #Log 1," page written is ".$page;
  1385. $select=sprintf("\x4E\%c",$page).$msgA;
  1386. #-- OLD OWX interface
  1387. if( !$master->{ASYNCHRONOUS} ){
  1388. OWX_Reset($master);
  1389. $res=OWX_Complex($master,$owx_dev,$select,0);
  1390. #-- issue the copy scratchpad to EEPROM command \x39
  1391. $select = "\x39";
  1392. OWX_Reset($master);
  1393. $res2=OWX_Complex($master,$owx_dev,$select,0);
  1394. #-- process results
  1395. if( ($res eq 0) || ($res2 eq 0) ){
  1396. return "OWLCD: Device $owx_dev not accessible for writing";
  1397. }
  1398. #-- NEW OWX interface
  1399. }else{
  1400. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1401. OWX_Qomplex($master, $hash, "seteeprom", 8, $owx_dev, $select, 0, 17, 0, \&OWXLCD_BinValues, 0.01);
  1402. }
  1403. return undef;
  1404. }
  1405. ########################################################################################
  1406. #
  1407. # OWXLCD_PT_Byte - write a single byte to the LCD device async
  1408. #
  1409. # Parameter hash = hash of device addressed
  1410. # cmd = register or data
  1411. # byte = byte
  1412. #
  1413. ########################################################################################
  1414. sub OWXLCD_PT_Byte($$$) {
  1415. my ($hash,$cmd,$byte) = @_;
  1416. return PT_THREAD(sub {
  1417. my ($thread) = @_;
  1418. my ($select);
  1419. #-- ID of the device
  1420. my $owx_dev = $hash->{ROM_ID};
  1421. #-- hash of the busmaster
  1422. my $master = $hash->{IODev};
  1423. my ($i,$j,$k);
  1424. PT_BEGIN($thread);
  1425. #=============== write to LCD register ===============================
  1426. if ( $cmd eq "register" ) {
  1427. #-- issue the read LCD register command \x10
  1428. $select = sprintf("\x10%c",$byte);
  1429. #=============== write to LCD data ===============================
  1430. }elsif ( $cmd eq "data" ) {
  1431. #-- issue the read LCD data command \x12
  1432. $select = sprintf("\x12%c",$byte);
  1433. #=============== wrong value requested ===============================
  1434. } else {
  1435. die "OWXLCD: Wrong byte write attempt";
  1436. }
  1437. #"byte"
  1438. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1439. PT_WAIT_THREAD($thread->{pt_execute});
  1440. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1441. PT_END;
  1442. });
  1443. }
  1444. ########################################################################################
  1445. #
  1446. # OWXLCD_PT_Get - get values from the LCD device async
  1447. #
  1448. # Parameter hash = hash of device addressed
  1449. # cmd = command string
  1450. #
  1451. ########################################################################################
  1452. sub OWXLCD_PT_Get($$) {
  1453. my ($hash,$cmd) = @_;
  1454. return PT_THREAD(sub {
  1455. my ($thread) = @_;
  1456. my ($select);
  1457. #-- ID of the device
  1458. my $owx_dev = $hash->{ROM_ID};
  1459. #-- hash of the busmaster
  1460. my $master = $hash->{IODev};
  1461. my ($i,$j,$k);
  1462. PT_BEGIN($thread);
  1463. #=============== fill scratch with gpio ports ===============================
  1464. if ( $cmd eq "gpio" ) {
  1465. #-- issue the read GPIO command \x22 (1 byte)
  1466. $select = "\x22";
  1467. $thread->{len} = 1;
  1468. #=============== fill scratch with gpio counters ===============================
  1469. }elsif ( $cmd eq "counter" ) {
  1470. #-- issue the read counter command \x23 (8 bytes)
  1471. $select = "\x23";
  1472. $thread->{len} = 8;
  1473. #=============== fill scratch with version ===============================
  1474. }elsif ( $cmd eq "version" ) {
  1475. #-- issue the read version command \x41
  1476. $select = "\x41";
  1477. $thread->{len} = 16;
  1478. } else {
  1479. die("OWXLCD: Wrong get attempt");
  1480. }
  1481. #"get.prepare"
  1482. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1483. PT_WAIT_THREAD($thread->{pt_execute});
  1484. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1485. #-- issue the read scratchpad command \xBE
  1486. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE", $thread->{len});
  1487. PT_WAIT_THREAD($thread->{pt_execute});
  1488. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1489. OWXLCD_BinValues($hash, "get.".$cmd, 1, $owx_dev, "\xBE", $thread->{len}, $thread->{pt_execute}->PT_RETVAL());
  1490. PT_END;
  1491. });
  1492. }
  1493. ########################################################################################
  1494. #
  1495. # OWXLCD_PT_GetMemory - get memory page from LCD device async (EXPERIMENTAL)
  1496. #
  1497. # Parameter hash = hash of device addressed
  1498. # page = memory page address
  1499. #
  1500. ########################################################################################
  1501. sub OWXLCD_PT_GetMemory($$) {
  1502. my ($hash,$page) = @_;
  1503. return PT_THREAD(sub {
  1504. my ($thread) = @_;
  1505. my ($select);
  1506. #-- ID of the device
  1507. my $owx_dev = $hash->{ROM_ID};
  1508. #-- hash of the busmaster
  1509. my $master = $hash->{IODev};
  1510. PT_BEGIN($thread);
  1511. #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E
  1512. #Log 1," page read is ".$page;
  1513. $select = sprintf("\4E%c\x10\x37",$page);
  1514. #"prepare"
  1515. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1516. PT_WAIT_THREAD($thread->{pt_execute});
  1517. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1518. #-- sleeping for some time
  1519. $thread->{ExecuteTime} = gettimeofday()+0.5;
  1520. PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
  1521. delete $thread->{ExecuteTime};
  1522. #-- issue the match ROM command \x55 and the read scratchpad command \xBE
  1523. $thread->{'select'} = "\xBE";
  1524. #"get.memory.$page"
  1525. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},16);
  1526. PT_WAIT_THREAD($thread->{pt_execute});
  1527. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1528. OWXLCD_BinValues($hash, "get.memory.$page", 1, $owx_dev, $thread->{'select'}, 16, $thread->{pt_execute}->PT_RETVAL());
  1529. #-- process results (10 bytes or more have been sent)
  1530. #$res2 = substr($res,11,16);
  1531. #return $res2;
  1532. PT_END;
  1533. });
  1534. }
  1535. ########################################################################################
  1536. #
  1537. # OWXLCD_PT_SetFunction - write state and values of the LCD device async
  1538. #
  1539. # Parameter hash = hash of device addressed
  1540. # cmd = command string
  1541. # value = data value
  1542. #
  1543. ########################################################################################
  1544. sub OWXLCD_PT_SetFunction($$$) {
  1545. my ($hash,$cmd,$value) = @_;
  1546. return PT_THREAD(sub {
  1547. my ($thread) = @_;
  1548. my ($select);
  1549. #-- ID of the device, hash of the busmaster
  1550. my $owx_dev = $hash->{ROM_ID};
  1551. my $master = $hash->{IODev};
  1552. my ($i,$j,$k);
  1553. PT_BEGIN($thread);
  1554. #=============== set gpio ports ===============================
  1555. if ( $cmd eq "gpio" ) {
  1556. #-- issue the write GPIO command
  1557. # \x21 followed by the data value (= integer 0 - 7)
  1558. $select = sprintf("\x21%c",$value);
  1559. #=============== switch LCD on ===============================
  1560. }elsif ( $cmd eq "lcdon" ) {
  1561. #-- issue the lcd on cmd
  1562. $select = "\x03";
  1563. #=============== switch LCD off ===============================
  1564. }elsif ( $cmd eq "lcdoff" ) {
  1565. #-- issue the lcd off cmd
  1566. $select = "\x05";
  1567. #=============== switch LCD backlight on ===============================
  1568. }elsif ( $cmd eq "bklon" ) {
  1569. #-- issue the backlight on cmd
  1570. $select = "\x08";
  1571. #=============== switch LCD backlight off ===============================
  1572. }elsif ( $cmd eq "bkloff" ) {
  1573. #-- issue the backlight off cmd
  1574. $select = "\x07";
  1575. #=============== switch LCD backlight off ===============================
  1576. }elsif ( $cmd eq "reset" ) {
  1577. #-- issue the clear LCD command
  1578. $select = "\x49";
  1579. #=============== wrong write attempt ===============================
  1580. } else {
  1581. die "OWXLCD: Wrong function selected '$cmd'";
  1582. }
  1583. #"set.function"
  1584. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1585. PT_WAIT_THREAD($thread->{pt_execute});
  1586. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1587. PT_END;
  1588. });
  1589. }
  1590. ########################################################################################
  1591. #
  1592. # OWXLCD_PT_SetIcon - set one of the icons async
  1593. #
  1594. # Parameter hash = hash of device addressed
  1595. # icon = address of the icon used = 0,1 .. 16 (0 = all off)
  1596. # value = data value: 0 = off, 1 = on, 2 = blink
  1597. # for battery icon 16: 0 = off, 1 = empty ... 5 = full, 6 = empty blink
  1598. #
  1599. ########################################################################################
  1600. sub OWXLCD_PT_SetIcon($$$) {
  1601. my ($hash,$icon,$value) = @_;
  1602. return PT_THREAD(sub {
  1603. my ($thread) = @_;
  1604. my ($i,$data,$select, $res);
  1605. #-- ID of the device, hash of the busmaster
  1606. my $owx_dev = $hash->{ROM_ID};
  1607. my $master = $hash->{IODev};
  1608. PT_BEGIN($thread);
  1609. #-- only for KS0073
  1610. if ( $lcdcontroller eq "KS0073"){
  1611. #-- write 16 zeros to erase all icons
  1612. if( $icon == 0){
  1613. #-- 4 bit data size, RE => 1, blink Enable = \x26
  1614. $select = "\x10\x26";
  1615. #"set.icon.1"
  1616. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1617. PT_WAIT_THREAD($thread->{pt_execute});
  1618. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1619. #-- SEGRAM addres to 0 = \x40,
  1620. $select = "\x10\x40";
  1621. #-- write 16 zeros to scratchpad
  1622. $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  1623. #"set.icon.2"
  1624. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1625. PT_WAIT_THREAD($thread->{pt_execute});
  1626. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1627. #-- issue the copy scratchpad to LCD command \x48
  1628. $select="\x48";
  1629. #"set.icon.3"
  1630. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1631. PT_WAIT_THREAD($thread->{pt_execute});
  1632. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1633. } else {
  1634. #-- determine data value
  1635. if( int($icon) != 16 ){
  1636. if( $value == 0 ){
  1637. $data = 0;
  1638. } elsif ( $value == 1) {
  1639. $data = 16;
  1640. } elsif ( $value == 2) {
  1641. $data = 80;
  1642. } else {
  1643. die("OWXLCD: Wrong data value $value for icon $icon");
  1644. }
  1645. } else {
  1646. if( $value == 0 ){
  1647. $data = 0;
  1648. } elsif ( $value == 1) {
  1649. $data = 16;
  1650. } elsif ( $value == 2) {
  1651. $data = 24;
  1652. } elsif ( $value == 3) {
  1653. $data = 28;
  1654. } elsif ( $value == 4) {
  1655. $data = 30;
  1656. } elsif ( $value == 5) {
  1657. $data = 31;
  1658. } elsif ( $value == 6) {
  1659. $data = 80;
  1660. } else {
  1661. die("OWXLCD: Wrong data value $value for icon $icon");
  1662. }
  1663. }
  1664. #-- 4 bit data size, RE => 1, blink Enable = \x26
  1665. $select = "\x10\x26";
  1666. #"set.icon.4"
  1667. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1668. PT_WAIT_THREAD($thread->{pt_execute});
  1669. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1670. #-- SEGRAM addres to 0 = \x40 + icon address
  1671. $select = sprintf("\x10%c",63+$icon);
  1672. #"set.icon.5"
  1673. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1674. PT_WAIT_THREAD($thread->{pt_execute});
  1675. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1676. #-- data
  1677. $select = sprintf("\x12%c",$data);
  1678. #"set.icon.6"
  1679. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1680. PT_WAIT_THREAD($thread->{pt_execute});
  1681. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1682. }
  1683. #-- return to normal state
  1684. $select = "\x10\x20";
  1685. #"set.icon.7"
  1686. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1687. PT_WAIT_THREAD($thread->{pt_execute});
  1688. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1689. #-- or else
  1690. } else {
  1691. die("OWXLCD: Wrong LCD controller type");
  1692. }
  1693. PT_END;
  1694. });
  1695. }
  1696. ########################################################################################
  1697. #
  1698. # OWXLCD_PT_SetLine - set one of the display lines async
  1699. #
  1700. # Parameter hash = hash of device addressed
  1701. # line = line number (0..3)
  1702. # msg = data string to be written
  1703. #
  1704. ########################################################################################
  1705. sub OWXLCD_PT_SetLine($$$) {
  1706. my ($hash,$line,$msg) = @_;
  1707. return PT_THREAD(sub {
  1708. my ($thread) = @_;
  1709. my ($select, $i, $msgA, $msgB);
  1710. #-- ID of the device, hash of the busmaster
  1711. my $owx_dev = $hash->{ROM_ID};
  1712. my $master = $hash->{IODev};
  1713. $line = int($line);
  1714. PT_BEGIN($thread);
  1715. $msg = defined($msg) ? $msg : "";
  1716. $msg = OWXLCD_Trans($msg);
  1717. #-- split if longer than 16 bytes, fill each with blanks
  1718. # has already been checked to be <= $lcdchars
  1719. if( $lcdchars > 16 ){
  1720. if( length($msg) > 16 ) {
  1721. $msgA = substr($msg,0,16);
  1722. $msgB = substr($msg,16,length($msg)-16);
  1723. for($i = 0;$i<$lcdchars-length($msg);$i++){
  1724. $msgB .= "\x20";
  1725. }
  1726. } else {
  1727. $msgA = $msg;
  1728. for($i = 0;$i<16-length($msg);$i++){
  1729. $msgA .= "\x20";
  1730. }
  1731. for($i = 0;$i<$lcdchars-16;$i++){
  1732. $msgB .= "\x20";
  1733. }
  1734. }
  1735. }else{
  1736. $msgA = $msg;
  1737. for($i = 0;$i<$lcdchars-length($msg);$i++){
  1738. $msgA .= "\x20";
  1739. }
  1740. $msgB = undef;
  1741. }
  1742. $thread->{msgB} = $msgB;
  1743. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1744. # followed by LCD page address and the text
  1745. $select=sprintf("\x4E%c",$lcdpage[$line]).$msgA;
  1746. #"set.line.1"
  1747. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1748. PT_WAIT_THREAD($thread->{pt_execute});
  1749. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1750. #-- issue the copy scratchpad to LCD command \x48
  1751. $select="\x48";
  1752. #"set.line.2"
  1753. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1754. PT_WAIT_THREAD($thread->{pt_execute});
  1755. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1756. #-- if second string available:
  1757. if( defined($thread->{msgB}) ) {
  1758. #select(undef,undef,undef,0.005);
  1759. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1760. # followed by LCD page address and the text
  1761. $select=sprintf("\x4E%c",$lcdpage[$line]+16).$thread->{msgB};
  1762. #"set.line.3"
  1763. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1764. PT_WAIT_THREAD($thread->{pt_execute});
  1765. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1766. #-- issue the copy scratchpad to LCD command \x48
  1767. $select="\x48";
  1768. #"set.line.4"
  1769. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1770. PT_WAIT_THREAD($thread->{pt_execute});
  1771. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1772. }
  1773. PT_END;
  1774. });
  1775. }
  1776. ########################################################################################
  1777. #
  1778. # OWXLCD_PT_SetMemory - set internal nonvolatile memory async
  1779. #
  1780. # Parameter hash = hash of device addressed
  1781. # page = page number (0..14)
  1782. # msg = data string to be written
  1783. #
  1784. ########################################################################################
  1785. sub OWXLCD_PT_SetMemory($$$) {
  1786. my ($hash,$page,$msg) = @_;
  1787. return PT_THREAD(sub {
  1788. my ($thread,$hash,$page,$msg) = @_;
  1789. my ($select, $i, $msgA);
  1790. #-- ID of the device, hash of the busmaster
  1791. my $owx_dev = $hash->{ROM_ID};
  1792. my $master = $hash->{IODev};
  1793. PT_BEGIN($thread);
  1794. $page = int($page);
  1795. $msg = defined($msg) ? $msg : "";
  1796. #-- fillup with blanks
  1797. $msgA = $msg;
  1798. for($i = 0;$i<16-length($msg);$i++){
  1799. $msgA .= "\x20";
  1800. }
  1801. #-- issue the match ROM command \x55 and the write scratchpad command \x4E
  1802. # followed by LCD page address and the text
  1803. #Log 1," page written is ".$page;
  1804. $select=sprintf("\x4E\%c",$page).$msgA;
  1805. #"set.memory.page"
  1806. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1807. PT_WAIT_THREAD($thread->{pt_execute});
  1808. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1809. #-- issue the copy scratchpad to EEPROM command \x39
  1810. $select = "\x39";
  1811. #"set.memory.copy"
  1812. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
  1813. PT_WAIT_THREAD($thread->{pt_execute});
  1814. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1815. PT_END;
  1816. });
  1817. }
  1818. 1;
  1819. =pod
  1820. =item device
  1821. =item summary to commmunicate with the 1-Wire LCD hardware
  1822. =begin html
  1823. <a name="OWLCD"></a>
  1824. <h3>OWLCD</h3>
  1825. <p>FHEM module to commmunicate with the <a
  1826. href="http://www.louisswart.co.za/1-Wire_Overview.html">1-Wire LCD controller</a>
  1827. from Louis Swart (1-Wire family id FF). See also the corresponding <a
  1828. href="http://fhemwiki.de/wiki/1-Wire_Textdisplay">Wiki page.</a><br /><br />
  1829. Note:<br /> This 1-Wire module so far works only with the OWX interface module. Please
  1830. define an <a href="#OWX">OWX</a> device first. <br /></p>
  1831. <br /><h4>Example</h4>
  1832. <p>
  1833. <code>define OWX_LCD OWLCD 9F0700000100</code>
  1834. <br />
  1835. </p>
  1836. <br />
  1837. <a name="OWLCDdefine"></a>
  1838. <h4>Define</h4>
  1839. <p>
  1840. <code>define &lt;name&gt; OWLCD &lt;id&gt;</code> or <br/>
  1841. <code>define &lt;name&gt; OWLCD FF.&lt;id&gt;</code>
  1842. <br /><br /> Define a 1-Wire LCD device.<br /><br /></p>
  1843. <ul>
  1844. <li>
  1845. <code>&lt;id&gt;</code>
  1846. <br />12-character unique ROM id of the converter device without family id and CRC
  1847. code </li>
  1848. </ul>
  1849. <br />
  1850. <a name="OWLCDset"></a>
  1851. <h4>Set</h4>
  1852. <ul>
  1853. <li><a name="owlcd_icon">
  1854. <code>set &lt;name&gt; icon &lt;int&gt; on|off|blink</code></a><br /> Set one of
  1855. the icons 0..14 on, off or blinking</li>
  1856. <li><a name="owlcd_icon2">
  1857. <code>set &lt;name&gt; icon 15 0..6</code></a><br /> Set icon 15 to one of its
  1858. values</li>
  1859. <li><a name="owlcd_icon3">
  1860. <code>set &lt;name&gt; icon none</code></a><br /> Set all icons off</li>
  1861. <li><a name="owlcd_line">
  1862. <code>set &lt;name&gt; line &lt;int&gt; &lt;string&gt;</code></a><br /> Write
  1863. LCD line 0..3 with some content </li>
  1864. <li><a name="owlcd_memory">
  1865. <code>set &lt;name&gt; memory &lt;page&gt; &lt;string&gt;</code></a><br />Write
  1866. memory page 0..6</li>
  1867. <li><a name="owlcd_gpio">
  1868. <code>set &lt;name&gt; gpio &lt;value&gt;</code></a><br />Write state for all
  1869. three gpio pins (value = 0..7, for each bit 0=ON, 1=OFF)</li>
  1870. <li><a name="owlcd_gpiobit">
  1871. <code>set &lt;name&gt; gpiobit &lt;bit&gt; &lt;value&gt;</code></a><br />Write state for gpio pin no. 1..3,
  1872. possible values are 0=ON, 1=OFF</li>
  1873. <li><a name="owlcd_bl">
  1874. <code>set &lt;name&gt; backlight ON|OFF</code></a><br />Switch backlight on or
  1875. off</li>
  1876. <li><a name="owlcd_lcd">
  1877. <code>set &lt;name&gt; lcd ON|OFF</code></a><br />Switch LCD power on or
  1878. off</li>
  1879. <li><a name="owlcd_reset">
  1880. <code>set &lt;name&gt; reset</code></a><br />Reset the display</li>
  1881. <li><a name="owlcd_test">
  1882. <code>set &lt;name&gt; test</code></a><br />Test the display</li>
  1883. </ul>
  1884. <br />
  1885. <a name="owlcdget"></a>
  1886. <h4>Get</h4>
  1887. <ul>
  1888. <li><a name="owlcd_id">
  1889. <code>get &lt;name&gt; id</code></a>
  1890. <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
  1891. <li><a name="owlcd_memory2">
  1892. <code>get &lt;name&gt; memory &lt;page&gt;</code></a><br />Read memory page 0..6 </li>
  1893. <li><a name="owlcd_gpio2">
  1894. <code>get &lt;name&gt; gpio</code></a><br />Obtain state of all four input
  1895. channels (15 = all off, 0 = all on)</li>
  1896. <li><a name="owlcd_counter">
  1897. <code>get &lt;name&gt; counter</code></a><br />Obtain state of all four input
  1898. counters (4 x 16 Bit)</li>
  1899. <li><a name="owlcd_version">
  1900. <code>get &lt;name&gt; version</code></a><br />Obtain firmware version of the
  1901. controller</li>
  1902. </ul>
  1903. <br />
  1904. <a name="owlcdattr"></a>
  1905. <h4>Attributes</h4>
  1906. <ul>
  1907. <li><a name="owlcd_lcdgeometry">
  1908. <code>attr &lt;name&gt; lcdgeometry &lt;string&gt;</code></a><br />
  1909. LCD geometry, values are 0-32-64-96 (default) or 0-64-20-84</li>
  1910. <li><a name="owlcd_lcdgcontroller">
  1911. <code>attr &lt;name&gt; lcdcontroller &lt;string&gt;</code></a><br />
  1912. LCD geometry, values are KS0073 (default) HD44780</li>
  1913. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1914. </ul>
  1915. =end html
  1916. =cut