Index: dialin/squish/crc.py =================================================================== diff -u -r10bd08a612562df62c94e3d304f17ba24f4275a6 -r2a6715ec861c15619188cbcf9afff957eec819c4 --- dialin/squish/crc.py (.../crc.py) (revision 10bd08a612562df62c94e3d304f17ba24f4275a6) +++ dialin/squish/crc.py (.../crc.py) (revision 2a6715ec861c15619188cbcf9afff957eec819c4) @@ -7,8 +7,8 @@ # # @file crc.py # -# @author (last) Peter Lucia -# @date (last) 09-Jul-2020 +# @author (last) Behrouz NematiPour +# @date (last) 07-Oct-2020 # @author (original) Peter Lucia # @date (original) 09-Jul-2020 # @@ -34,6 +34,11 @@ ) def crc8(vData): + """ + generates crc8 for the data vData + :param vData: byte of data + :return: (int) the crc code + """ crc = 0 l = len(vData) i = 0 @@ -45,6 +50,12 @@ def calcCRC8(vString, vDelimiter='.'): + """ + calculates crc8 for each character in string vString + :param vString: (str) the bytes of data + :param vDelimiter: (character) the string delimiter + :return: the hex formatted crc of the given string + """ str = vString.replace(vDelimiter, '') ba = bytearray.fromhex(str) x = '{:02X}'.format(crc8(ba), 'x') Index: dialin/squish/denaliMessages.py =================================================================== diff -u -ra8f0a0fbc13346a19e7cfdaf50a93a46d3194dc4 -r2a6715ec861c15619188cbcf9afff957eec819c4 --- dialin/squish/denaliMessages.py (.../denaliMessages.py) (revision a8f0a0fbc13346a19e7cfdaf50a93a46d3194dc4) +++ dialin/squish/denaliMessages.py (.../denaliMessages.py) (revision 2a6715ec861c15619188cbcf9afff957eec819c4) @@ -7,8 +7,8 @@ # # @file denaliMessages.py # -# @author (last) Peter Lucia -# @date (last) 09-Jul-2020 +# @author (last) Behrouz NematiPour +# @date (last) 20-Oct-2020 # @author (original) Peter Lucia # @date (original) 09-Jul-2020 # @@ -21,7 +21,24 @@ from dialin.squish import messageBuilder +class txStates: + # Saline states + SALINE_BOLUS_STATE_IDLE = 0 # No saline bolus delivery is in progress + SALINE_BOLUS_STATE_WAIT_FOR_PUMPS_STOP = 1 # Wait for pumps to stop before starting bolus + SALINE_BOLUS_STATE_IN_PROGRESS = 2 # A saline bolus delivery is in progress + SALINE_BOLUS_STATE_MAX_DELIVERED = 3 # Maximum saline bolus volume reached - no more saline bolus deliveries allowed + + # UF states + # UI only cares about the actual state and _NOT could be any other state + UF_PAUSED_STATE_NOT = 0 + UF_PAUSED_STATE = 1 + + # Sub Mode + # UI only cares about the actual state and _NOT could be any other state + TREATMENT_DIALYSIS_STATE_NOT = 0 + TREATMENT_DIALYSIS_STATE = 1 + class EResponse: Rejected = 0 Accepted = 1 @@ -60,85 +77,148 @@ AdjustDurationRsp = 27 AdjustUltrafiltrationStateReq = 16 # Req and Rsp are the same in this specific message - AdjustUltrafiltrationEditReq = 17 AdjustUltrafiltrationEditRsp = 19 - AdjustUltrafiltrationConfirmReq = 21 AdjustUltrafiltrationConfirmRsp = 46 - TreatmentRanges = 26 String = 65279 - Acknow = 65535 - AcknowGeneric = 0 # Generic Acknowledgment is not a unique message ID and inherits its Id from the actual message. Zero is a placeholder def send_acknowledge_HD(): + """ + the acknowledge from HD + :return: none + """ subprocess.call(['cansend', 'can0', '020#A5.01.00.FF.FF.00.19.00']) + def send_acknowledge_UI(): + """ + the acknowledge from UI + :return: none + """ subprocess.call(['cansend', 'can0', '100#A5.01.00.FF.FF.00.19.00']) + def send_CheckIn_DG(): + """ + check-in (keep alive) message from DG + :return: none + """ subprocess.call(['cansend', 'can0', '010#A5.01.00.06.00.00.76.00']) - + + def show_PowerOffDialog(): + """ + the message from HD to UI to show the power off dialog + :return: none + """ subprocess.call(['cansend', 'can0', '020#A5.01.00.01.00.01.00.38']) + def hide_PowerOffDialog(): + """ + the message from HD to UI to hide the power off dialog + :return: none + """ subprocess.call(['cansend', 'can0', '020#A5.01.00.01.00.01.01.09']) + def show_PowerOffNotificationDialog(): + """ + the message from HD to UI to shew the shutting down notipication box + :return: none + """ subprocess.call(['cansend', 'can0', '040#A5.01.00.0E.00.00.24.00']) + def show_PowerOffRejectionDialog(): + """ + the message from HD to UI to show the power off dialog + :return: none + """ subprocess.call(['cansend', 'can0', '020#A5.01.00.01.00.01.02.5A']) -################################################################################################## -# After each multi-frame message put a 100ms sleep, time.sleep(0.1) # -# it seems it's needed otherwise the test will check a value which has not been received yet. # -################################################################################################## + def waitForMessageToBeSent(): + """ + After each multi-frame message put a 100ms sleep, time.sleep(0.1) # + it seems it's needed otherwise the test will check a value which has not been received yet. # + :return: none + """ time.sleep(0.050) # 50ms -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + def buildHDDebugText(vText): + """ + the debug text message from HD builder method + :param vText: (str) the debug text + :return: none + """ len = 40 txt = messageBuilder.textToByte(vText, len) # + 1 null term msg = messageBuilder.buildMessage( GuiActionType.HDDebugText, 1 * (len + 1), False, txt) return messageBuilder.toFrames(msg) -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + def setHDDebugText (vText): + """ + the debug text message from HD setter/sender method + :param vText: (str) the debug text + :return: none + """ frames = buildHDDebugText(vText) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) waitForMessageToBeSent() -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + def buildDGDebugText(vText): + """ + the debug text message from DG builder method + :param vText: (str) the debug text + :return: none + """ len = 40 txt = messageBuilder.textToByte(vText, len) # + 1 null term msg = messageBuilder.buildMessage( GuiActionType.DGDebugText, 1 * (len + 1), False, txt) return messageBuilder.toFrames(msg) -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + def setDGDebugText (vText): + """ + the debug text message from DG setter/sender method + :param vText: (str) the debug text + :return: none + """ frames = buildDGDebugText(vText) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: subprocess.call(['cansend', 'can0', '070#{}'.format(frame)]) waitForMessageToBeSent() -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + def buildSetTreatmentParamRanges(vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate): + """ + the Treatment adjustment param ranges data message builder method + | MSG | CAN ID | Box | Type | Ack | Src | Dst | Description | #1:(U32) | #2:(U32) | #3:(F32) | #4:(F32) | #5:(U32) | #6:(U32) | + |:----:|:------:|:---:|:------:|:---:|:---:|:---:|:-----------: |:--: |:--: |:--: |:--: |:--: |:--: | + |0x1A00| 0x020 | 6 | 1/60 Hz| Y | HD | UI | Treatment adjustment param ranges Data | \ref Data::mDuration_Min | \ref Data::mDuration_Max | \ref Data::mUltrafiltration_Volume_Min | \ref Data::mUltrafiltration_Volume_Max | \ref Data::mDialysate_Flow_Min | \ref Data::mDialysate_Flow_Max | + :param vMinTreatmentDuration: (int) Min Treatment Duration + :param vMaxTreatmentDuration: (int) Max Treatment Duration + :param vMinUFVolume: (float) Min UF Volume + :param vMaxUFVolume: (float) Max UF Volume + :param vMinDialysateFlowRate: (int) Min Dialysate Flow Rate + :param vMaxDialysateFlowRate: (int) Max Dialysate Flow Rate + :return: (str) built message frame(s) + """ msg = messageBuilder.buildMessage(GuiActionType.TreatmentRanges, 4 * 6, True, utils.toI32(vMinTreatmentDuration), utils.toI32(vMaxTreatmentDuration), @@ -151,6 +231,16 @@ def setTreatmentParamRanges(vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate): + """ + the Treatment adjustment param ranges data message setter/sender method + :param vMinTreatmentDuration: (int) Min Treatment Duration + :param vMaxTreatmentDuration: (int) Max Treatment Duration + :param vMinUFVolume: (float) Min UF Volume + :param vMaxUFVolume: (float) Max UF Volume + :param vMinDialysateFlowRate: (int) Min Dialysate Flow Rate + :param vMaxDialysateFlowRate: (int) Max Dialysate Flow Rate + :return: none + """ frames = buildSetTreatmentParamRanges(vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: @@ -159,6 +249,20 @@ def buildSetTreatmentBloodFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + """ + the Blood Flow Data message builder method + | MSG | CAN ID | Box | Type | Ack | Src | Dst | Description | #1:(S32) | #2:(F32) | #3:(F32) | #4:(F32) | #5:(F32) | #6:(F32) | #7:(F32) | + |:----:|:------:|:---:|:------:|:---:|:---:|:---:|:-----------: |:--: |:--: |:--: |:--: |:--: |:--: |:--: | + |0x0500| 0x040 | 7 | 1 Hz | N | HD | All | Blood Flow Data | \ref Data::mFlowSetPoint | \ref Data::mMeasuredFlow | \ref Data::mRotorSpeed | \ref Data::mMotorSpeed | \ref Data::mMotorCtlSpeed | \ref Data::mMotorCtlCurrent | \ref Data::mPWMDutyCycle | + :param vFlowSetPt: (signed int) Flow Set Point + :param vMeasFlow: (float) Measured Flow + :param vRotSpd: (float) Rot Speed + :param vMotSpd: (float) Motor Speed + :param vMCSpd: (float) MC Speed + :param vMCCurr: (float) MC Current + :param vPWM: (float) PWM + :return: (str) built message frame(s) + """ msg = messageBuilder.buildMessage(GuiActionType.BloodFlow, 4 * 7, False, utils.toI32(vFlowSetPt ), utils.toF32(vMeasFlow ), @@ -172,6 +276,17 @@ def setTreatmentBloodFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + """ + the Blood Flow Data message setter/sender method + :param vFlowSetPt: (signed int) Flow Set Point + :param vMeasFlow: (float) Measured Flow + :param vRotSpd: (float) Rot Speed + :param vMotSpd: (float) Motor Speed + :param vMCSpd: (float) MC Speed + :param vMCCurr: (float) MC Current + :param vPWM: (float) PWM + :return: none + """ frames = buildSetTreatmentBloodFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: @@ -180,6 +295,20 @@ def buildSetTreatmentDialysateFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + """ + the Dialysate Flow Data message builder method + | MSG | CAN ID | Box | Type | Ack | Src | Dst | Description | #1:(S32) | #2:(F32) | #3:(F32) | #4:(F32) | #5:(F32) | #6:(F32) | #7:(F32) | + |:----:|:------:|:---:|:------:|:---:|:---:|:---:|:-----------: |:--: |:--: |:--: |:--: |:--: |:--: |:--: | + |0x0800| 0x040 | 7 | 1 Hz | N | HD | All | Dialysate Flow Data | mFlowSetPoint | mMeasuredFlow | mRotorSpeed | mMotorSpeed | mMotorCtlSpeed | mMotorCtlCurrent | mPWMDutyCycle | + :param vFlowSetPt: (signed int) Flow Set Point + :param vMeasFlow: (float) Measured Flow + :param vRotSpd: (float) Rot Speed + :param vMotSpd: (float) Motor Speed + :param vMCSpd: (float) MC Speed + :param vMCCurr: (float) MC Current + :param vPWM: (float) PWM + :return: (str) built message frame(s) + """ msg = messageBuilder.buildMessage(GuiActionType.DialysateInletFlow, 4 * 7, False, utils.toI32(vFlowSetPt), utils.toF32(vMeasFlow), @@ -193,6 +322,17 @@ def setTreatmentDialysateFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + """ + the Dialysate Flow Data message setter/sender method + :param vFlowSetPt: (signed int) Flow Set Point + :param vMeasFlow: (float) Measured Flow + :param vRotSpd: (float) Rot Speed + :param vMotSpd: (float) Motor Speed + :param vMCSpd: (float) MC Speed + :param vMCCurr: (float) MC Current + :param vPWM: (float) PWM + :return: none + """ frames = buildSetTreatmentDialysateFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: @@ -201,6 +341,17 @@ def buildTreatmentAdjustBloodDialysateResponse(vAccepted, vReason, vBloodRate, vDialysate): + """ + the Blood/dialysate rate change Response message builder method + | MSG | CAN ID | Box | Type | Ack | Src | Dst | Description | #1:(U32) | #2:(U32) | #3:(U32) | #4:(U32) | + |:----:|:------:|:---:|:------:|:---:|:---:|:---:|:-----------: |:--: |:--: |:--: |:--: | + |0x1800| 0x020 | 6 | Rsp | Y | HD | UI | Blood/dialysate rate change Response | \ref Data::mAccepted | \ref Data::mReason | \ref Data::mBloodRate | \ref Data::mDialysateRate | + :param vAccepted: (int) boolean accept/reject response + :param vReason: (int) rejection reason + :param vBloodRate: (int) Blood Flow Rate + :param vDialysate: (int) Dialysate Flow Rate + :return: (str) built message frame(s) + """ msg = messageBuilder.buildMessage(GuiActionType.AdjustBloodDialysateRsp, 4 * 4, True, utils.toI32(vAccepted), utils.toI32(vReason), @@ -211,6 +362,14 @@ def sendTreatmentAdjustBloodDialysateResponse(vAccepted, vReason, vBloodRate, vDialysate): + """ + the Blood/dialysate rate change Response message setter/sender method + :param vAccepted: (int) boolean accept/reject response + :param vReason: (int) rejection reason + :param vBloodRate: (int) Blood Flow Rate + :param vDialysate: (int) Dialysate Flow Rate + :return: none + """ frames = buildTreatmentAdjustBloodDialysateResponse(vAccepted, vReason, vBloodRate, vDialysate) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: @@ -219,6 +378,17 @@ def buildTreatmentAdjustDurationResponse(vAccepted, vReason, vDuration, vUltrafiltration): + """ + the Treatment Duration change Response message builder method + | MSG | CAN ID | Box | Type | Ack | Src | Dst | Description | #1:(U32) | #2:(U32) | #3:(U32) | #5:(F32) | + |:----:|:------:|:---:|:------:|:---:|:---:|:---:|:-----------: |:--: |:--: |:--: |:--: | + |0x1B00| 0x020 | 6 | Rsp | Y | HD | UI | Treatment Duration change Response | \ref Data::mAccepted | \ref Data::mReason | \ref Data::mDuration | \ref Data::mUFVolume | + :param vAccepted: (int) boolean accept/reject response + :param vReason: (int) rejection reason + :param vDuration: (int) Treatment Duration + :param vUltrafiltration: (float) Ultrafiltration Volume + :return: (str) built message frame(s) + """ msg = messageBuilder.buildMessage(GuiActionType.AdjustDurationRsp, 4 * 4, True, utils.toI32(vAccepted), utils.toI32(vReason), @@ -229,6 +399,14 @@ def sendTreatmentAdjustDurationResponse(vAccepted, vReason, vDuration, vUltrafiltration): + """ + the Treatment Duration change Response message setter/sender method + :param vAccepted: (int) boolean accept/reject response + :param vReason: (int) rejection reason + :param vDuration: (int) Treatment Duration + :param vUltrafiltration: (float) Ultrafiltration Volume + :return: none + """ frames = buildTreatmentAdjustDurationResponse(vAccepted, vReason, vDuration, vUltrafiltration) frames = messageBuilder.toCandumpFormat(frames) for frame in frames: @@ -237,13 +415,27 @@ def buildTreatmentAdjustUltrafiltrationStateResponse(vState): + """ + the Treatment ultrafiltration adjustment response message builder method + | MSG | CAN ID | M.Box | Type | Ack | Src | Dest | Description | #1:(U08) | + |:----:|:------:|:-----:|:----:|:---:|:---:|:----:|:-----------: |:--: | + |0x1000| 0x100 | 9 | Rsp | N | HD | UI | Generic response ACK/NAK | mAccepted | + :param vState: (-128f', vValue))[0],'X') def partition(vString, vPart, vRightDirection=True): """ - - @param vString: - @param vPart: - @param vRightDirection: - @return: + splits the given string into sections of vPart long + and puts the sections from left to right if vRightDirection is False + and puts the sections from right to left if vRightDirection is True + after the split is done + :param vString: (str) the given string + :param vPart: (int) length of the section + :param vRightDirection: (bool) order of sections in the output list + :return: (list) the section of the string vString in list """ return [vString[i: i + vPart] for i in range(0, len(vString), vPart)][::-1 if vRightDirection else 1] def padding(vString, vLen): """ - - @param vString: - @param vLen: - @return: + added zero at the right side of the string to be of length of vLen + :param vString: (str) the string to add trainling zero to + :param vLen: (int) the entire length of the string + :return: (str) padded string """ lStr = len(vString) lPad = int(lStr / vLen) * vLen + ( vLen * (1 if lStr % vLen else 0) ) return vString.ljust(lPad, "0") def tstStart(vTestName): """ - - @return: + test case start print out with time + :param vTestName: (str) name of the test case + :return: none - prints out on the console """ print(time.strftime("%H:%M:%S Start", time.localtime()) + " - " + vTestName) def tstDone(): """ - - @return: + test case end print out with time + :return: none - prints out on the console """ print(time.strftime("%H:%M:%S Done ", time.localtime())) def l2ml(vValue): """ - - @param vValue: - @return: + converts liter to mili liter + :param (int) vValue: the value in liter. + :return: (int) vValue converted to miliiliter. """ return int(round (vValue, 3) * 1000) def ml2l(vValue): """ - - @param vValue: - @return: + converts mili liter to liter + :param (int) vValue: the value in miliiliter. + :return: (int) vValue converted to liter. """ return vValue / 1000 - +