Index: dialin/squish/crc.py =================================================================== diff -u --- dialin/squish/crc.py (revision 0) +++ dialin/squish/crc.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file crc.py +# date 2020/04/08 +# author Behrouz NematiPour +# + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +crc8_table = ( + 0, 49, 98, 83, 196, 245, 166, 151, 185, 136, 219, 234, 125, 76, 31, 46, + 67, 114, 33, 16, 135, 182, 229, 212, 250, 203, 152, 169, 62, 15, 92, 109, + 134, 183, 228, 213, 66, 115, 32, 17, 63, 14, 93, 108, 251, 202, 153, 168, + 197, 244, 167, 150, 1, 48, 99, 82, 124, 77, 30, 47, 184, 137, 218, 235, + 61, 12, 95, 110, 249, 200, 155, 170, 132, 181, 230, 215, 64, 113, 34, 19, + 126, 79, 28, 45, 186, 139, 216, 233, 199, 246, 165, 148, 3, 50, 97, 80, + 187, 138, 217, 232, 127, 78, 29, 44, 2, 51, 96, 81, 198, 247, 164, 149, + 248, 201, 154, 171, 60, 13, 94, 111, 65, 112, 35, 18, 133, 180, 231, 214, + 122, 75, 24, 41, 190, 143, 220, 237, 195, 242, 161, 144, 7, 54, 101, 84, + 57, 8, 91, 106, 253, 204, 159, 174, 128, 177, 226, 211, 68, 117, 38, 23, + 252, 205, 158, 175, 56, 9, 90, 107, 69, 116, 39, 22, 129, 176, 227, 210, + 191, 142, 221, 236, 123, 74, 25, 40, 6, 55, 100, 85, 194, 243, 160, 145, + 71, 118, 37, 20, 131, 178, 225, 208, 254, 207, 156, 173, 58, 11, 88, 105, + 4, 53, 102, 87, 192, 241, 162, 147, 189, 140, 223, 238, 121, 72, 27, 42, + 193, 240, 163, 146, 5, 52, 103, 86, 120, 73, 26, 43, 188, 141, 222, 239, + 130, 179, 224, 209, 70, 119, 36, 21, 59, 10, 89, 104, 255, 206, 157, 172 +) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def crc8(vData): + crc = 0 + l = len(vData) + i = 0 + while l > 0: + crc = crc8_table[vData[i] ^ crc ] + l = l - 1 + i = i + 1 + return crc + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def calcCRC8(vString, vDelimiter = '.'): + str = vString.replace(vDelimiter, '') + ba = bytearray.fromhex(str) + x = '{:02X}'.format(crc8(ba), 'x') + return x Index: dialin/squish/denaliMessages.py =================================================================== diff -u --- dialin/squish/denaliMessages.py (revision 0) +++ dialin/squish/denaliMessages.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,458 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file denaliMessages.py +# date 2020/04/08 +# author Behrouz NematiPour +# + +import time +import subprocess +import utils +import messageBuilder + +#from enum import IntEnum + +class EResponse: + Rejected = 0 + Accepted = 1 + +class GuiActionType: + Unknown = 0 + PowerOff = 1 + KeepAlive = 7 + BloodFlow = 5 + DialysateInletFlow = 8 + DialysateOutletFlow = 11 + TreatmentTime = 13 + PowerOffBroadcast = 14 + + AlarmStatus = 2 + AlarmTriggered = 3 + AlarmCleared = 4 + + PressureOcclusion = 9 + LoadCellReadings = 12 + TemperatureSensors = 45 + CanBUSFaultCount = 2457 + + + AdjustBloodDialysateReq = 23 + AdjustBloodDialysateRsp = 24 + + AdjustDurationReq = 22 + 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(): + subprocess.call(['cansend', 'can0', '020#A5.01.00.FF.FF.00.19.00']) + +def send_acknowledge_UI(): + subprocess.call(['cansend', 'can0', '100#A5.01.00.FF.FF.00.19.00']) + +def show_PowerOffDialog(): + subprocess.call(['cansend', 'can0', '020#A5.01.00.01.00.01.00.38']) + +def hide_PowerOffDialog(): + subprocess.call(['cansend', 'can0', '020#A5.01.00.01.00.01.01.09']) + +def show_PowerOffNotificationDialog(): + subprocess.call(['cansend', 'can0', '040#A5.01.00.0E.00.00.24.00']) + +def show_PowerOffRejectionDialog(): + 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(): + time.sleep(0.200) # 200ms + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildSetTreatmentParamRanges(vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate): + msg = messageBuilder.buildMessage( GuiActionType.TreatmentRanges, 4 * 6, True, + utils.toI32(vMinTreatmentDuration), + utils.toI32(vMaxTreatmentDuration), + utils.toF32(vMinUFVolume ), + utils.toF32(vMaxUFVolume ), + utils.toI32(vMinDialysateFlowRate), + utils.toI32(vMaxDialysateFlowRate) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentParamRanges (vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate): + frames = buildSetTreatmentParamRanges(vMinTreatmentDuration, vMaxTreatmentDuration, vMinUFVolume, vMaxUFVolume, vMinDialysateFlowRate, vMaxDialysateFlowRate) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildSetTreatmentBloodFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + msg = messageBuilder.buildMessage( GuiActionType.BloodFlow, 4 * 7, False, + utils.toI32(vFlowSetPt ), + utils.toF32(vMeasFlow ), + utils.toF32(vRotSpd ), + utils.toF32(vMotSpd ), + utils.toF32(vMCSpd ), + utils.toF32(vMCCurr ), + utils.toF32(vPWM ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentBloodFlowRate (vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + frames = buildSetTreatmentBloodFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '040#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildSetTreatmentDialysateFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + msg = messageBuilder.buildMessage( GuiActionType.DialysateInletFlow, 4 * 7, False, + utils.toI32(vFlowSetPt ), + utils.toF32(vMeasFlow ), + utils.toF32(vRotSpd ), + utils.toF32(vMotSpd ), + utils.toF32(vMCSpd ), + utils.toF32(vMCCurr ), + utils.toF32(vPWM ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentDialysateFlowRate (vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + frames = buildSetTreatmentDialysateFlowRate(vFlowSetPt, vMeasFlow, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '040#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentAdjustBloodDialysateResponse(vAccepted, vReason, vBloodRate, vDialysate): + msg = messageBuilder.buildMessage( GuiActionType.AdjustBloodDialysateRsp, 4 * 4, True, + utils.toI32(vAccepted), + utils.toI32(vReason), + utils.toI32(vBloodRate), + utils.toI32(vDialysate) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def sendTreatmentAdjustBloodDialysateResponse (vAccepted, vReason, vBloodRate, vDialysate): + frames = buildTreatmentAdjustBloodDialysateResponse(vAccepted, vReason, vBloodRate, vDialysate) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentAdjustDurationResponse(vAccepted, vReason, vDuration, vUltrafiltration): + msg = messageBuilder.buildMessage( GuiActionType.AdjustDurationRsp, 4 * 4, True, + utils.toI32(vAccepted), + utils.toI32(vReason), + utils.toI32(vDuration), + utils.toF32(vUltrafiltration) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def sendTreatmentAdjustDurationResponse (vAccepted, vReason, vDuration, vUltrafiltration): + frames = buildTreatmentAdjustDurationResponse(vAccepted, vReason, vDuration, vUltrafiltration) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentAdjustUltrafiltrationStateResponse(vState): + msg = messageBuilder.buildMessage( GuiActionType.AdjustUltrafiltrationStateReq, 1 * 4 , False, + utils.toI32(vState) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentAdjustUltrafiltrationStateResponse(vState): + frames = buildTreatmentAdjustUltrafiltrationStateResponse(vState) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +def setTreatmentAdjustUltrafiltrationAccepted(): + setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Accepted ) + +def setTreatmentAdjustUltrafiltrationRejected(): + setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Rejected ) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# 19 0x020 6 Rsp Y HD UI UF Vol. Change Response (U32)-0=No, 1=Yes (U32) reject reason UF vol-mL (F32) Time-min (U32) Time diff (S32) UF rate-mL/min (F32) Rate diff (F32) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentAdjustUltrafiltrationEditResponse(vAccepted, vReason, vVolume, vDuration, vDurationDiff, vRate, vRateDiff, vRateOld): + msg = messageBuilder.buildMessage( GuiActionType.AdjustUltrafiltrationEditRsp, 8 * 4 , True, + utils.toI32(vAccepted ), + utils.toI32(vReason ), + utils.toF32(vVolume ), + utils.toI32(vDuration ), + utils.toI32(vDurationDiff), + utils.toF32(vRate ), + utils.toF32(vRateDiff ), + utils.toF32(vRateOld ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentAdjustUltrafiltrationEditResponse (vAccepted, vReason, vVolume, vDuration, vDurationDiff, vRate, vRateDiff, vRateOld): + frames = buildTreatmentAdjustUltrafiltrationEditResponse(vAccepted, vReason, vVolume, vDuration, vDurationDiff, vRate, vRateDiff, vRateOld) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +def setTreatmentAdjustUltrafiltrationEditRejected ( vReason ): + frames = buildTreatmentAdjustUltrafiltrationEditResponse(0, vReason, 0, 0, 0, 0, 0, 0) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# 46 0x020 6 Rsp Y HD UI UF Vol. Change Confirmation Response (U32)-0=No, 1=Yes (U32) reject reason UF vol-mL (F32) Time-min (U32) UF rate-mL/min (F32) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentAdjustUltrafiltrationConfirmResponse(vAccepted, vReason, vVolume, vDuration, vRate): + msg = messageBuilder.buildMessage( GuiActionType.AdjustUltrafiltrationConfirmRsp, 5 * 4 , True, + utils.toI32(vAccepted ), + utils.toI32(vReason ), + utils.toF32(vVolume ), + utils.toI32(vDuration ), + utils.toF32(vRate ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentAdjustUltrafiltrationConfirmResponse (vAccepted, vReason, vVolume, vDuration, vRate): + frames = buildTreatmentAdjustUltrafiltrationConfirmResponse(vAccepted, vReason, vVolume, vDuration, vRate) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +def setTreatmentAdjustUltrafiltrationConfirmRejected ( vReason ): + frames = buildTreatmentAdjustUltrafiltrationConfirmResponse(0, vReason, 0, 0, 0) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentTime(vSecsTotal, vSecsElap, vSecsRem): + msg = messageBuilder.buildMessage( GuiActionType.TreatmentTime, 3 * 4, False, + utils.toI32(vSecsTotal ), + utils.toI32(vSecsElap ), + utils.toI32(vSecsRem ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentTime (vSecsTotal, vSecsElap, vSecsRem = None): + if vSecsRem == None: + vSecsRem = vSecsTotal - vSecsElap + frames = buildTreatmentTime(vSecsTotal, vSecsElap, vSecsRem) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '040#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildSetTreatmentUltrafiltration(vRefUFVol, vMeasUFVol, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + msg = messageBuilder.buildMessage( GuiActionType.DialysateOutletFlow, 4 * 7, False, + utils.toF32(vRefUFVol ), + utils.toF32(vMeasUFVol ), + utils.toF32(vRotSpd ), + utils.toF32(vMotSpd ), + utils.toF32(vMCSpd ), + utils.toF32(vMCCurr ), + utils.toF32(vPWM ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentUltrafiltration (vRefUFVol, vMeasUFVol, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM): + frames = buildSetTreatmentUltrafiltration(vRefUFVol, vMeasUFVol, vRotSpd, vMotSpd, vMCSpd, vMCCurr, vPWM ) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '040#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildSetTreatmentPressureOcclusion(vArtPres, vVenPres, vBPOccl, vDIPOccl, vDOPOccl): + msg = messageBuilder.buildMessage( GuiActionType.PressureOcclusion, 4 * 5, False, + utils.toF32(vArtPres ), + utils.toF32(vVenPres ), + utils.toF32(vBPOccl ), + utils.toF32(vDIPOccl ), + utils.toF32(vDOPOccl ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentPressureOcclusion (vArtPres, vVenPres, vBPOccl, vDIPOccl, vDOPOccl): + frames = buildSetTreatmentPressureOcclusion(vArtPres, vVenPres, vBPOccl, vDIPOccl, vDOPOccl) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '040#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# 12 0x080 8 10 Hz N DG All Load Cell Readings Data Rs1 Prim. (F32) Rs1 Bkup (F32) Rs2 Prim. (F32) Rs2 Bkup (F32) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentLoadCellReadings(vRs1Prim, vRs1Bkup, vRs2Prim, vRs2Bkup): + msg = messageBuilder.buildMessage( GuiActionType.LoadCellReadings, 4 * 4, False, + utils.toF32(vRs1Prim), + utils.toF32(vRs1Bkup), + utils.toF32(vRs2Prim), + utils.toF32(vRs2Bkup) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentLoadCellReadings (vRs1Prim, vRs1Bkup, vRs2Prim, vRs2Bkup): + frames = buildTreatmentLoadCellReadings(vRs1Prim, vRs1Bkup, vRs2Prim, vRs2Bkup) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '080#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# 45 0x080 8 ??? Hz N DG All DG Temperature Data ??? +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildTreatmentTemperatureSensors(vInletPrimaryHeater, vOutletPrimaryHeater, vConductivitySensor1, vConductivitySensor2, vOutletRedundancy, vInletDialysate, vPrimaryHeaterThermoCouple, vPrimmerHeaterThermoCouple, vPrimaryHeaterColdJunction, vTrimmerHeaterColdJunction, vTrimaryHeaterInternal ,vTrimmerHeaterInternal): + msg = messageBuilder.buildMessage( GuiActionType.TemperatureSensors, 4 * 12, False, + utils.toF32(vInletPrimaryHeater ), + utils.toF32(vOutletPrimaryHeater ), + utils.toF32(vConductivitySensor1 ), + utils.toF32(vConductivitySensor2 ), + utils.toF32(vOutletRedundancy ), + utils.toF32(vInletDialysate ), + utils.toF32(vPrimaryHeaterThermoCouple), + utils.toF32(vPrimmerHeaterThermoCouple), + utils.toF32(vPrimaryHeaterColdJunction), + utils.toF32(vTrimmerHeaterColdJunction), + utils.toF32(vTrimaryHeaterInternal ), + utils.toF32(vTrimmerHeaterInternal ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setTreatmentTemperatureSensors (vInletPrimaryHeater, vOutletPrimaryHeater, vConductivitySensor1, vConductivitySensor2, vOutletRedundancy, vInletDialysate, vPrimaryHeaterThermoCouple, vPrimmerHeaterThermoCouple, vPrimaryHeaterColdJunction, vTrimmerHeaterColdJunction, vTrimaryHeaterInternal ,vTrimmerHeaterInternal): + frames = buildTreatmentTemperatureSensors(vInletPrimaryHeater, vOutletPrimaryHeater, vConductivitySensor1, vConductivitySensor2, vOutletRedundancy, vInletDialysate, vPrimaryHeaterThermoCouple, vPrimmerHeaterThermoCouple, vPrimaryHeaterColdJunction, vTrimmerHeaterColdJunction, vTrimaryHeaterInternal ,vTrimmerHeaterInternal) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '080#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildCanBUSFaultCount(vCount): + msg = messageBuilder.buildMessage( GuiActionType.CanBUSFaultCount, 4 * 1, False, + utils.toI32(vCount) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setCanBUSFaultCount (vCount): + frames = buildCanBUSFaultCount(vCount) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '020#{}'.format(frame)]) + waitForMessageToBeSent() + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildAlarm(vState, vTop, vEsclatesIn, vSilentExpires, vFlags): + msg = messageBuilder.buildMessage( GuiActionType.AlarmStatus, 4 * 4 + 2, False, + utils.toI32(vState ), + utils.toI32(vTop ), + utils.toI32(vEsclatesIn ), + utils.toI32(vSilentExpires ), + utils.toI16(vFlags ) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def sendAlarm(vState, vTop, vEsclatesIn, vSilentExpires, vFlags): + frames = buildAlarm(vState, vTop, vEsclatesIn, vSilentExpires, vFlags) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '001#{}'.format(frame)]) + waitForMessageToBeSent() +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildAlarmTriggered(vAlarmID): + msg = messageBuilder.buildMessage( GuiActionType.AlarmTriggered, 4 , True, + utils.toI16 (vAlarmID) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setAlarmTriggered(vAlarmID): + frames = buildAlarmTriggered(vAlarmID) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '001#{}'.format(frame)]) + waitForMessageToBeSent() +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildAlarmCleared(vAlarmID): + msg = messageBuilder.buildMessage( GuiActionType.AlarmCleared, 4 , True, + utils.toI32(vAlarmID) + ) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def setAlarmCleared(vAlarmID): + frames = buildAlarmCleared(vAlarmID) + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '001#{}'.format(frame)]) + waitForMessageToBeSent() +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildUnknown(): + msg = messageBuilder.buildMessage( GuiActionType.Unknown, 0 , False) + return messageBuilder.toFrames(msg) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def sendUnknown_HD(): + frames = buildUnknown() + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '001#{}'.format(frame)]) # send from HD + waitForMessageToBeSent() +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def sendUnknown_DG(): + frames = buildUnknown() + frames = messageBuilder.toCandumpFormat(frames) + for frame in frames: + subprocess.call(['cansend', 'can0', '070#{}'.format(frame)]) # send from DG + waitForMessageToBeSent() + +def clear_all_alarms(): + sendAlarm(0, 0, 0, 0, 0) + Index: dialin/squish/globals.py =================================================================== diff -u --- dialin/squish/globals.py (revision 0) +++ dialin/squish/globals.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file globals.py +# date 2020/02/21 +# author Behrouz NematiPour +# + +def SRSUI(vSRSUI = ""): + return "SRSUI " + "{}".format(vSRSUI).rjust(3, '0') Index: dialin/squish/messageBuilder.py =================================================================== diff -u --- dialin/squish/messageBuilder.py (revision 0) +++ dialin/squish/messageBuilder.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file messageBuilder.py +# date 2020/04/08 +# author Behrouz NematiPour +# + +import utils +import crc + +syncByte = 'A5' + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toCandumpFormat(vMsg): + if type(vMsg) == list: + for index, value in enumerate(vMsg): + vMsg[index] = ".".join(utils.partition(value, 2, False)) + else: + vMsg = ".".join(utils.partition(vMsg, 2, False)) + return vMsg + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toFrames(vMsg): + mLen = 16 + padded = utils.padding(vMsg, mLen) + frames = utils.partition(padded, mLen, False) + return frames + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def addCRC8(vString, vDelimiter = ""): + return vString + vDelimiter + crc.calcCRC8(vString, vDelimiter) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def buildMessage(vMsgID, vLen, vAck, *vArgs): + msg = "" + if vAck: + seq = -1 + else: + seq = 1 + + msg += utils.toI16(seq) # always used seq# (-)1 (for now) + msg += utils.toI16(vMsgID) + msg += utils.toI08(vLen) + for arg in vArgs: + msg += arg + msg += crc.calcCRC8(msg) + return syncByte + msg + + Index: dialin/squish/unittests.py =================================================================== diff -u --- dialin/squish/unittests.py (revision 0) +++ dialin/squish/unittests.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file unittests.py +# date 2019/11/20 +# author Behrouz NematiPour +# +import test +import sys +import crc + +def testPythonVersion(): + test.compare(sys.version_info.major,3) + test.compare(sys.version_info.minor,6) + test.compare(sys.version_info.micro,4) + +def testcrc8(): + strByte1 = ( "4B 43 09 00 14 00 00" + "00 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00" + "00 00" # 9D + ) + + strByte2 = ( "4C 43 02 00 12 03 00" + "00 00 14 00 00 00 00 00" + "00 00 00 00 00 00 7F 00" # 55 + ) + + strByte3 = ( "4A 43 05 00 1C 00 00" + "00 00 00 00 00 00 00 00" + "00 00 00 00 00 00 6A B6" + "99 43 D5 68 6F 44 00 00" + "00 00" #4F + ) + + strByte4 = ( "FB 18 07 00 04 00 00" + "00 00" #7F + ) + + test.compare(crc.calcCRC8(strByte1, ' '), '9D') + test.compare(crc.calcCRC8(strByte2, ' '), '55') + test.compare(crc.calcCRC8(strByte3, ' '), '4F') + test.compare(crc.calcCRC8(strByte4, ' '), '7F') Index: dialin/squish/utils.py =================================================================== diff -u --- dialin/squish/utils.py (revision 0) +++ dialin/squish/utils.py (revision 11074441e3cf2a05a9b8c55c6a7c9c21bc5fb5a3) @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file utils.py +# date 2019/11/21 +# author Behrouz NematiPour +# + +import time +import struct +import inspect +#from pathlib import PurePath + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def waitForGUI(vDelay = 2): + time.sleep(vDelay) +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toUXX(vValue, vByteCount, vDelimiter): + x = '{0:0{1}X}'.format(int(vValue) & (2**(4*vByteCount)-1), vByteCount, 'x') + bytes = partition(x, 2) + return vDelimiter.join(bytes) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toI32(vValue, vDelimiter = ""): + return toUXX(vValue, 8, vDelimiter) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toI16(vValue, vDelimiter = ""): + return toUXX(vValue, 4, vDelimiter) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toI08(vValue, vDelimiter = ""): + return toUXX(vValue, 2, vDelimiter) + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def toF32(vValue): + return '{:08X}'.format(struct.unpack('f', vValue))[0],'X') + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def partition(vString, vPart, vRightDirection=True): + return [vString[i: i + vPart] for i in range(0, len(vString), vPart)][::-1 if vRightDirection else 1] + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def padding(vString, vLen): + lStr = len(vString) + lPad = int(lStr / vLen) * vLen + ( vLen * (1 if lStr % vLen else 0) ) + return vString.ljust(lPad, "0") + +## ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def tstStart(): + print(time.strftime("%H:%M:%S Start", time.localtime())) #, PurePath(inspect.stack()[1][1]).parts[-2]) + +def tstDone(): + print(time.strftime("%H:%M:%S Done ", time.localtime())) #, PurePath(inspect.stack()[1][1]).parts[-2]) + +def l2ml(vValue): + return int(round (vValue, 3) * 1000) + +def ml2l(vValue): + return vValue / 1000 +