2026-07-10 10:38:57 +02:00

481 lines
17 KiB
Python

import math
from ScEpTIC.AST.builtins.builtin import Builtin
from ScEpTIC.AST.elements.value import Value
from ScEpTIC.emulator.energy.mcu import ADCPowerState
from ScEpTIC.emulator.energy.mcu.options import MCUClockCycleAction
from ScEpTIC.emulator.energy.options import OpModeName
class voc_read_data(Builtin):
"""
voc_read_data() builtin that reads voc from SGP40 sensor
"""
def get_val(self):
try:
sgp40 = self._vmstate.config.analysis.energy.system_model.get_component('SGP40')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if sgp40 is None:
raise Exception("SHT85 not attached to ScEpTIC")
# read
self._vmstate.global_clock += sgp40.simulate_read()
class temperature_read_data(Builtin):
"""
temperature_read_data() builtin that reads temperature from SHT85 sensor
"""
def get_val(self):
try:
sht85 = self._vmstate.config.analysis.energy.system_model.get_component('SHT85')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if sht85 is None:
raise Exception("SHT85 not attached to ScEpTIC")
# read
self._vmstate.global_clock += sht85.simulate_read()
class camera_read_data(Builtin):
"""
camera_read_data() builtin that reads a camera
"""
def get_val(self):
try:
camera = self._vmstate.config.analysis.energy.system_model.get_component('0V7620')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if camera is None:
raise Exception("Camera not attached to ScEpTIC")
# word size
self._vmstate.global_clock += camera.simulate_read(int(self.args[0]))
class generic_adc_sensor_read(Builtin):
"""
generic_adc_sensor_read() builtin that reads a generic ADC sensor
"""
def get_val(self):
try:
generic_sensor = self._vmstate.config.analysis.energy.system_model.get_component('generic_sensor')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if generic_sensor is None:
raise Exception("GenericADCSensor not attached to ScEpTIC")
self._vmstate.global_clock += generic_sensor.simulate_read(int(self.args[0]))
class cc1101_set_state(Builtin):
"""
cc1101_set_state() builtin that sets the state of cc1101
"""
states = {0: 'off', 1: 'inactive', 2: 'active'}
def get_val(self):
try:
cc1101 = self._vmstate.config.analysis.energy.system_model.get_component('cc1101')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if cc1101 is None:
raise Exception("CC1101 not attached to ScEpTIC")
self._vmstate.global_clock += cc1101.simulate_set_state(self.states[int(self.args[0])])
class cc1101_transmit(Builtin):
"""
cc1101_transmit() builtin that turns on the cc1101, transmit data, and turns it off
"""
def get_val(self):
try:
cc1101 = self._vmstate.config.analysis.energy.system_model.get_component('cc1101')
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
if cc1101 is None:
raise Exception("CC1101 not attached to ScEpTIC")
# args: bytes, word_size
self._vmstate.global_clock += cc1101.simulate_transmit(int(self.args[0]), int(self.args[1]))
class adc_off(Builtin):
"""
adc_off() builtin that turns off the ADCon
"""
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
# Turn off ADC
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_ADC)
system_model.mcu.set_adc_state(ADCPowerState.OFF)
class adc_on(Builtin):
"""
adc_on() builtin that turns on the ADC
"""
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
# Turn on ADC
# - Run instructions
# - ADCPowerState -> ON
for _ in range(system_model.mcu.adc_instructions['on']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_ADC)
system_model.mcu.set_adc_state(ADCPowerState.ON)
class adc_read(Builtin):
"""
adc_read() builtin that reads data from ADC
"""
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
# Wait for startup and data to be ready
for _ in range(system_model.mcu.get_ADC_wait_cycles()):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
# Transfer
for _ in range(system_model.mcu.adc_instructions['transfer']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
class adc_get_data(Builtin):
"""
adc_get_data(n_samples, wait_between_samples) builtin that turns the ADC on, collects n_samples (one every wait_between_samples ms), and turns the ADC off.
"""
op_mode_name = OpModeName.SIMULATE_ADC
def __adc_on(self, system_model):
# Turn on ADC
# - Run instructions
# - ADCPowerState -> ON
for _ in range(system_model.mcu.adc_instructions['on']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
system_model.mcu.set_adc_state(ADCPowerState.ON)
def __adc_off(self, system_model):
# Turn off ADC
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
system_model.mcu.set_adc_state(ADCPowerState.OFF)
def __adc_transfer_data(self, system_model):
# Wait for startup and data to be ready
for _ in range(system_model.mcu.get_ADC_wait_cycles()):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
# Transfer
for _ in range(system_model.mcu.adc_instructions['transfer']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
def __wait_cycles(self, system_model, wait_cycles):
if wait_cycles <= 0:
return
for _ in range(wait_cycles):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, self.op_mode_name)
def __adc_get_samples_on_off(self, system_model, n_samples, wait_cycles):
for i in range(n_samples):
self.__adc_on(system_model)
self.__adc_transfer_data(system_model)
self.__adc_off(system_model)
if i < (n_samples - 1):
self.__wait_cycles(system_model, wait_cycles)
def __adc_get_samples(self, system_model, n_samples, wait_cycles):
self.__adc_on(system_model)
for i in range(n_samples):
self.__adc_transfer_data(system_model)
if i < (n_samples - 1):
self.__wait_cycles(system_model, wait_cycles)
self.__adc_off(system_model)
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
# Samples to collect
n_samples = self.args[0]
# ms to wait between samples
samples_s_wait = float(self.args[1]) / 1000.0
frequency = system_model.mcu.get_frequency()
sample_wait_cycles = max(0, math.ceil(samples_s_wait*frequency) - system_model.mcu.get_ADC_wait_cycles())
wait_cycles = sample_wait_cycles - system_model.mcu.adc_instructions['on'] - 1
if self.args[2] == 0:
self.__adc_get_samples(system_model, n_samples, sample_wait_cycles)
else:
self.__adc_get_samples_on_off(system_model, n_samples, wait_cycles)
class timekeeper_get_time_us(Builtin):
"""
timekeeper_get_time_us() builtin that returns timekeeper power-off time in us
"""
def get_val(self):
try:
return self._vmstate.config.analysis.energy.system_model.timekeeper.get_time() * 1000000.0
except BaseException:
raise Exception("SystemModel/Timekeeper not attached to ScEpTIC")
class timekeeper_get_time(Builtin):
"""
timekeeper_get_time() builtin that returns timekeeper power-off time
"""
def get_val(self):
try:
return self._vmstate.config.analysis.energy.system_model.timekeeper.get_time()
except BaseException:
raise Exception("SystemModel/Timekeeper not attached to ScEpTIC")
class set_mcu_power_on_voltage(Builtin):
"""
set_mcu_power_on_voltage() builtin that sets the power on voltage of the MCU
"""
def get_val(self):
try:
voltage = self.args[0]
#print(f"Set MCU Von={voltage}V")
return self._vmstate.config.analysis.energy.system_model.mcu.set_v_on(voltage)
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_mcu_time(Builtin):
"""
get_mcu_time() builtin that returns the mcu time
"""
def get_val(self):
try:
#t = self._vmstate.config.analysis.energy.system_model.mcu.get_time()
#print(f"Time: {t}")
return self._vmstate.config.analysis.energy.system_model.mcu.get_time()
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_mcu_time_us(Builtin):
"""
get_mcu_time_us() builtin that returns the mcu time in us
"""
def get_val(self):
try:
return self._vmstate.config.analysis.energy.system_model.mcu.get_time() * 1000000
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class set_mcu_time(Builtin):
"""
set_mcu_time() builtin that sets the mcu time
"""
def get_val(self):
try:
t = float(self.args[0])
self._vmstate.config.analysis.energy.system_model.mcu.set_time(t)
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class set_mcu_time_us(Builtin):
"""
set_mcu_time_us() builtin that sets the mcu time in us
"""
def get_val(self):
try:
t = float(self.args[0]) / 1000000.0
self._vmstate.config.analysis.energy.system_model.mcu.set_time(t)
except BaseException as e:
print(self.args)
print(e)
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_simulation_time(Builtin):
"""
get_simulation_time() builtin that returns the simulation time
"""
print_enabled = False
def get_val(self):
try:
t = self._vmstate.config.analysis.energy.system_model.get_simulation_time()
if self.print_enabled:
t_us = t * 1000000.0
print(f"Time (us): {round(t_us, 2)}")
return t
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class reset_simulation_time(Builtin):
"""
reset_simulation_time() builtin that resets the simulation time
"""
def get_val(self):
try:
self._vmstate.config.analysis.energy.system_model.reset_simulation_time()
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_mcu_clock_cycles(Builtin):
"""
get_mcu_clock_cycles() builtin that returns the number of clock cycles in the latest active cycle
"""
def get_val(self):
try:
return self._vmstate.config.analysis.energy.system_model.mcu.get_clock_cycles()
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_used_energy(Builtin):
"""
get_used_energy() builtin that returns the used energy
"""
print_enabled = False
def get_val(self):
try:
e = self._vmstate.config.analysis.energy.system_model.get_used_energy()
if self.print_enabled:
e_uj = e * 1000000.0
print(f"Energy consumption (uJ): {round(e_uj, 2)}")
return e
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class set_capacitor_voltage(Builtin):
"""
set_voltage() bultin that sets the energy buffer voltage
"""
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
system_model.energy_buffer.set_voltage(self.args[0])
class reset_used_energy(Builtin):
"""
reset_energy() builtin that resets the energy consumption
"""
def get_val(self):
try:
self._vmstate.config.analysis.energy.system_model.reset_used_energy()
except BaseException:
raise Exception("SystemModel/MCU not attached to ScEpTIC")
class get_capacitor_voltage(Builtin):
"""
get_voltage() builtin that returns capacitor voltage
"""
def get_val(self):
try:
system_model = self._vmstate.config.analysis.energy.system_model
except BaseException:
raise Exception("SystemModel not attached to ScEpTIC")
op_mode_name = OpModeName.PROBE_ENERGY_BUFFER
# Turn on ADC
# - Run instructions
# - ADCPowerState -> ON
for _ in range(system_model.mcu.adc_instructions['on']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, op_mode_name)
system_model.mcu.set_adc_state(ADCPowerState.ON)
# Wait for startup and data to be ready
for _ in range(system_model.mcu.get_ADC_wait_cycles()):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, op_mode_name, True)
# Transfer data to reg
for _ in range(system_model.mcu.adc_instructions['transfer']):
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, op_mode_name)
v = system_model.energy_buffer.get_voltage()
# Turn off ADC
self._vmstate.global_clock += system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, op_mode_name)
system_model.mcu.set_adc_state(ADCPowerState.OFF)
return v
get_capacitor_voltage.define_builtin('sceptic_get_capacitor_voltage', '', 'double')
set_capacitor_voltage.define_builtin('sceptic_set_capacitor_voltage', 'double', 'void')
get_mcu_clock_cycles.define_builtin('sceptic_get_mcu_clock_cycles', '', 'i32')
get_mcu_time.define_builtin('sceptic_get_mcu_time', '', 'double')
get_mcu_time_us.define_builtin('sceptic_get_mcu_time_us', '', 'double')
get_used_energy.define_builtin('sceptic_get_used_energy', '', 'double')
reset_used_energy.define_builtin('sceptic_reset_used_energy', '', 'void')
get_simulation_time.define_builtin('sceptic_get_simulation_time', '', 'double')
set_mcu_time.define_builtin('sceptic_set_mcu_time', 'double', 'void')
set_mcu_time_us.define_builtin('sceptic_set_mcu_time_us', 'double', 'void')
reset_simulation_time.define_builtin('sceptic_reset_simulation_time', '', 'void')
# voltage
set_mcu_power_on_voltage.define_builtin('sceptic_set_mcu_power_on_voltage', 'double', 'void')
timekeeper_get_time.define_builtin('sceptic_timekeeper_get_time', '', 'double')
timekeeper_get_time_us.define_builtin('sceptic_timekeeper_get_time_us', '', 'double')
# n_samples, t_wait (ms), on_off
adc_get_data.define_builtin('sceptic_adc_get_data', 'i32, double, i32', 'void')
adc_on.define_builtin('sceptic_adc_on', '', 'void')
adc_off.define_builtin('sceptic_adc_off', '', 'void')
adc_read.define_builtin('sceptic_adc_read', '', 'void')
# bytes, word_size
cc1101_transmit.define_builtin('sceptic_cc1101_transmit', 'i32, i32', 'void')
# state_id
cc1101_set_state.define_builtin('sceptic_cc1101_set_state', 'i32', 'void')
# n_samples
generic_adc_sensor_read.define_builtin('sceptic_generic_adc_sensor_read', 'i32', 'void')
# word size
camera_read_data.define_builtin('sceptic_camera_read_data', 'i32', 'void')
temperature_read_data.define_builtin('sceptic_read_temperature', '', 'void')
voc_read_data.define_builtin('sceptic_read_voc', '', 'void')