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