tbf/TBF/Rig/Sirt/SirtUtils.cs
2021-10-26 19:38:09 +02:00

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";
}
}
}
}