/* ----------------------------------------------------------------------- DigiTemp Copyright 1996-2007 by Brian C. Lane All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA digitemp -w Walk the LAN & show all digitemp -i Initalize .digitemprc file digitemp -I Initialize .digitemprc w/sorted serial #s digitemp -s/dev/ttyS0 Set serial port (required) digitemp -cdigitemp.conf Configuration File digitemp -r1000 Set Read timeout to 1000mS digitemp -l/var/log/temperature Send output to logfile digitemp -v Verbose mode digitemp -t0 Read Temperature digitemp -q Quiet, no copyright banner digitemp -a Read all Temperatures digitemp -d5 Delay between samples (in sec.) digitemp -n50 Number of times to repeat. 0=forever digitemp -A Treat DS2438 as A/D converter digitemp -o1 Output format for logfile See description below digitemp -o"output format string" See description below digitemp -O"counter format" See description below digitemp -H"Humidity format" See description below Logfile formats: 1 = (default) - 1 line per sensor, time, C, F 1 line for each sample, elapsed time, sensor #1, #2, ... tab seperated 2 = Reading in C 3 = Reading in F The format string uses strftime tokens plus 6 special ones for digitemp - %s for sensor #, %C for centigrade, %F for fahrenheit, %R for hex serial number, %N for seconds since Epoch Humidity uses %h for the relative humidity in percent The counter format uses %n for the counter # and %C for the count in decimal Remember the case of the token is important! ======================================================================= See ChangeLog file for history of changes -----------------------------------------------------------------------*/ #include #include #include #include #if !defined(AIX) && !defined(SOLARIS) && !defined(FREEBSD) && !defined(DARWIN) #include #endif /* !AIX and !SOLARIS and !FREEBSD and !DARWIN */ #include #include #include #include #include #include #include #include #include #ifdef LINUX #ifndef OWUSB #ifdef LOCKDEV #include #endif #endif #endif #include "digitemp.h" #include "device_name.h" #include "ownet.h" #include "owproto.h" /* Setup the correct getopt starting point */ #ifdef LINUX #define GETOPTEOF -1 #define OPTINDSTART 0 #endif #ifdef CYGWIN #define GETOPTEOF -1 #define OPTINDSTART 0 #endif #ifdef AIX #define OPTINDSTART 0 #define GETOPTEOF 255 #endif #ifdef SOLARIS #define GETOPTEOF EOF #define OPTINDSTART 1 #endif #ifdef FREEBSD #define GETOPTEOF EOF #define OPTINDSTART 1 #endif #ifdef OPENBSD #define GETOPTEOF EOF #define OPTINDSTART 1 #endif #ifdef NETBSD #define GETOPTEOF EOF #define OPTINDSTART 1 #endif #ifdef DARWIN #define GETOPTEOF EOF #define OPTINDSTART 1 #endif #ifdef OTHER #define GETOPTEOF EOF #define OPTINDSTART 1 #endif /* For tracking down strange errors */ #undef BCL_DEBUG extern char *optarg; extern int optind, opterr, optopt; #if defined(FREEBSD) || defined(DARWIN) extern int optreset; #endif /* FREEBSD or DARWIN */ extern const char dtlib[]; /* Library Used */ char serial_port[40], /* Path to the serial port */ tmp_serial_port[40], serial_dev[40], /* Device name without /dev/ */ log_file[1024], /* Path to the log file */ tmp_log_file[1024], temp_format[80], /* Format for temperature readings */ tmp_temp_format[80], counter_format[80], /* Format for counter readings */ tmp_counter_format[80], humidity_format[80], /* Format for Humidity readings */ tmp_humidity_format[80], conf_file[1024], /* Configuration File */ option_list[40]; int read_time, /* Pause during read */ tmp_read_time, log_type, /* output format type */ tmp_log_type, num_cs = 0, /* Number of sensors on cplr */ opts = 0; /* Bitmask of flags */ struct _coupler *coupler_top = NULL; /* Linked list of couplers */ unsigned char Last2409[9]; /* Last selected coupler */ int global_msec = 10; /* For ReadCOM delay */ int global_msec_max = 15; /* ----------------------------------------------------------------------- * Print out the program usage * ----------------------------------------------------------------------- */ void usage() { printf(BANNER_1); printf(BANNER_2); printf(BANNER_3, dtlib ); /* Report Library version */ printf("\nUsage: digitemp [-s -i -I -U -l -r -v -t -a -d -n -o -c]\n"); printf(" -i Initalize .digitemprc file\n"); printf(" -I Initalize .digitemprc file w/sorted serial #s\n"); printf(" -w Walk the full device tree\n"); printf(" -s /dev/ttyS0 Set serial port\n"); printf(" -l /var/log/temperature Send output to logfile\n"); printf(" -c digitemp.conf Configuration File\n"); printf(" -r 1000 Read delay in mS\n"); printf(" -v Verbose output\n"); printf(" -t 0 Read Sensor #\n"); printf(" -q No Copyright notice\n"); printf(" -a Read all Sensors\n"); printf(" -d 5 Delay between samples (in sec.)\n"); printf(" -n 50 Number of times to repeat\n"); printf(" 0=loop forever\n"); printf(" -A Treat DS2438 as A/D converter\n"); printf(" -O\"counter format string\" See description below\n"); printf(" -o 2 Output format for logfile\n"); printf(" -o\"output format string\" See description below\n"); printf(" -H\"Humidity format string\" See description below\n"); printf("\nLogfile formats: 1 = One line per sensor, time, C, F (default)\n"); printf(" 2 = One line per sample, elapsed time, temperature in C\n"); printf(" 3 = Same as #2, except temperature is in F\n"); printf(" #2 and #3 have the data seperated by tabs, suitable for import\n"); printf(" into a spreadsheet or other graphing software.\n"); printf("\n The format string uses strftime tokens plus 5 special ones for\n"); printf(" digitemp - %%s for sensor #, %%C for centigrade, %%F for fahrenheit,\n"); printf(" %%R to output the hex serial number, and %%N for seconds since Epoch.\n"); printf(" The case of the token is important! The default format string is:\n"); printf(" \"%%b %%d %%H:%%M:%%S Sensor %%s C: %%.2C F: %%.2F\" which gives you an\n"); printf(" output of: May 24 21:25:43 Sensor 0 C: 23.66 F: 74.59\n\n"); printf(" The counter format string has 2 special specifiers:\n"); printf(" %%n is the counter # and %%C is the count in decimal.\n"); printf(" The humidity format uses %%h for the humidity in percent\n\n"); } /* ----------------------------------------------------------------------- * Free up all memory used by the coupler list * ----------------------------------------------------------------------- */ void free_coupler( int free_only ) { unsigned char a[3]; struct _coupler *c; c = coupler_top; while(c) { /* Turn off the Coupler */ if ( !free_only ) SetSwitch1F(0, c->SN, ALL_LINES_OFF, 0, a, TRUE); /* Free up the serial number lists */ if( c->num_main > 0 ) free( c->main ); if( c->num_aux > 0 ) free( c->aux ); /* Point to the next in the list */ coupler_top = c->next; /* Free up the current entry */ free( c ); c = coupler_top; } /* Coupler free loop */ /* Make sure its null */ coupler_top = NULL; } /* ----------------------------------------------------------------------- Convert degrees C to degrees F ----------------------------------------------------------------------- */ float c2f( float temp ) { return 32 + ((temp*9)/5); } /* ----------------------------------------------------------------------- Take the log_format string and parse out the digitemp tags (%*s %*C and %*F) including any format specifiers to pass to sprintf. Build a new string with the strftime tokens and the temperatures mixed together If humidity is <0 then it is invalid ----------------------------------------------------------------------- */ int build_tf( char *time_format, char *format, int sensor, float temp_c, int humidity, unsigned char *sn ) { char *tf_ptr, *lf_ptr, *lf_ptr2, *tk_ptr, token[80], temp[80]; if( !time_format || !format ) return 0; tf_ptr = time_format; lf_ptr = format; while( *lf_ptr ) { if( *lf_ptr != '%' ) { *tf_ptr++ = *lf_ptr++; } else { /* Found a token, decide if its one of ours... */ /* save initial pointer, grab everything up to... */ lf_ptr2 = lf_ptr; tk_ptr = token; /* At this point it has a potential format specifier, copy it over to the token variable, up to the alpha-numeric specifier. It needs to stop copying after it gets the alpha character */ while( isalnum( *lf_ptr ) || (*lf_ptr == '.') || (*lf_ptr == '*') || (*lf_ptr == '%') ) { *tk_ptr++ = *lf_ptr++; *tk_ptr = 0; /* Break out when the alpha character is copied over */ if( isalpha( *(lf_ptr-1) ) ) break; } /* see if the format specifier is digitemp or strftime */ switch( *(tk_ptr-1) ) { case 's' : /* Sensor number */ /* Change the specifier to a d */ *(tk_ptr-1) = 'd'; /* Pass it through sprintf */ sprintf( temp, token, sensor ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'h' : /* Relative humidity % */ /* Change the specifier to a d */ *(tk_ptr-1) = 'd'; /* Pass it through sprintf */ sprintf( temp, token, humidity ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'F' : /* Degrees Fahrenheit */ /* Change the specifier to a f */ *(tk_ptr-1) = 'f'; /* Pass it through sprintf */ sprintf( temp, token, c2f(temp_c) ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'C' : /* Degrees Centigrade */ /* Change the specifier to a f */ *(tk_ptr-1) = 'f'; /* Pass it through sprintf */ sprintf( temp, token, temp_c ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'R' : /* ROM Serial Number */ /* Change the specifier to a hex (x) */ *(tk_ptr-1) = 'X'; /* Insert the serial number in HEX, yes its ugly, but it works and saves using another temporary location and variable. */ sprintf( temp, "%02X%02X%02X%02X%02X%02X%02X%02X", sn[0],sn[1],sn[2],sn[3],sn[4],sn[5],sn[6],sn[7]); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'N' : /* Seconds since Epoch */ /* Change the specifier to a s and pass to time */ *(tk_ptr-1) = 's'; /* Intentional fall through */ default: /* Not something for us, copy it into the time format */ tk_ptr = token; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; } } } /* Terminate the string */ *tf_ptr = 0; return 1; } /* ----------------------------------------------------------------------- Take the log_format string and parse out the digitemp tags (%*s %*C and %*F) including any format specifiers to pass to sprintf. Build a new string with the strftime tokens and the temperatures mixed together ----------------------------------------------------------------------- */ int build_cf( char *time_format, char *format, int sensor, int page, unsigned long count, unsigned char *sn ) { char *tf_ptr, *lf_ptr, *lf_ptr2, *tk_ptr, token[80], temp[80]; if( !time_format || !format ) return 0; tf_ptr = time_format; lf_ptr = format; while( *lf_ptr ) { if( *lf_ptr != '%' ) { *tf_ptr++ = *lf_ptr++; } else { /* Found a token, decide if its one of ours... */ /* save initial pointer, grab everything up to... */ lf_ptr2 = lf_ptr; tk_ptr = token; /* Take numbers, astrix, period and letters */ while( isalnum( *lf_ptr ) || (*lf_ptr == '.') || (*lf_ptr == '*') || (*lf_ptr == '%') ) { *tk_ptr++ = *lf_ptr++; *tk_ptr = 0; } /* see if the format specifier is digitemp or strftime */ switch( *(tk_ptr-1) ) { case 's' : /* Sensor number */ /* Change the specifier to a d */ *(tk_ptr-1) = 'd'; /* Pass it through sprintf */ sprintf( temp, token, sensor ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'F' : break; case 'n' : /* Show the page/counter # (0 or 1) */ /* Change the specifier to a d */ *(tk_ptr-1) = 'd'; /* Pass it through sprintf */ sprintf( temp, token, page ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'C' : /* Counter reading, 32 bit value */ /* Change the specifier to a ld */ *(tk_ptr-1) = 'l'; *(tk_ptr) = 'd'; *(tk_ptr+1) = 0; /* Pass it through sprintf */ sprintf( temp, token, count ); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'R' : /* ROM Serial Number */ /* Change the specifier to a hex (x) */ *(tk_ptr-1) = 'X'; /* Insert the serial number in HEX, yes its ugly, but it works and saves using another temporary location and variable. */ sprintf( temp, "%02X%02X%02X%02X%02X%02X%02X%02X", sn[0],sn[1],sn[2],sn[3],sn[4],sn[5],sn[6],sn[7]); /* Insert this into the time format string */ tk_ptr = temp; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; case 'N' : /* Seconds since Epoch */ /* Change the specifier to a s and pass to time */ *(tk_ptr-1) = 's'; /* Intentional fall through */ default: /* Not something for us, copy it into the time format */ tk_ptr = token; while( *tk_ptr ) *tf_ptr++ = *tk_ptr++; break; } } } /* Terminate the string */ *tf_ptr = 0; return 1; } /* ----------------------------------------------------------------------- Print a string to the console or the logfile ----------------------------------------------------------------------- */ int log_string( char *line ) { int fd=0; if( log_file[0] != 0 ) { if( (fd = open( log_file, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) == -1 ) { printf("Error opening logfile: %s\n", log_file ); return -1; } if( write( fd, line, strlen( line ) ) == -1) perror("Error loging to logfile"); close( fd ); } else { printf( "%s", line ); } return 0; } /* ----------------------------------------------------------------------- Log one line of text to the logfile with the current date and time Used with temperatures ----------------------------------------------------------------------- */ int log_temp( int sensor, float temp_c, unsigned char *sn ) { char temp[1024], time_format[160]; time_t mytime; mytime = time(NULL); if( mytime ) { /* Build the time format string from log_format */ build_tf( time_format, temp_format, sensor, temp_c, -1, sn ); /* Handle the time format tokens */ strftime( temp, 1024, time_format, localtime( &mytime ) ); strcat( temp, "\n" ); } else { sprintf( temp, "Time Error\n" ); } /* Log it to stdout, logfile or both */ log_string( temp ); return 0; } /* ----------------------------------------------------------------------- Log one line of text to the logfile with the current date and time Used with counters ----------------------------------------------------------------------- */ int log_counter( int sensor, int page, unsigned long counter, unsigned char *sn ) { char temp[1024], time_format[160]; time_t mytime; mytime = time(NULL); if( mytime ) { /* Build the time format string from counter_format */ build_cf( time_format, counter_format, sensor, page, counter, sn ); /* Handle the time format tokens */ strftime( temp, 1024, time_format, localtime( &mytime ) ); strcat( temp, "\n" ); } else { sprintf( temp, "Time Error\n" ); } /* Log it to stdout, logfile or both */ log_string( temp ); return 0; } /* ----------------------------------------------------------------------- Log one line of text to the logfile with the current date and time Used with temperatures ----------------------------------------------------------------------- */ int log_humidity( int sensor, double temp_c, int solar_rad, int humidity, unsigned char *sn ) { char temp[1024], time_format[160]; time_t mytime; mytime = time(NULL); if( mytime ) { /* Log the temperature */ switch( log_type ) { /* Multiple Centigrade temps per line */ case 2: sprintf( temp, "\t%3.2f", temp_c ); break; /* Multiple Fahrenheit temps per line */ case 3: sprintf( temp, "\t%3.2f", c2f(temp_c) ); break; default: /* Build the time format string from log_format */ build_tf( time_format, humidity_format, sensor, temp_c, humidity, sn ); /* Handle the time format tokens */ strftime( temp, 1024, time_format, localtime( &mytime ) ); sprintf(temp, "%s S: %d \n", temp, solar_rad); break; } } else { sprintf( temp, "Time Error\n" ); } /* Log it to stdout, logfile or both */ log_string( temp ); return 0; } /* ----------------------------------------------------------------------- Compare two serial numbers and return 1 of they match The second one has an additional byte indicating the main (0) or aux (1) branch. ----------------------------------------------------------------------- */ int cmpSN( unsigned char *sn1, unsigned char *sn2, int branch ) { int i; for(i = 0; i < 8; i++ ) { if( sn1[i] != sn2[i] ) { return 0; } } if( branch != sn2[8] ) { return 0; } /* Everything Matches */ return 1; } /* ----------------------------------------------------------------------- Show the verbose contents of the scratchpad ----------------------------------------------------------------------- */ void show_scratchpad( unsigned char *scratchpad, int sensor_family ) { char temp[80]; int i; if( log_file[0] != 0 ) { switch( sensor_family ) { case DS1820_FAMILY: sprintf( temp, " Temperature : 0x%02X\n", scratchpad[1] ); sprintf( temp, " Sign : 0x%02X\n", scratchpad[2] ); sprintf( temp, " TH : 0x%02X\n", scratchpad[3] ); sprintf( temp, " TL : 0x%02X\n", scratchpad[4] ); sprintf( temp, " Remain : 0x%02X\n", scratchpad[7] ); sprintf( temp, " Count Per C : 0x%02X\n", scratchpad[8] ); sprintf( temp, " CRC : 0x%02X\n", scratchpad[9] ); break; case DS18B20_FAMILY: case DS1822_FAMILY: sprintf( temp, " Temp. LSB : 0x%02X\n", scratchpad[1] ); sprintf( temp, " Temp. MSB : 0x%02X\n", scratchpad[2] ); sprintf( temp, " TH : 0x%02X\n", scratchpad[3] ); sprintf( temp, " TL : 0x%02X\n", scratchpad[4] ); sprintf( temp, " Config Reg. : 0x%02X\n", scratchpad[5] ); sprintf( temp, " CRC : 0x%02X\n", scratchpad[9] ); break; case DS2422_FAMILY: case DS2423_FAMILY: break; } /* sensor_family switch */ } else { switch( sensor_family ) { case DS1820_FAMILY: printf(" Temperature : 0x%02X\n", scratchpad[1] ); printf(" Sign : 0x%02X\n", scratchpad[2] ); printf(" TH : 0x%02X\n", scratchpad[3] ); printf(" TL : 0x%02X\n", scratchpad[4] ); printf(" Remain : 0x%02X\n", scratchpad[7] ); printf(" Count Per C : 0x%02X\n", scratchpad[8] ); printf(" CRC : 0x%02X\n", scratchpad[9] ); break; case DS18B20_FAMILY: case DS1822_FAMILY: printf( " Temp. LSB : 0x%02X\n", scratchpad[1] ); printf( " Temp. MSB : 0x%02X\n", scratchpad[2] ); printf( " TH : 0x%02X\n", scratchpad[3] ); printf( " TL : 0x%02X\n", scratchpad[4] ); printf( " Config Reg. : 0x%02X\n", scratchpad[5] ); printf( " CRC : 0x%02X\n", scratchpad[9] ); break; case DS2422_FAMILY: case DS2423_FAMILY: break; } /* sensor_family switch */ } /* if log_file */ /* Dump the complete contents of the scratchpad */ for( i = 0; i < 10; i++ ) { printf( "scratchpad[%d] = 0x%02X\n", i, scratchpad[i] ); } } /* ----------------------------------------------------------------------- Read the temperature from one sensor Return the high-precision temperature value Calculated using formula from DS1820 datasheet Temperature = scratchpad[1] Sign = scratchpad[2] TH = scratchpad[3] TL = scratchpad[4] Count Remain = scratchpad[7] Count Per C = scratchpad[8] CRC = scratchpad[9] count_per_C - count_remain (temp - 0.25) * -------------------------- count_per_C If Sign is not 0x00 then it is a negative (Centigrade) number, and the temperature must be subtracted from 0x100 and multiplied by -1 ----------------------------------------------------------------------- */ int read_temperature( int sensor_family, int sensor ) { char temp[1024]; /* For output string */ unsigned char lastcrc8, scratchpad[30], /* Scratchpad block from the sensor */ TempSN[8]; int x, j, try, /* Number of tries at reading device */ strong_err, /* Error with strong pullup? */ ds1820_try, /* Allow ds1820 glitch 1 time */ ds18s20_try; /* Allow DS18S20 error 1 time */ float temp_c, /* Calculated temperature in Centigrade */ hi_precision; x = 0; ds1820_try = 0; ds18s20_try = 0; temp_c = 0; for( try = 0; try < MAX_READ_TRIES; try++ ) { if( owAccess(0) ) { /* Convert Temperature */ if( !owWriteBytePower( 0, 0x44 ) ) { return FALSE; } /* Sleep for conversion second */ msDelay( read_time ); /* Turn off the strong pullup */ if( owLevel( 0, MODE_NORMAL ) != MODE_NORMAL ) { strong_err = 2; } /* Now read the scratchpad from the device */ if( owAccess(0) ) { /* Use Read_Scratchpad instead? */ /* Build a block for the Scratchpad read */ scratchpad[0] = 0xBE; for( j = 1; j < 10; j++ ) scratchpad[j] = 0xFF; /* Send the block */ if( owBlock( 0, FALSE, scratchpad, 10 ) ) { /* Calculate the CRC 8 checksum on the received data */ setcrc8(0, 0); for( j = 1; j < 10; j++ ) lastcrc8 = docrc8( 0, scratchpad[j] ); /* If the CRC8 is valid then calculate the temperature */ if( lastcrc8 == 0x00 ) { /* DS1822 and DS18B20 use a different calculation */ if( (sensor_family == DS18B20_FAMILY) || (sensor_family == DS1822_FAMILY) || (sensor_family == DS1923_FAMILY) ) { short int temp2 = (scratchpad[2] << 8) | scratchpad[1]; temp_c = temp2 / 16.0; } /* Handle the DS1820 and DS18S20 */ if( sensor_family == DS1820_FAMILY ) { /* Check for DS1820 glitch condition */ /* COUNT_PER_C - COUNT_REMAIN == 1 */ if( ds1820_try == 0 ) { if( (scratchpad[7] - scratchpad[6]) == 1 ) { ds1820_try = 1; continue; } /* DS1820 error */ } /* ds1820_try */ /* Check for DS18S20 Error condition */ /* LSB = 0xAA MSB = 0x00 COUNT_REMAIN = 0x0C COUNT_PER_C = 0x10 */ if( ds18s20_try == 0 ) { if( (scratchpad[4]==0xAA) && (scratchpad[3]==0x00) && (scratchpad[7]==0x0C) && (scratchpad[8]==0x10) ) { ds18s20_try = 1; continue; } /* DS18S20 error condition */ } /* ds18s20_try */ /* Convert data to temperature */ if( scratchpad[2] == 0 ) { temp_c = (int) scratchpad[1] >> 1; } else { temp_c = -1 * (int) (0x100-scratchpad[1]) >> 1; } /* Negative temp calculation */ temp_c -= 0.25; hi_precision = (int) scratchpad[8] - (int) scratchpad[7]; hi_precision = hi_precision / (int) scratchpad[8]; temp_c = temp_c + hi_precision; } /* DS1820_FAMILY */ /* Log the temperature */ switch( log_type ) { /* Multiple Centigrade temps per line */ case 2: sprintf( temp, "\t%3.2f", temp_c ); log_string( temp ); break; /* Multiple Fahrenheit temps per line */ case 3: sprintf( temp, "\t%3.2f", c2f(temp_c) ); log_string( temp ); break; default: owSerialNum( 0, &TempSN[0], TRUE ); log_temp( sensor, temp_c, TempSN ); break; } /* switch( log_type ) */ /* Show the scratchpad if verbose is seelcted */ if( opts & OPT_VERBOSE ) { show_scratchpad( scratchpad, sensor_family ); } /* if OPT_VERBOSE */ /* Good conversion finished */ return TRUE; } else { fprintf( stderr, "CRC Failed. CRC is %02X instead of 0x00\n", lastcrc8 ); if( opts & OPT_VERBOSE ) { show_scratchpad( scratchpad, sensor_family ); } /* if OPT_VERBOSE */ } /* CRC 8 is OK */ } /* Scratchpad Read */ } /* owAccess failed */ } /* owAccess failed */ /* Failed to read, rest the network, delay and try again */ owTouchReset(0); msDelay( read_time ); } /* for try < 3 */ /* Failed, no good reads after MAX_READ_TRIES */ return FALSE; } /* ----------------------------------------------------------------------- Read the current counter values ----------------------------------------------------------------------- */ int read_counter( int sensor_family, int sensor ) { char temp[1024]; /* For output string */ unsigned char TempSN[8]; int page; unsigned long counter_value; if( sensor_family == DS2422_FAMILY ) { /* Read Pages 2, 3 */ for( page=2; page<=3; page++ ) { if( ReadCounter( 0, page, &counter_value ) ) { /* Log the counter */ switch( log_type ) { /* Multiple Centigrade temps per line */ case 2: case 3: sprintf( temp, "\t%ld", counter_value ); log_string( temp ); break; default: owSerialNum( 0, &TempSN[0], TRUE ); log_counter( sensor, page-2, counter_value, TempSN ); break; } /* switch( log_type ) */ } } } else if( sensor_family == DS2423_FAMILY ) { /* Read Pages 14, 15 */ for( page=14; page<=15; page++ ) { if( ReadCounter( 0, page, &counter_value ) ) { /* Log the counter */ switch( log_type ) { /* Multiple Centigrade temps per line */ case 2: case 3: sprintf( temp, "\t%ld", counter_value ); log_string( temp ); break; default: owSerialNum( 0, &TempSN[0], TRUE ); log_counter( sensor, page-14, counter_value, TempSN ); break; } /* switch( log_type ) */ } } } return FALSE; } /* ----------------------------------------------------------------------- Read the DS2438 General Purpose A/D VDD Temperature ... !!!! Not finished !!!! Needs an output format string system. Hard-coded for the moment. ----------------------------------------------------------------------- */ int read_ds2438( int sensor_family, int sensor ) { double temperature; float vdd, ad; char temp[1024], time_format[160]; time_t mytime; if( sensor_family == DS2438_FAMILY ) { temperature = Get_Temperature(0); /* Read Vdd */ vdd = Volt_Reading(0, 1); /* Read A/D */ ad = Volt_Reading(0, 0); mytime = time(NULL); if( mytime ) { /* Log the temperature */ switch( log_type ) { /* Multiple Centigrade temps per line */ case 2: sprintf( temp, "\t%3.2f", temperature ); break; /* Multiple Fahrenheit temps per line */ case 3: sprintf( temp, "\t%3.2f", c2f(temperature) ); break; default: sprintf( time_format, "%%b %%d %%H:%%M:%%S Sensor %d VDD: %0.2f AD: %0.2f C: %0.2f", sensor, vdd, ad, temperature ); /* Handle the time format tokens */ strftime( temp, 1024, time_format, localtime( &mytime ) ); strcat( temp, "\n" ); break; } /* switch( log_type ) */ } else { sprintf( temp, "Time Error\n" ); } /* Log it to stdout, logfile or both */ log_string( temp ); } return FALSE; } /* ----------------------------------------------------------------------- (This routine is modified from code by Eric Wilde) Read the humidity from one sensor (e.g. the AAG TAI8540x). Log the temperature value and relative humidity. Calculated using formula cribbed from the Dallas source code (gethumd.c), DS2438 data sheet and HIH-3610 data sheet. Sensors like the TAI8540x use a DS2438 battery monitor to sense temperature and convert humidity readings from a Honeywell HIH-3610. The DS2438 scratchpad is: Status/config = scratchpad[2] Temp LSB = scratchpad[3] Temp MSB = scratchpad[4] Voltage LSB = scratchpad[5] Voltage MSB = scratchpad[6] CRC = scratchpad[10] Temp LSB temp = (Temp MSB * 32) + -------- * 0.03125 8 The temperature is a two's complement signed number. voltage = ((Voltage MSB * 256) + Voltage LSB) / 100 There are two voltages that must be read to get an accurate humidity reading. The supply voltage (VDD) is read to determine what voltage the humidity sensor is running at (this affects the zero offset and slope of the humidity curve). The sensor voltage (VAD) is read to get the humidity value. Here is the formula for the humidity (temperature and voltage compensated): ((VAD/VDD) - 0.16) * 161.29 humidity = --------------------------- 1.0546 - (0.00216 * temp) The humidity sensor is linear from approx 10% to 100% R.H. Accuracy is approx 2%. !!!! Not Finished !!!! ----------------------------------------------------------------------- */ int read_humidity( int sensor_family, int sensor ) { double temp_c; /* Converted temperature in degrees C */ float sup_voltage, /* Supply voltage in volts */ hum_voltage, /* Humidity sensor voltage in volts */ humidity; /* Calculated humidity in %RH */ unsigned char TempSN[8]; int solar_rad; int try; for( try = 0; try < MAX_READ_TRIES; try++ ) { /* Read Vdd, the supply voltage */ if( (sup_voltage = Volt_Reading(0, 1)) != -1.0 ) { /* Read A/D reading from the humidity sensor */ if( (hum_voltage = Volt_Reading(0, 0)) != -1.0 ) { /* Read the solar radiation */ solar_rad = Get_Current(0); /* Read the temperature */ temp_c = Get_Temperature(0); /* Convert the measured voltage to humidity */ humidity = (((hum_voltage/sup_voltage) - 0.16) * 161.29) / (1.0546 - (0.00216 * temp_c)); if( humidity > 100.0 ) humidity = 100.0; else if( humidity < 0.0 ) humidity = 0.0; /* Log the temperature and humidity */ owSerialNum( 0, &TempSN[0], TRUE ); log_humidity( sensor, temp_c, solar_rad, humidity, TempSN ); /* Good conversion finished */ return TRUE; } } owTouchReset(0); msDelay(read_time); } return FALSE; } /* ----------------------------------------------------------------------- Read the DS1923 Hygrochton Temperature/Humidity Logger ----------------------------------------------------------------------- */ int read_temperature_DS1923( int sensor_family, int sensor ) { unsigned char TempSN[8], block2[2]; int try; /* Number of tries at reading device */ int b; int pre_t; float temp_c; int ival; float adval; float humidity; for( try = 0; try < MAX_READ_TRIES; try++ ) { if( owAccess(0) ) { /* Force Conversion */ if( !owWriteByte( 0, 0x55 ) || !owWriteByte( 0, 0x55 )) { return FALSE; } /* TODO CRC checking and read the addresses 020Ch to 020Fh (results)i * and the Device Sample Counter at address 0223h to 0225h. * If the count has incremented, the command was executed successfully. */ /* Sleep for conversion (spec says it takes max 666ms */ /* Q. Is it possible to poll? */ msDelay( 666 ); /* Now read the memory 0x20C:0x020F */ if( owAccess(0) ) { if( !owWriteByte( 0, 0x69 ) ) { return FALSE; } /* "Latest Temp" in the memory */ block2[0] = 0x0c; block2[1] = 0x02; /* Send the block */ if( owBlock( 0, FALSE, block2, 2 ) ) { if (block2[0] != 0x0c && block2[1] != 0x02) return FALSE; /* Send dummy password */ for(b = 0; b < 8; ++b) { owWriteByte(0, 0x04); } /* Read the temperature */ block2[0] = owReadByte(0); block2[1] = owReadByte(0); pre_t = (block2[1]/2)-41; temp_c = 1.0f * pre_t + block2[0]/512.0f; /* Read the humidity */ block2[0] = owReadByte(0); block2[1] = owReadByte(0); ival = (block2[1]*256 + block2[0])/16; adval = 1.0f * ival * 5.02f/4096; humidity = (adval-0.958f) / 0.0307f; /* Log the temperature and humidity */ /* TUTAJ masz wartosci we floatach dla Thermochrona sensor to nr sensora z pliku konfiguracyjnego, a tempsn to pewnie id urzadzenia 1wire */ owSerialNum( 0, &TempSN[0], TRUE ); log_humidity( sensor, temp_c, 0, humidity, TempSN ); /* Good conversion finished */ return TRUE; } /* Scratchpad Read */ } /* owAccess failed */ } /* owAccess failed */ /* Failed to read, rest the network, delay and try again */ owTouchReset(0); msDelay( read_time ); } /* for try < 3 */ /* Failed, no good reads after MAX_READ_TRIES */ return FALSE; } /* ----------------------------------------------------------------------- Select the indicated device, turning on any required couplers ----------------------------------------------------------------------- */ int read_device( struct _roms *sensor_list, int sensor ) { unsigned char TempSN[8], a[3]; int s, status = 0, sensor_family; struct _coupler *c_ptr; /* Coupler linked list */ /* Tell the sensor to do a temperature conversion */ /* Sort out how to address the sensor. If sensor < num_sensors then it can be directly addressed if sensor >= num_sensors then the coupler must first be addressed and the correct branch turned on. */ if( sensor < sensor_list->max ) { /* Address the sensor directly */ owSerialNum( 0, &sensor_list->roms[sensor*8], FALSE ); } else { /* Step through the coupler list until the right sensor is found. Sensors are in order. */ s = sensor - sensor_list->max; c_ptr = coupler_top; while( c_ptr ) { if( s < c_ptr->num_main ) { /* Found the right area */ /* Is this coupler & branch already on? */ if( !cmpSN( c_ptr->SN, Last2409, 0 ) ) { /* Turn on the main branch */ if(!SetSwitch1F(0, c_ptr->SN, DIRECT_MAIN_ON, 0, a, TRUE)) { printf("Setting Switch to Main ON state failed\n"); return FALSE; } /* Remember the last selected coupler & Branch */ memcpy( &Last2409, &c_ptr->SN, 8 ); Last2409[8] = 0; } /* Select the sensor */ owSerialNum( 0, &c_ptr->main[s*8], FALSE ); break; } else { s -= c_ptr->num_main; if( s < c_ptr->num_aux ) { /* Found the right area */ /* Is this coupler & branch already on? */ if( !cmpSN( c_ptr->SN, Last2409, 1 ) ) { /* Turn on the aux branch */ if(!SetSwitch1F(0, c_ptr->SN, AUXILARY_ON, 2, a, TRUE)) { printf("Setting Switch to Aux ON state failed\n"); return FALSE; } /* Remember the last selected coupler & Branch */ memcpy( &Last2409, &c_ptr->SN, 8 ); Last2409[8] = 1; } /* Last2409 check */ /* Select the sensor */ owSerialNum( 0, &c_ptr->aux[s*8], FALSE ); break; } } s -= c_ptr->num_aux; c_ptr = c_ptr->next; } } /* Get the Serial # selected */ owSerialNum( 0, &TempSN[0], TRUE ); sensor_family = TempSN[0]; switch( sensor_family ) { case DS1820_FAMILY: case DS1822_FAMILY: case DS18B20_FAMILY: status = read_temperature( sensor_family, sensor ); break; case DS1923_FAMILY: status = read_temperature_DS1923( sensor_family, sensor ); break; case DS2422_FAMILY: case DS2423_FAMILY: status = read_counter( sensor_family, sensor ); break; case DS2438_FAMILY: if( opts & OPT_DS2438 ) { status = read_ds2438( sensor_family, sensor ); } else { status = read_humidity( sensor_family, sensor ); } break; } return status; } /* ----------------------------------------------------------------------- Read the temperaturess for all the connected sensors Step through all the sensors in the list of serial numbers ----------------------------------------------------------------------- */ int read_all( struct _roms *sensor_list ) { int x; for( x = 0; x < (num_cs+sensor_list->max); x++ ) { read_device( sensor_list, x ); } return 0; } /* ----------------------------------------------------------------------- Read a .digitemprc file from the current directory The rc file contains: TTY LOG READ_TIME