21_OWLCD.pm 70 KB

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