Index: leahi_dialin/dd/modules/records.py =================================================================== diff -u -rfa06efd219892c67eabb3099a4af3dea4304edb5 -rc1bff8da59cff294d67d90dd1e1f102dd5b65466 --- leahi_dialin/dd/modules/records.py (.../records.py) (revision fa06efd219892c67eabb3099a4af3dea4304edb5) +++ leahi_dialin/dd/modules/records.py (.../records.py) (revision c1bff8da59cff294d67d90dd1e1f102dd5b65466) @@ -20,7 +20,7 @@ from time import sleep # Project imports -from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common import dd_enum_repository, disp_enum_repository from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_override @@ -36,15 +36,6 @@ DD interface containing pressure related commands. """ - CALIB_RECORDS_PRESSURE_SENSORS = 'pressure_sensors' - CALIB_RECORDS_TEMPERATURE_SENSORS = 'temperature_sensors' - CALIB_RECORDS_CONCENTRATE_PUMPS = 'concentrate_pump' - CALIB_RECORDS_DIALYSATE_PUMPS = 'dialysate_pumps' - CALIB_RECORDS_ACID_CONCENTRATE = 'acid_concentrate' - CALIB_RECORDS_BICARB_CONCENTRATE = 'bicarb_concentrate' - CALIB_RECORDS_ACCELEROMETER = 'accelerometer' - CALIB_RECORDS_BLOOD_LEAK = 'blood_leak' - def __init__(self, can_interface: CanMessenger, logger: Logger): """ @param can_interface: The CanMessenger object @@ -629,7 +620,7 @@ can_interface = self.can_interface) - def cmd_set_calibration_records(self, calibration_records: dict) -> int: + def cmd_set_calibration_records(self, calibration_records: dict={}) -> int: """ Constructs and sends a command for setting the Calibration Records. Constraints: @@ -640,72 +631,180 @@ @return: 1 if successful, zero otherwise """ msg_id_pairing = { - self.CALIB_RECORDS_PRESSURE_SENSORS: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_PRESSURE_SENSOR, - self.CALIB_RECORDS_TEMPERATURE_SENSORS: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_TEMP_SENSOR, - self.CALIB_RECORDS_CONCENTRATE_PUMPS: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_D48_PUMP, - self.CALIB_RECORDS_DIALYSATE_PUMPS: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_CONC_PUMP, - self.CALIB_RECORDS_ACID_CONCENTRATE: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_ACID_CONCENTRATE, - self.CALIB_RECORDS_BICARB_CONCENTRATE: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_BICARB_CONCENTRATE, - self.CALIB_RECORDS_ACCELEROMETER: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_ACCEL_SENSOR, - self.CALIB_RECORDS_BLOOD_LEAK: MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_BLOOD_LEAK_SENSOR, + 'PRES': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_PRESSURE_SENSOR, + 'TEMP': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_TEMP_SENSOR, + 'CONC': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_D48_PUMP, + 'DIAL': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_CONC_PUMP, + 'ACID': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_ACID_CONCENTRATE, + 'BICARB': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_BICARB_CONCENTRATE, + 'ACCEL': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_ACCEL_SENSOR, + 'BLOOD_LEAK': MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_BLOOD_LEAK_SENSOR, } - # Make a dictionary to store all the send functions for later send send_data = [] - for key in calibration_records: - if key.lower() in [self.CALIB_RECORDS_PRESSURE_SENSORS, self.CALIB_RECORDS_TEMPERATURE_SENSORS, self.CALIB_RECORDS_CONCENTRATE_PUMPS, self.CALIB_RECORDS_DIALYSATE_PUMPS]: - for sensor in calibration_records[key]: - # Exception handling as D12 has an extra field (target speed) - if sensor in [dd_enum_repository.DDDialysatePumpNames.D12_PUMP]: - # Store the function but do not execute it - send_data.append(partial(self.cmd_set_calibration_records_sensor, - sensor_enum = sensor, - msg_id = MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_D12_PUMP, - dialysate_pump_target_speed = calibration_records[key][sensor]['target_speed'], - forth_order_coeff = calibration_records[key][sensor]['forth_order_coeff'], - third_order_coeff = calibration_records[key][sensor]['third_order_coeff'], - second_order_coeff = calibration_records[key][sensor]['second_order_coeff'], - gain = calibration_records[key][sensor]['gain'], - offset = calibration_records[key][sensor]['offset'], - calibration_time = calibration_records[key][sensor]['calibration_time'])) - else: - # Store the function but do not execute it - send_data.append(partial(self.cmd_set_calibration_records_sensor, - sensor_enum = sensor, - msg_id = msg_id_pairing[key], - forth_order_coeff = calibration_records[key][sensor]['forth_order_coeff'], - third_order_coeff = calibration_records[key][sensor]['third_order_coeff'], - second_order_coeff = calibration_records[key][sensor]['second_order_coeff'], - gain = calibration_records[key][sensor]['gain'], - offset = calibration_records[key][sensor]['offset'], - calibration_time = calibration_records[key][sensor]['calibration_time'])) - elif key.lower() in [self.CALIB_RECORDS_ACID_CONCENTRATE, self.CALIB_RECORDS_BICARB_CONCENTRATE]: - for sensor in calibration_records[key]: - # Store the function but do not execute it - send_data.append(partial(self.cmd_set_calibration_records_concentrate, - msg_id = msg_id_pairing[key], - concentrate_mix_ratio = calibration_records[key][sensor]['concentrate_mix_ratio'], - volume_ml = calibration_records[key][sensor]['volume_ml'], - conductivity_uspcm = calibration_records[key][sensor]['conductivity_uspcm'], - temperature_c = calibration_records[key][sensor]['temperature_c'], - calibration_time = calibration_records[key][sensor]['calibration_time'])) - elif key.lower() in [self.CALIB_RECORDS_ACCELEROMETER]: - for sensor in calibration_records[key]: - # Store the function but do not execute it - send_data.append(partial(self.cmd_set_calibration_records_accelerometer, - msg_id = msg_id_pairing[key], - accel_x_offset = calibration_records[key][sensor]['accel_x_offset'], - accel_y_offset = calibration_records[key][sensor]['accel_y_offset'], - accel_z_offset = calibration_records[key][sensor]['accel_z_offset'], - calibration_time = calibration_records[key][sensor]['calibration_time'])) - elif key.lower() in [self.CALIB_RECORDS_BLOOD_LEAK]: - for sensor in calibration_records[key]: - # Store the function but do not execute it - send_data.append(partial(self.cmd_set_calibration_records_blood_leak, - msg_id = msg_id_pairing[key], - set_point = calibration_records[key][sensor]['set_point'], - calibration_time = calibration_records[key][sensor]['calibration_time'])) - + checked = [] + for record_enum in dd_enum_repository.CalibrationRecordFields: + record_parts = record_enum.name.split('__') + group = record_parts[0] + + # If a message already sent, then just go to the next value + if 'NUM_' in group or \ + group in checked or \ + record_parts[1] in checked: + continue + + if group in ['PRES', 'TEMP', 'CONC', 'DIAL']: + # Set the sensor name + if group == 'PRES': + sensor = dd_enum_repository.DDPressureSensorNames.from_str(record_parts[1]) + elif group == 'TEMP': + sensor = dd_enum_repository.DDTemperatureSensorNames.from_str(record_parts[1]) + elif group == 'CONC': + sensor = dd_enum_repository.DDConcentratePumpNames.from_str(record_parts[1]) + elif group == 'DIAL': + sensor = dd_enum_repository.DDDialysatePumpNames.from_str(record_parts[1]) + else: + sensor = 'UNKNOWN' + + # Set the arguments for the call + args = [] + kwargs = {} + target_speed_entry_name = f'{group}__{sensor.name}__TARGET_SPEED' + fourth_order_coeff_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.FOURTH_ORDER_COEFF.name}' + third_order_coeff_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.THIRD_ORDER_COEFF.name}' + second_order_coeff_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.SECOND_ORDER_COEFF.name}' + gain_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.GAIN.name}' + offset_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.OFFSET.name}' + calibration_time_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordSensorFields.CALIBRATION_TIME.name}' + + kwargs['sensor_enum'] = sensor + if sensor == dd_enum_repository.DDDialysatePumpNames.D12_PUMP: + kwargs['msg_id'] = MsgIds.MSG_ID_UI_DD_NVM_SET_CAL_D12_PUMP + else: + kwargs['msg_id'] = msg_id_pairing[group] + + if target_speed_entry_name in calibration_records and calibration_records[target_speed_entry_name] is not None: + kwargs['dialysate_pump_target_speed'] = calibration_records[target_speed_entry_name] + + if fourth_order_coeff_entry_name in calibration_records and calibration_records[fourth_order_coeff_entry_name] is not None: + kwargs['forth_order_coeff'] = calibration_records[fourth_order_coeff_entry_name] + + if third_order_coeff_entry_name in calibration_records and calibration_records[third_order_coeff_entry_name] is not None: + kwargs['third_order_coeff'] = calibration_records[third_order_coeff_entry_name] + + if second_order_coeff_entry_name in calibration_records and calibration_records[second_order_coeff_entry_name] is not None: + kwargs['second_order_coeff'] = calibration_records[second_order_coeff_entry_name] + + if gain_entry_name in calibration_records and calibration_records[gain_entry_name] is not None: + kwargs['gain'] = calibration_records[gain_entry_name] + + if offset_entry_name in calibration_records and calibration_records[offset_entry_name] is not None: + kwargs['offset'] = calibration_records[offset_entry_name] + + if calibration_time_entry_name in calibration_records and calibration_records[calibration_time_entry_name] is not None: + kwargs['calibration_time'] = calibration_records[calibration_time_entry_name] + + checked.append(record_parts[1]) + # Skip sending if dictionary is provided but all entry for the sensor was None (except sensor_enum and MSG_ID, because those are neccesary) + if calibration_records != {} and len(kwargs) == 2: + continue + + # Create the send data function + send_data.append(partial(self.cmd_set_calibration_records_sensor, *args, **kwargs)) + + elif group in ['ACID', 'BICARB']: + if group == 'ACID': + sensor = disp_enum_repository.AcidTypes.from_str(record_parts[1]) + elif group == 'BICARB': + sensor = disp_enum_repository.BicarbTypes.from_str(record_parts[1]) + else: + sensor = 'unknown' + + # Set the arguments for the call + args = [] + kwargs = {} + concentrate_mix_ratio_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordConcentrateFields.CONCENTRATE_MIX_RATIO.name}' + volume_ml_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordConcentrateFields.FULL_BOTTLE_VOLUME_ML.name}' + conductivity_uspcm_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordConcentrateFields.CONDUCTIVITY_USPCM.name}' + temperature_c_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordConcentrateFields.BOTTLE_TEMPERATURE_C.name}' + calibration_time_entry_name = f'{group}__{sensor.name}__{dd_enum_repository.CalibRecordConcentrateFields.CALIBRATION_TIME.name}' + + kwargs['msg_id'] = msg_id_pairing[group] + if concentrate_mix_ratio_entry_name in calibration_records and calibration_records[concentrate_mix_ratio_entry_name] is not None: + kwargs['concentrate_mix_ratio'] = calibration_records[concentrate_mix_ratio_entry_name] + + if volume_ml_entry_name in calibration_records and calibration_records[volume_ml_entry_name] is not None: + kwargs['volume_ml'] = calibration_records[volume_ml_entry_name] + + if conductivity_uspcm_entry_name in calibration_records and calibration_records[conductivity_uspcm_entry_name] is not None: + kwargs['conductivity_uspcm'] = calibration_records[conductivity_uspcm_entry_name] + + if temperature_c_entry_name in calibration_records and calibration_records[temperature_c_entry_name] is not None: + kwargs['temperature_c'] = calibration_records[temperature_c_entry_name] + + if calibration_time_entry_name in calibration_records and calibration_records[calibration_time_entry_name] is not None: + kwargs['calibration_time'] = calibration_records[calibration_time_entry_name] + + checked.append(record_parts[1]) + # Skip sending if dictionary is provided but all entry for the sensor was None (except MSG_ID, because that is neccesary) + if calibration_records != {} and len(kwargs) == 1: + continue + + # Store the function but do not execute it + send_data.append(partial(self.cmd_set_calibration_records_concentrate, *args, **kwargs)) + + elif group in ['ACCEL']: + # Set the arguments for the call + args = [] + kwargs = {} + accel_x_offset_entry_name = f'{group}__{dd_enum_repository.CalibRecordAccelerometerFields.ACCEL_X_OFFSET.name}' + accel_y_offset_entry_name = f'{group}__{dd_enum_repository.CalibRecordAccelerometerFields.ACCEL_Y_OFFSET.name}' + accel_z_offset_entry_name = f'{group}__{dd_enum_repository.CalibRecordAccelerometerFields.ACCEL_Z_OFFSET.name}' + calibration_time_entry_name = f'{group}__{dd_enum_repository.CalibRecordAccelerometerFields.CALIBRATION_TIME.name}' + + kwargs['msg_id'] = msg_id_pairing[group] + if accel_x_offset_entry_name in calibration_records and calibration_records[accel_x_offset_entry_name] is not None: + kwargs['accel_x_offset'] = calibration_records[accel_x_offset_entry_name] + + if accel_y_offset_entry_name in calibration_records and calibration_records[accel_y_offset_entry_name] is not None: + kwargs['accel_y_offset'] = calibration_records[accel_y_offset_entry_name] + + if accel_z_offset_entry_name in calibration_records and calibration_records[accel_z_offset_entry_name] is not None: + kwargs['accel_z_offset'] = calibration_records[accel_z_offset_entry_name] + + if calibration_time_entry_name in calibration_records and calibration_records[calibration_time_entry_name] is not None: + kwargs['calibration_time'] = calibration_records[calibration_time_entry_name] + + checked.append(group) + # Skip sending if dictionary is provided but all entry for the sensor was None (except MSG_ID, because that is neccesary) + if calibration_records != {} and len(kwargs) == 1: + continue + + # Store the function but do not execute it + send_data.append(partial(self.cmd_set_calibration_records_accelerometer, *args, **kwargs)) + + elif group in ['BLOOD_LEAK']: + # Set the arguments for the call + args = [] + kwargs = {} + set_point_entry_name = f'{group}__{dd_enum_repository.CalibRecordBloodLeakFields.SET_POINT.name}' + calibration_time_entry_name = f'{group}__{dd_enum_repository.CalibRecordBloodLeakFields.CALIBRATION_TIME.name}' + + kwargs['msg_id'] = msg_id_pairing[group] + if set_point_entry_name in calibration_records and calibration_records[set_point_entry_name] is not None: + kwargs['set_point'] = calibration_records[set_point_entry_name] + + if calibration_time_entry_name in calibration_records and calibration_records[calibration_time_entry_name] is not None: + kwargs['calibration_time'] = calibration_records[calibration_time_entry_name] + + checked.append(group) + # Skip sending if dictionary is provided but all entry for the sensor was None (except MSG_ID, because that is neccesary) + if calibration_records != {} and len(kwargs) == 1: + continue + + # Store the function but do not execute it + send_data.append(partial(self.cmd_set_calibration_records_blood_leak, *args, **kwargs)) + # Execute the stored functions one by one # Remove the ones that got 1 (successfully recieved) as response # Retry the ones that are failed 2 more times @@ -733,47 +832,34 @@ """ # Make a dictionary to store all the send functions for later send send_data = [] - total_payload = b'' for record_enum in dd_enum_repository.InstitutionalRecordFields: # Set the enum_id to identify which parameter is being sent U08 - 1 byte - 0->255 !! payload = byte_to_bytearray(record_enum.value) - if record_enum == dd_enum_repository.InstitutionalRecordFields.NUM_OF_INSTITUTIONAL_RECORD_FIELDS: + if record_enum in [dd_enum_repository.InstitutionalRecordFields.CRC, dd_enum_repository.InstitutionalRecordFields.NUM_OF_INSTITUTIONAL_RECORD_FIELDS]: # Skip the Number of fields continue - - elif record_enum == dd_enum_repository.InstitutionalRecordFields.CRC: - # If field is CRC, skip the reading, crc will be calculated - pass - - elif record_enum.name in institutional_records and institutional_records[record_enum.name] is not None: - # If record present in the dict and value is not None - value = institutional_records[record_enum.name] - - else: + elif institutional_records == {}: # Set default values if it's missing from the provided dictionary if record_enum.datatype() in [DataTypes.U32, DataTypes.BOOL, DataTypes.S32, DataTypes.U16, DataTypes.U08, DataTypes.BOOL_U08]: value = 0 elif record_enum.datatype() in [DataTypes.F32]: value = 0.0 + elif record_enum.name in institutional_records and institutional_records[record_enum.name] is not None: + # If record present in the dict and value is not None + value = institutional_records[record_enum.name] + else: + # If record is not present in the dict or it doesn't have value, skip sending it + continue - # Calculate the CRC for the total institutional record (should be the last message) - if record_enum == dd_enum_repository.InstitutionalRecordFields.CRC: - payload += unsigned_short_to_bytearray(self.crc16(total_payload)) - - # Else just send the data - elif record_enum.datatype() in [DataTypes.U32, DataTypes.BOOL, DataTypes.S32]: + if record_enum.datatype() in [DataTypes.U32, DataTypes.BOOL, DataTypes.S32]: payload += integer_to_bytearray(value) - total_payload += integer_to_bytearray(value) elif record_enum.datatype() in [DataTypes.F32]: payload += float_to_bytearray(value) - total_payload += float_to_bytearray(value) elif record_enum.datatype() in [DataTypes.U16]: payload += unsigned_short_to_bytearray(value) - total_payload += unsigned_short_to_bytearray(value) elif record_enum.datatype() in [DataTypes.U08, DataTypes.BOOL_U08]: payload += byte_to_bytearray(value) - total_payload += byte_to_bytearray(value) send_data.append(partial(cmd_generic_override, payload = payload,