line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::WS2500PC; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# # **************************************************************************** |
6
|
|
|
|
|
|
|
# # *** ws2500PC, (c) 2004 by Magnus Schmidt, ws2500@27b-6.de *** |
7
|
|
|
|
|
|
|
# # *** Library for interfacing the serial port of the WS2500PC Adapter *** |
8
|
|
|
|
|
|
|
# # *** Produced by German Distributor ELV *** |
9
|
|
|
|
|
|
|
# # **************************************************************************** |
10
|
|
|
|
|
|
|
# # *** This program is free software; you can redistribute it and/or modify *** |
11
|
|
|
|
|
|
|
# # *** it under the terms of the GNU General Public License as published by *** |
12
|
|
|
|
|
|
|
# # *** the Free Software Foundation; either version 2 of the License, or *** |
13
|
|
|
|
|
|
|
# # *** (at your option) any later version. *** |
14
|
|
|
|
|
|
|
# # **************************************************************************** |
15
|
|
|
|
|
|
|
# # *** History: 0.99 Initial release *** |
16
|
|
|
|
|
|
|
# # *** 0.99a Bugfix in distribution *** |
17
|
|
|
|
|
|
|
# # *** 0.99b Bugfix for reading other sensors than temp1-temp8 *** |
18
|
|
|
|
|
|
|
# # *** ws2500_GetDatasetBulk() added *** |
19
|
|
|
|
|
|
|
# # **************************************************************************** |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# ******************************************************** |
24
|
|
|
|
|
|
|
# *** Imports |
25
|
|
|
|
|
|
|
# ******************************************************** |
26
|
1
|
|
|
1
|
|
13346
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
420
|
|
27
|
1
|
|
|
1
|
|
8
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
40
|
|
28
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
99
|
|
29
|
1
|
|
|
1
|
|
1830
|
use Device::SerialPort qw(:PARAM :STAT 0.07); |
|
1
|
|
|
|
|
61263
|
|
|
1
|
|
|
|
|
396
|
|
30
|
1
|
|
|
1
|
|
1216
|
use Time::HiRes qw (sleep); |
|
1
|
|
|
|
|
18469
|
|
|
1
|
|
|
|
|
9
|
|
31
|
1
|
|
|
1
|
|
1401
|
use Time::Local qw(timelocal); |
|
1
|
|
|
|
|
1922
|
|
|
1
|
|
|
|
|
69
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# ******************************************************** |
36
|
|
|
|
|
|
|
# *** Package Definition |
37
|
|
|
|
|
|
|
# ******************************************************** |
38
|
|
|
|
|
|
|
require Exporter; |
39
|
1
|
|
|
1
|
|
7
|
use vars qw (@EXPORT @EXPORT_OK @ISA); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5973
|
|
40
|
|
|
|
|
|
|
@ISA = qw (Exporter); |
41
|
|
|
|
|
|
|
@EXPORT = qw (ws2500_GetTime ws2500_GetStatus ws2500_GetDataset ws2500_NextDataset); |
42
|
|
|
|
|
|
|
@EXPORT_OK = qw (ws2500_FirstDataset ws2500_SetDebug ws2500_InterfaceInit ws2500_GetDatasetBulk); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# ******************************************************** |
47
|
|
|
|
|
|
|
# *** Prototypes and global variables |
48
|
|
|
|
|
|
|
# ******************************************************** |
49
|
|
|
|
|
|
|
sub printhex ($); |
50
|
|
|
|
|
|
|
sub send_Command; |
51
|
|
|
|
|
|
|
sub read_Response ($;$); |
52
|
|
|
|
|
|
|
sub init_Interface ($); |
53
|
|
|
|
|
|
|
sub close_Interface (); |
54
|
|
|
|
|
|
|
sub ws2500_GetTime ($;$); |
55
|
|
|
|
|
|
|
sub ws2500_GetStatus ($;$); |
56
|
|
|
|
|
|
|
sub ws2500_GetDataset; |
57
|
|
|
|
|
|
|
sub ws2500_GetDatasetBulk ($;$;$); |
58
|
|
|
|
|
|
|
sub ws2500_NextDataset; |
59
|
|
|
|
|
|
|
sub ws2500_FirstDataset ($); |
60
|
|
|
|
|
|
|
sub ws2500_SetDebug ($); |
61
|
|
|
|
|
|
|
sub ws2500_InterfaceTest ($); |
62
|
|
|
|
|
|
|
sub ws2500_InterfaceInit ($;$); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
our %data; |
65
|
|
|
|
|
|
|
%data = ('debug'=>0, 'maxrepeat'=>10, |
66
|
|
|
|
|
|
|
'commands'=>{'ACTIVATE'=>'0', 'DCF'=>'1', 'NEXTSET'=>'2', 'FIRSTSET'=>'3', 'GETSET'=>'4', 'STATUS'=>'5', |
67
|
|
|
|
|
|
|
'INTERFACETEST'=>'CTST', 'INTERFACEINIT'=>'D'}, |
68
|
|
|
|
|
|
|
'markers'=>{'SOH'=>"\x01", 'STX'=>"\x02", 'ETX'=>"\x03", 'EOT'=>"\x04", |
69
|
|
|
|
|
|
|
'ENQ'=>"\x05", 'ACK'=>"\x06", |
70
|
|
|
|
|
|
|
'DLE'=>"\x10", 'DC2'=>"\x12", 'DC3'=>"\x13", |
71
|
|
|
|
|
|
|
'NAK'=>"\x15"}); |
72
|
|
|
|
|
|
|
our $VERSION = "0.99"; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# ******************************************************** |
77
|
|
|
|
|
|
|
# *** Internal package routines |
78
|
|
|
|
|
|
|
# ******************************************************** |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Returns a string in the form 2A E3 |
81
|
|
|
|
|
|
|
# The special markers used in this interface (like STX=02) are replaced by |
82
|
|
|
|
|
|
|
# the proper identifier. Only used by the debug messages. |
83
|
|
|
|
|
|
|
# Params: data The message to print |
84
|
|
|
|
|
|
|
# Return: string A string in the format described above |
85
|
|
|
|
|
|
|
sub printhex ($) { |
86
|
0
|
|
|
0
|
0
|
|
my $data = shift; |
87
|
0
|
|
|
|
|
|
my $result = ''; |
88
|
|
|
|
|
|
|
|
89
|
0
|
0
|
|
|
|
|
return "" if $data eq ''; |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
|
for (my $x=0;$x
|
92
|
0
|
|
|
|
|
|
my $char = substr($data,$x,1); |
93
|
0
|
|
|
|
|
|
my $printed = 0; |
94
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
|
foreach (keys %{$data{'markers'}}) { |
|
0
|
|
|
|
|
|
|
96
|
0
|
0
|
0
|
|
|
|
if ($char eq $data{'markers'}->{$_} and !$printed) { |
97
|
0
|
|
|
|
|
|
$result.=sprintf("<%s> ",$_); |
98
|
0
|
|
|
|
|
|
$printed=1; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
} |
101
|
0
|
0
|
|
|
|
|
$result.=sprintf("%02X ",ord($char)) unless $printed; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
return $result; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# Sends a command to the interface |
108
|
|
|
|
|
|
|
# This subroutine only encodes and sends a message, it does not care wether |
109
|
|
|
|
|
|
|
# the sent message has been received/acknowledged or not |
110
|
|
|
|
|
|
|
# Params: token A command from $data{'commands'} |
111
|
|
|
|
|
|
|
# param An optional parameter containing additional data |
112
|
|
|
|
|
|
|
# Return: 1 Always true |
113
|
|
|
|
|
|
|
sub send_Command { |
114
|
0
|
|
|
0
|
0
|
|
my $token = shift; |
115
|
0
|
|
|
|
|
|
my ($checksum,$message,$command,$param); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# Is this a valid command, when not die as this is an internal error |
118
|
0
|
0
|
|
|
|
|
die "Unknown command '$token'" unless exists $data{'commands'}->{$token}; |
119
|
0
|
|
|
|
|
|
$param=''; |
120
|
0
|
0
|
|
|
|
|
$param = shift if scalar @_; |
121
|
0
|
|
|
|
|
|
$command = $data{'commands'}->{$token}.$param; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Checksum is negative sum of command value, Bit 7 always set |
124
|
0
|
|
|
|
|
|
foreach (split //, $command) { $checksum+=ord($_); } |
|
0
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
$checksum = (0x100-($checksum & 0xFF)) | 0x80; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Build message and write to port |
128
|
0
|
|
|
|
|
|
$message = $data{'markers'}->{'SOH'}.$command.chr($checksum).$data{'markers'}->{'EOT'}; |
129
|
0
|
0
|
|
|
|
|
print "Sending '$token': ".(printhex($message))."\n" if $data{'debug'}; |
130
|
0
|
|
|
|
|
|
$data{'port'}->write ($message); |
131
|
|
|
|
|
|
|
# Bad hack, we have to wait until the command is processed |
132
|
|
|
|
|
|
|
# Otherwise we will read only partial data |
133
|
0
|
|
|
|
|
|
sleep (0.03); |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
return 1; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Reads a response from the interface |
139
|
|
|
|
|
|
|
# This routine reads a message from the interface, decodes it and does all integrity checking |
140
|
|
|
|
|
|
|
# Params: bytes_expected The number of *message* bytes expected, -1 if not known |
141
|
|
|
|
|
|
|
# response A hash-reference which will be filled with the reponse |
142
|
|
|
|
|
|
|
# Return: 1 Always true |
143
|
|
|
|
|
|
|
# The filled in hash reference has the following keys: |
144
|
|
|
|
|
|
|
# {ok} 1 if the response has been valid and passed all checks, 0 upon failure |
145
|
|
|
|
|
|
|
# {raw} Actual data received from the interface |
146
|
|
|
|
|
|
|
# {message} The actual message, already decoded without any headers |
147
|
|
|
|
|
|
|
# {datalength} The lenght in bytes of the message |
148
|
|
|
|
|
|
|
# {checksum} The checksum of the message |
149
|
|
|
|
|
|
|
sub read_Response ($;$) { |
150
|
0
|
|
|
0
|
0
|
|
my $bytes_expected = shift; |
151
|
0
|
|
|
|
|
|
my $response = shift; |
152
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
|
print "Reading Response ... \n" if $data{'debug'}; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Read data |
156
|
|
|
|
|
|
|
# As we do not know how many bytes we expect (due to special char encoding) |
157
|
|
|
|
|
|
|
# we poll as long we receive any data in a reasonable interval -> again a bad hack |
158
|
0
|
|
|
|
|
|
$$response{'raw'}=''; |
159
|
0
|
|
|
|
|
|
while (my $received=$data{'port'}->read (100)) { |
160
|
0
|
|
|
|
|
|
$$response{'raw'}.=$received; |
161
|
0
|
|
|
|
|
|
sleep (0.01); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Did we receive a message with a least 5 bytes (shortest possible message) |
165
|
0
|
0
|
|
|
|
|
if (length($$response{'raw'})>=5) { |
166
|
0
|
|
|
|
|
|
$$response{'ok'} = 1; |
167
|
|
|
|
|
|
|
# First decode any message sequences for STX/ETX/ENQ |
168
|
0
|
|
|
|
|
|
$$response{'message'} = ''; |
169
|
0
|
|
|
|
|
|
for (my $x=1;$x<=length($$response{'raw'})-2;$x++) { |
170
|
0
|
|
|
|
|
|
my $char1 = substr($$response{'raw'},$x,1); |
171
|
0
|
|
|
|
|
|
my $char2 = substr($$response{'raw'},$x+1,1); |
172
|
0
|
0
|
|
|
|
|
if ($char1 eq $data{'markers'}->{'ENQ'}) { |
173
|
0
|
0
|
|
|
|
|
if ($char2 eq $data{'markers'}->{'DC2'}) { $char1 = $data{'markers'}->{'STX'} } |
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
elsif ($char2 eq $data{'markers'}->{'DC3'}) { $char1 = $data{'markers'}->{'ETX'} } |
175
|
0
|
|
|
|
|
|
elsif ($char2 eq $data{'markers'}->{'NAK'}) { $char1 = $data{'markers'}->{'ENQ'} } |
176
|
|
|
|
|
|
|
else { |
177
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
178
|
0
|
0
|
|
|
|
|
print "ERROR: Unknown encoding char ".(ord($char2))."\n" if $data{'debug'}; |
179
|
|
|
|
|
|
|
}; |
180
|
0
|
|
|
|
|
|
$x++; |
181
|
|
|
|
|
|
|
}; |
182
|
|
|
|
|
|
|
# WTF ? This isn't documented anywhere ? |
183
|
0
|
0
|
0
|
|
|
|
if (ord($char1)==0xff and ord($char2)==0xff) { |
184
|
0
|
|
|
|
|
|
$x++; |
185
|
|
|
|
|
|
|
} |
186
|
0
|
|
|
|
|
|
$$response{'message_all'}.= $char1; |
187
|
|
|
|
|
|
|
} |
188
|
0
|
|
|
|
|
|
$$response{'message'} = substr($$response{'message_all'},1,ord(substr($$response{'message_all'},0,1))); |
189
|
|
|
|
|
|
|
# Check if the received frame is consistent |
190
|
0
|
|
|
|
|
|
$$response{'datalength'} = ord(substr($$response{'message_all'},0,1)); |
191
|
0
|
|
|
|
|
|
$$response{'checksum'} = ord(substr($$response{'message_all'},length($$response{'message_all'})-1,1)); |
192
|
|
|
|
|
|
|
# Did we receive enough data |
193
|
0
|
0
|
0
|
|
|
|
if ($bytes_expected!=-1 and $$response{'datalength'}!=$bytes_expected and $$response{'ok'}) { |
|
|
|
0
|
|
|
|
|
194
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
195
|
0
|
0
|
|
|
|
|
print "ERROR: Expected datalength is not correct\n" if $data{'debug'}; |
196
|
|
|
|
|
|
|
}; |
197
|
|
|
|
|
|
|
# Are the start and end markers ok ? |
198
|
0
|
0
|
0
|
|
|
|
if (substr($$response{'raw'},0,1) ne $data{'markers'}->{'STX'} and $$response{'ok'}) { |
199
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
200
|
0
|
0
|
|
|
|
|
print "ERROR: Start marker not found\n" if $data{'debug'}; |
201
|
|
|
|
|
|
|
} |
202
|
0
|
0
|
0
|
|
|
|
if (substr($$response{'raw'},length($$response{'raw'})-1,1) ne $data{'markers'}->{'ETX'} and $$response{'ok'}) { |
203
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
204
|
0
|
0
|
|
|
|
|
print "ERROR: End marker not found\n" if $data{'debug'}; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
# Check for a error message from the interface |
207
|
0
|
0
|
0
|
|
|
|
if ($$response{'message'} eq $data{'markers'}->{'NAK'} and $$response{'datalength'}==1 and $$response{'ok'}) { |
|
|
|
0
|
|
|
|
|
208
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
209
|
0
|
0
|
|
|
|
|
print "ERROR: NAK received from interface\n" if $data{'debug'}; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
# Calculate and check checksum |
212
|
0
|
0
|
|
|
|
|
if ($$response{'ok'}) { |
213
|
0
|
|
|
|
|
|
my $calc_checksum=0; |
214
|
0
|
|
|
|
|
|
for (my $x=0;$x<$$response{'datalength'};$x++) { |
215
|
0
|
|
|
|
|
|
$calc_checksum+=ord(substr($$response{'message'},$x,1)); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
# Add first to bytes of raw message to checksum |
218
|
0
|
|
|
|
|
|
$calc_checksum+=ord($data{'markers'}->{'STX'}) + $$response{'datalength'} + $$response{'checksum'}; |
219
|
0
|
0
|
|
|
|
|
if (($calc_checksum & 0xFF)!= 0) { |
220
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
221
|
0
|
0
|
|
|
|
|
print "ERROR: Checksum not correct\n" if $data{'debug'}; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} else { |
225
|
0
|
|
|
|
|
|
$$response{'ok'} = 0; |
226
|
0
|
0
|
|
|
|
|
print "ERROR: Message received is too short\n" if $data{'debug'}; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
0
|
0
|
|
|
|
|
print "Response status is: $$response{'ok'}, Message: ".(printhex($$response{'raw'}))."\n" if $data{'debug'}; |
230
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
return 1; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Tries to initialize the interface |
235
|
|
|
|
|
|
|
# The interface must be sent an initialization request. The interface will go offline |
236
|
|
|
|
|
|
|
# after 71ms when no data is sent. |
237
|
|
|
|
|
|
|
# Timing is crucial, probably on slow systems this may fail. The initialization request |
238
|
|
|
|
|
|
|
# is sent up to 100 times, until a valid reponse is received. |
239
|
|
|
|
|
|
|
# Params: port The interface to use, e.g. /dev/ttyS0 |
240
|
|
|
|
|
|
|
# Return: 0|1 1 upon success, 0 upon failure |
241
|
|
|
|
|
|
|
sub init_Interface ($) { |
242
|
0
|
|
|
0
|
0
|
|
my $interface = shift; |
243
|
0
|
|
|
|
|
|
my ($port,$x); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# Setup interface with needed specs |
247
|
0
|
0
|
|
|
|
|
print "Opening port '$interface'\n" if $data{'debug'}; |
248
|
0
|
0
|
|
|
|
|
$port = new Device::SerialPort ($interface) or croak "Can't open interface '$interface'\n"; |
249
|
0
|
0
|
|
|
|
|
$port->baudrate (19200) or croak "Cannot set baudrate"; |
250
|
0
|
0
|
|
|
|
|
$port->parity ("even") or croak "Cannot set parity"; |
251
|
0
|
|
|
|
|
|
$port->parity_enable(1); |
252
|
0
|
0
|
|
|
|
|
$port->databits (8) or croak "Cannot set databits"; |
253
|
0
|
0
|
|
|
|
|
$port->stopbits (2) or croak "Cannot set stopbits"; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# Activate interface |
256
|
|
|
|
|
|
|
# Sequence taken from Rainer Krienke's ws2500 program |
257
|
0
|
0
|
|
|
|
|
print "Trying to activate interface\n" if $data{'debug'}; |
258
|
0
|
0
|
|
|
|
|
$port->dtr_active(0) or croak "Cannot set dtr_active off"; |
259
|
0
|
0
|
|
|
|
|
$port->rts_active(1) or croak "Cannot set rtr_active on"; |
260
|
0
|
|
|
|
|
|
sleep (0.09); |
261
|
0
|
0
|
|
|
|
|
$port->dtr_active(1) or croak "Cannot set dtr_active on"; |
262
|
0
|
0
|
|
|
|
|
$port->rts_active(0) or croak "Cannot set rts_active off"; |
263
|
0
|
|
|
|
|
|
sleep (0.02); |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# Save for global usage |
266
|
0
|
|
|
|
|
|
$data{'port'} = $port; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# Send activation data set |
269
|
|
|
|
|
|
|
# Repeat as often as needed until interface responses |
270
|
0
|
|
|
|
|
|
for ($x=0;$x<100;$x++) { |
271
|
0
|
|
|
|
|
|
my %response; |
272
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
send_Command ('ACTIVATE'); |
274
|
0
|
|
|
|
|
|
read_Response (1,\%response); |
275
|
|
|
|
|
|
|
|
276
|
0
|
0
|
0
|
|
|
|
last if $response{'ok'} and $response{'message'} eq $data{'markers'}->{'ACK'}; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
0
|
0
|
|
|
|
|
print "Status of interface initialization: ".($x!=100?'Success':'Failure')."\n" if $data{'debug'}; |
|
|
0
|
|
|
|
|
|
280
|
0
|
0
|
|
|
|
|
return 0 if $x == 100; |
281
|
0
|
|
|
|
|
|
return 1; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Closes the interface |
286
|
|
|
|
|
|
|
# Params: port The port which has been used, e.g. /dev/ttyS0 |
287
|
|
|
|
|
|
|
# Return: 1 Alway true |
288
|
|
|
|
|
|
|
sub close_Interface () { |
289
|
0
|
0
|
|
0
|
0
|
|
print "Closing interface\n" if $data{'debug'}; |
290
|
|
|
|
|
|
|
|
291
|
0
|
0
|
|
|
|
|
$data{'port'}->close() or croak "Cannot close interface"; |
292
|
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
return 1; |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# ******************************************************** |
299
|
|
|
|
|
|
|
# *** Main package routines |
300
|
|
|
|
|
|
|
# ******************************************************** |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Reads the received DCF from the interface |
303
|
|
|
|
|
|
|
# Params: ,[] |
304
|
|
|
|
|
|
|
# Device: The port the interface is connected to, e.g. /dev/ttyS0 |
305
|
|
|
|
|
|
|
# DCF-Handling: The interface signals if the internal received time |
306
|
|
|
|
|
|
|
# is available (in sync) or not. When DCF-Handling is |
307
|
|
|
|
|
|
|
# set to 1, the routine will return 0 upon DCF failure. |
308
|
|
|
|
|
|
|
# Optional paramater. When not set the signaled error |
309
|
|
|
|
|
|
|
# is ignorred. |
310
|
|
|
|
|
|
|
# Return: Unix-Timestamp representing the received time, 0 upon failure |
311
|
|
|
|
|
|
|
sub ws2500_GetTime ($;$) { |
312
|
0
|
|
|
0
|
0
|
|
my %response; |
313
|
0
|
|
|
|
|
|
my $dcf_handling=0; |
314
|
0
|
|
|
|
|
|
my $port = shift; |
315
|
0
|
0
|
|
|
|
|
$dcf_handling = shift if scalar @_; |
316
|
0
|
|
|
|
|
|
my ($hour,$minute,$second,$day,$month,$year,$dcfok); |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Send command |
319
|
0
|
0
|
|
|
|
|
print "Starting Request: Read DCF Clock\n" if $data{'debug'}; |
320
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Try ten times to read interface |
323
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
324
|
0
|
|
|
|
|
|
send_Command ('DCF'); |
325
|
0
|
|
|
|
|
|
read_Response (6,\%response); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Read data |
328
|
0
|
0
|
|
|
|
|
if ($response{'ok'}) { |
329
|
0
|
|
|
|
|
|
$hour = sprintf ("%x",ord(substr($response{'message'},0,1))); |
330
|
0
|
|
|
|
|
|
$minute = sprintf ("%x",ord(substr($response{'message'},1,1))); |
331
|
0
|
|
|
|
|
|
$second = ord(substr($response{'message'},2,1)); |
332
|
0
|
|
|
|
|
|
$day = sprintf ("%x",ord(substr($response{'message'},3,1))); |
333
|
|
|
|
|
|
|
# BCD, second nibble |
334
|
0
|
|
|
|
|
|
$month = ord(substr($response{'message'},4,1)) & 0xF; |
335
|
|
|
|
|
|
|
# Get bit 7 |
336
|
0
|
|
|
|
|
|
$dcfok = (ord(substr($response{'message'},4,1)) & 0x80) >> 7; |
337
|
0
|
0
|
0
|
|
|
|
return 0 if $dcf_handling and !$dcfok; |
338
|
|
|
|
|
|
|
# Offset +2000, bad hack, but who cares ;-) |
339
|
0
|
|
|
|
|
|
$year = sprintf ("%x",ord(substr($response{'message'},5,1)))+2000; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
0
|
0
|
|
|
|
|
last if $response{'ok'}; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# Finish |
346
|
0
|
|
|
|
|
|
close_Interface; |
347
|
0
|
0
|
|
|
|
|
return 0 unless $response{'ok'}; |
348
|
|
|
|
|
|
|
|
349
|
0
|
|
|
|
|
|
return timelocal ($second,$minute,$hour,$day,$month-1,$year); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# Reads the status of the interface |
353
|
|
|
|
|
|
|
# A detailed hash reference is returned, containing all status data received. |
354
|
|
|
|
|
|
|
# Params: port The interface to connect to, e.g. /dev/ttyS0 |
355
|
|
|
|
|
|
|
# result A hash reference which will be filled the status data. |
356
|
|
|
|
|
|
|
# For information about the hash structure see below |
357
|
|
|
|
|
|
|
# The filled in hash structure contains following data: |
358
|
|
|
|
|
|
|
# {sensors}->{} Status about all sensors. Name is 'temp1'...'temp8', |
359
|
|
|
|
|
|
|
# 'rain', 'wind', 'light' or 'inside' |
360
|
|
|
|
|
|
|
# {sensors}->{}->{status'} Either 'OK', or 'n/a' when this sensor does not exit |
361
|
|
|
|
|
|
|
# {sensors}->{}->{dropouts'} The Number of dropouts (not received sensor data) |
362
|
|
|
|
|
|
|
# {sensors}->{address} The address of the sensor |
363
|
|
|
|
|
|
|
# {interface}->{'interval'} The interval in minutes the interface records data |
364
|
|
|
|
|
|
|
# {interface}->{'language'} Language ('English' or 'German'), don't know what this means |
365
|
|
|
|
|
|
|
# {interface}->{'sync_dcf'} Boolean, contains whether the DCF-clock is in sync |
366
|
|
|
|
|
|
|
# {interface}->{'with_dcf'} Boolean, true if DCF is available |
367
|
|
|
|
|
|
|
# {interface}->{'protocol'} The uses protocol version for the sensors, either '1.1' or '1.2' |
368
|
|
|
|
|
|
|
# {interface}->{'type'} Interface type. Either 'PC_WS2500' or 'WS2500' |
369
|
|
|
|
|
|
|
# {interface}->{'version'} Hardware version of the interface (?) |
370
|
|
|
|
|
|
|
sub ws2500_GetStatus ($;$) { |
371
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
372
|
0
|
|
|
|
|
|
my $result = shift; |
373
|
0
|
|
|
|
|
|
my %response; |
374
|
|
|
|
|
|
|
my $time; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# Request the status data |
377
|
0
|
0
|
|
|
|
|
print "Starting Request: Read Status\n" if $data{'debug'}; |
378
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# Try ten times to read interface |
381
|
0
|
|
|
|
|
|
$$result{'valid'} = 0; |
382
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
383
|
0
|
|
|
|
|
|
send_Command ('STATUS'); |
384
|
0
|
|
|
|
|
|
read_Response (17,\%response); |
385
|
|
|
|
|
|
|
|
386
|
0
|
0
|
|
|
|
|
if ($response{'ok'}) { |
387
|
|
|
|
|
|
|
# Status of sensors |
388
|
0
|
|
|
|
|
|
my $count=0; |
389
|
0
|
|
|
|
|
|
foreach my $sensor (qw (temp1 temp2 temp3 temp4 temp5 temp6 temp7 temp8 rain wind light inside)) { |
390
|
0
|
|
|
|
|
|
my $status = ord(substr($response{'message'},$count,1)); |
391
|
0
|
|
|
|
|
|
my $dropouts=0; |
392
|
0
|
0
|
|
|
|
|
if ( $status<16) { $status='n/a'; } |
|
0
|
0
|
|
|
|
|
|
393
|
0
|
|
|
|
|
|
elsif ( $status==16) { $status='OK'; } |
394
|
0
|
|
|
|
|
|
else { $dropouts=$status+16; $status='OK'; } |
|
0
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
$$result{'sensors'}->{$sensor}->{'status'} = $status; |
396
|
0
|
|
|
|
|
|
$$result{'sensors'}->{$sensor}->{'dropouts'} = $dropouts; |
397
|
0
|
0
|
|
|
|
|
$$result{'sensors'}->{$sensor}->{'address'} = $1 if $sensor=~ /^temp(\d+)$/; |
398
|
0
|
|
|
|
|
|
$count++; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
# Some misc data |
401
|
0
|
|
|
|
|
|
$$result{'interface'}->{'interval'} = ord(substr($response{'message'},12,1)); |
402
|
0
|
0
|
|
|
|
|
$$result{'interface'}->{'language'} = (ord(substr($response{'message'},13,1)) & 0x1)?'English':'German'; |
403
|
0
|
0
|
|
|
|
|
$$result{'interface'}->{'sync_dcf'} = (ord(substr($response{'message'},13,1)) & 0x2)?1:0; |
404
|
0
|
0
|
|
|
|
|
$$result{'interface'}->{'with_dcf'} = (ord(substr($response{'message'},13,1)) & 0x4)?1:0; |
405
|
0
|
0
|
|
|
|
|
$$result{'interface'}->{'protocol'} = (ord(substr($response{'message'},13,1)) & 0x8)?'1.1':'1.2'; |
406
|
0
|
0
|
|
|
|
|
$$result{'interface'}->{'type'} = (ord(substr($response{'message'},13,1)) & 0x10)?'PC_WS2500':'WS2500'; |
407
|
0
|
|
|
|
|
|
$$result{'interface'}->{'version'} = int(sprintf("%x",ord(substr($response{'message'},14,1))))/10; |
408
|
|
|
|
|
|
|
# Some addresses |
409
|
0
|
|
|
|
|
|
$$result{'sensors'}->{'rain'}->{'address'} = ord(substr($response{'message'}, 15,1)) & 0x7; |
410
|
0
|
|
|
|
|
|
$$result{'sensors'}->{'wind'}->{'address'} = (ord(substr($response{'message'},15,1)) & 0x70) >> 4; |
411
|
0
|
|
|
|
|
|
$$result{'sensors'}->{'light'}->{'address'} = ord(substr($response{'message'}, 16,1)) & 0x7; |
412
|
0
|
|
|
|
|
|
$$result{'sensors'}->{'inside'}->{'address'} = (ord(substr($response{'message'},16,1)) & 0x70) >> 4; |
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
$$result{'valid'} = 1; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
0
|
0
|
|
|
|
|
last if $response{'ok'}; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# Finish |
421
|
0
|
|
|
|
|
|
close_Interface; |
422
|
0
|
0
|
|
|
|
|
return 0 unless $$result{'valid'}; |
423
|
0
|
|
|
|
|
|
return 1; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Request next dataset |
427
|
|
|
|
|
|
|
# Normally when a dataset is requested from the interface, the internal pointer |
428
|
|
|
|
|
|
|
# does not increase. Use this function to advance to the next dataset, if any. |
429
|
|
|
|
|
|
|
# Params: port The port to connect to, e.g. '/dev/ttyS0' |
430
|
|
|
|
|
|
|
# special When special is set to 'isopen' the interface will not be |
431
|
|
|
|
|
|
|
# opened and will not be closed, for bulk data retrieval |
432
|
|
|
|
|
|
|
# Return: 0/1/-1 0 Error during communication |
433
|
|
|
|
|
|
|
# 1 Success |
434
|
|
|
|
|
|
|
# -1 No next dataset available |
435
|
|
|
|
|
|
|
sub ws2500_NextDataset { |
436
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
437
|
0
|
|
|
|
|
|
my %response; |
438
|
0
|
|
|
|
|
|
my $valid = 0; |
439
|
0
|
|
|
|
|
|
my $special = ''; |
440
|
0
|
0
|
|
|
|
|
$special = shift if scalar @_; |
441
|
|
|
|
|
|
|
|
442
|
0
|
0
|
|
|
|
|
if ($special eq '') { |
443
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# Having a loop here is a bad thing |
447
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
448
|
0
|
|
|
|
|
|
send_Command ('NEXTSET'); |
449
|
0
|
|
|
|
|
|
read_Response (1,\%response); |
450
|
0
|
0
|
|
|
|
|
if ($response{'ok'}) { |
451
|
0
|
|
|
|
|
|
$valid=1; |
452
|
0
|
|
|
|
|
|
last; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
0
|
0
|
|
|
|
|
close_Interface if $special eq ''; |
456
|
|
|
|
|
|
|
|
457
|
0
|
0
|
|
|
|
|
return 0 unless $valid; |
458
|
0
|
0
|
|
|
|
|
return 0 unless $response{'ok'}; |
459
|
0
|
0
|
|
|
|
|
return 1 if $response{'message'} eq $data{'markers'}->{'ACK'}; |
460
|
0
|
0
|
|
|
|
|
return -1 if $response{'message'} eq $data{'markers'}->{'DLE'}; |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
# Weird ... we should never have reached this point |
463
|
0
|
|
|
|
|
|
return 0; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# Reset pointer to first dataset |
467
|
|
|
|
|
|
|
# Puts the dataset on the oldest record available. All data will be new. |
468
|
|
|
|
|
|
|
# Params: port The port to connect to, e.g. '/dev/ttyS0' |
469
|
|
|
|
|
|
|
# Return: 0/1 0 Error during communication |
470
|
|
|
|
|
|
|
# 1 Success |
471
|
|
|
|
|
|
|
sub ws2500_FirstDataset ($) { |
472
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
473
|
0
|
|
|
|
|
|
my %response; |
474
|
0
|
|
|
|
|
|
my $valid = 0; |
475
|
|
|
|
|
|
|
|
476
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
477
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
478
|
0
|
|
|
|
|
|
send_Command ('FIRSTSET'); |
479
|
0
|
|
|
|
|
|
read_Response (1,\%response); |
480
|
0
|
0
|
0
|
|
|
|
if ($response{'ok'} and $response{'message'} eq $data{'markers'}->{'ACK'}) { |
481
|
0
|
|
|
|
|
|
$valid=1; |
482
|
0
|
|
|
|
|
|
last; |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
} |
485
|
0
|
|
|
|
|
|
close_Interface; |
486
|
|
|
|
|
|
|
|
487
|
0
|
0
|
|
|
|
|
return 1 if $valid; |
488
|
0
|
|
|
|
|
|
return 0; |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
# Read a dataset from the interface |
492
|
|
|
|
|
|
|
# This function reads the current dataset, to which the internal pointer is set. |
493
|
|
|
|
|
|
|
# Params: The device to read from, e.g. /dev/ttyS0 |
494
|
|
|
|
|
|
|
# A hash reference where the dataset will be stored in. |
495
|
|
|
|
|
|
|
# See below for hash structure |
496
|
|
|
|
|
|
|
# The can be either 'current' or 'next': |
497
|
|
|
|
|
|
|
# 'current': Get the current dataset, but do not increase to |
498
|
|
|
|
|
|
|
# next pointer |
499
|
|
|
|
|
|
|
# 'next' : Get the current dataset. After the has been successfully |
500
|
|
|
|
|
|
|
# read, advance the internal pointer to the next dataset |
501
|
|
|
|
|
|
|
# Return: 1 Communication successfull (This does not mean that a dataset has been read) |
502
|
|
|
|
|
|
|
# 0 Cummunication error, the hash-reference does not contain any valid data |
503
|
|
|
|
|
|
|
# |
504
|
|
|
|
|
|
|
# The hash-reference has the following structure: |
505
|
|
|
|
|
|
|
# {valid} This hash contains valid data, when set to 1 |
506
|
|
|
|
|
|
|
# {interface}->{timestamp} The current DCF-time |
507
|
|
|
|
|
|
|
# {interface} See status hash returned by ws2500_GetStatus |
508
|
|
|
|
|
|
|
# {sensors} See status hash returned by ws2500_GetStatus |
509
|
|
|
|
|
|
|
# {dataset}->{status} Either 'dataset' for a valid dataset, or 'nonew' when no dataset is available |
510
|
|
|
|
|
|
|
# {dataset}->{block} Block number of dataset |
511
|
|
|
|
|
|
|
# {dataset}->{timestamp} Timestamp of dataset |
512
|
|
|
|
|
|
|
# {dataset}->{tempX} Temperature sensors, X is 1 to 8 |
513
|
|
|
|
|
|
|
# {dataset}->{tempX}->{'status'} 1 if this sensor contains valid data, 'n/a' when not available |
514
|
|
|
|
|
|
|
# {dataset}->{tempX}->{'new'} New flag is set |
515
|
|
|
|
|
|
|
# {dataset}->{tempX}->{'temperature'} Temperature in Celcius |
516
|
|
|
|
|
|
|
# {dataset}->{tempX}->{'humidity'} Humidity in %, 'n/a' if this sensor is missing |
517
|
|
|
|
|
|
|
# {dataset}->{wind}->{'status'} 1 if this sensor contains valid data, 'n/a' when not available |
518
|
|
|
|
|
|
|
# {dataset}->{wind}->{'new'} The new flag is set |
519
|
|
|
|
|
|
|
# {dataset}->{wind}->{'speed'} Wind speed in km/h |
520
|
|
|
|
|
|
|
# {dataset}->{wind}->{'direction'} Direction in degree |
521
|
|
|
|
|
|
|
# {dataset}->{wind}->{'accuracy'} Average devivation for direction in degree |
522
|
|
|
|
|
|
|
# {dataset}->{inside}->{'status'} 1 if this sensor contains valid data, 'n/a' when not available |
523
|
|
|
|
|
|
|
# {dataset}->{inside}->{'new'} New flag is set |
524
|
|
|
|
|
|
|
# {dataset}->{inside}->{'temperature'} Temperature in Celcius |
525
|
|
|
|
|
|
|
# {dataset}->{inside}->{'humidity'} Humidity in %, 'n/a' if this sensor is missing |
526
|
|
|
|
|
|
|
# {dataset}->{inside}->{'pressure'} Pressure in hPa |
527
|
|
|
|
|
|
|
# {dataset}->{rain}->{'status'} 1 if this sensor contains valid data, 'n/a' when not available |
528
|
|
|
|
|
|
|
# {dataset}->{rain}->{'new'} New flag is set |
529
|
|
|
|
|
|
|
# {dataset}->{rain}->{'counter_ml'} Current counter |
530
|
|
|
|
|
|
|
# {dataset}->{rain}->{'counter_ml'} Current rain counter in ml, delta to previous call is the rainfall |
531
|
|
|
|
|
|
|
# {dataset}->{light}->{'status'} 1 if this sensor contains valid data, 'n/a' when not available |
532
|
|
|
|
|
|
|
# {dataset}->{light}->{'new'} New flag is set |
533
|
|
|
|
|
|
|
# {dataset}->{light}->{'duration'} Counter in minutes with brightness > 20.000 Lux |
534
|
|
|
|
|
|
|
# {dataset}->{light}->{'brightness'} Sun brightness in Lux |
535
|
|
|
|
|
|
|
# {dataset}->{light}->{'sunflag'} Sunflag is set, undocumented |
536
|
|
|
|
|
|
|
sub ws2500_GetDataset { |
537
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
538
|
0
|
|
|
|
|
|
my $result = shift; |
539
|
0
|
|
|
|
|
|
my $type = shift; |
540
|
0
|
|
|
|
|
|
my %response; |
541
|
0
|
|
|
|
|
|
my $doinit = ''; |
542
|
0
|
0
|
|
|
|
|
$doinit = shift if scalar @_; |
543
|
|
|
|
|
|
|
|
544
|
0
|
0
|
|
|
|
|
print "Starting Request: Read Dataset\n" if $data{'debug'}; |
545
|
|
|
|
|
|
|
|
546
|
0
|
0
|
0
|
|
|
|
if ($doinit eq '' or $doinit eq 'noclose') { |
547
|
|
|
|
|
|
|
# First get the time for reference |
548
|
0
|
|
|
|
|
|
$$result{'interface'}->{'timestamp'} = ws2500_GetTime ($port); |
549
|
0
|
0
|
|
|
|
|
return 0 if $$result{'interface'}->{'timestamp'}<=0; |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# Now the status, so we know which sensor is active |
552
|
0
|
0
|
|
|
|
|
return 0 unless ws2500_GetStatus ($port,$result); |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
# Start up the interface to get the data |
555
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
# Try several times to read interface, until we get a valid response |
559
|
0
|
|
|
|
|
|
$$result{'valid'}=0; |
560
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
561
|
0
|
|
|
|
|
|
send_Command ('GETSET'); |
562
|
0
|
|
|
|
|
|
read_Response (-1,\%response); |
563
|
|
|
|
|
|
|
|
564
|
0
|
0
|
|
|
|
|
if ($response{'ok'}) { |
565
|
0
|
0
|
|
|
|
|
unless ($response{'message'} eq $data{'markers'}->{'DLE'}) { |
566
|
|
|
|
|
|
|
# New dataset available |
567
|
|
|
|
|
|
|
# Prepare the message so we can access it more easy |
568
|
0
|
|
|
|
|
|
my @data = (split //, $response{'message'}); |
569
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'block'} = ord($data[0]) + ord($data[1])*0x100; |
570
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'timestamp'} = $$result{'interface'}->{'timestamp'}- |
571
|
|
|
|
|
|
|
((ord($data[2])+ord($data[3])*0x100)*60); |
572
|
|
|
|
|
|
|
# We only have the age in minutes, so cut down to zero seconds |
573
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'timestamp'} = int($$result{'dataset'}->{'timestamp'}/60)*60; |
574
|
0
|
|
|
|
|
|
my $nibble=0; |
575
|
0
|
|
|
|
|
|
foreach my $sensor (qw (temp1 temp2 temp3 temp4 temp5 temp6 temp7 temp8)) { |
576
|
0
|
|
|
|
|
|
my %temp; |
577
|
0
|
0
|
|
|
|
|
if ($$result{'sensors'}->{$sensor}->{'status'} ne 'n/a') { |
578
|
0
|
|
|
|
|
|
my $sign = +1; |
579
|
0
|
|
|
|
|
|
for (my $y=0;$y<5;$y++) { |
580
|
0
|
0
|
|
|
|
|
if ($nibble % 2) { $temp{$y}=(ord($data[int($nibble/2)+4]) & 0xF0) >> 4; } |
|
0
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
|
else { $temp{$y}=ord($data[int($nibble/2)+4]) & 0xF; } |
582
|
0
|
|
|
|
|
|
$nibble++; |
583
|
|
|
|
|
|
|
} # for |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# First the temperature |
586
|
|
|
|
|
|
|
# Test for plus/minus |
587
|
0
|
0
|
|
|
|
|
$sign=-1 if $temp{'2'} & 0x8; |
588
|
|
|
|
|
|
|
# Mask the sign bit |
589
|
0
|
|
|
|
|
|
$temp{'2'}=$temp{'2'} & 0x7; |
590
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'temperature'} = ($temp{'0'}/10 + $temp{'1'} + $temp{2}*10)*$sign; |
591
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'status'} = 'ok'; |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Now the humidity |
594
|
|
|
|
|
|
|
# Is the new flag set |
595
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'new'} = ($temp{'4'} & 0x8) >> 3; |
596
|
|
|
|
|
|
|
# Mask the new flag |
597
|
0
|
|
|
|
|
|
$temp{'4'}=$temp{'4'} & 0x7; |
598
|
0
|
0
|
|
|
|
|
if ($temp{'3'}<=9) { |
599
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'humidity'} = ($temp{'3'} + $temp{'4'}*10)+20; |
600
|
|
|
|
|
|
|
} else { |
601
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'humidity'} = 'n/a'; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
} else { |
604
|
|
|
|
|
|
|
# This sensor is not available |
605
|
0
|
|
|
|
|
|
$$result{'dataset'}->{$sensor}->{'status'} = 'n/a'; |
606
|
0
|
|
|
|
|
|
$nibble+=5; |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
} # foreach temperature |
611
|
|
|
|
|
|
|
|
612
|
0
|
|
|
|
|
|
my $of=3; |
613
|
|
|
|
|
|
|
# Wind direction |
614
|
0
|
0
|
|
|
|
|
if ($$result{'sensors'}->{'wind'}->{'status'} ne 'n/a') { |
615
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'speed'} = ((ord($data[$of+21]) & 0xF)/10)+ |
616
|
|
|
|
|
|
|
((ord($data[$of+21]) & 0xF0) >> 4)+ |
617
|
|
|
|
|
|
|
((ord($data[$of+22]) & 0xF)*10); |
618
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'direction'} = (((ord($data[$of+22]) & 0xF0) >> 4)*10)+ |
619
|
|
|
|
|
|
|
((ord($data[$of+23]) & 0x3)*100); |
620
|
0
|
0
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'direction'}+=5 if ord($data[$of+23]) & 0x10; |
621
|
0
|
|
|
|
|
|
my $accuracy = (ord($data[$of+23]) & 0xC) >> 2; |
622
|
0
|
0
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'accuracy'}=0 if $accuracy==0; |
623
|
0
|
0
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'accuracy'}=22.5 if $accuracy==1; |
624
|
0
|
0
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'accuracy'}=45 if $accuracy==2; |
625
|
0
|
0
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'accuracy'}=67.5 if $accuracy==3; |
626
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'new'} = (ord($data[$of+23]) & 0x8) >> 3; |
627
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'status'} = 'ok'; |
628
|
|
|
|
|
|
|
} else { |
629
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'wind'}->{'status'} = 'n/a'; |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# Inside sensor |
633
|
0
|
0
|
|
|
|
|
if ($$result{'sensors'}->{'inside'}->{'status'} ne 'n/a') { |
634
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'pressure'} = (ord($data[$of+24]) & 0xF)+ |
635
|
|
|
|
|
|
|
(((ord($data[$of+24]) & 0xF0)>>4)*10)+ |
636
|
|
|
|
|
|
|
((ord($data[$of+25]) & 0xF)*100); |
637
|
0
|
|
|
|
|
|
my $sign=1; |
638
|
0
|
0
|
|
|
|
|
$sign=-1 if ord($data[$of+26]) & 0x80; |
639
|
0
|
|
|
|
|
|
$data[$of+26]=chr(ord($data[$of+26]) & 0x7F); |
640
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'temperature'} = ((((ord($data[$of+25]) & 0xF0)>>4)/10)+ |
641
|
|
|
|
|
|
|
(ord($data[$of+26]) & 0xF)+ |
642
|
|
|
|
|
|
|
(((ord($data[$of+26]) & 0xF0)>>4)*10))*$sign; |
643
|
0
|
0
|
|
|
|
|
if ((ord($data[$of+27]) & 0xF)<=9) { |
644
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'humidity'} = (ord($data[$of+27]) & 0xF)+ |
645
|
|
|
|
|
|
|
(((ord($data[$of+27]) & 0x70)>>4)*10)+ |
646
|
|
|
|
|
|
|
20; |
647
|
|
|
|
|
|
|
} else { |
648
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'humidity'} = 'n/a'; |
649
|
|
|
|
|
|
|
} |
650
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'new'} = (ord($data[$of+27]) & 0x80) >> 7; |
651
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'status'} = 'ok'; |
652
|
|
|
|
|
|
|
} else { |
653
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'inside'}->{'status'} = 'n/a'; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# Rain sensor |
657
|
0
|
0
|
|
|
|
|
if ($$result{'sensors'}->{'rain'}->{'status'} ne 'n/a') { |
658
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'rain'}->{'counter'} = ord($data[$of+28])+ |
659
|
|
|
|
|
|
|
(ord($data[$of+29]) & 0x7)*0x100; |
660
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'rain'}->{'counter_ml'} = $$result{'dataset'}->{'rain'}->{'counter'}*370; |
661
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'rain'}->{'status'} = 'ok'; |
662
|
|
|
|
|
|
|
} else { |
663
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'rain'}->{'status'} = 'n/a'; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
# Light sensor |
667
|
0
|
0
|
|
|
|
|
if ($$result{'sensors'}->{'light'}->{'status'} ne 'n/a') { |
668
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'duration'} = ((ord($data[$of+29]) & 0xF0)>>4)+ |
669
|
|
|
|
|
|
|
((ord($data[$of+30]) & 0xF)*0x10)+ |
670
|
|
|
|
|
|
|
(((ord($data[$of+30]) & 0xF0)>>4)*0x100); |
671
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'brightness'} = ((ord($data[$of+31]) & 0xF)+ |
672
|
|
|
|
|
|
|
(((ord($data[$of+31]) & 0xF0)>>4)*10)+ |
673
|
|
|
|
|
|
|
((ord($data[$of+32]) & 0xF)*100))* |
674
|
|
|
|
|
|
|
(10**((ord($data[$of+32]) & 0x30)>>4)); |
675
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'sun_flag'} = (ord($data[$of+32]) & 0x40) >> 6; |
676
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'new'} = (ord($data[$of+32]) & 0x80) >> 7; |
677
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'status'} = 'ok'; |
678
|
|
|
|
|
|
|
} else { |
679
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'light'}->{'status'} = 'n/a'; |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'status'} = 'dataset'; |
683
|
|
|
|
|
|
|
} else { |
684
|
|
|
|
|
|
|
# No new dataset available |
685
|
0
|
|
|
|
|
|
$$result{'dataset'}->{'status'} = 'nonew'; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
0
|
|
|
|
|
|
$$result{'valid'} = 1; |
689
|
|
|
|
|
|
|
} |
690
|
0
|
0
|
|
|
|
|
last if $$result{'valid'}; |
691
|
|
|
|
|
|
|
} |
692
|
0
|
0
|
|
|
|
|
close_Interface if $doinit eq ''; |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
# Upon request advance to next dataset |
695
|
0
|
0
|
0
|
|
|
|
if ($type eq 'next' and $$result{'valid'} and $$result{'dataset'}->{'status'} eq 'dataset') { |
|
|
|
0
|
|
|
|
|
696
|
0
|
0
|
|
|
|
|
if ($doinit eq '') { |
697
|
0
|
|
|
|
|
|
ws2500_NextDataset ($port); |
698
|
|
|
|
|
|
|
} else { |
699
|
0
|
|
|
|
|
|
ws2500_NextDataset ($port,'isopen'); |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
# Finish |
704
|
0
|
0
|
|
|
|
|
return 0 unless $$result{'valid'}; |
705
|
0
|
|
|
|
|
|
return 1; |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
# Get bulk dataset data |
709
|
|
|
|
|
|
|
# Whereas the normal Getdataset function initializes and closes the interface for each |
710
|
|
|
|
|
|
|
# dataset, this function opens the communication only once, and serveral dataset are |
711
|
|
|
|
|
|
|
# then transferred in a batch. This greatly improves the performance |
712
|
|
|
|
|
|
|
# Params: port The port to use, e.g. '/dev/ttyS0' |
713
|
|
|
|
|
|
|
# result The result hash reference, see below |
714
|
|
|
|
|
|
|
# bulkcount The number of datasets to retrieve in one run |
715
|
|
|
|
|
|
|
# Return: 1 Always true |
716
|
|
|
|
|
|
|
# The result hash has the following structure: |
717
|
|
|
|
|
|
|
# {valid} If this bulkdata is valid |
718
|
|
|
|
|
|
|
# {bulkcount} The actual number of retrieved datasets |
719
|
|
|
|
|
|
|
# {bulk} An array. Each element contains a dataset hash reference |
720
|
|
|
|
|
|
|
# See the ws2500_GetDataset function for the structure |
721
|
|
|
|
|
|
|
# {interface} See ws2500_GetDataset function |
722
|
|
|
|
|
|
|
# {sensors} See ws2500_GetDataset function |
723
|
|
|
|
|
|
|
sub ws2500_GetDatasetBulk ($;$;$) { |
724
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
725
|
0
|
|
|
|
|
|
my $result = shift; |
726
|
0
|
|
|
|
|
|
my $bulkcount = shift; |
727
|
0
|
|
|
|
|
|
my @bulkdata; |
728
|
|
|
|
|
|
|
my %firstdataset; |
729
|
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
for (my $x=0;$x<$bulkcount;$x++) { |
731
|
0
|
0
|
|
|
|
|
if ($x==0) { |
732
|
|
|
|
|
|
|
# Request first dataset |
733
|
|
|
|
|
|
|
# As we supply the 'noclose' param the connection to the interface stays |
734
|
|
|
|
|
|
|
# open an we can request additional datasets without reestablishing the connection |
735
|
0
|
|
|
|
|
|
my $res = ws2500_GetDataset ($port,\%firstdataset,'next','noclose'); |
736
|
|
|
|
|
|
|
# Check for errors |
737
|
0
|
0
|
0
|
|
|
|
if ($res and $firstdataset{'valid'} and $firstdataset{'dataset'}->{'status'} eq 'dataset') { |
|
|
|
0
|
|
|
|
|
738
|
0
|
|
|
|
|
|
push @bulkdata, $firstdataset{'dataset'}; |
739
|
|
|
|
|
|
|
} else { |
740
|
0
|
|
|
|
|
|
last; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
} else { |
743
|
|
|
|
|
|
|
# Further datasets, use the firstdataset as base |
744
|
0
|
|
|
|
|
|
my %result = %firstdataset; |
745
|
0
|
|
|
|
|
|
delete $result{'dataset'}; |
746
|
0
|
|
|
|
|
|
my $res = ws2500_GetDataset ($port,\%result,'next','noinit'); |
747
|
|
|
|
|
|
|
# Check for errors |
748
|
0
|
0
|
0
|
|
|
|
if ($res and $result{'valid'} and $result{'dataset'}->{'status'} eq 'dataset') { |
|
|
|
0
|
|
|
|
|
749
|
0
|
|
|
|
|
|
push @bulkdata, $result{'dataset'}; |
750
|
|
|
|
|
|
|
} else { |
751
|
0
|
|
|
|
|
|
$firstdataset{'valid'} = $result{'valid'}; |
752
|
0
|
|
|
|
|
|
last; |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
# Prepare the result |
757
|
0
|
|
|
|
|
|
$$result{'valid'} = $firstdataset{'valid'}; |
758
|
0
|
|
|
|
|
|
$$result{'interface'} = $firstdataset{'interface'}; |
759
|
0
|
|
|
|
|
|
$$result{'sensors'} = $firstdataset{'sensors'}; |
760
|
|
|
|
|
|
|
# Save the bulkdata |
761
|
0
|
|
|
|
|
|
$$result{'bulk'} = \@bulkdata; |
762
|
0
|
|
|
|
|
|
$$result{'bulkcount'} = scalar @bulkdata; |
763
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
close_Interface; |
765
|
|
|
|
|
|
|
|
766
|
0
|
|
|
|
|
|
return 1; |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
# Test Interface |
771
|
|
|
|
|
|
|
# This function does not work and is not properly documented. See inline comments below |
772
|
|
|
|
|
|
|
# Params: port The port to use, e.g. /dev/ttyS0 |
773
|
|
|
|
|
|
|
# Return: 0 Always false, as it does not work |
774
|
|
|
|
|
|
|
sub ws2500_InterfaceTest ($) { |
775
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
776
|
0
|
|
|
|
|
|
my %response; |
777
|
0
|
|
|
|
|
|
my $valid = 0; |
778
|
|
|
|
|
|
|
|
779
|
0
|
|
|
|
|
|
return 0; |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
# This doesn't seem to work. Acoording to the docu we have to send either |
782
|
|
|
|
|
|
|
# 'C' or 'CTST'. However both variants fail, and there is either no data |
783
|
|
|
|
|
|
|
# received at all, or gibberish. Furthermore the interface is not reset. |
784
|
|
|
|
|
|
|
# If anyone has a clear documentation how to activate this (and what to |
785
|
|
|
|
|
|
|
# to with it), please send them. |
786
|
|
|
|
|
|
|
# return 0 unless init_Interface ($port); |
787
|
|
|
|
|
|
|
# for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
788
|
|
|
|
|
|
|
# send_Command ('INTERFACETEST'); |
789
|
|
|
|
|
|
|
# sleep (0.04); |
790
|
|
|
|
|
|
|
# read_Response (1,\%response); |
791
|
|
|
|
|
|
|
# if ($response{'ok'} and $response{'message'} eq $data{'markers'}->{'ACK'}) { |
792
|
|
|
|
|
|
|
# $valid=1; |
793
|
|
|
|
|
|
|
# last; |
794
|
|
|
|
|
|
|
# } |
795
|
|
|
|
|
|
|
# } |
796
|
|
|
|
|
|
|
# close_Interface; |
797
|
|
|
|
|
|
|
# |
798
|
|
|
|
|
|
|
# return 1 if $valid; |
799
|
|
|
|
|
|
|
# return 0; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
# Initialize the interface we new data |
803
|
|
|
|
|
|
|
# Params: port The port to sent the data, e.g. /dev/ttyS0 |
804
|
|
|
|
|
|
|
# data A hash-reference containing the configuration, see below |
805
|
|
|
|
|
|
|
# Return: 0|1 True upon success, else False |
806
|
|
|
|
|
|
|
# The configuration-hash must contain following keys: |
807
|
|
|
|
|
|
|
# {first} Minutes to wait after init to resume normal operation, 0..63 minutes |
808
|
|
|
|
|
|
|
# {interval} The interval in minutes to record data, 2..63 minutes |
809
|
|
|
|
|
|
|
# {addr-rain} The address of the rain sensor, 0..7 |
810
|
|
|
|
|
|
|
# {addr-wind} The address of the wind sensor, 0..7 |
811
|
|
|
|
|
|
|
# {addr-inside} The address of the inside sensor, 0..7 |
812
|
|
|
|
|
|
|
# {addr-light} The address of the light sensor, 0..7 |
813
|
|
|
|
|
|
|
# {version} The protocal version to use: 1 (V1.1) or 2 (V1.2) |
814
|
|
|
|
|
|
|
sub ws2500_InterfaceInit ($;$) { |
815
|
0
|
|
|
0
|
0
|
|
my $port = shift; |
816
|
0
|
|
|
|
|
|
my $data = shift; |
817
|
0
|
|
|
|
|
|
my %response; |
818
|
0
|
|
|
|
|
|
my $valid = 0; |
819
|
0
|
|
|
|
|
|
my $message; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
# {'first'=>12,'interval'=>3,'addr-rain'=>7,'addr-wind'=>7,'addr-inside'=>7,'addr-ligth'=>7,'version'}); |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# Prepare the message (4 Bytes) |
824
|
|
|
|
|
|
|
# First some checks if the data is correct |
825
|
0
|
|
|
|
|
|
foreach my $token (qw (first interval addr-rain addr-wind addr-inside addr-light version)) { |
826
|
0
|
0
|
|
|
|
|
croak "Token '$token' missing in configuration hash" unless exists $$data{$token}; |
827
|
0
|
0
|
|
|
|
|
croak "Token '$token' is not a number ('$$data{'$token'}') " unless $$data{$token}=~ /^\d+$/; |
828
|
|
|
|
|
|
|
} |
829
|
|
|
|
|
|
|
# Some sanity checks |
830
|
0
|
0
|
0
|
|
|
|
croak "First interval 'first' must be between 0 and 63" if $$data{'first'}<0 or $$data{'first'}>63; |
831
|
0
|
0
|
0
|
|
|
|
croak "Recording interval 'interval' must be between 2 and 63" if $$data{'interval'}<2 or $$data{'interval'}>63; |
832
|
0
|
|
|
|
|
|
foreach my $token (qw (addr-rain addr-wind addr-inside addr-light)) { |
833
|
0
|
0
|
0
|
|
|
|
croak "Sensor address for '$token' must be between 0 and 7" if $$data{$token}<0 or $$data{$token}>7; |
834
|
|
|
|
|
|
|
} |
835
|
0
|
0
|
0
|
|
|
|
croak "Version must be either 1 (V1.1) or 2 (V1.2)" if $$data{'version'}<1 or $$data{'version'}>2; |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Put everything together |
838
|
0
|
|
|
|
|
|
my $addr1 = $$data{'addr-rain'} + ($$data{'addr-wind'} << 4) + 0x80; |
839
|
0
|
0
|
|
|
|
|
$addr1|=0x8 if $$data{'version'}==1; |
840
|
0
|
|
|
|
|
|
my $addr2 = $$data{'addr-light'} + ($$data{'addr-inside'} << 4) + 0x80; |
841
|
|
|
|
|
|
|
# Now build the message |
842
|
0
|
|
|
|
|
|
$message = chr($$data{'first'}).chr($$data{'interval'}).chr($addr1).chr($addr2); |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
# Send the command |
845
|
0
|
0
|
|
|
|
|
return 0 unless init_Interface ($port); |
846
|
0
|
|
|
|
|
|
for (my $x=0;$x<$data{'maxrepeat'};$x++) { |
847
|
0
|
|
|
|
|
|
send_Command ('INTERFACEINIT',$message); |
848
|
0
|
|
|
|
|
|
read_Response (1,\%response); |
849
|
0
|
0
|
0
|
|
|
|
if ($response{'ok'} and $response{'message'} eq $data{'markers'}->{'ACK'}) { |
850
|
0
|
|
|
|
|
|
$valid=1; |
851
|
0
|
|
|
|
|
|
last; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
} |
854
|
0
|
|
|
|
|
|
close_Interface; |
855
|
|
|
|
|
|
|
|
856
|
0
|
0
|
|
|
|
|
return 1 if $valid; |
857
|
0
|
|
|
|
|
|
return 0; |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
# Enables debug |
861
|
|
|
|
|
|
|
# When debug is enabled, a lot of information is printed to STDOUT |
862
|
|
|
|
|
|
|
# Params: debug 1 to enable debug, 0 to disable (default) |
863
|
|
|
|
|
|
|
# Return: 1 Always true |
864
|
|
|
|
|
|
|
sub ws2500_SetDebug ($) { |
865
|
0
|
|
|
0
|
0
|
|
my $debug = shift; |
866
|
|
|
|
|
|
|
|
867
|
0
|
0
|
0
|
|
|
|
croak "Debug must be called with 0 or 1 as argument" if $debug>1 or $debug<0; |
868
|
|
|
|
|
|
|
|
869
|
0
|
|
|
|
|
|
$data{'debug'} = $debug; |
870
|
|
|
|
|
|
|
|
871
|
0
|
|
|
|
|
|
return 1; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
1; |
877
|
|
|
|
|
|
|
|