Index: dialin/dg/calibration_record.py =================================================================== diff -u -r066f421409c3a4ba71521c9da2907a26087f27c1 -ree278f5a643613b8e7acbc44c3e70ead692cd0f0 --- dialin/dg/calibration_record.py (.../calibration_record.py) (revision 066f421409c3a4ba71521c9da2907a26087f27c1) +++ dialin/dg/calibration_record.py (.../calibration_record.py) (revision ee278f5a643613b8e7acbc44c3e70ead692cd0f0) @@ -17,11 +17,12 @@ import time from collections import OrderedDict from logging import Logger +from time import sleep from ..common.msg_defs import MsgIds, MsgFieldPositions from ..protocols.CAN import DenaliMessage, DenaliChannels from ..utils.base import AbstractSubSystem, publish -from ..utils.nv_ops_utils import NVOpsUtils +from ..utils.nv_ops_utils import NVOpsUtils, Observer class DGCalibrationNVRecord(AbstractSubSystem): @@ -55,6 +56,9 @@ _PAYLOAD_TRANSFER_DELAY_S = 0.2 _DIALIN_RECORD_UPDATE_DELAY_S = 0.2 + _FIRMWARE_STACK_NAME = 'DG' + _CAL_RECORD_TAB_NAME = 'Calibration Record' + def __init__(self, can_interface, logger: Logger): """ @@ -92,6 +96,28 @@ return status + def cmd_get_dg_calibration_record_report(self, report_destination: str = None): + """ + Handles getting DG calibration_record record from firmware and writing it to excel. + + @param report_destination: (str) the destination that the report should be written to + + @return: none + """ + # Prepare the excel report + self._utilities.prepare_excel_report(self._FIRMWARE_STACK_NAME, self._CAL_RECORD_TAB_NAME, + report_destination, protect_sheet=True) + # Request the DG calibration record and set and observer class to callback when the calibration record is read + # back + self.cmd_request_dg_calibration_record() + observer = Observer("dg_calibration_record") + # Attach the observer to the list + self.attach(observer) + while not observer.received: + sleep(0.1) + # Pass the DG calibration record to the function to write the excel + self._utilities.write_fw_record_to_excel(self.dg_calibration_record) + def cmd_request_dg_calibration_record(self) -> bool: """ Handles getting DG calibration_record record from firmware. @@ -169,6 +195,23 @@ """ self.logger.debug("Received a complete dg calibration record.") + def cmd_set_dg_calibration_excel_to_fw(self, report_address: str): + # TODO header + # Request the DG calibration record and set and observer class to callback when the calibration record is read + # back + self.cmd_request_dg_calibration_record() + observer = Observer("dg_calibration_record") + # Attach the observer to the list + self.attach(observer) + while not observer.received: + sleep(0.1) + print(self.dg_calibration_record) + self._utilities.write_excel_record_to_fw_record(self.dg_calibration_record, report_address, + self._CAL_RECORD_TAB_NAME) + print(self.dg_calibration_record) + + self.cmd_set_dg_calibration_record(self.dg_calibration_record) + def cmd_set_dg_calibration_record(self, previous_record: OrderedDict) -> bool: """ Handles updating the DG calibration record with the newest calibration_record data of a hardware and @@ -279,7 +322,7 @@ @return: flow sensors hardware group dictionary and the byte size of this hardware group """ - hardware_names = ['ro_flow_sensor', 'dialysate_flow_sensor', 'reserved_2', 'reserved_3'] + hardware_names = ['ro_flow_sensor', 'dialysate_flow_sensor', 'reserved_1', 'reserved_2'] group_byte_size = 0 group_name = 'flow_sensors' hardware_group = OrderedDict({group_name: OrderedDict()}) Index: dialin/utils/excel_ops.py =================================================================== diff -u -r4ec12397809c5820ee654aaffe5924e67a79a072 -ree278f5a643613b8e7acbc44c3e70ead692cd0f0 --- dialin/utils/excel_ops.py (.../excel_ops.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) +++ dialin/utils/excel_ops.py (.../excel_ops.py) (revision ee278f5a643613b8e7acbc44c3e70ead692cd0f0) @@ -154,6 +154,7 @@ # To freeze row 1, make the cell is not row 1, that's why A2 was chosen active_sheet.freeze_panes = 'A2' + # Enforce the cell protection whether it is a False or True active_sheet.cell(row, column).protection = Protection(locked=protect_cell) Index: dialin/utils/nv_ops_utils.py =================================================================== diff -u -r4ec12397809c5820ee654aaffe5924e67a79a072 -ree278f5a643613b8e7acbc44c3e70ead692cd0f0 --- dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) +++ dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision ee278f5a643613b8e7acbc44c3e70ead692cd0f0) @@ -106,6 +106,10 @@ _SW_CONFIGS_TITLE_COL = 'SW Configurations' _SW_CONFIGS_VALUE_COL = 'Status' _SW_CONFIGS_REPORT_NAME = 'SW-Configs' + _CAL_TIME_NAME = 'cal_time' + _NEW_CAL_TIME_SIGNAL = 'new' + _CRC_NAME = 'crc' + _PADDING_GROUP_NAME = 'padding' def __init__(self, logger: Logger): """ @@ -206,44 +210,54 @@ # Setup worksheet and create the current tab setup_excel_worksheet(self._excel_workbook, self._record_name, protection=protect_sheet) - def write_fw_record_to_excel(self, calibration_record: dict): + def write_fw_record_to_excel(self, calibration_record: OrderedDict): """ Writes a calibration record to excel @param calibration_record: (dict) the record to write to excel @return: None """ try: row = 1 + # Let's say the calibration record is: + # TODO make this + # This loop gets the first set of keys of the calibration record for group in calibration_record.keys(): start_row = row start_col = 1 col = 1 + # TODo add comment here if isinstance(calibration_record[group], dict): - - write_to_excel(self._excel_workbook, self._record_name, row, col, - group, bold=True, max_col_len=len(group)) - + # Write the data to excel + write_to_excel(self._excel_workbook, self._record_name, row, col, group, bold=True, + max_col_len=len(group), protect_cell=True) + # Get the list of the hardware and write them to excel (i.e. list of pressure sensors) for hardware in calibration_record[group].keys(): list_of_keys = list(calibration_record[group].keys()) col = 2 - write_to_excel(self._excel_workbook, self._record_name, row, col, hardware) + write_to_excel(self._excel_workbook, self._record_name, row, col, hardware, protect_cell=True) col += 1 - + # If the list of the sensor hardware is a dictionary, loop through the hardware dictionary + # and write them to excel if isinstance(calibration_record[group][hardware], dict): for spec in calibration_record[group][hardware]: - + # Get the spec value from the dictionary spec_value = calibration_record[group][hardware][spec][1] - - write_to_excel(self._excel_workbook, self._record_name, row, col, spec) + write_to_excel(self._excel_workbook, self._record_name, row, col, spec, + protect_cell=True) col += 1 - write_to_excel(self._excel_workbook, self._record_name, row, col, spec_value) + # Write the value to the excel and make the cell protection to false. The actual + # calibration value should be edited + write_to_excel(self._excel_workbook, self._record_name, row, col, spec_value, + protect_cell=False) col += 1 else: + # The hardware value is not a CRC. Write it to excel spec_value = calibration_record[group][hardware][1] - write_to_excel(self._excel_workbook, self._record_name, row, col, spec_value) - + write_to_excel(self._excel_workbook, self._record_name, row, col, spec_value, + protect_cell=False) + # If all the hardware of a hardware group is written to excel, merge and center the if list_of_keys.index(hardware) == len(list_of_keys) - 1: merge_cells(self._excel_workbook, self._record_name, start_row, start_col, row, start_col) @@ -252,13 +266,67 @@ row += 1 save_report(self._excel_workbook, self._workspace_dir, self._firmware_stack) - # Signal reading is done - self._is_writing_to_excel_done = True + except Exception as e: self.logger.error("Failed to write calibration record to excel: {0}".format(e)) - def write_excel_record_to_calibration_record(self, calibration_record: dict): + def write_excel_record_to_fw_record(self, record: OrderedDict, report_address: str, record_tab: str): """ + Writes the data in the excel report to the firmware + + @param record: (dict) the record to write to firmware from excel + @param report_address: (str) the address of the excel report to get the data from + @param record_tab: (str) the name of the excel tab to get the data out (i.e. Calibration Record tab) + + @return: None + """ + try: + self._excel_workbook = load_excel_report(report_address) + row = 1 + col = 1 + # This is like + for group in record.keys(): + cell_value = get_cell_value(self._excel_workbook, record_tab, row, col) + cell_value = cell_value.lower() if isinstance(cell_value, str) else cell_value + if cell_value == group and group is not self._PADDING_GROUP_NAME: + if isinstance(record[group], dict): + col = 4 + for hardware in record[group].keys(): + if isinstance(record[group][hardware], dict): + for spec in record[group][hardware]: + cell_value = get_cell_value(self._excel_workbook, record_tab, row, col) + + record[group][hardware][spec][1] = cell_value + + cell_value = cell_value.lower() if isinstance(cell_value, str) else cell_value + #print(group, hardware, spec, type(cell_value), cell_value, row) + if spec == self._CAL_TIME_NAME and cell_value is None or cell_value is '' or \ + cell_value == self._NEW_CAL_TIME_SIGNAL: + + epoch = self.get_current_time_in_epoch() + date_time = self.get_current_date_time(epoch) + record[group][hardware][spec][1] = epoch + + crc = self.get_group_record_crc(record[group][hardware]) + record[group][hardware][self._CRC_NAME][1] = crc + write_to_excel(self._excel_workbook, record_tab, row, col, date_time) + write_to_excel(self._excel_workbook, record_tab, row, col + 2, crc) + self._excel_workbook.save(filename=report_address) + elif spec == self._CAL_TIME_NAME and isinstance(cell_value, str): + epoch_time = self.get_date_time_in_epoch(cell_value) + record[group][hardware][spec][1] = epoch_time + col += 2 + + row += 1 + col = 4 + col = 1 + row += 1 + + except Exception as e: + self.logger.error("Failed to load the excel record as a calibration record: {0}".format(e)) + + def write_excel_record_to_calibration_record_old(self, calibration_record: dict): + """ Writes an excel record to a calibration record @param calibration_record: (dict) the calibration record to write @@ -329,22 +397,6 @@ except Exception as e: self.logger.error("Failed to load the excel record as a calibration record: {0}".format(e)) - def get_writing_to_excel_status(self): # TODO remove - """ - Publicly accessible function to get the reading status - - @return True if reading to firmware records to excel is done otherwise False - """ - - return self._is_writing_to_excel_done - - def get_reading_record_status(self): # TODO remove - """ - Gets the reading record status - @return: True if done, false otherwise - """ - return self._is_read_done - @staticmethod def get_processed_characters(record: list) -> bytearray: """ @@ -432,15 +484,6 @@ return crc_value @staticmethod - def get_current_time_in_epoch(): - """ - Returns the current date and time in epoch in integer format. This is a static method. - - @return: (int) data and time in epoch - """ - return int(datetime.datetime.now().timestamp()) - - @staticmethod def get_current_date_time(epoch: int): """ Returns the current date and time from an epoch time @@ -451,6 +494,15 @@ return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(epoch)) @staticmethod + def get_current_time_in_epoch(): + """ + Returns the current date and time in epoch in integer format. This is a static method. + + @return: (int) data and time in epoch + """ + return int(datetime.datetime.now().timestamp()) + + @staticmethod def get_date_time_in_epoch(data_time: str): """ Returns the date time in epoch Index: tests/peter/test_dg_records.py =================================================================== diff -u -r4ec12397809c5820ee654aaffe5924e67a79a072 -ree278f5a643613b8e7acbc44c3e70ead692cd0f0 --- tests/peter/test_dg_records.py (.../test_dg_records.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) +++ tests/peter/test_dg_records.py (.../test_dg_records.py) (revision ee278f5a643613b8e7acbc44c3e70ead692cd0f0) @@ -231,29 +231,29 @@ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppo"]) """ - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["gain"][1] = 1.058527274 - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["offset"][1] = -127.3129791 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["gain"][1] = 0.971227 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["offset"][1] = -13.7163 dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]) - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["gain"][1] = 0.988036262 - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["offset"][1] = -116.6615859 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["gain"][1] = 0.980796 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["offset"][1] = -34.9747 dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]) - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["gain"][1] = 0.992981302 - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["offset"][1] = -49.84277209 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["gain"][1] = 1.006039 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["offset"][1] = 26.75222 dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]) - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["gain"][1] = 0.988057943 - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["offset"][1] = -1.127196988 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["gain"][1] = 1.01493 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["offset"][1] = 133.4312 dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["crc"][1] = \ @@ -348,11 +348,19 @@ dg.scheduled_runs_record.cmd_set_dg_scheduled_runs_record(dg.scheduled_runs_record.dg_scheduled_runs_record) +def test_dg_excel_report(): + dg = DG(log_level="DEBUG") + if dg.cmd_log_in_to_dg(): + #dg.calibration_record.cmd_get_dg_calibration_record_report() + dg.calibration_record.cmd_set_dg_calibration_excel_to_fw('/home/fw/projects/DG_NV_Records/2022-02-09-DG-Record.xlsx') + + if __name__ == "__main__": #test_dg_reset_record() # test_dg_sw_config_record() - test_dg_calibration_record() + #test_dg_calibration_record() # test_dg_service_record() #test_dg_system_record() # test_dg_scheduled_runs_record() + test_dg_excel_report() Index: tests/peter/test_hd_records.py =================================================================== diff -u -r4ec12397809c5820ee654aaffe5924e67a79a072 -ree278f5a643613b8e7acbc44c3e70ead692cd0f0 --- tests/peter/test_hd_records.py (.../test_hd_records.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) +++ tests/peter/test_hd_records.py (.../test_hd_records.py) (revision ee278f5a643613b8e7acbc44c3e70ead692cd0f0) @@ -142,8 +142,8 @@ #hd.sw_configs.cmd_reset_hd_sw_config_record() #sleep(2) - #hd.sw_configs.cmd_get_hd_sw_config_record() - hd.sw_configs.cmd_update_hd_sw_config_record('/home/fw/projects/HD_NV_Records/2022-02-08-HD-SW-CONFIGS-Record.xlsx') + hd.sw_configs.cmd_get_hd_sw_config_record() + #hd.sw_configs.cmd_update_hd_sw_config_record('/home/fw/projects/HD_NV_Records/2022-02-08-HD-SW-CONFIGS-Record.xlsx') #dg.sw_configs.cmd_set_dg_sw_config_record('/home/fw/DG_NV_Records/2022-01-22-SW-CONFIGS-Record.xlsx') """