~ubuntu-branches/debian/jessie/digitemp/jessie

« back to all changes in this revision

Viewing changes to src/digitemp.c

  • Committer: Bazaar Package Importer
  • Author(s): Jesus Roncero
  • Date: 2004-09-01 01:34:37 UTC
  • Revision ID: james.westby@ubuntu.com-20040901013437-eicsrrd40dr371u0
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -----------------------------------------------------------------------
 
2
   DigiTemp
 
3
      
 
4
   Copyright 1996-2004 by Brian C. Lane <bcl@brianlane.com>
 
5
   All Rights Reserved
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify it
 
8
   under the terms of the GNU General Public License as published by the Free
 
9
   Software Foundation; either version 2 of the License, or (at your option)
 
10
   any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful, but WITHOUT
 
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
15
   more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License along
 
18
   with this program; if not, write to the Free Software Foundation, Inc.,
 
19
   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 
20
   
 
21
     digitemp -w                        Walk the LAN & show all
 
22
     digitemp -i                        Initalize .digitemprc file
 
23
     digitemp -s/dev/ttyS0              Set serial port (required)
 
24
     digitemp -cdigitemp.conf           Configuration File
 
25
     digitemp -r1000                    Set Read timeout to 1000mS
 
26
     digitemp -l/var/log/temperature    Send output to logfile
 
27
     digitemp -v                        Verbose mode
 
28
     digitemp -t0                       Read Temperature
 
29
     digitemp -q                        Quiet, no copyright banner
 
30
     digitemp -a                        Read all Temperatures
 
31
     digitemp -d5                       Delay between samples (in sec.)
 
32
     digitemp -n50                      Number of times to repeat. 0=forever
 
33
     digitemp -A                        Treat DS2438 as A/D converter
 
34
     digitemp -o1                       Output format for logfile
 
35
                                        See description below
 
36
     digitemp -o"output format string"  See description below
 
37
     digitemp -O"counter format"        See description below
 
38
     digitemp -H"Humidity format"       See description below
 
39
 
 
40
     Logfile formats:
 
41
     1 = (default) - 1 line per sensor, time, C, F
 
42
         1 line for each sample, elapsed time, sensor #1, #2, ... tab seperated
 
43
     2 = Reading in C
 
44
     3 = Reading in F
 
45
 
 
46
     The format string uses strftime tokens plus 6 special
 
47
     ones for digitemp - %s for sensor #, %C for centigrade,
 
48
     %F for fahrenheit, %R for hex serial number, %N for seconds since Epoch
 
49
 
 
50
     Humidity uses %h for the relative humidity in percent
 
51
 
 
52
     The counter format uses %n for the counter # and %C for the count 
 
53
     in decimal
 
54
 
 
55
     Remember the case of the token is important!
 
56
 
 
57
   =======================================================================
 
58
   01/25/2004   A user reported a bug in the humidity temperature, it
 
59
   bcl          wasn't converting negative temperatures correctly.
 
60
                I also see a potential problem with the DS18B20 and DS1822
 
61
                which use a short int type and depend on it being 16 bits
 
62
                so that the sign comes out correct. But can we count on a
 
63
                short int always being 16 bits? I need to look into it.
 
64
 
 
65
   01/10/2003   Finally, humidity is working, thanks in large part to work
 
66
   bcl          by Eric Wilde. Need to add logging of DS2438. I think it
 
67
                will be hard-coded, if it needs to be in another format
 
68
                it can be parsed with perl or python or whatever.
 
69
                Fixed a bug that wasn't allowing %% to be embedded in the
 
70
                format specifier.
 
71
 
 
72
                Adding lockfile support using the lockdev library under
 
73
                Linux. Wrapping it in LINUX checks until other systems
 
74
                indicate that they can use it.
 
75
 
 
76
                Lockfiles are working, but - the binary has to be sgid to
 
77
                the lock group so that it can access /var/lock, adding
 
78
                the user to the lock group would also accomplish this.
 
79
 
 
80
   01/08/2003   Still trying to get DS2438 and Humidity support working
 
81
   bcl          Also changing strcpy to strncpy, dunno why they weren't
 
82
                already using it.
 
83
 
 
84
   01/04/2003   Adding DS2438 based humidity support from Eric Wilde.
 
85
   bcl
 
86
 
 
87
   11/29/2003   Trying to get a first pass at DS2438 (A/D & Battery monitor)
 
88
   bcl          support up and running.
 
89
                Found a bug, init wouldn't record counters found on branches
 
90
                of a hub.
 
91
 
 
92
   10/27/2003   Added patch from Sven Geggus to allow -n0 to make it run
 
93
   bcl          in an infinite loop. Need to check for exit conditions
 
94
                and clean up logfile, serial port, etc. in a nice manner.
 
95
 
 
96
   08/13/2003   Adding DS2490 USB to 1-wire adapter support. Bumping the
 
97
   bcl          version number to 3.3.0 without a release of 3.2.1
 
98
 
 
99
   06/14/2003   Made change to hub search from Jesús Roncer, it wouldn't
 
100
   bcl          work right if run with -q (a owFirst was inside the
 
101
                quiet check). Also adding the manpage created by Jesú.
 
102
 
 
103
                Version changed to 3.2.1
 
104
 
 
105
   05/24/2003   Adding a banner that reports what library the binary was
 
106
   bcl          compiled for (DS9097 or DS9097U).
 
107
                Adjusted the makefile a bit, change the dist to be one of
 
108
                dist-9097 or dist-9097u to build for the right target.
 
109
 
 
110
   05/23/2003   Adding kludges for USB to Serial adapter. Added a loop of
 
111
   bcl          10 tries to the DS2480Detect routine. Added DEBUG_USERIAL
 
112
                compile time wrappers for diagnostic information about the
 
113
                ReadCOM routine. Part of the key to this is the delay used
 
114
                in ReadCOM, its just too short for use with the USB to
 
115
                serial adapter. I've changed it to 1 second + 10-15mS --
 
116
                I'm not sure that the global_msec is really needed with the
 
117
                longer timeout time, its a fail-safe anyway; the character
 
118
                ought to come back a long time before the timeout.
 
119
 
 
120
                Changed version to v3.2.0
 
121
                
 
122
   02/14/2003   Adding logging of read values. Need to change the way it
 
123
   bcl          handles building the output string.
 
124
                It works, but the counter really needs its own format
 
125
                string. Kinda hard to automatically integrate it into the
 
126
                current temperature oriented format string.
 
127
 
 
128
   02/12/2003   Adding more code... Needs more work, the family code may
 
129
   bcl          be buried in the coupler linked list. I may need to move the
 
130
                decision as to how to read it to after it finds the coupler
 
131
                and turns it on.
 
132
                Change read_temp to read_sensor. device selection is common
 
133
                to all devices, then switch based on the serial number
 
134
                finally selected (saved as it is selected).
 
135
 
 
136
   02/06/2003   Changed version number to v3.1.0
 
137
   bcl          Adding support for counters
 
138
                Happy 92nd Birthday to Ronald Reagan!
 
139
 
 
140
   11/21/2002   Changed sleep method to use less CPU cycles, thanks to
 
141
   bcl          peter enderborg for pointing it out.
 
142
 
 
143
   08/21/2002   Small bug with -i crept in, it wants another command to be
 
144
   bcl          present, it won't just initalize.
 
145
 
 
146
   08/16/2002   Adding %N token to output seconds since Epoch, which is
 
147
   bcl          masked by my use of %s for the sensor number. I don't want
 
148
                to remove %s, because that would break old code. So %N
 
149
                now maps to %s in the strftime format.
 
150
                The check for commands is too strict, it isn't allowing
 
151
                -i to be combined with any of the other commands.
 
152
                Added permission checking on the serial device with a clean
 
153
                exit if the user doesn't have access to the serial device.
 
154
 
 
155
   06/23/2002   Releasing new version today. Really! Making -q turn off 
 
156
   bcl          the extra output I added for initalizing the 1-wire lan.
 
157
 
 
158
   06/08/2002   Adding patches from John. exit() codes are now #defines
 
159
   bcl          and .digitemprc now outputs the serial numbers as hex
 
160
                instead of decimal. But maintains backwards compatibility
 
161
                until a new .digitemprc is written.
 
162
                Output format string now includes an option to output the
 
163
                Sensor's serial number in hex (%R).
 
164
 
 
165
   05/11/2002   Adding more changes from John Stoffel
 
166
   bcl
 
167
 
 
168
   05/08/2002   Integrating changes for Solaris, AIX, FreeBSD from John
 
169
   bcl          Stoffel. Changes to getopt initial settings, Makefile
 
170
                and include files.
 
171
 
 
172
   05/06/2002   Adding changes and fixes from DT v2.5 for Windows. 
 
173
   bcl          Family code for DS1822 was wrong, it is really 0x22
 
174
                Lots of changes to the read_temp routine, added a better
 
175
                scratchpad dump routine (previous one only worked for
 
176
                the DS1820).                
 
177
                Quite a bit needs to be changed, I have switched to using
 
178
                a structure to store the sensor and coupler lists. I
 
179
                updated the core temperature read routine, the lan walk
 
180
                and device search routines. Reading when using a hub
 
181
                is now faster when reading multiple devices on the
 
182
                same hub segment.
 
183
 
 
184
   01/15/2002   Cleaning up, preparing for release
 
185
 
 
186
   01/14/2002   Adding support for reading sensors on DS2409 couplers.
 
187
 
 
188
   01/13/2002   Walking the tree now works -- after changing the swt1f.c
 
189
                routine to use the Smart-On Main command while searching
 
190
                for devices (otherwise it only finds the first).
 
191
                
 
192
                Adding support for Coupler to the main program.
 
193
                Init now works, writing .digitemprc now works.
 
194
                Read .digitemprc appears to work.
 
195
                Need to add reading of specified sensors and of all
 
196
                sensors.
 
197
                
 
198
 
 
199
   01/12/2002   Adding a diagnostic walk of the attached network, working
 
200
                on DS2409 MicroLAN Coupler support.
 
201
                Added release1WireNet calls before all exit calls.
 
202
                Switching to the userial library v3.0.0, I seem to have
 
203
                run into a problem with the old library and I cannot read
 
204
                either of my DS9097U adapters with v2.2 digitemp code.
 
205
                
 
206
 
 
207
   05/26/2001   The 18B20 and 1822 patch didn't work. It was reading the
 
208
                wrong scratchpad registers. (2,1 instead of 1,0).
 
209
                Changed version to v2.2
 
210
 
 
211
   03/16/2001   Integrating the AIX patch from Ewan Leith
 
212
                <ejl@man.fraser-williams.com>
 
213
                It amounts to return value checking on getopt and changes
 
214
                in the wirelnk.c file.
 
215
                Adding DS1822 and DS18B20 changes from Roland Roberts
 
216
                <roland@astrofoto.org>
 
217
 
 
218
   03/05/2001   Adding a command line option to specify the configuration
 
219
                file to use. -c config_file will override the default of
 
220
                .digitemprc
 
221
 
 
222
   02/17/2001   If there is an error with strong pullup on/off it shouldn't
 
223
                abort the conversion! Just log an error to stderr.
 
224
 
 
225
   01/31/2001   Added a dummy temperature output when a sensor cannot be
 
226
                read. It outputs a 0 so that scripts like my grapher 
 
227
                don't get confused and log the wrong sensor in the wrong
 
228
                place.
 
229
                
 
230
                An error message is also output to stderr.
 
231
 
 
232
   01/29/2001   Oops. It seems that I missed the line in the DS1820 
 
233
                datasheet that says Vdd needs to be tied to GND for
 
234
                Parasite power to work correctly.
 
235
                Various curses come to mind.
 
236
                The DS1820 works better than the DS18S20 with Vdd floating
 
237
                but this probably explains the infrequent glitches I
 
238
                saw before adding the DS18S20s.
 
239
 
 
240
   01/15/2001   Still getting glitches.
 
241
                Adding a reset and delay before retry
 
242
 
 
243
   01/14/2001   Changed Version number to 2.1
 
244
   
 
245
                I now have 2 DS18S20 sensors which supposedly fix the
 
246
                Temperature accuracy problems of the DS1820 (see the
 
247
                ds1820-report.pdf from Dallas). But now I get a huge
 
248
                number of glitches in the DS18S20's readings.
 
249
                The DS18S20 has an error condition, but it is +85C and
 
250
                the glitches I am seeing are because DigiTemp doesn't
 
251
                output anything at all for the DS18S20's reading.
 
252
                
 
253
                Adding a check for the DS18S20's error condition:
 
254
                LSB = 0xAA
 
255
                MSB = 0x00
 
256
                COUNT_REMAIN = 0x0C
 
257
                COUNT_PER_C = 0x10
 
258
                
 
259
                If this error case is encountered, the reading should be
 
260
                repeated. If it comes up again, use it.
 
261
                
 
262
                There is also a glitch possible in the DS1820 that exhibits
 
263
                itself by COUNT_PER_C - COUNT_REMAIN = 1, this should be
 
264
                checked for, and the reading repeated and the next result
 
265
                used.
 
266
 
 
267
                The problem with no reading from the device seems to
 
268
                happen when MLanAccess is called. There is no good way to
 
269
                tell what the problem is, so I will change the code to
 
270
                try 3 times before failing. Changes are in read_temp.
 
271
                                                
 
272
   01/04/2000   Changing the default read timeout to 1000mS. I had problems
 
273
                with it set to 500mS and a 30' sensor wire (the reading
 
274
                was low by about 10 degrees).
 
275
 
 
276
   01/01/2000   Well, no release last year. Adding -q to make the banner
 
277
                dissapear for batchfiles that want to get the output
 
278
                directly.
 
279
 
 
280
   12/28/99     Changed Version number to 2.0
 
281
                Adding GNU public license
 
282
                Changing this code to use the DS9097-U adapter
 
283
 
 
284
   06/03/99     Finishing this thing up.
 
285
 
 
286
   06/02/99     Use 2 logging routines, log_time to log a single line
 
287
                per sensor with optional time data and log_str to log
 
288
                a single line for multiple sensors with elapsed time at
 
289
                the beginning of the line.
 
290
 
 
291
   05/29/99     Added 2 new init file tags, LOG_FORMAT and LOG_TYPE
 
292
                New formatting works, need to clean up the logic now.
 
293
                
 
294
   05/27/99     Adding user specified format string. To use it, first
 
295
                parse out the digitemp specific stuff and create a new
 
296
                string to feed into strftime, with the sensor, temperature
 
297
                already set.
 
298
 
 
299
   05/24/99     Adding a output specifier string, this will allow users
 
300
                to configure the output to look however they want it to.
 
301
                The format string uses strftime tokens plus 3 special
 
302
                ones for digitemp - %s for sensor #, %C for centigrade,
 
303
                %F for fahrenheit
 
304
 
 
305
   05/23/99     Adding Solaris support via -DSOLARIS define
 
306
                Fixing the time problems once and for all, using localtime
 
307
                in the log_line routine. The user should have TZ set
 
308
                correctly for their timezone. This has been tested
 
309
                and works correctly.
 
310
 
 
311
                Changed version number to v1.3
 
312
 
 
313
   01/14/99     A user in Sweden (and another in Finland) discovered a
 
314
                long standing bug. In do_temp I should have been using
 
315
                0x100 instead of 0xFF for the subtraction. This caused
 
316
                temperatures below 0 degrees C to jump up 1 degree as
 
317
                it decreased. This is fixed.
 
318
                
 
319
                Changed version number to v1.2
 
320
 
 
321
   10/20/98     Adding new features from DOS version to keep things
 
