Big changes
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
// UNCLASSIFIED
|
||||
/*-------------------------------------------------------------------------
|
||||
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
||||
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
||||
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
||||
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
||||
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
||||
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
||||
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
||||
COMPANY.
|
||||
|
||||
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
||||
GOVERNMENT.
|
||||
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Raytheon.Common;
|
||||
|
||||
namespace Raytheon.Instruments
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse and Format Util for the DPF2 flow meter serial interface
|
||||
/// </summary>
|
||||
internal static class FlowMeterOmegaDPF20DataParser
|
||||
{
|
||||
#region PublicMembers
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct HeaderStruct
|
||||
{
|
||||
public byte startOfFrame;//2
|
||||
public byte frameType;//32,33,35,36,37,38
|
||||
public byte reserved;//32
|
||||
public byte orginAddress;//32 + real value
|
||||
public byte destinationAddress;//32 + real value
|
||||
public byte registerLocation;//32 + real value
|
||||
public byte reserved2;//32
|
||||
public byte dataLength;//num data bytes that follow
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ReadDisplayCmdStruct
|
||||
{
|
||||
public HeaderStruct header;
|
||||
public FooterStruct footer;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ReadDisplayRspStruct
|
||||
{
|
||||
public HeaderStruct header;
|
||||
public byte byte1;
|
||||
public byte byte2;
|
||||
public byte byte3;
|
||||
public byte byte4;
|
||||
public byte byte5;
|
||||
public byte byte6;
|
||||
public byte byte7;
|
||||
public byte byte8;
|
||||
public FooterStruct footer;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct FooterStruct
|
||||
{
|
||||
public byte crc;
|
||||
public byte endOfFrame;//3
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublicFunctions
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the CRC per the DPF20 manual
|
||||
/// </summary>
|
||||
/// <param name="data">The data to run the crc on</param>
|
||||
/// <param name="numBytesToProcess">The number of bytes to use for the crc</param>
|
||||
/// <returns></returns>
|
||||
public static byte PerformCrc(byte[] data, int numBytesToProcess)
|
||||
{
|
||||
byte crc = 0;
|
||||
|
||||
for (int i = 0; i < numBytesToProcess; i++)
|
||||
{
|
||||
crc = (byte)(crc ^ data[i]);
|
||||
}
|
||||
|
||||
if (crc < 32)
|
||||
{
|
||||
crc = (byte)~crc;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the byte array for the read display command
|
||||
/// </summary>
|
||||
/// <returns>a byte array that is the command to send to the meter to read the display</returns>
|
||||
public static byte[] CreateReadFlowCmd(byte flowMeterAddress)
|
||||
{
|
||||
// populate the header per the manual
|
||||
HeaderStruct header = new HeaderStruct();
|
||||
header.startOfFrame = 2;
|
||||
header.frameType = 36;
|
||||
header.reserved = 32;
|
||||
header.orginAddress = 32;
|
||||
header.destinationAddress = (byte)(flowMeterAddress + 32);
|
||||
header.registerLocation = 32;
|
||||
header.reserved2 = 32;
|
||||
header.dataLength = 32;
|
||||
|
||||
// populate the footer
|
||||
FooterStruct footer = new FooterStruct();
|
||||
footer.crc = 0;// set at end of function
|
||||
footer.endOfFrame = 3;
|
||||
|
||||
// create the message
|
||||
ReadDisplayCmdStruct cmd = new ReadDisplayCmdStruct();
|
||||
cmd.header = header;
|
||||
cmd.footer = footer;
|
||||
|
||||
// allocate the final buffer
|
||||
int messageSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(ReadDisplayCmdStruct)));
|
||||
byte[] buff = new byte[messageSize];
|
||||
|
||||
//Get a pointer to the Buffer
|
||||
GCHandle pinnedArray = GCHandle.Alloc(buff, GCHandleType.Pinned);
|
||||
|
||||
//Pinned pointer to array
|
||||
IntPtr pData = pinnedArray.AddrOfPinnedObject();
|
||||
|
||||
//Place message into buffer
|
||||
Marshal.StructureToPtr(cmd, pData, true);
|
||||
|
||||
//Release array pointer
|
||||
pinnedArray.Free();
|
||||
|
||||
// calculate and set crc
|
||||
byte calculatedCrc = PerformCrc(buff, 8);
|
||||
buff[8] = calculatedCrc;
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse out the flow from the read display response
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="numBytes"></param>
|
||||
/// <returns></returns>
|
||||
public static double ParseReadFlowRsp(byte[] data, int numBytes)
|
||||
{
|
||||
const int DISPLAY_REGISTER = 32;
|
||||
const int DATA_OFFSET = 32;
|
||||
const int EXPECTED_MSG_ID = 37;
|
||||
const int EXPECTED_DATA_LEN = 18;
|
||||
|
||||
if (numBytes < 18)
|
||||
{
|
||||
throw new Exception("Need at least " + EXPECTED_DATA_LEN + " to form the rsp message, received: " + numBytes);
|
||||
}
|
||||
|
||||
// get a pointer to the data
|
||||
GCHandle messagePinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
IntPtr pMessageData = messagePinnedArray.AddrOfPinnedObject();
|
||||
|
||||
// populate the structure
|
||||
ReadDisplayRspStruct msgStruct = (ReadDisplayRspStruct)Marshal.PtrToStructure(pMessageData, typeof(ReadDisplayRspStruct));
|
||||
|
||||
// free the ptr
|
||||
messagePinnedArray.Free();
|
||||
|
||||
if (msgStruct.header.frameType != EXPECTED_MSG_ID)
|
||||
{
|
||||
throw new Exception("expected msg id: " + EXPECTED_MSG_ID + ", received: " + msgStruct.header.frameType);
|
||||
}
|
||||
|
||||
// subtract the DATA_OFFSET because that is what the manual says to do:)
|
||||
int numDataBytes = msgStruct.header.dataLength - DATA_OFFSET;
|
||||
|
||||
int headerSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(HeaderStruct)));
|
||||
|
||||
byte calculatedCrc = PerformCrc(data, numDataBytes + headerSize);
|
||||
byte receivedCrc = msgStruct.footer.crc;
|
||||
if (calculatedCrc != receivedCrc)
|
||||
{
|
||||
throw new Exception("calculated crc: " + calculatedCrc + ", is not equal to the received crc: " + receivedCrc);
|
||||
}
|
||||
|
||||
// confirm the from register
|
||||
int fromRegister = msgStruct.header.registerLocation;
|
||||
if (fromRegister != DISPLAY_REGISTER)
|
||||
{
|
||||
throw new Exception("from register: " + fromRegister + ", is not the expected register: " + DISPLAY_REGISTER);
|
||||
}
|
||||
|
||||
// get the data
|
||||
byte[] dataPayload = new byte[numDataBytes];
|
||||
Array.Copy(data, headerSize, dataPayload, 0, numDataBytes);
|
||||
|
||||
// convert it to a string
|
||||
string rspStr = Encoding.ASCII.GetString(dataPayload);
|
||||
|
||||
//Convert string value to double and return
|
||||
return double.Parse(rspStr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// parse out flow from the master flow message (ID 35)
|
||||
/// </summary>
|
||||
/// <returns>the flow rate.</returns>
|
||||
public static double ParseMasterFlowMsg(byte[] data, int numBytes)
|
||||
{
|
||||
const int DISPLAY_REGISTER = 32;
|
||||
const int DATA_OFFSET = 32;
|
||||
const int EXPECTED_MSG_ID = 35;
|
||||
const int EXPECTED_DATA_LEN = 18;
|
||||
|
||||
// start of message data pattern
|
||||
byte[] startOfMesage = new byte[] { 2, 35 };
|
||||
|
||||
// data search index
|
||||
int searchIndex = 0;
|
||||
|
||||
// need at least 18 bytes
|
||||
if (numBytes < EXPECTED_DATA_LEN)
|
||||
{
|
||||
throw new Exception("Need at least " + EXPECTED_DATA_LEN + " to form the rsp message, received: " + numBytes);
|
||||
}
|
||||
// if there are more than two messages, just need the end of the buffer
|
||||
// worst case scenario for 1 complete message would be 35 bytes (17 from an incomplete message and then 18 for the complete one)
|
||||
else if (numBytes >= (EXPECTED_DATA_LEN * 2) - 1)
|
||||
{
|
||||
searchIndex = numBytes - ((EXPECTED_DATA_LEN * 2) - 1);
|
||||
}
|
||||
|
||||
int finalMsgStartIndex = Util.ByteArraySearch(data, searchIndex, startOfMesage);
|
||||
|
||||
if (finalMsgStartIndex == -1)
|
||||
{
|
||||
throw new Exception("Could not find start of message");
|
||||
}
|
||||
else if((numBytes - finalMsgStartIndex) < EXPECTED_DATA_LEN)
|
||||
{
|
||||
throw new Exception("Found start of message, but not enough bytes for a complete message");
|
||||
}
|
||||
|
||||
byte[] messagePayload = new byte[EXPECTED_DATA_LEN];
|
||||
Array.Copy(data, finalMsgStartIndex, messagePayload, 0, EXPECTED_DATA_LEN);
|
||||
|
||||
// get a pointer to the data
|
||||
GCHandle messagePinnedArray = GCHandle.Alloc(messagePayload, GCHandleType.Pinned);
|
||||
IntPtr pMessageData = messagePinnedArray.AddrOfPinnedObject();
|
||||
|
||||
// populate the structure
|
||||
HeaderStruct headerStruct = (HeaderStruct)Marshal.PtrToStructure(pMessageData, typeof(HeaderStruct));
|
||||
|
||||
// free the ptr
|
||||
messagePinnedArray.Free();
|
||||
|
||||
if (headerStruct.frameType != EXPECTED_MSG_ID)
|
||||
{
|
||||
throw new Exception("expected msg id: " + EXPECTED_MSG_ID + ", received: " + headerStruct.frameType);
|
||||
}
|
||||
|
||||
// subtract the DATA_OFFSET because that is what the manual says to do:)
|
||||
int numDataBytes = headerStruct.dataLength - DATA_OFFSET;
|
||||
|
||||
int headerSize = (int)(System.Runtime.InteropServices.Marshal.SizeOf(typeof(HeaderStruct)));
|
||||
|
||||
// confirm the crc
|
||||
byte calculatedCrc = PerformCrc(messagePayload, numDataBytes + headerSize);
|
||||
byte receivedCrc = messagePayload[numDataBytes + headerSize];
|
||||
if (calculatedCrc != receivedCrc)
|
||||
{
|
||||
throw new Exception("calculated crc: " + calculatedCrc + ", is not equal to the received crc: " + receivedCrc);
|
||||
}
|
||||
|
||||
// confirm the from register
|
||||
int fromRegister = headerStruct.registerLocation;
|
||||
if (fromRegister != DISPLAY_REGISTER)
|
||||
{
|
||||
throw new Exception("from register: " + fromRegister + ", is not the expected register: " + DISPLAY_REGISTER);
|
||||
}
|
||||
|
||||
// get the data
|
||||
byte[] dataPayload = new byte[numDataBytes];
|
||||
Array.Copy(messagePayload, headerSize, dataPayload, 0, numDataBytes);
|
||||
|
||||
// convert to a string
|
||||
string rspStr = Encoding.ASCII.GetString(dataPayload);
|
||||
|
||||
//Convert string value to double and return
|
||||
return double.Parse(rspStr);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user