Rev 74 | Rev 76 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 74 | Rev 75 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | */ |
18 | */ |
19 | /* USER CODE END Header */ |
19 | /* USER CODE END Header */ |
20 | /* Includes ------------------------------------------------------------------*/ |
20 | /* Includes ------------------------------------------------------------------*/ |
21 | #include "main.h" |
21 | #include "main.h" |
22 | 22 | ||
- | 23 | #include <stdlib.h> |
|
- | 24 | ||
23 | /* Private includes ----------------------------------------------------------*/ |
25 | /* Private includes ----------------------------------------------------------*/ |
24 | /* USER CODE BEGIN Includes */ |
26 | /* USER CODE BEGIN Includes */ |
25 | 27 | ||
26 | #include "libPLX/plx.h" |
28 | #include "libPLX/plx.h" |
- | 29 | #include "libPLX/displayinfo.h" |
|
27 | #include "libSerial/serial.H" |
30 | #include "libSerial/serialUtils.H" |
- | 31 | ||
28 | #include "libSmallPrintf/small_printf.h" |
32 | #include "libSmallPrintf/small_printf.h" |
29 | #include "libNMEA/nmea.h" |
33 | #include "libNMEA/nmea.h" |
30 | #include "switches.h" |
34 | #include "switches.h" |
31 | #include <string.h> |
35 | #include <string.h> |
32 | 36 | ||
Line 61... | Line 65... | ||
61 | UART_HandleTypeDef huart3; |
65 | UART_HandleTypeDef huart3; |
62 | 66 | ||
63 | /* USER CODE BEGIN PV */ |
67 | /* USER CODE BEGIN PV */ |
64 | /* Private variables ---------------------------------------------------------*/ |
68 | /* Private variables ---------------------------------------------------------*/ |
65 | 69 | ||
66 | context_t contexts[MAX_DISPLAYS]; |
- | |
67 | - | ||
68 | ///@brief timeout when the ignition is switched off |
70 | ///@brief timeout when the ignition is switched off |
69 | #define IGNITION_OFF_TIMEOUT 30000UL |
71 | uint32_t const IGNITION_OFF_TIMEOUT = 30000UL; |
70 | 72 | ||
71 | /// @brief 1000mS per logger period, print average per period |
73 | /// @brief 1000mS per logger period, print average per period |
72 | #define LOGGER_INTERVAL 500UL |
74 | uint32_t const LOGGER_INTERVAL = 250UL; |
73 | 75 | ||
74 | /// @brief about 10 seconds after twiddle, save the dial position. |
76 | /// @brief about 10 seconds after twiddle, save the dial position. |
75 | const int DialTimeout = 100; |
77 | const int DialTimeout = 100; |
76 | 78 | ||
77 | /// @brief Data storage for readings |
79 | /// @brief Unused Observation |
- | 80 | uniqueObs_t const nullObs = {PLX_MAX_OBS, |
|
- | 81 | PLX_MAX_INST}; |
|
- | 82 | ||
78 | info_t Info[MAXRDG]; |
83 | /// @brief Null context |
- | 84 | context_t const nullContext = {.knobPos = -1, |
|
- | 85 | .dial_timer = 0, |
|
- | 86 | .dial0 = -1, |
|
- | 87 | .dial1 = -1, |
|
- | 88 | .OldObservation = nullObs}; |
|
79 | 89 | ||
80 | /// @brief Define a null item |
90 | /// @brief Define a null item |
81 | const info_t nullInfo = {.Max = 0, |
91 | info_t const nullInfo = {.Max = 0, |
82 | .Min = 0xFFF, |
92 | .Min = 0xFFF, |
83 | .sum = 0, |
93 | .sum = 0, |
84 | .count = 0, |
94 | .count = 0, |
85 | .updated = 0, |
95 | .updated = 0, |
86 | .lastUpdated = 0, |
96 | .lastUpdated = 0, |
87 | .observation.Obs = PLX_MAX_OBS, |
97 | .observation = nullObs}; |
- | 98 | ||
- | 99 | context_t contexts[MAX_DISPLAYS]; |
|
- | 100 | ||
88 | .observation.Instance = PLX_MAX_INST}; |
101 | /// @brief Data storage for readings |
- | 102 | info_t Info[MAXRDG]; |
|
89 | 103 | ||
90 | /// \brief storage for incoming data |
104 | /// \brief storage for incoming data |
91 | data_t Data; |
105 | data_t Data; |
92 | 106 | ||
93 | uint32_t Latch_Timer = IGNITION_OFF_TIMEOUT; |
107 | uint32_t Latch_Timer; |
94 | 108 | ||
95 | // location for GPS data |
109 | // location for GPS data |
96 | Location loc; |
110 | Location loc; |
97 | 111 | ||
98 | /// @brief Time when the logged data will be sent |
112 | /// @brief Time when the logged data will be sent |
99 | uint32_t nextTickReload = 0; |
113 | uint32_t nextTickReload; |
100 | 114 | ||
101 | /* USER CODE END PV */ |
115 | /* USER CODE END PV */ |
102 | 116 | ||
103 | /* Private function prototypes -----------------------------------------------*/ |
117 | /* Private function prototypes -----------------------------------------------*/ |
104 | void SystemClock_Config(void); |
118 | void SystemClock_Config(void); |
Line 292... | Line 306... | ||
292 | // Initialuse UART4 for 4800 baud NMEA. |
306 | // Initialuse UART4 for 4800 baud NMEA. |
293 | setBaud(&uc4, 4800); |
307 | setBaud(&uc4, 4800); |
294 | 308 | ||
295 | cc_init(); |
309 | cc_init(); |
296 | 310 | ||
297 | int i; |
- | |
298 | for (i = 0; i < 2; i++) |
311 | for (int i = 0; i < MAX_DISPLAYS; ++i) |
299 | { |
312 | { |
300 | contexts[i].knobPos = -1; // set the knob position |
313 | contexts[i] = nullContext; // set the knob position |
301 | } |
314 | } |
302 | 315 | ||
303 | /* reset the display timeout, latch on power from accessories */ |
316 | /* reset the display timeout, latch on power from accessories */ |
304 | Latch_Timer = IGNITION_OFF_TIMEOUT; |
317 | Latch_Timer = IGNITION_OFF_TIMEOUT; |
305 | HAL_GPIO_WritePin(POWER_LATCH_GPIO_Port, POWER_LATCH_Pin, GPIO_PIN_RESET); |
318 | HAL_GPIO_WritePin(POWER_LATCH_GPIO_Port, POWER_LATCH_Pin, GPIO_PIN_RESET); |
306 | 319 | ||
- | 320 | /// @brief Time when the logged data will be sent |
|
- | 321 | ||
307 | setRmcCallback(&rmc_callback); |
322 | setRmcCallback(&rmc_callback); |
308 | 323 | ||
309 | // data timeout |
324 | // data timeout |
310 | uint32_t timeout = 0; // |
325 | uint32_t timeout = 0; // |
311 | 326 | ||
312 | // used in NMEA style logging |
327 | // used in NMEA style logging |
313 | uint32_t nextTick = 0; ///< time to send next |
328 | uint32_t nextTick = 0; ///< time to send next |
- | 329 | nextTickReload = 0; |
|
314 | uint32_t offsetTicks = 0; ///< time to print as offset in mS for each loop |
330 | uint32_t offsetTicks = 0; ///< time to print as offset in mS for each loop |
315 | 331 | ||
316 | // PLX decoder protocols |
332 | // PLX decoder protocols |
317 | char PLXPacket = 0; |
333 | char PLXPacket = 0; |
- | 334 | int PLXPtr = 0; |
|
318 | 335 | ||
319 | for (i = 0; i < MAXRDG; i++) |
336 | for (int i = 0; i < MAXRDG; ++i) |
320 | { |
337 | { |
321 | Info[i] = nullInfo; |
338 | Info[i] = nullInfo; |
322 | } |
339 | } |
323 | 340 | ||
324 | int PLXPtr = 0; |
- | |
325 | - | ||
326 | uint32_t resetCounter = 0; // record time at which both reset buttons were first pressed. |
341 | uint32_t resetCounter = 0; // record time at which both reset buttons were first pressed. |
327 | 342 | ||
328 | /* USER CODE END 2 */ |
343 | /* USER CODE END 2 */ |
329 | 344 | ||
330 | /* Infinite loop */ |
345 | /* Infinite loop */ |
Line 363... | Line 378... | ||
363 | if (resetCounter != 0) |
378 | if (resetCounter != 0) |
364 | { |
379 | { |
365 | // Held down reset button for 10 seconds, clear NVRAM. |
380 | // Held down reset button for 10 seconds, clear NVRAM. |
366 | if ((HAL_GetTick() - resetCounter) > 10000) |
381 | if ((HAL_GetTick() - resetCounter) > 10000) |
367 | { |
382 | { |
368 | for (i = 0; i < 2; i++) |
383 | for (int i = 0; i < MAX_DISPLAYS; i++) |
369 | { |
384 | { |
370 | contexts[i].knobPos = -1; // set the knob position |
385 | contexts[i] = nullContext; |
371 | contexts[i].dial_timer = 1; // timeout immediately when decremented |
386 | contexts[i].dial_timer = 1; // timeout immediately when decremented |
372 | } |
387 | } |
373 | erase_nvram(); |
388 | erase_nvram(); |
374 | } |
389 | } |
375 | resetCounter = 0; |
390 | resetCounter = 0; |
Line 382... | Line 397... | ||
382 | memset(loc.time, '-', 6); |
397 | memset(loc.time, '-', 6); |
383 | 398 | ||
384 | // if permitted, log data from RMC packet |
399 | // if permitted, log data from RMC packet |
385 | if (btConnected()) |
400 | if (btConnected()) |
386 | { |
401 | { |
387 | // Any RMC data, send it, reset the logger timeout |
- | |
388 | - | ||
389 | // Timeout for data logging regularly |
402 | // Timeout for data logging regularly |
390 | if (HAL_GetTick() > nextTick) |
403 | if (HAL_GetTick() > nextTick) |
391 | { |
404 | { |
392 | nextTick = nextTickReload; |
405 | nextTick = nextTickReload; |
393 | nextTickReload += LOGGER_INTERVAL; |
406 | nextTickReload += LOGGER_INTERVAL; |
394 | 407 | ||
395 | // Send items to BT if it is in connected state |
408 | // Send items to BT if it is in connected state |
396 | // print timestamp as a $PLTIM record. |
409 | // print timestamp as a $PLTIM record. |
397 | char linebuff[20]; |
410 | char linebuff[20]; |
398 | strftime(linebuff, sizeof(linebuff), "%H%M%S", &loc.tv); |
411 | strftime(linebuff, sizeof(linebuff), "%H%M%S", &loc.tv); |
399 | 412 | ||
400 | char outbuff[100]; |
413 | char outbuff[100]; |
401 | int cnt = small_sprintf(outbuff, "$PLTIM,%s.%03lu\n", linebuff, offsetTicks); |
414 | int cnt = small_sprintf(outbuff, "$PLTIM,%s.%03lu\n", linebuff, offsetTicks); |
402 | sendString(&uc3, outbuff, cnt); |
415 | sendString(&uc3, outbuff, cnt); |
403 | offsetTicks += LOGGER_INTERVAL; |
416 | offsetTicks += LOGGER_INTERVAL; |
- | 417 | ||
404 | 418 | // increment timer |
|
405 | if (offsetTicks >= (1000)) |
419 | if (offsetTicks >= (1000)) |
406 | { |
420 | { |
407 | offsetTicks = 0; |
421 | offsetTicks -= 1000; |
408 | loc.tv.tm_sec++; |
422 | loc.tv.tm_sec++; |
409 | if (loc.tv.tm_sec >= 60) |
423 | if (loc.tv.tm_sec >= 60) |
410 | { |
424 | { |
411 | loc.tv.tm_sec = 0; |
425 | loc.tv.tm_sec = 0; |
412 | loc.tv.tm_min++; |
426 | loc.tv.tm_min++; |
Line 416... | Line 430... | ||
416 | if (loc.tv.tm_hour >= 24) |
430 | if (loc.tv.tm_hour >= 24) |
417 | loc.tv.tm_hour = 0; |
431 | loc.tv.tm_hour = 0; |
418 | } |
432 | } |
419 | } |
433 | } |
420 | } |
434 | } |
421 | 435 | ||
422 | - | ||
423 | - | ||
424 | - | ||
425 | - | ||
426 | - | ||
427 | for (int i = 0; i < MAXRDG; ++i) |
436 | for (int i = 0; i < MAXRDG; ++i) |
428 | { |
437 | { |
429 | if (!isValid(i)) |
438 | if (!isValid(i)) |
430 | continue; |
439 | continue; |
- | 440 | // format output |
|
- | 441 | // avoid division by zero for items with no sample data this iteration |
|
- | 442 | if (Info[i].count == 0) |
|
- | 443 | continue; |
|
- | 444 | double average = (double)Info[i].sum / Info[i].count; |
|
- | 445 | enum PLX_Observations Observation = Info[i].observation.Obs; |
|
- | 446 | ||
- | 447 | double cur_rdg = ConveriMFDRaw2Data((enum PLX_Observations)Observation, DisplayInfo[Observation].Units, |
|
- | 448 | average); |
|
- | 449 | int cnt; |
|
- | 450 | int intPart; |
|
- | 451 | switch (DisplayInfo[Observation].DP) |
|
- | 452 | { |
|
- | 453 | default: |
|
- | 454 | case 0: |
|
- | 455 | cnt = small_sprintf(outbuff, |
|
431 | // print logger items as $PLLOG record |
456 | "$PLLOG,%s,%d,%d", |
- | 457 | DisplayInfo[Info[i].observation.Obs].name, |
|
- | 458 | Info[i].observation.Instance, |
|
- | 459 | (int)cur_rdg); |
|
- | 460 | ||
- | 461 | break; |
|
- | 462 | case 1: |
|
- | 463 | intPart = (int)(cur_rdg * 10); |
|
432 | int cnt = small_sprintf(outbuff, |
464 | cnt = small_sprintf(outbuff, |
433 | "$PLLOG,%d,%d,%ld", |
465 | "$PLLOG,%s,%d,%d.%1d", |
- | 466 | DisplayInfo[Info[i].observation.Obs].name, |
|
434 | Info[i].observation.Obs, |
467 | Info[i].observation.Instance, |
- | 468 | intPart / 10, abs(intPart) % 10); |
|
- | 469 | ||
- | 470 | break; |
|
- | 471 | case 2: |
|
- | 472 | intPart = (int)(cur_rdg * 100); |
|
- | 473 | cnt = small_sprintf(outbuff, |
|
- | 474 | "$PLLOG,%s,%d,%d.%02d", |
|
- | 475 | DisplayInfo[Info[i].observation.Obs].name, |
|
435 | Info[i].observation.Instance, |
476 | Info[i].observation.Instance, |
436 | Info[i].count == 0 ? 0 : Info[i].sum / Info[i].count); |
477 | intPart / 100, abs(intPart) % 100); |
- | 478 | ||
- | 479 | break; |
|
- | 480 | } |
|
- | 481 | ||
437 | Info[i].count = 0; |
482 | Info[i].count = 0; |
438 | Info[i].sum = 0; |
483 | Info[i].sum = 0; |
439 | 484 | ||
440 | // NMEA style checksum |
485 | // NMEA style checksum |
441 | int ck; |
486 | int ck; |
Line 488... | Line 533... | ||
488 | { |
533 | { |
489 | // we can now decode the selected parameter |
534 | // we can now decode the selected parameter |
490 | int PLXNewItems = PLXPtr / sizeof(PLX_SensorInfo); // total items in last reading batch |
535 | int PLXNewItems = PLXPtr / sizeof(PLX_SensorInfo); // total items in last reading batch |
491 | 536 | ||
492 | // process items |
537 | // process items |
493 | for (i = 0; i < PLXNewItems; i++) |
538 | for (int dataItem = 0; dataItem < PLXNewItems; ++dataItem) |
494 | { |
539 | { |
495 | // search to see if the item already has a slot in the Info[] array |
540 | // search to see if the item already has a slot in the Info[] array |
496 | // match the observation and instance: if found, update entry |
541 | // match the observation and instance: if found, update entry |
497 | enum PLX_Observations observation = ConvPLX(Data.Sensor[i].AddrH, |
542 | enum PLX_Observations observation = ConvPLX(Data.Sensor[dataItem].AddrH, |
498 | Data.Sensor[i].AddrL); |
543 | Data.Sensor[dataItem].AddrL); |
499 | 544 | ||
500 | char instance = Data.Sensor[i].Instance; |
545 | char instance = Data.Sensor[dataItem].Instance; |
501 | 546 | ||
- | 547 | int16_t data = ConvPLX(Data.Sensor[dataItem].ReadingH, |
|
- | 548 | Data.Sensor[dataItem].ReadingL); |
|
502 | // validate the current item, discard out of range |
549 | // validate the current item, discard out of range |
503 | 550 | ||
504 | if ((instance > PLX_MAX_INST) || (observation > PLX_MAX_OBS)) |
551 | if ((instance > PLX_MAX_INST) || (observation > PLX_MAX_OBS)) |
505 | continue; |
552 | continue; |
506 | 553 | ||
507 | // search for the item in the list |
554 | // search for the item in the list |
508 | int j; |
555 | int currentSlot; |
509 | for (j = 0; j < MAXRDG; ++j) |
556 | for (currentSlot = 0; currentSlot < MAXRDG; ++currentSlot) |
510 | { |
557 | { |
511 | if ((Info[j].observation.Obs == observation) && (Info[j].observation.Instance == instance)) |
558 | if ((Info[currentSlot].observation.Obs == observation) && (Info[currentSlot].observation.Instance == instance)) |
512 | break; |
559 | break; |
513 | } |
560 | } |
514 | // fallen off the end of the list of existing items without a match, so j points at next new item |
561 | // fallen off the end of the list of existing items without a match, so j points at next new item |
515 | // |
562 | // |
516 | // Find an unused slot |
563 | // Find an unused slot |
517 | 564 | ||
518 | if (j == MAXRDG) |
565 | if (currentSlot == MAXRDG) |
519 | { |
566 | { |
520 | int k; |
567 | int k; |
521 | { |
568 | { |
522 | for (k = 0; k < MAXRDG; ++k) |
569 | for (k = 0; k < MAXRDG; ++k) |
523 | if (!isValid(k)) |
570 | if (!isValid(k)) |
524 | { |
571 | { |
525 | j = k; // found a spare slot |
572 | currentSlot = k; // found a spare slot |
526 | break; |
573 | break; |
527 | } |
574 | } |
528 | } |
575 | } |
529 | if (k == MAXRDG) |
576 | if (k == MAXRDG) |
530 | continue; // abandon this iteration |
577 | continue; // abandon this iteration |
531 | } |
578 | } |
532 | 579 | ||
533 | // give up if we are going to fall off the end of the array |
580 | // give up if we are going to fall off the end of the array |
534 | if (j > MAXRDG) |
581 | if (currentSlot >= MAXRDG) |
535 | break; |
582 | break; |
536 | 583 | ||
537 | Info[j].observation.Obs = observation; |
584 | Info[currentSlot].observation.Obs = observation; |
538 | 585 | ||
539 | Info[j].observation.Instance = instance; |
586 | Info[currentSlot].observation.Instance = instance; |
540 | Info[j].data = ConvPLX(Data.Sensor[j].ReadingH, |
587 | Info[currentSlot].data = data; |
541 | Data.Sensor[j].ReadingL); |
- | |
542 | if (Info[j].data > Info[j].Max) |
588 | if (data > Info[currentSlot].Max) |
543 | { |
589 | { |
544 | Info[j].Max = Info[j].data; |
590 | Info[currentSlot].Max = data; |
545 | } |
591 | } |
546 | if (Info[j].data < Info[j].Min) |
592 | if (data < Info[currentSlot].Min) |
547 | { |
593 | { |
548 | Info[j].Min = Info[j].data; |
594 | Info[currentSlot].Min = data; |
549 | } |
595 | } |
550 | // take an average |
596 | // take an average |
551 | Info[j].sum += Info[j].data; |
597 | Info[currentSlot].sum += data; |
552 | Info[j].count++; |
598 | Info[currentSlot].count++; |
553 | // note the last update time |
599 | // note the last update time |
554 | Info[j].lastUpdated = HAL_GetTick(); |
600 | Info[currentSlot].lastUpdated = HAL_GetTick(); |
555 | Info[j].updated = 1; // it has been updated |
601 | Info[currentSlot].updated = 1; // it has been updated |
556 | } |
602 | } |
557 | PLXPtr = 0; |
603 | PLXPtr = 0; |
558 | PLXPacket = 0; |
604 | PLXPacket = 0; |
559 | 605 | ||
560 | // scan through and invalidate all old items |
606 | // scan through and invalidate all old items |
Line 578... | Line 624... | ||
578 | Data.Bytes[PLXPtr++] = c; |
624 | Data.Bytes[PLXPtr++] = c; |
579 | } |
625 | } |
580 | } |
626 | } |
581 | 627 | ||
582 | // handle switch rotation |
628 | // handle switch rotation |
583 | for (i = 0; i < MAX_DIALS; ++i) |
629 | for (int i = 0; i < MAX_DIALS; ++i) |
584 | { |
630 | { |
585 | int delta = get_dial_diff(i); |
631 | int delta = get_dial_diff(i); |
586 | int pos = contexts[i].knobPos; |
632 | int pos = contexts[i].knobPos; |
587 | if (pos < 0) |
633 | if (pos < 0) |
588 | break; // dont process until we have read NVRAM for the first time . |
634 | break; // dont process until we have read NVRAM for the first time . |
Line 604... | Line 650... | ||
604 | break; |
650 | break; |
605 | } |
651 | } |
606 | 652 | ||
607 | // move in negative direction |
653 | // move in negative direction |
608 | while (delta < 0) |
654 | while (delta < 0) |
609 | - | ||
610 | { |
655 | { |
611 | // skip invalid items, dont count |
656 | // skip invalid items, dont count |
612 | if (pos > 0) |
657 | if (pos > 0) |
613 | pos--; |
658 | pos--; |
614 | else |
659 | else |
Line 626... | Line 671... | ||
626 | if (pos != start) |
671 | if (pos != start) |
627 | contexts[i].dial_timer = DialTimeout; |
672 | contexts[i].dial_timer = DialTimeout; |
628 | } |
673 | } |
629 | 674 | ||
630 | int suppress = -1; |
675 | int suppress = -1; |
631 | for (i = 0; i < MAX_DISPLAYS; i++) |
676 | for (int i = 0; i < MAX_DISPLAYS; ++i) |
632 | { // now to display the information |
677 | { // now to display the information |
633 | suppress = DisplayCurrent(i, suppress); |
678 | suppress = DisplayCurrent(i, suppress); |
634 | 679 | ||
635 | cc_check_nvram(i); |
680 | cc_check_nvram(i); |
636 | } |
681 | } |