public static byte ConvertToByte(PLCCommandAndQueryTypeEnum input) { if (!Enum.IsDefined(typeof(PLCCommandAndQueryTypeEnum), input)) { return(ConvertToByte(PLCCommandAndQueryTypeEnum.UNDEFINED)); } else { return((byte)input); } }
public void BuildUp() { _input_undefined = PLCCommandAndQueryTypeEnum.UNDEFINED; _input_test_connection = PLCCommandAndQueryTypeEnum.TEST_CONNECTION; _input_get_current_azel_positions = PLCCommandAndQueryTypeEnum.GET_CURRENT_AZEL_POSITIONS; _input_get_current_limit_switch_statuses = PLCCommandAndQueryTypeEnum.GET_CURRENT_LIMIT_SWITCH_STATUSES; _input_get_current_safety_interlock_status = PLCCommandAndQueryTypeEnum.GET_CURRENT_SAFETY_INTERLOCK_STATUS; _input_cancel_active_objective_azel_position = PLCCommandAndQueryTypeEnum.CANCEL_ACTIVE_OBJECTIVE_AZEL_POSITION; _input_shutdown = PLCCommandAndQueryTypeEnum.SHUTDOWN; _input_calibrate = PLCCommandAndQueryTypeEnum.CALIBRATE; _input_set_objective_azel_position = PLCCommandAndQueryTypeEnum.SET_OBJECTIVE_AZEL_POSITION; }
public bool ProcessRequest(NetworkStream ActiveClientStream, byte[] query) { int ExpectedSize = query[0] + (256 * query[1]); if (query.Length != ExpectedSize) { throw new ArgumentException( "ScaleModelPLCDriverController read a package specifying a size [" + ExpectedSize.ToString() + "], but the actual size was different [" + query.Length + "]." ); } byte CommandQueryTypeAndExpectedResponseStatus = query[2]; byte CommandQueryTypeByte = (byte)(CommandQueryTypeAndExpectedResponseStatus & 0x3F); byte ExpectedResponseStatusByte = (byte)(CommandQueryTypeAndExpectedResponseStatus >> 6); PLCCommandAndQueryTypeEnum CommandQueryTypeEnum = PLCCommandAndQueryTypeConversionHelper.GetFromByte(CommandQueryTypeByte); PLCCommandResponseExpectationEnum ExpectedResponseStatusEnum = PLCCommandResponseExpectationConversionHelper.GetFromByte(ExpectedResponseStatusByte); byte[] FinalResponseContainer; if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.FULL_RESPONSE) { FinalResponseContainer = new byte[] { 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.TEST_CONNECTION: { FinalResponseContainer[3] = 0x1; FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_AZEL_POSITIONS: { double TestAzimuth = 180.0; double TestElevation = 42.0; Array.Copy(BitConverter.GetBytes(TestAzimuth), 0, FinalResponseContainer, 3, 8); Array.Copy(BitConverter.GetBytes(TestElevation), 0, FinalResponseContainer, 11, 8); FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_LIMIT_SWITCH_STATUSES: { PLCLimitSwitchStatusEnum StatusAzimuthUnderRotation = PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusAzimuthOverRotation = PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusElevationUnderRotation = PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusElevationOverRotation = PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; int PacketSum = PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusElevationOverRotation) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusElevationUnderRotation) * 0x4) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusAzimuthOverRotation) * 0x10) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusAzimuthUnderRotation) * 0x40) ; FinalResponseContainer[3] = (byte)PacketSum; FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_SAFETY_INTERLOCK_STATUS: { FinalResponseContainer[3] = PLCSafetyInterlockStatusConversionHelper.ConvertToByte(PLCSafetyInterlockStatusEnum.LOCKED); FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.MINOR_RESPONSE) { FinalResponseContainer = new byte[] { 0x3, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.CANCEL_ACTIVE_OBJECTIVE_AZEL_POSITION: case PLCCommandAndQueryTypeEnum.SHUTDOWN: case PLCCommandAndQueryTypeEnum.CALIBRATE: { FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.SET_OBJECTIVE_AZEL_POSITION: { double NextAZ, NextEL; try { NextAZ = BitConverter.ToDouble(query, 3); NextEL = BitConverter.ToDouble(query, 11); } catch (Exception e) { if ((e is ArgumentException) || (e is ArgumentNullException) || (e is ArgumentOutOfRangeException)) { // This error code means that the data could not be converted into a double-precision floating point FinalResponseContainer[2] = 0x2; break; } else { // Unexpected exception throw e; } } if ((NextAZ < 0) || (NextAZ > 360)) { // This error code means that the objective azimuth position is invalid FinalResponseContainer[2] = 0x3; break; } if ((NextEL < 0) || (NextEL > 90)) { // This error code means that the objective elevation position is invalid FinalResponseContainer[2] = 0x4; break; } // Otherwise, this is valid // TODO: Perform task(s) to set objective orientation! FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while NOT expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else { throw new ArgumentException("Invalid PLCCommandResponseExpectationEnum value seen while processing client request in ScaleModelPLCDriver: " + ExpectedResponseStatusEnum.ToString()); } return(AttemptToWriteDataToServer(ActiveClientStream, FinalResponseContainer)); }
/// <summary> /// handle conection data comming from modbus device /// this serves as part of a tcp server along with HandleClientManagementThread /// it apears to have been designed for ethernet/ip which we found out our plc cant do /// this is probably unnecicary in the mcu drivers. /// </summary> /// <param name="ActiveClientStream"></param> /// <param name="query"></param> /// <returns></returns> public bool ProcessRequest(NetworkStream ActiveClientStream, byte[] query) { int ExpectedSize = query[0] + (256 * query[1]); if (query.Length != ExpectedSize) { throw new ArgumentException( "ProductionPLCDriver read a package specifying a size [" + ExpectedSize.ToString() + "], but the actual size was different [" + query.Length + "]." ); } byte CommandQueryTypeAndExpectedResponseStatus = query[2]; byte CommandQueryTypeByte = (byte)(CommandQueryTypeAndExpectedResponseStatus & 0x3F); byte ExpectedResponseStatusByte = (byte)(CommandQueryTypeAndExpectedResponseStatus >> 6); PLCCommandAndQueryTypeEnum CommandQueryTypeEnum = PLCCommandAndQueryTypeConversionHelper.GetFromByte(CommandQueryTypeByte); PLCCommandResponseExpectationEnum ExpectedResponseStatusEnum = PLCCommandResponseExpectationConversionHelper.GetFromByte(ExpectedResponseStatusByte); byte[] FinalResponseContainer; if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.FULL_RESPONSE) { FinalResponseContainer = new byte[] { 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.TEST_CONNECTION: { // Read the heartbeat register ushort[] inputRegisters = MCUModbusMaster.ReadInputRegisters(MCUConstants.ACTUAL_MCU_READ_INPUT_REGISTER_HEARTBEAT_ADDRESS, 1); ushort resultValue = (ushort)((inputRegisters.Length == 1) ? inputRegisters[0] : 0); FinalResponseContainer[3] = (byte)(((resultValue == 8192) || (resultValue == 24576)) ? 0x1 : 0x0); FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_AZEL_POSITIONS: { PrintReadInputRegsiterContents("Before getting current position"); // Get the MCU's value for the displacement since its power cycle ushort[] inputRegisters = MCUModbusMaster.ReadInputRegisters(MCUConstants.ACTUAL_MCU_READ_INPUT_REGISTER_CURRENT_POSITION_ADDRESS, 2); int currentStepForMCU = (65536 * inputRegisters[0]) + inputRegisters[1]; PrintReadInputRegsiterContents("After getting current position"); // Convert that step change into degrees and write the bytes to return Array.Copy(BitConverter.GetBytes(currentStepForMCU * 360 / 10000000.0), 0, FinalResponseContainer, 3, 8); Array.Copy(BitConverter.GetBytes(0.0), 0, FinalResponseContainer, 11, 8); FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.MINOR_RESPONSE) { FinalResponseContainer = new byte[] { 0x3, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.SET_CONFIGURATION: { // Copy over data we care about, which for now is only the azimuth // We skip over the data concerning the elevation, hence the gap in element access for query ushort[] DataToWrite = { (ushort)((256 * query[3]) + query[4]), (ushort)((256 * query[5]) + query[6]), (ushort)((256 * query[7]) + query[8]), (ushort)((256 * query[9]) + query[10]), (ushort)((256 * query[15]) + query[16]), 0, 0, 0, 0, 0 }; MCUModbusMaster.WriteMultipleRegisters(MCUConstants.ACTUAL_MCU_WRITE_REGISTER_START_ADDRESS, DataToWrite); PrintReadInputRegsiterContents("After setting configuration"); if (SendResetErrorsCommand()) { Console.WriteLine("[ProductionPLCDriver] Successfully sent reset command."); PrintReadInputRegsiterContents("After sending reset command"); FinalResponseContainer[2] = 0x1; } else { // Send an error code Console.WriteLine("[ProductionPLCDriver] ERROR sending reset command."); FinalResponseContainer[2] = 0x2; } break; } case PLCCommandAndQueryTypeEnum.CONTROLLED_STOP: { // There was already a helper function to execute a controlled stop, so just call that // Send an error code if there's a failure for some reason FinalResponseContainer[2] = (byte)(SendEmptyMoveCommand() ? 0x1 : 0x2); break; } case PLCCommandAndQueryTypeEnum.IMMEDIATE_STOP: { // There was already a helper function to execute a controlled stop, so just call that // Send an error code if there's a failure for some reason FinalResponseContainer[2] = (byte)(SendImmediateStopCommand() ? 0x1 : 0x2); break; } case PLCCommandAndQueryTypeEnum.SET_OBJECTIVE_AZEL_POSITION: { PrintReadInputRegsiterContents("Before setting objective position"); // Copy over data we care about, so skip over the data concerning the elevation double discrepancyMultiplier = 1.0; double objectiveAZDouble = BitConverter.ToDouble(query, 3); int stepChange = (int)(discrepancyMultiplier * Math.Pow(2, MCUConstants.ACTUAL_MCU_AZIMUTH_ENCODER_BIT_RESOLUTION) * objectiveAZDouble / 360); ushort stepChangeUShortMSW = (ushort)((stepChange >> 16) & 0xFFFF); ushort stepChangeUShortLSW = (ushort)(stepChange & 0xFFFF); int programmedPeakSpeed = BitConverter.ToInt32(query, 7); ushort programmedPeakSpeedUShortMSW = (ushort)((programmedPeakSpeed >> 16) & 0xFFFF); ushort programmedPeakSpeedUShortLSW = (ushort)(programmedPeakSpeed & 0xFFFF); ushort[] DataToWrite = { 0x2, // Denotes a relative move in command mode 0x3, // Denotes a Trapezoidal S-Curve profile stepChangeUShortMSW, stepChangeUShortLSW, programmedPeakSpeedUShortMSW, programmedPeakSpeedUShortLSW, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, 0, 0 }; MCUModbusMaster.WriteMultipleRegisters(MCUConstants.ACTUAL_MCU_WRITE_REGISTER_START_ADDRESS, DataToWrite); PrintReadInputRegsiterContents("After setting objective position"); FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.START_JOG_MOVEMENT: { PrintReadInputRegsiterContents("Before starting jog command"); // Make sure the command is intended for the azimuth if (query[3] != 0x1) { throw new ArgumentException("Unsupported value for axis specified in jog command for ProductionPLCDriver: " + query[3].ToString()); } ushort programmedPeakSpeedUShortMSW = (ushort)((256 * query[4]) + query[5]); ushort programmedPeakSpeedUShortLSW = (ushort)((256 * query[6]) + query[7]); ushort commandCode; switch (query[8]) { case 0x1: { commandCode = 0x80; break; } case 0x2: { commandCode = 0x100; break; } default: { throw new ArgumentException("Unsupported value for motor movement direction in jog command for ProductionPLCDriver: " + query[8].ToString()); } } ushort[] DataToWrite = { commandCode, // Denotes a jog move, either CW or CCW, in command mode 0x3, // Denotes a Trapezoidal S-Curve profile 0, // Reserved to 0 for a jog command 0, // Reserved to 0 for a jog command programmedPeakSpeedUShortMSW, programmedPeakSpeedUShortLSW, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, 0, 0 }; MCUModbusMaster.WriteMultipleRegisters(MCUConstants.ACTUAL_MCU_WRITE_REGISTER_START_ADDRESS, DataToWrite); PrintReadInputRegsiterContents("After starting jog command"); FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.TRANSLATE_AZEL_POSITION: { PrintReadInputRegsiterContents("Before starting relative move"); // Make sure the command is intended for the azimuth if (query[3] != 0x1) { throw new ArgumentException("Unsupported value for axis specified in move relative command for ProductionPLCDriver: " + query[3].ToString()); } ushort programmedPeakSpeedUShortMSW = (ushort)((256 * query[4]) + query[5]); ushort programmedPeakSpeedUShortLSW = (ushort)((256 * query[6]) + query[7]); short programmedPositionUShortMSW = (short)((256 * query[8]) + query[9]); short programmedPositionUShortLSW = (short)((256 * query[10]) + query[11]); ushort[] DataToWrite = { 0x2, // Denotes a relative move 0x3, // Denotes a Trapezoidal S-Curve profile (ushort)programmedPositionUShortMSW, // MSW for position (ushort)programmedPositionUShortLSW, // LSW for position programmedPeakSpeedUShortMSW, programmedPeakSpeedUShortLSW, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, MCUConstants.ACTUAL_MCU_MOVE_ACCELERATION_WITH_GEARING, 0, 0 }; MCUModbusMaster.WriteMultipleRegisters(MCUConstants.ACTUAL_MCU_WRITE_REGISTER_START_ADDRESS, DataToWrite); PrintReadInputRegsiterContents("After starting relative move command"); FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while NOT expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else { throw new ArgumentException("Invalid PLCCommandResponseExpectationEnum value seen while processing client request in ProductionPLCDriver: " + ExpectedResponseStatusEnum.ToString()); } return(AttemptToWriteDataToServer(ActiveClientStream, FinalResponseContainer)); }
public bool ProcessRequest(NetworkStream ActiveClientStream, byte[] query) { int ExpectedSize = query[0] + (256 * query[1]); if (query.Length != ExpectedSize) { throw new ArgumentException( "TestPLCDriverController read a package specifying a size [" + ExpectedSize.ToString() + "], but the actual size was different [" + query.Length + "]." ); } byte CommandQueryTypeAndExpectedResponseStatus = query[2]; byte CommandQueryTypeByte = (byte)(CommandQueryTypeAndExpectedResponseStatus & 0x3F); byte ExpectedResponseStatusByte = (byte)(CommandQueryTypeAndExpectedResponseStatus >> 6); PLCCommandAndQueryTypeEnum CommandQueryTypeEnum = PLCCommandAndQueryTypeConversionHelper.GetFromByte(CommandQueryTypeByte); PLCCommandResponseExpectationEnum ExpectedResponseStatusEnum = PLCCommandResponseExpectationConversionHelper.GetFromByte(ExpectedResponseStatusByte); byte[] FinalResponseContainer; if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.FULL_RESPONSE) { FinalResponseContainer = new byte[] { 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.TEST_CONNECTION: { FinalResponseContainer[3] = 0x1; FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_AZEL_POSITIONS: { Array.Copy(BitConverter.GetBytes(CurrentOrientation.Azimuth), 0, FinalResponseContainer, 3, 8); Array.Copy(BitConverter.GetBytes(CurrentOrientation.Elevation), 0, FinalResponseContainer, 11, 8); FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_LIMIT_SWITCH_STATUSES: { double CurrentAZ = CurrentOrientation.Azimuth; double CurrentEL = CurrentOrientation.Elevation; double ThresholdAZ = MiscellaneousHardwareConstants.LIMIT_SWITCH_AZ_THRESHOLD_DEGREES; double ThresholdEL = MiscellaneousHardwareConstants.LIMIT_SWITCH_EL_THRESHOLD_DEGREES; // Subtracting out those 2 degrees is because of our actual rotational limits of (-2 : 362) and (-2 : 92) degrees in azimuth and elevation respectively PLCLimitSwitchStatusEnum StatusAzimuthUnderRotation = (CurrentAZ < (ThresholdAZ - 2.0)) ? PLCLimitSwitchStatusEnum.WITHIN_WARNING_LIMITS : PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusAzimuthOverRotation = (CurrentAZ > (360 + ThresholdAZ - 2.0)) ? PLCLimitSwitchStatusEnum.WITHIN_WARNING_LIMITS : PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusElevationUnderRotation = (CurrentEL < (ThresholdEL - 2.0)) ? PLCLimitSwitchStatusEnum.WITHIN_WARNING_LIMITS : PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; PLCLimitSwitchStatusEnum StatusElevationOverRotation = (CurrentEL > (90 + ThresholdEL - 2.0)) ? PLCLimitSwitchStatusEnum.WITHIN_WARNING_LIMITS : PLCLimitSwitchStatusEnum.WITHIN_SAFE_LIMITS; int PacketSum = PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusElevationOverRotation) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusElevationUnderRotation) * 0x4) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusAzimuthOverRotation) * 0x10) + (PLCLimitSwitchStatusConversionHelper.ConvertToByte(StatusAzimuthUnderRotation) * 0x40) ; FinalResponseContainer[3] = (byte)PacketSum; FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.GET_CURRENT_SAFETY_INTERLOCK_STATUS: { FinalResponseContainer[3] = PLCSafetyInterlockStatusConversionHelper.ConvertToByte(PLCSafetyInterlockStatusEnum.LOCKED); FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else if (ExpectedResponseStatusEnum == PLCCommandResponseExpectationEnum.MINOR_RESPONSE) { FinalResponseContainer = new byte[] { 0x3, 0x0, 0x0 }; switch (CommandQueryTypeEnum) { case PLCCommandAndQueryTypeEnum.CANCEL_ACTIVE_OBJECTIVE_AZEL_POSITION: case PLCCommandAndQueryTypeEnum.SHUTDOWN: case PLCCommandAndQueryTypeEnum.CALIBRATE: { FinalResponseContainer[2] = 0x1; break; } case PLCCommandAndQueryTypeEnum.SET_OBJECTIVE_AZEL_POSITION: { double NextAZ, NextEL; try { NextAZ = BitConverter.ToDouble(query, 3); NextEL = BitConverter.ToDouble(query, 11); } catch (Exception e) { if ((e is ArgumentException) || (e is ArgumentNullException) || (e is ArgumentOutOfRangeException)) { // This error code means that the data could not be converted into a double-precision floating point FinalResponseContainer[2] = 0x2; break; } else { // Unexpected exception throw e; } } if ((NextAZ < 0) || (NextAZ > 360)) { // This error code means that the objective azimuth position is invalid FinalResponseContainer[2] = 0x3; break; } if ((NextEL < 0) || (NextEL > 90)) { // This error code means that the objective elevation position is invalid FinalResponseContainer[2] = 0x4; break; } // Otherwise, this is valid CurrentOrientation = new Orientation(NextAZ, NextEL); logger.Info("[TestPLCDriver] Setting current orientation to {" + CurrentOrientation.Azimuth.ToString() + ", " + CurrentOrientation.Elevation.ToString() + "}"); FinalResponseContainer[2] = 0x1; break; } default: { throw new ArgumentException("Invalid PLCCommandAndQueryTypeEnum value seen while NOT expecting a response: " + CommandQueryTypeEnum.ToString()); } } } else { throw new ArgumentException("Invalid PLCCommandResponseExpectationEnum value seen while processing client request in ScaleModelPLCDriver: " + ExpectedResponseStatusEnum.ToString()); } return(AttemptToWriteDataToServer(ActiveClientStream, FinalResponseContainer)); }
public byte[] RequestMessageSend(PLCCommandAndQueryTypeEnum MessageType, params object[] MessageParameters) { byte[] NetOutgoingMessage = { 0x13, 0x0, PLCCommandAndQueryTypeConversionHelper.ConvertToByte(MessageType), 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; PLCCommandResponseExpectationEnum ResponseExpectationValue; switch (MessageType) { case PLCCommandAndQueryTypeEnum.TEST_CONNECTION: case PLCCommandAndQueryTypeEnum.GET_CURRENT_AZEL_POSITIONS: case PLCCommandAndQueryTypeEnum.GET_CURRENT_LIMIT_SWITCH_STATUSES: case PLCCommandAndQueryTypeEnum.GET_CURRENT_SAFETY_INTERLOCK_STATUS: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.FULL_RESPONSE; break; } case PLCCommandAndQueryTypeEnum.CANCEL_ACTIVE_OBJECTIVE_AZEL_POSITION: case PLCCommandAndQueryTypeEnum.SHUTDOWN: case PLCCommandAndQueryTypeEnum.CALIBRATE: case PLCCommandAndQueryTypeEnum.CONTROLLED_STOP: case PLCCommandAndQueryTypeEnum.IMMEDIATE_STOP: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.MINOR_RESPONSE; break; } case PLCCommandAndQueryTypeEnum.SET_CONFIGURATION: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.MINOR_RESPONSE; int StartSpeedAzimuth = (int)MessageParameters[0]; int StartSpeedElevation = (int)MessageParameters[1]; int HomeTimeoutAzimuth = (int)MessageParameters[2]; int HomeTimeoutElevation = (int)MessageParameters[3]; NetOutgoingMessage[3] = 0x84; NetOutgoingMessage[4] = 0x00; NetOutgoingMessage[5] = 0x00; NetOutgoingMessage[6] = 0x00; NetOutgoingMessage[7] = 0x0; NetOutgoingMessage[8] = (byte)(StartSpeedAzimuth / 0xFFFF); NetOutgoingMessage[9] = (byte)((StartSpeedAzimuth >> 8) & 0xFF); NetOutgoingMessage[10] = (byte)(StartSpeedAzimuth & 0xFF); NetOutgoingMessage[11] = 0x0; NetOutgoingMessage[12] = (byte)(StartSpeedElevation / 0xFFFF); NetOutgoingMessage[13] = (byte)((StartSpeedElevation >> 8) & 0xFF); NetOutgoingMessage[14] = (byte)(StartSpeedElevation & 0xFF); NetOutgoingMessage[15] = (byte)(HomeTimeoutAzimuth >> 8); NetOutgoingMessage[16] = (byte)(HomeTimeoutAzimuth & 0xFF); NetOutgoingMessage[17] = (byte)(HomeTimeoutElevation >> 8); NetOutgoingMessage[18] = (byte)(HomeTimeoutElevation & 0xFF); break; } case PLCCommandAndQueryTypeEnum.SET_OBJECTIVE_AZEL_POSITION: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.MINOR_RESPONSE; Orientation ObjectiveOrientation = (Orientation)MessageParameters[0]; Array.Copy(BitConverter.GetBytes(ObjectiveOrientation.Azimuth), 0, NetOutgoingMessage, 3, 8); Array.Copy(BitConverter.GetBytes(ObjectiveOrientation.Elevation), 0, NetOutgoingMessage, 11, 8); break; } case PLCCommandAndQueryTypeEnum.START_JOG_MOVEMENT: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.MINOR_RESPONSE; RadioTelescopeAxisEnum AxisEnum = (RadioTelescopeAxisEnum)MessageParameters[0]; int AxisJogSpeed = (int)MessageParameters[1]; bool JogClockwise = (bool)MessageParameters[2]; switch (AxisEnum) { case RadioTelescopeAxisEnum.AZIMUTH: { NetOutgoingMessage[3] = 0x1; break; } case RadioTelescopeAxisEnum.ELEVATION: { NetOutgoingMessage[3] = 0x2; break; } default: { throw new ArgumentException("Invalid RadioTelescopeAxisEnum value seen while preparing jog movement bytes: " + AxisEnum.ToString()); } } NetOutgoingMessage[4] = 0x0; NetOutgoingMessage[5] = (byte)(AxisJogSpeed / 0xFFFF); NetOutgoingMessage[6] = (byte)((AxisJogSpeed >> 8) & 0xFF); NetOutgoingMessage[7] = (byte)(AxisJogSpeed & 0xFF); NetOutgoingMessage[8] = (byte)(JogClockwise ? 0x1 : 0x2); break; } case PLCCommandAndQueryTypeEnum.TRANSLATE_AZEL_POSITION: { ResponseExpectationValue = PLCCommandResponseExpectationEnum.MINOR_RESPONSE; RadioTelescopeAxisEnum AxisEnum = (RadioTelescopeAxisEnum)MessageParameters[0]; int AxisJogSpeed = (int)MessageParameters[1]; int position = (int)MessageParameters[2]; switch (AxisEnum) { case RadioTelescopeAxisEnum.AZIMUTH: { NetOutgoingMessage[3] = 0x1; break; } case RadioTelescopeAxisEnum.ELEVATION: { NetOutgoingMessage[3] = 0x2; break; } default: { throw new ArgumentException("Invalid RadioTelescopeAxisEnum value seen while preparing relative movement bytes: " + AxisEnum.ToString()); } } NetOutgoingMessage[4] = 0x0; NetOutgoingMessage[5] = (byte)(AxisJogSpeed / 0xFFFF); NetOutgoingMessage[6] = (byte)((AxisJogSpeed >> 8) & 0xFF); NetOutgoingMessage[7] = (byte)(AxisJogSpeed & 0xFF); if (position > 0) { NetOutgoingMessage[8] = 0x0; NetOutgoingMessage[9] = (byte)(position / 0xFFFF); NetOutgoingMessage[10] = (byte)((position >> 8) & 0xFF); NetOutgoingMessage[11] = (byte)(position & 0xFF); } else { NetOutgoingMessage[8] = 0xFF; NetOutgoingMessage[9] = (byte)((position / 0xFFFF) - 1); NetOutgoingMessage[10] = (byte)((position >> 8) & 0xFF); NetOutgoingMessage[11] = (byte)(position & 0xFF); } break; } default: { throw new ArgumentException("Illegal PLCCommandAndQueryTypeEnum value: " + MessageType.ToString()); } } NetOutgoingMessage[2] += (byte)(PLCCommandResponseExpectationConversionHelper.ConvertToByte(ResponseExpectationValue) * 0x40); // This is the expected response size of anything from the PLC (simulated or real), minor or full response. // See the TCP/IP packet contents google sheets file describing this under Wiki Documentation -> Control Room in the shared GDrive byte ExpectedResponseSize = (ResponseExpectationValue == PLCCommandResponseExpectationEnum.FULL_RESPONSE) ? (byte)0x13 : (byte)0x3; return(SendMessageWithResponse(NetOutgoingMessage, ExpectedResponseSize)); }