OWNet-2.8p17.pm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. package OWNet ;
  2. # OWNet module for perl
  3. # $Id: OWNet.pm,v 1.22 2011/03/24 01:40:39 alfille Exp $
  4. #
  5. # Paul H Alfille -- copyright 2007
  6. # Part of the OWFS suite:
  7. # http://www.owfs.org
  8. # http://owfs.sourceforge.net
  9. =head1 NAME
  10. OWNet -
  11. Light weight access to B<owserver>
  12. =head1 SYNOPSIS
  13. OWNet is an easy way to access B<owserver> and thence the 1-wire bus.
  14. Dallas Semiconductor's 1-wire system uses simple wiring and unique addresses for its interesting devices. The B<One Wire File System (OWFS)> is a suite of programs that hide 1-wire details behind a file system metaphor. B<owserver> connects to the 1-wire bus and provides network access.
  15. B<OWNet> is a perl module that connects to B<owserver> and allows reading, writing and listing the 1-wire bus.
  16. Example perl program that prints the temperature:
  17. use OWNet ;
  18. print OWNet::read( "localhost:4304" , "/10.67C6697351FF/temperature" ) ."\n" ;
  19. There is the alternative object oriented form:
  20. use OWNet ;
  21. my $owserver = OWNet->new( "localhost:4304" ) ;
  22. print $owserver->read( "/10.67C6697351FF/temperature" ) ."\n" ;
  23. =head1 SYNTAX
  24. =head2 methods
  25. =over
  26. =item B<new>
  27. my $owserver = OWNet -> new( address ) ;
  28. =item B<read>
  29. OWNet::read( address, path [,size [,offset]] )
  30. $owserver -> read( path [,size [,offset]] )
  31. =item B<write>
  32. OWNet::write( address, path, value [,offset] )
  33. $owserver -> write( path, value [,offset] )
  34. =item B<dir>
  35. OWNet::dir( address, path )
  36. $owserver -> dir( path )
  37. =back
  38. =head2 I<address>
  39. TCP/IP I<address> of B<owserver>. Valid forms:
  40. =over
  41. =item I<name> test.owfs.net:4304
  42. =item I<quad> number: 123.231.312.213:4304
  43. =item I<host> localhost:4304
  44. =item I<port> 4304
  45. =back
  46. =head2 I<additional arguments>
  47. Additional arguments to add to address
  48. Temperature scale can also be specified in the I<address>. Same syntax as the other OWFS programs:
  49. =over
  50. =item -C Celsius (Centigrade)
  51. =item -F Fahrenheit
  52. =item -K Kelvin
  53. =item -R Rankine
  54. =back
  55. Pressure scale can also be specified in the I<address>. Same syntax as the other OWFS programs:
  56. =over
  57. =item --mbar millibar (default)
  58. =item --atm atmosphere
  59. =item --mmHg mm Mercury
  60. =item --inHg inch Mercury
  61. =item --psi pounds per inch^2
  62. =item --Pa pascal
  63. =back
  64. Device display format (1-wire unique address) can also be specified in the I<address>, with the general form of -ff[.]i[[.]c] (I<f>amily I<i>d I<c>rc):
  65. =over
  66. =item -ff.i /10.67C6697351FF (default)
  67. =item -ffi /1067C6697351FF
  68. =item -ff.i.c /10.67C6697351FF.8D
  69. =item -ff.ic /10.67C6697351FF8D
  70. =item -ffi.c /1067C6697351FF.8D
  71. =item -ffic /1067C6697351FF8D
  72. =back
  73. Show directories that are themselves directories with a '/' suffix ( e.g. /10.67C6697351FF/ )
  74. =over
  75. =item -slash show directory elements
  76. =back
  77. Warning messages will only be displayed if verbose flag is specified in I<address>
  78. =over
  79. =item -v verbose
  80. =back
  81. =head2 I<path>
  82. B<owfs>-type I<path> to an item on the 1-wire bus. Valid forms:
  83. =over
  84. =item main directories
  85. Used for the I<dir> method. E.g. "/" "/uncached" "/1F.321432320000/main"
  86. =item device directory
  87. Used for the I<dir> and I<present> method. E.g. "/10.4300AC220000" "/statistics"
  88. =item device properties
  89. Used to I<read>, I<write>. E.g. "/10.4300AC220000/temperature"
  90. =back
  91. =head2 I<value>
  92. New I<value> for a device property. Used by I<write>.
  93. =head1 METHODS
  94. =over
  95. =cut
  96. BEGIN { }
  97. use 5.008 ;
  98. use warnings ;
  99. use strict ;
  100. use IO::Socket::INET ;
  101. use bytes ;
  102. my $MSG_READ = 2 ;
  103. my $MSG_WRITE = 3 ;
  104. my $MSG_DIR = 4 ;
  105. my $MSG_PRESENCE = 6 ;
  106. my $MSG_DIRALL = 7 ;
  107. my $MSG_DIRALLSLASH = 9 ;
  108. # return value should be negative for error, but the networking layer uses 32bit unsigned integers. This is the boundary.
  109. my $MAX_RETURN = 66000 ;
  110. # Network timeout in ms
  111. my $MAX_WAIT = 3000 ;
  112. my $RECV_FLAGS = 0 ;
  113. my $SEND_FLAGS = 0 ;
  114. my $NO_OFFSET = 0 ;
  115. my $PERSISTENCE_BIT = 0x04 ;
  116. # PresenceCheck, Return bus list, and apply aliases
  117. my $DEFAULT_SG = 0x100 + 0x2 + 0x8 ;
  118. my $DEFAULT_BLOCK_LENGTH = 33000 ;
  119. our $VERSION=(split(/ /,q[$Revision: 1.22 $]))[1] ;
  120. sub _new($$) {
  121. my ($self,$addr) = @_ ;
  122. $addr =~ s/--/-/g ;
  123. my $tempscale = 0 ;
  124. TEMPSCALE: {
  125. $tempscale = 0x00000 , last TEMPSCALE if $addr =~ /-C/ ;
  126. $tempscale = 0x10000 , last TEMPSCALE if $addr =~ /-F/ ;
  127. $tempscale = 0x20000 , last TEMPSCALE if $addr =~ /-K/ ;
  128. $tempscale = 0x30000 , last TEMPSCALE if $addr =~ /-R/ ;
  129. }
  130. my $presscale = 0 ;
  131. PRESSCALE: {
  132. $presscale = 0x000000 , last PRESSCALE if $addr =~ /-mbar/i ;
  133. $presscale = 0x040000 , last PRESSCALE if $addr =~ /-atm/i ;
  134. $presscale = 0x080000 , last PRESSCALE if $addr =~ /-mmhg/i ;
  135. $presscale = 0x0C0000 , last PRESSCALE if $addr =~ /-inhg/i ;
  136. $presscale = 0x100000 , last PRESSCALE if $addr =~ /-psi/i ;
  137. $presscale = 0x140000 , last PRESSCALE if $addr =~ /-pa/i ;
  138. }
  139. my $format = 0 ;
  140. FORMAT: {
  141. $format = 0x2000000 , last FORMAT if $addr =~ /-ff\.i\.c/ ;
  142. $format = 0x4000000 , last FORMAT if $addr =~ /-ffi\.c/ ;
  143. $format = 0x3000000 , last FORMAT if $addr =~ /-ff\.ic/ ;
  144. $format = 0x5000000 , last FORMAT if $addr =~ /-ffic/ ;
  145. $format = 0x0000000 , last FORMAT if $addr =~ /-ff\.i/ ;
  146. $format = 0x1000000 , last FORMAT if $addr =~ /-ffi/ ;
  147. $format = 0x2000000 , last FORMAT if $addr =~ /-f\.i\.c/ ;
  148. $format = 0x4000000 , last FORMAT if $addr =~ /-fi\.c/ ;
  149. $format = 0x3000000 , last FORMAT if $addr =~ /-f\.ic/ ;
  150. $format = 0x5000000 , last FORMAT if $addr =~ /-fic/ ;
  151. $format = 0x0000000 , last FORMAT if $addr =~ /-f\.i/ ;
  152. $format = 0x1000000 , last FORMAT if $addr =~ /-fi/ ;
  153. }
  154. # Verbose flag
  155. $self->{VERBOSE} = 1 if $addr =~ /-v/i ;
  156. # slash after directory elements
  157. $self->{SLASH} = 1 if $addr =~ /-slash/i ;
  158. $addr =~ s/-[\w\.]*//g ;
  159. $addr =~ s/ //g ;
  160. my $port ;
  161. if ( $addr =~ /(.*):(.*)/ ) {
  162. $addr = $1 ;
  163. $port = $2 ;
  164. } elsif ( $addr =~/\D/ ) {
  165. $port = '' ;
  166. } else {
  167. $port = $addr ;
  168. $addr = '' ;
  169. }
  170. $self->{ADDR} = $addr ;
  171. $self->{PORT} = $port ;
  172. $self->{SG} = $DEFAULT_SG + $tempscale + $presscale + $format ;
  173. $self->{VER} = 0 ;
  174. }
  175. sub _Sock($) {
  176. my $self = shift ;
  177. # persistent socket already there?
  178. if ( defined($self->{SOCK} && $self->{PERSIST} != 0 ) ) {
  179. return 1 ;
  180. }
  181. # defaults
  182. my $addr = $self->{ADDR} ;
  183. my $port = $self->{PORT} ;
  184. $addr = '127.0.0.1' if $addr eq '' ;
  185. $port = 'owserver(4304)' if $port eq '' ;
  186. # New socket
  187. $self->{SOCK} = IO::Socket::INET->new(
  188. PeerAddr=>$addr,
  189. PeerPort=>$port,
  190. Proto=>'tcp')
  191. || do {
  192. warn("Can't open $addr:$port ($!) \n") if $self->{VERBOSE} ;
  193. $self->{SOCK} = undef ;
  194. return ;
  195. } ;
  196. return 1 ;
  197. }
  198. sub _self($) {
  199. my $addr = shift ;
  200. my $self ;
  201. if ( ref($addr) ) {
  202. $self = $addr ;
  203. $self->{PERSIST} = $PERSISTENCE_BIT ;
  204. } else {
  205. $self = {} ;
  206. _new($self,$addr) ;
  207. $self->{PERSIST} = 0 ;
  208. }
  209. if ( ($self->{ADDR} eq '') && ($self->{PORT} eq '') ) {
  210. _BonjourLookup($self) || _Sock($self) || return ;
  211. } else {
  212. _Sock($self) || return ;
  213. }
  214. return $self;
  215. }
  216. sub _BonjourLookup($) {
  217. my $self = shift ;
  218. eval { require Net::Rendezvous; };
  219. if ($@) {
  220. print "$@\n" if $self->{VERBOSE} ;
  221. return ;
  222. }
  223. my $owservers = Net::Rendezvous->new('owserver') || do {
  224. print "Unable to start owserver discovery via Net::Rendezvous $!\n" if $self->{VERBOSE} ;
  225. return ;
  226. } ;
  227. $owservers->discover ;
  228. my $owserver_selected = $owservers->shift_entry || do {
  229. print "No owserver discovered by Net::Rendezvous\n" if $self->{VERBOSE} ;
  230. return ;
  231. } ;
  232. print $owserver_selected->host.":".$owserver_selected->port."\n" if $self->{VERBOSE} ;
  233. # New socket
  234. $self->{SOCK} = IO::Socket::INET->new(PeerAddr=>$owserver_selected->host,PeerPort=>$owserver_selected->port,Proto=>'tcp') || do {
  235. warn("Can't open Bonjour (autodiscovered) port ($!) \n") if $self->{VERBOSE} ;
  236. $self->{SOCK} = undef ;
  237. return ;
  238. } ;
  239. $self->{ADDR} = $self->{SOCK}->peeraddr ;
  240. $self->{PORT} = $self->{SOCK}->peerport ;
  241. return 1 ;
  242. }
  243. sub _ToServer ($$$$;$) {
  244. my ($self, $msg_type, $size, $offset, $payload_data) = @_ ;
  245. my $f = "N6" ;
  246. my $payload_length = length($payload_data) + 1 ;
  247. $f .= 'Z'.$payload_length ;
  248. my $message = pack($f,$self->{VER},$payload_length,$msg_type,$self->{SG}|$self->{PERSIST},$size,$offset,$payload_data) ;
  249. # try to send
  250. send( $self->{SOCK}, $message, $SEND_FLAGS ) && return 1 ;
  251. # maybe bad persistent connection
  252. if ( $self->{PERSIST} != 0 ) {
  253. $self->{SOCK} = undef ;
  254. _Sock($self) || return ;
  255. send( $self->{SOCK}, $message, $SEND_FLAGS ) && return 1 ;
  256. }
  257. warn("Send problem $! \n") if $self->{VERBOSE} ;
  258. return ;
  259. }
  260. sub _FromServerBinaryParse($$) {
  261. my $self = shift ;
  262. my $length_wanted = shift ;
  263. return '' if $length_wanted == 0 ;
  264. my $fileno = $self->{SOCK}->fileno ;
  265. my $selectreadbits = '' ;
  266. vec($selectreadbits,$fileno,1) = 1 ;
  267. my $remaininglength = $length_wanted ;
  268. my $fullread = '' ;
  269. do {
  270. select($selectreadbits,undef,undef,$MAX_WAIT) ;
  271. return if vec($selectreadbits,$fileno,1) == 0 ;
  272. my $partialread ;
  273. defined( recv( $self->{SOCK}, $partialread, $remaininglength, $RECV_FLAGS ) ) || do {
  274. warn("Trouble getting data back $! after $remaininglength of $length_wanted") if $self->{VERBOSE} ;
  275. return ;
  276. } ;
  277. $fullread .= $partialread ;
  278. $remaininglength = $length_wanted - length($fullread) ;
  279. } while $remaininglength > 0 ;
  280. return $fullread ;
  281. }
  282. sub _FromServer($) {
  283. my $self = shift ;
  284. my ( $version, $payload_length, $return_status, $sg, $size, $offset, $payload_data ) ;
  285. do {
  286. my $r = _FromServerBinaryParse( $self,24 ) || do {
  287. warn("Trouble getting header $!") if $self->{VERBOSE} ;
  288. return ;
  289. } ;
  290. ($version, $payload_length, $return_status, $sg, $size, $offset) = unpack('N6', $r ) ;
  291. return if $return_status > $MAX_RETURN ;
  292. } while $payload_length > $MAX_RETURN ;
  293. $payload_data = _FromServerBinaryParse( $self,$payload_length ) ;
  294. if ( !defined($payload_data) ) {
  295. warn("Trouble getting payload $!") if $self->{VERBOSE} ;
  296. return ;
  297. } ;
  298. $payload_data = substr($payload_data,0,$size) ;
  299. $self->{PERSIST} = $sg & $PERSISTENCE_BIT ;
  300. return ($version, $payload_length, $return_status, $sg, $size, $offset, $payload_data ) ;
  301. }
  302. =item B<new>
  303. Object-oriented (only):
  304. B<OWNet::new>( I<address> )
  305. Create a new OWNet object -- corresponds to an B<owserver>.
  306. Error (and undef return value) if:
  307. =over
  308. =item 1 Badly formed tcp/ip I<address>
  309. =item 2 No B<owserver> at I<address>
  310. =item
  311. =back
  312. =cut
  313. sub new($$) {
  314. my $class = shift ;
  315. my $addr = shift || "" ;
  316. my $self = {} ;
  317. _new($self,$addr) ;
  318. if ( !defined($self->{ADDR}) ) {
  319. return ;
  320. } ;
  321. bless $self, $class ;
  322. return $self ;
  323. }
  324. =item B<read>
  325. =over
  326. =item Non object-oriented:
  327. B<OWNet::read>( I<address> , I<path> [ , I<size> [ , I<offset> ] ] )
  328. =item Object-oriented:
  329. $ownet->B<read>( I<path> [ , I<size> [ , I<offset> ] ] )
  330. =back
  331. Read the value of a 1-wire device property. Returns the (scalar string) value of the property.
  332. I<size> (number of bytes to read) is optional
  333. I<offset> (number of bytes from start of field to start write) is optional
  334. Error (and undef return value) if:
  335. =over
  336. =item 1 (Non object) No B<owserver> at I<address>
  337. =item 2 (Object form) Not called with a valid OWNet object
  338. =item 3 Bad I<path>
  339. =item 4 I<path> not a readable device property
  340. =item
  341. =back
  342. =cut
  343. sub read($$) {
  344. my $self = _self(shift) || return ;
  345. my $path = shift ;
  346. my $read_length = shift || $DEFAULT_BLOCK_LENGTH ;
  347. my $offset = shift || $NO_OFFSET ;
  348. _ToServer($self,$MSG_READ,$read_length,$offset,$path) ;
  349. my @r = _FromServer($self) ;
  350. if ( !@r ) {
  351. return ;
  352. }
  353. return $r[6] ;
  354. }
  355. =item B<write>
  356. =over
  357. =item Non object-oriented:
  358. B<OWNet::write>( I<address> , I<path> , I<value> [ , I<offset> ] )
  359. =item Object-oriented:
  360. $ownet->B<write>( I<path> , I<value> [ , I<offset> ] )
  361. =back
  362. Set the value of a 1-wire device property. Returns "1" on success.
  363. I<offset> (number of bytes from start of field to start write) is optional
  364. Error (and undef return value) if:
  365. =over
  366. =item 1 (Non object) No B<owserver> at I<address>
  367. =item 2 (Object form) Not called with a valid OWNet object
  368. =item 3 Bad I<path>
  369. =item 4 I<path> not a writable device property
  370. =item 5 I<value> incorrect size or format
  371. =item
  372. =back
  373. =cut
  374. sub write($$$;$) {
  375. my $self = _self(shift) || return ;
  376. my $path = shift ;
  377. my $val = shift ;
  378. my $offset = shift || $NO_OFFSET ;
  379. my $value_length = length($val) ;
  380. my $path_length = length($path)+1 ;
  381. my $payload = pack( 'Z'.$path_length.'A'.$value_length,$path,$val ) ;
  382. _ToServer($self,$MSG_WRITE,$value_length,$offset,$payload) ;
  383. my @r = _FromServer($self) ;
  384. if ( !@r ) {
  385. return;
  386. }
  387. return $r[2]>=0 ;
  388. }
  389. =item B<dir>
  390. =over
  391. =item Non object-oriented:
  392. B<OWNet::dir>( I<address> , I<path> )
  393. =item Object-oriented:
  394. $ownet->B<dir>( I<path> )
  395. =back
  396. Return a comma-separated list of the entries in I<path>. Entries are equivalent to "fully qualified names" -- full path names.
  397. Error (and undef return value) if:
  398. =over
  399. =item 1 (Non object) No B<owserver> at I<address>
  400. =item 2 (Object form) Not called with a valid OWNet object
  401. =item 3 Bad I<path>
  402. =item 4 I<path> not a directory
  403. =item
  404. =back
  405. =cut
  406. sub dir($$) {
  407. my $self = _self(shift) || return ;
  408. my $path = shift ;
  409. # DIRALLSLASH method -- single packet with slash (/) after each dir entry
  410. if ( $self->{SLASH}) {
  411. _ToServer($self,$MSG_DIRALLSLASH,$DEFAULT_BLOCK_LENGTH,$NO_OFFSET,$path) || return ;
  412. my @r = _FromServer($self) ;
  413. if (@r) {
  414. $self->{SOCK} = undef if $self->{PERSIST} == 0 ;
  415. return $r[6] ;
  416. } ;
  417. }
  418. # new MSG_DIRALL method -- single packet
  419. _ToServer($self,$MSG_DIRALL,$DEFAULT_BLOCK_LENGTH,$NO_OFFSET,$path) || return ;
  420. my @r = _FromServer($self) ;
  421. if (@r) {
  422. $self->{SOCK} = undef if $self->{PERSIST} == 0 ;
  423. return $r[6] ;
  424. } ;
  425. # old MSG_DIR method -- many packets
  426. _Sock($self) || return ;
  427. _ToServer($self,$MSG_DIR,$DEFAULT_BLOCK_LENGTH,$NO_OFFSET,$path) || return ;
  428. my $dirlist = '' ;
  429. while (1) {
  430. @r = _FromServer($self) || return ;
  431. return if !@r ;
  432. if ( $r[1] == 0 ) { # last null packet
  433. $self->{SOCK} = undef if $self->{PERSIST} == 0 ;
  434. return substr($dirlist,1) ; # not starting comma
  435. }
  436. $dirlist .= ','.$r[6] ;
  437. }
  438. }
  439. return 1 ;
  440. END { }
  441. =item B<present> (deprecated)
  442. =over
  443. =item Non object-oriented:
  444. B<OWNet::present>( I<address> , I<path> )
  445. =item Object-oriented:
  446. $ownet->B<present>( I<path> )
  447. =back
  448. Test if a 1-wire device exists.
  449. Error (and undef return value) if:
  450. =over
  451. =item 1 (Non object) No B<owserver> at I<address>
  452. =item 2 (Object form) Not called with a valid OWNet object
  453. =item 3 Bad I<path>
  454. =item 4 I<path> not a device
  455. =item
  456. =back
  457. =cut
  458. sub present($$) {
  459. my $self = _self(shift) || return ;
  460. my $path = shift ;
  461. _ToServer($self,$MSG_PRESENCE,$DEFAULT_BLOCK_LENGTH,$NO_OFFSET,$path) ;
  462. my @r = _FromServer($self) ;
  463. return if !@r ;
  464. return $r[2]>=0 ;
  465. }
  466. =back
  467. =head1 DESCRIPTION
  468. =head2 OWFS
  469. I<OWFS> is a suite of programs that allows easy access to I<Dallas Semiconductor>'s 1-wire bus and devices.
  470. I<OWFS> provides a consistent naming scheme, safe multplexing of 1-wire traffice, multiple methods of access and display, and network access.
  471. The basic I<OWFS> metaphor is a file-system, with the bus beinng the root directory, each device a subdirectory, and the the device properties (e.g. voltage, temperature, memory) a file.
  472. =head2 1-Wire
  473. I<1-wire> is a protocol allowing simple connection of inexpensive devices.
  474. Each device has a unique ID number (used in its OWFS address) and is individually addressable.
  475. The bus itself is extremely simple -- a data line and a ground. The data line also provides power.
  476. 1-wire devices come in a variety of packages -- chips, commercial boxes, and iButtons (stainless steel cans).
  477. 1-wire devices have a variety of capabilities, from simple ID to complex voltage, temperature, current measurements, memory, and switch control.
  478. =head2 Programs
  479. Connection to the 1-wire bus is either done by bit-banging a digital pin on the processor, or by using a bus master -- USB, serial, i2c, parallel.
  480. The heavy-weight I<OWFS> programs: B<owserver> B<owfs> B<owhttpd> B<owftpd> and the heavy-weight perl module B<OW> all link in the full I<OWFS> library and can connect directly to the bus master(s) and/or to B<owserver>.
  481. B<OWNet> is a light-weight module. It connects only to an B<owserver>, does not link in the I<OWFS> library, and should be more portable..
  482. =head2 Object-oriented
  483. B<OWNet> can be used in either a classical (non-object-oriented) manner, or with objects.
  484. The object stored the ip address of the B<owserver> and a network socket to communicate.
  485. B<OWNet> will use persistent tcp connections for the object form -- potentially a performance boost over a slow network.
  486. =head1 EXAMPLES
  487. =head2 owserver
  488. B<owserver> is a separate process that must be accessible on the network. It allows multiple clients, and can connect to many physical 1-wire adapters and 1-wire devices. It's address must be discoverable -- either set on the command line, or at it's default location, or by using Bonjour (zeroconf) service discovery.
  489. An example owserver invocation for a serial adapter and explicitly chooses the default port:
  490. owserver -d /dev/ttyS0 -p 4304
  491. =head2 OWNet
  492. use OWNet ;
  493. # Create owserver object
  494. my $owserver = OWNet->new('localhost:4304 -v -F') ; #default location, verbose errors, Fahrenheit degrees
  495. # my $owserver = OWNet->new() ; #simpler, again default location, no error messages, default Celsius
  496. #print directory
  497. print $owserver->dir('/') ;
  498. #print temperature from known device (DS18S20, ID: 10.13224366A280)
  499. print "Temperature: ".$owserver->read('/uncached/10.13224366A280/temperature') ;
  500. # Now for some fun -- a tree of everything:
  501. sub Tree($$) {
  502. my $ow = shift ;
  503. my $path = shift ;
  504. print "$path\t" ;
  505. # first try to read
  506. my $value = $ow->read($path) ;
  507. if ( defined($value) ) {
  508. print "$value\n";
  509. return ;
  510. }
  511. # not readable, try as directory
  512. my $dirstring = $ow->dir($path) ;
  513. if ( defined($dirstring) ) {
  514. print "<directory>\n" ;
  515. my @dir = split /,/ , $ow->dir($path) ;
  516. foreach (@dir) {
  517. Tree($ow,$_) ;
  518. }
  519. return ;
  520. }
  521. # can't read, not directory
  522. print "<write-only>\n" ;
  523. return ;
  524. }
  525. Tree( $owserver, '/' ) ;
  526. =head1 INTERNALS
  527. =head2 Object properties (All private)
  528. =over
  529. =item ADDR
  530. literal sting for the IP address, in dotted-quad or host format. This property is also used to indicate a substantiated object.
  531. =item PORT
  532. string for the port number (or service name). Service name must be specified as :owserver or the like.
  533. =item SG
  534. Flag sent to server, and returned, that encodes temperature scale and display format. Persistence is also encoded in this word in the actual tcp message, but kept separately in the object.
  535. =item VERBOSE
  536. Print error messages? Set by "-v" in object invocation.
  537. =item SLASH
  538. Add "/" to the end of directory entries. Set by "-slash" in object invocation.
  539. =item SOCK
  540. Socket address (object) for communication. Stays defined for persistent connections, else deleted between calls.
  541. =item PERSIST
  542. State of socket connection (persistent means the same socket is used which speeds network communication).
  543. =item VER
  544. owprotocol version number (currently 0)
  545. =back
  546. =head2 Private methods
  547. =over
  548. =item _self
  549. Takes either the implicit object reference (if called on an object) or the ip address in non-object format.
  550. In either case a socket is created, the persistence bit is properly set, and the address parsed.
  551. Returns the object reference, or undef on error.
  552. Called by each external method (read,write,dir) on the first parameter.
  553. =item _new
  554. Takes command line invocation parameters (for an object or not) and properly parses and sets up the properties in a hash array.
  555. =item _Sock
  556. Socket processing, including tests for persistence and opening.
  557. If no host is specified, localhost (127.0.0.1) is used.
  558. If no port is specified, uses the IANA allocated well known port (4304) for owserver. First looks in /etc/services, then just tries 4304.
  559. =item _ToServer
  560. Sends a message to owserver. Formats in owserver protocol. If a persistent socket fails, retries after new socket created.
  561. =item _FromServerBinaryParse
  562. Reads a specified length from server
  563. =item _FromServer
  564. Reads whole packet from server, using _FromServerBinaryParse (first for header, then payload). Discards ping packets silently.
  565. =item _BonjourLookup
  566. Uses the mDNS service discovery protocol to find an available owserver.
  567. Employs NET::Rendezvous (an earlier name or Apple's Bonjour)
  568. This module is loaded only if available. (Uses the method of http://sial.org/blog/2006/12/optional_perl_module_loading.html)
  569. =back
  570. =head1 AUTHOR
  571. Paul H Alfille paul.alfille@gmail.com
  572. =head1 BUGS
  573. Support for proper timeout using the "select" function seems broken in perl. This might leave the routines vulnerable to network timing errors.
  574. =head1 SEE ALSO
  575. =over
  576. =item http://www.owfs.org
  577. Documentation for the full B<owfs> program suite, including man pages for each of the supported 1-wire devices, and more extensive explanatation of owfs components.
  578. =item http://owfs.sourceforge.net/projects/owfs
  579. Location where source code is hosted.
  580. =back
  581. =head1 COPYRIGHT
  582. Copyright (c) 2007 Paul H Alfille. All rights reserved.
  583. This program is free software; you can redistribute it and/or
  584. modify it under the same terms as Perl itself.
  585. =cut