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 "ownet.h"
37 #include "thermo21.h"
38 #include <time.h>
39 #include <stdio.h>
40 
41 // Include files for the Palm and Visor
42 #ifdef __MC68K__
43 #include <DateTime.h>
44 #include <TimeMgr.h>
45 #else
46 #include <string.h>
47 #endif
48 
49 // structure to hold each state in the StateMachine
50 typedef struct
51 {
52    int  Step;
53    char StepDescription[50];
54 
55 } ThermoScript;
56 
57 // step constants
58 enum { ST_SETUP=0, ST_READ_STATUS, ST_READ_ALARM, ST_READ_HIST,
59        ST_READ_LOG, ST_CLEAR_MEM, ST_CLEAR_VERIFY, ST_WRITE_TIME,
60        ST_WRITE_CONTROL, ST_WRITE_RATE, ST_FINISH, ST_GET_SESSION,
61        ST_FIND_THERMO, ST_REL_SESSION, ST_READ_PAGES, ST_WRITE_MEM,
62        ST_CLEAR_SETUP };
63 
64 // status contants
65 enum { STATUS_STEP_COMPLETE, STATUS_COMPLETE, STATUS_INPROGRESS,
66        STATUS_ERROR_HALT, STATUS_ERROR_TRANSIENT };
67 
68 // download steps
69 static ThermoScript Download[] =
70     {{ ST_READ_STATUS,  "Setup to read the mission status"},
71      { ST_READ_PAGES,   "Read the status page"},
72      { ST_READ_ALARM,   "Setup to read alarm pages"},
73      { ST_READ_PAGES,   "Read the alarm pages"},
74      { ST_READ_HIST,    "Setup to read histogram pages"},
75      { ST_READ_PAGES,   "Read the histogram pages"},
76      { ST_READ_LOG,     "Setup to read log pages"},
77      { ST_READ_PAGES,   "Read the log pages"},
78      { ST_FINISH,       "Finished"}};
79 
80 // read status only steps
81 static ThermoScript GetStatus[] =
82     {{ ST_READ_STATUS,  "Setup to read the mission status"},
83      { ST_READ_PAGES,   "Read the status page"},
84      { ST_FINISH,       "Finished"}};
85 
86 // mission steps (assume already did StatusThermo)
87 static ThermoScript Mission[] =
88     {{ ST_CLEAR_SETUP,  "Setup clear memory"},
89      { ST_WRITE_MEM,    "Write clear memory bit"},
90      { ST_CLEAR_MEM,    "Clear the memory"},
91      { ST_READ_STATUS,  "Setup to read the mission status"},
92      { ST_READ_PAGES,   "Read the status page"},
93      { ST_CLEAR_VERIFY, "Verify memory is clear"},
94      { ST_WRITE_TIME,   "Setup to write the real time clock"},
95      { ST_WRITE_MEM,    "Write the real time clock"},
96      { ST_WRITE_CONTROL,"Setup to write the control"},
97      { ST_WRITE_MEM,    "Write the control"},
98      { ST_WRITE_RATE,   "Setup to write the sample rate to start mission"},
99      { ST_WRITE_MEM,    "Write the sample rate"},
100      { ST_READ_STATUS,  "Read the new mission status"},
101      { ST_FINISH,       "Finished"}};
102 
103 // external One Wire functions from nework layer
104 extern SMALLINT owAccess(int);
105 extern void     owSerialNum(int,uchar *,SMALLINT);
106 extern void     owFamilySearchSetup(int,SMALLINT);
107 extern SMALLINT owNext(int,SMALLINT,SMALLINT);
108 extern SMALLINT owVerify(int,SMALLINT);
109 extern SMALLINT owOverdriveAccess(int);
110 
111 // external One Wire functions from transaction layer
112 extern SMALLINT owBlock(int,SMALLINT,uchar *,SMALLINT);
113 
114 // external One Wire functions from link layer
115 extern SMALLINT owTouchReset(int);
116 extern SMALLINT owWriteByte(int,SMALLINT);
117 extern SMALLINT owSpeed(int,SMALLINT);
118 extern void     msDelay(int);
119 
120 // external functions defined in crcutil.c
121 extern void setcrc16(int,ushort);
122 extern ushort docrc16(int,ushort);
123 
124 // extern function prototypes
125 extern int key_abort(void);
126 
127 // Local Function Prototypes
128 int DownloadThermo(int,uchar *,ThermoStateType *,FILE *);
129 int ReadThermoStatus(int,uchar *,ThermoStateType *,FILE *);
130 int MissionThermo(int,uchar *,ThermoStateType *,FILE *);
131 static int RunThermoScript(int,ThermoStateType *,ThermoScript script[],FILE *fp);
132 void MissionStatusToString(MissionStatus *,int,char *);
133 void  SecondsToDate(timedate *, ulong);
134 ulong DateToSeconds(timedate *);
135 uchar BCDToBin(uchar);
136 void  InterpretStatus(MissionStatus *);
137 void  FormatMission(MissionStatus *);
138 void  InterpretHistogram(Histogram *);
139 void  HistogramToString(Histogram *, int, char *);
140 void  InterpretAlarms(TempAlarmEvents *, MissionStatus *);
141 void  AlarmsToString(TempAlarmEvents *, char *);
142 void  InterpretLog(Log *, MissionStatus *);
143 void  LogToString(Log *, int, char *);
144 void  DebugToString(MissionStatus *, TempAlarmEvents *, Histogram *, Log *, char *);
145 float TempToFloat(uchar, int);
146 float CToF(float);
147 uchar ToBCD(short);
148 static int ThermoStep(int,ThermoStateType *,ThermoScript *,int *,int *,int *,char *);
149 static int ReadPages(int,int,int,int *,uchar *);
150 static int WriteScratch(int,uchar *,int,int);
151 static int CopyScratch(int,int,int);
152 static int WriteMemory(int,uchar *, int, int);
153 
154 // global state information
155 static int current_speed[MAX_PORTNUM];
156 
157 
158 //--------------------------------------------------------------------------
159 // The 'DownloadThermo' downloads the specified Thermochron in 'SerialNum'
160 // and puts the data in the state variable 'ThermoState'.  Progress output
161 // is printed to the specified file 'fp'.
162 //
163 // 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
164 //                 indicate the symbolic port number.
165 // 'SerialNum'   - Device serial number to download
166 // 'ThermoState' - pointer to a structure type that holds the raw and
167 //                 translated Thermochron data.
168 // 'fp'          - file pointer to print status information to
169 //
170 // Returns:   TRUE (1) : Thermochron download with raw data in ThermoState
171 //            FALSE (0): not downloaded.  Abort due to repeated errors
172 //                       or user keypress.
173 //
DownloadThermo(int portnum,uchar * SerialNum,ThermoStateType * ThermoState,FILE * fp)174 int DownloadThermo(int portnum, uchar *SerialNum,
175 				   ThermoStateType *ThermoState, FILE *fp)
176 {
177    // set the serial num
178    owSerialNum(portnum, SerialNum, FALSE);
179 
180    // run the script and download thermochron
181    return RunThermoScript(portnum,ThermoState,Download,fp);
182 }
183 
184 //--------------------------------------------------------------------------
185 // The 'ReadThermoStatus' reads the Thermochron status in 'SerialNum'
186 // and puts the data in the state variable 'ThermoState'.  Progress output
187 // is printed to the specified file 'fp'.
188 //
189 // 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
190 //                 indicate the symbolic port number.
191 // 'SerialNum'   - Device serial number to download
192 // 'ThermoState' - pointer to a structure type that holds the raw and
193 //                 translated Thermochron data.
194 // 'fp'          - file pointer to print status information to
195 //
196 // Returns:   TRUE (1) : Thermochron status read with raw data in ThermoState
197 //            FALSE (0): status not read.  Abort due to repeated errors
198 //                       or user keypress.
199 //
ReadThermoStatus(int portnum,uchar * SerialNum,ThermoStateType * ThermoState,FILE * fp)200 int ReadThermoStatus(int portnum, uchar *SerialNum,
201 				   ThermoStateType *ThermoState, FILE *fp)
202 {
203 
204    // set the serial num
205    owSerialNum(portnum, SerialNum, FALSE);
206 
207    // run the script and read status of thermochron
208    return RunThermoScript(portnum,ThermoState,GetStatus,fp);
209 }
210 
211 //--------------------------------------------------------------------------
212 // The 'MissionThermo' starts a new Thermochron mission on 'SerialNum'
213 // from the state information provided in 'ThermoState'. Progress output
214 // is printed to the specified file 'fp'.
215 //
216 // 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
217 //                 indicate the symbolic port number.
218 // 'SerialNum'   - Device serial number to download
219 // 'ThermoState' - pointer to a structure type that holds the raw and
220 //                 translated Thermochron data.
221 // 'fp'          - file pointer to print status information to
222 //
223 // Returns:   TRUE (1) : Thermochron missioned
224 //            FALSE (0): not missioned.  Abort due to repeated errors
225 //                       or user keypress.
226 //
MissionThermo(int portnum,uchar * SerialNum,ThermoStateType * ThermoState,FILE * fp)227 int MissionThermo(int portnum, uchar *SerialNum,
228                    ThermoStateType *ThermoState,FILE *fp)
229 {
230    // set the serial num
231    owSerialNum(portnum, SerialNum, FALSE);
232 
233    // run the script and mission thermochron
234    return RunThermoScript(portnum,ThermoState,Mission,fp);
235 }
236 
237 //--------------------------------------------------------------------------
238 // Run the specified script.  Return TRUE if all steps completed else FALSE.
239 // Status is printed to file 'fp'.
240 //
RunThermoScript(int portnum,ThermoStateType * ThermoState,ThermoScript script[],FILE * fp)241 int RunThermoScript(int portnum, ThermoStateType *ThermoState,
242                     ThermoScript script[], FILE *fp)
243 {
244    char msg[256],LastDescription[256],LastMsg[256];
245    int StepCount,SubStep,ErrorCount,Status;
246    int last_clear_step=0;
247 
248    // reset the step to the begining
249    StepCount = 0;
250    SubStep = 0;
251    ErrorCount = 0;
252    Status = STATUS_INPROGRESS;
253 
254    // loop to perform all of the steps to download the Thermochron
255    do
256    {
257       // switch on the status of the last step done
258       switch(Status)
259       {
260          // step complete so go to the next
261          case STATUS_STEP_COMPLETE:
262             StepCount++;
263             SubStep = 0;
264             ErrorCount = 0;
265             Status = STATUS_INPROGRESS;
266             LastDescription[0] = 0;
267             LastMsg[0] = 0;
268             break;
269          // in progress so call again
270          case STATUS_INPROGRESS:
271             // record the step position of the last memory clear
272             // this is in case we need to attempt a clear again
273             if (script[StepCount].Step == ST_CLEAR_SETUP)
274                last_clear_step = StepCount;
275 
276             // print step description if different
277             if (strcmp(LastDescription,
278                 script[StepCount].StepDescription) != 0)
279             {
280                fprintf(fp,"%s --> ",script[StepCount].StepDescription);
281                sprintf(LastDescription,"%s",script[StepCount].StepDescription);
282             }
283 
284             // perform a step in the job
285             ThermoStep(portnum,ThermoState,&script[StepCount],&SubStep,
286                       &Status, &ErrorCount, msg);
287 
288             // print results if different
289             if (strcmp(LastMsg,msg) != 0)
290             {
291                fprintf(fp,"%s\n",msg);
292                sprintf(LastMsg,"%s",msg);
293             }
294            else
295                fprintf(fp,".");
296             break;
297          // encountered a transient error
298          case STATUS_ERROR_TRANSIENT:
299             // check if transient error is a memory clear
300             if (script[StepCount].Step == ST_CLEAR_VERIFY)
301             {
302                // put back to starting clear over again
303                StepCount = last_clear_step;
304                SubStep = 0;
305                ErrorCount = 0;
306                Status = STATUS_INPROGRESS;
307                break;
308             }
309             // if 20 tansient errors in a row then abort
310             if (ErrorCount > 20)
311                Status = STATUS_ERROR_HALT;
312             else
313                Status = STATUS_INPROGRESS;
314             break;
315          // all steps complete
316          case STATUS_COMPLETE:
317             fprintf(fp,"End script normally\n");
318             return TRUE;
319             break;
320          // non-recoverable error
321          case STATUS_ERROR_HALT:
322             fprintf(fp,"Aborting script due to non-recoverable error\n");
323             return FALSE;
324             break;
325       }
326    }
327    while (!key_abort());
328 
329    // key abort
330    fprintf(fp,"Aborting script due to key press\n");
331    return FALSE;
332 }
333 
334 
335 //----------------------------------------------------------------------
336 //  Use the script to perform a step and return.
337 //
ThermoStep(int portnum,ThermoStateType * ThermoState,ThermoScript * StateScript,int * SubStep,int * Status,int * ErrorCount,char * msg)338 int ThermoStep(int portnum, ThermoStateType *ThermoState,
339                ThermoScript *StateScript, int *SubStep,
340                int *Status, int *ErrorCount, char *msg)
341 {
342    short  rslt;
343    static int read_page_num, read_pages, write_addr, write_len;
344    static uchar *read_buf, *write_buf;
345    static uchar tbuf[5];
346 
347    // do the current step
348    switch (StateScript->Step)
349    {
350       // the operation is complete
351       case ST_FINISH:
352          sprintf(msg,"Operation complete");
353          *Status = STATUS_COMPLETE;
354          break;
355 
356       // read the mission status page
357       case ST_READ_STATUS:
358          read_page_num = STATUS_PAGE;
359          read_pages = 1;
360          read_buf = ThermoState->MissStat.status_raw;
361          sprintf(msg,"Ready to read status page %d",
362                       read_page_num);
363          *Status = STATUS_STEP_COMPLETE;
364          break;
365 
366       // set up to read the alarm registers
367       case ST_READ_ALARM:
368          read_page_num = 17;
369          read_pages = 3;
370          read_buf = ThermoState->AlarmData.alarm_raw;
371          sprintf(msg,"Ready to read alarm pages %d to %d",
372                       read_page_num, read_page_num + read_pages - 1);
373          *Status = STATUS_STEP_COMPLETE;
374          break;
375 
376       // set up to read the histogram data
377       case ST_READ_HIST:
378          read_page_num = 64;
379          read_pages = 4;
380          read_buf = ThermoState->HistData.hist_raw;
381          sprintf(msg,"Ready to read histogram pages %d to %d",
382                       read_page_num, read_page_num + read_pages - 1);
383          *Status = STATUS_STEP_COMPLETE;
384          break;
385 
386       // set up to read the log data
387       case ST_READ_LOG:
388          read_page_num = 128;
389          read_pages = 64;
390          read_buf = ThermoState->LogData.log_raw;
391          sprintf(msg,"Ready to read log pages %d to %d",
392                       read_page_num, read_page_num + read_pages - 1);
393          *Status = STATUS_STEP_COMPLETE;
394          break;
395 
396       // read the specified pages
397       case ST_READ_PAGES:
398          // check for last page
399          if (*SubStep == 0)
400             // set the sub-step to the current page being read
401             *SubStep =  read_page_num;
402          // read the status page
403          rslt = ReadPages(portnum, read_page_num, read_pages, SubStep, read_buf);
404          if (rslt == FALSE)
405          {
406             sprintf(msg,"Thermochron not on 1-Wire Net");
407 #ifdef __MC68K__
408             *Status = STATUS_ERROR_HALT;
409 #else
410 			*Status = STATUS_INPROGRESS;
411 #endif
412          }
413          else
414          {
415             sprintf(msg,"Pages read from Thermochron");
416             *Status = STATUS_STEP_COMPLETE;
417          }
418          break;
419 
420       // setup the clear memory
421       case ST_CLEAR_SETUP:
422          // create a small buff to write to start the clear memory
423          tbuf[0] = 0x40;
424          write_buf = &tbuf[0];
425          write_len = 1;
426          write_addr = 0x20E;
427          sprintf(msg,"Write to setup clear memory");
428          *Status = STATUS_STEP_COMPLETE;
429          break;
430 
431       // clear the memory
432       case ST_CLEAR_MEM:
433          // set the clear memory command (not check return because verify)
434          owAccess(portnum);
435          owWriteByte(portnum,0x3C);
436          msDelay(3);
437          owTouchReset(portnum);
438          sprintf(msg,"Clear memory command sent");
439          *Status = STATUS_STEP_COMPLETE;
440          break;
441 
442       // clear the memory
443       case ST_CLEAR_VERIFY:
444          // look at the memory clear bit
445          if ((ThermoState->MissStat.status_raw[0x14] & 0x40) == 0x40)
446          {
447             sprintf(msg,"Memory is clear");
448             *Status = STATUS_STEP_COMPLETE;
449             break;
450          }
451          else
452          {
453             sprintf(msg,"Memory did NOT clear");
454             *Status = STATUS_ERROR_TRANSIENT;
455             break;
456          }
457          break;
458 
459       // setup write time, clock alarm, control, trips
460       case ST_WRITE_TIME:
461          // create the write buffer
462          FormatMission(&ThermoState->MissStat);
463          write_buf = &ThermoState->MissStat.status_raw[0x00];
464          write_len = 13;
465          write_addr = 0x200;
466          sprintf(msg,"Write time, clock alarm, and trips setup");
467          *Status = STATUS_STEP_COMPLETE;
468          break;
469 
470       // write the control, mission delay and clear flags
471       case ST_WRITE_CONTROL:
472          write_buf = &ThermoState->MissStat.status_raw[0x0E];
473          write_len = 7;
474          write_addr = 0x20E;
475          sprintf(msg,"Write control, mission delay, clear flags setup");
476          *Status = STATUS_STEP_COMPLETE;
477          break;
478 
479       case ST_WRITE_RATE:
480          write_buf = &ThermoState->MissStat.status_raw[0x0D];
481          write_len = 1;
482          write_addr = 0x20D;
483          sprintf(msg,"Write sample rate setup");
484          *Status = STATUS_STEP_COMPLETE;
485          break;
486 
487       // write the specified memory location
488       case ST_WRITE_MEM:
489          if (WriteMemory(portnum, write_buf, write_len, write_addr))
490          {
491             sprintf(msg,"Memory written to Thermochron");
492             *Status = STATUS_STEP_COMPLETE;
493          }
494          else
495          {
496             sprintf(msg,"Thermochron not on 1-Wire Net");
497             *Status = STATUS_INPROGRESS;
498          }
499       default:
500            break;
501    }
502 
503    return *Status;
504 }
505 
506 //----------------------------------------------------------------------
507 //  Read a specified number of pages in overdrive
508 //
509 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
510 //              indicate the symbolic port number.
511 //
ReadPages(int portnum,int start_pg,int num_pgs,int * last_pg,uchar * finalbuf)512 int ReadPages(int portnum, int start_pg, int num_pgs, int *last_pg, uchar *finalbuf)
513 {
514    int skip_overaccess = 0, skip_access = 0;
515    uchar pkt[60];
516    int len,i;
517    uchar  SerialNumber[8];
518    ushort lastcrc16;
519 
520    // read the rom number
521    owSerialNum(portnum,SerialNumber,TRUE);
522 
523 #ifndef __MC68K__
524    // verify device is in overdrive
525    if (current_speed[portnum] == MODE_OVERDRIVE)
526    {
527       if (owVerify(portnum,FALSE))
528          skip_overaccess = 1;
529    }
530 
531    if (!skip_overaccess)
532    {
533       if (owOverdriveAccess(portnum))
534          current_speed[portnum] = MODE_OVERDRIVE;
535       else
536          current_speed[portnum] = MODE_NORMAL;
537    }
538 #endif
539 
540    // loop while there is pages to read
541    do
542    {
543       // create a packet to read a page
544       len = 0;
545       setcrc16(portnum,0);
546       // optional skip access on subsequent pages
547       if (!skip_access)
548       {
549          // match
550          pkt[len++] = 0x55;
551          // rom number
552          for (i = 0; i < 8; i++)
553             pkt[len++] = SerialNumber[i];
554          // read memory with crc command
555          pkt[len] = 0xA5;
556          docrc16(portnum,pkt[len++]);
557          // address
558          pkt[len] = (uchar)((*last_pg << 5) & 0xFF);
559          docrc16(portnum,pkt[len++]);
560          pkt[len] = (uchar)(*last_pg >> 3);
561          docrc16(portnum,pkt[len++]);
562       }
563 
564       // set 32 reads for data and 2 for crc
565       for (i = 0; i < 34; i++)
566          pkt[len++] = 0xFF;
567 
568       // send the bytes
569       if (owBlock(portnum,!skip_access,pkt,len))
570       {
571          // calucate the CRC over the last 34 bytes
572          for (i = 0; i < 34; i++)
573             lastcrc16 = docrc16(portnum,pkt[len - 34 + i]);
574 
575          // check crc
576          if (lastcrc16 == 0xB001)
577          {
578             // copy the data into the buffer
579             for (i = 0; i < 32; i++)
580                finalbuf[i + (*last_pg - start_pg) * 32] = pkt[len - 34 + i];
581 
582             // change number of pages
583             *last_pg = *last_pg + 1;
584 
585             // now skip access
586             skip_access = TRUE;
587          }
588          else
589             return FALSE;
590 
591       }
592       else
593          return FALSE;
594 
595    }
596    while ((*last_pg - start_pg) < num_pgs);
597 
598    return TRUE;
599 }
600 
601 //----------------------------------------------------------------------------}
602 // Write a memory location. Data must all be on the same page
603 //
604 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
605 //              indicate the symbolic port number.
606 //
WriteMemory(int portnum,uchar * Buf,int ln,int adr)607 int WriteMemory(int portnum, uchar *Buf, int ln, int adr)
608 {
609    // write to scratch and then copy
610    if (WriteScratch(portnum,Buf,ln,adr))
611       return CopyScratch(portnum,ln,adr);
612 
613    return FALSE;
614 }
615 
616 //----------------------------------------------------------------------------}
617 // Write the scratch pad
618 //
619 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
620 //              indicate the symbolic port number.
621 //
WriteScratch(int portnum,uchar * Buf,int ln,int adr)622 int WriteScratch(int portnum, uchar *Buf, int ln, int adr)
623 {
624    int i;
625    uchar pbuf[80];
626 
627    // check for alarm indicator
628    if (owAccess(portnum))
629    {
630       // construct a packet to send
631       pbuf[0] = 0x0F; // write scratch command
632       pbuf[1] = (adr & 0xFF); // address 1
633       pbuf[2] = ((adr >> 8) & 0xFF); // address 2
634 
635       // the write bytes
636       for (i = 0; i < ln; i++)
637         pbuf[3 + i] = (uchar)(Buf[i]); // data
638 
639       // perform the block
640       if (!owBlock(portnum,FALSE,pbuf,ln+3))
641          return FALSE;
642 
643       // Now read back the scratch
644       if (owAccess(portnum))
645       {
646          // construct a packet to send
647          pbuf[0] = 0xAA; // read scratch command
648          pbuf[1] = 0xFF; // address 1
649          pbuf[2] = 0xFF; // address 2
650          pbuf[3] = 0xFF; // offset
651 
652          // the write bytes
653          for (i = 0; i < ln; i++)
654             pbuf[4 + i] = 0xFF; // data
655 
656          // perform the block
657          if (!owBlock(portnum,FALSE,pbuf,ln+4))
658             return FALSE;
659 
660          // read address 1
661          if (pbuf[1] != (adr & 0xFF))
662             return FALSE;
663          // read address 2
664          if (pbuf[2] != ((adr >> 8) & 0xFF))
665             return FALSE;
666          // read the offset
667          if (pbuf[3] != ((adr + ln - 1) & 0x1F))
668             return FALSE;
669          // read and compare the contents
670          for (i = 0; i < ln; i++)
671          {
672             if (pbuf[4 + i] != Buf[i])
673               return FALSE;
674          }
675          // success
676          return TRUE;
677       }
678    }
679 
680    return FALSE;
681 }
682 
683 
684 //----------------------------------------------------------------------------}
685 // Copy the scratch pad
686 //
687 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
688 //              indicate the symbolic port number.
689 //
CopyScratch(int portnum,int ln,int adr)690 int CopyScratch(int portnum, int ln, int adr)
691 {
692    int i;
693    uchar pbuf[50];
694 
695    // check for alarm indicator
696    if (owAccess(portnum))
697    {
698       // construct a packet to send
699       pbuf[0] = 0x55;                  // copy scratch command
700       pbuf[1] = (adr & 0xFF);          // address 1
701       pbuf[2] = ((adr >> 8) & 0xFF);   // address 2
702       pbuf[3] = (adr + ln - 1) & 0x1F; // offset
703       for (i = 0; i <= 9; i++)
704          pbuf[4 + i] = 0xFF;           // result of copy
705 
706       // perform the block
707       if (owBlock(portnum,FALSE,pbuf,14))
708       {
709          if ((pbuf[13] == 0x55) ||
710              (pbuf[13] == 0xAA))
711            return TRUE;
712       }
713    }
714 
715    return FALSE;
716 }
717 
718 //----------------------------------------------------------------------
719 //  Interpret the Status by looking at the 'raw' portion of the
720 //  mission status structure.
721 //
InterpretStatus(MissionStatus * mstatus)722 void InterpretStatus(MissionStatus *mstatus)
723 {
724    timedate td,tdtmp;
725    int offset;
726    ulong tmtmp;
727 
728 #ifndef __MC68K__
729    time_t tlong;
730    struct tm *tstruct;
731 #endif
732 
733 
734    // mission in progress flag
735    mstatus->mission_in_progress = (0x20 & mstatus->status_raw[0x14]) >> 5;
736 
737    // sample rate
738    mstatus->sample_rate = mstatus->status_raw[0x0D];
739 
740    // rollover enabled
741    mstatus->rollover_enable = (0x08 & mstatus->status_raw[0x0E]) >> 3;
742 
743    // startdelay
744    mstatus->start_delay = (mstatus->status_raw[0x13] << 8) |
745                            mstatus->status_raw[0x12];
746 
747    // number of samples in this mission
748 #ifdef __MC68K__
749    mstatus->mission_samples = (((ulong) mstatus->status_raw[0x1C]) * 65536) +
750    							  (((ulong) mstatus->status_raw[0x1B]) * 256) +
751    							  ((ulong) mstatus->status_raw[0x1A]);
752 #else
753    mstatus->mission_samples = (mstatus->status_raw[0x1C] << 16) |
754                               (mstatus->status_raw[0x1B] << 8) |
755                                mstatus->status_raw[0x1A];
756 #endif
757 
758 
759 
760    // total number of samples
761 #ifdef __MC68K__
762    mstatus->samples_total   = (((ulong) mstatus->status_raw[0x1F]) * 65536) +
763    							  (((ulong) mstatus->status_raw[0x1E]) * 256) +
764    							  ((ulong) mstatus->status_raw[0x1D]);
765 #else
766    mstatus->samples_total = (mstatus->status_raw[0x1F] << 16) |
767                             (mstatus->status_raw[0x1E] << 8) |
768                              mstatus->status_raw[0x1D];
769 #endif
770 
771    // temperature thresholds
772    mstatus->high_threshold = mstatus->status_raw[0x0C];
773    mstatus->low_threshold = mstatus->status_raw[0x0B];
774 
775    // rollover occurred
776    if ((mstatus->mission_samples > 2048) && mstatus->rollover_enable)
777       mstatus->rollover_occurred = 1;
778    else
779       mstatus->rollover_occurred = 0;
780 
781    // current real-time clock value
782    offset = 0x00;
783    td.second = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
784    td.minute = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x7F));
785    // check for 12 hour mode
786    if (mstatus->status_raw[offset + 2] & 0x40)
787    {
788       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x1F));
789       // check for PM
790       if (mstatus->status_raw[offset + 2] & 0x20)
791          td.hour += 12;
792    }
793    else
794       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
795    td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 4] & 0x3F));
796    td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 5] & 0x1F));
797    td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 1900;
798    // check for century bit
799    if (mstatus->status_raw[offset + 5] & 0x80)
800       td.year = BCDToBin(mstatus->status_raw[offset + 6]) + 2000; // (2.00)
801    // convert to seconds since 1970
802    mstatus->current_time = DateToSeconds(&td);
803 
804    // date/time when mission started
805    offset = 0x15;
806    td.second = (uchar)0;
807    td.minute = BCDToBin((uchar)(mstatus->status_raw[offset] & 0x7F));
808    // check for 12 hour mode
809    if (mstatus->status_raw[offset + 1] & 0x40)
810    {
811       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x1F));
812       // check for PM
813       if (mstatus->status_raw[offset + 1] & 0x20)
814          td.hour += 12;
815    }
816    else
817       td.hour = BCDToBin((uchar)(mstatus->status_raw[offset + 1] & 0x3F));
818    td.day = BCDToBin((uchar)(mstatus->status_raw[offset + 2] & 0x3F));
819    td.month = BCDToBin((uchar)(mstatus->status_raw[offset + 3] & 0x1F));
820    td.year = BCDToBin((uchar)(mstatus->status_raw[offset + 4])); // (2.00)
821    // (2.00) logic to decide on century of mission stamp
822    // check if century bit set in mission stamp
823    if (mstatus->status_raw[offset + 3] & 0x80)
824       td.year += 2000;
825    // check in mission in progress
826    else if (mstatus->mission_in_progress)
827    {
828       // calculate the mission start year back from real time clock
829       tmtmp = mstatus->current_time -
830              (mstatus->sample_rate * mstatus->mission_samples * 60);
831       SecondsToDate(&tdtmp,tmtmp);
832       td.year = tdtmp.year;
833    }
834    else
835    {
836       // mission stopped so get century by year window
837       if (td.year <= 70)
838          td.year += 2000;
839       else
840          td.year += 1900;
841    }
842    // convert to seconds since 1970
843    if ((td.month == 0) || (td.day == 0))
844       mstatus->mission_start_time = 0;
845    else
846       mstatus->mission_start_time = DateToSeconds(&td);
847 
848    // download stations time of reading
849 #ifdef __MC68K__
850    mstatus->download_time = TimGetSeconds();
851 #else
852    time(&tlong);
853    tstruct = localtime(&tlong);
854    td.day = tstruct->tm_mday;
855    td.month = tstruct->tm_mon + 1;  // (1.01)
856    td.year = tstruct->tm_year + 1900;
857    td.hour = tstruct->tm_hour;
858    td.minute = tstruct->tm_min;
859    td.second = tstruct->tm_sec;
860    mstatus->download_time = DateToSeconds(&td);
861 #endif
862 
863    // skip alarm modes and status for now
864 }
865 
866 //--------------------------------------------------------------------------
867 // Take the Mission Status structure and create new raw data to start
868 // a new mission.
869 //
FormatMission(MissionStatus * mstatus)870 void FormatMission(MissionStatus *mstatus)
871 {
872    int i;
873    time_t tlong;
874 #ifndef __MC68K__
875    struct tm *tstruct;
876 #else
877    DateTimePtr tstruct = NULL;
878 #endif
879    // clear the buffer
880    for (i = 0; i < 32; i++)
881       mstatus->status_raw[i] = 0;
882 
883    // Real Time Clock
884 #ifdef __MC68K__
885    tlong = TimGetSeconds();
886 #else
887    time(&tlong);
888 #endif
889    tlong++;  // add 1 second
890 
891 #ifdef __MC68K__
892    TimSecondsToDateTime(tlong, tstruct);
893 #else
894    tstruct = localtime(&tlong);
895 #endif
896 
897    // convert to BCD
898 #ifdef __MC68K__
899    mstatus->status_raw[0x00] = ToBCD((short)tstruct->second);
900    mstatus->status_raw[0x01] = ToBCD((short)tstruct->minute);
901    mstatus->status_raw[0x02] = ToBCD((short)tstruct->hour);
902    mstatus->status_raw[0x03] = ToBCD((short)(tstruct->weekDay + 1));
903    mstatus->status_raw[0x04] = ToBCD((short)tstruct->day);
904    mstatus->status_raw[0x05] = ToBCD((short)(tstruct->month + 1));
905    if (tstruct->year >= 100)
906       mstatus->status_raw[0x05] |= 0x80;
907    mstatus->status_raw[0x06] = ToBCD((short)(tstruct->year % 100));
908 #else
909    mstatus->status_raw[0x00] = ToBCD((short)tstruct->tm_sec);
910    mstatus->status_raw[0x01] = ToBCD((short)tstruct->tm_min);
911    mstatus->status_raw[0x02] = ToBCD((short)tstruct->tm_hour);
912    mstatus->status_raw[0x03] = ToBCD((short)(tstruct->tm_wday + 1));
913    mstatus->status_raw[0x04] = ToBCD((short)tstruct->tm_mday);
914    mstatus->status_raw[0x05] = ToBCD((short)(tstruct->tm_mon + 1));
915    if (tstruct->tm_year >= 100)
916       mstatus->status_raw[0x05] |= 0x80;
917    mstatus->status_raw[0x06] = ToBCD((short)(tstruct->tm_year % 100));
918 #endif
919 
920    // Real Time clock Alarm (leave 0's)
921    // Low temp alarm
922    mstatus->status_raw[0x0B] = mstatus->low_threshold;
923    // High temp alarm
924    mstatus->status_raw[0x0C] = mstatus->high_threshold;
925    // sample rate
926    mstatus->status_raw[0x0D] = mstatus->sample_rate;
927    // control
928    mstatus->status_raw[0x0E] = 0x40;
929    if (mstatus->rollover_enable)
930       mstatus->status_raw[0x0E] |= 0x08;
931    // mission start delay
932    mstatus->status_raw[0x12] = mstatus->start_delay & 0xFF;
933    mstatus->status_raw[0x13] = (mstatus->start_delay >> 8) & 0xFF;
934 }
935 
936 //--------------------------------------------------------------------------
937 // Convert an integer to a 1 Byte BCD number (99 max)
938 //
ToBCD(short num)939 uchar ToBCD(short num)
940 {
941    uchar rtbyte;
942 
943    rtbyte = (num - ((num / 10) * 10)) & 0x0F;
944    rtbyte = rtbyte | ((num / 10) << 4);
945 
946    return rtbyte;
947 }
948 
949 
950 //--------------------------------------------------------------------------
951 // Take the Mission Status structure and convert to string format
952 //
MissionStatusToString(MissionStatus * mstatus,int ConvertToF,char * str)953 void MissionStatusToString(MissionStatus *mstatus, int ConvertToF, char *str)
954 {
955    int cnt=0,i;
956    timedate td;
957 #ifndef __MC68K__
958    time_t tlong;
959    struct tm *tstruct;
960 #else
961    DateTimePtr tstruct = NULL;
962 #endif
963 
964    // title
965 #ifdef __MC68K__
966    cnt += sprintf(&str[cnt],"Stat For DS1921:");
967 #else
968    cnt += sprintf(&str[cnt],"Mission State\n-------------\n");
969    cnt += sprintf(&str[cnt],"Serial Number of DS1921: ");
970 #endif
971 
972    // serial number
973    for (i = 7; i >= 0; i--)
974    	  cnt += sprintf(&str[cnt],"%02X",mstatus->serial_num[i]);
975 
976    // mission state
977    if (mstatus->mission_in_progress)
978       cnt += sprintf(&str[cnt],"\nMission is in progress\n");
979    else
980       cnt += sprintf(&str[cnt],"\nMission is ended\n");
981 
982    // sample rate
983    cnt += sprintf(&str[cnt],"Sample rate: %d minute(s)\n",mstatus->sample_rate);
984 
985    // rollover
986    cnt += sprintf(&str[cnt],"Roll-Over Enabled: ");
987    if (mstatus->rollover_enable)
988       cnt += sprintf(&str[cnt],"yes\n");
989    else
990       cnt += sprintf(&str[cnt],"no\n");
991 
992    cnt += sprintf(&str[cnt],"Roll-Over Occurred: ");
993    if (mstatus->rollover_occurred)
994       cnt += sprintf(&str[cnt],"yes\n");
995    else
996       cnt += sprintf(&str[cnt],"no\n");
997 
998    // mission start time
999    if (mstatus->start_delay == 0)
1000    {
1001       SecondsToDate(&td,mstatus->mission_start_time);
1002       if (mstatus->mission_start_time == 0)
1003          cnt += sprintf(&str[cnt],"Mission Start time: not started yet\n");
1004       else
1005          cnt += sprintf(&str[cnt],"Mission Start: %02d/%02d/%04d  %02d:%02d:%02d\n",
1006             td.month,td.day,td.year,td.hour,td.minute,td.second);
1007 
1008    }
1009    else
1010       cnt += sprintf(&str[cnt],"Mission Start time: na\n");
1011 
1012    // mission start delay
1013    cnt += sprintf(&str[cnt],"Mission Start delay: %d minute(s)\n",mstatus->start_delay);
1014 
1015    // mission samples
1016    cnt += sprintf(&str[cnt],"Mission Samples: %ld\n",mstatus->mission_samples);
1017 
1018    // device total samples
1019    cnt += sprintf(&str[cnt],"Device total samples: %ld\n",mstatus->samples_total);
1020 
1021    // temperature display mode
1022    cnt += sprintf(&str[cnt],"Temp displayed in: ");
1023    if (ConvertToF)
1024       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1025    else
1026       cnt += sprintf(&str[cnt],"(Celsius)\n");
1027 
1028    // thresholds
1029    cnt += sprintf(&str[cnt],"High Threshold: %6.1f\n",
1030           TempToFloat(mstatus->high_threshold,ConvertToF));
1031 
1032    cnt += sprintf(&str[cnt],"Low Threshold: %6.1f\n",
1033           TempToFloat(mstatus->low_threshold,ConvertToF));
1034 
1035    // time from D1921
1036    SecondsToDate(&td,mstatus->current_time);
1037    cnt += sprintf(&str[cnt],"Current Real-Time Clock from DS1921: %02d/%02d/%04d  %02d:%02d:%02d\n",
1038        td.month,td.day,td.year,td.hour,td.minute,td.second);
1039 
1040 #ifndef __MC68K__
1041    // current PC time
1042    time(&tlong);
1043    tstruct = localtime(&tlong);
1044 
1045    cnt += sprintf(&str[cnt],"Current PC Time: %02d/%02d/%04d  %02d:%02d:%02d\n",
1046        tstruct->tm_mon + 1,tstruct->tm_mday,tstruct->tm_year + 1900,
1047        tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec);
1048 #endif
1049 
1050    // zero terminate string
1051    str[cnt] = 0;
1052 }
1053 
1054 //----------------------------------------------------------------------
1055 //  Interpret the Histogram by looking at the 'raw' portion of the
1056 //  Histogram structure.  Store the temperature range values in Celsius.
1057 //
InterpretHistogram(Histogram * hist)1058 void InterpretHistogram(Histogram *hist)
1059 {
1060    int i;
1061 
1062    // loop through each bin value
1063    for (i = 0; i < 126; i += 2) // (2.00)
1064    {
1065       // get the bin value
1066       hist->bin_count[i / 2] = hist->hist_raw[i] | (hist->hist_raw[i + 1] << 8);
1067 
1068       // start value for this bin
1069       hist->start_range[i / 2] = TempToFloat((uchar)((i / 2) << 2),FALSE);
1070 
1071       // end value for this bin
1072       hist->end_range[i / 2] = TempToFloat((uchar)(((i / 2) << 2) | 0x03),FALSE);
1073    }
1074 }
1075 
1076 //--------------------------------------------------------------------------
1077 // Take the Histogram structure and convert to string format
1078 //
HistogramToString(Histogram * hist,int ConvertToF,char * str)1079 void HistogramToString(Histogram *hist, int ConvertToF, char *str)
1080 {
1081    int cnt=0,i;
1082 
1083    // title
1084    cnt += sprintf(&str[cnt],"Temperature Histogram\n---------------------\n"
1085                             "Format: [Temp Range, Count] ");
1086 
1087    if (ConvertToF)
1088       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1089    else
1090       cnt += sprintf(&str[cnt],"(Celsius)\n");
1091 
1092    // loop through bins
1093    for (i = 0; i < 63; i++) // (2.00)
1094    {
1095       cnt += sprintf(&str[cnt],"%6.1f to %6.1f, %d\n",
1096                      (ConvertToF) ? CToF(hist->start_range[i]): hist->start_range[i],
1097                      (ConvertToF) ? CToF(hist->end_range[i]): hist->end_range[i],
1098                       hist->bin_count[i]);
1099    }
1100 
1101    // zero terminate string
1102    str[cnt] = 0;
1103 }
1104 
1105 //----------------------------------------------------------------------
1106 //  Interpret the Temperature Alarm Event data by looking at the 'raw'
1107 //  portion of the TempAlarmEvents structure.  Mission Status is needed
1108 //  to interpret the events.
1109 //
InterpretAlarms(TempAlarmEvents * alarm,MissionStatus * mstatus)1110 void InterpretAlarms(TempAlarmEvents *alarm, MissionStatus *mstatus)
1111 {
1112    int i;
1113    ulong event_mission_count;
1114    uchar duration;
1115 
1116    // low events
1117    alarm->num_low = 0;
1118    for (i = 0; i < 48; i += 4)
1119    {
1120       // get the mission start count of this event
1121       event_mission_count = (alarm->alarm_raw[i + 2] << 16) |
1122                             (alarm->alarm_raw[i + 1] << 8) |
1123                              alarm->alarm_raw[i];
1124 
1125       // check if done with low events
1126       if (!event_mission_count)
1127          break;
1128 
1129       // get the duration
1130       duration = alarm->alarm_raw[i + 3];
1131 
1132       // calculate the start time
1133       alarm->low_start_time[alarm->num_low] =
1134           mstatus->mission_start_time +
1135           (event_mission_count - 1) * (mstatus->sample_rate * 60);
1136 
1137       // calculate the end time
1138       alarm->low_end_time[alarm->num_low] =
1139           alarm->low_start_time[alarm->num_low] +
1140           (duration - 1) * (mstatus->sample_rate * 60);
1141 
1142       // increment number of low events
1143       alarm->num_low++;
1144    }
1145 
1146    // high events
1147    alarm->num_high = 0;
1148    for (i = 48; i < 96; i += 4)
1149    {
1150       // get the mission start count of this event
1151       event_mission_count = (alarm->alarm_raw[i + 2] << 16) |
1152                             (alarm->alarm_raw[i + 1] << 8) |
1153                              alarm->alarm_raw[i];
1154 
1155       // check if done with low events
1156       if (!event_mission_count)
1157          break;
1158 
1159       // get the duration
1160       duration = alarm->alarm_raw[i + 3];
1161 
1162       // calculate the start time
1163       alarm->high_start_time[alarm->num_high] =
1164           mstatus->mission_start_time +
1165           (event_mission_count - 1) * (mstatus->sample_rate * 60);
1166 
1167       // calculate the end time
1168       alarm->high_end_time[alarm->num_high] =
1169           alarm->high_start_time[alarm->num_high] +
1170           (duration - 1) * (mstatus->sample_rate * 60);
1171 
1172       // increment number of low events
1173       alarm->num_high++;
1174    }
1175 }
1176 
1177 //--------------------------------------------------------------------------
1178 // Take the Temperature Alarms Events structure and convert to string
1179 // format
1180 //
AlarmsToString(TempAlarmEvents * alarm,char * str)1181 void AlarmsToString(TempAlarmEvents *alarm, char *str)
1182 {
1183    int i, cnt=0;
1184    timedate td;
1185 
1186    // title
1187    cnt += sprintf(&str[cnt],"Temperature Alarms\n------------------\n"
1188                             "Format: [(HIGH/LOW), Time/Date Range]\n");
1189 
1190    // loop through each low alarm
1191    for (i = 0; i < alarm->num_low; i++)
1192    {
1193       cnt += sprintf(&str[cnt],"LOW  , ");
1194       // start time
1195       SecondsToDate(&td,alarm->low_start_time[i]);
1196       cnt += sprintf(&str[cnt]," %02d/%02d/%04d  %02d:%02d  to  ",
1197          td.month,td.day,td.year,td.hour,td.minute);
1198       // end time
1199       SecondsToDate(&td,alarm->low_end_time[i]);
1200       cnt += sprintf(&str[cnt]," %02d/%02d/%04d  %02d:%02d\n",
1201          td.month,td.day,td.year,td.hour,td.minute);
1202    }
1203 
1204    // loop through each high alarm
1205    for (i = 0; i < alarm->num_high; i++)
1206    {
1207       cnt += sprintf(&str[cnt],"HIGH , ");
1208       // start time
1209       SecondsToDate(&td,alarm->high_start_time[i]);
1210       cnt += sprintf(&str[cnt]," %02d/%02d/%04d  %02d:%02d  to  ",
1211          td.month,td.day,td.year,td.hour,td.minute);
1212       // end time
1213       SecondsToDate(&td,alarm->high_end_time[i]);
1214       cnt += sprintf(&str[cnt]," %02d/%02d/%04d  %02d:%02d\n",
1215          td.month,td.day,td.year,td.hour,td.minute);
1216    }
1217 
1218    // zero terminate string
1219    str[cnt] = 0;
1220 }
1221 
1222 //----------------------------------------------------------------------
1223 //  Interpret the Log data by looking at the 'raw'
1224 //  portion of the Log structure.  Mission Status is needed
1225 //  to interpret when the logs occurred.
1226 //
InterpretLog(Log * log,MissionStatus * mstatus)1227 void InterpretLog(Log *log, MissionStatus *mstatus)
1228 {
1229    ulong loops=0,overlap=0,lastlog=2048,i;
1230    int logcnt=0;
1231 
1232    // check if wrap occurred
1233    if (mstatus->rollover_occurred)
1234    {
1235       // calculate the number loops
1236       loops = (mstatus->mission_samples / 2048) - 1;
1237       // calculate the number of overlap
1238       overlap = mstatus->mission_samples % 2048;
1239       log->num_log = 2048;
1240    }
1241    else
1242    {
1243       log->start_time = mstatus->mission_start_time;
1244       if (mstatus->mission_samples > 2048)  // (1.02)
1245          lastlog = 2048;
1246       else
1247          lastlog = mstatus->mission_samples;
1248       log->num_log = (int)lastlog;
1249    }
1250 
1251    // set the interval
1252    log->interval = mstatus->sample_rate * 60;
1253 
1254    // caluclate the start time of the first log value
1255    log->start_time = mstatus->mission_start_time +
1256       loops * 2048 * log->interval + overlap * log->interval;
1257 
1258    // loop to fill in the remainder first
1259    for (i = overlap; i < lastlog; i++)
1260       log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1261 
1262    // loop to get the overlap
1263    for (i = 0; i < overlap; i++)
1264       log->temp[logcnt++] = TempToFloat(log->log_raw[i],FALSE);
1265 }
1266 
1267 //--------------------------------------------------------------------------
1268 // Take the Log structure and convert to string
1269 // format
1270 //
LogToString(Log * log,int ConvertToF,char * str)1271 void LogToString(Log *log, int ConvertToF, char *str)
1272 {
1273    int i,cnt=0;
1274    ulong logtime;
1275    timedate td;
1276 
1277    // title
1278    cnt += sprintf(&str[cnt],"Log Data\n--------\n"
1279                             "Format: [Time/Date , Temperature] ");
1280    if (ConvertToF)
1281       cnt += sprintf(&str[cnt],"(Fahrenheit)\n");
1282    else
1283       cnt += sprintf(&str[cnt],"(Celsius)\n");
1284 
1285    // loop through the logs
1286    logtime = log->start_time;
1287    for (i = 0; i < log->num_log; i++)
1288    {
1289       // time
1290       SecondsToDate(&td,logtime);
1291       cnt += sprintf(&str[cnt],"%02d/%02d/%04d  %02d:%02d ,",
1292          td.month,td.day,td.year,td.hour,td.minute);
1293       // temp
1294       cnt += sprintf(&str[cnt],"%6.1f\n",
1295              (ConvertToF) ? CToF(log->temp[i]): log->temp[i]);
1296 
1297       // increment the time
1298       logtime += log->interval;
1299    }
1300 
1301    // zero terminate string
1302    str[cnt] = 0;
1303 }
1304 
1305 //--------------------------------------------------------------------------
1306 // Convert the raw debug data to a string
1307 //
DebugToString(MissionStatus * mstatus,TempAlarmEvents * alarm,Histogram * hist,Log * log,char * str)1308 void DebugToString(MissionStatus *mstatus, TempAlarmEvents *alarm,
1309                    Histogram *hist, Log *log, char *str)
1310 {
1311    int i,cnt=0;
1312 
1313    // title
1314    cnt += sprintf(&str[cnt],"Debug Dump\n----------\nRegister Page:\n");
1315 
1316    // reg
1317    for (i = 0; i < 32; i++)
1318    {
1319       cnt += sprintf(&str[cnt],"%02X ",mstatus->status_raw[i]);
1320       if (i && (((i + 1) % 16) == 0))
1321          cnt += sprintf(&str[cnt],"\n");
1322    }
1323 
1324    // alarms
1325    cnt += sprintf(&str[cnt],"Alarms:\n");
1326    for (i = 0; i < 96; i++)
1327    {
1328       cnt += sprintf(&str[cnt],"%02X ",alarm->alarm_raw[i]);
1329       if (i && (((i + 1) % 16) == 0))
1330          cnt += sprintf(&str[cnt],"\n");
1331    }
1332 
1333    // histogram
1334    cnt += sprintf(&str[cnt],"Histogram:\n");
1335    for (i = 0; i < 128; i++)
1336    {
1337       cnt += sprintf(&str[cnt],"%02X ",hist->hist_raw[i]);
1338       if (i && (((i + 1) % 16) == 0))
1339          cnt += sprintf(&str[cnt],"\n");
1340    }
1341 
1342 
1343    // log
1344    cnt += sprintf(&str[cnt],"Log:\n");
1345    for (i = 0; i < ((log->num_log > 2048) ? 2048 : log->num_log); i++)
1346    {
1347       cnt += sprintf(&str[cnt],"%02X ",log->log_raw[i]);
1348       if (i && (((i + 1) % 16) == 0))
1349          cnt += sprintf(&str[cnt],"\n");
1350    }
1351 
1352    // zero terminate string
1353    str[cnt] = 0;
1354 }
1355 
1356 //--------------------------------------------------------------------------
1357 // Take one byte BCD value and return binary value
1358 //
BCDToBin(uchar bcd)1359 uchar BCDToBin(uchar bcd)
1360 {
1361    return (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
1362 }
1363 
1364 
1365 //--------------------------------------------------------------------------
1366 // Take a 4 byte long string and convert it into a timedata structure.
1367 //
1368 static int dm[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,365 };
1369 
SecondsToDate(timedate * td,ulong x)1370 void SecondsToDate(timedate *td, ulong x)
1371 {
1372    short tmp,i,j;
1373    ulong y;
1374 
1375    // check to make sure date is not over 2070 (sanity check)
1376    if (x > 0xBBF81E00L)
1377       x = 0;
1378 
1379    y = x/60;  td->second = (ushort)(x-60*y);
1380    x = y/60;  td->minute = (ushort)(y-60*x);
1381    y = x/24;  td->hour   = (ushort)(x-24*y);
1382    x = 4*(y+731);  td->year = (ushort)(x/1461);
1383    i = (int)((x-1461*(ulong)(td->year))/4);  td->month = 13;
1384 
1385    do
1386    {
1387       td->month -= 1;
1388       tmp = (td->month > 2) && ((td->year & 3)==0) ? 1 : 0;
1389       j = dm[td->month]+tmp;
1390 
1391    } while (i < j);
1392 
1393    td->day = i-j+1;
1394 
1395    // slight adjustment to algorithm
1396    if (td->day == 0)
1397       td->day = 1;
1398 
1399    td->year = (td->year < 32)  ? td->year + 68 + 1900: td->year - 32 + 2000;
1400 }
1401 
1402 //--------------------------------------------------------------------------
1403 // DateToSeconds takes a time/date structure and converts it into the
1404 // number of seconds since 1970
1405 //
DateToSeconds(timedate * td)1406 ulong DateToSeconds(timedate *td)
1407 {
1408    ulong Sv,Bv,Xv;
1409 
1410    // convert the date/time values into the 5 byte format used in the touch
1411    if (td->year >= 2000)
1412       Sv = td->year + 32 - 2000;
1413    else
1414       Sv = td->year - 68 - 1900;
1415 
1416    if ((td->month > 2) && ( (Sv & 3) == 0))
1417      Bv = 1;
1418    else
1419      Bv = 0;
1420 
1421    Xv = 365 * (Sv-2) + (Sv-1)/4 + dm[td->month] + td->day + Bv - 1;
1422 
1423    Xv = 86400 * Xv + (ulong)(td->second) + 60*((ulong)(td->minute) + 60*(ulong)(td->hour));
1424 
1425    return Xv;
1426 }
1427 
1428 //--------------------------------------------------------------------------
1429 // Convert from DS1921 termature format to a float
1430 //
1431 //
TempToFloat(uchar tmp,int ConvertToF)1432 float TempToFloat(uchar tmp, int ConvertToF)
1433 {
1434    float tfloat;
1435 
1436    tfloat = (float)((tmp / 2.0) - 40.0);
1437 
1438    if (ConvertToF)
1439       return (float)(tfloat * 9.0 / 5.0 + 32.0);
1440    else
1441       return tfloat;
1442 }
1443 
1444 //--------------------------------------------------------------------------
1445 // Convert from Celsius to Fahrenheit
1446 //
CToF(float CVal)1447 float CToF(float CVal)
1448 {
1449    return (float)(CVal * 9.0 / 5.0 + 32.0);
1450 }
1451