comparison src/p2_deco.c @ 584:d63dec562d50

CNS fix
author heinrichsweikamp
date Wed, 28 Feb 2018 10:24:54 +0100
parents b455b31ce022
children 00ad4ffd915b
comparison
equal deleted inserted replaced
583:6636cbe64c6d 584:d63dec562d50
1 // *************************************************************************** 1 // ***************************************************************************
2 // p2_deco.c REFACTORED VERSION V2.97b 2 // p2_deco.c REFACTORED VERSION V2.98
3 // 3 //
4 // Created on: 12.05.2009 4 // Created on: 12.05.2009
5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others 5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others
6 // 6 //
7 // *************************************************************************** 7 // ***************************************************************************
67 // 2014/06/29: [mH] Compute int_O_ceiling 67 // 2014/06/29: [mH] Compute int_O_ceiling
68 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model. 68 // 2015/06/12: [jDG] Fix NDL prediction while desaturating with the Buhlmann model.
69 // 2017/08/04: [mH] Switch to absolute GF everywhere and apply safety margin parameters to both models (GF and non-GF), fixes from Ralph Lembcke 69 // 2017/08/04: [mH] Switch to absolute GF everywhere and apply safety margin parameters to both models (GF and non-GF), fixes from Ralph Lembcke
70 // 2017/10/31: [rl] enhancements for pSCR mode and introduction of 2nd deco plan computation 70 // 2017/10/31: [rl] enhancements for pSCR mode and introduction of 2nd deco plan computation
71 // 2017/12/31: [rl] completion of 2nd deco plan computation and various up-fixes 71 // 2017/12/31: [rl] completion of 2nd deco plan computation and various up-fixes
72 // 2018/02/17: [rl] switch-over to new ceiling rounding (V2.98a)
72 // 73 //
73 // 74 //
74 // Literature: 75 // Literature:
75 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002]; 76 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002];
76 // Schr"oder, Kai & Reith, Steffen; 2000; S"attigungsvorg"ange beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq 77 // Schr"oder, Kai & Reith, Steffen; 2000; S"attigungsvorg"ange beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq
115 116
116 // thresholds 117 // thresholds
117 #define GF_WARNING_THRESHOLD 100 // threshold for GF warning (attention threshold is current GF_high) 118 #define GF_WARNING_THRESHOLD 100 // threshold for GF warning (attention threshold is current GF_high)
118 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning 119 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning
119 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention 120 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention
120 #define ppO2_ATTENTION_THRESHOLD 120 // threshold for ppO2 attention (thresholds for warnings come by options_table.asm) 121 #define ppO2_ATTENTION_THRESHOLD 130 // threshold for ppO2 attention (thresholds for warnings come by options_table.asm)
121 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] 122 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar]
122 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention 123 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention
123 124
124 // deco engine states and modes - char_O_deco_status 125 // deco engine states and modes - char_O_deco_status
125 #define DECO_STATUS_MASK 0x03 126 #define DECO_STATUS_MASK 0x03
146 //#define DECO_MODE_PSCR 0x08 147 //#define DECO_MODE_PSCR 0x08
147 #define DECO_GASCHANGE_OVRD 0x10 148 #define DECO_GASCHANGE_OVRD 0x10
148 #define DECO_BOTTOM_CALCULATE 0x40 149 #define DECO_BOTTOM_CALCULATE 0x40
149 150
150 // deco engine states and modes - tissue_increment 151 // deco engine states and modes - tissue_increment
151 #define TIME_MASK 0x7F // (127 decimal, bits 0-6) 152 #define TIME_MASK 0x7F // (127 decimal, bits 0-6 set)
152 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 ) 153 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 set)
153 154
154 // deco engine warnings 155 // deco engine warnings
155 #define DECO_WARNING_IBCD 0x01 156 #define DECO_WARNING_IBCD 0x01
156 #define DECO_WARNING_IBCD_lock 0x02 157 #define DECO_WARNING_IBCD_lock 0x02
157 #define DECO_WARNING_MBUBBLES 0x04 158 #define DECO_WARNING_MBUBBLES 0x04
175 // ** P R O T O T Y P E S ** 176 // ** P R O T O T Y P E S **
176 // ************************* 177 // *************************
177 178
178 static void calc_hauptroutine(void); 179 static void calc_hauptroutine(void);
179 static void calc_hauptroutine_data_input(void); 180 static void calc_hauptroutine_data_input(void);
180 static void calc_hauptroutine_update_tissues(void);
181 static void calc_hauptroutine_calc_deco(void); 181 static void calc_hauptroutine_calc_deco(void);
182 static void calc_alveolar_pressures(void); 182 static void calc_alveolar_pressures(void);
183 static void calc_tissues(void); 183 static void calc_tissues(void);
184 static void calc_NDL_time(void); 184 static void calc_NDL_time(void);
185 static void calc_ascenttime(void); 185 static void calc_ascenttime(void);
515 ////////////////////////////////////////////////////////////////////////////// 515 //////////////////////////////////////////////////////////////////////////////
516 // 516 //
517 // all new in v.102 517 // all new in v.102
518 // moved from 0x0D000 to 0x0C000 in v.108 518 // moved from 0x0D000 to 0x0C000 in v.108
519 #ifndef UNIX 519 #ifndef UNIX
520 # pragma code p2_deco = 0x0C000 520 # pragma code p2_deco = 0x0C000
521 #endif 521 #endif
522 522
523 ////////////////////////////////////////////////////////////////////////////// 523 //////////////////////////////////////////////////////////////////////////////
524 ////////////////////////////////////////////////////////////////////////////// 524 //////////////////////////////////////////////////////////////////////////////
525 //////////////// U T I L I T I E S //////////////// 525 //////////////// U T I L I T I E S ////////////////
537 ////////////////////////////////////////////////////////////////////////////// 537 //////////////////////////////////////////////////////////////////////////////
538 // When calling C code from ASM context, the data stack pointer and 538 // When calling C code from ASM context, the data stack pointer and
539 // frames should be reset. Bank8 is used by stack 539 // frames should be reset. Bank8 is used by stack
540 540
541 #ifdef CROSS_COMPILE 541 #ifdef CROSS_COMPILE
542 # define RESET_C_STACK 542 # define RESET_C_STACK
543 #else 543 #else
544 # ifdef __DEBUG 544 # ifdef __DEBUG
545 # define RESET_C_STACK fillDataStack(); 545 # define RESET_C_STACK fillDataStack();
546 void fillDataStack(void) 546 void fillDataStack(void)
547 { 547 {
548 _asm 548 _asm
549 LFSR 1,C_STACK 549 LFSR 1,C_STACK
550 MOVLW 0xCC 550 MOVLW 0xCC
551 loop: MOVWF POSTINC1,0 551 loop: MOVWF POSTINC1,0
552 TSTFSZ FSR1L,0 552 TSTFSZ FSR1L,0
553 BRA loop 553 BRA loop
554 554
555 LFSR 1,C_STACK 555 LFSR 1,C_STACK
556 LFSR 2,C_STACK 556 LFSR 2,C_STACK
557 _endasm 557 _endasm
558 } 558 }
559 # else 559 # else
560 # define RESET_C_STACK \ 560 # define RESET_C_STACK \
561 _asm \ 561 _asm \
562 LFSR 1, C_STACK \ 562 LFSR 1, C_STACK \
563 LFSR 2, C_STACK \ 563 LFSR 2, C_STACK \
564 _endasm 564 _endasm
565 # endif 565 # endif
566 #endif 566 #endif
567 567
568 ////////////////////////////////////////////////////////////////////////////// 568 //////////////////////////////////////////////////////////////////////////////
569 // Fast subroutine to read timer 5. 569 // Fast subroutine to read timer 5.
570 // Note: result is in 1/32 of milliseconds (30,51757813 us/bit to be precise) 570 // Note: result is in 1/32 of milliseconds (30,51757813 us/bit to be precise)
571 static unsigned short tmr5(void) 571 static unsigned short tmr5(void)
572 { 572 {
573 #ifndef CROSS_COMPILE 573 #ifndef CROSS_COMPILE
574 _asm 574 _asm
575 movff 0xf7c,PRODL // TMR5L 575 movff 0xf7c,PRODL // TMR5L
576 movff 0xf7d,PRODH // TMR5H 576 movff 0xf7d,PRODH // TMR5H
577 _endasm // result in PRODH:PRODL. 577 _endasm // result in PRODH:PRODL.
578 #else 578 #else
579 return 0; 579 return 0;
580 #endif 580 #endif
581 } 581 }
582 582
583 ////////////////////////////////////////////////////////////////////////////// 583 //////////////////////////////////////////////////////////////////////////////
584 // read Buhlmann tables A and B for compartment ci 584 // read Buhlmann tables A and B for compartment ci
585 // 585 //
586 static void read_Buhlmann_coefficients(void) 586 static void read_Buhlmann_coefficients(void)
587 { 587 {
588 #ifndef CROSS_COMPILE 588 #ifndef CROSS_COMPILE
589 // Note: we don't use far rom pointer, because the 589 // Note: we don't use far rom pointer, because the
590 // 24 bits is too complex, hence we have to set 590 // 24 bits is too complex, hence we have to set
591 // the UPPER page ourself... 591 // the UPPER page ourself...
592 // --> Set zero if tables are moved to lower pages ! 592 // --> Set zero if tables are moved to lower pages !
593 _asm 593 _asm
594 movlw 1 594 movlw 1
595 movwf TBLPTRU,0 595 movwf TBLPTRU,0
596 _endasm 596 _endasm
597 #endif 597 #endif
598 598
599 assert( ci < NUM_COMP ); 599 assert( ci < NUM_COMP );
600 600
601 // Use an interleaved array (AoS) to access coefficients with a 601 // Use an interleaved array (AoS) to access coefficients with a
602 // single addressing. 602 // single addressing.
603 { 603 {
604 overlay rom const float* ptr = &Buhlmann_ab[4*ci]; 604 overlay rom const float* ptr = &Buhlmann_ab[4*ci];
605 var_N2_a = *ptr++; 605 var_N2_a = *ptr++;
606 var_N2_b = *ptr++; 606 var_N2_b = *ptr++;
607 var_He_a = *ptr++; 607 var_He_a = *ptr++;
608 var_He_b = *ptr++; 608 var_He_b = *ptr++;
609 } 609 }
610 } 610 }
611 611
612 ////////////////////////////////////////////////////////////////////////////// 612 //////////////////////////////////////////////////////////////////////////////
613 // read Buhlmann tables for compartment ci 613 // read Buhlmann tables for compartment ci
614 // If period == 0 : 2sec interval 614 // If period == 0 : 2sec interval
615 // 1 : 1 min interval 615 // 1 : 1 min interval
616 // 2 : 10 min interval. 616 // 2 : 10 min interval.
617 static void read_Buhlmann_times(PARAMETER char period) 617 static void read_Buhlmann_times(PARAMETER char period)
618 { 618 {
619 #ifndef CROSS_COMPILE 619 #ifndef CROSS_COMPILE
620 // Note: we don't use far rom pointer, because the 620 // Note: we don't use far rom pointer, because the
621 // 24 bits is to complex, hence we have to set 621 // 24 bits is to complex, hence we have to set
622 // the UPPER page ourself... 622 // the UPPER page ourself...
623 // --> Set zero if tables are moved to lower pages ! 623 // --> Set zero if tables are moved to lower pages!
624 _asm 624 _asm
625 movlw 1 625 movlw 1
626 movwf TBLPTRU,0 626 movwf TBLPTRU,0
627 _endasm 627 _endasm
628 #endif 628 #endif
629 629
630 assert( ci < NUM_COMP ); 630 assert( ci < NUM_COMP );
631 631
632 // Integration intervals. 632 // Integration intervals
633 switch(period) 633 switch(period)
634 { 634 {
635 case 0: //---- 2 sec ----------------------------------------------------- 635 case 0: //---- 2 sec -----------------------------------------------------
636 { 636 {
637 overlay rom const float* ptr = &e2secs[2*ci]; 637 overlay rom const float* ptr = &e2secs[2*ci];
638 var_N2_e = *ptr++; 638 var_N2_e = *ptr++;
639 var_He_e = *ptr++; 639 var_He_e = *ptr++;
640 } 640 }
641 break; 641 break;
642 642
643 case 1: //---- 1 min ----------------------------------------------------- 643 case 1: //---- 1 min -----------------------------------------------------
644 { 644 {
645 overlay rom const float* ptr = &e1min[2*ci]; 645 overlay rom const float* ptr = &e1min[2*ci];
646 var_N2_e = *ptr++; 646 var_N2_e = *ptr++;
647 var_He_e = *ptr++; 647 var_He_e = *ptr++;
648 } 648 }
649 break; 649 break;
650 650
651 case 2: //---- 10 min ---------------------------------------------------- 651 case 2: //---- 10 min ----------------------------------------------------
652 { 652 {
653 overlay rom const float* ptr = &e10min[2*ci]; 653 overlay rom const float* ptr = &e10min[2*ci];
654 var_N2_e = *ptr++; 654 var_N2_e = *ptr++;
655 var_He_e = *ptr++; 655 var_He_e = *ptr++;
656 } 656 }
657 break; 657 break;
658 658
659 default: 659 default:
660 assert(0); // Never go there... 660 assert(0); // Never go there...
661 } 661 }
662 } 662 }
663 663
664 ////////////////////////////////////////////////////////////////////////////// 664 //////////////////////////////////////////////////////////////////////////////
665 // read Buhlmann tables for compartment ci 665 // read Buhlmann tables for compartment ci
666 // 666 //
667 static void read_Buhlmann_ht(void) 667 static void read_Buhlmann_ht(void)
668 { 668 {
669 669
670 #ifndef CROSS_COMPILE 670 #ifndef CROSS_COMPILE
671 // Note: we don't use far rom pointer, because the 671 // Note: we don't use far rom pointer, because the
672 // 24 bits is to complex, hence we have to set 672 // 24 bits is to complex, hence we have to set
673 // the UPPER page ourself... 673 // the UPPER page ourself...
674 // --> Set zero if tables are moved to lower pages ! 674 // --> Set zero if tables are moved to lower pages !
675 _asm 675 _asm
676 movlw 1 676 movlw 1
677 movwf TBLPTRU,0 677 movwf TBLPTRU,0
678 _endasm 678 _endasm
679 #endif 679 #endif
680 680
681 assert( ci < NUM_COMP ); 681 assert( ci < NUM_COMP );
682 { 682 {
683 overlay rom const float* ptr = &Buhlmann_ht[2*ci]; 683 overlay rom const float* ptr = &Buhlmann_ht[2*ci];
684 var_N2_ht = *ptr++; 684 var_N2_ht = *ptr++;
685 var_He_ht = *ptr++; 685 var_He_ht = *ptr++;
686 } 686 }
687 687
688 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 ); 688 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 );
689 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 ); 689 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 );
690 } 690 }
691 691
692 ////////////////////////////////////////////////////////////////////////////// 692 //////////////////////////////////////////////////////////////////////////////
693 ////////////////////////////////////////////////////////////////////////////// 693 //////////////////////////////////////////////////////////////////////////////
694 //////////////// THE JUMP-IN CODE for the asm code //////////////// 694 //////////////// THE JUMP-IN CODE for the asm code ////////////////
1105 { 1105 {
1106 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 ); 1106 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 );
1107 1107
1108 if( char_I_current_gas <= NUM_GAS ) // Gas 1-5 1108 if( char_I_current_gas <= NUM_GAS ) // Gas 1-5
1109 { 1109 {
1110 sim_gas_last_used = sim_gas_first_used = char_I_current_gas; 1110 sim_gas_last_used = sim_gas_first_used = char_I_current_gas;
1111 1111 sim_gas_last_depth = char_I_deco_gas_change[sim_gas_last_used-1]; // > 0 for OC deco gases,
1112 // If current gas is a deco gas get it's change depth. 1112 // > 0 for first & normal diluents,
1113 // Set change depth to 0 if the current gas is the first gas or 1113 // = 0 else
1114 // a travel/normal gas, i.e. if it can be breathed at "any" depth.
1115 if( char_I_deco_gas_change[sim_gas_last_used-1] ) sim_gas_last_depth = char_I_deco_gas_change[sim_gas_last_used-1];
1116 else sim_gas_last_depth = 0;
1117 } 1114 }
1118 else 1115 else
1119 { 1116 {
1120 sim_gas_last_used = sim_gas_first_used = 0; // Gas 6 (the manually set one) has number 0 here 1117 sim_gas_last_used = sim_gas_first_used = 0; // Gas 6 (the manually set one) has number 0 here
1121 sim_gas_last_depth = 0; // handle it as a travel/normal gas 1118 sim_gas_last_depth = 0; // handle it as a travel/normal gas
1122 } 1119 }
1123 } 1120 }
1124 1121
1125 1122
1126 ////////////////////////////////////////////////////////////////////////////// 1123 //////////////////////////////////////////////////////////////////////////////
1253 // float_deco_distance : safety factor 1250 // float_deco_distance : safety factor
1254 // ppWater : water-vapor pressure inside respiratory tract 1251 // ppWater : water-vapor pressure inside respiratory tract
1255 // 1252 //
1256 // Output: ppN2 : respired N2 partial pressure 1253 // Output: ppN2 : respired N2 partial pressure
1257 // ppHe : respired He partial pressure 1254 // ppHe : respired He partial pressure
1255 // char_ppO2 : breathed ppO2 in %, to be used for CNS calculation
1258 // 1256 //
1259 void calc_alveolar_pressures(void) 1257 void calc_alveolar_pressures(void)
1260 { 1258 {
1261 overlay float pres_diluent; 1259 overlay float pres_diluent;
1262 overlay float calc_O2_ratio; 1260 overlay float calc_O2_ratio;
1451 static void calc_hauptroutine(void) 1449 static void calc_hauptroutine(void)
1452 { 1450 {
1453 overlay unsigned int int_ppO2_min; 1451 overlay unsigned int int_ppO2_min;
1454 overlay unsigned int int_ppO2_max; 1452 overlay unsigned int int_ppO2_max;
1455 overlay unsigned int int_ppO2_max_dil; 1453 overlay unsigned int int_ppO2_max_dil;
1456 1454 overlay float EAD;
1457 //--- set-up part -------------------------------------------------------------------------------- 1455 overlay float END;
1456
1457
1458 //--- Set-up Part --------------------------------------------------------------------------------
1458 1459
1459 // twosectimer: 1460 // twosectimer:
1460 // calc_hauptroutine is now invoked every second to speed up the deco planning. 1461 // calc_hauptroutine is now invoked every second to speed up the deco planning.
1461 // Because the tissue and CNS calculations are based on a 2 seconds period, the 1462 // Because the tissue and CNS calculations are based on a two seconds period, a
1462 // the following toggle-timer will be used by the respective routines to skip 1463 // toggle-timer is used by the respective routines to skip every 2nd invocation.
1463 // every 2nd invocation.
1464 twosectimer = (twosectimer) ? 0 : 1; // toggle the toggle-timer 1464 twosectimer = (twosectimer) ? 0 : 1; // toggle the toggle-timer
1465 1465
1466 1466
1467 // set up normal tissue updating or "fast forward" updating for simulator sim+5' function 1467 // set up normal tissue updating or "fast forward" updating for simulator sim+5' function
1468 // and deco calculator bottom time calculation 1468 // and deco calculator bottom time calculation
1480 tissue_increment = 0 // encoding for 2 seconds update 1480 tissue_increment = 0 // encoding for 2 seconds update
1481 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS 1481 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS
1482 } 1482 }
1483 1483
1484 1484
1485 //---- calculate the real tissue's data ----------------------------------------------------------------- 1485 //---- Calculations Part ----------------------------------------------------------------------
1486 1486
1487 // acquire current environment data 1487 // acquire current environment data
1488 calc_hauptroutine_data_input(); 1488 calc_hauptroutine_data_input();
1489 1489
1490 // update tissue pressures, also sets char_ppO2 for calc_CNS_increment()
1491 calc_hauptroutine_update_tissues();
1492
1493 // calculate CNS value increment for the real tissues
1494 calc_CNS_increment();
1495
1496 // update the CNS value for the real tissues
1497 CNS_fraction += CNS_fraction_inc;
1498
1499 // compute integer copy of CNS value for display purpose
1500 convert_CNS_for_display();
1501
1502
1503 //---- compute ppO2 warnings ------------------------------------------------------------------------------
1504
1505 // compute conditional min/max values
1506 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min;
1507 int_ppO2_max = (char_O_deco_warnings & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max;
1508
1509 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold
1510 int_ppO2_max_dil = int_ppO2_max;
1511
1512 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
1513 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR )
1514 {
1515 overlay unsigned int max_dil;
1516
1517 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
1518 // (the condition protects from negative numbers which would cause a wrap-around)
1519 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
1520
1521 // ...but never above int_ppO2_max.
1522 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil;
1523
1524 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
1525 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
1526 }
1527
1528 // check for safe range of pure oxygen
1529 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1530
1531 // check for safe range of breathed gas
1532 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1533 else if ( int_O_breathed_ppO2 >= int_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1534 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes
1535 else if ( int_O_breathed_ppO2 >= ppO2_ATTENTION_THRESHOLD ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
1536
1537 // check for safe range of pure diluent
1538 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1539 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1540 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION;
1541
1542 // check for safe range of calculated pSCR loop gas
1543 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1544 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1545
1546
1547
1548 //---- toggle between calculation for NDL (bottom time), ------
1549 //---- deco stops and more deco stops (continue) ------
1550
1551
1552 // done with the real tissues, all following operations
1553 // target the simulated tissues so clear flag in bit 7
1554 tissue_increment = 0;
1555
1556 // branch to the code for the current phase the deco calculations are in
1557 switch( char_O_deco_status & DECO_STATUS_MASK )
1558 {
1559 overlay unsigned char i;
1560
1561 case DECO_STATUS_INIT: //---- At surface: Start a new dive ---------------------
1562
1563 // clear the internal stops table from remains lasting from the last dive
1564 clear_deco_table();
1565
1566 // publish the cleared stops table to the display functions
1567 publish_deco_table();
1568
1569 // clear the gas needs table
1570 for(i=0; i<NUM_GAS; ++i)
1571 {
1572 int_O_gas_volumes[i] = 0;
1573 int_O_tank_pres_need[i] = 0 + INT_FLAG_ZERO;
1574 }
1575
1576 // initialize the balancing between N2 and He for later no-fly time calculation
1577 for(i=0; i<NUM_COMP; ++i)
1578 {
1579 split_N2_He[i] = 90; // assumes 90% of total tissue pressure will be needed for N2
1580 }
1581
1582 // ** UNDER CONSTRUCTION - temporary code only **
1583 char_I_gas_change_time = 1; // TODO: validate proper operation before enabling this options-table parameter
1584 char_I_ascent_speed = 10; // TODO: validate proper operation before enabling this options-table parameter,
1585 // caution: values < 10 may have an impact on the deco calculation run-times!
1586
1587 // initialize values that are constant during the course of the dive
1588 float_ascent_speed = 1.00 * char_I_ascent_speed;
1589 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier;
1590 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier;
1591 float_deco_distance = 0.01 * char_I_deco_distance;
1592
1593 // initialize values that will be recalculated later on periodically
1594 char_O_nullzeit = 0; // reset NDL time for the normal plan
1595 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan
1596 int_O_ascenttime = 0; // reset ascent time for the normal plan
1597 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan
1598 char_O_deco_warnings = 0; // reset all deco warnings
1599 deco_tissue_vector = 0; // reset tissue deco vector
1600 IBCD_tissue_vector = 0; // reset tissue IBCD vector
1601 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation
1602
1603 // tag desaturation time as invalid (it will not be computed during a dive)
1604 int_O_desaturation_time = 65535;
1605
1606 // initialize CNS values
1607 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1608
1609 // Values that should be reset just once for the full real dive.
1610 // This is used to record the lowest stop for the whole dive,
1611 // including ACCROSS all simulated ascents.
1612 low_depth_norm = low_depth_alt = 0.0;
1613 locked_GF_step_norm = locked_GF_step_alt = 0.0;
1614
1615 //
1616 // --> code execution continues in state DECO_STATUS_START
1617 //
1618
1619 case DECO_STATUS_START: //---- Bottom Time & initial Ascent --------------------
1620 default:
1621
1622 // clear the internal(!) stops table
1623 clear_deco_table();
1624
1625 // initialize the simulated tissues with the current state of the real tissues
1626 for(i=0; i<NUM_COMP; i++)
1627 {
1628 sim_pres_tissue_N2[i] = pres_tissue_N2[i];
1629 sim_pres_tissue_He[i] = pres_tissue_He[i];
1630 }
1631
1632 // Lookup the current gas and store it also as the first gas used.
1633 // This gas will be used for the bottom segment of the dive and for
1634 // the period of delayed ascent when calculating fTTS or bailout.
1635 gas_find_current();
1636
1637 // setup the calculation ratio's for N2, He and O2 (sim_N2/He/O2_ratio)
1638 gas_set_ratios();
1639
1640 // initialize depth in absolute pressure, it is needed by
1641 // - calc_alveolar_pressures(),
1642 // - calc_ascent_to_first_stop(), and
1643 // - calc_hauptroutine_calc_deco()
1644 sim_pres_respiration = pres_respiration;
1645
1646 // calculate ppN2 and ppHe from sim_N2/He_ratio (<- tissue_increment has been set to 0)
1647 calc_alveolar_pressures();
1648
1649 // calculate the effect of extended bottom time due to delayed ascent
1650 if( char_O_deco_status & DECO_ASCENT_DELAYED )
1651 {
1652 // program interval on simulated tissues (flag bit 7 = 0)
1653 tissue_increment = char_I_extra_time;
1654
1655 // update the tissues
1656 calc_tissues();
1657 }
1658
1659 // calculate if we are within no decompression limit (NDL)
1660 calc_NDL_time();
1661
1662 // Calculate the initial ascent if in deco. calc_NDL_time() is very fast
1663 // in detecting being beyond NDL, so there is enough time left in this
1664 // phase to do the initial ascent calculation.
1665 if( NDL_time == 0 )
1666 {
1667 //--- in deco --------------------------------------------------------
1668
1669 // calculate ascent to first stop
1670 calc_ascent_to_first_stop();
1671
1672 // continue with calculating the stops
1673 char_O_deco_status &= ~DECO_STATUS_MASK; // clear status bits and set status bits for
1674 char_O_deco_status |= DECO_STATUS_STOPS; // calculation of stops on next invocation
1675 }
1676 else
1677 {
1678 //--- within NDL -----------------------------------------------------
1679
1680 // continue with gathering all results
1681 char_O_deco_status &= ~DECO_STATUS_MASK;
1682 char_O_deco_status |= DECO_STATUS_RESULTS;
1683 }
1684
1685 break;
1686
1687
1688 case DECO_STATUS_STOPS: //---- Calculate Stops ---------------------------------
1689
1690 // calculate the stops
1691 calc_hauptroutine_calc_deco();
1692
1693 // calc_hauptroutine_calc_deco iterates in this phase as long as it is
1694 // calculating the stops. Once done, it will set the status to doing the
1695 // results gathering.
1696
1697 break;
1698
1699
1700 case DECO_STATUS_RESULTS: //--- Gathering of all Results -----------------------
1701
1702 // if in normal plan, publish the stops table to the display functions
1703 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) ) publish_deco_table();
1704
1705 // The current depth is needed by calc_CNS_planning() and gas_volumes().
1706 // As it may be needed in different code blocks below but we don't want
1707 // it to be in the code multiple times, it's done here on stockpile.
1708 bottom_depth = (unsigned char)((pres_respiration - pres_surface) * BAR_TO_METER);
1709
1710 // Calculate the ascent time.
1711 // When within NDL, potential gas switches will be treated as done "on the fly".
1712 calc_ascenttime();
1713
1714 // results to publish depend whether within NDL or in deco
1715 if( NDL_time )
1716 {
1717 //---- within NDL ----------------------------------------------
1718
1719 // Calculate the initial ascent (not yet done when within NDL) -
1720 // just to get potential gas switches into the stops table for use
1721 // by gas_volumes(). The stops table can be polluted by now because
1722 // the clean table has already been published to the display
1723 // functions before.
1724 calc_ascent_to_first_stop();
1725
1726 // check which plan we are on
1727 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1728 {
1729 //---- alternate dive plan ---------------------------------
1730
1731 // As we are in no stop, CNS at end of dive is more or less
1732 // the same CNS as we have right now. It's so simple that we
1733 // don't check if it requested to be computed or not...
1734 int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1735
1736 // output NDL time
1737 char_O_alternate_nullzeit = NDL_time;
1738
1739 // clear ascent time
1740 int_O_alternate_ascenttime = 0;
1741 }
1742 else
1743 {
1744 //---- normal dive plan ------------------------------------
1745
1746 // As we are in no stop, CNS at end of dive is more or less
1747 // the same CNS as we have right now. It's so simple that we
1748 // don't check if it requested to be computed or not...
1749 int_O_normal_CNS_fraction = int_O_CNS_fraction;
1750
1751 // output NDL time
1752 char_O_nullzeit = NDL_time;
1753
1754 // clear ascent time
1755 int_O_ascenttime = 0;
1756 }
1757 } // NDL
1758 else
1759 {
1760 //---- in DECO -------------------------------------------------
1761
1762 // check which plan we are on
1763 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1764 {
1765 //---- alternative plan ----------------------------------------------------
1766
1767 // shall the CNS at the end of the dive be calculated?
1768 if( char_O_deco_status & DECO_CNS_CALCULATE )
1769 {
1770 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction
1771 calc_CNS_planning();
1772
1773 // add current CNS value
1774 sim_CNS_fraction += CNS_fraction;
1775
1776 // convert to integer value
1777 convert_sim_CNS_for_display();
1778
1779 // export result
1780 int_O_alternate_CNS_fraction = int_sim_CNS_fraction;
1781 }
1782
1783 // clear NDL time
1784 char_O_alternate_nullzeit = 0;
1785
1786 // output ascent time
1787 int_O_alternate_ascenttime = ascent_time;
1788
1789 } // alternative plan
1790 else
1791 {
1792 //---- normal plan ---------------------------------------------------------
1793
1794 // shall the CNS at the end of the dive be calculated?
1795 if( char_O_deco_status & DECO_CNS_CALCULATE )
1796 {
1797 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction
1798 calc_CNS_planning();
1799
1800 // add current CNS value
1801 sim_CNS_fraction += CNS_fraction;
1802
1803 // convert to integer value
1804 convert_sim_CNS_for_display();
1805
1806 // export result
1807 int_O_normal_CNS_fraction = int_sim_CNS_fraction;
1808 }
1809
1810 // clear NDL time
1811 char_O_nullzeit = 0;
1812
1813 // output ascent time
1814 int_O_ascenttime = ascent_time;
1815
1816 } // normal plan
1817 } // DECO
1818
1819 // if requested, calculate the required gas volumes and tank pressures at the end of the dive
1820 if( char_O_deco_status & DECO_VOLUME_CALCULATE ) gas_volumes();
1821
1822 // signal that the computation cycle is finished
1823 char_O_deco_status &= ~DECO_STATUS_MASK;
1824
1825 break;
1826
1827 } // switch
1828 }
1829
1830 //////////////////////////////////////////////////////////////////////////////
1831 // calc_hauptroutine_data_input
1832 //
1833 // Set all C-code dive parameters from their ASM-code values.
1834 // Detect gas change condition.
1835 //
1836 void calc_hauptroutine_data_input(void)
1837 {
1838 overlay float IG_ratio;
1839
1840 // get the current pressures
1841 pres_surface = 0.001 * int_I_pres_surface;
1842 pres_respiration = 0.001 * int_I_pres_respiration;
1843
1844 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling
1845 N2_equilibrium = 0.7902 * (pres_surface - ppWater);
1846
1847 // read the GF settings (they may have been switch between GF/aGF)
1848 GF_high = 0.01 * char_I_GF_High_percentage;
1849 GF_low = 0.01 * char_I_GF_Low_percentage;
1850 GF_delta = GF_high - GF_low;
1851
1852 // get the currently breathed gas mixture
1853 O2_ratio = 0.01 * char_I_O2_ratio;
1854 He_ratio = 0.01 * char_I_He_ratio;
1855
1856 // inert gas ratio (local helper variable)
1857 IG_ratio = 1.00 - O2_ratio;
1858
1859 // N2 ratio
1860 N2_ratio = IG_ratio - He_ratio;
1861
1862 // precomputed values for ppO2 drop in pSCR loop
1863 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio;
1864 pSCR_drop = IG_ratio * float_pSCR_factor;
1865 }
1866
1867 //////////////////////////////////////////////////////////////////////////////
1868 //
1869 //
1870 void calc_hauptroutine_update_tissues(void)
1871 {
1872 overlay float EAD, END;
1873
1874 //---- calculations part ----------------------------------------------------------------------
1875
1876 // calculate ppN2 and ppHe 1490 // calculate ppN2 and ppHe
1877 calc_alveolar_pressures(); 1491 calc_alveolar_pressures();
1878 1492
1879 // calculate the tissues 1493 // All deco code is invoked every second. But as the tissue and CNS updates are based
1880 calc_tissues(); 1494 // on 2 seconds periods, each update is done only on each 2nd second.
1881 1495 // In case a "fast forward" of the tissues is commanded, the 2-seconds rule is over raided.
1882 // calculate ceiling (at GF_high) and current GF 1496 // To distribute computational load, updating of tissues and CNS is done in alternation.
1883 calc_limit(GF_high); 1497 if( twosectimer || (tissue_increment & TIME_MASK) )
1498 {
1499 // calculate the real tissues
1500 calc_tissues();
1501
1502 // calculate ceiling (at GF_high) and current GF
1503 calc_limit(GF_high);
1504 }
1505
1506 if( !twosectimer || (tissue_increment & TIME_MASK) )
1507 {
1508 // calculate CNS value increment for the real tissues
1509 calc_CNS_increment();
1510
1511 // increment CNS value of the real tissues
1512 CNS_fraction += CNS_fraction_inc;
1513
1514 // compute integer copy of CNS value for display purpose
1515 convert_CNS_for_display();
1516 }
1517
1518
1519 //---- Calculate and Export EAD and END ------------------------------------------------------
1884 1520
1885 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air 1521 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air
1886 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER; 1522 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER;
1887 1523
1888 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too 1524 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too
1889 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott, 1525 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott,
1890 // 4th edition, 1993, W.B.Saunders Company Ltd, London. 1526 // 4th edition, 1993, W.B.Saunders Company Ltd, London.
1891 END = (pres_respiration - ppHe - pres_surface) * BAR_TO_METER; 1527 END = (pres_respiration - ppHe - pres_surface) * BAR_TO_METER;
1892 1528
1893 1529 // export EAD
1894 //---- export ppO2 values in [cbar] for warning generation and display purpose ---------------- 1530 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0;
1531 else char_O_EAD = (unsigned char)(EAD + 0.5);
1532
1533 // export END
1534 if( (END < 0.0) || (END > 245.5) ) char_O_END = 0;
1535 else char_O_END = (unsigned char)(END + 0.5);
1536
1537
1538 //---- Compute ppO2 Values in [cbar] ---------------------------------------------------------
1895 1539
1896 // pure oxygen ppO2 1540 // pure oxygen ppO2
1897 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0; 1541 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0;
1898 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999; 1542 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999;
1899 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5); 1543 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5);
1912 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0; 1556 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0;
1913 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999; 1557 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999;
1914 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5); 1558 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5);
1915 1559
1916 1560
1917 //---- export EAD and END --------------------------------------------------------------------- 1561 //---- Compute ppO2 Warnings ------------------------------------------------------------------
1918 1562
1919 // EAD 1563 // compute conditional min/max values
1920 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0; 1564 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min;
1921 else char_O_EAD = (unsigned char)(EAD + 0.5); 1565 int_ppO2_max = (char_O_deco_warnings & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max;
1922 1566
1923 // END 1567 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold
1924 if( (END < 0.0) || (END > 245.5) ) char_O_END = 0; 1568 int_ppO2_max_dil = int_ppO2_max;
1925 else char_O_END = (unsigned char)(END + 0.5); 1569
1570 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
1571 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR )
1572 {
1573 overlay unsigned int max_dil;
1574
1575 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
1576 // (the condition protects from negative numbers which would cause a wrap-around)
1577 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
1578
1579 // ...but never above int_ppO2_max.
1580 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil;
1581
1582 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
1583 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
1584 }
1585
1586 // check for safe range of pure oxygen
1587 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1588
1589 // check for safe range of breathed gas
1590 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1591 else if ( int_O_breathed_ppO2 >= int_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1592 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes
1593 else if ( int_O_breathed_ppO2 >= ppO2_ATTENTION_THRESHOLD ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
1594
1595 // check for safe range of pure diluent
1596 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1597 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1598 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION;
1599
1600 // check for safe range of calculated pSCR loop gas
1601 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1602 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1603
1604
1605 // done with the real tissues
1606
1607
1608
1609 //---- Toggle between Calculation for NDL (bottom time), -------------------------------------
1610 //---- Deco Stops, more Deco Stops and Results Gathering -------------------------------------
1611
1612
1613 // all following operations target the simulated tissues, so clear flag in bit 7
1614 tissue_increment = 0;
1615
1616 // branch to the code for the current phase the deco calculations are in
1617 switch( char_O_deco_status & DECO_STATUS_MASK )
1618 {
1619 overlay unsigned char i;
1620
1621 case DECO_STATUS_INIT: //---- At surface: Start a new dive ---------------------
1622
1623 // clear the internal stops table from remains lasting from the last dive
1624 clear_deco_table();
1625
1626 // publish the cleared stops table to the display functions
1627 publish_deco_table();
1628
1629 // clear the gas needs table
1630 for(i=0; i<NUM_GAS; ++i)
1631 {
1632 int_O_gas_volumes[i] = 0;
1633 int_O_tank_pres_need[i] = 0 + INT_FLAG_ZERO;
1634 }
1635
1636 // initialize the balancing between N2 and He for later no-fly time calculation
1637 for(i=0; i<NUM_COMP; ++i)
1638 {
1639 split_N2_He[i] = 90; // assumes 90% of total tissue pressure will be needed for N2
1640 }
1641
1642 // ** UNDER CONSTRUCTION - temporary code only **
1643 char_I_gas_change_time = 1; // TODO: validate proper operation before enabling this options-table parameter
1644 char_I_ascent_speed = 10; // TODO: validate proper operation before enabling this options-table parameter,
1645 // caution: values < 10 may have an impact on the deco calculation run-times!
1646
1647 // initialize values that are constant during the course of the dive
1648 float_ascent_speed = 1.00 * char_I_ascent_speed;
1649 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier;
1650 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier;
1651 float_deco_distance = 0.01 * char_I_deco_distance;
1652
1653 // initialize values that will be recalculated later on periodically
1654 char_O_nullzeit = 0; // reset NDL time for the normal plan
1655 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan
1656 int_O_ascenttime = 0; // reset ascent time for the normal plan
1657 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan
1658 char_O_deco_warnings = 0; // reset all deco warnings
1659 deco_tissue_vector = 0; // reset tissue deco vector
1660 IBCD_tissue_vector = 0; // reset tissue IBCD vector
1661 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation
1662
1663 // tag desaturation time as invalid (it will not be computed during a dive)
1664 int_O_desaturation_time = 65535;
1665
1666 // initialize CNS values
1667 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1668
1669 // Values that should be reset just once for the full real dive.
1670 // This is used to record the lowest stop for the whole dive,
1671 // including ACCROSS all simulated ascents.
1672 low_depth_norm = low_depth_alt = 0.0;
1673 locked_GF_step_norm = locked_GF_step_alt = 0.0;
1674
1675 //
1676 // --> code execution continues in state DECO_STATUS_START
1677 //
1678
1679 case DECO_STATUS_START: //---- Bottom Time & initial Ascent --------------------
1680 default:
1681
1682 // clear the internal(!) stops table
1683 clear_deco_table();
1684
1685 // initialize the simulated tissues with the current state of the real tissues
1686 for(i=0; i<NUM_COMP; i++)
1687 {
1688 sim_pres_tissue_N2[i] = pres_tissue_N2[i];
1689 sim_pres_tissue_He[i] = pres_tissue_He[i];
1690 }
1691
1692 // Lookup the current gas and store it also as the first gas used.
1693 // This gas will be used for the bottom segment of the dive and for
1694 // the period of delayed ascent when calculating fTTS or bailout.
1695 gas_find_current();
1696
1697 // setup the calculation ratio's for N2, He and O2 (sim_N2/He/O2_ratio)
1698 gas_set_ratios();
1699
1700 // initialize depth in absolute pressure, it is needed by
1701 // - calc_alveolar_pressures(),
1702 // - calc_ascent_to_first_stop(), and
1703 // - calc_hauptroutine_calc_deco()
1704 sim_pres_respiration = pres_respiration;
1705
1706 // calculate ppN2 and ppHe from sim_N2/He_ratio (<- tissue_increment has been set to 0)
1707 calc_alveolar_pressures();
1708
1709 // calculate the effect of extended bottom time due to delayed ascent
1710 if( char_O_deco_status & DECO_ASCENT_DELAYED )
1711 {
1712 // program interval on simulated tissues (flag bit 7 = 0)
1713 tissue_increment = char_I_extra_time;
1714
1715 // update the tissues
1716 calc_tissues();
1717 }
1718
1719 // calculate if we are within no decompression limit (NDL)
1720 calc_NDL_time();
1721
1722 // Calculate the initial ascent if in deco. calc_NDL_time() is very fast
1723 // in detecting being beyond NDL, so there is enough time left in this
1724 // phase to do the initial ascent calculation.
1725 if( NDL_time == 0 )
1726 {
1727 //--- in deco --------------------------------------------------------
1728
1729 // calculate ascent to first stop
1730 calc_ascent_to_first_stop();
1731
1732 // continue with calculating the stops
1733 char_O_deco_status &= ~DECO_STATUS_MASK; // clear status bits and set status bits for
1734 char_O_deco_status |= DECO_STATUS_STOPS; // calculation of stops on next invocation
1735 }
1736 else
1737 {
1738 //--- within NDL -----------------------------------------------------
1739
1740 // continue with gathering all results
1741 char_O_deco_status &= ~DECO_STATUS_MASK;
1742 char_O_deco_status |= DECO_STATUS_RESULTS;
1743 }
1744
1745 break;
1746
1747
1748 case DECO_STATUS_STOPS: //---- Calculate Stops ---------------------------------
1749
1750 // calculate the stops
1751 calc_hauptroutine_calc_deco();
1752
1753 // calc_hauptroutine_calc_deco iterates in this phase as long as it is
1754 // calculating the stops. Once done, it will set the status to doing the
1755 // results gathering.
1756
1757 break;
1758
1759
1760 case DECO_STATUS_RESULTS: //--- Gathering of all Results -----------------------
1761
1762 // if in normal plan, publish the stops table to the display functions
1763 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) ) publish_deco_table();
1764
1765 // The current depth is needed by calc_CNS_planning() and gas_volumes().
1766 // As it may be needed in different code blocks below but we don't want
1767 // it to be in the code multiple times, it's done here on stockpile.
1768 bottom_depth = (unsigned char)((pres_respiration - pres_surface) * BAR_TO_METER);
1769
1770 // Calculate the ascent time.
1771 // When within NDL, potential gas switches will be treated as done "on the fly".
1772 calc_ascenttime();
1773
1774 // results to publish depend whether within NDL or in deco
1775 if( NDL_time )
1776 {
1777 //---- within NDL ----------------------------------------------
1778
1779 // Calculate the initial ascent (not yet done when within NDL) -
1780 // just to get potential gas switches into the stops table for use
1781 // by gas_volumes(). The stops table can be polluted by now because
1782 // the clean table has already been published to the display
1783 // functions before.
1784 calc_ascent_to_first_stop();
1785
1786 // check which plan we are on
1787 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1788 {
1789 //---- alternate dive plan ---------------------------------
1790
1791 // As we are in no stop, CNS at end of dive is more or less
1792 // the same CNS as we have right now. It's so simple that we
1793 // don't check if it requested to be computed or not...
1794 int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1795
1796 // output NDL time
1797 char_O_alternate_nullzeit = NDL_time;
1798
1799 // clear ascent time
1800 int_O_alternate_ascenttime = 0;
1801 }
1802 else
1803 {
1804 //---- normal dive plan ------------------------------------
1805
1806 // As we are in no stop, CNS at end of dive is more or less
1807 // the same CNS as we have right now. It's so simple that we
1808 // don't check if it requested to be computed or not...
1809 int_O_normal_CNS_fraction = int_O_CNS_fraction;
1810
1811 // output NDL time
1812 char_O_nullzeit = NDL_time;
1813
1814 // clear ascent time
1815 int_O_ascenttime = 0;
1816 }
1817 } // NDL
1818 else
1819 {
1820 //---- in DECO -------------------------------------------------
1821
1822 // check which plan we are on
1823 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1824 {
1825 //---- alternative plan ----------------------------------------------------
1826
1827 // shall the CNS at the end of the dive be calculated?
1828 if( char_O_deco_status & DECO_CNS_CALCULATE )
1829 {
1830 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction
1831 calc_CNS_planning();
1832
1833 // add current CNS value
1834 sim_CNS_fraction += CNS_fraction;
1835
1836 // convert to integer value
1837 convert_sim_CNS_for_display();
1838
1839 // export result
1840 int_O_alternate_CNS_fraction = int_sim_CNS_fraction;
1841 }
1842
1843 // clear NDL time
1844 char_O_alternate_nullzeit = 0;
1845
1846 // output ascent time
1847 int_O_alternate_ascenttime = ascent_time;
1848
1849 } // alternative plan
1850 else
1851 {
1852 //---- normal plan ---------------------------------------------------------
1853
1854 // shall the CNS at the end of the dive be calculated?
1855 if( char_O_deco_status & DECO_CNS_CALCULATE )
1856 {
1857 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction
1858 calc_CNS_planning();
1859
1860 // add current CNS value
1861 sim_CNS_fraction += CNS_fraction;
1862
1863 // convert to integer value
1864 convert_sim_CNS_for_display();
1865
1866 // export result
1867 int_O_normal_CNS_fraction = int_sim_CNS_fraction;
1868 }
1869
1870 // clear NDL time
1871 char_O_nullzeit = 0;
1872
1873 // output ascent time
1874 int_O_ascenttime = ascent_time;
1875
1876 } // normal plan
1877 } // DECO
1878
1879 // if requested, calculate the required gas volumes and tank pressures at the end of the dive
1880 if( char_O_deco_status & DECO_VOLUME_CALCULATE ) gas_volumes();
1881
1882 // signal that the computation cycle is finished
1883 char_O_deco_status &= ~DECO_STATUS_MASK;
1884
1885 break;
1886
1887 } // switch
1888 }
1889
1890 //////////////////////////////////////////////////////////////////////////////
1891 // calc_hauptroutine_data_input
1892 //
1893 // Set all C-code dive parameters from their ASM-code values.
1894 // Detect gas change condition.
1895 //
1896 void calc_hauptroutine_data_input(void)
1897 {
1898 overlay float IG_ratio;
1899
1900 // get the current pressures
1901 pres_surface = 0.001 * int_I_pres_surface;
1902 pres_respiration = 0.001 * int_I_pres_respiration;
1903
1904 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling
1905 N2_equilibrium = 0.7902 * (pres_surface - ppWater);
1906
1907 // read the GF settings (they may have been switch between GF/aGF)
1908 GF_high = 0.01 * char_I_GF_High_percentage;
1909 GF_low = 0.01 * char_I_GF_Low_percentage;
1910 GF_delta = GF_high - GF_low;
1911
1912 // get the currently breathed gas mixture
1913 O2_ratio = 0.01 * char_I_O2_ratio;
1914 He_ratio = 0.01 * char_I_He_ratio;
1915
1916 // inert gas ratio (local helper variable)
1917 IG_ratio = 1.00 - O2_ratio;
1918
1919 // N2 ratio
1920 N2_ratio = IG_ratio - He_ratio;
1921
1922 // precomputed values for ppO2 drop in pSCR loop
1923 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio;
1924 pSCR_drop = IG_ratio * float_pSCR_factor;
1926 } 1925 }
1927 1926
1928 1927
1929 ////////////////////////////////////////////////////////////////////////////// 1928 //////////////////////////////////////////////////////////////////////////////
1930 // Compute stops. 1929 // Compute stops.
2171 2170
2172 temp_tissue_safety(); 2171 temp_tissue_safety();
2173 2172
2174 if( tissue_increment & TISSUE_FLAG ) 2173 if( tissue_increment & TISSUE_FLAG )
2175 { 2174 {
2176 // The temp variable takes on purpose just the tissue increment from the last loop's iteration. 2175 temp_tissue_N2 = temp_tissue;
2177 temp_tissue_N2 = temp_tissue; 2176 pres_tissue_N2[ci] += temp_tissue;
2178
2179 // Update the real tissues if either we are on the 2 seconds interval,
2180 // or if we shall advance the tissues on a one or several minutes basis.
2181 if( twosectimer || (tissue_increment & TIME_MASK) ) pres_tissue_N2[ci] += temp_tissue;
2182 } 2177 }
2183 else 2178 else
2184 { 2179 {
2185 // Updates of the sim-tissues always comes on a 1 minutes basis,
2186 // so we do not need to check of the 2 seconds interval.
2187 sim_pres_tissue_N2[ci] += temp_tissue; 2180 sim_pres_tissue_N2[ci] += temp_tissue;
2188 } 2181 }
2189 2182
2190 2183
2191 //---- He ------------------------------------------------------------------------------- 2184 //---- He -------------------------------------------------------------------------------
2196 2189
2197 temp_tissue_safety(); 2190 temp_tissue_safety();
2198 2191
2199 if( tissue_increment & TISSUE_FLAG ) 2192 if( tissue_increment & TISSUE_FLAG )
2200 { 2193 {
2201 // The temp variable takes on purpose just the tissue increment from the last loop's iteration. 2194 temp_tissue_He = temp_tissue;
2202 temp_tissue_He = temp_tissue; 2195 pres_tissue_He[ci] += temp_tissue;
2203
2204 // Update the real tissues if either we are on the 2 seconds interval,
2205 // or if we shall advance the tissues on a one or several minutes basis.
2206 if( twosectimer || (tissue_increment & TIME_MASK) ) pres_tissue_He[ci] += temp_tissue;
2207 } 2196 }
2208 else 2197 else
2209 { 2198 {
2210 // Updates of the sim-tissues always comes on a 1 minutes basis,
2211 // so we do not need to check of the 2 seconds interval.
2212 sim_pres_tissue_He[ci] += temp_tissue; 2199 sim_pres_tissue_He[ci] += temp_tissue;
2213 } 2200 }
2214 2201
2215 // decrement loop counter 2202 // decrement loop counter
2216 i -= period; 2203 i -= period;
2224 } 2211 }
2225 while( i ); 2212 while( i );
2226 2213
2227 2214
2228 // have the computations been done for the "real" tissues? 2215 // have the computations been done for the "real" tissues?
2229 if( (tissue_increment & TISSUE_FLAG) && (twosectimer || (tissue_increment & TIME_MASK)) ) 2216 if( tissue_increment & TISSUE_FLAG )
2230 { 2217 {
2231 // net tissue balance 2218 // net tissue balance
2232 temp_tissue = temp_tissue_N2 + temp_tissue_He; 2219 temp_tissue = temp_tissue_N2 + temp_tissue_He;
2233 2220
2234 // check tissue on-/off-gassing and IBCD with applying a threshold of +/-HYST 2221 // check tissue on-/off-gassing and IBCD with applying a threshold of +/-HYST
2235 // 2222 //
2236 if ( temp_tissue < -HYST ) // Check if the tissue is off-gassing 2223 if ( temp_tissue < -HYST ) // check if the tissue is off-gassing
2237 { 2224 {
2238 deco_tissue_vector |= (1 << ci); // tag tissue as being in decompression 2225 deco_tissue_vector |= (1 << ci); // tag tissue as being in decompression
2239 IBCD_tissue_vector &= ~(1 << ci); // tag tissue as not experiencing mentionable IBCD 2226 IBCD_tissue_vector &= ~(1 << ci); // tag tissue as not experiencing mentionable IBCD
2240 } 2227 }
2241 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing 2228 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing
2369 // next calculations are only relevant when invoked on the real tissues 2356 // next calculations are only relevant when invoked on the real tissues
2370 if( tissue_increment & TISSUE_FLAG ) 2357 if( tissue_increment & TISSUE_FLAG )
2371 { 2358 {
2372 overlay float supersat; 2359 overlay float supersat;
2373 overlay float threshold; 2360 overlay float threshold;
2374 2361
2375 // calculate current supersaturation value (1.0 = 100%) of this tissue 2362 // calculate current supersaturation value (1.0 = 100%) of this tissue
2376 supersat = (pres_tissue - pres_respiration) / (pres_tissue - pres_min); 2363 supersat = (pres_tissue - pres_respiration) / (pres_tissue - pres_min);
2377 2364
2378 // check if tissue is in supersaturation 2365 // check if tissue is in supersaturation
2379 if( supersat > 0.0 ) 2366 if( supersat > 0.0 )
2448 2435
2449 // convert ceiling to int_O_ceiling in mbar 2436 // convert ceiling to int_O_ceiling in mbar
2450 if ( ceiling <= 0 ) int_O_ceiling = 0; 2437 if ( ceiling <= 0 ) int_O_ceiling = 0;
2451 else if ( ceiling > 16 ) int_O_ceiling = 16000; 2438 else if ( ceiling > 16 ) int_O_ceiling = 16000;
2452 // Compatibility version 2439 // Compatibility version
2453 else int_O_ceiling = (short)(ceiling * 1000); 2440 // else int_O_ceiling = (short)(ceiling * 1000);
2454 2441
2455 // New version: Rounds up to next 10 cm so that the ceiling disappears on the display only when the 2442 // New version: Rounds up to next 10 cm so that the ceiling disappears on the display only when the
2456 // ceiling limit is really zero. This will coincident then with TTS switching back to NDL time. 2443 // ceiling limit is really zero. This will coincident then with TTS switching back to NDL time.
2457 // else int_O_ceiling = (short)(ceiling * 1000 + 9); 2444 else int_O_ceiling = (short)(ceiling * 1000 + 9);
2458 2445
2459 2446
2460 // convert highest supersaturation found to int_O_gradient_factor in % (1.0 = 100%) 2447 // convert highest supersaturation found to int_O_gradient_factor in % (1.0 = 100%)
2461 // limit to 255 because of constraints in ghostwriter code 2448 // limit to 255 because of constraints in ghostwriter code
2462 if ( lead_supersat <= 0.0 ) int_O_gradient_factor = 0; 2449 if ( lead_supersat <= 0.0 ) int_O_gradient_factor = 0;
3135 { 3122 {
3136 overlay float time_factor = 1.0; // default is 2sec 3123 overlay float time_factor = 1.0; // default is 2sec
3137 3124
3138 assert( char_ppO2 > 15 ); 3125 assert( char_ppO2 > 15 );
3139 3126
3140 // All deco code is now invoked every second. But as the CNS update is based on
3141 // 2 seconds periods, we skip every 2nd seconds-based invocation of this function.
3142 // TISSUE_FLAG = 128 (flag for "real" CNS) + 0 (2 seconds period)
3143 // To distribute computational load, the CNS% is calculated in "the other second"
3144 // than the tissues.
3145 if( (tissue_increment == TISSUE_FLAG) && (twosectimer) ) return;
3146
3147 // adjust time factor if minute-based stepping is commanded, mask out flag bit 3127 // adjust time factor if minute-based stepping is commanded, mask out flag bit
3148 if( tissue_increment & TIME_MASK ) time_factor = 30.0 * (float)(tissue_increment & TIME_MASK); 3128 if( tissue_increment & TIME_MASK ) time_factor = 30.0 * (float)(tissue_increment & TIME_MASK);
3149
3150 3129
3151 //------------------------------------------------------------------------ 3130 //------------------------------------------------------------------------
3152 // Don't increase CNS below 0.5 bar, but keep it steady. 3131 // Don't increase CNS below 0.5 bar, but keep it steady.
3153 if (char_ppO2 < 50) CNS_fraction_inc = 0; // no CNS increase below 0.5 bar ppO2 3132 if (char_ppO2 < 50) CNS_fraction_inc = 0; // no CNS increase below 0.5 bar ppO2
3154 //------------------------------------------------------------------------ 3133 //------------------------------------------------------------------------