322
                consistent. Removing the debug command, not used anyway.
 
323
                Added a free() to error condition edit from read_rcfile()               
 
324
                Set some cases of freeing to = NULL, also freed the rom
 
325
                list before doing a search rom (searchROM checks too, but
 
326
                this is the right place for it).
 
327
 
 
328
   08/31/98     Adding a check for family 0x10 so that we can read DS1820s
 
329
                while they are on a network that includes other 1-wire
 
330
                devices.
 
331
                Fixed a problem with freeing uninitalized rom_list when
 
332
                starting a SearchROM. Not sure why this never appeared
 
333
                before.
 
334
 
 
335
   03/06/98     Adding a -d debug level to help figure out why this thing
 
336
                is no longer working.
 
337
 
 
338
   03/13/97     Error in CRC calculation. Wrong # of bytes.
 
339
                Error with 3 sensors. Sometimes doesn't store correct ROM
 
340
                data to .digitemprc -- need to malloc more memory dummy!
 
341
 
 
342
   03/08/97     Adding user defined timeouts for failure and for the
 
343
                read delay.
 
344
 
 
345
   01/24/97     Changed over to correct baud rate and 6 bits @ 115.2k
 
346
                ROM search function is now working. All low level code
 
347
                is functioning except for Alarm Search. Starting to move
 
348
                into a seperate object file with API for users to write
 
349
                their own code with.
 
350
                
 
351
   01/22/97     Working on ROM search routine, double cannot handle a full
 
352
                64 bits for some reason, converting to 64 byte array for
 
353
                each bit.
 
354
 
 
355
   01/19/97     Rewriting for new interface. This programs handles all the
 
356
                low level communications with the temperature sensor using
 
357
                the 115200k serial adapter.
 
358
   
 
359
   01/02/96     Rewriting this code to be more user friendly
 
360
     
 
361
   -----------------------------------------------------------------------*/
 
362
#include <stdio.h>
 
363
#include <stdlib.h>
 
364
#include <ctype.h>
 
365
#include <unistd.h>
 
366
#if !defined(AIX) && !defined(SOLARIS) && !defined(FREEBSD) && !defined(DARWIN)
 
367
#include <getopt.h>
 
368
#endif /* !AIX and !SOLARIS and !FREEBSD and !DARWIN */
 
369
#include <sys/types.h>
 
370
#include <sys/stat.h>
 
371
#include <sys/time.h>
 
372
#include <time.h>
 
373
#include <string.h>
 
374
#include <fcntl.h>
 
375
#include <strings.h>
 
376
 
 
377
#ifdef LINUX
 
378
#ifndef OWUSB
 
379
#ifdef LOCKDEV
 
380
#include <lockdev.h>
 
381
#endif
 
382
#endif
 
383
#endif
 
384
 
 
385
#include "digitemp.h"
 
386
#include "device_name.h"
 
387
#include "ownet.h"
 
388
#include "owproto.h"
 
389
 
 
390
 
 
391
/* Setup the correct getopt starting point */
 
392
#ifdef LINUX
 
393
#define GETOPTEOF -1
 
394
#define OPTINDSTART 0
 
395
#endif
 
396
  
 
397
#ifdef AIX
 
398
#define OPTINDSTART 0
 
399
#define GETOPTEOF 255
 
400
#endif
 
401
 
 
402
#ifdef SOLARIS
 
403
#define GETOPTEOF EOF
 
404
#define OPTINDSTART 1
 
405
#endif
 
406
 
 
407
#ifdef FREEBSD
 
408
#define GETOPTEOF EOF
 
409
#define OPTINDSTART 1
 
410
#endif
 
411
 
 
412
#ifdef OPENBSD
 
413
#define GETOPTEOF EOF
 
414
#define OPTINDSTART 1
 
415
#endif
 
416
 
 
417
#ifdef NETBSD
 
418
#define GETOPTEOF EOF
 
419
#define OPTINDSTART 1
 
420
#endif
 
421
 
 
422
#ifdef DARWIN
 
423
#define GETOPTEOF EOF
 
424
#define OPTINDSTART 1
 
425
#endif
 
426
 
 
427
#ifdef OTHER
 
428
#define GETOPTEOF EOF
 
429
#define OPTINDSTART 1
 
430
#endif 
 
431
 
 
432
 
 
433
/* For tracking down strange errors */
 
434
#undef BCL_DEBUG
 
435
 
 
436
extern char     *optarg;              
 
437
extern int      optind, opterr, optopt;
 
438
 
 
439
#if defined(FREEBSD) || defined(DARWIN)
 
440
extern int optreset;
 
441
#endif /* FREEBSD or DARWIN */
 
442
 
 
443
extern const char dtlib[];                      /* Library Used            */
 
444
 
 
445
char    serial_port[40],                        /* Path to the serial port */
 
446
        tmp_serial_port[40], 
 
447
        serial_dev[40],                         /* Device name without /dev/ */
 
448
        log_file[1024],                         /* Path to the log file    */
 
449
        tmp_log_file[1024],
 
450
        temp_format[80],                        /* Format for temperature readings      */
 
451
        tmp_temp_format[80],
 
452
        counter_format[80],                     /* Format for counter readings          */
 
453
        tmp_counter_format[80],
 
454
        humidity_format[80],                    /* Format for Humidity readings         */
 
455
        tmp_humidity_format[80],
 
456
        conf_file[1024],                        /* Configuration File      */
 
457
        option_list[40];
 
458
int     read_time,                              /* Pause during read       */
 
459
        tmp_read_time,
 
460
        log_type,                               /* output format type      */
 
461
        tmp_log_type,
 
462
        num_cs = 0,                             /* Number of sensors on cplr */
 
463
        opts = 0;                               /* Bitmask of flags             */
 
464
 
 
465
struct _coupler *coupler_top = NULL;            /* Linked list of couplers */
 
466
 
 
467
unsigned char Last2409[9];                      /* Last selected coupler   */
 
468
 
 
469
 
 
470
int     global_msec = 10;                       /* For ReadCOM delay       */
 
471
int     global_msec_max = 15;
 
472
 
 
473
/* ----------------------------------------------------------------------- *
 
474
   Print out the program usage
 
475
 * ----------------------------------------------------------------------- */
 
476
void usage()
 
477
{
 
478
  printf(BANNER_1);
 
479
  printf(BANNER_2);
 
480
  printf(BANNER_3, dtlib );                      /* Report Library version */
 
481
  printf("\nUsage: digitemp [-s -i -U -l -r -v -t -a -d -n -o -c]\n");
 
482
  printf("                -i                            Initalize .digitemprc file\n");
 
483
  printf("                -w                            Walk the full device tree\n");
 
484
/*  printf("                -U                            Use the DS909-U adapter\n"); */
 
485
  printf("                -s /dev/ttyS0                 Set serial port\n");
 
486
  printf("                -l /var/log/temperature       Send output to logfile\n");
 
487
  printf("                -c digitemp.conf              Configuration File\n");
 
488
  printf("                -r 1000                       Read delay in mS\n");
 
489
  printf("                -v                            Verbose output\n");
 
490
  printf("                -t 0                          Read Sensor #\n");
 
491
  printf("                -q                            No Copyright notice\n");
 
492
  printf("                -a                            Read all Sensors\n");
 
493
  printf("                -d 5                          Delay between samples (in sec.)\n");
 
494
  printf("                -n 50                         Number of times to repeat\n");
 
495
  printf("                                              0=loop forever\n");
 
496
  printf("                -A                            Treat DS2438 as A/D converter\n");
 
497
  printf("                -O\"counter format string\"      See description below\n");
 
498
  printf("                -o 2                          Output format for logfile\n");
 
499
  printf("                -o\"output format string\"      See description below\n");
 
500
  printf("                -H\"Humidity format string\"    See description below\n");
 
501
  printf("\nLogfile formats:  1 = One line per sensor, time, C, F (default)\n");
 
502
  printf("                  2 = One line per sample, elapsed time, temperature in C\n");
 
503
  printf("                  3 = Same as #2, except temperature is in F\n");
 
504
  printf("        #2 and #3 have the data seperated by tabs, suitable for import\n");
 
505
  printf("        into a spreadsheet or other graphing software.\n");
 
506
  printf("\n        The format string uses strftime tokens plus 5 special ones for\n");
 
507
  printf("        digitemp - %%s for sensor #, %%C for centigrade, %%F for fahrenheit,\n");
 
508
  printf("        %%R to output the hex serial number, and %%N for seconds since Epoch.\n");
 
509
  printf("        The case of the token is important! The default format string is:\n");
 
510
  printf("        \"%%b %%d %%H:%%M:%%S Sensor %%s C: %%.2C F: %%.2F\" which gives you an\n");
 
511
  printf("        output of: May 24 21:25:43 Sensor 0 C: 23.66 F: 74.59\n\n");
 
512
  printf("        The counter format string has 2 special specifiers:\n");
 
513
  printf("        %%n is the counter # and %%C is the count in decimal.\n");
 
514
  printf("        The humidity format uses %%h for the humidity in percent\n\n");
 
515
}
 
516
 
 
517
 
 
518
/* ----------------------------------------------------------------------- *
 
519
   Free up all memory used by the coupler list
 
520
 * ----------------------------------------------------------------------- */
 
521
void free_coupler()
 
522
{
 
523
  unsigned char   a[3];
 
524
  struct _coupler *c;
 
525
  
 
526
  c = coupler_top;
 
527
  while(c)
 
528
  {
 
529
     /* Turn off the Coupler */
 
530
     SetSwitch1F(0, c->SN, ALL_LINES_OFF, 0, a, TRUE);
 
531
 
 
532
    /* Free up the serial number lists */
 
533
    if( c->num_main > 0 )
 
534
      free( c->main );
 
535
      
 
536
    if( c->num_aux > 0 )
 
537
      free( c->aux );
 
538
      
 
539
    /* Point to the next in the list */
 
540
    coupler_top = c->next;
 
541
    
 
542
    /* Free up the current entry */
 
543
    free( c );
 
544
    
 
545
    c = coupler_top;
 
546
  } /* Coupler free loop */
 
547
 
 
548
  /* Make sure its null */
 
549
  coupler_top = NULL;
 
550
}
 
551
 
 
552
 
 
553
/* -----------------------------------------------------------------------
 
554
   Convert degrees C to degrees F
 
555
   ----------------------------------------------------------------------- */
 
556
float c2f( float temp )
 
557
{
 
558
  return 32 + ((temp*9)/5);
 
559
}
 
560
 
 
561
 
 
562
/* -----------------------------------------------------------------------
 
563
   Take the log_format string and parse out the
 
564
   digitemp tags (%*s %*C and %*F) including any format
 
565
   specifiers to pass to sprintf. Build a new string
 
566
   with the strftime tokens and the temperatures mixed
 
567
   together
 
568
 
 
569
   If humidity is <0 then it is invalid
 
570
   ----------------------------------------------------------------------- */
 
571
int build_tf( char *time_format, char *format, int sensor, 
 
572
              float temp_c, int humidity, unsigned char *sn )
 
573
{
 
574
  char  *tf_ptr,
 
575
        *lf_ptr,
 
576
        *lf_ptr2,
 
577
        *tk_ptr,
 
578
        token[80],
 
579
        temp[80];
 
580
        
 
581
  if( !time_format || !format )
 
582
    return 0;
 
583
 
 
584
  tf_ptr = time_format;
 
585
  lf_ptr = format;
 
586
  
 
587
  while( *lf_ptr )
 
588
  {
 
589
    if( *lf_ptr != '%' )
 
590
    {
 
591
      *tf_ptr++ = *lf_ptr++;
 
592
    } else {
 
593
      /* Found a token, decide if its one of ours... */
 
594
      /* save initial pointer, grab everything up to... */
 
595
      lf_ptr2 = lf_ptr;
 
596
      tk_ptr = token;
 
597
 
 
598
      /* 
 
599
         At this point it has a potential format specifier, copy it over
 
600
         to the token variable, up to the alpha-numeric specifier.
 
601
         
 
602
         It needs to stop copying after it gets the alpha character
 
603
      */
 
604
      while( isalnum( *lf_ptr ) || (*lf_ptr == '.') || (*lf_ptr == '*') 
 
605
             || (*lf_ptr == '%') )
 
606
      {
 
607
        *tk_ptr++ = *lf_ptr++;
 
608
        *tk_ptr = 0;
 
609
        
 
610
        /* Break out when the alpha character is copied over */
 
611
        if( isalpha( *(lf_ptr-1) ) )
 
612
          break;
 
613
      }
 
614
      
 
615
      /* see if the format specifier is digitemp or strftime */
 
616
      switch( *(tk_ptr-1) )
 
617
      {
 
618
        case 's' :
 
619
                /* Sensor number */
 
620
                /* Change the specifier to a d */
 
621
                *(tk_ptr-1) = 'd';
 
622
                
 
623
                /* Pass it through sprintf */
 
624
                sprintf( temp, token, sensor );
 
625
 
 
626
                /* Insert this into the time format string */
 
627
                tk_ptr = temp;
 
628
                while( *tk_ptr )
 
629
                  *tf_ptr++ = *tk_ptr++;
 
630
                break;
 
631
                
 
632
        case 'h' :
 
633
                /* Relative humidity % */
 
634
                /* Change the specifier to a d */
 
635
                *(tk_ptr-1) = 'd';
 
636
                
 
637
                /* Pass it through sprintf */
 
638
                sprintf( temp, token, humidity );
 
639
 
 
640
                /* Insert this into the time format string */
 
641
                tk_ptr = temp;
 
642
                while( *tk_ptr )
 
643
                  *tf_ptr++ = *tk_ptr++;
 
644
                break;
 
645
                
 
646
        case 'F' :
 
647
                /* Degrees Fahrenheit */
 
648
                /* Change the specifier to a f */
 
649
                *(tk_ptr-1) = 'f';
 
650
                
 
651
                /* Pass it through sprintf */
 
652
                sprintf( temp, token, c2f(temp_c) );
 
653
 
 
654
                /* Insert this into the time format string */
 
655
                tk_ptr = temp;
 
656
                while( *tk_ptr )
 
657
                  *tf_ptr++ = *tk_ptr++;
 
658
        
 
659
                break;
 
660
                
 
661
        case 'C' :
 
662
                /* Degrees Centigrade */
 
663
                /* Change the specifier to a f */
 
664
                *(tk_ptr-1) = 'f';
 
665
                
 
666
                /* Pass it through sprintf */
 
667
                sprintf( temp, token, temp_c );
 
668
 
 
669
                /* Insert this into the time format string */
 
670
                tk_ptr = temp;
 
671
                while( *tk_ptr )
 
672
                  *tf_ptr++ = *tk_ptr++;                
 
673
                break;
 
674
                
 
675
        case 'R' :
 
676
                /* ROM Serial Number */
 
677
                /* Change the specifier to a hex (x) */
 
678
                *(tk_ptr-1) = 'X';
 
679
 
 
680
                /* Insert the serial number in HEX, yes its ugly,
 
681
                   but it works and saves using another temporary
 
682
                   location and variable.
 
683
                */
 
684
                sprintf( temp, "%02X%02X%02X%02X%02X%02X%02X%02X",
 
685
                         sn[0],sn[1],sn[2],sn[3],sn[4],sn[5],sn[6],sn[7]);
 
686
                
 
687
                /* Insert this into the time format string */
 
688
                tk_ptr = temp;
 
689
                while( *tk_ptr )
 
690
                  *tf_ptr++ = *tk_ptr++;
 
691
                break;
 
692
 
 
693
        case 'N' :
 
694
                /* Seconds since Epoch */
 
695
                /* Change the specifier to a s and pass to time */
 
696
                *(tk_ptr-1) = 's';
 
697
 
 
698
                /* Intentional fall through */
 
699
        default:
 
700
                /* Not something for us, copy it into the time format */
 
701
                tk_ptr = token;
 
702
                while( *tk_ptr )
 
703
                  *tf_ptr++ = *tk_ptr++;
 
704
                break;
 
705
      } 
 
706
    }
 
707
  
 
708
  }
 
709
 
 
710
  /* Terminate the string */
 
711
  *tf_ptr = 0;
 
712
 
 
713
 
 
714
  return 1;
 
715
}
 
