OWNet-3.1p5.pm 21 KB

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