198 lines
7.0 KiB
C#
198 lines
7.0 KiB
C#
///
|
|
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Text;
|
|
|
|
namespace TBF.Rig.Sirt
|
|
{
|
|
public enum Mark : byte
|
|
{
|
|
Send = 0x55,
|
|
Receive = 0xFF,
|
|
Stop = 0x16,
|
|
}
|
|
|
|
public enum Tel : byte
|
|
{
|
|
/// Sent
|
|
PamWrite = 0x81,
|
|
PamRead = 0x82,
|
|
RacWrite = 0x88,
|
|
RacRead = 0x8b,
|
|
RegisterWrite = 0x84,
|
|
RegisterRead = 0x87,
|
|
|
|
/// Received
|
|
TelFromAir = 0x11, /// sent without a request
|
|
AlertMsg = 0x14, /// sent without a request
|
|
AckOrAnswer = 0x12,
|
|
}
|
|
|
|
public static class SirtUtils
|
|
{
|
|
public const int MinTelegramLen = 12;
|
|
|
|
|
|
public static byte[] WriteToPamPool(UInt32 radioAddress, byte param1, byte param2,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.PamWrite, param1, param2, optionalData);
|
|
}
|
|
|
|
public static byte[] ReadFromPamPool(UInt32 radioAddress, byte param1, byte param2,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.PamRead, param1, param2, optionalData);
|
|
}
|
|
|
|
public static byte[] WriteToRacPool(UInt32 radioAddress, byte param1, byte param2,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.RacWrite, param1, param2, optionalData);
|
|
}
|
|
|
|
public static byte[] ReadFromRacPool(UInt32 radioAddress, byte param1, byte param2,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.RacRead, param1, param2, optionalData);
|
|
}
|
|
|
|
public static byte[] WriteToRegisterAddress(UInt32 radioAddress, byte param, byte wrLenght,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.RegisterWrite, param, wrLenght, optionalData);
|
|
}
|
|
|
|
public static byte[] ReadFromRegisterAddress(UInt32 radioAddress, byte param, byte wrLenght,
|
|
byte[] optionalData = null)
|
|
{
|
|
return GenericReadWrite(radioAddress, Tel.RegisterRead, param, wrLenght, optionalData);
|
|
}
|
|
|
|
|
|
static byte[] GenericReadWrite(UInt32 radioAddress, Tel tel, byte param1, byte param2,
|
|
byte[] optionalData)
|
|
{
|
|
byte[] data = (optionalData != null) ? optionalData : new byte[0];
|
|
int dataLen = data.Length;
|
|
|
|
if (dataLen > 128) return null;
|
|
|
|
byte[] telegram = new byte[12 + dataLen];
|
|
telegram[0] = (byte)Mark.Send;
|
|
telegram[1] = (byte)tel;
|
|
telegram[2] = param1;
|
|
telegram[3] = param2;
|
|
telegram[4] = (byte)((radioAddress >> 24) & 0x000000FF);
|
|
telegram[5] = (byte)((radioAddress >> 16) & 0x000000FF);
|
|
telegram[6] = (byte)((radioAddress >> 8) & 0x000000FF);
|
|
telegram[7] = (byte)(radioAddress & 0x000000FF);
|
|
telegram[8] = (byte)dataLen;
|
|
for (int i = 0; i < dataLen; i++)
|
|
{
|
|
telegram[9 + i] = data[i];
|
|
}
|
|
UpdateCrcCcitt(telegram, 1, dataLen + 8); /// Updates telegram[dataLen + 9] and telegram[dataLen + 10]
|
|
telegram[dataLen + 11] = 0x16;
|
|
|
|
return telegram;
|
|
}
|
|
|
|
public static void UpdateCrcCcitt(byte[] data, int start, int length)
|
|
{
|
|
if (data.Length < start + length + 2) return;
|
|
|
|
UInt16 crc_result = CalculateCrcCcitt(data, start, length);
|
|
|
|
data[start + length] = (byte)((crc_result >> 8) & 0xFF);
|
|
data[start + length + 1] = (byte)(crc_result & 0xFF);
|
|
}
|
|
|
|
|
|
public static UInt16 CalculateCrcCcitt(byte[] data, int start, int length)
|
|
{
|
|
if (data.Length < start + length) return 0;
|
|
|
|
UInt16 crc_result = 0xFFFF;
|
|
|
|
for (int ui_index = start; ui_index < length + start; ui_index++)
|
|
{
|
|
byte znak = data[ui_index];
|
|
|
|
/// Repeat 8 times
|
|
for (int h = 0; h < 8; h++)
|
|
{
|
|
int test = ((crc_result & 0x8000) != 0) ? 0x80 : 0;
|
|
|
|
crc_result <<= 1;
|
|
|
|
if (((znak & 0x80) ^ test) != 0)
|
|
{
|
|
crc_result ^= 0x1021;
|
|
}
|
|
znak <<= 1;
|
|
}
|
|
}
|
|
|
|
return crc_result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether there is a valid telegram frame in 'buffer' at 'offset'.
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer with received bytes</param>
|
|
/// <param name="rcvdBytesCount">Received bytes count (stored always at the beginning of the buffer)</param>
|
|
/// <param name="offset">Checked telegram frame offset</param>
|
|
/// <returns>true when telegram frame fits received data</returns>
|
|
public static bool IsTelegramAt(byte[] buffer, int rcvdBytesCount, int offset)
|
|
{
|
|
/// It is guaranteed that (offset + MinTelegramLen < rcvdBytesCount)
|
|
int optDataLen = buffer[offset + 8];
|
|
|
|
return (buffer[offset] == (byte)Mark.Receive) &&
|
|
(buffer[offset + 1] == (byte)Tel.TelFromAir ||
|
|
buffer[offset + 1] == (byte)Tel.AlertMsg ||
|
|
buffer[offset + 1] == (byte)Tel.AckOrAnswer) &&
|
|
(offset + SirtUtils.MinTelegramLen + optDataLen < rcvdBytesCount) &&
|
|
(buffer[offset + 11 + optDataLen] == (byte)Mark.Stop) &&
|
|
(SirtUtils.CalculateCrcCcitt(buffer, offset + 1, optDataLen + 8)
|
|
== (UInt16)(256 * buffer[offset + 9 + optDataLen] + buffer[offset + 10 + optDataLen]));
|
|
}
|
|
|
|
public static int GetTelegramLength(byte[] data, int offset = 0)
|
|
{
|
|
return (offset + 8 >= data.Length) ? 0 : MinTelegramLen + data[offset + 8];
|
|
}
|
|
|
|
public static UInt32 GetRadioAddress(byte[] data)
|
|
{
|
|
return (data.Length < MinTelegramLen) ? 0 : (UInt32)(((((data[4] << 8) + data[5]) << 8) + data[6]) << 8) + data[7];
|
|
}
|
|
|
|
public static string TelegramToString(byte[] data)
|
|
{
|
|
var sb = new StringBuilder();
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
sb.Append(string.Format("{0:X2} ", data[i]));
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public static string GetPortSettingsStr(System.IO.Ports.SerialPort sp)
|
|
{
|
|
if (sp != null)
|
|
{
|
|
return string.Format("BaudRate={0} DataBits={1} Parity={2}, StopBits={3}",
|
|
sp.BaudRate, sp.DataBits, sp.Parity, sp.StopBits);
|
|
}
|
|
else
|
|
{
|
|
return "null";
|
|
}
|
|
}
|
|
}
|
|
}
|