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
8
    pub fn new() -> Self
39
8
    {
40
8
      Self {
41
8
        // BEGIN MARKER STATE VAR INIT
42
8
        lastCmd: Isolette_Data_Model::On_Off::default(),
43
8
        // END MARKER STATE VAR INIT
44
8
      }
45
8
    }
46

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

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

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

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

            
112
4
      //================ compute / control logic ===========================
113
4

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

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

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

            
131
4
    }
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
12
  pub fn log_info(msg: &str)
154
12
  {
155
12
    log::info!("{0}", msg);
156
12
  }
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
}