Imported Upstream version 2.9.0
[debian/cc1111] / device / examples / ds390 / ow390 / thermo21.c
1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
3 // 
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:
10 // 
11 // The above copyright notice and this permission notice shall be included 
12 // in all copies or substantial portions of the Software.
13 // 
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.
21 // 
22 // Except as contained in this notice, the name of Dallas Semiconductor 
23 // shall not be used except as stated in the Dallas Semiconductor 
24 // Branding Policy. 
25 //---------------------------------------------------------------------------
26 //
27 //  thermo21.c - Thermochron iButton utility functions 
28 //
29 //  Version: 2.00
30 //    
31 //    History:
32 //           1.03 -> 2.00  Reorganization of Public Domain Kit 
33 //                         Convert to global CRC utility functions
34 //                         Y2K fix.
35
36 #include <stdio.h>
37 #include "time.h"
38 #include <string.h>
39 #include "ownet.h"
40 #include "thermo21.h"   
41
42 // a hack for sdcc/TINI, just printf to stdout
43 int fprintf (FILE *fp, char *format, ...) reentrant {
44   va_list arg;
45   *fp; // hush the compiler
46   va_start(arg, format);
47   vsprintf(NULL, format, arg);
48   va_end(arg);
49 }
50
51 FILE * fopen(char * path, char *mode) {
52   path, mode; //hush the compiler
53   return (FILE *)0;
54 }
55
56 int fclose(FILE *fp) {
57   fp; // hust the compiler
58   return 0;
59 }
60
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);
67
68 // step constants
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,
73        ST_CLEAR_SETUP };
74
75 // status contants
76 enum { STATUS_STEP_COMPLETE, STATUS_COMPLETE, STATUS_INPROGRESS,
77        STATUS_ERROR_HALT, STATUS_ERROR_TRANSIENT };
78
79 // download steps
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"}}; 
90
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"}}; 
96
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"}}; 
113
114 // global state information
115 static int current_speed[MAX_PORTNUM];
116
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'. 
121 //
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
128 //
129 // Returns:   TRUE (1) : Thermochron download with raw data in ThermoState
130 //            FALSE (0): not downloaded.  Abort due to repeated errors
131 //                       or user keypress.
132 //
133 int DownloadThermo(int portnum, uchar *SerialNum, 
134                    ThermoStateType *ThermoState, FILE *fp)
135 {
136    // set the serial num
137    owSerialNum(portnum, SerialNum, FALSE);
138
139    // run the script and download thermochron
140    return RunThermoScript(portnum,ThermoState,Download,fp);
141 }
142
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'. 
147 //
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
154 //
155 // Returns:   TRUE (1) : Thermochron status read with raw data in ThermoState
156 //            FALSE (0): status not read.  Abort due to repeated errors
157 //                       or user keypress.
158 //
159 int ReadThermoStatus(int portnum, uchar *SerialNum, 
160                    ThermoStateType *ThermoState, FILE *fp)
161 {
162    // set the serial num
163    owSerialNum(portnum, SerialNum, FALSE);
164
165    // run the script and read status of thermochron
166    return RunThermoScript(portnum,ThermoState,GetStatus,fp);
167
168
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'. 
173 //
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
180 //
181 // Returns:   TRUE (1) : Thermochron missioned
182 //            FALSE (0): not missioned.  Abort due to repeated errors
183 //                       or user keypress.
184 //
185 int MissionThermo(int portnum, uchar *SerialNum, 
186                    ThermoStateType *ThermoState, FILE *fp)
187 {
188    // set the serial num
189    owSerialNum(portnum, SerialNum, FALSE);
190
191    // run the script and mission thermochron
192    return RunThermoScript(portnum,ThermoState,Mission,fp);
193 }
194
195 //--------------------------------------------------------------------------
196 // Run the specified script.  Return TRUE if all steps completed else FALSE.
197 // Status is printed to file 'fp'.  
198 //
199 int RunThermoScript(int portnum, ThermoStateType *ThermoState,
200                     ThermoScript script[], FILE *fp)
201 {
202    char msg[256],LastDescription[256],LastMsg[256];
203    int StepCount,SubStep,ErrorCount,Status;
204    int last_clear_step=0;
205    
206    // reset the step to the begining
207    StepCount = 0;
208    SubStep = 0;
209    ErrorCount = 0;
210    Status = STATUS_INPROGRESS;
211  
212    // loop to perform all of the steps to download the Thermochron
213    do
214    {   
215       // switch on the status of the last step done
216       switch(Status)
217       {
218          // step complete so go to the next
219          case STATUS_STEP_COMPLETE:
220             StepCount++;
221             SubStep = 0;
222             ErrorCount = 0;
223             Status = STATUS_INPROGRESS;
224             LastDescription[0] = 0;
225             LastMsg[0] = 0;
226             break;
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;               
233
234             // print step description if different 
235             if (strcmp(LastDescription,
236                 script[StepCount].StepDescription) != 0)
237             {
238                fprintf(fp,"%s --> ",script[StepCount].StepDescription);
239                sprintf(LastDescription,"%s",script[StepCount].StepDescription);
240             }
241
242             // perform a step in the job
243             ThermoStep(portnum,ThermoState,&script[StepCount],&SubStep, 
244                       &Status, &ErrorCount, msg);
245
246             // print results if different
247             if (strcmp(LastMsg,msg) != 0)
248             {
249                fprintf(fp,"%s\n",msg);
250                sprintf(LastMsg,"%s",msg);
251             }
252             else
253                fprintf(fp,".");
254             break;     
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)
259             {
260                // put back to starting clear over again
261                StepCount = last_clear_step;
262                SubStep = 0;
263                ErrorCount = 0;
264                Status = STATUS_INPROGRESS;
265                break; 
266             }    
267             // if 20 tansient errors in a row then abort
268             if (ErrorCount > 20)
269                Status = STATUS_ERROR_HALT;
270             else
271                Status = STATUS_INPROGRESS;
272             break;
273          // all steps complete
274          case STATUS_COMPLETE:
275             fprintf(fp,"End script normally\n");
276             return TRUE;
277             break;
278          // non-recoverable error
279          case STATUS_ERROR_HALT:
280             fprintf(fp,"Aborting script due to non-recoverable error\n");
281             return FALSE;
282             break;
283       }
284    }
285    while (!Serial0CharArrived());
286  
287    // key abort
288    fprintf(fp,"Aborting script due to key press\n");
289    return FALSE;
290 }
291
292 //----------------------------------------------------------------------
293 //  Use the script to perform a step and return.
294 //
295 int ThermoStep(int portnum, ThermoStateType *ThermoState, 
296                ThermoScript *StateScript, int *SubStep, 
297                int *Status, int *ErrorCount, char *msg)
298 {
299    short  rslt;
300    static int read_page_num, read_pages, write_addr, write_len;
301    static uchar *read_buf, *write_buf;
302    static uchar tbuf[5];
303
304    ErrorCount; // hush the compiler
305
306    // do the current step
307    switch (StateScript->Step)
308    {
309       // the operation is complete      
310       case ST_FINISH:
311          sprintf(msg,"Operation complete");
312          *Status = STATUS_COMPLETE;
313          break;      
314
315       // read the mission status page
316       case ST_READ_STATUS:
317          read_page_num = STATUS_PAGE;
318          read_pages = 1;
319          read_buf = ThermoState->MissStat.status_raw;
320          sprintf(msg,"Ready to read status page %d",
321                       read_page_num);
322          *Status = STATUS_STEP_COMPLETE;
323          break;      
324
325       // set up to read the alarm registers
326       case ST_READ_ALARM:
327          read_page_num = 17;
328          read_pages = 3;
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;
333          break;
334          
335       // set up to read the histogram data
336       case ST_READ_HIST:
337          read_page_num = 64;
338          read_pages = 4;
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;
343          break;
344
345       // set up to read the log data
346       case ST_READ_LOG:
347          read_page_num = 128;
348          read_pages = 64;
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;
353          break;
354
355       // read the specified pages
356       case ST_READ_PAGES:
357          // check for last page
358          if (*SubStep == 0)
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);
363          if (rslt == FALSE)
364          {
365             sprintf(msg,"Thermochron not on 1-Wire Net");
366             *Status = STATUS_INPROGRESS;
367          }
368          else 
369          {
370             sprintf(msg,"Pages read from Thermochron");
371             *Status = STATUS_STEP_COMPLETE;
372          }
373          break;      
374
375       // setup the clear memory
376       case ST_CLEAR_SETUP:
377          // create a small buff to write to start the clear memory
378          tbuf[0] = 0x40;
379          write_buf = &tbuf[0];
380          write_len = 1;
381          write_addr = 0x20E;
382          sprintf(msg,"Write to setup clear memory");
383          *Status = STATUS_STEP_COMPLETE;
384          break;
385
386       // clear the memory
387       case ST_CLEAR_MEM:
388          // set the clear memory command (not check return because verify)        
389          owAccess(portnum);
390          owWriteByte(portnum,0x3C);
391          msDelay(3);
392          owTouchReset(portnum);
393          sprintf(msg,"Clear memory command sent");
394          *Status = STATUS_STEP_COMPLETE;
395          break;
396
397       // clear the memory
398       case ST_CLEAR_VERIFY:
399          // look at the memory clear bit
400          if ((ThermoState->MissStat.status_raw[0x14] & 0x40) == 0x40)
401          {
402             sprintf(msg,"Memory is clear");
403             *Status = STATUS_STEP_COMPLETE;
404             break;
405          }
406          else
407          {
408             sprintf(msg,"Memory did NOT clear");
409             *Status = STATUS_ERROR_TRANSIENT;
410             break;
411          }
412          break;      
413
414       // setup write time, clock alarm, control, trips
415       case ST_WRITE_TIME:
416          // create the write buffer
417          FormatMission(&ThermoState->MissStat);
418          write_buf = &ThermoState->MissStat.status_raw[0x00];
419          write_len = 13;
420          write_addr = 0x200;
421          sprintf(msg,"Write time, clock alarm, and trips setup");
422          *Status = STATUS_STEP_COMPLETE;
423          break;
424
425       // write the control, mission delay and clear flags
426       case ST_WRITE_CONTROL:
427          write_buf = &ThermoState->MissStat.status_raw[0x0E];
428          write_len = 7;
429          write_addr = 0x20E;
430          sprintf(msg,"Write control, mission delay, clear flags setup");
431          *Status = STATUS_STEP_COMPLETE;
432          break;
433
434       case ST_WRITE_RATE:
435          write_buf = &ThermoState->MissStat.status_raw[0x0D];
436          write_len = 1;
437          write_addr = 0x20D;
438          sprintf(msg,"Write sample rate setup");
439          *Status = STATUS_STEP_COMPLETE;
440          break;
441
442       // write the specified memory location 
443       case ST_WRITE_MEM:
444          if (WriteMemory(portnum, write_buf, write_len, write_addr))
445          {
446             sprintf(msg,"Memory written to Thermochron");
447             *Status = STATUS_STEP_COMPLETE;
448          }
449          else
450          {
451             sprintf(msg,"Thermochron not on 1-Wire Net");
452             *Status = STATUS_INPROGRESS;
453          }
454       default:
455            break;
456    }
457
458    return *Status;
459 }
460
461 //----------------------------------------------------------------------
462 //  Read a specified number of pages in overdrive
463 //
464 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
465 //              indicate the symbolic port number.
466 //
467 int ReadPages(int portnum, int start_pg, int num_pgs, int *last_pg, uchar *finalbuf)
468 {
469    int skip_overaccess = 0, skip_access = 0;
470    uchar pkt[60];
471    int len,i;
472    uchar  SerialNumber[8];
473    ushort lastcrc16;
474
475    // read the rom number 
476    owSerialNum(portnum,SerialNumber,TRUE);
477
478    // verify device is in overdrive
479    if (current_speed[portnum] == MODE_OVERDRIVE)
480    {
481       if (owVerify(portnum,FALSE)) 
482          skip_overaccess = 1;
483    }
484
485    if (!skip_overaccess)
486    {
487       if (owOverdriveAccess(portnum))
488          current_speed[portnum] = MODE_OVERDRIVE;
489       else
490          current_speed[portnum] = MODE_NORMAL;
491    }
492
493    // loop while there is pages to read
494    do
495    {
496       // create a packet to read a page
497       len = 0;
498       setcrc16(portnum,0);
499       // optional skip access on subsequent pages 
500       if (!skip_access)
501       {  
502          // match
503          pkt[len++] = 0x55; 
504          // rom number
505          for (i = 0; i < 8; i++)
506             pkt[len++] = SerialNumber[i];
507          // read memory with crc command 
508          pkt[len] = 0xA5; 
509          docrc16(portnum,pkt[len++]);         
510          // address
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++]);         
515       }
516
517       // set 32 reads for data and 2 for crc
518       for (i = 0; i < 34; i++)
519          pkt[len++] = 0xFF; 
520          
521       // send the bytes
522       if (owBlock(portnum,!skip_access,pkt,len))
523       {
524          // calucate the CRC over the last 34 bytes
525          for (i = 0; i < 34; i++)
526             lastcrc16 = docrc16(portnum,pkt[len - 34 + i]);
527
528          // check crc
529          if (lastcrc16 == 0xB001)
530          {
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];
535 #endif
536            {
537              ushort k;
538              for (i = 0; i < 32; i++) {
539                k=i + (*last_pg - start_pg) * 32;
540                finalbuf[k] = pkt[len - 34 + i];
541              }
542            }
543             // change number of pages 
544             *last_pg = *last_pg + 1;
545
546             // now skip access 
547             skip_access = TRUE;
548          }
549          else
550             return FALSE;
551       }
552       else
553          return FALSE;
554    }
555    while ((*last_pg - start_pg) < num_pgs);
556
557    return TRUE;
558 }
559
560 //----------------------------------------------------------------------------}
561 // Write a memory location. Data must all be on the same page
562 //
563 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
564 //              indicate the symbolic port number.
565 //
566 int WriteMemory(int portnum, uchar *Buf, int ln, int adr)
567 {
568    // write to scratch and then copy
569    if (WriteScratch(portnum,Buf,ln,adr)) 
570       return CopyScratch(portnum,ln,adr);
571
572    return FALSE;
573 }
574
575 //----------------------------------------------------------------------------}
576 // Write the scratch pad
577 //
578 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
579 //              indicate the symbolic port number.
580 //
581 int WriteScratch(int portnum, uchar *Buf, int ln, int adr)
582 {
583    int i;
584    uchar pbuf[80];
585
586    // check for alarm indicator 
587    if (owAccess(portnum)) 
588    {
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 
593
594       // the write bytes 
595       for (i = 0; i < ln; i++)
596         pbuf[3 + i] = (uchar)(Buf[i]); // data 
597
598       // perform the block 
599       if (!owBlock(portnum,FALSE,pbuf,ln+3))
600          return FALSE;
601
602       // Now read back the scratch 
603       if (owAccess(portnum)) 
604       {
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 
610
611          // the write bytes 
612          for (i = 0; i < ln; i++)
613             pbuf[4 + i] = 0xFF; // data 
614
615          // perform the block  
616          if (!owBlock(portnum,FALSE,pbuf,ln+4))
617             return FALSE;
618
619          // read address 1 
620          if (pbuf[1] != (adr & 0xFF)) 
621             return FALSE;
622          // read address 2 
623          if (pbuf[2] != ((adr >> 8) & 0xFF)) 
624             return FALSE;
625          // read the offset 
626          if (pbuf[3] != ((adr + ln - 1) & 0x1F)) 
627             return FALSE;
628          // read and compare the contents 
629          for (i = 0; i < ln; i++)
630          {
631             if (pbuf[4 + i] != Buf[i]) 
632               return FALSE;
633          }
634          // success
635          return TRUE;
636       }
637    }
638
639    return FALSE;
640 }
641
642
643 //----------------------------------------------------------------------------}
644 // Copy the scratch pad
645 //
646 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
647 //              indicate the symbolic port number.
648 //
649 int CopyScratch(int portnum, int ln, int adr)
650 {
651    int i;
652    uchar pbuf[50];
653
654    // check for alarm indicator 
655    if (owAccess(portnum)) 
656    {
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 
664
665       // perform the block 
666       if (owBlock(portnum,FALSE,pbuf,14))
667       {
668          if ((pbuf[13] == 0x55) ||
669              (pbuf[13] == 0xAA)) 
670            return TRUE;
671       }
672    }
673
674    return FALSE;
675 }
676
677 //----------------------------------------------------------------------
678 //  Interpret the Status by looking at the 'raw' portion of the 
679 //  mission status structure.
680 //
681 void InterpretStatus(MissionStatus *mstatus)
682 {
683    timedate td,tdtmp;
684    int offset;
685    ulong tmtmp;
686    time_t tlong; 
687    struct tm *tstruct; 
688
689    // mission in progress flag
690    mstatus->mission_in_progress = (0x20 & mstatus->status_raw[0x14]) >> 5;
691
692    // sample rate
693    mstatus->sample_rate = mstatus->status_raw[0x0D];
694
695    // rollover enabled 
696    mstatus->rollover_enable = (0x08 & mstatus->status_raw[0x0E]) >> 3;
697
698    // startdelay
699    mstatus->start_delay = ((int)mstatus->status_raw[0x13] << 8) | 
700                             mstatus->status_raw[0x12];
701
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];
706
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];
711
712    // temperature thresholds
713    mstatus->high_threshold = mstatus->status_raw[0x0C];
714    mstatus->low_threshold = mstatus->status_raw[0x0B];
715
716    // rollover occurred
717    if ((mstatus->mission_samples > 2048) && mstatus->rollover_enable)
718       mstatus->rollover_occurred = 1;
719    else
720       mstatus->rollover_occurred = 0;
721
722    // current real-time clock value
723    offset = 0x00;
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)
728    {
729       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x1F));
730       // check for PM
731       if (mstatus->status_raw[offset + 2] & 0x20)
732          td.hour += 12;
733    }
734    else
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);
744
745    // date/time when mission started
746    offset = 0x15;
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)
751    {
752       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x1F));
753       // check for PM
754       if (mstatus->status_raw[offset + 1] & 0x20)
755          td.hour += 12;
756    }
757    else
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)
765       td.year += 2000;
766    // check in mission in progress
767    else if (mstatus->mission_in_progress)
768    {
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;      
774    }
775    else
776    {
777       // mission stopped so get century by year window
778       if (td.year <= 70)
779          td.year += 2000;
780       else
781          td.year += 1900;
782    }
783    // convert to seconds since 1970
784    if ((td.month == 0) || (td.day == 0))
785       mstatus->mission_start_time = 0;
786    else
787       mstatus->mission_start_time = DateToSeconds(&td);
788       
789    // download stations time of reading
790    time(&tlong);
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);
799
800    // skip alarm modes and status for now
801 }
802
803 //--------------------------------------------------------------------------
804 // Take the Mission Status structure and create new raw data to start
805 // a new mission.
806 //
807 void FormatMission(MissionStatus *mstatus)
808 {
809    int i;
810    time_t tlong; 
811    struct tm *tstruct; 
812
813    // clear the buffer
814    for (i = 0; i < 32; i++)
815       mstatus->status_raw[i] = 0;
816    
817    // Real Time Clock
818    time(&tlong);
819    tlong++;  // add 1 second
820    tstruct = localtime(&tlong); 
821    // convert to BCD
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)
832    // Low temp alarm
833    mstatus->status_raw[0x0B] = mstatus->low_threshold;
834    // High temp alarm
835    mstatus->status_raw[0x0C] = mstatus->high_threshold;
836    // sample rate
837    mstatus->status_raw[0x0D] = mstatus->sample_rate;
838    // control
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;
845 }
846
847 //--------------------------------------------------------------------------
848 // Convert an integer to a 1 Byte BCD number (99 max) 
849 //
850 uchar ToBCD(short num)
851 {
852    uchar rtbyte;
853
854    rtbyte = (num - ((num / 10) * 10)) & 0x0F;
855    rtbyte = rtbyte | ((num / 10) << 4);
856    
857    return rtbyte;
858 }
859
860
861 //--------------------------------------------------------------------------
862 // Take the Mission Status structure and convert to string format
863 //
864 void MissionStatusToString(MissionStatus *mstatus, int ConvertToF, char *str)
865 {
866    int cnt=0,i;
867    timedate td;
868    time_t tlong; 
869    struct tm *tstruct; 
870
871    // title
872    cnt += sprintf(&str[cnt],"Mission State\n-------------\n");
873
874    // serial number
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]);
878
879    // mission state
880    if (mstatus->mission_in_progress)
881       cnt += sprintf(&str[cnt],"\nMission is in progress\n");
882    else
883       cnt += sprintf(&str[cnt],"\nMission is ended\n");
884
885    // sample rate
886    cnt += sprintf(&str[cnt],"Sample rate: %d minute(s)\n",mstatus->sample_rate);
887
888    // rollover
889    cnt += sprintf(&str[cnt],"Roll-Over Enabled: ");
890    if (mstatus->rollover_enable)
891       cnt += sprintf(&str[cnt],"yes\n");
892    else
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");
897    else
898       cnt += sprintf(&str[cnt],"no\n");
899   
900    // mission start time
901    if (mstatus->start_delay == 0)
902    {
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");
906       else
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);
909    }
910    else
911       cnt += sprintf(&str[cnt],"Mission Start time: na\n");
912
913    // mission start delay
914    cnt += sprintf(&str[cnt],"Mission Start delay: %d minute(s)\n",mstatus->start_delay);
915    
916    // mission samples
917    cnt += sprintf(&str[cnt],"Mission Samples: %d\n",mstatus->mission_samples);
918
919    // device total samples
920    cnt += sprintf(&str[cnt],"Device total samples: %d\n",mstatus->samples_total);
921
922    // temperature display mode
923    cnt += sprintf(&str[cnt],"Temperature displayed in: ");   
924    if (ConvertToF)
925       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
926    else
927       cnt += sprintf(&str[cnt],"(Celsius)\n");
928
929    // thresholds
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));   
934    
935    // time from D1921
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);
939
940    // current PC time
941    time(&tlong);
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);
946
947    // zero terminate string
948    str[cnt] = 0;
949 }
950
951 //----------------------------------------------------------------------
952 //  Interpret the Histogram by looking at the 'raw' portion of the 
953 //  Histogram structure.  Store the temperature range values in Celsius.
954 //
955 void InterpretHistogram(Histogram *hist)
956 {
957    int i;
958
959    // loop through each bin value
960    for (i = 0; i < 126; i += 2) // (2.00)
961    {
962       // get the bin value
963       hist->bin_count[i / 2] = hist->hist_raw[i] | ((int)hist->hist_raw[i + 1] << 8);
964
965       // start value for this bin
966       hist->start_range[i / 2] = TempToFloat((uchar)((i / 2) << 2),FALSE);
967
968       // end value for this bin
969       hist->end_range[i / 2] = TempToFloat((uchar)(((i / 2) << 2) | 0x03),FALSE);
970    }
971 }
972
973 //--------------------------------------------------------------------------
974 // Take the Histogram structure and convert to string format
975 //
976 void HistogramToString(Histogram *hist, int ConvertToF, char *str)
977 {
978    int cnt=0,i;
979
980    // title
981    cnt += sprintf(&str[cnt],"Temperature Histogram\n---------------------\n"  
982                             "Format: [Temp Range, Count] ");
983    if (ConvertToF)
984       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
985    else
986       cnt += sprintf(&str[cnt],"(Celsius)\n");
987
988    // loop through bins
989    for (i = 0; i < 63; i++) // (2.00)
990    {
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],
994                       hist->bin_count[i]);
995    }
996
997    // zero terminate string
998    str[cnt] = 0;
999 }
1000
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.
1005 //
1006 void InterpretAlarms(TempAlarmEvents *alarm, MissionStatus *mstatus)
1007 {
1008    int i;
1009    ulong event_mission_count;
1010    uchar duration;
1011
1012    // low events
1013    alarm->num_low = 0;
1014    for (i = 0; i < 48; i += 4)
1015    {
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];  
1020
1021       // check if done with low events
1022       if (!event_mission_count)
1023          break;
1024
1025       // get the duration
1026       duration = alarm->alarm_raw[i + 3];
1027    
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);  
1032
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);
1037
1038       // increment number of low events
1039       alarm->num_low++;
1040    }
1041
1042    // high events
1043    alarm->num_high = 0;
1044    for (i = 48; i < 96; i += 4)
1045    {
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];  
1050
1051       // check if done with low events
1052       if (!event_mission_count)
1053          break;
1054
1055       // get the duration
1056       duration = alarm->alarm_raw[i + 3];
1057
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);  
1062
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);
1067
1068       // increment number of low events
1069       alarm->num_high++;
1070    }
1071 }
1072
1073 //--------------------------------------------------------------------------
1074 // Take the Temperature Alarms Events structure and convert to string 
1075 // format
1076 //
1077 void AlarmsToString(TempAlarmEvents *alarm, char *str)
1078 {
1079    int i, cnt=0;
1080    timedate td;
1081
1082    // title
1083    cnt += sprintf(&str[cnt],"Temperature Alarms\n------------------\n"  
1084                             "Format: [(HIGH/LOW), Time/Date Range]\n");
1085
1086    // loop through each low alarm
1087    for (i = 0; i < alarm->num_low; i++)
1088    {
1089       cnt += sprintf(&str[cnt],"LOW  , ");
1090       // start time
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);
1094       // end time
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);
1098    }
1099
1100    // loop through each high alarm
1101    for (i = 0; i < alarm->num_high; i++)
1102    {
1103       cnt += sprintf(&str[cnt],"HIGH , ");
1104       // start time
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);
1108       // end time
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);
1112    }
1113
1114    // zero terminate string
1115    str[cnt] = 0;
1116 }
1117
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.
1122 //
1123 void InterpretLog(Log *log, MissionStatus *mstatus)
1124 {
1125    ulong loops=0,overlap=0,lastlog=2048,i;
1126    int logcnt=0;
1127
1128    // check if wrap occurred
1129    if (mstatus->rollover_occurred)
1130    {
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;
1136    }
1137    else
1138    {
1139       log->start_time = mstatus->mission_start_time;
1140       if (mstatus->mission_samples > 2048)  // (1.02)  
1141          lastlog = 2048;
1142       else
1143          lastlog = mstatus->mission_samples;
1144       log->num_log = (int)lastlog;
1145    }
1146
1147    // set the interval
1148    log->interval = mstatus->sample_rate * 60;
1149
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;
1153
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);
1157
1158    // loop to get the overlap
1159    for (i = 0; i < overlap; i++)
1160       log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1161 }
1162
1163 //--------------------------------------------------------------------------
1164 // Take the Log structure and convert to string 
1165 // format
1166 //
1167 void LogToString(Log *log, int ConvertToF, char *str)
1168 {
1169    int i,cnt=0;
1170    ulong logtime;
1171    timedate td;
1172
1173    // title
1174    cnt += sprintf(&str[cnt],"Log Data\n--------\n"  
1175                             "Format: [Time/Date , Temperature] ");
1176    if (ConvertToF)
1177       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1178    else
1179       cnt += sprintf(&str[cnt],"(Celsius)\n");
1180
1181    // loop through the logs
1182    logtime = log->start_time;
1183    for (i = 0; i < log->num_log; i++)
1184    {
1185       // time
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);
1189       // temp
1190       cnt += sprintf(&str[cnt],"%6.1f\n", 
1191              (ConvertToF) ? CToF(log->temp[i]): log->temp[i]);
1192
1193       // increment the time
1194       logtime += log->interval;
1195    }
1196
1197    // zero terminate string
1198    str[cnt] = 0;
1199 }
1200
1201 //--------------------------------------------------------------------------
1202 // Convert the raw debug data to a string
1203 //
1204 void DebugToString(MissionStatus *mstatus, TempAlarmEvents *alarm, 
1205                    Histogram *hist, Log *log, char *str) 
1206 {
1207    int i,cnt=0;
1208
1209    // title
1210    cnt += sprintf(&str[cnt],"Debug Dump\n----------\nRegister Page:\n");
1211
1212    // reg
1213    for (i = 0; i < 32; i++)
1214    {
1215       cnt += sprintf(&str[cnt],"%02X ",mstatus->status_raw[i]);
1216       if (i && (((i + 1) % 16) == 0))
1217          cnt += sprintf(&str[cnt],"\n");
1218    }
1219
1220    // alarms
1221    cnt += sprintf(&str[cnt],"Alarms:\n");
1222    for (i = 0; i < 96; i++)
1223    {
1224       cnt += sprintf(&str[cnt],"%02X ",alarm->alarm_raw[i]);
1225       if (i && (((i + 1) % 16) == 0))
1226          cnt += sprintf(&str[cnt],"\n");
1227    }
1228
1229    // histogram
1230    cnt += sprintf(&str[cnt],"Histogram:\n");
1231    for (i = 0; i < 128; i++)
1232    {
1233       cnt += sprintf(&str[cnt],"%02X ",hist->hist_raw[i]);
1234       if (i && (((i + 1) % 16) == 0))
1235          cnt += sprintf(&str[cnt],"\n");
1236    }
1237
1238
1239    // log
1240    cnt += sprintf(&str[cnt],"Log:\n");
1241    for (i = 0; i < ((log->num_log > 2048) ? 2048 : log->num_log); i++)
1242    {
1243       cnt += sprintf(&str[cnt],"%02X ",log->log_raw[i]);
1244       if (i && (((i + 1) % 16) == 0))
1245          cnt += sprintf(&str[cnt],"\n");
1246    }
1247
1248    // zero terminate string
1249    str[cnt] = 0;
1250 }
1251
1252 //--------------------------------------------------------------------------
1253 // Take one byte BCD value and return binary value
1254 //
1255 uchar BCDToBin(uchar bcd)
1256 {
1257    return (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
1258 }
1259
1260
1261 //--------------------------------------------------------------------------
1262 // Take a 4 byte long string and convert it into a timedata structure.
1263 //
1264 static int dm[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,365 };
1265
1266 void SecondsToDate(timedate *td, ulong x)
1267 {
1268    short tmp,i,j;
1269    ulong y;
1270    
1271    // check to make sure date is not over 2070 (sanity check)
1272    if (x > 0xBBF81E00L)
1273       x = 0;
1274    
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;
1280    
1281    do
1282    {
1283       td->month -= 1;
1284       tmp = (td->month > 2) && ((td->year & 3)==0) ? 1 : 0;
1285       j = dm[td->month]+tmp;
1286    
1287    } while (i < j);
1288    
1289    td->day = i-j+1;
1290    
1291    // slight adjustment to algorithm 
1292    if (td->day == 0) 
1293       td->day = 1;
1294    
1295    td->year = (td->year < 32)  ? td->year + 68 + 1900: td->year - 32 + 2000;
1296 }
1297
1298 //--------------------------------------------------------------------------
1299 // DateToSeconds takes a time/date structure and converts it into the 
1300 // number of seconds since 1970
1301 //
1302 ulong DateToSeconds(timedate *td)
1303 {
1304    ulong Sv,Bv,Xv;
1305
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;
1309    else 
1310       Sv = td->year - 68 - 1900;
1311
1312    if ((td->month > 2) && ( (Sv & 3) == 0))
1313      Bv = 1;
1314    else
1315      Bv = 0;
1316
1317    Xv = 365 * (Sv-2) + (Sv-1)/4 + dm[td->month] + td->day + Bv - 1;
1318
1319    Xv = 86400 * Xv + (ulong)(td->second) + 60*((ulong)(td->minute) + 60*(ulong)(td->hour));
1320
1321    return Xv;
1322 }
1323
1324 //--------------------------------------------------------------------------
1325 // Convert from DS1921 termature format to a float
1326 // 
1327 //
1328 float TempToFloat(uchar tmp, int ConvertToF)
1329 {
1330    float tfloat;
1331
1332    tfloat = (float)((tmp / 2.0) - 40.0);
1333
1334    if (ConvertToF)
1335       return (float)(tfloat * 9.0 / 5.0 + 32.0);
1336    else
1337       return tfloat;   
1338 }
1339
1340 //--------------------------------------------------------------------------
1341 // Convert from Celsius to Fahrenheit
1342 //
1343 float CToF(float CVal)
1344 {
1345    return (float)(CVal * 9.0 / 5.0 + 32.0);
1346 }