1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
18 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
22 // Except as contained in this notice, the name of Dallas Semiconductor
23 // shall not be used except as stated in the Dallas Semiconductor
25 //---------------------------------------------------------------------------
27 // thermo21.c - Thermochron iButton utility functions
32 // 1.03 -> 2.00 Reorganization of Public Domain Kit
33 // Convert to global CRC utility functions
42 // a hack for sdcc/TINI, just printf to stdout
43 int fprintf (FILE *fp, char *format, ...) reentrant {
45 *fp; // hush the compiler
46 va_start(arg, format);
47 vsprintf(NULL, format, arg);
51 FILE * fopen(char * path, char *mode) {
52 path, mode; //hush the compiler
56 int fclose(FILE *fp) {
57 fp; // hust the compiler
61 static int RunThermoScript(int,ThermoStateType *,ThermoScript script[], FILE *fp);
62 static int ThermoStep(int,ThermoStateType *,ThermoScript *,int *,int *,int *,char *);
63 static int ReadPages(int,int,int,int *,uchar *);
64 static int WriteScratch(int,uchar *,int,int);
65 static int CopyScratch(int,int,int);
66 static int WriteMemory(int,uchar *, int, int);
69 enum { ST_SETUP=0, ST_READ_STATUS, ST_READ_ALARM, ST_READ_HIST,
70 ST_READ_LOG, ST_CLEAR_MEM, ST_CLEAR_VERIFY, ST_WRITE_TIME,
71 ST_WRITE_CONTROL, ST_WRITE_RATE, ST_FINISH, ST_GET_SESSION,
72 ST_FIND_THERMO, ST_REL_SESSION, ST_READ_PAGES, ST_WRITE_MEM,
76 enum { STATUS_STEP_COMPLETE, STATUS_COMPLETE, STATUS_INPROGRESS,
77 STATUS_ERROR_HALT, STATUS_ERROR_TRANSIENT };
80 static ThermoScript Download[] =
81 {{ ST_READ_STATUS, "Setup to read the mission status"},
82 { ST_READ_PAGES, "Read the status page"},
83 { ST_READ_ALARM, "Setup to read alarm pages"},
84 { ST_READ_PAGES, "Read the alarm pages"},
85 { ST_READ_HIST, "Setup to read histogram pages"},
86 { ST_READ_PAGES, "Read the histogram pages"},
87 { ST_READ_LOG, "Setup to read log pages"},
88 { ST_READ_PAGES, "Read the log pages"},
89 { ST_FINISH, "Finished"}};
91 // read status only steps
92 static ThermoScript GetStatus[] =
93 {{ ST_READ_STATUS, "Setup to read the mission status"},
94 { ST_READ_PAGES, "Read the status page"},
95 { ST_FINISH, "Finished"}};
97 // mission steps (assume already did StatusThermo)
98 static ThermoScript Mission[] =
99 {{ ST_CLEAR_SETUP, "Setup clear memory"},
100 { ST_WRITE_MEM, "Write clear memory bit"},
101 { ST_CLEAR_MEM, "Clear the memory"},
102 { ST_READ_STATUS, "Setup to read the mission status"},
103 { ST_READ_PAGES, "Read the status page"},
104 { ST_CLEAR_VERIFY, "Verify memory is clear"},
105 { ST_WRITE_TIME, "Setup to write the real time clock"},
106 { ST_WRITE_MEM, "Write the real time clock"},
107 { ST_WRITE_CONTROL,"Setup to write the control"},
108 { ST_WRITE_MEM, "Write the control"},
109 { ST_WRITE_RATE, "Setup to write the sample rate to start mission"},
110 { ST_WRITE_MEM, "Write the sample rate"},
111 { ST_READ_STATUS, "Read the new mission status"},
112 { ST_FINISH, "Finished"}};
114 // global state information
115 static int current_speed[MAX_PORTNUM];
117 //--------------------------------------------------------------------------
118 // The 'DownloadThermo' downloads the specified Thermochron in 'SerialNum'
119 // and puts the data in the state variable 'ThermoState'. Progress output
120 // is printed to the specified file 'fp'.
122 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
123 // indicate the symbolic port number.
124 // 'SerialNum' - Device serial number to download
125 // 'ThermoState' - pointer to a structure type that holds the raw and
126 // translated Thermochron data.
127 // 'fp' - file pointer to print status information to
129 // Returns: TRUE (1) : Thermochron download with raw data in ThermoState
130 // FALSE (0): not downloaded. Abort due to repeated errors
133 int DownloadThermo(int portnum, uchar *SerialNum,
134 ThermoStateType *ThermoState, FILE *fp)
136 // set the serial num
137 owSerialNum(portnum, SerialNum, FALSE);
139 // run the script and download thermochron
140 return RunThermoScript(portnum,ThermoState,Download,fp);
143 //--------------------------------------------------------------------------
144 // The 'ReadThermoStatus' reads the Thermochron status in 'SerialNum'
145 // and puts the data in the state variable 'ThermoState'. Progress output
146 // is printed to the specified file 'fp'.
148 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
149 // indicate the symbolic port number.
150 // 'SerialNum' - Device serial number to download
151 // 'ThermoState' - pointer to a structure type that holds the raw and
152 // translated Thermochron data.
153 // 'fp' - file pointer to print status information to
155 // Returns: TRUE (1) : Thermochron status read with raw data in ThermoState
156 // FALSE (0): status not read. Abort due to repeated errors
159 int ReadThermoStatus(int portnum, uchar *SerialNum,
160 ThermoStateType *ThermoState, FILE *fp)
162 // set the serial num
163 owSerialNum(portnum, SerialNum, FALSE);
165 // run the script and read status of thermochron
166 return RunThermoScript(portnum,ThermoState,GetStatus,fp);
169 //--------------------------------------------------------------------------
170 // The 'MissionThermo' starts a new Thermochron mission on 'SerialNum'
171 // from the state information provided in 'ThermoState'. Progress output
172 // is printed to the specified file 'fp'.
174 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
175 // indicate the symbolic port number.
176 // 'SerialNum' - Device serial number to download
177 // 'ThermoState' - pointer to a structure type that holds the raw and
178 // translated Thermochron data.
179 // 'fp' - file pointer to print status information to
181 // Returns: TRUE (1) : Thermochron missioned
182 // FALSE (0): not missioned. Abort due to repeated errors
185 int MissionThermo(int portnum, uchar *SerialNum,
186 ThermoStateType *ThermoState, FILE *fp)
188 // set the serial num
189 owSerialNum(portnum, SerialNum, FALSE);
191 // run the script and mission thermochron
192 return RunThermoScript(portnum,ThermoState,Mission,fp);
195 //--------------------------------------------------------------------------
196 // Run the specified script. Return TRUE if all steps completed else FALSE.
197 // Status is printed to file 'fp'.
199 int RunThermoScript(int portnum, ThermoStateType *ThermoState,
200 ThermoScript script[], FILE *fp)
202 char msg[256],LastDescription[256],LastMsg[256];
203 int StepCount,SubStep,ErrorCount,Status;
204 int last_clear_step=0;
206 // reset the step to the begining
210 Status = STATUS_INPROGRESS;
212 // loop to perform all of the steps to download the Thermochron
215 // switch on the status of the last step done
218 // step complete so go to the next
219 case STATUS_STEP_COMPLETE:
223 Status = STATUS_INPROGRESS;
224 LastDescription[0] = 0;
227 // in progress so call again
228 case STATUS_INPROGRESS:
229 // record the step position of the last memory clear
230 // this is in case we need to attempt a clear again
231 if (script[StepCount].Step == ST_CLEAR_SETUP)
232 last_clear_step = StepCount;
234 // print step description if different
235 if (strcmp(LastDescription,
236 script[StepCount].StepDescription) != 0)
238 fprintf(fp,"%s --> ",script[StepCount].StepDescription);
239 sprintf(LastDescription,"%s",script[StepCount].StepDescription);
242 // perform a step in the job
243 ThermoStep(portnum,ThermoState,&script[StepCount],&SubStep,
244 &Status, &ErrorCount, msg);
246 // print results if different
247 if (strcmp(LastMsg,msg) != 0)
249 fprintf(fp,"%s\n",msg);
250 sprintf(LastMsg,"%s",msg);
255 // encountered a transient error
256 case STATUS_ERROR_TRANSIENT:
257 // check if transient error is a memory clear
258 if (script[StepCount].Step == ST_CLEAR_VERIFY)
260 // put back to starting clear over again
261 StepCount = last_clear_step;
264 Status = STATUS_INPROGRESS;
267 // if 20 tansient errors in a row then abort
269 Status = STATUS_ERROR_HALT;
271 Status = STATUS_INPROGRESS;
273 // all steps complete
274 case STATUS_COMPLETE:
275 fprintf(fp,"End script normally\n");
278 // non-recoverable error
279 case STATUS_ERROR_HALT:
280 fprintf(fp,"Aborting script due to non-recoverable error\n");
285 while (!Serial0CharArrived());
288 fprintf(fp,"Aborting script due to key press\n");
292 //----------------------------------------------------------------------
293 // Use the script to perform a step and return.
295 int ThermoStep(int portnum, ThermoStateType *ThermoState,
296 ThermoScript *StateScript, int *SubStep,
297 int *Status, int *ErrorCount, char *msg)
300 static int read_page_num, read_pages, write_addr, write_len;
301 static uchar *read_buf, *write_buf;
302 static uchar tbuf[5];
304 ErrorCount; // hush the compiler
306 // do the current step
307 switch (StateScript->Step)
309 // the operation is complete
311 sprintf(msg,"Operation complete");
312 *Status = STATUS_COMPLETE;
315 // read the mission status page
317 read_page_num = STATUS_PAGE;
319 read_buf = ThermoState->MissStat.status_raw;
320 sprintf(msg,"Ready to read status page %d",
322 *Status = STATUS_STEP_COMPLETE;
325 // set up to read the alarm registers
329 read_buf = ThermoState->AlarmData.alarm_raw;
330 sprintf(msg,"Ready to read alarm pages %d to %d",
331 read_page_num, read_page_num + read_pages - 1);
332 *Status = STATUS_STEP_COMPLETE;
335 // set up to read the histogram data
339 read_buf = ThermoState->HistData.hist_raw;
340 sprintf(msg,"Ready to read histogram pages %d to %d",
341 read_page_num, read_page_num + read_pages - 1);
342 *Status = STATUS_STEP_COMPLETE;
345 // set up to read the log data
349 read_buf = ThermoState->LogData.log_raw;
350 sprintf(msg,"Ready to read log pages %d to %d",
351 read_page_num, read_page_num + read_pages - 1);
352 *Status = STATUS_STEP_COMPLETE;
355 // read the specified pages
357 // check for last page
359 // set the sub-step to the current page being read
360 *SubStep = read_page_num;
361 // read the status page
362 rslt = ReadPages(portnum, read_page_num, read_pages, SubStep, read_buf);
365 sprintf(msg,"Thermochron not on 1-Wire Net");
366 *Status = STATUS_INPROGRESS;
370 sprintf(msg,"Pages read from Thermochron");
371 *Status = STATUS_STEP_COMPLETE;
375 // setup the clear memory
377 // create a small buff to write to start the clear memory
379 write_buf = &tbuf[0];
382 sprintf(msg,"Write to setup clear memory");
383 *Status = STATUS_STEP_COMPLETE;
388 // set the clear memory command (not check return because verify)
390 owWriteByte(portnum,0x3C);
392 owTouchReset(portnum);
393 sprintf(msg,"Clear memory command sent");
394 *Status = STATUS_STEP_COMPLETE;
398 case ST_CLEAR_VERIFY:
399 // look at the memory clear bit
400 if ((ThermoState->MissStat.status_raw[0x14] & 0x40) == 0x40)
402 sprintf(msg,"Memory is clear");
403 *Status = STATUS_STEP_COMPLETE;
408 sprintf(msg,"Memory did NOT clear");
409 *Status = STATUS_ERROR_TRANSIENT;
414 // setup write time, clock alarm, control, trips
416 // create the write buffer
417 FormatMission(&ThermoState->MissStat);
418 write_buf = &ThermoState->MissStat.status_raw[0x00];
421 sprintf(msg,"Write time, clock alarm, and trips setup");
422 *Status = STATUS_STEP_COMPLETE;
425 // write the control, mission delay and clear flags
426 case ST_WRITE_CONTROL:
427 write_buf = &ThermoState->MissStat.status_raw[0x0E];
430 sprintf(msg,"Write control, mission delay, clear flags setup");
431 *Status = STATUS_STEP_COMPLETE;
435 write_buf = &ThermoState->MissStat.status_raw[0x0D];
438 sprintf(msg,"Write sample rate setup");
439 *Status = STATUS_STEP_COMPLETE;
442 // write the specified memory location
444 if (WriteMemory(portnum, write_buf, write_len, write_addr))
446 sprintf(msg,"Memory written to Thermochron");
447 *Status = STATUS_STEP_COMPLETE;
451 sprintf(msg,"Thermochron not on 1-Wire Net");
452 *Status = STATUS_INPROGRESS;
461 //----------------------------------------------------------------------
462 // Read a specified number of pages in overdrive
464 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
465 // indicate the symbolic port number.
467 int ReadPages(int portnum, int start_pg, int num_pgs, int *last_pg, uchar *finalbuf)
469 int skip_overaccess = 0, skip_access = 0;
472 uchar SerialNumber[8];
475 // read the rom number
476 owSerialNum(portnum,SerialNumber,TRUE);
478 // verify device is in overdrive
479 if (current_speed[portnum] == MODE_OVERDRIVE)
481 if (owVerify(portnum,FALSE))
485 if (!skip_overaccess)
487 if (owOverdriveAccess(portnum))
488 current_speed[portnum] = MODE_OVERDRIVE;
490 current_speed[portnum] = MODE_NORMAL;
493 // loop while there is pages to read
496 // create a packet to read a page
499 // optional skip access on subsequent pages
505 for (i = 0; i < 8; i++)
506 pkt[len++] = SerialNumber[i];
507 // read memory with crc command
509 docrc16(portnum,pkt[len++]);
511 pkt[len] = (uchar)((*last_pg << 5) & 0xFF);
512 docrc16(portnum,pkt[len++]);
513 pkt[len] = (uchar)(*last_pg >> 3);
514 docrc16(portnum,pkt[len++]);
517 // set 32 reads for data and 2 for crc
518 for (i = 0; i < 34; i++)
522 if (owBlock(portnum,!skip_access,pkt,len))
524 // calucate the CRC over the last 34 bytes
525 for (i = 0; i < 34; i++)
526 lastcrc16 = docrc16(portnum,pkt[len - 34 + i]);
529 if (lastcrc16 == 0xB001)
531 // copy the data into the buffer
532 #ifdef LetsCrashTheCompiler
533 for (i = 0; i < 32; i++)
534 finalbuf[i + (*last_pg - start_pg) * 32] = pkt[len - 34 + i];
538 for (i = 0; i < 32; i++) {
539 k=i + (*last_pg - start_pg) * 32;
540 finalbuf[k] = pkt[len - 34 + i];
543 // change number of pages
544 *last_pg = *last_pg + 1;
555 while ((*last_pg - start_pg) < num_pgs);
560 //----------------------------------------------------------------------------}
561 // Write a memory location. Data must all be on the same page
563 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
564 // indicate the symbolic port number.
566 int WriteMemory(int portnum, uchar *Buf, int ln, int adr)
568 // write to scratch and then copy
569 if (WriteScratch(portnum,Buf,ln,adr))
570 return CopyScratch(portnum,ln,adr);
575 //----------------------------------------------------------------------------}
576 // Write the scratch pad
578 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
579 // indicate the symbolic port number.
581 int WriteScratch(int portnum, uchar *Buf, int ln, int adr)
586 // check for alarm indicator
587 if (owAccess(portnum))
589 // construct a packet to send
590 pbuf[0] = 0x0F; // write scratch command
591 pbuf[1] = (adr & 0xFF); // address 1
592 pbuf[2] = ((adr >> 8) & 0xFF); // address 2
595 for (i = 0; i < ln; i++)
596 pbuf[3 + i] = (uchar)(Buf[i]); // data
599 if (!owBlock(portnum,FALSE,pbuf,ln+3))
602 // Now read back the scratch
603 if (owAccess(portnum))
605 // construct a packet to send
606 pbuf[0] = 0xAA; // read scratch command
607 pbuf[1] = 0xFF; // address 1
608 pbuf[2] = 0xFF; // address 2
609 pbuf[3] = 0xFF; // offset
612 for (i = 0; i < ln; i++)
613 pbuf[4 + i] = 0xFF; // data
616 if (!owBlock(portnum,FALSE,pbuf,ln+4))
620 if (pbuf[1] != (adr & 0xFF))
623 if (pbuf[2] != ((adr >> 8) & 0xFF))
626 if (pbuf[3] != ((adr + ln - 1) & 0x1F))
628 // read and compare the contents
629 for (i = 0; i < ln; i++)
631 if (pbuf[4 + i] != Buf[i])
643 //----------------------------------------------------------------------------}
644 // Copy the scratch pad
646 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
647 // indicate the symbolic port number.
649 int CopyScratch(int portnum, int ln, int adr)
654 // check for alarm indicator
655 if (owAccess(portnum))
657 // construct a packet to send
658 pbuf[0] = 0x55; // copy scratch command
659 pbuf[1] = (adr & 0xFF); // address 1
660 pbuf[2] = ((adr >> 8) & 0xFF); // address 2
661 pbuf[3] = (adr + ln - 1) & 0x1F; // offset
662 for (i = 0; i <= 9; i++)
663 pbuf[4 + i] = 0xFF; // result of copy
666 if (owBlock(portnum,FALSE,pbuf,14))
668 if ((pbuf[13] == 0x55) ||
677 //----------------------------------------------------------------------
678 // Interpret the Status by looking at the 'raw' portion of the
679 // mission status structure.
681 void InterpretStatus(MissionStatus *mstatus)
689 // mission in progress flag
690 mstatus->mission_in_progress = (0x20 & mstatus->status_raw[0x14]) >> 5;
693 mstatus->sample_rate = mstatus->status_raw[0x0D];
696 mstatus->rollover_enable = (0x08 & mstatus->status_raw[0x0E]) >> 3;
699 mstatus->start_delay = ((int)mstatus->status_raw[0x13] << 8) |
700 mstatus->status_raw[0x12];
702 // number of samples in this mission
703 mstatus->mission_samples = ((long)mstatus->status_raw[0x1C] << 16) |
704 ((int)mstatus->status_raw[0x1B] << 8) |
705 mstatus->status_raw[0x1A];
707 // total number of samples
708 mstatus->samples_total = ((long)mstatus->status_raw[0x1F] << 16) |
709 ((int)mstatus->status_raw[0x1E] << 8) |
710 mstatus->status_raw[0x1D];
712 // temperature thresholds
713 mstatus->high_threshold = mstatus->status_raw[0x0C];
714 mstatus->low_threshold = mstatus->status_raw[0x0B];
717 if ((mstatus->mission_samples > 2048) && mstatus->rollover_enable)
718 mstatus->rollover_occurred = 1;
720 mstatus->rollover_occurred = 0;
722 // current real-time clock value
724 td.second = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
725 td.minute = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x7F));
726 // check for 12 hour mode
727 if (mstatus->status_raw[offset + 2] & 0x40)
729 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x1F));
731 if (mstatus->status_raw[offset + 2] & 0x20)
735 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
736 td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 4] & 0x3F));
737 td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 5] & 0x1F));
738 td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 1900;
739 // check for century bit
740 if (mstatus->status_raw[offset + 5] & 0x80)
741 td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 2000; // (2.00)
742 // convert to seconds since 1970
743 mstatus->current_time = DateToSeconds(&td);
745 // date/time when mission started
747 td.second = (uchar)0;
748 td.minute = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
749 // check for 12 hour mode
750 if (mstatus->status_raw[offset + 1] & 0x40)
752 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x1F));
754 if (mstatus->status_raw[offset + 1] & 0x20)
758 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x3F));
759 td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
760 td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 3] & 0x1F));
761 td.year = BCDToBin((uchar)(mstatus->status_raw[offset + 4])); // (2.00)
762 // (2.00) logic to decide on century of mission stamp
763 // check if century bit set in mission stamp
764 if (mstatus->status_raw[offset + 3] & 0x80)
766 // check in mission in progress
767 else if (mstatus->mission_in_progress)
769 // calculate the mission start year back from real time clock
770 tmtmp = mstatus->current_time -
771 (mstatus->sample_rate * mstatus->mission_samples * 60);
772 SecondsToDate(&tdtmp,tmtmp);
773 td.year = tdtmp.year;
777 // mission stopped so get century by year window
783 // convert to seconds since 1970
784 if ((td.month == 0) || (td.day == 0))
785 mstatus->mission_start_time = 0;
787 mstatus->mission_start_time = DateToSeconds(&td);
789 // download stations time of reading
791 tstruct = localtime(&tlong);
792 td.day = tstruct->tm_mday;
793 td.month = tstruct->tm_mon + 1; // (1.01)
794 td.year = tstruct->tm_year + 1900;
795 td.hour = tstruct->tm_hour;
796 td.minute = tstruct->tm_min;
797 td.second = tstruct->tm_sec;
798 mstatus->download_time = DateToSeconds(&td);
800 // skip alarm modes and status for now
803 //--------------------------------------------------------------------------
804 // Take the Mission Status structure and create new raw data to start
807 void FormatMission(MissionStatus *mstatus)
814 for (i = 0; i < 32; i++)
815 mstatus->status_raw[i] = 0;
819 tlong++; // add 1 second
820 tstruct = localtime(&tlong);
822 mstatus->status_raw[0x00] = ToBCD((short)tstruct->tm_sec);
823 mstatus->status_raw[0x01] = ToBCD((short)tstruct->tm_min);
824 mstatus->status_raw[0x02] = ToBCD((short)tstruct->tm_hour);
825 mstatus->status_raw[0x03] = ToBCD((short)(tstruct->tm_wday + 1));
826 mstatus->status_raw[0x04] = ToBCD((short)tstruct->tm_mday);
827 mstatus->status_raw[0x05] = ToBCD((short)(tstruct->tm_mon + 1));
828 if (tstruct->tm_year >= 100)
829 mstatus->status_raw[0x05] |= 0x80;
830 mstatus->status_raw[0x06] = ToBCD((short)(tstruct->tm_year % 100));
831 // Real Time clock Alarm (leave 0's)
833 mstatus->status_raw[0x0B] = mstatus->low_threshold;
835 mstatus->status_raw[0x0C] = mstatus->high_threshold;
837 mstatus->status_raw[0x0D] = mstatus->sample_rate;
839 mstatus->status_raw[0x0E] = 0x40;
840 if (mstatus->rollover_enable)
841 mstatus->status_raw[0x0E] |= 0x08;
842 // mission start delay
843 mstatus->status_raw[0x12] = mstatus->start_delay & 0xFF;
844 mstatus->status_raw[0x13] = (mstatus->start_delay >> 8) & 0xFF;
847 //--------------------------------------------------------------------------
848 // Convert an integer to a 1 Byte BCD number (99 max)
850 uchar ToBCD(short num)
854 rtbyte = (num - ((num / 10) * 10)) & 0x0F;
855 rtbyte = rtbyte | ((num / 10) << 4);
861 //--------------------------------------------------------------------------
862 // Take the Mission Status structure and convert to string format
864 void MissionStatusToString(MissionStatus *mstatus, int ConvertToF, char *str)
872 cnt += sprintf(&str[cnt],"Mission State\n-------------\n");
875 cnt += sprintf(&str[cnt],"Serial Number of DS1921: ");
876 for (i = 7; i >= 0; i--)
877 cnt += sprintf(&str[cnt],"%02X",mstatus->serial_num[i]);
880 if (mstatus->mission_in_progress)
881 cnt += sprintf(&str[cnt],"\nMission is in progress\n");
883 cnt += sprintf(&str[cnt],"\nMission is ended\n");
886 cnt += sprintf(&str[cnt],"Sample rate: %d minute(s)\n",mstatus->sample_rate);
889 cnt += sprintf(&str[cnt],"Roll-Over Enabled: ");
890 if (mstatus->rollover_enable)
891 cnt += sprintf(&str[cnt],"yes\n");
893 cnt += sprintf(&str[cnt],"no\n");
894 cnt += sprintf(&str[cnt],"Roll-Over Occurred: ");
895 if (mstatus->rollover_occurred)
896 cnt += sprintf(&str[cnt],"yes\n");
898 cnt += sprintf(&str[cnt],"no\n");
900 // mission start time
901 if (mstatus->start_delay == 0)
903 SecondsToDate(&td,mstatus->mission_start_time);
904 if (mstatus->mission_start_time == 0)
905 cnt += sprintf(&str[cnt],"Mission Start time: not started yet\n");
907 cnt += sprintf(&str[cnt],"Mission Start time: %02d/%02d/%04d %02d:%02d:%02d\n",
908 td.month,td.day,td.year,td.hour,td.minute,td.second);
911 cnt += sprintf(&str[cnt],"Mission Start time: na\n");
913 // mission start delay
914 cnt += sprintf(&str[cnt],"Mission Start delay: %d minute(s)\n",mstatus->start_delay);
917 cnt += sprintf(&str[cnt],"Mission Samples: %d\n",mstatus->mission_samples);
919 // device total samples
920 cnt += sprintf(&str[cnt],"Device total samples: %d\n",mstatus->samples_total);
922 // temperature display mode
923 cnt += sprintf(&str[cnt],"Temperature displayed in: ");
925 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
927 cnt += sprintf(&str[cnt],"(Celsius)\n");
930 cnt += sprintf(&str[cnt],"High Threshold: %6.1f\n",
931 TempToFloat(mstatus->high_threshold,ConvertToF));
932 cnt += sprintf(&str[cnt],"Low Threshold: %6.1f\n",
933 TempToFloat(mstatus->low_threshold,ConvertToF));
936 SecondsToDate(&td,mstatus->current_time);
937 cnt += sprintf(&str[cnt],"Current Real-Time Clock from DS1921: %02d/%02d/%04d %02d:%02d:%02d\n",
938 td.month,td.day,td.year,td.hour,td.minute,td.second);
942 tstruct = localtime(&tlong);
943 cnt += sprintf(&str[cnt],"Current PC Time: %02d/%02d/%04d %02d:%02d:%02d\n",
944 tstruct->tm_mon + 1,tstruct->tm_mday,tstruct->tm_year + 1900,
945 tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec);
947 // zero terminate string
951 //----------------------------------------------------------------------
952 // Interpret the Histogram by looking at the 'raw' portion of the
953 // Histogram structure. Store the temperature range values in Celsius.
955 void InterpretHistogram(Histogram *hist)
959 // loop through each bin value
960 for (i = 0; i < 126; i += 2) // (2.00)
963 hist->bin_count[i / 2] = hist->hist_raw[i] | ((int)hist->hist_raw[i + 1] << 8);
965 // start value for this bin
966 hist->start_range[i / 2] = TempToFloat((uchar)((i / 2) << 2),FALSE);
968 // end value for this bin
969 hist->end_range[i / 2] = TempToFloat((uchar)(((i / 2) << 2) | 0x03),FALSE);
973 //--------------------------------------------------------------------------
974 // Take the Histogram structure and convert to string format
976 void HistogramToString(Histogram *hist, int ConvertToF, char *str)
981 cnt += sprintf(&str[cnt],"Temperature Histogram\n---------------------\n"
982 "Format: [Temp Range, Count] ");
984 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
986 cnt += sprintf(&str[cnt],"(Celsius)\n");
989 for (i = 0; i < 63; i++) // (2.00)
991 cnt += sprintf(&str[cnt],"%6.1f to %6.1f, %d\n",
992 (ConvertToF) ? CToF(hist->start_range[i]): hist->start_range[i],
993 (ConvertToF) ? CToF(hist->end_range[i]): hist->end_range[i],
997 // zero terminate string
1001 //----------------------------------------------------------------------
1002 // Interpret the Temperature Alarm Event data by looking at the 'raw'
1003 // portion of the TempAlarmEvents structure. Mission Status is needed
1004 // to interpret the events.
1006 void InterpretAlarms(TempAlarmEvents *alarm, MissionStatus *mstatus)
1009 ulong event_mission_count;
1014 for (i = 0; i < 48; i += 4)
1016 // get the mission start count of this event
1017 event_mission_count = ((long)alarm->alarm_raw[i + 2] << 16) |
1018 ((int)alarm->alarm_raw[i + 1] << 8) |
1019 alarm->alarm_raw[i];
1021 // check if done with low events
1022 if (!event_mission_count)
1026 duration = alarm->alarm_raw[i + 3];
1028 // calculate the start time
1029 alarm->low_start_time[alarm->num_low] =
1030 mstatus->mission_start_time +
1031 (event_mission_count - 1) * (mstatus->sample_rate * 60);
1033 // calculate the end time
1034 alarm->low_end_time[alarm->num_low] =
1035 alarm->low_start_time[alarm->num_low] +
1036 (duration - 1) * (mstatus->sample_rate * 60);
1038 // increment number of low events
1043 alarm->num_high = 0;
1044 for (i = 48; i < 96; i += 4)
1046 // get the mission start count of this event
1047 event_mission_count = ((long)alarm->alarm_raw[i + 2] << 16) |
1048 ((int)alarm->alarm_raw[i + 1] << 8) |
1049 alarm->alarm_raw[i];
1051 // check if done with low events
1052 if (!event_mission_count)
1056 duration = alarm->alarm_raw[i + 3];
1058 // calculate the start time
1059 alarm->high_start_time[alarm->num_high] =
1060 mstatus->mission_start_time +
1061 (event_mission_count - 1) * (mstatus->sample_rate * 60);
1063 // calculate the end time
1064 alarm->high_end_time[alarm->num_high] =
1065 alarm->high_start_time[alarm->num_high] +
1066 (duration - 1) * (mstatus->sample_rate * 60);
1068 // increment number of low events
1073 //--------------------------------------------------------------------------
1074 // Take the Temperature Alarms Events structure and convert to string
1077 void AlarmsToString(TempAlarmEvents *alarm, char *str)
1083 cnt += sprintf(&str[cnt],"Temperature Alarms\n------------------\n"
1084 "Format: [(HIGH/LOW), Time/Date Range]\n");
1086 // loop through each low alarm
1087 for (i = 0; i < alarm->num_low; i++)
1089 cnt += sprintf(&str[cnt],"LOW , ");
1091 SecondsToDate(&td,alarm->low_start_time[i]);
1092 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d to ",
1093 td.month,td.day,td.year,td.hour,td.minute);
1095 SecondsToDate(&td,alarm->low_end_time[i]);
1096 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d\n",
1097 td.month,td.day,td.year,td.hour,td.minute);
1100 // loop through each high alarm
1101 for (i = 0; i < alarm->num_high; i++)
1103 cnt += sprintf(&str[cnt],"HIGH , ");
1105 SecondsToDate(&td,alarm->high_start_time[i]);
1106 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d to ",
1107 td.month,td.day,td.year,td.hour,td.minute);
1109 SecondsToDate(&td,alarm->high_end_time[i]);
1110 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d\n",
1111 td.month,td.day,td.year,td.hour,td.minute);
1114 // zero terminate string
1118 //----------------------------------------------------------------------
1119 // Interpret the Log data by looking at the 'raw'
1120 // portion of the Log structure. Mission Status is needed
1121 // to interpret when the logs occurred.
1123 void InterpretLog(Log *log, MissionStatus *mstatus)
1125 ulong loops=0,overlap=0,lastlog=2048,i;
1128 // check if wrap occurred
1129 if (mstatus->rollover_occurred)
1131 // calculate the number loops
1132 loops = (mstatus->mission_samples / 2048) - 1;
1133 // calculate the number of overlap
1134 overlap = mstatus->mission_samples % 2048;
1135 log->num_log = 2048;
1139 log->start_time = mstatus->mission_start_time;
1140 if (mstatus->mission_samples > 2048) // (1.02)
1143 lastlog = mstatus->mission_samples;
1144 log->num_log = (int)lastlog;
1148 log->interval = mstatus->sample_rate * 60;
1150 // caluclate the start time of the first log value
1151 log->start_time = mstatus->mission_start_time +
1152 loops * 2048 * log->interval + overlap * log->interval;
1154 // loop to fill in the remainder first
1155 for (i = overlap; i < lastlog; i++)
1156 log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1158 // loop to get the overlap
1159 for (i = 0; i < overlap; i++)
1160 log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1163 //--------------------------------------------------------------------------
1164 // Take the Log structure and convert to string
1167 void LogToString(Log *log, int ConvertToF, char *str)
1174 cnt += sprintf(&str[cnt],"Log Data\n--------\n"
1175 "Format: [Time/Date , Temperature] ");
1177 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1179 cnt += sprintf(&str[cnt],"(Celsius)\n");
1181 // loop through the logs
1182 logtime = log->start_time;
1183 for (i = 0; i < log->num_log; i++)
1186 SecondsToDate(&td,logtime);
1187 cnt += sprintf(&str[cnt],"%02d/%02d/%04d %02d:%02d ,",
1188 td.month,td.day,td.year,td.hour,td.minute);
1190 cnt += sprintf(&str[cnt],"%6.1f\n",
1191 (ConvertToF) ? CToF(log->temp[i]): log->temp[i]);
1193 // increment the time
1194 logtime += log->interval;
1197 // zero terminate string
1201 //--------------------------------------------------------------------------
1202 // Convert the raw debug data to a string
1204 void DebugToString(MissionStatus *mstatus, TempAlarmEvents *alarm,
1205 Histogram *hist, Log *log, char *str)
1210 cnt += sprintf(&str[cnt],"Debug Dump\n----------\nRegister Page:\n");
1213 for (i = 0; i < 32; i++)
1215 cnt += sprintf(&str[cnt],"%02X ",mstatus->status_raw[i]);
1216 if (i && (((i + 1) % 16) == 0))
1217 cnt += sprintf(&str[cnt],"\n");
1221 cnt += sprintf(&str[cnt],"Alarms:\n");
1222 for (i = 0; i < 96; i++)
1224 cnt += sprintf(&str[cnt],"%02X ",alarm->alarm_raw[i]);
1225 if (i && (((i + 1) % 16) == 0))
1226 cnt += sprintf(&str[cnt],"\n");
1230 cnt += sprintf(&str[cnt],"Histogram:\n");
1231 for (i = 0; i < 128; i++)
1233 cnt += sprintf(&str[cnt],"%02X ",hist->hist_raw[i]);
1234 if (i && (((i + 1) % 16) == 0))
1235 cnt += sprintf(&str[cnt],"\n");
1240 cnt += sprintf(&str[cnt],"Log:\n");
1241 for (i = 0; i < ((log->num_log > 2048) ? 2048 : log->num_log); i++)
1243 cnt += sprintf(&str[cnt],"%02X ",log->log_raw[i]);
1244 if (i && (((i + 1) % 16) == 0))
1245 cnt += sprintf(&str[cnt],"\n");
1248 // zero terminate string
1252 //--------------------------------------------------------------------------
1253 // Take one byte BCD value and return binary value
1255 uchar BCDToBin(uchar bcd)
1257 return (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
1261 //--------------------------------------------------------------------------
1262 // Take a 4 byte long string and convert it into a timedata structure.
1264 static int dm[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,365 };
1266 void SecondsToDate(timedate *td, ulong x)
1271 // check to make sure date is not over 2070 (sanity check)
1272 if (x > 0xBBF81E00L)
1275 y = x/60; td->second = (ushort)(x-60*y);
1276 x = y/60; td->minute = (ushort)(y-60*x);
1277 y = x/24; td->hour = (ushort)(x-24*y);
1278 x = 4*(y+731); td->year = (ushort)(x/1461);
1279 i = (int)((x-1461*(ulong)(td->year))/4); td->month = 13;
1284 tmp = (td->month > 2) && ((td->year & 3)==0) ? 1 : 0;
1285 j = dm[td->month]+tmp;
1291 // slight adjustment to algorithm
1295 td->year = (td->year < 32) ? td->year + 68 + 1900: td->year - 32 + 2000;
1298 //--------------------------------------------------------------------------
1299 // DateToSeconds takes a time/date structure and converts it into the
1300 // number of seconds since 1970
1302 ulong DateToSeconds(timedate *td)
1306 // convert the date/time values into the 5 byte format used in the touch
1307 if (td->year >= 2000)
1308 Sv = td->year + 32 - 2000;
1310 Sv = td->year - 68 - 1900;
1312 if ((td->month > 2) && ( (Sv & 3) == 0))
1317 Xv = 365 * (Sv-2) + (Sv-1)/4 + dm[td->month] + td->day + Bv - 1;
1319 Xv = 86400 * Xv + (ulong)(td->second) + 60*((ulong)(td->minute) + 60*(ulong)(td->hour));
1324 //--------------------------------------------------------------------------
1325 // Convert from DS1921 termature format to a float
1328 float TempToFloat(uchar tmp, int ConvertToF)
1332 tfloat = (float)((tmp / 2.0) - 40.0);
1335 return (float)(tfloat * 9.0 / 5.0 + 32.0);
1340 //--------------------------------------------------------------------------
1341 // Convert from Celsius to Fahrenheit
1343 float CToF(float CVal)
1345 return (float)(CVal * 9.0 / 5.0 + 32.0);