1
// This file will not be overwritten if codegen is rerun
2

            
3
//============================================================================
4
//  T h e r m o s t a t  -- Thread Component
5
//
6
//  This Thread component implements control logic that 
7
//  turns a heat source on/off based on the values of the following inputs...
8
//    - current temperature
9
//    - set points provided by an operator 
10
//        (these specify the lower and upper bounds (inclusive) for the 
11
//        desired temperature range.
12
//
13
//============================================================================
14

            
15
use data::*;
16
use data::Isolette_Data_Model::*; // Add for easier reference of data types
17
use crate::bridge::thermostat_thermostat_api::*;
18
use vstd::prelude::*;
19

            
20
verus! {
21

            
22
  //-------------------------------------------
23
  //  Application State (as a struct)
24
  //
25
  //  The application state includes a model-level GUMBO declared state variable
26
  //  `lastCmd` that is visible to the model-level contract for the thread.
27
  //-------------------------------------------
28
  pub struct thermostat_thermostat {
29
    // BEGIN MARKER STATE VARS
30
    pub lastCmd: Isolette_Data_Model::On_Off,
31
    // END MARKER STATE VARS
32
  }
33

            
34
  impl thermostat_thermostat {
35
    //-------------------------------------------
36
    //  Application Component Constructor
37
    //-------------------------------------------
38
526
    pub fn new() -> Self
39
526
    {
40
526
      Self {
41
526
        // BEGIN MARKER STATE VAR INIT
42
526
        lastCmd: Isolette_Data_Model::On_Off::default(),
43
526
        // END MARKER STATE VAR INIT
44
526
      }
45
526
    }
46

            
47
    //-------------------------------------------
48
    //  Initialize Entry Point
49
    //-------------------------------------------
50
526
    pub fn initialize<API: thermostat_thermostat_Put_Api> (
51
526
      &mut self,
52
526
      api: &mut thermostat_thermostat_Application_Api<API>)
53
526
      ensures
54
526
        // BEGIN MARKER INITIALIZATION ENSURES
55
526
        // guarantee initlastCmd
56
526
        self.lastCmd == Isolette_Data_Model::On_Off::Off,
57
526
        // guarantee REQ_THERM_1
58
526
        //   The Heat Control command shall be Off initially.
59
526
        api.heat_control == Isolette_Data_Model::On_Off::Off,
60
526
        // END MARKER INITIALIZATION ENSURES
61
526
    {
62
526
      log_info("initialize entrypoint invoked");
63
526

            
64
526
      self.lastCmd = On_Off::Off;
65
526
      // REQ_THERM_1: The Heat Control shall be initially Off
66
526
      let currentCmd = On_Off::Off;
67
526
      api.put_heat_control(currentCmd) 
68
526
    }
69

            
70
    //-------------------------------------------
71
    //  Compute Entry Point
72
    //-------------------------------------------
73
244
    pub fn timeTriggered<API: thermostat_thermostat_Full_Api> (
74
244
      &mut self,
75
244
      api: &mut thermostat_thermostat_Application_Api<API>)
76
244
      requires
77
244
        // BEGIN MARKER TIME TRIGGERED REQUIRES
78
244
        // assume ASSM_LDT_LE_UDT
79
244
        old(api).desired_temp.lower.degrees <= old(api).desired_temp.upper.degrees,
80
244
        // END MARKER TIME TRIGGERED REQUIRES
81
244
      ensures
82
244
        // BEGIN MARKER TIME TRIGGERED ENSURES
83
244
        // guarantee lastCmd
84
244
        //   Set lastCmd to value of output Cmd port
85
244
        self.lastCmd == api.heat_control,
86
244
        // case REQ_THERM_2
87
244
        //   If Current Temperature is less than
88
244
        //   the Lower Desired Temperature, the Heat Control shall be set to On.
89
244
        (old(api).current_temp.degrees < old(api).desired_temp.lower.degrees) ==>
90
244
          (api.heat_control == Isolette_Data_Model::On_Off::Onn),
91
244
        // case REQ_THERM_3
92
244
        //   If the Current Temperature is greater than
93
244
        //   the Upper Desired Temperature, the Heat Control shall be set to Off.
94
244
        (old(api).current_temp.degrees > old(api).desired_temp.upper.degrees) ==>
95
244
          (api.heat_control == Isolette_Data_Model::On_Off::Off),
96
244
        // case REQ_THERM_4
97
244
        //   If the Current Temperature is greater than or equal 
98
244
        //   to the Lower Desired Temperature
99
244
        //   and less than or equal to the Upper Desired Temperature, the value of
100
244
        //   the Heat Control shall not be changed.
101
244
        ((old(api).current_temp.degrees >= old(api).desired_temp.lower.degrees) &&
102
244
          (old(api).current_temp.degrees <= old(api).desired_temp.upper.degrees)) ==>
103
244
          (api.heat_control == old(self).lastCmd),
104
244
        // END MARKER TIME TRIGGERED ENSURES
105
244
    {
106
244
      log_info("compute entrypoint invoked");
107
244

            
108
244
       // -------------- Get values of input ports ------------------
109
244
      let desired_temp: Set_Points = api.get_desired_temp(); 
110
244
      let currentTemp: Temp = api.get_current_temp();
111
244

            
112
244
      //================ compute / control logic ===========================
113
244

            
114
244
      // current command defaults to value of last command (REQ-THERM-4)
115
244
      let mut currentCmd: On_Off = self.lastCmd;
116
244

            
117
244
      if (currentTemp.degrees > desired_temp.upper.degrees) {
118
36
         // REQ-THERM-3
119
36
         currentCmd = On_Off::Off;
120
208
      } else if (currentTemp.degrees < desired_temp.lower.degrees) {
121
74
         assert(api.current_temp.degrees < api.desired_temp.lower.degrees);
122
74
         // REQ-THERM-2
123
74
         //currentCmd = On_Off::Off; // seeded bug/error
124
74
         currentCmd = On_Off::Onn;
125
134
      }
126

            
127
      // -------------- Set values of output ports ------------------
128
244
      api.put_heat_control(currentCmd);
129
244
      self.lastCmd = currentCmd        
130
244

            
131
244
    }
132

            
133
    //-------------------------------------------
134
    //  seL4 / Microkit Error Handling
135
    //-------------------------------------------
136
    pub fn notify(
137
      &mut self,
138
      channel: microkit_channel)
139
    {
140
      // this method is called when the monitor does not handle the passed in channel
141
      match channel {
142
        _ => {
143
          log_warn_channel(channel)
144
        }
145
      }
146
    }
147
  }
148

            
149
  //-------------------------------------------
150
  //  Logging Helper Functions
151
  //-------------------------------------------
152
  #[verifier::external_body]
153
770
  pub fn log_info(msg: &str)
154
770
  {
155
770
    log::info!("{0}", msg);
156
770
  }
157

            
158
  #[verifier::external_body]
159
  pub fn log_warn_channel(channel: u32)
160
  {
161
    log::warn!("Unexpected channel: {0}", channel);
162
  }
163

            
164
  //-------------------------------------------
165
  //  GUMBO-derived functions/constants auto-generated by HAMR from 
166
  //  model.
167
  //-------------------------------------------
168

            
169
  // BEGIN MARKER GUMBO METHODS
170
  pub open spec fn Temp_Lower_Bound() -> i32
171
  {
172
    95i32
173
  }
174

            
175
  pub open spec fn Temp_Upper_Bound() -> i32
176
  {
177
    104i32
178
  }
179
  // END MARKER GUMBO METHODS
180

            
181
}