using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SDRgateway { public enum TGctrl { TGControlNotUsed = 0x0, TGChangeOnAlert = 0x1, TGChangeUserInter = 0x2, Reserved = 0x3 }; public enum CallOutFunction { Alert = 0x1, Test = 0x2, Info = 0x3, Clear = 0x4, Availability = 0x5, AvailabilityRequest = 0x6 }; public enum TextEncoding { ISO8859Latin1 = 0x1, ISO10646UTF = 0x1A }; public enum UDH { Yes = 0x01, No = 0x00 }; public class CallOutClass { public UInt32 callOutNumber = 1; public byte cm_msg_id = 1; public static byte[] SendCallOut(bool recFlag, uint callOutFunction, uint callOutNumber, uint callOutSeverity, uint tgCtrl, uint tgNumber, ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, string data) { // Call Out Function [15-12] + CallOutNumber [11-4] + CallOutSeverity [3-0] //uint bytes23 = (uint)CallOutFunction.Alert * 4096 + callOutNumber * 16 + callOutSeverity; UInt16 callOut = (UInt16)(callOutFunction * 0x1000 + callOutNumber * 0x10 + callOutSeverity); // TGctrl [31-30] + TGnumber [29-6] + Reserved [5-0] UInt32 talkGroup = (uint)tgCtrl * 0x40000000 + tgNumber * 0x40 + 0x00; //return SDR_CallOut(ref cm_msg_id, sourceISSI, destISSI, callOut, talkGroup, data); return SDTS_CallOut(recFlag, ref cm_msg_id, sourceISSI, destISSI, callOut, talkGroup, data); } public static byte[] SDTS_CallOut(bool recFlag, ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI, UInt16 callOut, UInt32 talkGroup, string data) { int buflen = 0; if (data != null) buflen = data.Length; byte[] cmBytes = SDR_CM_COM_CallOut(ref cm_msg_id, sourceISSI, destISSI); byte[] tlBytes = SDTS_TLX_CallOut(callOut, talkGroup); CallOutFunction callOutFunction = (CallOutFunction)((callOut >> 12) & 0x0000f); if (callOutFunction == CallOutFunction.Test || callOutFunction == CallOutFunction.Info || callOutFunction == CallOutFunction.Clear) Array.Resize(ref tlBytes, tlBytes.Length - 7); // cut the buffer at the right length else if (callOutFunction == CallOutFunction.Availability || callOutFunction == CallOutFunction.AvailabilityRequest) Array.Resize(ref tlBytes, tlBytes.Length - 8); // compute the TL length in bits // the TL fields are taken into consideration (count starting with 'TL encoding scheme' and transform in bits (*8) ) ==> 9 fields if (tlBytes != null) { int headerLength = tlBytes[0] * 256 + tlBytes[1]; int tlLength = tlBytes.Length - headerLength; tlBytes[3] = (byte)((((buflen + tlLength) * 8) & 0xff00) >> 8); tlBytes[4] = (byte)(((buflen + tlLength) * 8) & 0x00ff); } // compute the CM length in bytes byte[] cmSize = new byte[2]; if (cmBytes != null) { int cmLength = cmBytes.Length + tlBytes.Length + buflen; cmSize[0] = (byte)((cmLength & 0xff00) >> 8); cmSize[1] = (byte)(cmLength & 0x00ff); } byte[] cmResult = Combine(cmSize, cmBytes); if (recFlag) tlBytes[6] = 0x80; if (buflen > 0) return Combine(cmResult, tlBytes, Encoding.UTF8.GetBytes(data)); return Combine(cmResult, tlBytes); } public static byte[] SDR_CM_COM_CallOut(ref byte cm_msg_id, UInt32 sourceISSI, UInt32 destISSI) { if (cm_msg_id > 0xfe) cm_msg_id = 0; cm_msg_id += 1; byte[] msg = { 0x17, //1 PDU Type 0x01, //2 Protocol version 0x00, //3 header length 0x34, //4 header length ( 52 bytes ) 0x40, //5 Next PDU Type ( SDTS_CM_TLX) 0x00,0x00,0x00,0x00,0x00, //6-10 Reserved 0x01, //11 Calling party type identifier (byte)(((UInt32)sourceISSI & 0xff0000)>>16), //12 source ISSI (byte)(((UInt32)sourceISSI & 0x00ff00)>>8), //13 source ISSI (byte)(((UInt32)sourceISSI & 0x0000ff)), //14 source ISSI 0x00,0x00,0x00, //15-17 Calling party extension 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //18-26 Reserved 0x01, //27 Calling party type identifier (byte)(((UInt32)destISSI & 0x00ff0000)>>16), //28 destination ISSI (byte)(((UInt32)destISSI & 0x0000ff00)>>8), //29 destination ISSI (byte)(((UInt32)destISSI & 0x000000ff)), //30 destination ISSI 0x00,0x00,0x00, //31-33 Calling party extension 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //34-42 Reserved 0xC3, //43 CM_PROTOCOL (CallOut), 0x60, //44 flags (SDS type=011 (7-5) | SS (4)| RV (3) | Reserved ( 2-1 )| CSV ( 0 ) cm_msg_id, //45 message reference 0x00, //46 Reserved 0x00, //47 Reserved (7-3)| GS (2)| PDCH (1) | MCCH (0) 0x00, //48 Reserved (7-1)| RR (0) 0x00,0x00, //49-50 Region selection 0x00,0x00 //51-52 Reserved }; return msg; } public static byte[] SDTS_TLX_CallOut(UInt16 callOut, UInt32 talkGroup) { byte[] callOutBytes = BitConverter.GetBytes(callOut); byte[] talkGroupBytes = BitConverter.GetBytes(talkGroup); byte[] msg = { 0x00, //01 Header length 0x11, //02 Header length 0xFF, //03 Next extension PDU type 0x00, //04 TL user data length 0x00, //05 TL user data length 0x04, //06 PDU type 0x00, //07 REC | CON | STO | TL forward adress type 0x00, //08 Validity period 0x00,0x00,0x00, //09-11 Forward address 0x00,0x00,0x00,0x00,0x00,0x00, //12-17 Reserved (byte)TextEncoding.ISO8859Latin1, //18 TL encoding scheme callOutBytes[1], //19 TL call out number + call out severity callOutBytes[0], //20 TL call out number + call out severity talkGroupBytes[3], //21 TL TG ( ctrl + number ) talkGroupBytes[2], //22 TL TG ( ctrl + number ) talkGroupBytes[1], //23 TL TG ( ctrl + number ) talkGroupBytes[0], //24 TL TG ( ctrl + number ) 0x00, //25 forward address 0x00, //26 forward address 0x00 //27 forward address }; return msg; } private static byte[] Combine(byte[] a, byte[] b) { byte[] result = new byte[a.Length + b.Length]; Buffer.BlockCopy(a, 0, result, 0, a.Length); Buffer.BlockCopy(b, 0, result, a.Length, b.Length); return result; } private static byte[] Combine(byte[] a, byte[] b, byte[] c) { byte[] result = new byte[a.Length + b.Length + c.Length]; Buffer.BlockCopy(a, 0, result, 0, a.Length); Buffer.BlockCopy(b, 0, result, a.Length, b.Length); Buffer.BlockCopy(c, 0, result, a.Length + b.Length, c.Length); return result; } } }