Index: dialin/common/dg_defs.py =================================================================== diff -u -ra901fe931c08daea69337c1f44135637a764ce7a -r107697bd31dc87e450f18cca334025c631a6825d --- dialin/common/dg_defs.py (.../dg_defs.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) +++ dialin/common/dg_defs.py (.../dg_defs.py) (revision 107697bd31dc87e450f18cca334025c631a6825d) @@ -156,3 +156,20 @@ CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT = 6 CHEM_DISINFECT_UI_STATE_COMPLETE = 7 + +@unique +class DGEventList(DialinEnum): + DG_EVENT_STARTUP = 0 + DG_EVENT_OP_MODE_CHANGE = 1 + DG_EVENT_SUB_MODE_CHANGE = 2 + + +@unique +class DGEventDataType(DialinEnum): + EVENT_DATA_TYPE_NONE = 0 + EVENT_DATA_TYPE_U32 = 1 + EVENT_DATA_TYPE_S32 = 2 + EVENT_DATA_TYPE_F32 = 3 + EVENT_DATA_TYPE_BOOL = 4 + + Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -r107697bd31dc87e450f18cca334025c631a6825d --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 107697bd31dc87e450f18cca334025c631a6825d) @@ -45,6 +45,7 @@ from .uv_reactors import UVReactors from .valves import DGValves from .voltages import DGVoltages +from .events import DGEvents from ..common.msg_defs import MsgIds, MsgFieldPositions from ..protocols.CAN import DenaliCanMessenger, DenaliMessage, DenaliChannels from ..utils import * @@ -178,6 +179,7 @@ self.uv_reactors = UVReactors(self.can_interface, self.logger) self.valves = DGValves(self.can_interface, self.logger) self.voltages = DGVoltages(self.can_interface, self.logger) + self.events = DGEvents(self.can_interface, self.logger) def get_version(self): """ Index: dialin/dg/events.py =================================================================== diff -u -ra901fe931c08daea69337c1f44135637a764ce7a -r107697bd31dc87e450f18cca334025c631a6825d --- dialin/dg/events.py (.../events.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) +++ dialin/dg/events.py (.../events.py) (revision 107697bd31dc87e450f18cca334025c631a6825d) @@ -1,23 +1,19 @@ import struct -from enum import unique from logging import Logger +from ..common import DGEventList, DGEventDataType from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import DenaliMessage, DenaliChannels -from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..protocols.CAN import DenaliChannels +from ..utils.base import AbstractSubSystem, publish from datetime import datetime -#TODO add events enum - class DGEvents(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for events related commands. """ - _LENGTH_OF_DG_EVENTS_LIST = 20 - def __init__(self, can_interface, logger: Logger): """ @@ -29,14 +25,62 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dg_sync_broadcast_ch_id + channel_id = DenaliChannels.dg_to_ui_ch_id msg_id = MsgIds.MSG_ID_DG_EVENT.value self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_events_sync) - self._dg_events_list = [] - self._current_event_index = 0 + # Define the dictionaries + self._dg_event_dictionary = dict() + self._dg_event_data_type = dict() - @publish(['_dg_events_list']) + # Loop through the list of the DG events enums and initial the event dictionary. Each event is a key in the + # dictionary and the value is a list. + for event in DGEventList: + self._dg_event_dictionary[DGEventList(event).name] = [] + + # Loop through the list of the event data type enum and update the dictionary + for data_type in DGEventDataType: + event_data_type = DGEventDataType(data_type).name + struct_unpack_type = None + + # If U32 is in the data type enum (i.e. EVENT_DATA_TYPE_U32), then the key is the enum and the value is + # the corresponding format in the python struct + if 'U32' in event_data_type or 'BOOL' in event_data_type: + struct_unpack_type = 'I' + elif 'S32' in event_data_type: + struct_unpack_type = 'i' + elif 'F32' in event_data_type: + struct_unpack_type = 'f' + + self._dg_event_data_type[event_data_type] = struct_unpack_type + + def get_dg_events(self, event_id, number_of_events): + """ + Returns the requested number of a certain DG event ID + + @param event_id the ID of the DG event types (i.e. DG_EVENT_STARTUP) + @param number_of_events the last number of messages of a certain event type + + @returns a list of the requested DG event type + """ + + list_of_events = [] + + # If there are not enough event lists send all the events that are available + if len(self._dg_event_dictionary[DGEventList(event_id).name]) <= number_of_events: + list_of_events = self._dg_event_dictionary[DGEventList(event_id).name] + else: + # Get the all the events + complete_list = self._dg_event_dictionary[DGEventList(event_id).name] + + # Since the last are located at the end of the list, iterate backwards for the defined + # event messages + for i in range(len(complete_list) - 1, number_of_events + 1, -1): + list_of_events.append(complete_list[i]) + + return list_of_events + + @publish(['_dg_event_dictionary']) def _handler_events_sync(self, message): """ Handles published events message @@ -46,19 +90,26 @@ """ event_id = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + + # Get the data type event_data_type_1 = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - event_data_1 = struct.unpack('i', bytearray( + # Get the corresponding structure format + struct_data_type = self._dg_event_data_type[DGEventDataType(event_data_type_1).name] + # Get the data value by unpacking the data type + event_data_1 = struct.unpack(struct_data_type, bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + event_data_type_2 = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - event_data_2 = struct.unpack('i', bytearray( + struct_data_type = self._dg_event_data_type[DGEventDataType(event_data_type_2).name] + event_data_2 = struct.unpack(struct_data_type, bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - local_event = [datetime.now(), event_id, event_data_type_1, event_data_1, event_data_type_2, event_data_2] - self._dg_events_list.insert(self._current_event_index, local_event) + # Convert the event ID to enum + event_state_name = DGEventList(event_id).name + # Get the current timestamp and create a tuple of the current events + event_tuple = (str(datetime.now()), event_state_name, event_data_1, event_data_2) - if self._current_event_index >= self._LENGTH_OF_DG_EVENTS_LIST - 1: - self._current_event_index = 0 - else: - self._current_event_index += 1 + # Update event dictionary + self._dg_event_dictionary[event_state_name].append(event_tuple) Index: tests/dg_heat_and_chemical_disinfect_test.py =================================================================== diff -u -r43496ad886040327652f976a8796943f508cc764 -r107697bd31dc87e450f18cca334025c631a6825d --- tests/dg_heat_and_chemical_disinfect_test.py (.../dg_heat_and_chemical_disinfect_test.py) (revision 43496ad886040327652f976a8796943f508cc764) +++ tests/dg_heat_and_chemical_disinfect_test.py (.../dg_heat_and_chemical_disinfect_test.py) (revision 107697bd31dc87e450f18cca334025c631a6825d) @@ -26,6 +26,7 @@ from dialin.dg.temperature_sensors import TemperatureSensorsNames from dialin.dg.dialysate_generator import DGOperationModes from dialin.hd.temperatures import HDTemperaturesNames +from dialin.dg.events import DGEvents from time import sleep from datetime import datetime import sys @@ -71,8 +72,9 @@ def get_dg_run_info(): - info = ('DG_op_mode, {}, DG_sub_mode, {}, '.format(DGOperationModes(dg.dg_operation_mode).name, - dg.dg_operation_sub_mode)) + info = ('DG_op_mode, {}, DG_sub_mode, {}, DG_event, {}, '.format(DGOperationModes(dg.dg_operation_mode).name, + dg.dg_operation_sub_mode, + dg.events.get_dg_events())) return info @@ -543,9 +545,9 @@ #run_chemical_disinfect() - #run_dg() + run_dg() - run_ro_pump_duty_cycles() + #run_ro_pump_duty_cycles() #cmd_set_disinfect_ui_screen()