716
 
 
717
 
 
718
/* -----------------------------------------------------------------------
 
719
   Take the log_format string and parse out the
 
720
   digitemp tags (%*s %*C and %*F) including any format
 
721
   specifiers to pass to sprintf. Build a new string
 
722
   with the strftime tokens and the temperatures mixed
 
723
   together
 
724
   ----------------------------------------------------------------------- */
 
725
int build_cf( char *time_format, char *format, int sensor, int page,
 
726
              unsigned long count, unsigned char *sn )
 
727
{
 
728
  char  *tf_ptr,
 
729
        *lf_ptr,
 
730
        *lf_ptr2,
 
731
        *tk_ptr,
 
732
        token[80],
 
733
        temp[80];
 
734
        
 
735
  if( !time_format || !format )
 
736
    return 0;
 
737
 
 
738
  tf_ptr = time_format;
 
739
  lf_ptr = format;
 
740
  
 
741
  while( *lf_ptr )
 
742
  {
 
743
    if( *lf_ptr != '%' )
 
744
    {
 
745
      *tf_ptr++ = *lf_ptr++;
 
746
    } else {
 
747
      /* Found a token, decide if its one of ours... */
 
748
      /* save initial pointer, grab everything up to... */
 
749
      lf_ptr2 = lf_ptr;
 
750
      tk_ptr = token;
 
751
      
 
752
      /* Take numbers, astrix, period and letters */
 
753
      while( isalnum( *lf_ptr ) || (*lf_ptr == '.') ||
 
754
             (*lf_ptr == '*') || (*lf_ptr == '%') )
 
755
      {
 
756
        *tk_ptr++ = *lf_ptr++;
 
757
        *tk_ptr = 0;  
 
758
      }
 
759
      
 
760
      /* see if the format specifier is digitemp or strftime */
 
761
      switch( *(tk_ptr-1) )
 
762
      {
 
763
        case 's' :
 
764
                /* Sensor number */
 
765
                /* Change the specifier to a d */
 
766
                *(tk_ptr-1) = 'd';
 
767
                
 
768
                /* Pass it through sprintf */
 
769
                sprintf( temp, token, sensor );
 
770
 
 
771
                /* Insert this into the time format string */
 
772
                tk_ptr = temp;
 
773
                while( *tk_ptr )
 
774
                  *tf_ptr++ = *tk_ptr++;
 
775
                break;
 
776
                
 
777
        case 'F' :
 
778
                break;
 
779
 
 
780
        case 'n' :
 
781
                /* Show the page/counter # (0 or 1) */
 
782
                /* Change the specifier to a d */
 
783
                *(tk_ptr-1) = 'd';
 
784
                
 
785
                /* Pass it through sprintf */
 
786
                sprintf( temp, token, page );
 
787
 
 
788
                /* Insert this into the time format string */
 
789
                tk_ptr = temp;
 
790
                while( *tk_ptr )
 
791
                  *tf_ptr++ = *tk_ptr++;
 
792
                break;
 
793
                
 
794
        case 'C' :
 
795
                /* Counter reading, 32 bit value */
 
796
                /* Change the specifier to a ld */
 
797
                *(tk_ptr-1) = 'l';
 
798
                *(tk_ptr) = 'd';
 
799
                *(tk_ptr+1) = 0;
 
800
                
 
801
                /* Pass it through sprintf */
 
802
                sprintf( temp, token, count );
 
803
 
 
804
                /* Insert this into the time format string */
 
805
                tk_ptr = temp;
 
806
                while( *tk_ptr )
 
807
                  *tf_ptr++ = *tk_ptr++;                
 
808
                break;
 
809
                
 
810
        case 'R' :
 
811
                /* ROM Serial Number */
 
812
                /* Change the specifier to a hex (x) */
 
813
                *(tk_ptr-1) = 'X';
 
814
 
 
815
                /* Insert the serial number in HEX, yes its ugly,
 
816
                   but it works and saves using another temporary
 
817
                   location and variable.
 
818
                */
 
819
                sprintf( temp, "%02X%02X%02X%02X%02X%02X%02X%02X",
 
820
                         sn[0],sn[1],sn[2],sn[3],sn[4],sn[5],sn[6],sn[7]);
 
821
                
 
822
                /* Insert this into the time format string */
 
823
                tk_ptr = temp;
 
824
                while( *tk_ptr )
 
825
                  *tf_ptr++ = *tk_ptr++;                
 
826
                break;
 
827
 
 
828
        case 'N' :
 
829
                /* Seconds since Epoch */
 
830
                /* Change the specifier to a s and pass to time */
 
831
                *(tk_ptr-1) = 's';
 
832
 
 
833
                /* Intentional fall through */
 
834
        default:
 
835
                /* Not something for us, copy it into the time format */
 
836
                tk_ptr = token;
 
837
                while( *tk_ptr )
 
838
                  *tf_ptr++ = *tk_ptr++;
 
839
                break;
 
840
      } 
 
841
    }
 
842
  }
 
843
 
 
844
  /* Terminate the string */
 
845
  *tf_ptr = 0;
 
846
 
 
847
  return 1;
 
848
}
 
849
 
 
850
 
 
851
/* -----------------------------------------------------------------------
 
852
   Print a string to the console or the logfile
 
853
   ----------------------------------------------------------------------- */
 
854
int log_string( char *line )
 
