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, xdata char *format, ...) reentrant {
45 *fp; // hush the compiler
46 va_start(arg, format);
47 vsprintf(NULL, format, arg);
51 static int RunThermoScript(int,ThermoStateType *,ThermoScript script[], FILE *fp);
52 static int ThermoStep(int,ThermoStateType *,ThermoScript *,int *,int *,int *,char *);
53 static int ReadPages(int,int,int,int *,uchar *);
54 static int WriteScratch(int,uchar *,int,int);
55 static int CopyScratch(int,int,int);
56 static int WriteMemory(int,uchar *, int, int);
59 enum { ST_SETUP=0, ST_READ_STATUS, ST_READ_ALARM, ST_READ_HIST,
60 ST_READ_LOG, ST_CLEAR_MEM, ST_CLEAR_VERIFY, ST_WRITE_TIME,
61 ST_WRITE_CONTROL, ST_WRITE_RATE, ST_FINISH, ST_GET_SESSION,
62 ST_FIND_THERMO, ST_REL_SESSION, ST_READ_PAGES, ST_WRITE_MEM,
66 enum { STATUS_STEP_COMPLETE, STATUS_COMPLETE, STATUS_INPROGRESS,
67 STATUS_ERROR_HALT, STATUS_ERROR_TRANSIENT };
70 static ThermoScript Download[] =
71 {{ ST_READ_STATUS, "Setup to read the mission status"},
72 { ST_READ_PAGES, "Read the status page"},
73 { ST_READ_ALARM, "Setup to read alarm pages"},
74 { ST_READ_PAGES, "Read the alarm pages"},
75 { ST_READ_HIST, "Setup to read histogram pages"},
76 { ST_READ_PAGES, "Read the histogram pages"},
77 { ST_READ_LOG, "Setup to read log pages"},
78 { ST_READ_PAGES, "Read the log pages"},
79 { ST_FINISH, "Finished"}};
81 // read status only steps
82 static ThermoScript GetStatus[] =
83 {{ ST_READ_STATUS, "Setup to read the mission status"},
84 { ST_READ_PAGES, "Read the status page"},
85 { ST_FINISH, "Finished"}};
87 // mission steps (assume already did StatusThermo)
88 static ThermoScript Mission[] =
89 {{ ST_CLEAR_SETUP, "Setup clear memory"},
90 { ST_WRITE_MEM, "Write clear memory bit"},
91 { ST_CLEAR_MEM, "Clear the memory"},
92 { ST_READ_STATUS, "Setup to read the mission status"},
93 { ST_READ_PAGES, "Read the status page"},
94 { ST_CLEAR_VERIFY, "Verify memory is clear"},
95 { ST_WRITE_TIME, "Setup to write the real time clock"},
96 { ST_WRITE_MEM, "Write the real time clock"},
97 { ST_WRITE_CONTROL,"Setup to write the control"},
98 { ST_WRITE_MEM, "Write the control"},
99 { ST_WRITE_RATE, "Setup to write the sample rate to start mission"},
100 { ST_WRITE_MEM, "Write the sample rate"},
101 { ST_READ_STATUS, "Read the new mission status"},
102 { ST_FINISH, "Finished"}};
104 // global state information
105 static int current_speed[MAX_PORTNUM];
107 //--------------------------------------------------------------------------
108 // The 'DownloadThermo' downloads the specified Thermochron in 'SerialNum'
109 // and puts the data in the state variable 'ThermoState'. Progress output
110 // is printed to the specified file 'fp'.
112 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
113 // indicate the symbolic port number.
114 // 'SerialNum' - Device serial number to download
115 // 'ThermoState' - pointer to a structure type that holds the raw and
116 // translated Thermochron data.
117 // 'fp' - file pointer to print status information to
119 // Returns: TRUE (1) : Thermochron download with raw data in ThermoState
120 // FALSE (0): not downloaded. Abort due to repeated errors
123 int DownloadThermo(int portnum, uchar *SerialNum,
124 ThermoStateType *ThermoState, FILE *fp)
126 // set the serial num
127 owSerialNum(portnum, SerialNum, FALSE);
129 // run the script and download thermochron
130 return RunThermoScript(portnum,ThermoState,Download,fp);
133 //--------------------------------------------------------------------------
134 // The 'ReadThermoStatus' reads the Thermochron status in 'SerialNum'
135 // and puts the data in the state variable 'ThermoState'. Progress output
136 // is printed to the specified file 'fp'.
138 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
139 // indicate the symbolic port number.
140 // 'SerialNum' - Device serial number to download
141 // 'ThermoState' - pointer to a structure type that holds the raw and
142 // translated Thermochron data.
143 // 'fp' - file pointer to print status information to
145 // Returns: TRUE (1) : Thermochron status read with raw data in ThermoState
146 // FALSE (0): status not read. Abort due to repeated errors
149 int ReadThermoStatus(int portnum, uchar *SerialNum,
150 ThermoStateType *ThermoState, FILE *fp)
152 // set the serial num
153 owSerialNum(portnum, SerialNum, FALSE);
155 // run the script and read status of thermochron
156 return RunThermoScript(portnum,ThermoState,GetStatus,fp);
159 //--------------------------------------------------------------------------
160 // The 'MissionThermo' starts a new Thermochron mission on 'SerialNum'
161 // from the state information provided in 'ThermoState'. Progress output
162 // is printed to the specified file 'fp'.
164 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
165 // indicate the symbolic port number.
166 // 'SerialNum' - Device serial number to download
167 // 'ThermoState' - pointer to a structure type that holds the raw and
168 // translated Thermochron data.
169 // 'fp' - file pointer to print status information to
171 // Returns: TRUE (1) : Thermochron missioned
172 // FALSE (0): not missioned. Abort due to repeated errors
175 int MissionThermo(int portnum, uchar *SerialNum,
176 ThermoStateType *ThermoState, FILE *fp)
178 // set the serial num
179 owSerialNum(portnum, SerialNum, FALSE);
181 // run the script and mission thermochron
182 return RunThermoScript(portnum,ThermoState,Mission,fp);
185 //--------------------------------------------------------------------------
186 // Run the specified script. Return TRUE if all steps completed else FALSE.
187 // Status is printed to file 'fp'.
189 int RunThermoScript(int portnum, ThermoStateType *ThermoState,
190 ThermoScript script[], FILE *fp)
192 char msg[256],LastDescription[256],LastMsg[256];
193 int StepCount,SubStep,ErrorCount,Status;
194 int last_clear_step=0;
196 // reset the step to the begining
200 Status = STATUS_INPROGRESS;
202 // loop to perform all of the steps to download the Thermochron
205 // switch on the status of the last step done
208 // step complete so go to the next
209 case STATUS_STEP_COMPLETE:
213 Status = STATUS_INPROGRESS;
214 LastDescription[0] = 0;
217 // in progress so call again
218 case STATUS_INPROGRESS:
219 // record the step position of the last memory clear
220 // this is in case we need to attempt a clear again
221 if (script[StepCount].Step == ST_CLEAR_SETUP)
222 last_clear_step = StepCount;
224 // print step description if different
225 if (strcmp(LastDescription,
226 script[StepCount].StepDescription) != 0)
228 fprintf(fp,"%s --> ",script[StepCount].StepDescription);
229 sprintf(LastDescription,"%s",script[StepCount].StepDescription);
232 // perform a step in the job
233 ThermoStep(portnum,ThermoState,&script[StepCount],&SubStep,
234 &Status, &ErrorCount, msg);
236 // print results if different
237 if (strcmp(LastMsg,msg) != 0)
239 fprintf(fp,"%s\n",msg);
240 sprintf(LastMsg,"%s",msg);
245 // encountered a transient error
246 case STATUS_ERROR_TRANSIENT:
247 // check if transient error is a memory clear
248 if (script[StepCount].Step == ST_CLEAR_VERIFY)
250 // put back to starting clear over again
251 StepCount = last_clear_step;
254 Status = STATUS_INPROGRESS;
257 // if 20 tansient errors in a row then abort
259 Status = STATUS_ERROR_HALT;
261 Status = STATUS_INPROGRESS;
263 // all steps complete
264 case STATUS_COMPLETE:
265 fprintf(fp,"End script normally\n");
268 // non-recoverable error
269 case STATUS_ERROR_HALT:
270 fprintf(fp,"Aborting script due to non-recoverable error\n");
275 while (!Serial0CharArrived());
278 fprintf(fp,"Aborting script due to key press\n");
282 //----------------------------------------------------------------------
283 // Use the script to perform a step and return.
285 int ThermoStep(int portnum, ThermoStateType *ThermoState,
286 ThermoScript *StateScript, int *SubStep,
287 int *Status, int *ErrorCount, char *msg)
290 static int read_page_num, read_pages, write_addr, write_len;
291 static uchar *read_buf, *write_buf;
292 static uchar tbuf[5];
294 ErrorCount; // hush the compiler
296 // do the current step
297 switch (StateScript->Step)
299 // the operation is complete
301 sprintf(msg,"Operation complete");
302 *Status = STATUS_COMPLETE;
305 // read the mission status page
307 read_page_num = STATUS_PAGE;
309 read_buf = ThermoState->MissStat.status_raw;
310 sprintf(msg,"Ready to read status page %d",
312 *Status = STATUS_STEP_COMPLETE;
315 // set up to read the alarm registers
319 read_buf = ThermoState->AlarmData.alarm_raw;
320 sprintf(msg,"Ready to read alarm pages %d to %d",
321 read_page_num, read_page_num + read_pages - 1);
322 *Status = STATUS_STEP_COMPLETE;
325 // set up to read the histogram data
329 read_buf = ThermoState->HistData.hist_raw;
330 sprintf(msg,"Ready to read histogram 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 log data
339 read_buf = ThermoState->LogData.log_raw;
340 sprintf(msg,"Ready to read log pages %d to %d",
341 read_page_num, read_page_num + read_pages - 1);
342 *Status = STATUS_STEP_COMPLETE;
345 // read the specified pages
347 // check for last page
349 // set the sub-step to the current page being read
350 *SubStep = read_page_num;
351 // read the status page
352 rslt = ReadPages(portnum, read_page_num, read_pages, SubStep, read_buf);
355 sprintf(msg,"Thermochron not on 1-Wire Net");
356 *Status = STATUS_INPROGRESS;
360 sprintf(msg,"Pages read from Thermochron");
361 *Status = STATUS_STEP_COMPLETE;
365 // setup the clear memory
367 // create a small buff to write to start the clear memory
369 write_buf = &tbuf[0];
372 sprintf(msg,"Write to setup clear memory");
373 *Status = STATUS_STEP_COMPLETE;
378 // set the clear memory command (not check return because verify)
380 owWriteByte(portnum,0x3C);
382 owTouchReset(portnum);
383 sprintf(msg,"Clear memory command sent");
384 *Status = STATUS_STEP_COMPLETE;
388 case ST_CLEAR_VERIFY:
389 // look at the memory clear bit
390 if ((ThermoState->MissStat.status_raw[0x14] & 0x40) == 0x40)
392 sprintf(msg,"Memory is clear");
393 *Status = STATUS_STEP_COMPLETE;
398 sprintf(msg,"Memory did NOT clear");
399 *Status = STATUS_ERROR_TRANSIENT;
404 // setup write time, clock alarm, control, trips
406 // create the write buffer
407 FormatMission(&ThermoState->MissStat);
408 write_buf = &ThermoState->MissStat.status_raw[0x00];
411 sprintf(msg,"Write time, clock alarm, and trips setup");
412 *Status = STATUS_STEP_COMPLETE;
415 // write the control, mission delay and clear flags
416 case ST_WRITE_CONTROL:
417 write_buf = &ThermoState->MissStat.status_raw[0x0E];
420 sprintf(msg,"Write control, mission delay, clear flags setup");
421 *Status = STATUS_STEP_COMPLETE;
425 write_buf = &ThermoState->MissStat.status_raw[0x0D];
428 sprintf(msg,"Write sample rate setup");
429 *Status = STATUS_STEP_COMPLETE;
432 // write the specified memory location
434 if (WriteMemory(portnum, write_buf, write_len, write_addr))
436 sprintf(msg,"Memory written to Thermochron");
437 *Status = STATUS_STEP_COMPLETE;
441 sprintf(msg,"Thermochron not on 1-Wire Net");
442 *Status = STATUS_INPROGRESS;
451 //----------------------------------------------------------------------
452 // Read a specified number of pages in overdrive
454 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
455 // indicate the symbolic port number.
457 int ReadPages(int portnum, int start_pg, int num_pgs, int *last_pg, uchar *finalbuf)
459 int skip_overaccess = 0, skip_access = 0;
462 uchar SerialNumber[8];
465 // read the rom number
466 owSerialNum(portnum,SerialNumber,TRUE);
468 // verify device is in overdrive
469 if (current_speed[portnum] == MODE_OVERDRIVE)
471 if (owVerify(portnum,FALSE))
475 if (!skip_overaccess)
477 if (owOverdriveAccess(portnum))
478 current_speed[portnum] = MODE_OVERDRIVE;
480 current_speed[portnum] = MODE_NORMAL;
483 // loop while there is pages to read
486 // create a packet to read a page
489 // optional skip access on subsequent pages
495 for (i = 0; i < 8; i++)
496 pkt[len++] = SerialNumber[i];
497 // read memory with crc command
499 docrc16(portnum,pkt[len++]);
501 pkt[len] = (uchar)((*last_pg << 5) & 0xFF);
502 docrc16(portnum,pkt[len++]);
503 pkt[len] = (uchar)(*last_pg >> 3);
504 docrc16(portnum,pkt[len++]);
507 // set 32 reads for data and 2 for crc
508 for (i = 0; i < 34; i++)
512 if (owBlock(portnum,!skip_access,pkt,len))
514 // calucate the CRC over the last 34 bytes
515 for (i = 0; i < 34; i++)
516 lastcrc16 = docrc16(portnum,pkt[len - 34 + i]);
519 if (lastcrc16 == 0xB001)
521 // copy the data into the buffer
522 #ifdef LetsCrashTheCompiler
523 for (i = 0; i < 32; i++)
524 finalbuf[i + (*last_pg - start_pg) * 32] = pkt[len - 34 + i];
528 for (i = 0; i < 32; i++) {
529 k=i + (*last_pg - start_pg) * 32;
530 finalbuf[k] = pkt[len - 34 + i];
533 // change number of pages
534 *last_pg = *last_pg + 1;
545 while ((*last_pg - start_pg) < num_pgs);
550 //----------------------------------------------------------------------------}
551 // Write a memory location. Data must all be on the same page
553 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
554 // indicate the symbolic port number.
556 int WriteMemory(int portnum, uchar *Buf, int ln, int adr)
558 // write to scratch and then copy
559 if (WriteScratch(portnum,Buf,ln,adr))
560 return CopyScratch(portnum,ln,adr);
565 //----------------------------------------------------------------------------}
566 // Write the scratch pad
568 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
569 // indicate the symbolic port number.
571 int WriteScratch(int portnum, uchar *Buf, int ln, int adr)
576 // check for alarm indicator
577 if (owAccess(portnum))
579 // construct a packet to send
580 pbuf[0] = 0x0F; // write scratch command
581 pbuf[1] = (adr & 0xFF); // address 1
582 pbuf[2] = ((adr >> 8) & 0xFF); // address 2
585 for (i = 0; i < ln; i++)
586 pbuf[3 + i] = (uchar)(Buf[i]); // data
589 if (!owBlock(portnum,FALSE,pbuf,ln+3))
592 // Now read back the scratch
593 if (owAccess(portnum))
595 // construct a packet to send
596 pbuf[0] = 0xAA; // read scratch command
597 pbuf[1] = 0xFF; // address 1
598 pbuf[2] = 0xFF; // address 2
599 pbuf[3] = 0xFF; // offset
602 for (i = 0; i < ln; i++)
603 pbuf[4 + i] = 0xFF; // data
606 if (!owBlock(portnum,FALSE,pbuf,ln+4))
610 if (pbuf[1] != (adr & 0xFF))
613 if (pbuf[2] != ((adr >> 8) & 0xFF))
616 if (pbuf[3] != ((adr + ln - 1) & 0x1F))
618 // read and compare the contents
619 for (i = 0; i < ln; i++)
621 if (pbuf[4 + i] != Buf[i])
633 //----------------------------------------------------------------------------}
634 // Copy the scratch pad
636 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
637 // indicate the symbolic port number.
639 int CopyScratch(int portnum, int ln, int adr)
644 // check for alarm indicator
645 if (owAccess(portnum))
647 // construct a packet to send
648 pbuf[0] = 0x55; // copy scratch command
649 pbuf[1] = (adr & 0xFF); // address 1
650 pbuf[2] = ((adr >> 8) & 0xFF); // address 2
651 pbuf[3] = (adr + ln - 1) & 0x1F; // offset
652 for (i = 0; i <= 9; i++)
653 pbuf[4 + i] = 0xFF; // result of copy
656 if (owBlock(portnum,FALSE,pbuf,14))
658 if ((pbuf[13] == 0x55) ||
667 //----------------------------------------------------------------------
668 // Interpret the Status by looking at the 'raw' portion of the
669 // mission status structure.
671 void InterpretStatus(MissionStatus *mstatus)
679 // mission in progress flag
680 mstatus->mission_in_progress = (0x20 & mstatus->status_raw[0x14]) >> 5;
683 mstatus->sample_rate = mstatus->status_raw[0x0D];
686 mstatus->rollover_enable = (0x08 & mstatus->status_raw[0x0E]) >> 3;
689 mstatus->start_delay = ((int)mstatus->status_raw[0x13] << 8) |
690 mstatus->status_raw[0x12];
692 // number of samples in this mission
693 mstatus->mission_samples = ((long)mstatus->status_raw[0x1C] << 16) |
694 ((int)mstatus->status_raw[0x1B] << 8) |
695 mstatus->status_raw[0x1A];
697 // total number of samples
698 mstatus->samples_total = ((long)mstatus->status_raw[0x1F] << 16) |
699 ((int)mstatus->status_raw[0x1E] << 8) |
700 mstatus->status_raw[0x1D];
702 // temperature thresholds
703 mstatus->high_threshold = mstatus->status_raw[0x0C];
704 mstatus->low_threshold = mstatus->status_raw[0x0B];
707 if ((mstatus->mission_samples > 2048) && mstatus->rollover_enable)
708 mstatus->rollover_occurred = 1;
710 mstatus->rollover_occurred = 0;
712 // current real-time clock value
714 td.second = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
715 td.minute = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x7F));
716 // check for 12 hour mode
717 if (mstatus->status_raw[offset + 2] & 0x40)
719 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x1F));
721 if (mstatus->status_raw[offset + 2] & 0x20)
725 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
726 td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 4] & 0x3F));
727 td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 5] & 0x1F));
728 td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 1900;
729 // check for century bit
730 if (mstatus->status_raw[offset + 5] & 0x80)
731 td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 2000; // (2.00)
732 // convert to seconds since 1970
733 mstatus->current_time = DateToSeconds(&td);
735 // date/time when mission started
737 td.second = (uchar)0;
738 td.minute = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
739 // check for 12 hour mode
740 if (mstatus->status_raw[offset + 1] & 0x40)
742 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x1F));
744 if (mstatus->status_raw[offset + 1] & 0x20)
748 td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x3F));
749 td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
750 td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 3] & 0x1F));
751 td.year = BCDToBin((uchar)(mstatus->status_raw[offset + 4])); // (2.00)
752 // (2.00) logic to decide on century of mission stamp
753 // check if century bit set in mission stamp
754 if (mstatus->status_raw[offset + 3] & 0x80)
756 // check in mission in progress
757 else if (mstatus->mission_in_progress)
759 // calculate the mission start year back from real time clock
760 tmtmp = mstatus->current_time -
761 (mstatus->sample_rate * mstatus->mission_samples * 60);
762 SecondsToDate(&tdtmp,tmtmp);
763 td.year = tdtmp.year;
767 // mission stopped so get century by year window
773 // convert to seconds since 1970
774 if ((td.month == 0) || (td.day == 0))
775 mstatus->mission_start_time = 0;
777 mstatus->mission_start_time = DateToSeconds(&td);
779 // download stations time of reading
781 tstruct = localtime(&tlong);
782 td.day = tstruct->tm_mday;
783 td.month = tstruct->tm_mon + 1; // (1.01)
784 td.year = tstruct->tm_year + 1900;
785 td.hour = tstruct->tm_hour;
786 td.minute = tstruct->tm_min;
787 td.second = tstruct->tm_sec;
788 mstatus->download_time = DateToSeconds(&td);
790 // skip alarm modes and status for now
793 //--------------------------------------------------------------------------
794 // Take the Mission Status structure and create new raw data to start
797 void FormatMission(MissionStatus *mstatus)
804 for (i = 0; i < 32; i++)
805 mstatus->status_raw[i] = 0;
809 tlong++; // add 1 second
810 tstruct = localtime(&tlong);
812 mstatus->status_raw[0x00] = ToBCD((short)tstruct->tm_sec);
813 mstatus->status_raw[0x01] = ToBCD((short)tstruct->tm_min);
814 mstatus->status_raw[0x02] = ToBCD((short)tstruct->tm_hour);
815 mstatus->status_raw[0x03] = ToBCD((short)(tstruct->tm_wday + 1));
816 mstatus->status_raw[0x04] = ToBCD((short)tstruct->tm_mday);
817 mstatus->status_raw[0x05] = ToBCD((short)(tstruct->tm_mon + 1));
818 if (tstruct->tm_year >= 100)
819 mstatus->status_raw[0x05] |= 0x80;
820 mstatus->status_raw[0x06] = ToBCD((short)(tstruct->tm_year % 100));
821 // Real Time clock Alarm (leave 0's)
823 mstatus->status_raw[0x0B] = mstatus->low_threshold;
825 mstatus->status_raw[0x0C] = mstatus->high_threshold;
827 mstatus->status_raw[0x0D] = mstatus->sample_rate;
829 mstatus->status_raw[0x0E] = 0x40;
830 if (mstatus->rollover_enable)
831 mstatus->status_raw[0x0E] |= 0x08;
832 // mission start delay
833 mstatus->status_raw[0x12] = mstatus->start_delay & 0xFF;
834 mstatus->status_raw[0x13] = (mstatus->start_delay >> 8) & 0xFF;
837 //--------------------------------------------------------------------------
838 // Convert an integer to a 1 Byte BCD number (99 max)
840 uchar ToBCD(short num)
844 rtbyte = (num - ((num / 10) * 10)) & 0x0F;
845 rtbyte = rtbyte | ((num / 10) << 4);
851 //--------------------------------------------------------------------------
852 // Take the Mission Status structure and convert to string format
854 void MissionStatusToString(MissionStatus *mstatus, int ConvertToF, char *str)
862 cnt += sprintf(&str[cnt],"Mission State\n-------------\n");
865 cnt += sprintf(&str[cnt],"Serial Number of DS1921: ");
866 for (i = 7; i >= 0; i--)
867 cnt += sprintf(&str[cnt],"%02X",mstatus->serial_num[i]);
870 if (mstatus->mission_in_progress)
871 cnt += sprintf(&str[cnt],"\nMission is in progress\n");
873 cnt += sprintf(&str[cnt],"\nMission is ended\n");
876 cnt += sprintf(&str[cnt],"Sample rate: %d minute(s)\n",mstatus->sample_rate);
879 cnt += sprintf(&str[cnt],"Roll-Over Enabled: ");
880 if (mstatus->rollover_enable)
881 cnt += sprintf(&str[cnt],"yes\n");
883 cnt += sprintf(&str[cnt],"no\n");
884 cnt += sprintf(&str[cnt],"Roll-Over Occurred: ");
885 if (mstatus->rollover_occurred)
886 cnt += sprintf(&str[cnt],"yes\n");
888 cnt += sprintf(&str[cnt],"no\n");
890 // mission start time
891 if (mstatus->start_delay == 0)
893 SecondsToDate(&td,mstatus->mission_start_time);
894 if (mstatus->mission_start_time == 0)
895 cnt += sprintf(&str[cnt],"Mission Start time: not started yet\n");
897 cnt += sprintf(&str[cnt],"Mission Start time: %02d/%02d/%04d %02d:%02d:%02d\n",
898 td.month,td.day,td.year,td.hour,td.minute,td.second);
901 cnt += sprintf(&str[cnt],"Mission Start time: na\n");
903 // mission start delay
904 cnt += sprintf(&str[cnt],"Mission Start delay: %d minute(s)\n",mstatus->start_delay);
907 cnt += sprintf(&str[cnt],"Mission Samples: %d\n",mstatus->mission_samples);
909 // device total samples
910 cnt += sprintf(&str[cnt],"Device total samples: %d\n",mstatus->samples_total);
912 // temperature display mode
913 cnt += sprintf(&str[cnt],"Temperature displayed in: ");
915 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
917 cnt += sprintf(&str[cnt],"(Celsius)\n");
920 cnt += sprintf(&str[cnt],"High Threshold: %6.1f\n",
921 TempToFloat(mstatus->high_threshold,ConvertToF));
922 cnt += sprintf(&str[cnt],"Low Threshold: %6.1f\n",
923 TempToFloat(mstatus->low_threshold,ConvertToF));
926 SecondsToDate(&td,mstatus->current_time);
927 cnt += sprintf(&str[cnt],"Current Real-Time Clock from DS1921: %02d/%02d/%04d %02d:%02d:%02d\n",
928 td.month,td.day,td.year,td.hour,td.minute,td.second);
932 tstruct = localtime(&tlong);
933 cnt += sprintf(&str[cnt],"Current PC Time: %02d/%02d/%04d %02d:%02d:%02d\n",
934 tstruct->tm_mon + 1,tstruct->tm_mday,tstruct->tm_year + 1900,
935 tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec);
937 // zero terminate string
941 //----------------------------------------------------------------------
942 // Interpret the Histogram by looking at the 'raw' portion of the
943 // Histogram structure. Store the temperature range values in Celsius.
945 void InterpretHistogram(Histogram *hist)
949 // loop through each bin value
950 for (i = 0; i < 126; i += 2) // (2.00)
953 hist->bin_count[i / 2] = hist->hist_raw[i] | ((int)hist->hist_raw[i + 1] << 8);
955 // start value for this bin
956 hist->start_range[i / 2] = TempToFloat((uchar)((i / 2) << 2),FALSE);
958 // end value for this bin
959 hist->end_range[i / 2] = TempToFloat((uchar)(((i / 2) << 2) | 0x03),FALSE);
963 //--------------------------------------------------------------------------
964 // Take the Histogram structure and convert to string format
966 void HistogramToString(Histogram *hist, int ConvertToF, char *str)
971 cnt += sprintf(&str[cnt],"Temperature Histogram\n---------------------\n"
972 "Format: [Temp Range, Count] ");
974 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
976 cnt += sprintf(&str[cnt],"(Celsius)\n");
979 for (i = 0; i < 63; i++) // (2.00)
981 cnt += sprintf(&str[cnt],"%6.1f to %6.1f, %d\n",
982 (ConvertToF) ? CToF(hist->start_range[i]): hist->start_range[i],
983 (ConvertToF) ? CToF(hist->end_range[i]): hist->end_range[i],
987 // zero terminate string
991 //----------------------------------------------------------------------
992 // Interpret the Temperature Alarm Event data by looking at the 'raw'
993 // portion of the TempAlarmEvents structure. Mission Status is needed
994 // to interpret the events.
996 void InterpretAlarms(TempAlarmEvents *alarm, MissionStatus *mstatus)
999 ulong event_mission_count;
1004 for (i = 0; i < 48; i += 4)
1006 // get the mission start count of this event
1007 event_mission_count = ((long)alarm->alarm_raw[i + 2] << 16) |
1008 ((int)alarm->alarm_raw[i + 1] << 8) |
1009 alarm->alarm_raw[i];
1011 // check if done with low events
1012 if (!event_mission_count)
1016 duration = alarm->alarm_raw[i + 3];
1018 // calculate the start time
1019 alarm->low_start_time[alarm->num_low] =
1020 mstatus->mission_start_time +
1021 (event_mission_count - 1) * (mstatus->sample_rate * 60);
1023 // calculate the end time
1024 alarm->low_end_time[alarm->num_low] =
1025 alarm->low_start_time[alarm->num_low] +
1026 (duration - 1) * (mstatus->sample_rate * 60);
1028 // increment number of low events
1033 alarm->num_high = 0;
1034 for (i = 48; i < 96; i += 4)
1036 // get the mission start count of this event
1037 event_mission_count = ((long)alarm->alarm_raw[i + 2] << 16) |
1038 ((int)alarm->alarm_raw[i + 1] << 8) |
1039 alarm->alarm_raw[i];
1041 // check if done with low events
1042 if (!event_mission_count)
1046 duration = alarm->alarm_raw[i + 3];
1048 // calculate the start time
1049 alarm->high_start_time[alarm->num_high] =
1050 mstatus->mission_start_time +
1051 (event_mission_count - 1) * (mstatus->sample_rate * 60);
1053 // calculate the end time
1054 alarm->high_end_time[alarm->num_high] =
1055 alarm->high_start_time[alarm->num_high] +
1056 (duration - 1) * (mstatus->sample_rate * 60);
1058 // increment number of low events
1063 //--------------------------------------------------------------------------
1064 // Take the Temperature Alarms Events structure and convert to string
1067 void AlarmsToString(TempAlarmEvents *alarm, char *str)
1073 cnt += sprintf(&str[cnt],"Temperature Alarms\n------------------\n"
1074 "Format: [(HIGH/LOW), Time/Date Range]\n");
1076 // loop through each low alarm
1077 for (i = 0; i < alarm->num_low; i++)
1079 cnt += sprintf(&str[cnt],"LOW , ");
1081 SecondsToDate(&td,alarm->low_start_time[i]);
1082 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d to ",
1083 td.month,td.day,td.year,td.hour,td.minute);
1085 SecondsToDate(&td,alarm->low_end_time[i]);
1086 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d\n",
1087 td.month,td.day,td.year,td.hour,td.minute);
1090 // loop through each high alarm
1091 for (i = 0; i < alarm->num_high; i++)
1093 cnt += sprintf(&str[cnt],"HIGH , ");
1095 SecondsToDate(&td,alarm->high_start_time[i]);
1096 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d to ",
1097 td.month,td.day,td.year,td.hour,td.minute);
1099 SecondsToDate(&td,alarm->high_end_time[i]);
1100 cnt += sprintf(&str[cnt]," %02d/%02d/%04d %02d:%02d\n",
1101 td.month,td.day,td.year,td.hour,td.minute);
1104 // zero terminate string
1108 //----------------------------------------------------------------------
1109 // Interpret the Log data by looking at the 'raw'
1110 // portion of the Log structure. Mission Status is needed
1111 // to interpret when the logs occurred.
1113 void InterpretLog(Log *log, MissionStatus *mstatus)
1115 ulong loops=0,overlap=0,lastlog=2048,i;
1118 // check if wrap occurred
1119 if (mstatus->rollover_occurred)
1121 // calculate the number loops
1122 loops = (mstatus->mission_samples / 2048) - 1;
1123 // calculate the number of overlap
1124 overlap = mstatus->mission_samples % 2048;
1125 log->num_log = 2048;
1129 log->start_time = mstatus->mission_start_time;
1130 if (mstatus->mission_samples > 2048) // (1.02)
1133 lastlog = mstatus->mission_samples;
1134 log->num_log = (int)lastlog;
1138 log->interval = mstatus->sample_rate * 60;
1140 // caluclate the start time of the first log value
1141 log->start_time = mstatus->mission_start_time +
1142 loops * 2048 * log->interval + overlap * log->interval;
1144 // loop to fill in the remainder first
1145 for (i = overlap; i < lastlog; i++)
1146 log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1148 // loop to get the overlap
1149 for (i = 0; i < overlap; i++)
1150 log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1153 //--------------------------------------------------------------------------
1154 // Take the Log structure and convert to string
1157 void LogToString(Log *log, int ConvertToF, char *str)
1164 cnt += sprintf(&str[cnt],"Log Data\n--------\n"
1165 "Format: [Time/Date , Temperature] ");
1167 cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1169 cnt += sprintf(&str[cnt],"(Celsius)\n");
1171 // loop through the logs
1172 logtime = log->start_time;
1173 for (i = 0; i < log->num_log; i++)
1176 SecondsToDate(&td,logtime);
1177 cnt += sprintf(&str[cnt],"%02d/%02d/%04d %02d:%02d ,",
1178 td.month,td.day,td.year,td.hour,td.minute);
1180 cnt += sprintf(&str[cnt],"%6.1f\n",
1181 (ConvertToF) ? CToF(log->temp[i]): log->temp[i]);
1183 // increment the time
1184 logtime += log->interval;
1187 // zero terminate string
1191 //--------------------------------------------------------------------------
1192 // Convert the raw debug data to a string
1194 void DebugToString(MissionStatus *mstatus, TempAlarmEvents *alarm,
1195 Histogram *hist, Log *log, char *str)
1200 cnt += sprintf(&str[cnt],"Debug Dump\n----------\nRegister Page:\n");
1203 for (i = 0; i < 32; i++)
1205 cnt += sprintf(&str[cnt],"%02X ",mstatus->status_raw[i]);
1206 if (i && (((i + 1) % 16) == 0))
1207 cnt += sprintf(&str[cnt],"\n");
1211 cnt += sprintf(&str[cnt],"Alarms:\n");
1212 for (i = 0; i < 96; i++)
1214 cnt += sprintf(&str[cnt],"%02X ",alarm->alarm_raw[i]);
1215 if (i && (((i + 1) % 16) == 0))
1216 cnt += sprintf(&str[cnt],"\n");
1220 cnt += sprintf(&str[cnt],"Histogram:\n");
1221 for (i = 0; i < 128; i++)
1223 cnt += sprintf(&str[cnt],"%02X ",hist->hist_raw[i]);
1224 if (i && (((i + 1) % 16) == 0))
1225 cnt += sprintf(&str[cnt],"\n");
1230 cnt += sprintf(&str[cnt],"Log:\n");
1231 for (i = 0; i < ((log->num_log > 2048) ? 2048 : log->num_log); i++)
1233 cnt += sprintf(&str[cnt],"%02X ",log->log_raw[i]);
1234 if (i && (((i + 1) % 16) == 0))
1235 cnt += sprintf(&str[cnt],"\n");
1238 // zero terminate string
1242 //--------------------------------------------------------------------------
1243 // Take one byte BCD value and return binary value
1245 uchar BCDToBin(uchar bcd)
1247 return (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
1251 //--------------------------------------------------------------------------
1252 // Take a 4 byte long string and convert it into a timedata structure.
1254 static int dm[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,365 };
1256 void SecondsToDate(timedate *td, ulong x)
1261 // check to make sure date is not over 2070 (sanity check)
1262 if (x > 0xBBF81E00L)
1265 y = x/60; td->second = (ushort)(x-60*y);
1266 x = y/60; td->minute = (ushort)(y-60*x);
1267 y = x/24; td->hour = (ushort)(x-24*y);
1268 x = 4*(y+731); td->year = (ushort)(x/1461);
1269 i = (int)((x-1461*(ulong)(td->year))/4); td->month = 13;
1274 tmp = (td->month > 2) && ((td->year & 3)==0) ? 1 : 0;
1275 j = dm[td->month]+tmp;
1281 // slight adjustment to algorithm
1285 td->year = (td->year < 32) ? td->year + 68 + 1900: td->year - 32 + 2000;
1288 //--------------------------------------------------------------------------
1289 // DateToSeconds takes a time/date structure and converts it into the
1290 // number of seconds since 1970
1292 ulong DateToSeconds(timedate *td)
1296 // convert the date/time values into the 5 byte format used in the touch
1297 if (td->year >= 2000)
1298 Sv = td->year + 32 - 2000;
1300 Sv = td->year - 68 - 1900;
1302 if ((td->month > 2) && ( (Sv & 3) == 0))
1307 Xv = 365 * (Sv-2) + (Sv-1)/4 + dm[td->month] + td->day + Bv - 1;
1309 Xv = 86400 * Xv + (ulong)(td->second) + 60*((ulong)(td->minute) + 60*(ulong)(td->hour));
1314 //--------------------------------------------------------------------------
1315 // Convert from DS1921 termature format to a float
1318 float TempToFloat(uchar tmp, int ConvertToF)
1322 tfloat = (float)((tmp / 2.0) - 40.0);
1325 return (float)(tfloat * 9.0 / 5.0 + 32.0);
1330 //--------------------------------------------------------------------------
1331 // Convert from Celsius to Fahrenheit
1333 float CToF(float CVal)
1335 return (float)(CVal * 9.0 / 5.0 + 32.0);