855
{
 
856
  int fd=0;
 
857
  
 
858
 
 
859
  if( log_file[0] != 0 )
 
860
  {  
 
861
    if( (fd = open( log_file, O_CREAT | O_WRONLY | O_APPEND,
 
862
                          S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) == -1 )
 
863
    {
 
864
      printf("Error opening logfile: %s\n", log_file );
 
865
      return -1;
 
866
    }
 
867
    if( write( fd, line, strlen( line ) ) == -1)
 
868
      perror("Error loging to logfile");
 
869
    close( fd );
 
870
  } else {
 
871
    printf( line );
 
872
  }
 
873
  return 0;
 
874
}  
 
875
 
 
876
 
 
877
/* -----------------------------------------------------------------------
 
878
   Log one line of text to the logfile with the current date and time
 
879
 
 
880
   Used with temperatures
 
881
   ----------------------------------------------------------------------- */
 
882
int log_temp( int sensor, float temp_c, unsigned char *sn )
 
883
{
 
884
  unsigned char temp[1024],
 
885
                time_format[160];
 
886
  time_t        mytime;
 
887
 
 
888
 
 
889
  mytime = time(NULL);
 
890
  if( mytime )
 
891
  {
 
892
    /* Build the time format string from log_format */
 
893
    build_tf( time_format, temp_format, sensor, temp_c, -1, sn );
 
894
 
 
895
    /* Handle the time format tokens */
 
896
    strftime( temp, 1024, time_format, localtime( &mytime ) );
 
897
 
 
898
    strcat( temp, "\n" );
 
899
  } else {
 
900
    sprintf( temp, "Time Error\n" );
 
901
  }
 
902
  /* Log it to stdout, logfile or both */
 
903
  log_string( temp );
 
904
 
 
905
  return 0;
 
906
}
 
907
 
 
908
 
 
909
/* -----------------------------------------------------------------------
 
910
   Log one line of text to the logfile with the current date and time
 
911
 
 
912
   Used with counters
 
913
   ----------------------------------------------------------------------- */
 
914
int log_counter( int sensor, int page, unsigned long counter, unsigned char *sn )
 
915
{
 
916
  unsigned char temp[1024],
 
917
                time_format[160];
 
918
  time_t        mytime;
 
919
 
 
920
 
 
921
  mytime = time(NULL);
 
922
  if( mytime )
 
923
  {
 
924
    /* Build the time format string from counter_format */
 
925
    build_cf( time_format, counter_format, sensor, page, counter, sn );
 
926
 
 
927
    /* Handle the time format tokens */
 
928
    strftime( temp, 1024, time_format, localtime( &mytime ) );
 
929
 
 
930
    strcat( temp, "\n" );
 
931
  } else {
 
932
    sprintf( temp, "Time Error\n" );
 
933
  }
 
934
  /* Log it to stdout, logfile or both */
 
935
  log_string( temp );
 
936
 
 
937
  return 0;
 
938
}
 
939
 
 
940
 
 
941
/* -----------------------------------------------------------------------
 
942
   Log one line of text to the logfile with the current date and time
 
943
 
 
944
   Used with temperatures
 
945
   ----------------------------------------------------------------------- */
 
946
int log_humidity( int sensor, double temp_c, int humidity, unsigned char *sn )
 
947
{
 
948
  unsigned char temp[1024],
 
949
                time_format[160];
 
950
  time_t        mytime;
 
951
 
 
952
 
 
953
  mytime = time(NULL);
 
954
  if( mytime )
 
955
  {
 
956
    /* Build the time format string from log_format */
 
957
    build_tf( time_format, humidity_format, sensor, temp_c, humidity, sn );
 
958
 
 
959
    /* Handle the time format tokens */
 
960
    strftime( temp, 1024, time_format, localtime( &mytime ) );
 
961
 
 
962
    strcat( temp, "\n" );
 
963
  } else {
 
964
    sprintf( temp, "Time Error\n" );
 
965
  }
 
966
  /* Log it to stdout, logfile or both */
 
967
  log_string( temp );
 
968
 
 
969
  return 0;
 
970
}
 
971
 
 
972
 
 
973
/* -----------------------------------------------------------------------
 
974
   Compare two serial numbers and return 1 of they match
 
975
 
 
976
   The second one has an additional byte indicating the main (0) or aux (1)
 
977
   branch.
 
978
   ----------------------------------------------------------------------- */
 
979
int cmpSN( unsigned char *sn1, unsigned char *sn2, int branch )
 
980
{
 
981
  int i;
 
982
 
 
983
  for(i = 0; i < 8; i++ )
 
984
  {
 
985
    if( sn1[i] != sn2[i] )
 
986
    {
 
987
      return 0;
 
988
    }
 
989
  }
 
990
  if( branch != sn2[8] )
 
991
  {
 
992
    return 0;
 
993
  }
 
994
 
 
995
  /* Everything Matches */
 
996
  return 1;
 
997
}  
 
998
 
 
999
 
 
1000
/* -----------------------------------------------------------------------
 
1001
   Show the verbose contents of the scratchpad
 
1002
   ----------------------------------------------------------------------- */
 
1003
void show_scratchpad( unsigned char *scratchpad, int sensor_family )
 
1004
{
 
1005
  unsigned char temp[80];
 
1006
  int i;
 
1007
  
 
1008
  if( log_file[0] != 0 )
 
1009
  {
 
1010
    switch( sensor_family )
 
1011
    {
 
1012
      case DS1820_FAMILY:
 
1013
        sprintf( temp, "  Temperature   : 0x%02X\n", scratchpad[1] );
 
1014
        sprintf( temp, "  Sign          : 0x%02X\n", scratchpad[2] );
 
1015
        sprintf( temp, "  TH            : 0x%02X\n", scratchpad[3] );
 
1016
        sprintf( temp, "  TL            : 0x%02X\n", scratchpad[4] );
 
1017
        sprintf( temp, "  Remain        : 0x%02X\n", scratchpad[7] );
 
1018
        sprintf( temp, "  Count Per C   : 0x%02X\n", scratchpad[8] );
 
1019
        sprintf( temp, "  CRC           : 0x%02X\n", scratchpad[9] );
 
1020
        break;
 
1021
 
 
1022
      case DS18B20_FAMILY:
 
1023
      case DS1822_FAMILY:
 
1024
        sprintf( temp, "  Temp. LSB     : 0x%02X\n", scratchpad[1] );
 
1025
        sprintf( temp, "  Temp. MSB     : 0x%02X\n", scratchpad[2] );
 
1026
        sprintf( temp, "  TH            : 0x%02X\n", scratchpad[3] );
 
1027
        sprintf( temp, "  TL            : 0x%02X\n", scratchpad[4] );
 
1028
        sprintf( temp, "  Config Reg.   : 0x%02X\n", scratchpad[5] );
 
1029
        sprintf( temp, "  CRC           : 0x%02X\n", scratchpad[9] );
 
1030
        break;
 
1031
        
 
1032
      case DS2422_FAMILY:
 
1033
      case DS2423_FAMILY:
 
1034
      
 
1035
        break;  
 
1036
    } /* sensor_family switch */
 
1037
  } else {
 
1038
    switch( sensor_family )
 
1039
    {
 
1040
      case DS1820_FAMILY:
 
1041
        printf("  Temperature   : 0x%02X\n", scratchpad[1] );
 
1042
        printf("  Sign          : 0x%02X\n", scratchpad[2] );
 
1043
        printf("  TH            : 0x%02X\n", scratchpad[3] );
 
1044
        printf("  TL            : 0x%02X\n", scratchpad[4] );
 
1045
        printf("  Remain        : 0x%02X\n", scratchpad[7] );
 
1046
        printf("  Count Per C   : 0x%02X\n", scratchpad[8] );
 
1047
        printf("  CRC           : 0x%02X\n", scratchpad[9] );
 
1048
        break;
 
1049
 
 
1050
      case DS18B20_FAMILY:
 
1051
      case DS1822_FAMILY:
 
1052
        printf( "  Temp. LSB     : 0x%02X\n", scratchpad[1] );
 
1053
        printf( "  Temp. MSB     : 0x%02X\n", scratchpad[2] );
 
1054
        printf( "  TH            : 0x%02X\n", scratchpad[3] );
 
1055
        printf( "  TL            : 0x%02X\n", scratchpad[4] );
 
1056
        printf( "  Config Reg.   : 0x%02X\n", scratchpad[5] );
 
1057
        printf( "  CRC           : 0x%02X\n", scratchpad[9] );
 
1058
        break;
 
1059
 
 
1060
      case DS2422_FAMILY:
 
1061
      case DS2423_FAMILY:
 
1062
      
 
1063
        break;  
 
1064
    } /* sensor_family switch */
 
1065
  } /* if log_file */
 
1066
 
 
1067
  /* Dump the complete contents of the scratchpad */
 
1068
  for( i = 0; i < 10; i++ )
 
1069
  {
 
1070
    printf( "scratchpad[%d] = 0x%02X\n", i, scratchpad[i] );
 
1071
  }
 
1072
}
 
1073
 
 
1074
 
 
1075
 
 
1076
/* -----------------------------------------------------------------------
 
1077
   Read the temperature from one sensor
 
1078
 
 
1079
   Return the high-precision temperature value
 
1080
 
 
1081
   Calculated using formula from DS1820 datasheet
 
1082
 
 
1083
   Temperature   = scratchpad[1]
 
1084
   Sign          = scratchpad[2]
 
1085
   TH            = scratchpad[3]
 
1086
   TL            = scratchpad[4]
 
1087
   Count Remain  = scratchpad[7]
 
1088
   Count Per C   = scratchpad[8]
 
1089
   CRC           = scratchpad[9]
 
1090
   
 
1091
                   count_per_C - count_remain
 
1092
   (temp - 0.25) * --------------------------
 
1093
                       count_per_C
 
1094
 
 
1095
   If Sign is not 0x00 then it is a negative (Centigrade) number, and
 
1096
   the temperature must be subtracted from 0x100 and multiplied by -1
 
1097
   ----------------------------------------------------------------------- */
 
1098
int read_temperature( int sensor_family, int sensor )
 
1099
{
 
1100
  char    temp[1024];              /* For output string                    */
 
1101
  unsigned char lastcrc8,
 
1102
                scratchpad[30],    /* Scratchpad block from the sensor     */
 
1103
                TempSN[8];
 
1104
  int     x,
 
1105
          j,
 
1106
          try,                     /* Number of tries at reading device    */
 
1107
          strong_err,              /* Error with strong pullup?            */
 
1108
          ds1820_try,              /* Allow ds1820 glitch 1 time           */
 
1109
          ds18s20_try;             /* Allow DS18S20 error 1 time           */
 
1110
  float   temp_c,                  /* Calculated temperature in Centigrade */
 
1111
          hi_precision;
 
1112
 
 
1113
  x = 0;  
 
1114
  ds1820_try = 0;
 
1115
  ds18s20_try = 0;  
 
1116
  temp_c = 0;
 
1117
  
 
1118
  for( try = 0; try < MAX_READ_TRIES; try++ )
 
1119
  {
 
1120
    if( owAccess(0) )
 
1121
    {
 
1122
      /* Convert Temperature */
 
1123
      if( !owWriteBytePower( 0, 0x44 ) )
 
1124
      {
 
1125
        return FALSE;
 
1126
      }
 
1127
 
 
1128
      /* Sleep for conversion second */
 
1129
      msDelay( read_time );
 
1130
      
 
1131
      /* Turn off the strong pullup */
 
1132
      if( owLevel( 0, MODE_NORMAL ) != MODE_NORMAL )
 
1133
      {
 
1134
        strong_err = 2;
 
1135
      }
 
1136
 
 
1137
 
 
1138
      /* Now read the scratchpad from the device */
 
1139
      if( owAccess(0) )
 
1140
      {
 
1141
/* Use Read_Scratchpad instead? */
 
1142
        /* Build a block for the Scratchpad read */
 
1143
        scratchpad[0] = 0xBE;
 
1144
        for( j = 1; j < 10; j++ )
 
1145
          scratchpad[j] = 0xFF;
 
1146
 
 
1147
        /* Send the block */
 
1148
        if( owBlock( 0, FALSE, scratchpad, 10 ) )
 
1149
        {
 
1150
          /* Calculate the CRC 8 checksum on the received data */
 
1151
          setcrc8(0, 0);
 
1152
          for( j = 1; j < 10; j++ )
 
1153
            lastcrc8 = docrc8( 0, scratchpad[j] );
 
1154
 
 
1155
          /* If the CRC8 is valid then calculate the temperature */
 
1156
          if( lastcrc8 == 0x00 )
 
1157
          {
 
1158
            /* DS1822 and DS18B20 use a different calculation */
 
1159
            if( (sensor_family == DS18B20_FAMILY) ||
 
1160
                (sensor_family == DS1822_FAMILY) )
 
1161
            {
 
1162
              short int temp2 = (scratchpad[2] << 8) | scratchpad[1];
 
1163
              temp_c = temp2 / 16.0;
 
1164
            }
 
1165
 
 
1166
            /* Handle the DS1820 and DS18S20 */
 
1167
            if( sensor_family == DS1820_FAMILY )
 
1168
            {
 
1169
              /* Check for DS1820 glitch condition */
 
1170
              /* COUNT_PER_C - COUNT_REMAIN == 1 */
 
1171
              if( ds1820_try == 0 )
 
1172
              {
 
1173
                if( (scratchpad[7] - scratchpad[6]) == 1 )
 
1174
                {
 
1175
                  ds1820_try = 1;
 
1176
                  continue;
 
1177
                } /* DS1820 error */
 
1178
              } /* ds1820_try */
 
1179
            
 
1180
              /* Check for DS18S20 Error condition */
 
1181
              /*  LSB = 0xAA
 
1182
                  MSB = 0x00
 
1183
                  COUNT_REMAIN = 0x0C
 
1184
                  COUNT_PER_C = 0x10
 
1185
              */
 
1186
              if( ds18s20_try == 0 )
 
1187
              {
 
1188
                if( (scratchpad[4]==0xAA) &&
 
1189
                    (scratchpad[3]==0x00) &&
 
1190
                    (scratchpad[7]==0x0C) &&
 
1191
                    (scratchpad[8]==0x10)
 
1192
                  )
 
1193
                {
 
1194
                  ds18s20_try = 1;
 
1195
                  continue;
 
1196
                } /* DS18S20 error condition */
 
1197
              } /* ds18s20_try */
 
1198
          
 
1199
              /* Convert data to temperature */
 
1200
              if( scratchpad[2] == 0 )
 
1201
              {
 
1202
                temp_c = (int) scratchpad[1] >> 1;
 
1203
              } else {
 
1204
                temp_c = -1 * (int) (0x100-scratchpad[1]) >> 1;
 
1205
              } /* Negative temp calculation */
 
1206
              temp_c -= 0.25;
 
1207
              hi_precision = (int) scratchpad[8] - (int) scratchpad[7];
 
1208
              hi_precision = hi_precision / (int) scratchpad[8];
 
1209
              temp_c = temp_c + hi_precision;
 
1210
            } /* DS1820_FAMILY */
 
1211
            
 
1212
            /* Log the temperature */
 
1213
            switch( log_type )
 
1214
            {
 
1215
              /* Multiple Centigrade temps per line */
 
1216
              case 2:     sprintf( temp, "\t%3.2f", temp_c );
 
1217
                          log_string( temp );
 
1218
                          break;
 
1219
 
 
1220
              /* Multiple Fahrenheit temps per line */
 
1221
              case 3:     sprintf( temp, "\t%3.2f", c2f(temp_c) );
 
1222
                          log_string( temp );
 
1223
                          break;
 
1224
 
 
1225
              default:    owSerialNum( 0, &TempSN[0], TRUE );
 
1226
                          log_temp( sensor, temp_c, TempSN );
 
1227
                          break;
 
1228
            } /* switch( log_type ) */
 
1229
 
 
1230
            /* Show the scratchpad if verbose is seelcted */
 
1231
            if( opts & OPT_VERBOSE )
 
1232
            {
 
1233
              show_scratchpad( scratchpad, sensor_family );              
 
1234
            } /* if OPT_VERBOSE */
 
1235
 
 
1236
            /* Good conversion finished */
 
1237
            return TRUE;
 
1238
          } else {
 
1239
            fprintf( stderr, "CRC Failed. CRC is %02X instead of 0x00\n", lastcrc8 );
 
1240
 
 
1241
            if( opts & OPT_VERBOSE )
 
1242
            {
 
1243
              show_scratchpad( scratchpad, sensor_family );              
 
1244
            } /* if OPT_VERBOSE */
 
1245
          } /* CRC 8 is OK */
 
1246
        } /* Scratchpad Read */
 
1247
      } /* owAccess failed */
 
1248
    } /* owAccess failed */
 
1249
    
 
1250
    /* Failed to read, rest the network, delay and try again */
 
1251
    owTouchReset(0);
 
1252
    msDelay( read_time );
 
1253
  } /* for try < 3 */
 
1254
  
 
1255
  /* Failed, no good reads after MAX_READ_TRIES */
 
1256
  return FALSE;
 
1257
}
 
1258
 
 
1259
 
 
1260
/* -----------------------------------------------------------------------
 
1261
   Read the current counter values
 
1262
   ----------------------------------------------------------------------- */
 
1263
int read_counter( int sensor_family, int sensor )
 
1264
{
 
1265
  char          temp[1024];        /* For output string                    */
 
1266
  unsigned char TempSN[8];
 
1267
  int           page;
 
1268
  unsigned long counter_value;
 
1269
  
 
1270
  if( sensor_family == DS2422_FAMILY )
 
1271
  {
 
1272
    /* Read Pages 2, 3 */
 
1273
    for( page=2; page<=3; page++ )
 
1274
    {
 
1275
      if( ReadCounter( 0, page, &counter_value ) )
 
1276
      {
 
1277
        /* Log the counter */
 
1278
        switch( log_type )
 
1279
        {
 
1280
          /* Multiple Centigrade temps per line */
 
1281
          case 2:
 
1282
          case 3:     sprintf( temp, "\t%ld", counter_value );
 
1283
                      log_string( temp );
 
1284
                      break;
 
1285
 
 
1286
          default:    owSerialNum( 0, &TempSN[0], TRUE );
 
1287
                      log_counter( sensor, page-2, counter_value, TempSN );
 
1288
                      break;
 
1289
        } /* switch( log_type ) */
 
1290
      }
 
1291
    }    
 
1292
  } else if( sensor_family == DS2423_FAMILY ) {
 
1293
    /* Read Pages 14, 15 */
 
1294
    for( page=14; page<=15; page++ )
 
1295
    {
 
1296
      if( ReadCounter( 0, page, &counter_value ) )
 
1297
      {
 
1298
        /* Log the counter */
 
1299
        switch( log_type )
 
1300
        {
 
1301
          /* Multiple Centigrade temps per line */
 
1302
          case 2:
 
1303
          case 3:     sprintf( temp, "\t%ld", counter_value );
 
1304
                      log_string( temp );
 
1305
                      break;
 
1306
 
 
1307
          default:    owSerialNum( 0, &TempSN[0], TRUE );
 
1308
                      log_counter( sensor, page-14, counter_value, TempSN );
 
1309
                      break;
 
1310
        } /* switch( log_type ) */
 
1311
      }
 
1312
    }    
 
1313
  }
 
1314
 
 
1315
  return FALSE;
 
1316
}
 
1317
 
 
1318
 
 
1319
/* -----------------------------------------------------------------------
 
1320
   Read the DS2438
 
1321
   General Purpose A/D
 
1322
   VDD
 
1323
   Temperature
 
1324
   ...
 
1325
 
 
1326
   !!!! Not finished !!!!
 
1327
   Needs an output format string system. Hard-coded for the moment.
 
1328
   ----------------------------------------------------------------------- */
 
1329
int read_ds2438( int sensor_family, int sensor )
 
1330
{
 
1331
  double        temperature;
 
1332
  float         vdd,
 
1333
                ad;
 
1334
  unsigned char temp[1024],
 
1335
                time_format[160];
 
1336
  time_t        mytime;
 
1337
 
 
1338
  
 
1339
  if( sensor_family == DS2438_FAMILY )
 
1340
  {
 
1341
    temperature = Get_Temperature(0);
 
1342
 
 
1343
    /* Read Vdd */
 
1344
    vdd = Volt_Reading(0, 1);
 
1345
 
 
1346
    /* Read A/D */
 
1347
    ad = Volt_Reading(0, 0);
 
1348
 
 
1349
    mytime = time(NULL);
 
1350
    if( mytime )
 
1351
    {
 
1352
      sprintf( time_format, "%%b %%d %%H:%%M:%%S Sensor %d VDD: %0.2f AD: %0.2f C: %0.2f", sensor, vdd, ad, temperature );
 
1353
      
 
1354
      /* Handle the time format tokens */
 
1355
      strftime( temp, 1024, time_format, localtime( &mytime ) );
 
1356
 
 
1357
      strcat( temp, "\n" );
 
1358
    } else {
 
1359
      sprintf( temp, "Time Error\n" );
 
1360
    }
 
1361
 
 
1362
    /* Log it to stdout, logfile or both */
 
1363
    log_string( temp );
 
1364
  }
 
1365
 
 
1366
  return FALSE;
 
1367
}
 
1368
 
 
1369
 
 
1370
/* -----------------------------------------------------------------------
 
1371
   (This routine is modified from code by Eric Wilde)
 
1372
 
 
1373
   Read the humidity from one sensor (e.g. the AAG TAI8540x).
 
1374
 
 
1375
   Log the temperature value and relative humidity.
 
1376
 
 
1377
   Calculated using formula cribbed from the Dallas source code (gethumd.c),
 
1378
   DS2438 data sheet and HIH-3610 data sheet.
 
1379
 
 
1380
   Sensors like the TAI8540x use a DS2438 battery monitor to sense temperature
 
1381
   and convert humidity readings from a Honeywell HIH-3610.  The DS2438
 
1382
   scratchpad is:
 
1383
 
 
1384
   Status/config = scratchpad[2]
 
1385
   Temp LSB      = scratchpad[3]
 
1386
   Temp MSB      = scratchpad[4]
 
1387
   Voltage LSB   = scratchpad[5]
 
1388
   Voltage MSB   = scratchpad[6]
 
1389
   CRC           = scratchpad[10]
 
1390
 
 
1391
                            Temp LSB
 
1392
   temp = (Temp MSB * 32) + -------- * 0.03125
 
1393
                                8
 
1394
 
 
1395
   The temperature is a two's complement signed number.
 
1396
 
 
1397
   voltage = ((Voltage MSB * 256) + Voltage LSB) / 100
 
1398
 
 
1399
   There are two voltages that must be read to get an accurate humidity
 
1400
   reading.  The supply voltage (VDD) is read to determine what voltage the
 
1401
   humidity sensor is running at (this affects the zero offset and slope of
 
1402
   the humidity curve).  The sensor voltage (VAD) is read to get the humidity
 
1403
   value.  Here is the formula for the humidity (temperature and voltage
 
1404
   compensated):
 
1405
    
 
1406
              ((VAD/VDD) - 0.16) * 161.29
 
1407
   humidity = ---------------------------
 
1408
               1.0546 - (0.00216 * temp)
 
1409
 
 
1410
   The humidity sensor is linear from approx 10% to 100% R.H.  Accuracy is
 
1411
   approx 2%.
 
1412
 
 
1413
   !!!! Not Finished !!!!
 
1414
   ----------------------------------------------------------------------- */
 
1415
int read_humidity( int sensor_family, int sensor )
 
1416
{
 
1417
  double        temp_c;                 /* Converted temperature in degrees C */
 
1418
  float         sup_voltage,            /* Supply voltage in volts            */
 
1419
                hum_voltage,            /* Humidity sensor voltage in volts   */
 
1420
                humidity;               /* Calculated humidity in %RH         */
 
1421
  unsigned char TempSN[8];
 
1422
  int           try;  
 
1423
        
 
1424
  for( try = 0; try < MAX_READ_TRIES; try++ )
 
1425
  {
 
1426
    /* Read Vdd, the supply voltage */
 
1427
    if( (sup_voltage = Volt_Reading(0, 1)) != -1.0 )
 
1428
    {
 
1429
      /* Read A/D reading from the humidity sensor */
 
1430
      if( (hum_voltage = Volt_Reading(0, 0)) != -1.0 )
 
1431
      {
 
1432
        /* Read the temperature */
 
1433
        temp_c = Get_Temperature(0);
 
1434
 
 
1435
        /* Convert the measured voltage to humidity */
 
1436
        humidity = (((hum_voltage/sup_voltage) - 0.16) * 161.29)
 
1437
                      / (1.0546 - (0.00216 * temp_c));
 
1438
        if( humidity > 100.0 ) 
 
1439
          humidity = 100.0;
 
1440
        else if( humidity < 0.0 )
 
1441
          humidity = 0.0;
 
1442
 
 
1443
        /* Log the temperature and humidity */
 
1444
        owSerialNum( 0, &TempSN[0], TRUE );
 
1445
        log_humidity( sensor, temp_c, humidity, TempSN );
 
1446
 
 
1447
        /* Good conversion finished */
 
1448
        return TRUE;
 
1449
      }
 
1450
    }
 
1451
 
 
1452
    owTouchReset(0);
 
1453
    msDelay(read_time);
 
1454
  }
 
1455
 
 
1456
  return FALSE;
 
1457
}
 
1458
 
 
1459
 
 
1460
/* -----------------------------------------------------------------------
 
1461
   Select the indicated device, turning on any required couplers
 
1462
   ----------------------------------------------------------------------- */
 
1463
int read_device( struct _roms *sensor_list, int sensor )
 
1464
{
 
1465
  unsigned char   TempSN[8],
 
1466
                  a[3];
 
1467
  int             s,
 
1468
                  status = 0,
 
1469
                  sensor_family;
 
1470
  struct _coupler *c_ptr;          /* Coupler linked list                  */
 
1471
    
 
1472
  /* Tell the sensor to do a temperature conversion */
 
1473
 
 
1474
  /* Sort out how to address the sensor.
 
1475
     If sensor < num_sensors then it can be directly addressed
 
1476
     if sensor >= num_sensors then the coupler must first be
 
1477
     addressed and the correct branch turned on.
 
1478
  */
 
1479
  if( sensor < sensor_list->max )
 
1480
  {
 
1481
    /* Address the sensor directly */
 
1482
    owSerialNum( 0, &sensor_list->roms[sensor*8], FALSE );
 
1483
  } else {
 
1484
    /* Step through the coupler list until the right sensor is found.
 
1485
       Sensors are in order.
 
1486
    */
 
1487
    s = sensor - sensor_list->max;
 
1488
    c_ptr = coupler_top;
 
1489
    while( c_ptr )
 
1490
    {
 
1491
      if( s < c_ptr->num_main )
 
1492
      {
 
1493
        /* Found the right area */
 
1494
        
 
1495
        /* Is this coupler & branch already on? */
 
1496
        if( !cmpSN( c_ptr->SN, Last2409, 0 ) )
 
1497
        {
 
1498
          /* Turn on the main branch */
 
1499
          if(!SetSwitch1F(0, c_ptr->SN, DIRECT_MAIN_ON, 0, a, TRUE))
 
1500
          {
 
1501
            printf("Setting Switch to Main ON state failed\n");
 
1502
            return FALSE;
 
1503
          }
 
1504
          /* Remember the last selected coupler & Branch */
 
1505
          memcpy( &Last2409, &c_ptr->SN, 8 );
 
1506
          Last2409[8] = 0;
 
1507
        }
 
1508
        
 
1509
        /* Select the sensor */
 
1510
        owSerialNum( 0, &c_ptr->main[s*8], FALSE );
 
1511
        break;
 
1512
      } else {
 
1513
        s -= c_ptr->num_main;
 
1514
        if( s < c_ptr->num_aux )
 
1515
        {
 
1516
          /* Found the right area */
 
1517
 
 
1518
          /* Is this coupler & branch already on? */
 
1519
          if( !cmpSN( c_ptr->SN, Last2409, 1 ) )
 
1520
          {        
 
1521
            /* Turn on the aux branch */
 
1522
            if(!SetSwitch1F(0, c_ptr->SN, AUXILARY_ON, 2, a, TRUE))
 
1523
            {
 
1524
              printf("Setting Switch to Aux ON state failed\n");
 
1525
              return FALSE;
 
1526
            }
 
1527
            /* Remember the last selected coupler & Branch */
 
1528
            memcpy( &Last2409, &c_ptr->SN, 8 );
 
1529
            Last2409[8] = 1;
 
1530
          } /* Last2409 check */
 
1531
 
 
1532
          /* Select the sensor */
 
1533
          owSerialNum( 0, &c_ptr->aux[s*8], FALSE );
 
1534
          break;          
 
1535
        }
 
1536
      }
 
1537
      s -= c_ptr->num_aux;
 
1538
      c_ptr = c_ptr->next;
 
1539
    }    
 
1540
  }
 
1541
 
 
1542
  /* Get the Serial # selected */
 
1543
  owSerialNum( 0, &TempSN[0], TRUE );
 
1544
  sensor_family = TempSN[0];
 
1545
  
 
1546
  switch( sensor_family )
 
1547
  {
 
1548
    case DS1820_FAMILY:
 
1549
    case DS1822_FAMILY:
 
1550
    case DS18B20_FAMILY:
 
1551
      status = read_temperature( sensor_family, sensor );
 
1552
      break;
 
1553
      
 
1554
    case DS2422_FAMILY:
 
1555
    case DS2423_FAMILY:
 
1556
      status = read_counter( sensor_family, sensor );
 
1557
      break;
 
1558
 
 
1559
    case DS2438_FAMILY:
 
1560
      if( opts & OPT_DS2438 )
 
1561
      {
 
1562
        status = read_ds2438( sensor_family, sensor );
 
1563
      } else {
 
1564
        status = read_humidity( sensor_family, sensor );
 
1565
      }
 
1566
      break;
 
1567
  }
 
1568
  
 
1569
  return status;
 
1570
}
 
1571
 
 
1572
 
 
1573
 
 
1574
 
 
1575
/* -----------------------------------------------------------------------
 
1576
   Read the temperaturess for all the connected sensors
 
1577
 
 
1578
   Step through all the sensors in the list of serial numbers
 
1579
   ----------------------------------------------------------------------- */
 
1580
int read_all( struct _roms *sensor_list )
 
1581
{
 
1582
  int x;
 
1583
  
 
1584
  for( x = 0; x <  (num_cs+sensor_list->max); x++ )
 
1585
  {
 
1586
    read_device( sensor_list, x );
 
1587
  }
 
1588
  
 
1589
  return 0;
 
1590
}
 
1591
 
 
1592
 
 
1593
/* -----------------------------------------------------------------------
 
1594
   Read a .digitemprc file from the current directory
 
1595
 
 
1596
   The rc file contains:
 
1597
   
 
1598
   TTY <serial>
 
1599
   LOG <logfilepath>
 
1600
   READ_TIME <time in mS>
 
1601
   LOG_TYPE <from -o>
 
1602
   LOG_FORMAT <format string for temperature logging and printing>
 
1603
   CNT_FORMAT <format string for counter logging and printing>
 
1604
   SENSORS <number of ROM lines>
 
1605
   Multiple ROM x <serial number in bytes> lines
 
1606
 
 
1607
   v 2.3 additions:
 
1608
   Multiple COUPLER x <serial number in decimal> lines
 
1609
   CROM x <COUPLER #> <M or A> <Serial number in decimal>
 
1610
   
 
1611
   ----------------------------------------------------------------------- */
 
1612
int read_rcfile( char *fname, struct _roms *sensor_list )
 
1613
{
 
1614
  FILE  *fp;
 
1615
  char  temp[1024];
 
1616
  char  *ptr;
 
1617
  int   sensors, x;
 
1618
  struct _coupler *c_ptr, *coupler_end;
 
1619
  
 
1620
  sensors = 0;
 
1621
  num_cs = 0;
 
1622
  c_ptr = coupler_top;
 
1623
  coupler_end = coupler_top;
 
1624
    
 
1625
  if( ( fp = fopen( fname, "r" ) ) == NULL )
 
1626
  {
 
1627
    /* No rcfile to read, could be part of an -i so don't die */
 
1628
    return 1;
 
1629
  }
 
1630
  
 
1631
  while( fgets( temp, 80, fp ) != 0 )
 
1632
  {
 
1633
    if( (temp[0] == '\n') || (temp[0] == '#') )
 
1634
      continue;
 
1635
      
 
1636
    ptr = strtok( temp, " \t\n" );
 
1637
    
 
1638
    if( strncasecmp( "TTY", ptr, 3 ) == 0 )
 
1639
    {
 
1640
      ptr = strtok( NULL, " \t\n" );
 
1641
      strncpy( serial_port, ptr, sizeof(serial_port)-1 );
 
1642
    } else if( strncasecmp( "LOG_TYPE", ptr, 8 ) == 0 ) {
 
1643
      ptr = strtok( NULL, " \t\n");
 
1644
      log_type = atoi( ptr );
 
1645
    } else if( strncasecmp( "LOG_FORMAT", ptr, 10 ) == 0 ) {
 
1646
      ptr = strtok( NULL, "\"\n");
 
1647
      strncpy( temp_format, ptr, sizeof(temp_format)-1 );
 
1648
    } else if( strncasecmp( "CNT_FORMAT", ptr, 10 ) == 0 ) {
 
1649
      ptr = strtok( NULL, "\"\n");
 
1650
      strncpy( counter_format, ptr, sizeof(counter_format)-1 );
 
1651
    } else if( strncasecmp( "HUM_FORMAT", ptr, 10 ) == 0 ) {
 
1652
      ptr = strtok( NULL, "\"\n");
 
1653
      strncpy( humidity_format, ptr, sizeof(humidity_format)-1 );
 
1654
    } else if( strncasecmp( "LOG", ptr, 3 ) == 0 ) {
 
1655
      ptr = strtok( NULL, " \t\n" );
 
1656
      strncpy( log_file, ptr, sizeof(log_file)-1 );
 
1657
    } else if( strncasecmp( "FAIL_TIME", ptr, 9 ) == 0 ) {
 
1658
 
 
1659
    } else if( strncasecmp( "READ_TIME", ptr, 9 ) == 0 ) {
 
1660
      ptr = strtok( NULL, " \t\n");
 
1661
      read_time = atoi( ptr );
 
1662
    } else if( strncasecmp( "SENSORS", ptr, 7 ) == 0 ) {
 
1663
      ptr = strtok( NULL, " \t\n" );
 
1664
      sensors = atoi( ptr );
 
1665
      
 
1666
      if( sensors > 0 )
 
1667
      {
 
1668
        /* Reserve some memory for the list */
 
1669
        if( ( sensor_list->roms = malloc( sensors * 8 ) ) == NULL )
 
1670
        {
 
1671
          fprintf( stderr, "Error reserving memory for %d sensors\n", sensors );
 
1672
          return -1;
 
1673
        }
 
1674
        sensor_list->max = sensors; 
 
1675
      }
 
1676
    } else if( strncasecmp( "ROM", ptr, 3 ) == 0 ) {
 
1677
      /* Main LAN sensors */
 
1678
      ptr = strtok( NULL, " \t\n" );
 
1679
      sensors = atoi( ptr );
 
1680
      
 
1681
      /* Read the 8 byte ROM address */
 
1682
      for( x = 0; x < 8; x++ )
 
1683
      {
 
1684
        ptr = strtok( NULL, " \t\n" );
 
1685
        sensor_list->roms[(sensors * 8) + x] = strtol( ptr, (char **)NULL, 0 );
 
1686
      }
 
1687
    } else if( strncasecmp( "COUPLER", ptr, 7 ) == 0 ) {
 
1688
      /* DS2409 Coupler list, they are ALWAYS in order, so ignore the
 
1689
         coupler # and create the list in the order found
 
1690
       */
 
1691
      
 
1692
      /* Allocate space for this coupler */
 
1693
      /* Create a new entry in the coupler linked list */
 
1694
      if( (c_ptr = malloc( sizeof( struct _coupler ) ) ) == NULL )
 
1695
      {
 
1696
        fprintf( stderr, "Failed to allocate %d bytes for coupler linked list\n", sizeof( struct _coupler ) );
 
1697
        free_coupler();
 
1698
        if( sensor_list != NULL )
 
1699
          free(sensor_list);
 
1700
#ifndef OWUSB
 
1701
        owRelease(0);
 
1702
#else
 
1703
        owRelease(0, temp );
 
1704
        fprintf( stderr, "USB ERROR: %s\n", temp );
 
1705
#endif /* OWUSB */
 
1706
        exit(EXIT_ERR);
 
1707
      }
 
1708
 
 
1709
      c_ptr->next = NULL;
 
1710
      c_ptr->num_main = 0;
 
1711
      c_ptr->num_aux = 0;
 
1712
      c_ptr->main = NULL;
 
1713
      c_ptr->aux = NULL;
 
1714
 
 
1715
      if( coupler_top == NULL )
 
1716
      {
 
1717
        /* First coupler, add it to the top of the list */
 
1718
        coupler_top = c_ptr;
 
1719
        coupler_end = c_ptr;
 
1720
      } else {
 
1721
        /* Add the new coupler to the list, point to new end */
 
1722
        coupler_end->next = c_ptr;
 
1723
        coupler_end = c_ptr;
 
1724
      }
 
1725
 
 
1726
      /* Ignore the coupler # */
 
1727
      ptr = strtok( NULL, " \t\n" );
 
1728
      
 
1729
      /* Read the 8 byte ROM address */
 
1730
      for( x = 0; x < 8; x++ )
 
1731
      {
 
1732
        ptr = strtok( NULL, " \t\n" );
 
1733
        c_ptr->SN[x] = strtol( ptr, (char **)NULL, 0);
 
1734
      }
 
1735
    } else if( strncasecmp( "CROM", ptr, 4 ) == 0 ) {
 
1736
      /* Count the number of coupler connected sensors */
 
1737
      num_cs++;
 
1738
 
 
1739
      /* DS2409 Coupler sensors */    
 
1740
      /* Ignore sensor #, they are all created in order */
 
1741
      ptr = strtok( NULL, " \t\n" );
 
1742
 
 
1743
      /* Get the coupler number, and set the pointer to the right
 
1744
         coupler
 
1745
       */
 
1746
      ptr = strtok( NULL, " \t\n" );
 
1747
      x = atoi(ptr);
 
1748
      c_ptr = coupler_top;
 
1749
      while( c_ptr && (x > 0) )
 
1750
      {
 
1751
        c_ptr = c_ptr->next;
 
1752
        x--;
 
1753
      }
 
1754
        
 
1755
      /* Make sure we are pointing to something */
 
1756
      if( c_ptr )
 
1757
      {
 
1758
        /* Main/Aux branch */
 
1759
        ptr = strtok( NULL, " \t\n" );
 
1760
        
 
1761
        if( *ptr == 'M' )
 
1762
        {
 
1763
          /* Add to the main list */
 
1764
          c_ptr->num_main++;
 
1765
          
 
1766
          /* Allocate enough space for the new serial number */
 
1767
          if( (c_ptr->main = realloc( c_ptr->main, c_ptr->num_main * 8 ) ) == NULL )
 
1768
          {
 
1769
            fprintf( stderr, "Failed to allocate %d bytes for main branch\n", c_ptr->num_main * 8 );
 
1770
            free_coupler();
 
1771
            if( sensor_list != NULL )
 
1772
              free( sensor_list );
 
1773
#ifndef OWUSB
 
1774
            owRelease(0);
 
1775
#else
 
1776
            owRelease(0, temp );
 
1777
            fprintf( stderr, "USB ERROR: %s\n", temp );
 
1778
#endif /* OWUSB */
 
1779
            exit(EXIT_ERR);
 
1780
          }
 
1781
          
 
1782
          /* Add the serial number to the list */
 
1783
          for( x = 0; x < 8; x++ )
 
1784
          {
 
1785
            ptr = strtok( NULL, " \t\n" );
 
1786
            c_ptr->main[((c_ptr->num_main-1)*8)+x] = strtol( ptr, (char **)NULL,0);
 
1787
          }       
 
1788
        } else {
 
1789
          /* Add to the aux list */
 
1790
          c_ptr->num_aux++;
 
1791
          
 
1792
          /* Allocate enough space for the new serial number */
 
1793
          if( (c_ptr->aux = realloc( c_ptr->aux, c_ptr->num_aux * 8 ) ) == NULL )
 
1794
          {
 
1795
            fprintf( stderr, "Failed to allocate %d bytes for aux branch\n", c_ptr->num_aux * 8 );
 
1796
            free_coupler();
 
1797
            if( sensor_list != NULL )
 
1798
              free( sensor_list );
 
1799
#ifndef OWUSB
 
1800
            owRelease(0);
 
1801
#else
 
1802
            owRelease(0, temp );
 
1803
            fprintf( stderr, "USB ERROR: %s\n", temp );
 
1804
#endif /* OWUSB */
 
1805
            exit(EXIT_ERR);
 
1806
          } /* Allocate more aux space */
 
1807
          
 
1808
          /* Add the serial number to the list */
 
1809
          for( x = 0; x < 8; x++ )
 
1810
          {
 
1811
            ptr = strtok( NULL, " \t\n" );
 
1812
            c_ptr->aux[((c_ptr->num_aux-1)*8)+x] = strtol( ptr, (char **)NULL, 0 );
 
1813
          } /* aux serial number loop */
 
1814
        } /* Main/Aux branch check */
 
1815
      } /* c_ptr Pointing somewhere check */
 
1816
    } else {
 
1817
      fprintf( stderr, "Error reading %s file\n", fname );
 
1818
      free( sensor_list );
 
1819
      fclose( fp );
 
1820
      return -1;
 
1821
    }
 
1822
  }
 
1823
  
 
1824
  fclose( fp ); 
 
1825
 
 
1826
  return 0;
 
1827
}
 
1828
 
 
1829
 
 
1830
/* -----------------------------------------------------------------------
 
1831
   Write a .digitemprc file, it contains:
 
1832
   
 
1833
   TTY <serial>
 
1834
   LOG <logfilepath>
 
1835
   READ_TIME <time in mS>
 
1836
   LOG_TYPE <from -o>
 
1837
   LOG_FORMAT <format string for temperature logging and printing>
 
1838
   CNT_FORMAT <format string for counter logging and printing>
 
1839
   SENSORS <number of ROM lines>
 
1840
   Multiple ROM x <serial number in bytes> lines
 
1841
 
 
1842
   v 2.3 additions:
 
1843
   Multiple COUPLER x <serial number in decimal> lines
 
1844
   CROM x <COUPLER #> <M or A> <Serial number in decimal>
 
1845
 
 
1846
   v 2.4 additions:
 
1847
   All serial numbers are now in Hex.  Still can read older decimal
 
1848
     format. 
 
1849
   Added 'ALIAS # <string>'  
 
1850
   ----------------------------------------------------------------------- */
 
1851
int write_rcfile( char *fname, struct _roms *sensor_list )
 
1852
{
 
1853
  FILE  *fp;
 
1854
  int   x, y, i;
 
1855
  struct _coupler *c_ptr;
 
1856
 
 
1857
  if( ( fp = fopen( fname, "wb" ) ) == NULL )
 
1858
  {
 
1859
    return -1;
 
1860
  }
 
1861
  
 
1862
  fprintf( fp, "TTY %s\n", serial_port );
 
1863
  if( log_file[0] != 0 )
 
1864
    fprintf( fp, "LOG %s\n", log_file );
 
1865
 
 
1866
  fprintf( fp, "READ_TIME %d\n", read_time );           /* mSeconds     */
 
1867
 
 
1868
  fprintf( fp, "LOG_TYPE %d\n", log_type );
 
1869
  fprintf( fp, "LOG_FORMAT \"%s\"\n", temp_format );
 
1870
  fprintf( fp, "CNT_FORMAT \"%s\"\n", counter_format );
 
1871
  fprintf( fp, "HUM_FORMAT \"%s\"\n", humidity_format );
 
1872
    
 
1873
  fprintf( fp, "SENSORS %d\n", sensor_list->max );
 
1874
 
 
1875
  for( x = 0; x < sensor_list->max; x++ )
 
1876
  {
 
1877
    fprintf( fp, "ROM %d ", x );
 
1878
    
 
1879
    for( y = 0; y < 8; y++ )
 
1880
    {
 
1881
          fprintf( fp, "0x%02X ", sensor_list->roms[(x * 8) + y] );
 
1882
    }
 
1883
    fprintf( fp, "\n" );
 
1884
  }
 
1885
 
 
1886
  /* If any DS2409 Couplers were found, write out their information too */
 
1887
  /* Write out the couplers first */
 
1888
  c_ptr = coupler_top;
 
1889
  x =  0;
 
1890
  while( c_ptr )
 
1891
  {
 
1892
    fprintf( fp, "COUPLER %d ", x );
 
1893
    for( y = 0; y < 8; y++ )
 
1894
    {
 
1895
      fprintf( fp, "0x%02X ", c_ptr->SN[y] );
 
1896
    }
 
1897
    fprintf( fp, "\n" );
 
1898
    x++;
 
1899
    c_ptr = c_ptr->next;
 
1900
  } /* Coupler list */
 
1901
 
 
1902
  /* Sendor # ID for coupler starts at num_sensors */
 
1903
  num_cs = 0;  
 
1904
 
 
1905
  /* Start at the top of the coupler list */  
 
1906
  c_ptr = coupler_top;
 
1907
  x =  0;
 
1908
  while( c_ptr )
 
1909
  {
 
1910
    /* Print the devices on this coupler's main branch */
 
1911
    if( c_ptr->num_main > 0 )
 
1912
    {
 
1913
      for( i = 0; i < c_ptr->num_main; i++ )
 
1914
      {
 
1915
        fprintf( fp, "CROM %d %d M ", sensor_list->max+num_cs++, x );
 
1916
 
 
1917
        for( y = 0; y < 8; y++ )
 
1918
        {
 
1919
          fprintf( fp, "0x%02X ", c_ptr->main[(i * 8) + y] );
 
1920
        }
 
1921
        fprintf( fp, "\n" );
 
1922
      }
 
1923
    }
 
1924
    
 
1925
    /* Print the devices on this coupler's aux branch */
 
1926
    if( c_ptr->num_aux > 0 )
 
1927
    {
 
1928
      for( i = 0; i < c_ptr->num_aux; i++ )
 
1929
      {
 
1930
        fprintf( fp, "CROM %d %d A ", sensor_list->max+num_cs++, x );
 
1931
 
 
1932
        for( y = 0; y < 8; y++ )
 
1933
        {
 
1934
          fprintf( fp, "0x%02X ", c_ptr->aux[(i * 8) + y] );
 
1935
        }
 
1936
        fprintf( fp, "\n" );
 
1937
      }
 
1938
    }
 
1939
 
 
1940
    x++;
 
1941
    c_ptr = c_ptr->next;
 
1942
  } /* Coupler list */
 
1943
  
 
1944
 
 
1945
  fclose( fp );
 
1946
  if( !(opts & OPT_QUIET) )
 
1947
  {
 
1948
    fprintf( stderr, "Wrote %s\n",fname);
 
1949
  }
 
1950
  return 0;
 
1951
}
 
1952
 
 
1953
 
 
1954
/* -----------------------------------------------------------------------
 
1955
   Print out a serial number
 
1956
   ----------------------------------------------------------------------- */      
 
1957
void printSN( unsigned char *TempSN, int crlf )
 
1958
{
 
1959
  int y;
 
1960
 
 
1961
  /* Print the serial number */    
 
1962
  for( y = 0; y < 8; y++ )
 
1963
  {
 
1964
    printf("%02X", TempSN[y] );
 
1965
  }
 
1966
  if( crlf )
 
1967
    printf("\n");
 
1968
}
 
1969
 
 
1970
 
 
1971
/* -----------------------------------------------------------------------
 
1972
   Walk the entire connected 1-wire LAN and display the serial number
 
1973
   and type of device.
 
1974
   ----------------------------------------------------------------------- */      
 
1975
int Walk1Wire()
 
1976
{
 
1977
  unsigned char TempSN[8],
 
1978
                InfoByte[3];
 
1979
  short result;
 
1980
  struct _roms  coupler_list;           /* Attached Roms                */
 
1981
  int   x;
 
1982
 
 
1983
  bzero( &coupler_list, sizeof( struct _roms ) );
 
1984
    
 
1985
  /* Find any DS2409 Couplers and turn them all off.
 
1986
     This WILL NOT WORK if there is a coupler attached to the
 
1987
     bus of another coupler. DigiTemp on;y supports couplers
 
1988
     on the main 1-Wire LAN.
 
1989
 
 
1990
     We also don't record any couplers in this loop because if
 
1991
     one was one and we detected a branch that is closed off
 
1992
     after it is turned off we will end up with multiple copies
 
1993
     of the same couplers.
 
1994
  */
 
1995
  if( !(opts & OPT_QUIET) )
 
1996
  {
 
1997
    printf("Turning off all DS2409 Couplers\n");
 
1998
  }
 
1999
  result = owFirst( 0, TRUE, FALSE );
 
2000
  while(result)
 
2001
  {
 
2002
    owSerialNum( 0, TempSN, TRUE );
 
2003
    if( !(opts & OPT_QUIET) )
 
2004
    {
 
2005
      printf(".");
 
2006
    }
 
2007
    fflush(stdout);
 
2008
    if( TempSN[0] == SWITCH_FAMILY )
 
2009
    {
 
2010
      /* Turn off the Coupler */
 
2011
      if(!SetSwitch1F(0, TempSN, ALL_LINES_OFF, 0, InfoByte, TRUE))
 
2012
      {
 
2013
        fprintf( stderr, "Setting Coupler to OFF state failed\n");
 
2014
 
 
2015
        if( coupler_list.roms != NULL )
 
2016
          free( coupler_list.roms );
 
2017
 
 
2018
        return -1;
 
2019
      }
 
2020
    }
 
2021
    result = owNext( 0, TRUE, FALSE );
 
2022
  } /* HUB search */
 
2023
  if( !(opts &OPT_QUIET) )
 
2024
  {
 
2025
    printf("\n");
 
2026
  }
 
2027
  
 
2028
  /* Now we know all the couplers on the main LAN are off, we
 
2029
     can now start mapping the 1-Wire LAN
 
2030
   */
 
2031
  if( !(opts & OPT_QUIET) )
 
2032
  {
 
2033
    printf("Devices on the Main LAN\n");
 
2034
  }
 
2035
  result = owFirst( 0, TRUE, FALSE );
 
2036
  while(result)
 
2037
  {
 
2038
    owSerialNum( 0, TempSN, TRUE );
 
2039
    /* Print the serial number */    
 
2040
    printSN( TempSN, 0 );
 
2041
    printf(" : %s\n", device_name( TempSN[0]) );
 
2042
 
 
2043
    if( TempSN[0] == SWITCH_FAMILY )
 
2044
    {
 
2045
      /* Save the Coupler's serial number so we can explore it later */
 
2046
      /* Count the sensors detected */
 
2047
      coupler_list.max++;
 
2048
 
 
2049
      /* Allocate enough space for the new serial number */
 
2050
      if( (coupler_list.roms = realloc( coupler_list.roms, coupler_list.max * 8 ) ) == NULL )
 
2051
      {
 
2052
        fprintf( stderr,"Failed to allocate %d bytes for coupler_list\n", coupler_list.max * 8 );
 
2053
 
 
2054
        if( coupler_list.roms != NULL )
 
2055
          free( coupler_list.roms );
 
2056
 
 
2057
        return -1;
 
2058
      }
 
2059
      owSerialNum( 0, &coupler_list.roms[(coupler_list.max-1)*8], TRUE );
 
2060
        
 
2061
      /* Turn off the Coupler */
 
2062
      if(!SetSwitch1F(0, TempSN, ALL_LINES_OFF, 0, InfoByte, TRUE))
 
2063
      {
 
2064
        fprintf(stderr, "Setting Switch to OFF state failed\n");
 
2065
 
 
2066
        if( coupler_list.roms != NULL )
 
2067
          free( coupler_list.roms );
 
2068
 
 
2069
        return -1;
 
2070
      }
 
2071
    }
 
2072
    result = owNext( 0, TRUE, FALSE );
 
2073
  } /* HUB search */
 
2074
  if( !(opts & OPT_QUIET) )
 
2075
  {
 
2076
    printf("\n");
 
2077
  }
 
2078
 
 
2079
  /* If there were any 2409 Couplers present walk their trees too */
 
2080
  if( coupler_list.max > 0 )
 
2081
  {
 
2082
    for(x = 0; x < coupler_list.max; x++ )
 
2083
    {
 
2084
      if( !(opts & OPT_QUIET) )
 
2085
      {
 
2086
        printf("\nDevices on Main Branch of Coupler : ");
 
2087
        printSN( &coupler_list.roms[x*8], 1 );
 
2088
      }
 
2089
      result = owBranchFirst( 0, &coupler_list.roms[x * 8], FALSE, TRUE );
 
2090
      while(result)
 
2091
      {
 
2092
        owSerialNum( 0, TempSN, TRUE );
 
2093
 
 
2094
        /* Print the serial number */    
 
2095
        printSN( TempSN, 0 );
 
2096
        printf(" : %s\n", device_name( TempSN[0]) );
 
2097
 
 
2098
        result = owBranchNext(0, &coupler_list.roms[x * 8], FALSE, TRUE );
 
2099
      } /* Main branch loop */
 
2100
      
 
2101
      if( !(opts & OPT_QUIET) )
 
2102
      {
 
2103
        printf("\n");
 
2104
        printf("Devices on Aux Branch of Coupler : ");
 
2105
        printSN( &coupler_list.roms[x*8], 1 );
 
2106
      }
 
2107
      result = owBranchFirst( 0, &coupler_list.roms[x * 8], FALSE, FALSE );
 
2108
      while(result)
 
2109
      {
 
2110
        owSerialNum( 0, TempSN, TRUE );
 
2111
 
 
2112
        /* Print the serial number */    
 
2113
        printSN( TempSN, 0 );
 
2114
        printf(" : %s\n", device_name( TempSN[0]) );
 
2115
 
 
2116
        result = owBranchNext(0, &coupler_list.roms[x * 8], FALSE, FALSE );
 
2117
      } /* Aux Branch loop */
 
2118
    }  /* Coupler loop */
 
2119
  } /* num_couplers check */
 
2120
    
 
2121
  if( coupler_list.roms != NULL )
 
2122
    free( coupler_list.roms );
 
2123
 
 
2124
  return 0;
 
2125
}
 
2126
 
 
2127
 
 
2128
 
 
2129
/* -----------------------------------------------------------------------
 
2130
   Find all the supported temperature sensors on the bus, searching down
 
2131
   DS2409 hubs on the main bus (but not on other hubs).
 
2132
   ----------------------------------------------------------------------- */
 
2133
int Init1WireLan( struct _roms *sensor_list )
 
2134
{
 
2135
  unsigned char TempSN[8],
 
2136
                InfoByte[3];
 
2137
  int result,
 
2138
      x;
 
2139
  unsigned int found_sensors = 0;
 
2140
  struct _coupler       *c_ptr,         /* Coupler pointer              */
 
2141
                        *coupler_end;   /* end of the list              */
 
2142
 
 
2143
  /* Free up any thing that was read from .digitemprc */
 
2144
  if( sensor_list->roms != NULL )
 
2145
  {
 
2146
    free( sensor_list->roms );
 
2147
    sensor_list->roms = NULL;
 
2148
  }
 
2149
  sensor_list->max = 0;
 
2150
  num_cs = 0;
 
2151
 
 
2152
  /* Free up the coupler list */
 
2153
  free_coupler();
 
2154
 
 
2155
  /* Initalize the coupler pointer */
 
2156
  coupler_end = coupler_top;
 
2157
 
 
2158
  if( !(opts & OPT_QUIET) )
 
2159
  {
 
2160
    printf("Turning off all DS2409 Couplers\n");
 
2161
  }
 
2162
  result = owFirst( 0, TRUE, FALSE );
 
2163
  while(result)
 
2164
  {
 
2165
    owSerialNum( 0, TempSN, TRUE );
 
2166
    if( !(opts & OPT_QUIET) )
 
2167
    {
 
2168
      printf(".");
 
2169
    }
 
2170
    fflush(stdout);
 
2171
    if( TempSN[0] == SWITCH_FAMILY )
 
2172
    {
 
2173
      /* Turn off the Coupler */
 
2174
      if(!SetSwitch1F(0, TempSN, ALL_LINES_OFF, 0, InfoByte, TRUE))
 
2175
      {
 
2176
        fprintf( stderr, "Setting Coupler to OFF state failed\n");
 
2177
        free_coupler();
 
2178
        return -1;
 
2179
      }
 
2180
    }
 
2181
    result = owNext( 0, TRUE, FALSE );
 
2182
  } /* HUB OFF search */ 
 
2183
  if( !(opts & OPT_QUIET) )
 
2184
  {
 
2185
    printf("\n");
 
2186
  }
 
2187
  
 
2188
  if( !(opts & OPT_QUIET) )
 
2189
  {
 
2190
    printf("Searching the 1-Wire LAN\n");
 
2191
  }
 
2192
  /* Find any DS2409 Couplers and turn them all off */
 
2193
  result = owFirst( 0, TRUE, FALSE );
 
2194
  while(result)
 
2195
  {
 
2196
    owSerialNum( 0, TempSN, TRUE );
 
2197
 
 
2198
    if( TempSN[0] == SWITCH_FAMILY )
 
2199
    {
 
2200
      /* Print the serial number */
 
2201
      printSN( TempSN, 0 );
 
2202
      printf(" : %s\n", device_name( TempSN[0]) );
 
2203
 
 
2204
      /* Save the Coupler's serial number */
 
2205
      /* Create a new entry in the coupler linked list */
 
2206
      if( (c_ptr = malloc( sizeof( struct _coupler ) ) ) == NULL )
 
2207
      {
 
2208
        fprintf( stderr, "Failed to allocate %d bytes for coupler linked list\n", sizeof( struct _coupler ) );
 
2209
        free_coupler();
 
2210
        return -1;
 
2211
      }
 
2212
 
 
2213
      c_ptr->next = NULL;
 
2214
      c_ptr->num_main = 0;
 
2215
      c_ptr->num_aux = 0;
 
2216
      c_ptr->main = NULL;
 
2217
      c_ptr->aux = NULL;
 
2218
        
 
2219
      if( coupler_top == NULL )
 
2220
      {
 
2221
        /* First coupler, add it to the top of the list */
 
2222
        coupler_top = c_ptr;
 
2223
        coupler_end = c_ptr;
 
2224
      } else {
 
2225
        /* Add the new coupler to the list, point to new end */
 
2226
        coupler_end->next = c_ptr;
 
2227
        coupler_end = c_ptr;
 
2228
      }
 
2229
        
 
2230
      /* Write the serial number to the new list entry */
 
2231
      owSerialNum( 0, coupler_end->SN, TRUE );
 
2232
    } else if( (TempSN[0] == DS1820_FAMILY) ||
 
2233
               (TempSN[0] == DS1822_FAMILY) ||
 
2234
               (TempSN[0] == DS18B20_FAMILY) ||
 
2235
               (TempSN[0] == DS2422_FAMILY) ||
 
2236
               (TempSN[0] == DS2423_FAMILY) ||
 
2237
               (TempSN[0] == DS2438_FAMILY)
 
2238
             )
 
2239
    {
 
2240
      /* Print the serial number */
 
2241
      printSN( TempSN, 0 );
 
2242
      printf(" : %s\n", device_name( TempSN[0]) );
 
2243
 
 
2244
      found_sensors = 1;
 
2245
      /* Count the sensors detected */
 
2246
      sensor_list->max++;
 
2247
 
 
2248
      /* Allocate enough space for the new serial number */
 
2249
      if( (sensor_list->roms = realloc( sensor_list->roms, sensor_list->max * 8 ) ) == NULL )
 
2250
      {
 
2251
        fprintf( stderr, "Failed to allocate %d bytes for sensor_list\n", sensor_list->max * 8 );
 
2252
        if( sensor_list->roms )
 
2253
        {
 
2254
          if( sensor_list->roms )
 
2255
          {
 
2256
            free( sensor_list->roms );
 
2257
            sensor_list->roms = NULL;
 
2258
          }
 
2259
        }
 
2260
        return -1;
 
2261
      }
 
2262
      owSerialNum( 0, &sensor_list->roms[(sensor_list->max-1)*8], TRUE );
 
2263
    }
 
2264
    result = owNext( 0, TRUE, FALSE );
 
2265
  }    
 
2266
 
 
2267
  /* Now go through each coupler branch and search there */
 
2268
  c_ptr = coupler_top;
 
2269
  while( c_ptr )
 
2270
  {
 
2271
    /* Search the Main branch */
 
2272
    result = owBranchFirst( 0, c_ptr->SN, FALSE, TRUE );
 
2273
    while(result)
 
2274
    {
 
2275
      owSerialNum( 0, TempSN, TRUE );
 
2276
 
 
2277
      /* Check to see if it is a temperature sensor */
 
2278
      if( (TempSN[0] == DS1820_FAMILY) ||
 
2279
          (TempSN[0] == DS1822_FAMILY) ||
 
2280
          (TempSN[0] == DS18B20_FAMILY)||
 
2281
          (TempSN[0] == DS2422_FAMILY) ||
 
2282
          (TempSN[0] == DS2423_FAMILY) ||
 
2283
          (TempSN[0] == DS2438_FAMILY)
 
2284
        )
 
2285
      {
 
2286
        /* Print the serial number */
 
2287
        printSN( TempSN, 0 );
 
2288
        printf(" : %s\n", device_name( TempSN[0]) );
 
2289
 
 
2290
        found_sensors = 1;
 
2291
        /* Count the number of sensors on the main branch */
 
2292
        c_ptr->num_main++;
 
2293
                
 
2294
        /* Allocate enough space for the new serial number */
 
2295
        if( (c_ptr->main = realloc( c_ptr->main, c_ptr->num_main * 8 ) ) == NULL )
 
2296
        {
 
2297
          fprintf( stderr, "Failed to allocate %d bytes for main branch\n", c_ptr->num_main * 8 );
 
2298
          free_coupler();
 
2299
          if( sensor_list->roms )
 
2300
          {
 
2301
            free( sensor_list->roms );
 
2302
            sensor_list->roms = NULL;
 
2303
          }
 
2304
          return -1;
 
2305
        }
 
2306
        owSerialNum( 0, &c_ptr->main[(c_ptr->num_main-1)*8], TRUE );
 
2307
      } /* Add serial number to list */
 
2308
        
 
2309
      /* Find the next device on this branch */
 
2310
      result = owBranchNext(0, c_ptr->SN, FALSE, TRUE );
 
2311
    } /* Main branch loop */
 
2312
      
 
2313
    /* Search the Aux branch */
 
2314
    result = owBranchFirst( 0, c_ptr->SN, FALSE, FALSE );
 
2315
    while(result)
 
2316
    {
 
2317
      owSerialNum( 0, TempSN, TRUE );
 
2318
 
 
2319
      if( (TempSN[0] == DS1820_FAMILY) ||
 
2320
          (TempSN[0] == DS1822_FAMILY) ||
 
2321
          (TempSN[0] == DS18B20_FAMILY)||
 
2322
          (TempSN[0] == DS2422_FAMILY) ||
 
2323
          (TempSN[0] == DS2423_FAMILY) ||
 
2324
          (TempSN[0] == DS2438_FAMILY)
 
2325
        )
 
2326
      {
 
2327
        /* Print the serial number */
 
2328
        printSN( TempSN, 0 );
 
2329
        printf(" : %s\n", device_name( TempSN[0]) );
 
2330
 
 
2331
        found_sensors = 1;
 
2332
        /* Count the number of sensors on the aux branch */
 
2333
        c_ptr->num_aux++;
 
2334
        
 
2335
        /* Allocate enough space for the new serial number */
 
2336
        if( (c_ptr->aux = realloc( c_ptr->aux, c_ptr->num_aux * 8 ) ) == NULL )
 
2337
        {
 
2338
          fprintf( stderr, "Failed to allocate %d bytes for aux branch\n", c_ptr->num_main * 8 );
 
2339
          free_coupler();
 
2340
          if( sensor_list->roms )
 
2341
          {
 
2342
            free( sensor_list->roms );
 
2343
            sensor_list->roms = NULL;
 
2344
          }
 
2345
          return -1;
 
2346
        }
 
2347
        owSerialNum( 0, &c_ptr->aux[(c_ptr->num_aux-1)*8], TRUE );
 
2348
      } /* Add serial number to list */
 
2349
        
 
2350
      /* Find the next device on this branch */
 
2351
      result = owBranchNext(0, c_ptr->SN, FALSE, FALSE );
 
2352
    } /* Aux branch loop */
 
2353
      
 
2354
    c_ptr = c_ptr->next;
 
2355
  }  /* Coupler loop */
 
2356
 
 
2357
 
 
2358
  /*
 
2359
     Did the search find any sensors? Even if there was an error it may
 
2360
     have found some valid sensors
 
2361
  */ 
 
2362
  if( found_sensors )
 
2363
  {
 
2364
    /* Was anything found on the main branch? */
 
2365
    if( sensor_list->max > 0 )
 
2366
    {
 
2367
      for( x = 0; x < sensor_list->max; x++ )
 
2368
      {
 
2369
        printf("ROM #%d : ", x );
 
2370
        printSN( &sensor_list->roms[x*8], 1 );
 
2371
      }
 
2372
    } /* num_sensors check */
 
2373
      
 
2374
    /* Was anything found on any DS2409 couplers? */
 
2375
    c_ptr = coupler_top;
 
2376
    while( c_ptr )      
 
2377
    {
 
2378
      /* Check the main branch */
 
2379
      if( c_ptr->num_main > 0 )
 
2380
      {
 
2381
        for( x = 0; x < c_ptr->num_main; x++ )
 
2382
        {    
 
2383
          printf("ROM #%d : ", sensor_list->max+num_cs++ );
 
2384
          printSN( &c_ptr->main[x*8], 1 );
 
2385
        }
 
2386
      }
 
2387
      
 
2388
      /* Check the aux branch */
 
2389
      if( c_ptr->num_aux > 0 )
 
2390
      {
 
2391
        for( x = 0; x < c_ptr->num_aux; x++ )
 
2392
        {    
 
2393
          printf("ROM #%d : ", sensor_list->max+num_cs++ );
 
2394
          printSN( &c_ptr->aux[x*8], 1 );
 
2395
        }
 
2396
      }
 
2397
        
 
2398
      /* Next Coupler */
 
2399
      c_ptr = c_ptr->next;
 
2400
    } /* Coupler list loop */
 
2401
 
 
2402
    /* Write the new list of sensors to the current directory */
 
2403
    write_rcfile( conf_file, sensor_list );
 
2404
  }
 
2405
  return 0;
 
2406
}
 
2407
 
 
2408
 
 
2409
/* ----------------------------------------------------------------------- *
 
2410
   DigiTemp main routine
 
2411
   
 
2412
   Parse command line options, run functions
 
2413
 * ----------------------------------------------------------------------- */
 
2414
int main( int argc, char *argv[] )
 
2415
{
 
2416
  int           sensor;                 /* Single sensor index to read  */
 
2417
  char          temp[1024];             /* Temporary strings            */
 
2418
  char          *p;
 
2419
  int           c;
 
2420
  int           sample_delay = 0;       /* Delay between samples (SEC)  */
 
2421
  unsigned int  x,
 
2422
                num_samples = 1;        /* Number of samples            */
 
2423
  time_t        last_time,              /* Last time we started samples */
 
2424
                start_time;             /* Starting time                */
 
2425
  long int      elapsed_time;           /* Elapsed from start           */
 
2426
  struct _roms  sensor_list;            /* Attached Roms                */
 
2427
  pid_t         pid;                    /* pid of process using serial  */
 
2428
 
 
2429
 
 
2430
  /* Make sure the structure is erased */
 
2431
  bzero( &sensor_list, sizeof( struct _roms ) );
 
2432
 
 
2433
 
 
2434
  if( argc <= 1 )
 
2435
  {
 
2436
    fprintf(stderr,"Error! Not enough arguements.\n\n");
 
2437
    usage();
 
2438
    return -1;
 
2439
  }
 
2440
 
 
2441
#ifndef OWUSB
 
2442
  serial_port[0] = 0;                   /* No default port              */
 
2443
#else
 
2444
  strcpy( serial_port, "USB" );
 
2445
#endif
 
2446
  tmp_serial_port[0] = 0;
 
2447
  log_file[0] = 0;                      /* No default log file          */
 
2448
  tmp_log_file[0] = 0;
 
2449
  tmp_counter_format[0] = 0;
 
2450
  tmp_temp_format[0] = 0;
 
2451
  tmp_humidity_format[0] = 0;
 
2452
  read_time = 1000;                     /* 1000mS read delay            */
 
2453
  tmp_read_time = -1;
 
2454
  sensor = 0;                           /* First sensor in list         */
 
2455
  log_type = 1;                         /* Normal DigiTemp logfile      */
 
2456
  tmp_log_type = -1;
 
2457
  sample_delay = 0;                     /* No delay                     */
 
2458
  num_samples = 1;                      /* Only do it once by default   */
 
2459
 
 
2460
  /* Default log format string:                 */
 
2461
  /* May 24 21:25:43 Sensor 0 C: 23.66 F: 74.59 */
 
2462
  strcpy( temp_format, "%b %d %H:%M:%S Sensor %s C: %.2C F: %.2F" );
 
2463
  strcpy( counter_format, "%b %d %H:%M:%S Sensor %s #%n %C" );
 
2464
  strcpy( humidity_format, "%b %d %H:%M:%S Sensor %s C: %.2C F: %.2F H: %h%%" );
 
2465
  strcpy( conf_file, ".digitemprc" );
 
2466
  strcpy( option_list, "?hqiaAvwr:f:s:l:t:d:n:o:c:O:H:" );
 
2467
 
 
2468
 
 
2469
  /* Command line options override any .digitemprc options temporarily  */
 
2470
  /* Unless the -i parameter is specified, then changes are saved to    */
 
2471
  /* .digitemprc file                                                   */
 
2472
 
 
2473
  optind = OPTINDSTART;
 
2474
  opterr = 1;
 
2475
 
 
2476
  while( (c = getopt(argc, argv, option_list)) != GETOPTEOF )
 
2477
  {
 
2478
    /* Process the command line arguments */
 
2479
    switch( c )
 
2480
    {
 
2481
      case 'c': if( optarg )                    /* Configuration file   */
 
2482
                {
 
2483
                  strncpy( conf_file, optarg, sizeof( conf_file ) - 1 );
 
2484
                }
 
2485
                break;
 
2486
 
 
2487
      case 'w': opts |= OPT_WALK;               /* Walk the LAN         */
 
2488
                break;
 
2489
    
 
2490
      case 'i': opts |= OPT_INIT;               /* Initalize the s#'s   */
 
2491
                break;
 
2492
                
 
2493
      case 'r': tmp_read_time = atoi(optarg);   /* Read delay in mS     */
 
2494
                break;
 
2495
                
 
2496
      case 'v': opts |= OPT_VERBOSE;            /* Verbose              */
 
2497
                break;
 
2498
 
 
2499
      case 's': if(optarg)                      /* Serial port          */
 
2500
                {
 
2501
                  strncpy( tmp_serial_port, optarg, sizeof(tmp_serial_port) - 1 );
 
2502
                }
 
2503
                break;
 
2504
                
 
2505
      case 'l': if(optarg)                      /* Log Filename         */
 
2506
                {
 
2507
                  strncpy( tmp_log_file, optarg, sizeof( tmp_log_file ) - 1);
 
2508
                }
 
2509
                break;
 
2510
                
 
2511
      case 't': if(optarg)                      /* Single Sensor #      */
 
2512
                {
 
2513
                  sensor = atoi(optarg);
 
2514
                  opts |= OPT_SINGLE;
 
2515
                }
 
2516
                break;
 
2517
 
 
2518
      case 'a': opts |= OPT_ALL;                /* Read All sensors     */
 
2519
                break;
 
2520
 
 
2521
      case 'd': if(optarg)                      /* Sample Delay         */
 
2522
                {
 
2523
                  sample_delay = atoi(optarg);
 
2524
                }
 
2525
                break;
 
2526
 
 
2527
      case 'n': if(optarg)                      /* Number of samples    */
 
2528
                {
 
2529
                  num_samples = atoi(optarg);
 
2530
                }
 
2531
                break;
 
2532
 
 
2533
      case 'A': opts |= OPT_DS2438;             /* Treat DS2438 as A/D converter */
 
2534
                break;
 
2535
 
 
2536
      case 'o': if(optarg)                      /* Temperature Logfile format   */
 
2537
                {
 
2538
                  if( isdigit( optarg[0] ) )
 
2539
                  {
 
2540
                    /* Its a number, get it */
 
2541
                    tmp_log_type = atoi(optarg);
 
2542
                  } else {
 
2543
                    /* Not a nuber, get the string */
 
2544
                    if( strlen( optarg ) > sizeof(tmp_temp_format)-1 )
 
2545
                      printf("Temperature format string too long! > %d\n", sizeof(tmp_temp_format)-1);
 
2546
                    else
 
2547
                      strncpy( tmp_temp_format, optarg, sizeof(tmp_temp_format)-1 );
 
2548
                    tmp_log_type=0;
 
2549
                  }
 
2550
                }
 
2551
                break;
 
2552
                
 
2553
      case 'O': if(optarg)                      /* Counter Logfile format       */
 
2554
                {
 
2555
                  if( strlen( optarg ) > sizeof(tmp_counter_format)-1 )
 
2556
                    printf("Counter format string too long! > %d\n", sizeof(tmp_counter_format)-1);
 
2557
                  else
 
2558
                    strncpy( tmp_counter_format, optarg, sizeof(tmp_counter_format)-1 );
 
2559
                }
 
2560
                break;
 
2561
                
 
2562
      case 'H': if(optarg)                      /* Humidity Logfile format      */
 
2563
                {
 
2564
                  if( strlen( optarg ) > sizeof(tmp_humidity_format)-1 )
 
2565
                    printf("Humidity format string too long! > %d\n", sizeof(tmp_humidity_format)-1);
 
2566
                  else
 
2567
                    strncpy( tmp_humidity_format, optarg, sizeof(tmp_humidity_format)-1 );
 
2568
                }
 
2569
                break;
 
2570
                
 
2571
      case 'q': opts |= OPT_QUIET;
 
2572
                break;
 
2573
 
 
2574
      case ':':
 
2575
      case 'h':
 
2576
      case '?': usage();
 
2577
                exit(EXIT_HELP);
 
2578
                break;
 
2579
    
 
2580
      default:  break;
 
2581
    } /* switch getopt */
 
2582
  }  /* while getopt */
 
2583
 
 
2584
  /* Require one 1 action command, no more, no less. */
 
2585
  if ((opts & (OPT_WALK|OPT_INIT|OPT_SINGLE|OPT_ALL)) == 0 )
 
2586
  {
 
2587
    fprintf( stderr, "Error!  You need 1 of the following action commands, -w -a -i -t\n");
 
2588
    exit(EXIT_HELP);
 
2589
  }
 
2590
 
 
2591
  if ( read_rcfile( conf_file, &sensor_list ) < 0 ) {
 
2592
    exit(EXIT_NORC);
 
2593
  }
 
2594
 
 
2595
  /* Now we go through and override with values from the command line */
 
2596
  if (tmp_read_time > 0) {
 
2597
        read_time = tmp_read_time;
 
2598
  }
 
2599
  
 
2600
  if (tmp_serial_port[0] != 0) {
 
2601
        strncpy( serial_port, tmp_serial_port, sizeof(serial_port)-1 );
 
2602
  }
 
2603
  
 
2604
  if (tmp_log_file[0] != 0) {
 
2605
        strncpy( log_file, tmp_log_file, sizeof(log_file)-1 );
 
2606
  }
 
2607
  
 
2608
  if (tmp_log_type != -1) {
 
2609
    log_type = tmp_log_type;
 
2610
    if ( tmp_log_type == 0 )
 
2611
    {
 
2612
      strncpy( temp_format, tmp_temp_format, sizeof(temp_format)-1 );
 
2613
    }
 
2614
  }
 
2615
 
 
2616
  if( tmp_counter_format[0] != 0 ) {
 
2617
    strncpy( counter_format, tmp_counter_format, sizeof(counter_format)-1 );
 
2618
  }
 
2619
  
 
2620
  if( tmp_humidity_format[0] != 0 ) {
 
2621
    strncpy( humidity_format, tmp_humidity_format, sizeof(humidity_format)-1 );
 
2622
  }
 
2623
  
 
2624
  /* Show the copyright banner? */
 
2625
  if( !(opts & OPT_QUIET) )
 
2626
  {
 
2627
    printf(BANNER_1);
 
2628
    printf(BANNER_2);
 
2629
  }
 
2630
 
 
2631
 
 
2632
  /* Check to make sure we have permission to access the port */
 
2633
#ifndef OWUSB
 
2634
  if( access( serial_port, R_OK|W_OK ) < 0 ) {
 
2635
    fprintf( stderr, "Error, you don't have +rw permission to access %s\n", serial_port );
 
2636
 
 
2637
    if( sensor_list.roms != NULL )
 
2638
      free( sensor_list.roms );
 
2639
 
 
2640
    if( coupler_top != NULL )
 
2641
      free_coupler();
 
2642
 
 
2643
    exit(EXIT_NOPERM);
 
2644
  }
 
2645
 
 
2646
  /* Lock our use of the serial port, exit if it is in use */
 
2647
#ifdef LINUX
 
2648
#ifndef OWUSB
 
2649
#ifdef LOCKDEV
 
2650
  /* First turn serial_port into just the final device name */
 
2651
  if( !(p = strrchr( serial_port, '/' )) )
 
2652
  {
 
2653
    fprintf( stderr, "Error getting serial device from %s\n", serial_port );
 
2654
    
 
2655
    if( sensor_list.roms != NULL )
 
2656
      free( sensor_list.roms );
 
2657
 
 
2658
    if( coupler_top != NULL )
 
2659
      free_coupler();
 
2660
 
 
2661
    exit(EXIT_DEVERR);
 
2662
  }
 
2663
  strncpy( serial_dev, p+1, sizeof(serial_dev)-1 );
 
2664
 
 
2665
  if( (pid = dev_lock( serial_dev )) != 0 )
 
2666
  {
 
2667
    if( pid == -1 )
 
2668
    {
 
2669
      fprintf( stderr, "Error locking %s. Do you have permission to write to /var/lock?\n", serial_dev );
 
2670
    } else {
 
2671
      fprintf( stderr, "Error, %s is locked by process %d\n", serial_dev, pid );
 
2672
    }
 
2673
      
 
2674
    if( sensor_list.roms != NULL )
 
2675
      free( sensor_list.roms );
 
2676
 
 
2677
    if( coupler_top != NULL )
 
2678
      free_coupler();
 
2679
 
 
2680
    exit(EXIT_LOCKED);
 
2681
  }
 
2682
#endif          /* LOCKDEV      */
 
2683
#endif          /* OWUSB        */
 
2684
#endif          /* LINUX        */
 
2685
#endif          /* !OWUSB       */
 
2686
 
 
2687
  /* Connect to the MLan network */
 
2688
#ifndef OWUSB
 
2689
  if( !owAcquire( 0, serial_port) )
 
2690
  {
 
2691
#else
 
2692
  if( !owAcquire( 0, serial_port, temp ) )
 
2693
  {
 
2694
    fprintf( stderr, "USB ERROR: %s\n", temp );
 
2695
#endif
 
2696
    
 
2697
    /* Error connecting, print the error and exit */
 
2698
    OWERROR_DUMP(stdout);
 
2699
 
 
2700
    if( sensor_list.roms != NULL )
 
2701
      free( sensor_list.roms );
 
2702
 
 
2703
    if( coupler_top != NULL )
 
2704
      free_coupler();
 
2705
 
 
2706
#ifdef LINUX
 
2707
#ifndef OWUSB
 
2708
#ifdef LOCKDEV
 
2709
    dev_unlock( serial_dev, 0 );
 
2710
#endif          /* LOCKDEV      */
 
2711
#endif          /* OWUSB        */
 
2712
#endif          /* LINUX        */
 
2713
    exit(EXIT_ERR);
 
2714
  }
 
2715
 
 
2716
 
 
2717
  /* Should we walk the whole LAN and display all devices? */
 
2718
  if( opts & OPT_WALK )
 
2719
  {
 
2720
    Walk1Wire();
 
2721
 
 
2722
    if( sensor_list.roms != NULL )
 
2723
      free( sensor_list.roms );
 
2724
 
 
2725
    if( coupler_top != NULL )
 
2726
      free_coupler();
 
2727
 
 
2728
#ifndef OWUSB
 
2729
      owRelease(0);
 
2730
#else
 
2731
      owRelease(0, temp );
 
2732
#endif /* OWUSB */
 
2733
 
 
2734
#ifdef LINUX
 
2735
#ifndef OWUSB
 
2736
#ifdef LOCKDEV
 
2737
    dev_unlock( serial_dev, 0 );
 
2738
#endif          /* LOCKDEV      */
 
2739
#endif          /* OWUSB        */
 
2740
#endif          /* LINUX        */
 
2741
 
 
2742
    exit(EXIT_OK);
 
2743
  }
 
2744
 
 
2745
 
 
2746
  /* ------------------------------------------------------------------*/
 
2747
  /* Should we initalize the sensors?                                  */
 
2748
  /* This should store the serial numbers to the .digitemprc file      */
 
2749
  if( opts & OPT_INIT )
 
2750
  {
 
2751
    if( Init1WireLan( &sensor_list ) != 0 )
 
2752
    {
 
2753
      if( sensor_list.roms != NULL )
 
2754
        free( sensor_list.roms );
 
2755
 
 
2756
      if( coupler_top != NULL )
 
2757
        free_coupler();
 
2758
 
 
2759
      /* Close the serial port */
 
2760
#ifndef OWUSB
 
2761
      owRelease(0);
 
2762
#else
 
2763
      owRelease(0, temp );
 
2764
      fprintf( stderr, "USB ERROR: %s\n", temp );
 
2765
#endif /* OWUSB */
 
2766
 
 
2767
#ifdef LINUX
 
2768
#ifndef OWUSB
 
2769
#ifdef LOCKDEV
 
2770
      dev_unlock( serial_dev, 0 );
 
2771
#endif          /* LOCKDEV      */
 
2772
#endif          /* OWUSB        */
 
2773
#endif          /* LINUX        */
 
2774
 
 
2775
      exit(EXIT_ERR);
 
2776
    }
 
2777
  }
 
2778
 
 
2779
  
 
2780
  /* Record the starting time */
 
2781
  start_time = time(NULL);
 
2782
 
 
2783
  /* Sample the prescribed number of times, 0=infinity */
 
2784
  for( x = 0;num_samples==0 || x < num_samples; x++ )
 
2785
  {
 
2786
    last_time = time(NULL);
 
2787
    elapsed_time = last_time - start_time;
 
2788
 
 
2789
    switch( log_type )
 
2790
    {
 
2791
      /* For this type of logging we print out the elapsed time at the
 
2792
         start of the line
 
2793
       */
 
2794
      case 3:
 
2795
      case 2:   sprintf(temp, "%ld", elapsed_time );
 
2796
                log_string( temp );
 
2797
                break;
 
2798
      default:
 
2799
                break;
 
2800
    }
 
2801
 
 
2802
 
 
2803
    /* Should we read just one sensor? */
 
2804
    if( opts & OPT_SINGLE )
 
2805
    {
 
2806
      read_device( &sensor_list, sensor );  
 
2807
    }
 
2808
  
 
2809
    /* Should we read all connected sensors? */
 
2810
    if( opts & OPT_ALL )
 
2811
    {
 
2812
      read_all( &sensor_list );
 
2813
    }
 
2814
  
 
2815
    switch( log_type )
 
2816
    {
 
2817
      /* For this type of logging we print out the elapsed time at the
 
2818
         start of the line
 
2819
       */
 
2820
      case 3:
 
2821
      case 2:   log_string( "\n" );
 
2822
                break;
 
2823
      default:
 
2824
                break;
 
2825
    }
 
2826
 
 
2827
    /* Wait until we have passed last_time + sample_delay. We do it
 
2828
       this way because reading the sensors takes a certain amount
 
2829
       of time, and sample_delay may be less then the time needed
 
2830
       to read all the sensors. We should complain about this.
 
2831
    */
 
2832
    if( (time(NULL) > last_time + sample_delay) && (sample_delay > 0) )
 
2833
    {
 
2834
      fprintf(stderr, "Warning: delay (-d) is less than the time needed to ");
 
2835
      fprintf(stderr, "read all of the attached sensors. It took %ld seconds", (long int) time(NULL) - last_time );
 
2836
      fprintf(stderr, " to read the sensors\n" );
 
2837
    }
 
2838
 
 
2839
    /* Should we delay before the next sample? */
 
2840
    if( sample_delay > 0 )
 
2841
    {
 
2842
      /* Sleep for the remaining time, if there is any */
 
2843
      if( (time(NULL) - last_time) < sample_delay )
 
2844
        sleep( sample_delay - (time(NULL) - last_time) );
 
2845
    }
 
2846
  }
 
2847
 
 
2848
  if( sensor_list.roms != NULL )
 
2849
    free( sensor_list.roms );
 
2850
 
 
2851
  free_coupler();
 
2852
 
 
2853
#ifndef OWUSB
 
2854
  owRelease(0);
 
2855
#else
 
2856
  owRelease(0, temp );
 
2857
#endif /* OWUSB */
 
2858
 
 
2859
#ifdef LINUX
 
2860
#ifdef OWUSB
 
2861
#ifdef LOCKDEV
 
2862
  dev_unlock( serial_dev, 0 );
 
2863
#endif          /* LOCKDEV      */
 
2864
#endif          /* OWUSB        */
 
2865
#endif          /* LINUX        */
 
2866
 
 
2867
  exit(EXIT_OK);
 
2868
}
 
2869
 
 
2870
 
 
2871
 
 
2872
/* Local Variables: */
 
2873
/* mode: C */
 
2874
/* compile-command: "cd ..; make -k" */
 
2875
/* End: */