2685 lines
129 KiB
C#
2685 lines
129 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Threading;
|
|||
|
using System.Net.Sockets;
|
|||
|
using System.Net;
|
|||
|
using System.Runtime.Caching;
|
|||
|
using SafeMobileLib;
|
|||
|
|
|||
|
namespace MotoRepeater
|
|||
|
{
|
|||
|
public class Wireline
|
|||
|
{
|
|||
|
// all available operations
|
|||
|
public enum Operations
|
|||
|
{
|
|||
|
WL_REGISTRATION_REQUEST = 0x01,
|
|||
|
WL_REGISTRATION_STATUS = 0x02,
|
|||
|
WL_REGISTRATION_GENERAL_OPS = 0x03,
|
|||
|
WL_PROTOCOL_VERSION_QUERY = 0x04,
|
|||
|
WL_PROTOCOL_VERSION_QUERY_RESPONSE = 0x05,
|
|||
|
WL_CHNL_STATUS = 0x11,
|
|||
|
WL_CHNL_STATUS_QUERY = 0x12,
|
|||
|
WL_VC_CHNL_CTRL_REQUEST = 0x13,
|
|||
|
WL_VC_CHNL_CTRL_STATUS = 0x16,
|
|||
|
WL_VC_CSBK_CALL = 0x17,
|
|||
|
WL_VC_VOICE_START = 0x18,
|
|||
|
WL_VC_VOICE_END_BURST = 0X19,
|
|||
|
WL_VC_CALL_SESSION_STATUS = 0x20,
|
|||
|
WL_VC_VOICE_BURST = 0x21,
|
|||
|
WL_VC_PRIVACY_BURST = 0X22
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
private static byte[] AuthenticationID = new byte[] { 0x01, 0x02, 0x00, 0x6E };
|
|||
|
private static byte[] VendorKey = new byte[] { 0x85, 0x8a, 0x5e, 0xa6, 0x8c, 0xf9, 0xa9, 0x7f, 0x49, 0xc7,
|
|||
|
0x10, 0x87, 0xe7, 0xf2, 0xb4, 0x64, 0xd5, 0x9c, 0x52, 0x5d };
|
|||
|
|
|||
|
private static byte[] AuthenticationKey = new byte[] { 0x00 }; // set by the user in the repeater
|
|||
|
private static byte[] AuthenticationSignatureKey = new byte[40];
|
|||
|
|
|||
|
/* System variables */
|
|||
|
private Thread wirelineHandlerThread;
|
|||
|
public int majorWirelineProtocolVersion = 3;
|
|||
|
public byte wirelineProtocolVersion = 0x00;
|
|||
|
private bool isWirelineRegistered = false;
|
|||
|
private SlotNumber currentSlot = SlotNumber.BothSlots;
|
|||
|
private LinkEstablishment le;
|
|||
|
|
|||
|
/* CRT CALL VARIABLES */
|
|||
|
private CSBKCall crtCSBKCallStausSlot1 = new CSBKCall();
|
|||
|
private CSBKCall crtCSBKCallStausSlot2 = new CSBKCall();
|
|||
|
|
|||
|
// store the previous burst type in order to add the missing frames
|
|||
|
private int previousBrustTypeSlot1 = 0x06;
|
|||
|
private int previousBrustTypeSlot2 = 0x06;
|
|||
|
|
|||
|
|
|||
|
private byte currentWirelineProtocolVersion = 0x00;
|
|||
|
private byte oldestWirelineProtocolVersion = 0x00;
|
|||
|
|
|||
|
private MemoryCache mem = new MemoryCache("MotoTRBOCache");
|
|||
|
|
|||
|
public Wireline(LinkEstablishment linkEstablishment)
|
|||
|
{
|
|||
|
this.le = linkEstablishment;
|
|||
|
le.OnRegistrationResponseReceived += new LinkEstablishment.RegistrationResponseDEl(le_OnRegistrationResponseReceived);
|
|||
|
le.OnWirelineMessageReceived += new LinkEstablishment.WirelineMessageReceivedDEl(le_OnWirelineMessageReceived);
|
|||
|
|
|||
|
this.OnRadioStatusChanged += new RadioStatusChangedDEl(Wireline_OnRadioStatusChanged);
|
|||
|
this.OnCSBKCallReceived += new CSBKCallReceivedDEl(Wireline_OnCSBKCallReceived);
|
|||
|
this.OnChannelControlStatusReceived += new ChannelControlStatusReceivedDel(Wireline_OnChannelControlStatusReceived);
|
|||
|
this.OnCallSesionStatusReceived += new CallSessionStatusReceivedDEl(Wireline_OnCallSesionStatusReceived);
|
|||
|
|
|||
|
SetCurrentAndOldestWirelineProtocolVersion();
|
|||
|
|
|||
|
GenerateAuthenticationSignatureKey();
|
|||
|
|
|||
|
/* TEST WITH THE VALUES FROM MOTOROLA
|
|||
|
|
|||
|
AuthenticationID = new byte[] { 0x01, 0x01, 0x00, 0x2A };
|
|||
|
VendorKey = new byte[] { 0xcf, 0xd0, 0x25, 0xcb, 0x75, 0x60, 0xdb, 0x13, 0x5d, 0x70,
|
|||
|
0x2a, 0x20, 0x1e, 0x65, 0xd0, 0x30, 0x9f, 0xd2, 0xb3, 0xb2 };
|
|||
|
//AuthenticationKey = new byte[] { 0xAB, 0xCD }; // set by the user
|
|||
|
//AuthenticationSignatureKey = new byte[40];
|
|||
|
|
|||
|
GenerateAuthenticationSignatureKey();
|
|||
|
byte[] pdu;
|
|||
|
byte[] restp = AddWirelineSignatureKey(
|
|||
|
pdu = new byte[] { 0xb2, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x94, 0xb8, 0xcf, 0x00, 0x00, 0x01, 0x00, 0x01,
|
|||
|
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x04, 0x04}
|
|||
|
);
|
|||
|
|
|||
|
//*/
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* When a new Wireline Message is received by the Link Establishment */
|
|||
|
void le_OnWirelineMessageReceived(byte[] received, string peerIP, Int32 peerPort)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
decode(received, peerIP, peerPort);
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
Console.Write("\n\n " + ex.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void le_OnRegistrationResponseReceived(bool isValid)
|
|||
|
{
|
|||
|
if (isValid)
|
|||
|
{
|
|||
|
Utils.WriteLine("LE Registered. Starting Wireline registration...");
|
|||
|
|
|||
|
List<RegEntry> regEntries = new List<RegEntry>();
|
|||
|
regEntries.Add(new RegEntry(AddressType.AllIndividualCall, 1, 16777215));
|
|||
|
regEntries.Add(new RegEntry(AddressType.AllTalkgroupCall, 1, 16777215));
|
|||
|
regEntries.Add(new RegEntry(AddressType.AllLocalTalkgroupsCall, 1, 16777215));
|
|||
|
regEntries.Add(new RegEntry(AddressType.AllWideTakgroupsCall, 1, 16777215));
|
|||
|
//reg.regEntriesList.Add(new RegEntry(AddressType.GroupCall, 1, 1024));
|
|||
|
|
|||
|
Register(le.GetRegisteredSlots(), regEntries);
|
|||
|
//le.SendLEMessage(createWirelineMessage(Operations.WL_REGISTRATION_REQUEST, reg));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// set the current and oldest wireline Protocol Version
|
|||
|
private void SetCurrentAndOldestWirelineProtocolVersion()
|
|||
|
{
|
|||
|
// clear previous values
|
|||
|
currentWirelineProtocolVersion = 0x00;
|
|||
|
oldestWirelineProtocolVersion = 0x00;
|
|||
|
|
|||
|
// create two 'bit' arrays for System ID and Protocol Version
|
|||
|
bool[] systemID = new bool[6];
|
|||
|
bool[] protocolVers = new bool[10];
|
|||
|
bool[] oldestProtocolVers = new bool[10];
|
|||
|
|
|||
|
switch (le.systemType)
|
|||
|
{
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.IP_SITE_CONNECT:
|
|||
|
{
|
|||
|
systemID = new bool[] { false, false, false, false, false, true };
|
|||
|
break;
|
|||
|
}
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.CAPACITY_PLUS:
|
|||
|
{
|
|||
|
systemID = new bool[] { false, false, false, false, true, false };
|
|||
|
break;
|
|||
|
}
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.LINKED_CAPACITY_PLUS:
|
|||
|
{
|
|||
|
systemID = new bool[] { false, false, false, true, false, false };
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
switch (le.releaseNumber)
|
|||
|
{
|
|||
|
case MotoRepeater.LinkEstablishment.SystemReleaseNumber.R23A:
|
|||
|
{
|
|||
|
majorWirelineProtocolVersion = 3;
|
|||
|
wirelineProtocolVersion = 0x0C; // 0b00000100
|
|||
|
break;
|
|||
|
}
|
|||
|
case MotoRepeater.LinkEstablishment.SystemReleaseNumber.R23:
|
|||
|
case MotoRepeater.LinkEstablishment.SystemReleaseNumber.R22:
|
|||
|
{
|
|||
|
majorWirelineProtocolVersion = 1;
|
|||
|
wirelineProtocolVersion = 0x04; // 0b00001100
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
currentWirelineProtocolVersion = wirelineProtocolVersion;
|
|||
|
oldestWirelineProtocolVersion = 0x04;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// function which will generate the authentication Signature KEY which is used as HMAC-SHA1 key for
|
|||
|
// generating the Authentication Signature bytes which are added to each Call Control Wireline Messages
|
|||
|
private void GenerateAuthenticationSignatureKey()
|
|||
|
{
|
|||
|
List<byte> authSign = new List<byte>();
|
|||
|
authSign.AddRange(VendorKey);
|
|||
|
|
|||
|
// padd with zeros
|
|||
|
for (int i = 0; i < 20 - AuthenticationKey.Length; i++)
|
|||
|
{
|
|||
|
authSign.Add(0x00);
|
|||
|
}
|
|||
|
|
|||
|
foreach (byte by in AuthenticationKey)
|
|||
|
authSign.Add(by);
|
|||
|
|
|||
|
// save the authentication signature key which is compute from the Vendor Key and Authentication Key
|
|||
|
AuthenticationSignatureKey = authSign.ToArray();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the byte array which needs to be send, already containing the wireline authentication signature
|
|||
|
/// </summary>
|
|||
|
/// <param name="wirelineMessage">the byte array which will be used used for genereting the Wireline Signature Key</param>
|
|||
|
/// <returns>A byte array containing the original byte array followed by the Authentication ID [Motorola Provided] and
|
|||
|
/// the Authentication Signature Key [Generated using HMACSha1 algoritm]</returns>
|
|||
|
private byte[] AddWirelineSignatureKey(byte[] wirelineMessage)
|
|||
|
{
|
|||
|
// encrypts the wireline messages using Authentication Signature as the key
|
|||
|
System.Security.Cryptography.HMACSHA1 hmacSha1 = new System.Security.Cryptography.HMACSHA1(AuthenticationSignatureKey);
|
|||
|
hmacSha1.ComputeHash(wirelineMessage);
|
|||
|
|
|||
|
// trim the authentication signature to only 10 bytes
|
|||
|
byte[] truncatedAuthenticationSignature = new byte[10];
|
|||
|
for (int i = 0; i < 10; i++)
|
|||
|
truncatedAuthenticationSignature[i] = hmacSha1.Hash[i];
|
|||
|
|
|||
|
// add Authentication Key and Authentication Signature to the end of the wireline message
|
|||
|
List<byte> resp = new List<byte>(wirelineMessage);
|
|||
|
resp.AddRange(AuthenticationID);
|
|||
|
resp.AddRange(truncatedAuthenticationSignature);
|
|||
|
|
|||
|
// return the complete wireline message
|
|||
|
return resp.ToArray();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#region WIRELINE MESSAGES
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Wireline registration procedure. This procedure creats the wireline message which will be sent to the
|
|||
|
/// repeater in order to create the wireline registration
|
|||
|
/// </summary>
|
|||
|
/// <param name="slot">The slot on which the wireline registration is required</param>
|
|||
|
/// <param name="regEntriesList">The list of entries for which the call messages will be received and parsed</param>
|
|||
|
public void Register(SlotNumber slot, List<RegEntry> regEntriesList)
|
|||
|
{
|
|||
|
// create a wireline registration object and populate it with the required values
|
|||
|
WirelineRegistration reg = new WirelineRegistration();
|
|||
|
reg.slotNumber = slot;
|
|||
|
reg.wirelineChannelStatus = Wireline.WirelineChannelStatus.NotRegisteredWLStatus;
|
|||
|
// copy all registry
|
|||
|
foreach (RegEntry regEntry in regEntriesList)
|
|||
|
reg.regEntriesList.Add(regEntry);
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_REGISTRATION_REQUEST, reg));
|
|||
|
// send wireline message to the repeater
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Deregister a prior registration on a desired slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="slot">The slot on which the wireline registration was done</param>
|
|||
|
public void DeRegister(SlotNumber slot)
|
|||
|
{
|
|||
|
WirelineQueryRegistration queryReg = new WirelineQueryRegistration();
|
|||
|
queryReg.regOpCode = RegistrationOperationCode.DeRegister;
|
|||
|
queryReg.slotNumber = slot;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_REGISTRATION_GENERAL_OPS, queryReg));
|
|||
|
|
|||
|
// send wireline message to the repeater
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
// query a prior registration to find out the Identifier of the registration
|
|||
|
public void QueryRegistration(SlotNumber slot)
|
|||
|
{
|
|||
|
WirelineQueryRegistration queryReg = new WirelineQueryRegistration();
|
|||
|
queryReg.regOpCode = RegistrationOperationCode.QueryRegStatus;
|
|||
|
queryReg.slotNumber = slot;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_REGISTRATION_GENERAL_OPS, queryReg));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
// check what protocol version is supported by the repeater
|
|||
|
public void ProtocolVersionQuery()
|
|||
|
{
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_PROTOCOL_VERSION_QUERY, null));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
// request status from the repeater about the rest channel or conventional channel
|
|||
|
// depending on the system type
|
|||
|
public void ChannelStatusReq(SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.slotNumber = slot;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_CHNL_STATUS_QUERY, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
#region ENABLE/DISABLE
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Enable a radio on a specific slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the unit which needs to be enabled</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void EnableRadioOnSlot(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.slotNumber = slot;
|
|||
|
call.callType = CallType.RadioUninhibitRequest;
|
|||
|
call.sourceID = le.myselfPeer.peerID;
|
|||
|
call.targetID = radioID;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Enable a radio on the current slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the unit which needs to be enabled</param>
|
|||
|
public void EnableRadio(Int64 radioID)
|
|||
|
{
|
|||
|
EnableRadioOnSlot(radioID, GetCurrentSlot());
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Disable a radio on a specific slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the unit which needs to be disabled</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void DisableRadioOnSlot(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.slotNumber = slot;
|
|||
|
call.callType = CallType.RadioInhibitRequest;
|
|||
|
call.sourceID = le.myselfPeer.peerID;
|
|||
|
call.targetID = radioID;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
// if thread allready exists I should send the commnad only once
|
|||
|
if (mem.Contains(String.Format("{0}.{1}", radioID, slot)))
|
|||
|
{
|
|||
|
// get the thread and reset the counter to 0
|
|||
|
//Thread running = (Thread)mem.Get(String.Format("{0}.{1}", radioID, slot));
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// create a thread which will resend the message after 3 seconds
|
|||
|
Thread p = new Thread(() =>
|
|||
|
{
|
|||
|
// save the message which needs to be sent
|
|||
|
byte[] toSendd = (byte[])toSend.Clone();
|
|||
|
Int64 radioIDD = radioID;
|
|||
|
SlotNumber slott = slot;
|
|||
|
|
|||
|
int count = 0;
|
|||
|
// run this procedure for three times or while the answer is received from the repeater
|
|||
|
while (mem.Contains(String.Format("{0}.{1}", radioID, slot)))
|
|||
|
{
|
|||
|
Thread.CurrentThread.IsBackground = true;
|
|||
|
|
|||
|
// send wireline message each 3 seconds
|
|||
|
if (count++ % 30 == 0)
|
|||
|
{
|
|||
|
//Utils.WriteLine(String.Format("Thread {0}.{1} is alive", radioID, slot));
|
|||
|
SendWirelineMessage(toSendd);
|
|||
|
}
|
|||
|
Thread.Sleep(100); // sleep 100 ms
|
|||
|
}
|
|||
|
//Utils.WriteLine(String.Format("Thread {0}.{1} ended", radioID, slot));
|
|||
|
});
|
|||
|
p.Name = String.Format("{0}.{1}", radioID, slot);
|
|||
|
p.Start();
|
|||
|
|
|||
|
// add thread to the memory cache and set live duration to 10 seconds
|
|||
|
mem.Add(p.Name, p, new CacheItemPolicy() { AbsoluteExpiration = DateTime.UtcNow.AddSeconds(10) });
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Disable a radio on the current slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the unit which needs to be disabled</param>
|
|||
|
public void DisableRadio(Int64 radioID)
|
|||
|
{
|
|||
|
DisableRadioOnSlot(radioID, GetCurrentSlot());
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Event Callback for when a radio changes its status to Enable or Disable.
|
|||
|
/// This callback will have to remove the thread that sends the Inhibit [disable] request from memCache
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio which changed its status</param>
|
|||
|
/// <param name="slot">The slot on which the radio had reported</param>
|
|||
|
/// <param name="isEnabled">The radio state. Will be true if the radio is Enabled or false otherwise</param>
|
|||
|
void Wireline_OnRadioStatusChanged(long radioID, Wireline.SlotNumber slot, bool isEnabled)
|
|||
|
{
|
|||
|
// close the thread which sends the Inhibit [disble] command, if exists
|
|||
|
if (!isEnabled && mem.Contains(String.Format("{0}.{1}", radioID, slot)))
|
|||
|
{
|
|||
|
mem.Remove(String.Format("{0}.{1}", radioID, slot));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Acknowledge an emergency received from a field radio on the current selected slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The field radio which had sent the emergency</param>
|
|||
|
public void EmergencyAck(Int64 radioID)
|
|||
|
{
|
|||
|
EmergencyACKOnSlot(radioID, GetCurrentSlot());
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Acknowledge an emergency received from a field radio
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The field radio which had sent the emergency</param>
|
|||
|
/// <param name="slot">The slot on which the request will be sent</param>
|
|||
|
public void EmergencyACKOnSlot(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
// response to Emergency with Emerg ACK
|
|||
|
CSBKCall csbkCall = new CSBKCall();
|
|||
|
csbkCall.slotNumber = slot;
|
|||
|
csbkCall.sourceID = le.myselfPeer.peerID;
|
|||
|
csbkCall.targetID = radioID;
|
|||
|
csbkCall.callType = CallType.EmergencyCSBKAlertResponse;
|
|||
|
|
|||
|
this.SendWirelineMessage(AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, csbkCall)));
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region CALL
|
|||
|
/// <summary>
|
|||
|
/// Initiate a private call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the field station which needs to be called</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void InitiatePrivateCallOnSlot(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.PrivateCallRequest;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = (slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID);
|
|||
|
call.targetID = radioID;
|
|||
|
|
|||
|
if ((slot == SlotNumber.Slot1 && crtCSBKCallStausSlot1 != null) ||
|
|||
|
(slot == SlotNumber.Slot2 && crtCSBKCallStausSlot2 != null))
|
|||
|
{
|
|||
|
// save current call parameters
|
|||
|
crtCSBKCallStausSlot1 = call;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void InitiatePrivateCallOnSlotAfterPreamble(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.PrivateCallResponse;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = (slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID);
|
|||
|
call.targetID = radioID;
|
|||
|
call.callAttributes = CallAttributes.SmartAfterPreamble;
|
|||
|
|
|||
|
if ((slot == SlotNumber.Slot1 && crtCSBKCallStausSlot1 != null) ||
|
|||
|
(slot == SlotNumber.Slot2 && crtCSBKCallStausSlot2 != null))
|
|||
|
{
|
|||
|
// save current call parameters
|
|||
|
crtCSBKCallStausSlot1 = call;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Terminate a private call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="radioID">The radio ID of the field station which needs to end the call</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void EndPrivateCallOnSlot(Int64 radioID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.PrivateCallRequest;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID;
|
|||
|
call.targetID = radioID;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initiate a group call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="groupID">The group ID of the field stations which needs to be called</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void InitiateGroupCallOnSlot(Int64 groupID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.GroupVoiceCall;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID;
|
|||
|
call.targetID = groupID;
|
|||
|
|
|||
|
// save current call parameters
|
|||
|
crtCSBKCallStausSlot1 = call;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Terminate a group call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="groupID">The group ID of the field stations which needs to end the call</param>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void EndGroupCallOnSlot(Int64 groupID, SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.GroupVoiceCall;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID;
|
|||
|
call.targetID = groupID;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initiate an all call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void InitiateAllCallOnSlot(SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.AllCall;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID;
|
|||
|
call.targetID = 16777215;
|
|||
|
|
|||
|
// save current call parameters
|
|||
|
crtCSBKCallStausSlot1 = call;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Terminate an all call on the specified slot
|
|||
|
/// </summary>
|
|||
|
/// <param name="slot">Slot number on which the request will be sent</param>
|
|||
|
public void EndAllCallOnSlot(SlotNumber slot)
|
|||
|
{
|
|||
|
CSBKCall call = new CSBKCall();
|
|||
|
call.callType = CallType.AllCall;
|
|||
|
call.preambleDuration = PreambleDuration.BurstDurationMS;
|
|||
|
call.preambleValue = 0x03;
|
|||
|
call.slotNumber = slot;
|
|||
|
call.sourceID = slot == SlotNumber.Slot1 ? le.myselfPeer.slot1ID : le.myselfPeer.slot2ID;
|
|||
|
call.targetID = 16777215;
|
|||
|
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_CHNL_CTRL_REQUEST, call));
|
|||
|
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Event Callback for a channel control status received. The event is triggered each time a call changes
|
|||
|
/// it's status, this is equal to channel status had changed
|
|||
|
/// </summary>
|
|||
|
/// <param name="sourceID">The radio ID of the field radio which had initiated the call</param>
|
|||
|
/// <param name="targetID">The radio ID of the field radio which had been called</param>
|
|||
|
/// <param name="callType">The type of call which is in progress/was made</param>
|
|||
|
/// <param name="chnCtrlStatus">The status of the channel </param>
|
|||
|
/// <param name="slot">The slot on which the call was made</param>
|
|||
|
void Wireline_OnChannelControlStatusReceived(Int64 callID, CallType callType, ChannelControlStatus chnCtrlStatus, SlotNumber slot)
|
|||
|
{
|
|||
|
// call has been accepted and I can send voice as from the docs/Smart Wireshark
|
|||
|
if (chnCtrlStatus == ChannelControlStatus.SmartInProgress)
|
|||
|
{
|
|||
|
Thread p = new Thread(new ThreadStart(CSBKVoiceCall));
|
|||
|
p.Start();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Event Callback for a call session status received. The event is triggered each time a call is transmited,
|
|||
|
/// declined etc.
|
|||
|
/// </summary>
|
|||
|
/// <param name="sourceID">The radio ID of the field radio which had initiated the call</param>
|
|||
|
/// <param name="targetID">The radio ID of the field radio which had been called</param>
|
|||
|
/// <param name="callType">The type of call which is in progress/was made</param>
|
|||
|
/// <param name="callSessionStatus">The status of the call on Transportation Layer</param>
|
|||
|
/// <param name="slot">The slot on which the call was made</param>
|
|||
|
void Wireline_OnCallSesionStatusReceived(Int64 sourceID, Int64 targertID, CallType callType, CallSessionStatus callSessionStatus, SlotNumber slot)
|
|||
|
{
|
|||
|
// get csbkCall for current slot number
|
|||
|
CSBKCall crtCSBKCall = (slot == SlotNumber.Slot1 ? crtCSBKCallStausSlot1 : crtCSBKCallStausSlot2);
|
|||
|
|
|||
|
// I should resend the call request because the call is hanged as a result of a CSBK Preamble recieved
|
|||
|
if (callSessionStatus == CallSessionStatus.CallHang && crtCSBKCall.isCSBKPreambleReceived)
|
|||
|
{
|
|||
|
switch (crtCSBKCall.callType)
|
|||
|
{
|
|||
|
// initiate the all call on selected slot
|
|||
|
case CallType.AllCall:
|
|||
|
InitiateAllCallOnSlot(slot);
|
|||
|
break;
|
|||
|
|
|||
|
// initiate the group call on selected slot
|
|||
|
case CallType.GroupVoiceCall:
|
|||
|
InitiateGroupCallOnSlot(crtCSBKCall.targetID, slot);
|
|||
|
break;
|
|||
|
|
|||
|
// initiate the private call on selected slot
|
|||
|
case CallType.PrivateCallRequest:
|
|||
|
InitiatePrivateCallOnSlotAfterPreamble(crtCSBKCall.targetID, slot);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
crtCSBKCall.isCSBKPreambleReceived = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="callID"></param>
|
|||
|
/// <param name="isAccepted"></param>
|
|||
|
private void Wireline_OnCSBKCallReceived(Int64 sourceID, Int64 targetID, CallType callType, SlotNumber slot)
|
|||
|
{
|
|||
|
// get csbkCall for current slot number
|
|||
|
CSBKCall crtCSBKCall = (slot == SlotNumber.Slot1 ? crtCSBKCallStausSlot1 : crtCSBKCallStausSlot2);
|
|||
|
|
|||
|
// flag that the Preamble CSBK was received and I can now resend the cmd when the hang status is received
|
|||
|
crtCSBKCall.isCSBKPreambleReceived = true;
|
|||
|
}
|
|||
|
|
|||
|
private void CSBKVoiceCall()
|
|||
|
{
|
|||
|
for(int i=0; i<30; i++)
|
|||
|
{
|
|||
|
CSBKCall csbkCall = new CSBKCall();
|
|||
|
csbkCall.slotNumber = SlotNumber.Slot1;
|
|||
|
// add Authentication Signature to the wireline message
|
|||
|
byte[] toSend = AddWirelineSignatureKey(createWirelineMessage(Operations.WL_VC_VOICE_BURST, csbkCall));
|
|||
|
Thread.Sleep(100);
|
|||
|
SendWirelineMessage(toSend);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
// return the current slot number
|
|||
|
public SlotNumber GetCurrentSlot()
|
|||
|
{
|
|||
|
return currentSlot;
|
|||
|
}
|
|||
|
|
|||
|
public SlotNumber GetSlotNumber(int slotNumber)
|
|||
|
{
|
|||
|
switch (slotNumber)
|
|||
|
{
|
|||
|
case 1: return SlotNumber.Slot1;
|
|||
|
case 2: return SlotNumber.Slot2;
|
|||
|
case 3: return SlotNumber.BothSlots;
|
|||
|
case 0:
|
|||
|
{
|
|||
|
if (le.systemType == LinkEstablishment.SystemType.IP_SITE_CONNECT)
|
|||
|
return SlotNumber.SiteIPAddress;
|
|||
|
else if (le.systemType == LinkEstablishment.SystemType.CAPACITY_PLUS)
|
|||
|
return SlotNumber.RestChannel;
|
|||
|
else
|
|||
|
return SlotNumber.BothSlots;
|
|||
|
}
|
|||
|
default: return SlotNumber.BothSlots;
|
|||
|
}
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
private Int32 csbkCallParam1 = 0x7bee;
|
|||
|
private Int32 csbkCallParam2 = 0x3178;
|
|||
|
private Int32 csbkCallParam3 = 0x94;
|
|||
|
private Int32 csbkCallParam4 = 0x2A;
|
|||
|
private static int val = 0x01;
|
|||
|
|
|||
|
private byte[] createWirelineMessage(Operations operation, Object parameters)
|
|||
|
{
|
|||
|
List<byte> responseList = new List<byte>();
|
|||
|
// opCode
|
|||
|
responseList.Add(0xB2);
|
|||
|
// ID of the sending peer = me
|
|||
|
responseList.Add(BitConverter.GetBytes(le.myselfPeer.peerID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(le.myselfPeer.peerID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(le.myselfPeer.peerID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(le.myselfPeer.peerID)[0]);
|
|||
|
// increment registration PDU number
|
|||
|
if (operation == Operations.WL_REGISTRATION_REQUEST ||
|
|||
|
operation == Operations.WL_REGISTRATION_GENERAL_OPS)
|
|||
|
WirelineRegistration.registrationPduID++;
|
|||
|
|
|||
|
byte[] response = { };
|
|||
|
switch (operation)
|
|||
|
{
|
|||
|
#region WL_REGISTRATION_REQUEST
|
|||
|
case Operations.WL_REGISTRATION_REQUEST:
|
|||
|
{
|
|||
|
WirelineRegistration wireReg = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// get the paramerets in the correct form
|
|||
|
wireReg = (WirelineRegistration)parameters;
|
|||
|
}
|
|||
|
catch (Exception)
|
|||
|
{
|
|||
|
// THROW AN EXCEPTION
|
|||
|
return new byte[0];
|
|||
|
}
|
|||
|
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_REGISTRATION_REQUEST);
|
|||
|
|
|||
|
/* registrationSlotNumber - Only for de-register operation in SS/IPSC mode */
|
|||
|
if (le.systemType == LinkEstablishment.SystemType.LINKED_CAPACITY_PLUS)
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
else
|
|||
|
responseList.Add((byte)wireReg.slotNumber);
|
|||
|
|
|||
|
/* registrationPduID - The identifier of the registration PDU [Uint32] */
|
|||
|
responseList.Add(BitConverter.GetBytes(WirelineRegistration.registrationPduID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(WirelineRegistration.registrationPduID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(WirelineRegistration.registrationPduID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(WirelineRegistration.registrationPduID)[0]);
|
|||
|
|
|||
|
/* registrationID - The identifier associated with the registration profile in this PDU. [Uint16] */
|
|||
|
responseList.Add(BitConverter.GetBytes(wireReg.registrationID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(wireReg.registrationID)[0]);
|
|||
|
|
|||
|
/* wirelineStatusRegistration - Registration flag for Wireline Channel Status [Uint8] */
|
|||
|
responseList.Add((byte)wireReg.wirelineChannelStatus);
|
|||
|
|
|||
|
/* numberOfRegistrationEntries - Number of registration entries in this registration message [Uint8] */
|
|||
|
responseList.Add((byte)wireReg.regEntriesList.Count);
|
|||
|
|
|||
|
foreach (RegEntry entity in wireReg.regEntriesList)
|
|||
|
{
|
|||
|
/* AddressType - Address type of the call being registered in this entry */
|
|||
|
responseList.Add((byte)entity.addressType);
|
|||
|
|
|||
|
/* addressRangeStart - Start of radio/group addresses (CAI ID) range in this entry [Uint32] */
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeStart)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeStart)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeStart)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeStart)[0]);
|
|||
|
|
|||
|
/* addressRangeEnd - Start of radio/group addresses (CAI ID) range in this entry [Uint32] */
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeEnd)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeEnd)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeEnd)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(entity.addressRangeEnd)[0]);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x80);
|
|||
|
|
|||
|
/* CSBK Attributes - Attributes of CSBK Registration in this entry */
|
|||
|
responseList.Add((byte)entity.csbkAttributes);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
}
|
|||
|
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_REGISTRATION_GENERAL_OPS
|
|||
|
case Operations.WL_REGISTRATION_GENERAL_OPS:
|
|||
|
{
|
|||
|
WirelineQueryRegistration queryReg = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// get the paramerets in the correct form
|
|||
|
queryReg = (WirelineQueryRegistration)parameters;
|
|||
|
}
|
|||
|
catch (Exception)
|
|||
|
{
|
|||
|
// THROW AN EXCEPTION
|
|||
|
return new byte[0];
|
|||
|
}
|
|||
|
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_REGISTRATION_GENERAL_OPS);
|
|||
|
|
|||
|
/* registrationSlotNumber - Only for de-register operation in SS/IPSC mode */
|
|||
|
if(le.systemType == LinkEstablishment.SystemType.IP_SITE_CONNECT && queryReg.regOpCode == RegistrationOperationCode.DeRegister)
|
|||
|
responseList.Add((byte)queryReg.slotNumber);
|
|||
|
else
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* registrationPduID - The identifier of the registration PDU [Uint32] */
|
|||
|
responseList.Add(BitConverter.GetBytes(queryReg.registrationPduID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryReg.registrationPduID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryReg.registrationPduID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryReg.registrationPduID)[0]);
|
|||
|
|
|||
|
/* registrationOperationOpcode - The registration Operation Code [Uint8] */
|
|||
|
responseList.Add((byte)queryReg.regOpCode);
|
|||
|
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_PROTOCOL_VERSION_QUERY
|
|||
|
case Operations.WL_PROTOCOL_VERSION_QUERY:
|
|||
|
{
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_PROTOCOL_VERSION_QUERY);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* query ID - ID of the protocol version query PDU. Response from the repeater
|
|||
|
* pertaining to this message has the same Query ID value */
|
|||
|
responseList.Add(BitConverter.GetBytes(queryID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(queryID)[0]);
|
|||
|
|
|||
|
//increment query id
|
|||
|
queryID++;
|
|||
|
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_CHNL_STATUS_QUERY
|
|||
|
case Operations.WL_CHNL_STATUS_QUERY:
|
|||
|
{
|
|||
|
CSBKCall call = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// get the paramerets in the correct form
|
|||
|
call = (CSBKCall)parameters;
|
|||
|
}
|
|||
|
catch (Exception)
|
|||
|
{
|
|||
|
// THROW AN EXCEPTION
|
|||
|
return new byte[0];
|
|||
|
}
|
|||
|
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_CHNL_STATUS_QUERY);
|
|||
|
|
|||
|
/* slot number - Specifies the channel/slot reporting the channel status.*/
|
|||
|
responseList.Add((byte)call.slotNumber);
|
|||
|
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_CHNL_CTRL_REQUEST
|
|||
|
/*
|
|||
|
* This message is sent from the third party applications to the repeater peer to initial the
|
|||
|
* CSBK call or send CSBK call response
|
|||
|
*/
|
|||
|
case Operations.WL_VC_CHNL_CTRL_REQUEST:
|
|||
|
{
|
|||
|
CSBKCall call = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// get the paramerets in the correct form
|
|||
|
call = (CSBKCall)parameters;
|
|||
|
}
|
|||
|
catch (Exception )
|
|||
|
{
|
|||
|
// THROW AN EXCEPTION
|
|||
|
return new byte[0];
|
|||
|
}
|
|||
|
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_VC_CHNL_CTRL_REQUEST);
|
|||
|
|
|||
|
/* slot number - Specifies the channel/slot reporting the channel status */
|
|||
|
responseList.Add((byte)call.slotNumber);
|
|||
|
|
|||
|
/* call ID */
|
|||
|
responseList.Add(BitConverter.GetBytes(call.callID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.callID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.callID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.callID)[0]);
|
|||
|
|
|||
|
/* callType - The type of call */
|
|||
|
responseList.Add((byte)call.callType);
|
|||
|
|
|||
|
/* source ID - The ID of the subscriber that initiated the call */
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[0]);
|
|||
|
|
|||
|
/* target ID - The ID of the subscriber that initiated the call */
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[0]);
|
|||
|
|
|||
|
/* accessCriteria - The priority type to access the channel */
|
|||
|
responseList.Add((byte)call.accessCriteria);
|
|||
|
|
|||
|
/* callAttributes - General Call Attributes */
|
|||
|
responseList.Add((byte)call.callAttributes);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* preambleDuration - Only available for CSBK Call.
|
|||
|
* The numbers of Preamble bursts send before transmission. */
|
|||
|
if (call.preambleDuration.ToString().Contains("BurstDurationMS"))
|
|||
|
responseList.Add((byte)call.preambleValue);
|
|||
|
else
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* CSBK Arguments - Only available for CSBK call
|
|||
|
* The arguments encoded in the DMR CSBK burst [Uint64] */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00); // reserved
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
/*
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.targetID)[0]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(call.sourceID)[0]);
|
|||
|
*/
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_VOICE_BURST
|
|||
|
/*
|
|||
|
* This message is sent from the third party applications to the repeater peer containing
|
|||
|
* all the voice data [I hope: pray]
|
|||
|
*/
|
|||
|
case Operations.WL_VC_VOICE_BURST:
|
|||
|
{
|
|||
|
CSBKCall crtCSBKCall = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// get the paramerets in the correct form
|
|||
|
crtCSBKCall = (CSBKCall)parameters;
|
|||
|
|
|||
|
// set current csbk call values depending on the slot
|
|||
|
crtCSBKCall = (crtCSBKCall.slotNumber == SlotNumber.Slot1 ? crtCSBKCallStausSlot1 : crtCSBKCallStausSlot2);
|
|||
|
}
|
|||
|
catch (Exception)
|
|||
|
{
|
|||
|
// THROW AN EXCEPTION
|
|||
|
return new byte[0];
|
|||
|
}
|
|||
|
|
|||
|
/* Wireline Operation Code*/
|
|||
|
responseList.Add((byte)Operations.WL_VC_VOICE_BURST);
|
|||
|
|
|||
|
/* slot number - Specifies the channel/slot reporting the channel status */
|
|||
|
responseList.Add((byte)crtCSBKCall.slotNumber);
|
|||
|
|
|||
|
/* call ID */
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.crtCallID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.crtCallID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.crtCallID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.crtCallID)[0]);
|
|||
|
|
|||
|
/* callType - The type of call */
|
|||
|
responseList.Add((byte)crtCSBKCall.callType);
|
|||
|
|
|||
|
/* source ID - The ID of the subscriber that initiated the call */
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.sourceID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.sourceID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.sourceID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.sourceID)[0]);
|
|||
|
|
|||
|
/* target ID - The ID of the subscriber that initiated the call */
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.targetID)[3]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.targetID)[2]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.targetID)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(crtCSBKCall.targetID)[0]);
|
|||
|
|
|||
|
/* RESERVED ? ? ? */
|
|||
|
responseList.Add(0xA0);
|
|||
|
|
|||
|
/* RESERVED */
|
|||
|
responseList.Add(0x00);
|
|||
|
|
|||
|
/* callAttributes or Preamble Duration */
|
|||
|
responseList.Add((byte)crtCSBKCall.callAttributes);
|
|||
|
|
|||
|
/* Reserved field */
|
|||
|
responseList.Add((byte)0x5D);
|
|||
|
|
|||
|
/* CSBK Field Param 1 */
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam1)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam1)[0]);
|
|||
|
csbkCallParam1++;
|
|||
|
|
|||
|
/* CSBK Field Param 2 */
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam2)[1]);
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam2)[0]);
|
|||
|
|
|||
|
/* CSBK Field Param 3 */
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam3)[0]);
|
|||
|
csbkCallParam3 = csbkCallParam3 + 0x02;
|
|||
|
|
|||
|
/* CSBK Field Param 4 */
|
|||
|
responseList.Add(BitConverter.GetBytes(csbkCallParam4)[0]);
|
|||
|
csbkCallParam4 = csbkCallParam4 - 0x20;
|
|||
|
|
|||
|
/* CSBK Arguments - Only available for CSBK call
|
|||
|
* The arguments encoded in the DMR CSBK burst [Uint64] */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00); // reserved
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* Seqeuence number */
|
|||
|
responseList.Add((byte)(val++ % 6));
|
|||
|
|
|||
|
/* 10 RESERVED Fields */
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
responseList.Add((byte)0x00);
|
|||
|
|
|||
|
/* add 19 bytes for voice ??? */
|
|||
|
responseList.AddRange(new byte[] { 0xb8, 0x34, 0xb3, 0x87, 0xa2, 0xa2, 0xb6, 0x0e, 0x29, 0x8b, 0x99, 0x80, 0xcd, 0x83, 0xb0, 0x39, 0x94, 0x59, 0xc0 });
|
|||
|
|
|||
|
/* RESERVED */
|
|||
|
responseList.Add(0x00);
|
|||
|
responseList.Add(0x00);
|
|||
|
|
|||
|
|
|||
|
/* Current or Accepted Wireline Protocol Version */
|
|||
|
responseList.Add(currentWirelineProtocolVersion);
|
|||
|
responseList.Add(oldestWirelineProtocolVersion);
|
|||
|
|
|||
|
// convert the list of bytes to a byte array
|
|||
|
response = new byte[responseList.Count];
|
|||
|
for (int i = 0; i < responseList.Count; i++)
|
|||
|
response[i] = responseList[i];
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
}
|
|||
|
|
|||
|
return response;
|
|||
|
}
|
|||
|
|
|||
|
public void decode(byte[] toDecode, string peerIP, Int32 peerPort)
|
|||
|
{
|
|||
|
int crtPosition = 0;
|
|||
|
byte opCode = toDecode[crtPosition++];
|
|||
|
|
|||
|
// first opCode is for a CSBK Call message
|
|||
|
//if (opCode != 0xB2)
|
|||
|
// return;
|
|||
|
|
|||
|
/* get peerID */
|
|||
|
byte[] remotePeerID = new byte[4];
|
|||
|
remotePeerID[3] = toDecode[crtPosition++];
|
|||
|
remotePeerID[2] = toDecode[crtPosition++];
|
|||
|
remotePeerID[1] = toDecode[crtPosition++];
|
|||
|
remotePeerID[0] = toDecode[crtPosition++];
|
|||
|
Int64 peerID = BitConverter.ToUInt32(remotePeerID, 0);
|
|||
|
|
|||
|
byte wirelineOpCode = toDecode[crtPosition++];
|
|||
|
Utils.WriteLine("");
|
|||
|
Utils.WriteLine(String.Format("»»» {0}", GetMessageType(wirelineOpCode)), ConsoleColor.Yellow);
|
|||
|
|
|||
|
//Utils.WriteLine(Utils.printBytesArray(toDecode));
|
|||
|
|
|||
|
switch (wirelineOpCode)
|
|||
|
{
|
|||
|
#region WL_REGISTRATION_STATUS
|
|||
|
case (byte)Operations.WL_REGISTRATION_STATUS:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// identifier of the registration PDU [Uint32]
|
|||
|
byte[] registrationPduID = new byte[4];
|
|||
|
registrationPduID[3] = toDecode[crtPosition++];
|
|||
|
registrationPduID[2] = toDecode[crtPosition++];
|
|||
|
registrationPduID[1] = toDecode[crtPosition++];
|
|||
|
registrationPduID[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
Int64 registrPduID = BitConverter.ToUInt32(registrationPduID, 0);
|
|||
|
|
|||
|
// identifier associated with the registration profile in this PDU [Uint16]
|
|||
|
byte[] registrationIDSlot1 = new byte[2];
|
|||
|
registrationIDSlot1[1] = toDecode[crtPosition++];
|
|||
|
registrationIDSlot1[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// identifier associated with the registration profile in this PDU [Uint16]
|
|||
|
byte[] registrationIDSlot2 = new byte[2];
|
|||
|
registrationIDSlot2[1] = toDecode[crtPosition++];
|
|||
|
registrationIDSlot2[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// registration status [Uint8]
|
|||
|
byte registrationStatus = toDecode[crtPosition++];
|
|||
|
|
|||
|
// registration status code [Uint8]
|
|||
|
byte registrationStatusCode = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current or Accepted Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\tRegistration Status: {0}", GetRegistrationStatus(registrationStatus)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tRegistration Status Code: {0}", GetRegistrationStatusCode(registrationStatusCode)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
// do not display and trigger nothing if the registered PDU is empty
|
|||
|
if (!(registrPduID > 0))
|
|||
|
break;
|
|||
|
|
|||
|
if (BitConverter.ToInt16(registrationIDSlot1, 0) != 0)
|
|||
|
{
|
|||
|
Utils.WriteLine(String.Format("\tSlot 1 Registered"), ConsoleType.WIRELINE);
|
|||
|
OnRegistrationReceived(true, SlotNumber.Slot1);
|
|||
|
}
|
|||
|
if (BitConverter.ToInt16(registrationIDSlot2, 0) != 0)
|
|||
|
{
|
|||
|
Utils.WriteLine(String.Format("\tSlot 2 Registered"), ConsoleType.WIRELINE);
|
|||
|
OnRegistrationReceived(true, SlotNumber.Slot2);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_REGISTRATION_GENERAL_OPS
|
|||
|
case (byte)Operations.WL_REGISTRATION_GENERAL_OPS:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// identifier associated with the registration profile in this PDU [Uint16]
|
|||
|
int registrationSlot = toDecode[crtPosition++];
|
|||
|
|
|||
|
// identifier of the registration PDU [Uint32]
|
|||
|
byte[] registrationPduID = new byte[4];
|
|||
|
registrationPduID[3] = toDecode[crtPosition++];
|
|||
|
registrationPduID[2] = toDecode[crtPosition++];
|
|||
|
registrationPduID[1] = toDecode[crtPosition++];
|
|||
|
registrationPduID[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
|
|||
|
Int64 registrPduID = BitConverter.ToUInt32(registrationPduID, 0);
|
|||
|
|
|||
|
|
|||
|
// registration operation code [Uint8]
|
|||
|
byte registrationOperationCode = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current or Accepted Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine("RegSlot " + registrationSlot + " | OpCode " + registrationOperationCode + " [" + registrPduID + "]", ConsoleType.WIRELINE);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_PROTOCOL_VERSION_QUERY_RESPONSE
|
|||
|
/*
|
|||
|
* This message is sent from the repeater peer to the third party application as a response
|
|||
|
* to the WL_PROTOCOL_VERSION_QUERY. The repeater always responds with its
|
|||
|
* current and oldest version irrespective of the version numbers in the Wireline Protocol
|
|||
|
* Version Query.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_PROTOCOL_VERSION_QUERY_RESPONSE:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 3)
|
|||
|
{
|
|||
|
// reserved field
|
|||
|
Int64 reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// queryID - ID of the protocol version query PDU.
|
|||
|
// Response from the repeater pertaining to this message
|
|||
|
// has the same Query ID value [Uint32]
|
|||
|
byte[] queryID = new byte[4];
|
|||
|
queryID[3] = toDecode[crtPosition++];
|
|||
|
queryID[2] = toDecode[crtPosition++];
|
|||
|
queryID[1] = toDecode[crtPosition++];
|
|||
|
queryID[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
Int64 querryID = BitConverter.ToUInt32(queryID, 0);
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_CHNL_STATUS
|
|||
|
/*
|
|||
|
* This message is sent from the repeater peer to the third party applications to report the
|
|||
|
* conventional channel status of SS/IPSC system or rest channel status of CPP/LCP
|
|||
|
* system. This message is only sent out by the first repeater peer, which receives the call
|
|||
|
* over the air from the radio or receives the call over the network from the third party
|
|||
|
* application.
|
|||
|
* Only the third party application who has subscribed the wireline channel status during
|
|||
|
* wireline registration can receive this message.
|
|||
|
* A repeater peer sends out a Wireline Channel Status in one of the following situations:
|
|||
|
* 1) Upon receiving a Wireline Channel Status Query from the third party application.
|
|||
|
* 2) The register channel status of SS/IPSC system or rest channel status of
|
|||
|
* CPC/LCP system is updated.
|
|||
|
* In MOTOTRBO 2.2, the data revert repeaters in CPP/LCP system didn’t send Wireline
|
|||
|
* Channel Status PDU.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_CHNL_STATUS:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// statusPduID - The ID of the status PDU
|
|||
|
// uniquely identifies the
|
|||
|
// channel status PDU. [Uint32]
|
|||
|
byte[] statusPduID = new byte[4];
|
|||
|
statusPduID[3] = toDecode[crtPosition++];
|
|||
|
statusPduID[2] = toDecode[crtPosition++];
|
|||
|
statusPduID[1] = toDecode[crtPosition++];
|
|||
|
statusPduID[0] = toDecode[crtPosition++];
|
|||
|
Int64 statusPDUID = BitConverter.ToUInt32(statusPduID, 0);
|
|||
|
|
|||
|
// Only available in IPSC modes. The channel status information. [Uint8]
|
|||
|
byte conventionalChannelStatus = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Only available in CPP/LCP modes. The rest channel status information. [Uint8]
|
|||
|
byte restChannelStatus = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Call type [Uint8]
|
|||
|
byte typeOfCall = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tConventional Channel Status: {0}", GetChannelStatus(conventionalChannelStatus)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tRest Channel Status: {0}", GetChannelStatus(restChannelStatus)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(typeOfCall)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_CHNL_CTRL_STATUS
|
|||
|
/*
|
|||
|
* This message is sent from the repeater peer to the third party applications to response
|
|||
|
* the Wireline Call Channel Control Request.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_CHNL_CTRL_STATUS:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// chnCtrlstatus - Channel control Status [Uint8]
|
|||
|
byte chnCtrlstatus = toDecode[crtPosition++];
|
|||
|
|
|||
|
// DeclineReasonCode - The reason for decline the call control request [Uint8]
|
|||
|
byte declineReasonCode = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\tSlot {0}",GetSlotNumber(slotNumber)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(callType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tChannel Ctrl Status: {0}", GetChannelControlStatus(chnCtrlstatus)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
if ((SlotNumber)slotNumber == SlotNumber.Slot1)
|
|||
|
crtCSBKCallStausSlot1.chnCtrlstatus = (ChannelControlStatus)chnCtrlstatus;
|
|||
|
else
|
|||
|
crtCSBKCallStausSlot2.chnCtrlstatus = (ChannelControlStatus)chnCtrlstatus;
|
|||
|
|
|||
|
OnChannelControlStatusReceived(calllID, (CallType)callType, (ChannelControlStatus)chnCtrlstatus, (SlotNumber) slotNumber);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_CSBK_CALL
|
|||
|
/*
|
|||
|
* This message is sent from the repeater peer to the third party application to send the
|
|||
|
* CSBK request or response message
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_CSBK_CALL:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFID - The DMR Feature Set ID / Manufacturer’s ID [Uint8]
|
|||
|
byte mfid = toDecode[crtPosition++];
|
|||
|
|
|||
|
// CSBK Arguments - The reason for decline the call control request [Uint8]
|
|||
|
byte[] csbkArguments = new byte[8];
|
|||
|
csbkArguments[7] = toDecode[crtPosition++];
|
|||
|
csbkArguments[6] = toDecode[crtPosition++];
|
|||
|
csbkArguments[5] = toDecode[crtPosition++];
|
|||
|
csbkArguments[4] = toDecode[crtPosition++];
|
|||
|
csbkArguments[3] = toDecode[crtPosition++];
|
|||
|
csbkArguments[2] = toDecode[crtPosition++];
|
|||
|
csbkArguments[1] = toDecode[crtPosition++];
|
|||
|
csbkArguments[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// rawRssiValue - The raw RSSI value for each burst
|
|||
|
byte[] rawRssiValue = new byte[2];
|
|||
|
rawRssiValue[1] = toDecode[crtPosition++];
|
|||
|
rawRssiValue[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(callType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tSource ID: {0}", sourceeID), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tTarget ID: {0}", targettID), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
switch (callType)
|
|||
|
{
|
|||
|
case (byte)CallType.RadioInhibitResponse:
|
|||
|
{
|
|||
|
// eg.
|
|||
|
// 0xB2 0x0 0x0 0x0 0x2 0x17 0x1 0x0 0x0 0x0 0x65 0x4A 0x0 0x0 0x0 0x6F 0x0 0x0
|
|||
|
// 0x0 0x1 0x0 0x0 0x10 0x0 0xFF 0x0 0x0 0x1 0x0 0x0 0x6F 0x3B 0x60 0xC 0x4
|
|||
|
OnRadioStatusChanged(sourceeID, GetSlotNumber(slotNumber), false);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (byte)CallType.RadioUninhibitResponse:
|
|||
|
{
|
|||
|
// eg.
|
|||
|
// 0xB2 0x0 0x0 0x0 0x2 0x17 0x1 0x0 0x0 0x0 0x4C 0x4C 0x0 0x0 0x0 0x65 0x0 0x0
|
|||
|
// 0x0 0x1 0x0 0x0 0x10 0x0 0xFE 0x0 0x0 0x1 0x0 0x0 0x65 0x3B 0x69 0xC 0x4
|
|||
|
OnRadioStatusChanged(sourceeID, GetSlotNumber(slotNumber), true);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (byte)CallType.EmergencyCSBKAlertRequest:
|
|||
|
{
|
|||
|
OnEmergencyChanged(sourceeID, GetSlotNumber(slotNumber));
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (byte)CallType.AllCall:
|
|||
|
case (byte)CallType.GroupVoiceCall:
|
|||
|
case (byte)CallType.PrivateCallRequest:
|
|||
|
{
|
|||
|
|
|||
|
OnCSBKCallReceived(sourceeID, targettID, (CallType)callType, (SlotNumber)slotNumber);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_VOICE_START
|
|||
|
/*
|
|||
|
* This message is sent by the repeater peer to indicate the beginning of a voice stream.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_VOICE_START:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
CallType callTypee = GetCallType(callType);
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// callAttributes [Uint8] - Call General attributes
|
|||
|
byte callAttributes = toDecode[crtPosition++];
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFID [Uint8] - The DMR Feature Set ID / Manufacturer’s ID
|
|||
|
byte mfid = toDecode[crtPosition++];
|
|||
|
|
|||
|
// service option [Uint8] - DMR LC Service Option
|
|||
|
byte serviceOption = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(callType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tSource ID: {0}", sourceeID), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tTarget ID: {0}", targettID), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
if (callTypee == CallType.AllCall || callTypee == CallType.GroupVoiceCall
|
|||
|
|| callTypee == CallType.PrivateVoiceCall || callTypee == CallType.EmergencyVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(callTypee),
|
|||
|
ConvertCallSessionStatus4MessageBus(CallSessionStatus.CallInProgress), GetSlotNumber(slotNumber));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_VOICE_END_BURST
|
|||
|
/*
|
|||
|
* This message is sent by the repeater peer to indicate the beginning of a voice stream.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_VOICE_END_BURST:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
CallType callTypee = GetCallType(callType);
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// callAttributes [Uint8] - Call General attributes
|
|||
|
byte[] rtpInformationField = new byte[12];
|
|||
|
rtpInformationField[11] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[10] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[9] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[8] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[7] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[6] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[5] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[4] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[3] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[2] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[1] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// burst type [Uint8] - DMR voice burst type Must be Voice Terminator
|
|||
|
byte burstType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFID [Uint8] - The DMR Feature Set ID / Manufacturer’s ID
|
|||
|
byte mfid = toDecode[crtPosition++];
|
|||
|
|
|||
|
// service option [Uint8] - DMR LC Service Option
|
|||
|
byte serviceOption = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tCall Type: {0}", GetCallType(callType)));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tSource ID: {0}", sourceeID));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tTarget ID: {0}", targettID));
|
|||
|
Utils.WriteLine(String.Format("\tBurst Type: {0}", GetBurstType(burstType)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
/*
|
|||
|
if (callTypee == CallType.AllCall || callTypee == CallType.GroupVoiceCall || callTypee == CallType.PrivateCallRequest)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(callTypee),
|
|||
|
ConvertCallSessionStatus4MessageBus(CallSessionStatus.CallInProgress), GetSlotNumber(slotNumber));
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_CALL_SESSION_STATUS
|
|||
|
/*
|
|||
|
* This message is sent from repeater peer to the third party application to inform the call
|
|||
|
* session status. Only the repeater peer, which receives the call over the air from the
|
|||
|
* radio or receives the call from the third party application over the network interface,
|
|||
|
* sends out the WL_VC_CALL_SESSION_STATUS message
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_CALL_SESSION_STATUS:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// reserved [Uint32]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
reserved = toDecode[crtPosition++];
|
|||
|
reserved = toDecode[crtPosition++];
|
|||
|
reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFIcallSessionStatusD - Call Session Stats [Uint8]
|
|||
|
byte callSessionStatus = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)));
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(callType)));
|
|||
|
Utils.WriteLine(String.Format("\tSource ID: {0}", sourceeID));
|
|||
|
Utils.WriteLine(String.Format("\tTarget ID: {0}", targettID));
|
|||
|
Utils.WriteLine(String.Format("\tCall Session Status: {0}", GetCallSessionStatus(callSessionStatus)));
|
|||
|
|
|||
|
CallSessionStatus callStatus = (callSessionStatus == (byte)CallSessionStatus.CallEnd ? CallSessionStatus.CallEnd : CallSessionStatus.CallHang);
|
|||
|
|
|||
|
// broadcast the call status only if in hangtime or ended
|
|||
|
if(callStatus == CallSessionStatus.CallEnd || callStatus == CallSessionStatus.CallHang)
|
|||
|
{
|
|||
|
if (callType == (byte)CallType.AllCall || callType == (byte)CallType.GroupVoiceCall
|
|||
|
|| callType == (byte)CallType.PrivateVoiceCall || callType == (byte)CallType.EmergencyVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus((CallType)callType),
|
|||
|
ConvertCallSessionStatus4MessageBus(callStatus), GetSlotNumber(slotNumber, le.systemType));
|
|||
|
/*
|
|||
|
if (callType == (byte)CallType.GroupVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(CallType.GroupVoiceCall),
|
|||
|
ConvertCallSessionStatus4MessageBus(callStatus), GetSlotNumber(slotNumber, le.systemType));
|
|||
|
else if (callType == (byte)CallType.PrivateVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(CallType.PrivateVoiceCall),
|
|||
|
ConvertCallSessionStatus4MessageBus(callStatus), GetSlotNumber(slotNumber, le.systemType));
|
|||
|
else if (callType == (byte)CallType.AllCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(CallType.AllCall),
|
|||
|
ConvertCallSessionStatus4MessageBus(callStatus), GetSlotNumber(slotNumber, le.systemType));
|
|||
|
else if (callType == (byte)CallType.EmergencyVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(CallType.EmergencyVoiceCall),
|
|||
|
ConvertCallSessionStatus4MessageBus(callStatus), GetSlotNumber(slotNumber, le.systemType));
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
// fire event for call session status received
|
|||
|
OnCallSesionStatusReceived(sourceeID, targettID, (CallType)callType, (CallSessionStatus)callSessionStatus, (SlotNumber) slotNumber);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_VOICE_BURST
|
|||
|
/*
|
|||
|
* This message is used by the Repeater Peer to send Voice Burst to the third party
|
|||
|
* application.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_VOICE_BURST:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
CallType callTypee = GetCallType(callType);
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// callAttributes [Uint8] - Call General attributes
|
|||
|
byte callAttributes = toDecode[crtPosition++];
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// rptInformationField [Uint8 * 12] - RPT Header Information
|
|||
|
byte[] rtpInformationField = new byte[12];
|
|||
|
rtpInformationField[11] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[10] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[9] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[8] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[7] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[6] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[5] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[4] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[3] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[2] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[1] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// burst type [Uint8] - DMR voice burst type Must be Voice Terminator
|
|||
|
byte burstType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved3 = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFID [Uint8] - The DMR Feature Set ID / Manufacturer’s ID
|
|||
|
byte mfid = toDecode[crtPosition++];
|
|||
|
|
|||
|
// service option [Uint8] - DMR LC Service Option
|
|||
|
byte serviceOption = toDecode[crtPosition++];
|
|||
|
|
|||
|
// algorithmID [Uint8] - Algorithm ID
|
|||
|
byte algorithmID = toDecode[crtPosition++];
|
|||
|
|
|||
|
// keyID [Uint8] - ID of the Privacy Key
|
|||
|
byte keyID = toDecode[crtPosition++];
|
|||
|
|
|||
|
// iv [Uint8] - Initialization Vector
|
|||
|
byte[] iv = new byte[4];
|
|||
|
iv[3] = toDecode[crtPosition++];
|
|||
|
iv[2] = toDecode[crtPosition++];
|
|||
|
iv[1] = toDecode[crtPosition++];
|
|||
|
iv[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// ambe [Uint8 * 20] - The AMBE voice encoded frames
|
|||
|
byte[] ambe = new byte[20];
|
|||
|
ambe[0] = toDecode[crtPosition++];
|
|||
|
ambe[1] = toDecode[crtPosition++];
|
|||
|
ambe[2] = toDecode[crtPosition++];
|
|||
|
ambe[3] = toDecode[crtPosition++];
|
|||
|
ambe[4] = toDecode[crtPosition++];
|
|||
|
ambe[5] = toDecode[crtPosition++];
|
|||
|
ambe[6] = toDecode[crtPosition++];
|
|||
|
ambe[7] = toDecode[crtPosition++];
|
|||
|
ambe[8] = toDecode[crtPosition++];
|
|||
|
ambe[9] = toDecode[crtPosition++];
|
|||
|
ambe[10] = toDecode[crtPosition++];
|
|||
|
ambe[11] = toDecode[crtPosition++];
|
|||
|
ambe[12] = toDecode[crtPosition++];
|
|||
|
ambe[13] = toDecode[crtPosition++];
|
|||
|
ambe[14] = toDecode[crtPosition++];
|
|||
|
ambe[15] = toDecode[crtPosition++];
|
|||
|
ambe[16] = toDecode[crtPosition++];
|
|||
|
ambe[17] = toDecode[crtPosition++];
|
|||
|
ambe[18] = toDecode[crtPosition++];
|
|||
|
ambe[19] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// add ambe burst to file
|
|||
|
//DecodeAMBE2(ambe, GetBurstType(burstType), (SlotNumber)slotNumber);
|
|||
|
|
|||
|
// rawRssiValue [Uint16] - Only for WL outbound: The raw RSSI value for each voice burst
|
|||
|
byte[] rawRssiValue = new byte[2];
|
|||
|
rawRssiValue[1] = toDecode[crtPosition++];
|
|||
|
rawRssiValue[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)), ConsoleType.WIRELINE);
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tCall Type: {0}", GetCallType(callType)));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tSource ID: {0}", sourceeID));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tTarget ID: {0}", targettID));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tCurrent Version: {0}", currentWirelineProtocolVersion));
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, String.Format("\tOldest Version: {0}", oldestWirelineProtocolVersion));
|
|||
|
Utils.WriteLine(String.Format("\tBurst Type: {0}", GetBurstType(burstType)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
|
|||
|
// verify if a voice burst was skyped and send an empty one if yes
|
|||
|
int skipped = 0;
|
|||
|
// set the previous bursty type for this slot number
|
|||
|
int prevWorkingBurstType = (slotNumber == (byte)SlotNumber.Slot1 ? previousBrustTypeSlot1 : previousBrustTypeSlot2);
|
|||
|
if (burstType < prevWorkingBurstType)
|
|||
|
skipped = Math.Abs(burstType + 6 - prevWorkingBurstType) % 6 - 1;
|
|||
|
else
|
|||
|
skipped = Math.Abs(burstType - prevWorkingBurstType % 6) - 1;
|
|||
|
|
|||
|
|
|||
|
if (skipped > 0)
|
|||
|
{
|
|||
|
for (int i = 0; i < skipped; i++)
|
|||
|
{
|
|||
|
// frame 1
|
|||
|
OnAudioFrameReceived(new byte[7], (Wireline.SlotNumber)slotNumber);
|
|||
|
// frame 2
|
|||
|
OnAudioFrameReceived(new byte[7], (Wireline.SlotNumber)slotNumber);
|
|||
|
// frame 3
|
|||
|
OnAudioFrameReceived(new byte[7], (Wireline.SlotNumber)slotNumber);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// trigger event for voice frame received
|
|||
|
List<byte[]> voiceFrames = AMBE.Rate34PrepareForEncoding(ambe);
|
|||
|
foreach (byte[] by in voiceFrames)
|
|||
|
OnAudioFrameReceived(by, (Wireline.SlotNumber)slotNumber);
|
|||
|
|
|||
|
// save previous burst type for specified slot
|
|||
|
if (slotNumber == (byte)SlotNumber.Slot1)
|
|||
|
previousBrustTypeSlot1 = burstType;
|
|||
|
else
|
|||
|
previousBrustTypeSlot2 = burstType;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WL_VC_PRIVACY_BURST
|
|||
|
/*
|
|||
|
* This message is use by the Repeater Peer to send Privacy Voice Burst to the third party
|
|||
|
* application.
|
|||
|
*/
|
|||
|
case (byte)Operations.WL_VC_PRIVACY_BURST:
|
|||
|
{
|
|||
|
if (wirelineProtocolVersion >= 1)
|
|||
|
{
|
|||
|
// Slot number - Specifies the channel/slot reporting the channel status.[Uint8]
|
|||
|
byte slotNumber = toDecode[crtPosition++];
|
|||
|
|
|||
|
// call ID - The ID of the call
|
|||
|
byte[] callID = new byte[4];
|
|||
|
callID[3] = toDecode[crtPosition++];
|
|||
|
callID[2] = toDecode[crtPosition++];
|
|||
|
callID[1] = toDecode[crtPosition++];
|
|||
|
callID[0] = toDecode[crtPosition++];
|
|||
|
Int64 calllID = BitConverter.ToUInt32(callID, 0);
|
|||
|
|
|||
|
// The type of the call [Uint8]
|
|||
|
byte callType = toDecode[crtPosition++];
|
|||
|
CallType callTypee = GetCallType(callType);
|
|||
|
|
|||
|
// source ID - The ID of the subscriber that initiated the call
|
|||
|
byte[] sourceID = new byte[4];
|
|||
|
sourceID[3] = toDecode[crtPosition++];
|
|||
|
sourceID[2] = toDecode[crtPosition++];
|
|||
|
sourceID[1] = toDecode[crtPosition++];
|
|||
|
sourceID[0] = toDecode[crtPosition++];
|
|||
|
Int64 sourceeID = BitConverter.ToUInt32(sourceID, 0);
|
|||
|
|
|||
|
// target ID - The ID of the subscriber ot talk-group to which the call is targeted
|
|||
|
byte[] targetID = new byte[4];
|
|||
|
targetID[3] = toDecode[crtPosition++];
|
|||
|
targetID[2] = toDecode[crtPosition++];
|
|||
|
targetID[1] = toDecode[crtPosition++];
|
|||
|
targetID[0] = toDecode[crtPosition++];
|
|||
|
Int64 targettID = BitConverter.ToUInt32(targetID, 0);
|
|||
|
|
|||
|
// rptInformationField [Uint8 * 12] - RPT Header Information
|
|||
|
byte[] rtpInformationField = new byte[12];
|
|||
|
rtpInformationField[11] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[10] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[9] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[8] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[7] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[6] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[5] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[4] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[3] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[2] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[1] = toDecode[crtPosition++];
|
|||
|
rtpInformationField[0] = toDecode[crtPosition++];
|
|||
|
|
|||
|
// burst type [Uint8] - DMR Voice burst Type Must be Privacy Header
|
|||
|
byte burstType = toDecode[crtPosition++];
|
|||
|
|
|||
|
// reserved [Uint8]
|
|||
|
byte reserved = toDecode[crtPosition++];
|
|||
|
|
|||
|
// MFID [Uint8] - The DMR Feature Set ID / Manufacturer’s ID
|
|||
|
byte mfid = toDecode[crtPosition++];
|
|||
|
|
|||
|
// service option [Uint8] - DMR LC Service Option
|
|||
|
byte serviceOption = toDecode[crtPosition++];
|
|||
|
|
|||
|
// algorithmID [Uint8] - Algorithm ID
|
|||
|
byte algorithmID = toDecode[crtPosition++];
|
|||
|
|
|||
|
// keyID [Uint8] - ID of the Privacy Key
|
|||
|
byte keyID = toDecode[crtPosition++];
|
|||
|
|
|||
|
// iv [Uint8] - Initialization Vector
|
|||
|
byte iv = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Current Wireline Protocol Version [Uint8]
|
|||
|
byte currentWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
// Oldest Wireline Protocol Version [Uint8]
|
|||
|
byte oldestWirelineProtocolVersion = toDecode[crtPosition++];
|
|||
|
|
|||
|
Utils.WriteLine(String.Format("\t{0}", GetSlotNumberName(slotNumber, le.systemType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tCall Type: {0}", GetCallType(callType)), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tSource ID: {0}", sourceeID), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tTarget ID: {0}", targettID), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(String.Format("\tBurst Type: {0}", GetBurstType(burstType)), ConsoleType.WIRELINE);
|
|||
|
|
|||
|
if (callTypee == CallType.AllCall || callTypee == CallType.GroupVoiceCall
|
|||
|
|| callTypee == CallType.PrivateVoiceCall || callTypee == CallType.EmergencyVoiceCall)
|
|||
|
OnCallStatusReceived(sourceeID, targettID, ConvertCallType4MessageBus(callTypee),
|
|||
|
ConvertCallSessionStatus4MessageBus(CallSessionStatus.CallInProgress), GetSlotNumber(slotNumber));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
Utils.WriteLine(String.Format("Unknown Wireline Message: 0x{0:X} [{1}:{2}]", wirelineOpCode, peerIP, peerPort), ConsoleType.WIRELINE);
|
|||
|
Utils.WriteLine(Utils.PrintBytesArray(toDecode), ConsoleType.WIRELINE);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#region WIRELINE SENDING
|
|||
|
|
|||
|
/* Send a Wireline message to the desired peer */
|
|||
|
public void SendWirelineMessage(byte[] message, String peerIP, Int32 peerUDPPort)
|
|||
|
{
|
|||
|
if (message.Length < 1)
|
|||
|
return;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
le.udpClient.Client.SendTo(message, new IPEndPoint(IPAddress.Parse(peerIP), peerUDPPort));
|
|||
|
Utils.WriteLine(String.Format("««« {0,-34} [{1}]", GetMessageType(message[5]), peerIP), ConsoleType.WIRELINE); // + ":" + peerUDPPort);
|
|||
|
//Utils.WriteLine(ConsoleType.WIRELINE, Utils.printBytesArray(message));
|
|||
|
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
Utils.WriteLine("Wireline Thread Send exception: " + ex.ToString(), ConsoleType.WIRELINE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Send a Wireline message to the current Master Peer */
|
|||
|
public void SendWirelineMessage(byte[] message)
|
|||
|
{
|
|||
|
SendWirelineMessage(message, le.masterPeer.ipAddress, le.masterPeer.port);
|
|||
|
}
|
|||
|
|
|||
|
/* Get a string that represents the Message Type based on the opCode */
|
|||
|
private string GetMessageType(byte wirelineOpCode)
|
|||
|
{
|
|||
|
switch (wirelineOpCode)
|
|||
|
{
|
|||
|
case (byte)Operations.WL_REGISTRATION_REQUEST: return Operations.WL_REGISTRATION_REQUEST.ToString();
|
|||
|
case (byte)Operations.WL_REGISTRATION_STATUS: return Operations.WL_REGISTRATION_STATUS.ToString();
|
|||
|
case (byte)Operations.WL_REGISTRATION_GENERAL_OPS: return Operations.WL_REGISTRATION_GENERAL_OPS.ToString();
|
|||
|
case (byte)Operations.WL_PROTOCOL_VERSION_QUERY: return Operations.WL_PROTOCOL_VERSION_QUERY.ToString();
|
|||
|
case (byte)Operations.WL_PROTOCOL_VERSION_QUERY_RESPONSE: return Operations.WL_PROTOCOL_VERSION_QUERY_RESPONSE.ToString();
|
|||
|
case (byte)Operations.WL_CHNL_STATUS: return Operations.WL_CHNL_STATUS.ToString();
|
|||
|
case (byte)Operations.WL_CHNL_STATUS_QUERY: return Operations.WL_CHNL_STATUS_QUERY.ToString();
|
|||
|
case (byte)Operations.WL_VC_CHNL_CTRL_REQUEST: return Operations.WL_VC_CHNL_CTRL_REQUEST.ToString();
|
|||
|
case (byte)Operations.WL_VC_CHNL_CTRL_STATUS: return Operations.WL_VC_CHNL_CTRL_STATUS.ToString();
|
|||
|
case (byte)Operations.WL_VC_CSBK_CALL: return Operations.WL_VC_CSBK_CALL.ToString();
|
|||
|
case (byte)Operations.WL_VC_VOICE_START: return Operations.WL_VC_VOICE_START.ToString();
|
|||
|
case (byte)Operations.WL_VC_VOICE_END_BURST: return Operations.WL_VC_VOICE_END_BURST.ToString();
|
|||
|
case (byte)Operations.WL_VC_CALL_SESSION_STATUS: return Operations.WL_VC_CALL_SESSION_STATUS.ToString();
|
|||
|
case (byte)Operations.WL_VC_VOICE_BURST: return Operations.WL_VC_VOICE_BURST.ToString();
|
|||
|
case (byte)Operations.WL_VC_PRIVACY_BURST: return Operations.WL_VC_PRIVACY_BURST.ToString();
|
|||
|
|
|||
|
default: return "Unknown Wireline Message";
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WIRELINE CALL ENUMS
|
|||
|
public enum AccessCriteria
|
|||
|
{
|
|||
|
PoliteAccess = 0x01
|
|||
|
};
|
|||
|
public enum CallAttributes
|
|||
|
{
|
|||
|
ForwardCSBK = 0x20,
|
|||
|
DoNotForwardCSBK = 0x00,
|
|||
|
SmartPTT = 0x80,
|
|||
|
SmartAfterPreamble = 0xA0
|
|||
|
};
|
|||
|
public enum PreambleDuration
|
|||
|
{
|
|||
|
MinDuration = 0x00,
|
|||
|
MaxDuration = 0x80,
|
|||
|
BurstDurationMS = 0x3C
|
|||
|
};
|
|||
|
public enum CallSessionStatus
|
|||
|
{
|
|||
|
CallHang = 0x0A,
|
|||
|
CallEnd = 0x0B,
|
|||
|
CallInProgress = 0x09,
|
|||
|
RESERVED = 0x00
|
|||
|
};
|
|||
|
public enum CallType
|
|||
|
{
|
|||
|
PreamblePrivateCSBKCall = 0x32,
|
|||
|
PreambleGroupCSBKCall = 0x33,
|
|||
|
PreambleEmergencyCall = 0x34,
|
|||
|
EmergencyCSBKAlertRequest = 0x40,
|
|||
|
EmergencyCSBKAlertResponse = 0x41,
|
|||
|
EmergencyVoiceCall = 0x42,
|
|||
|
PrivateCallRequest = 0x43,
|
|||
|
PrivateCallResponse = 0x44,
|
|||
|
CallAlertRequest = 0x45,
|
|||
|
CallAlertResponse = 0x46,
|
|||
|
RadioCheckRequest = 0x47,
|
|||
|
RadioCheckResponse = 0x48,
|
|||
|
RadioInhibitRequest = 0x49,
|
|||
|
RadioInhibitResponse = 0x4A,
|
|||
|
RadioUninhibitRequest = 0x4B,
|
|||
|
RadioUninhibitResponse = 0x4C,
|
|||
|
RadioRemoteMonitorRequest = 0x4D,
|
|||
|
RadioRemoteMonitorResponse = 0x4E,
|
|||
|
GroupVoiceCall = 0x4F,
|
|||
|
PrivateVoiceCall = 0x50,
|
|||
|
AllCall = 0x53,
|
|||
|
Reserved = 0x54,
|
|||
|
Other = 0x55,
|
|||
|
IPConsoleRadioUninhibitRequest = 0x56,
|
|||
|
IPConsoleRadioInhibitRequest = 0x57,
|
|||
|
IPConsoleRadioUninhibitResponse = 0x58,
|
|||
|
IPConsoleRadioInhibitResponse = 0x59,
|
|||
|
GroupPhoneCall = 0x5A,
|
|||
|
PrivatePhoneCall = 0x5B,
|
|||
|
PhoneAllCall = 0x5C,
|
|||
|
CallAlertNackResponse = 0x83,
|
|||
|
RadioMonitorNackResponse = 0x84,
|
|||
|
RadioInhibitUninhibitNackResponse = 0x85
|
|||
|
};
|
|||
|
public enum ChannelStatus
|
|||
|
{
|
|||
|
Active = 0x01,
|
|||
|
Idle = 0x02,
|
|||
|
SlotBlocked = 0x0A,
|
|||
|
SlotUnblocked = 0x0B,
|
|||
|
BusyRestChannel = 0x10,
|
|||
|
RestChannelIdleAvailable = 0x11, // works for idle and available
|
|||
|
LocalGroupCallsNotAllowed = 0x12,
|
|||
|
LocalGroupCallsAllowed = 0x13,
|
|||
|
RestChannelBlocked = 0x14
|
|||
|
};
|
|||
|
public enum ChannelControlStatus
|
|||
|
{
|
|||
|
Received = 0x01,
|
|||
|
Transmiting = 0x02,
|
|||
|
TransmissionSuccessful = 0x03,
|
|||
|
SmartInProgress = 0x04,
|
|||
|
Declined = 0x05
|
|||
|
};
|
|||
|
public enum SlotNumber
|
|||
|
{
|
|||
|
Slot1 = 0x01,
|
|||
|
Slot2 = 0x02,
|
|||
|
BothSlots = 0x03,
|
|||
|
RestChannel = 0x00, // only in CPC
|
|||
|
SiteIPAddress = 0x00, // only in IPSC
|
|||
|
Reserved = 0xFF
|
|||
|
};
|
|||
|
public enum RegistrationStatusCode
|
|||
|
{
|
|||
|
CFSNotEnabled = 0x01,
|
|||
|
RegistrationEntriesExceded = 0x02,
|
|||
|
IncompatibleVersion = 0x03
|
|||
|
};
|
|||
|
public enum RegistrationStatus
|
|||
|
{
|
|||
|
Successful = 0x00,
|
|||
|
Unsuccessful = 0x01
|
|||
|
};
|
|||
|
public enum RegistrationOperationCode
|
|||
|
{
|
|||
|
QueryRegStatus = 0x01,
|
|||
|
DeRegister = 0x02
|
|||
|
};
|
|||
|
public enum WirelineChannelStatus
|
|||
|
{
|
|||
|
RegisteredWLStatus = 0x80,
|
|||
|
NotRegisteredWLStatus = 0x00
|
|||
|
};
|
|||
|
public enum AddressType
|
|||
|
{
|
|||
|
IndividualCall = 0x01,
|
|||
|
GroupCall = 0x02,
|
|||
|
AllIndividualCall = 0x03,
|
|||
|
AllTalkgroupCall = 0x04,
|
|||
|
AllWideTakgroupsCall = 0x05,
|
|||
|
AllLocalTalkgroupsCall = 0x06
|
|||
|
};
|
|||
|
public enum CSBKAttributes
|
|||
|
{
|
|||
|
// bit 0
|
|||
|
VoiceCallNotInterruptible = 0x00,
|
|||
|
VoiceCallInterruptible = 0x01,
|
|||
|
// bit 1
|
|||
|
ClearCall = 0x00,
|
|||
|
PrivacyCall = 0x02,
|
|||
|
// bit 2-3
|
|||
|
ClearCall23 = 0x00,
|
|||
|
BasicPrivacy = 0x01,
|
|||
|
EnhancedPrivacy = 0x02,
|
|||
|
// bit 6
|
|||
|
CSBKService = 0x00,
|
|||
|
CSBKMonitorOnly = 0x40,
|
|||
|
// bit 7
|
|||
|
CSBKNotRegisteredService = 0x00,
|
|||
|
CSBKRegisteredService = 0x80
|
|||
|
}
|
|||
|
public enum VoiceAttributes
|
|||
|
{
|
|||
|
NormalService = 0x00,
|
|||
|
VoiceMonitorOnly = 0x01,
|
|||
|
NotRegisteredVoiceService = 0x00,
|
|||
|
RegisterVoiceService = 0x01
|
|||
|
};
|
|||
|
|
|||
|
public enum BurstType
|
|||
|
{
|
|||
|
VoiceBurstA = 0x01,
|
|||
|
VoiceBurstB = 0x02,
|
|||
|
VoiceBurstC = 0x03,
|
|||
|
VoiceBurstD = 0x04,
|
|||
|
VoiceBurstE = 0x05,
|
|||
|
VoiceBurstF = 0x06,
|
|||
|
VoiceTerminator = 0x07,
|
|||
|
PrivacyHeader = 0x08,
|
|||
|
Unknown = 0x00
|
|||
|
}
|
|||
|
public enum ServiceOption
|
|||
|
{
|
|||
|
// bit 3 - Only for group call
|
|||
|
NonBroadcastService = 0x00,
|
|||
|
BroadcastService = 0x04,
|
|||
|
|
|||
|
// bit 7
|
|||
|
NonEmergencyService = 0x00,
|
|||
|
BroadcastService7 = 0x80
|
|||
|
}
|
|||
|
public enum PrivacyType
|
|||
|
{
|
|||
|
Clear = 0x00,
|
|||
|
Basic = 0x01,
|
|||
|
Enhanced = 0x02
|
|||
|
};
|
|||
|
public enum ManufacturerID
|
|||
|
{
|
|||
|
StandardFeature = 0x00,
|
|||
|
MotorolaSolutionProprietaryFeature = 0x10,
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private string GetRegistrationStatus(int registrationStatus)
|
|||
|
{
|
|||
|
switch(registrationStatus)
|
|||
|
{
|
|||
|
case (int)RegistrationStatus.Successful: return "Successful";
|
|||
|
case (int)RegistrationStatus.Unsuccessful: return "Unsuccessful";
|
|||
|
default: return "RESERVED";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private string GetRegistrationStatusCode(int registrationStatusCode)
|
|||
|
{
|
|||
|
switch(registrationStatusCode)
|
|||
|
{
|
|||
|
case (int)RegistrationStatusCode.CFSNotEnabled: return "CFS Not Enabled";
|
|||
|
case (int)RegistrationStatusCode.IncompatibleVersion: return "Incompatible Version";
|
|||
|
case (int)RegistrationStatusCode.RegistrationEntriesExceded: return "Registration Entries Exceded";
|
|||
|
case (int)0x00: return "Registered";
|
|||
|
default: return "RESERVED";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private int ConvertCallType4MessageBus(CallType type)
|
|||
|
{
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case CallType.GroupVoiceCall: return (int)SafeMobileLib.CallType.GROUPCALL;
|
|||
|
case CallType.PrivateVoiceCall: return (int)SafeMobileLib.CallType.PRIVATECALL;
|
|||
|
case CallType.AllCall: return (int)SafeMobileLib.CallType.ALLCALL;
|
|||
|
case CallType.EmergencyVoiceCall: return (int)SafeMobileLib.CallType.EMERGENCYCALL;
|
|||
|
default: return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private string GetCallType(int type)
|
|||
|
{
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case (int)CallType.CallAlertNackResponse: return "CallAlertNackResponse";
|
|||
|
case (int)CallType.CallAlertRequest: return "CallAlertRequest";
|
|||
|
case (int)CallType.CallAlertResponse: return "CallAlertResponse";
|
|||
|
case (int)CallType.EmergencyCSBKAlertRequest: return "EmergencyCSBKAlertRequest";
|
|||
|
case (int)CallType.EmergencyCSBKAlertResponse: return "EmergencyCSBKAlertResponse";
|
|||
|
case (int)CallType.EmergencyVoiceCall: return "EmergencyVoiceCall";
|
|||
|
case (int)CallType.GroupVoiceCall: return "GroupVoiceCall";
|
|||
|
case (int)CallType.PrivateVoiceCall: return "PrivateVoiceCall";
|
|||
|
case (int)CallType.IPConsoleRadioInhibitRequest: return "IPConsoleRadioInhibitRequest";
|
|||
|
case (int)CallType.IPConsoleRadioInhibitResponse: return "IPConsoleRadioInhibitResponse";
|
|||
|
case (int)CallType.IPConsoleRadioUninhibitRequest: return "IPConsoleRadioUninhibitRequest";
|
|||
|
case (int)CallType.IPConsoleRadioUninhibitResponse: return "IPConsoleRadioUninhibitResponse";
|
|||
|
case (int)CallType.AllCall: return "AllCall";
|
|||
|
case (int)CallType.Other: return "Other";
|
|||
|
case (int)CallType.GroupPhoneCall: return "GroupPhoneCall";
|
|||
|
case (int)CallType.PrivatePhoneCall: return "PrivatePhoneCall";
|
|||
|
case (int)CallType.PreambleEmergencyCall: return "PreambleEmergencyCall";
|
|||
|
case (int)CallType.PreambleGroupCSBKCall: return "PreambleGroupCSBKCall";
|
|||
|
case (int)CallType.PreamblePrivateCSBKCall: return "PreamblePrivateCSBKCall";
|
|||
|
case (int)CallType.RadioCheckRequest: return "RadioCheckRequest";
|
|||
|
case (int)CallType.RadioCheckResponse: return "RadioCheckResponse";
|
|||
|
case (int)CallType.RadioInhibitRequest: return "RadioInhibitRequest";
|
|||
|
case (int)CallType.RadioInhibitResponse: return "RadioInhibitResponse";
|
|||
|
case (int)CallType.RadioInhibitUninhibitNackResponse: return "RadioInhibitUninhibitNackResponse";
|
|||
|
case (int)CallType.RadioMonitorNackResponse: return "RadioMonitorNackResponse";
|
|||
|
case (int)CallType.RadioRemoteMonitorRequest: return "RadioRemoteMonitorRequest";
|
|||
|
case (int)CallType.RadioRemoteMonitorResponse: return "RadioRemoteMonitorResponse";
|
|||
|
case (int)CallType.RadioUninhibitRequest: return "RadioUninhibitRequest";
|
|||
|
case (int)CallType.RadioUninhibitResponse: return "RadioUninhibitResponse";
|
|||
|
default:
|
|||
|
{
|
|||
|
if ((type >= 0x00 && type <= 0x31) || (type >= 0x35 && type <= 0x3F) || (type >= 0x4F && type <= 0x54)
|
|||
|
|| (type >= 0x5A && type <= 0x5C) || (type >= 0x86 && type <= 0xFF))
|
|||
|
return "RESERVED";
|
|||
|
else
|
|||
|
return "Unknown call type";
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private CallType GetCallType(byte type)
|
|||
|
{
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case (byte)CallType.AllCall: return CallType.AllCall;
|
|||
|
case (byte)CallType.GroupVoiceCall: return CallType.GroupVoiceCall;
|
|||
|
case (byte)CallType.PrivateVoiceCall: return CallType.PrivateVoiceCall;
|
|||
|
case (byte)CallType.PrivateCallRequest: return CallType.PrivateCallRequest;
|
|||
|
case (byte)CallType.PrivateCallResponse: return CallType.PrivateCallResponse;
|
|||
|
case (byte)CallType.GroupPhoneCall: return CallType.GroupPhoneCall;
|
|||
|
case (byte)CallType.PrivatePhoneCall: return CallType.PrivatePhoneCall;
|
|||
|
case (byte)CallType.PhoneAllCall: return CallType.PhoneAllCall;
|
|||
|
case (byte)CallType.CallAlertNackResponse: return CallType.CallAlertNackResponse;
|
|||
|
case (byte)CallType.CallAlertRequest: return CallType.CallAlertRequest;
|
|||
|
case (byte)CallType.CallAlertResponse: return CallType.CallAlertResponse;
|
|||
|
case (byte)CallType.EmergencyCSBKAlertRequest: return CallType.EmergencyCSBKAlertRequest;
|
|||
|
case (byte)CallType.EmergencyCSBKAlertResponse: return CallType.EmergencyCSBKAlertResponse;
|
|||
|
case (byte)CallType.IPConsoleRadioInhibitRequest: return CallType.IPConsoleRadioInhibitRequest;
|
|||
|
case (byte)CallType.IPConsoleRadioInhibitResponse: return CallType.IPConsoleRadioInhibitResponse;
|
|||
|
case (byte)CallType.IPConsoleRadioUninhibitRequest: return CallType.IPConsoleRadioUninhibitRequest;
|
|||
|
case (byte)CallType.IPConsoleRadioUninhibitResponse: return CallType.IPConsoleRadioUninhibitResponse;
|
|||
|
case (byte)CallType.Other: return CallType.Other;
|
|||
|
case (byte)CallType.PreambleEmergencyCall: return CallType.PreambleEmergencyCall;
|
|||
|
case (byte)CallType.PreambleGroupCSBKCall: return CallType.PreambleGroupCSBKCall;
|
|||
|
case (byte)CallType.PreamblePrivateCSBKCall: return CallType.PreamblePrivateCSBKCall;
|
|||
|
case (byte)CallType.RadioCheckRequest: return CallType.RadioCheckRequest;
|
|||
|
case (byte)CallType.RadioCheckResponse: return CallType.RadioCheckResponse;
|
|||
|
case (byte)CallType.RadioInhibitRequest: return CallType.RadioInhibitRequest;
|
|||
|
case (byte)CallType.RadioInhibitResponse: return CallType.RadioInhibitResponse;
|
|||
|
case (byte)CallType.RadioInhibitUninhibitNackResponse: return CallType.RadioInhibitUninhibitNackResponse;
|
|||
|
case (byte)CallType.RadioMonitorNackResponse: return CallType.RadioMonitorNackResponse;
|
|||
|
case (byte)CallType.RadioRemoteMonitorRequest: return CallType.RadioRemoteMonitorRequest;
|
|||
|
case (byte)CallType.RadioRemoteMonitorResponse: return CallType.RadioRemoteMonitorResponse;
|
|||
|
case (byte)CallType.RadioUninhibitRequest: return CallType.RadioUninhibitRequest;
|
|||
|
case (byte)CallType.RadioUninhibitResponse: return CallType.RadioUninhibitResponse;
|
|||
|
case (byte)CallType.EmergencyVoiceCall: return CallType.EmergencyVoiceCall;
|
|||
|
default:
|
|||
|
{
|
|||
|
if ((type >= 0x00 && type <= 0x31) || (type >= 0x35 && type <= 0x3F) || (type >= 0x4F && type <= 0x54)
|
|||
|
|| (type >= 0x5A && type <= 0x5C) || (type >= 0x86 && type <= 0xFF))
|
|||
|
return CallType.Reserved;
|
|||
|
else
|
|||
|
return CallType.Reserved;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private BurstType GetBurstType(byte type)
|
|||
|
{
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case (byte)BurstType.PrivacyHeader: return BurstType.PrivacyHeader;
|
|||
|
case (byte)BurstType.VoiceBurstA: return BurstType.VoiceBurstA;
|
|||
|
case (byte)BurstType.VoiceBurstB: return BurstType.VoiceBurstB;
|
|||
|
case (byte)BurstType.VoiceBurstC: return BurstType.VoiceBurstC;
|
|||
|
case (byte)BurstType.VoiceBurstD: return BurstType.VoiceBurstD;
|
|||
|
case (byte)BurstType.VoiceBurstE: return BurstType.VoiceBurstE;
|
|||
|
case (byte)BurstType.VoiceBurstF: return BurstType.VoiceBurstF;
|
|||
|
case (byte)BurstType.VoiceTerminator: return BurstType.VoiceTerminator;
|
|||
|
default: return BurstType.Unknown;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private string GetChannelStatus(int channelStatus)
|
|||
|
{
|
|||
|
switch (channelStatus)
|
|||
|
{
|
|||
|
case (int)ChannelStatus.Active: return "Active";
|
|||
|
case (int)ChannelStatus.Idle: return "Idle";
|
|||
|
case (int)ChannelStatus.SlotBlocked: return "SlotBlocked";
|
|||
|
case (int)ChannelStatus.SlotUnblocked: return "SlotUnblocked";
|
|||
|
case (int)ChannelStatus.BusyRestChannel: return "BusyRestChannel";
|
|||
|
case (int)ChannelStatus.RestChannelIdleAvailable: return "RestChannelIdleAvailable";
|
|||
|
case (int)ChannelStatus.LocalGroupCallsNotAllowed: return "LocalGroupCallsBotAllowed";
|
|||
|
case (int)ChannelStatus.LocalGroupCallsAllowed: return "LocalGroupCallsAllowed";
|
|||
|
case (int)ChannelStatus.RestChannelBlocked: return "RestChannelBlocked";
|
|||
|
default:
|
|||
|
{
|
|||
|
if (channelStatus == 0x00 || (channelStatus >= 0x03 && channelStatus <= 0x09) ||
|
|||
|
(channelStatus >= 0x0C && channelStatus <= 0x0F) || (channelStatus >= 0x15 && channelStatus <= 0xFF))
|
|||
|
return "RESERVED";
|
|||
|
else
|
|||
|
return "Unknown Channel Control Status";
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private string GetSlotNumberName(int slotNumber, MotoRepeater.LinkEstablishment.SystemType systemType)
|
|||
|
{
|
|||
|
switch (slotNumber)
|
|||
|
{
|
|||
|
case (int)SlotNumber.Slot1: return "Slot1";
|
|||
|
case (int)SlotNumber.Slot2: return "Slot2";
|
|||
|
case 0x00:
|
|||
|
{
|
|||
|
switch (systemType)
|
|||
|
{
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.IP_SITE_CONNECT: return "RESERVED";
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.CAPACITY_PLUS: return "RestChannel";
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.LINKED_CAPACITY_PLUS: return "SiteIPAddress";
|
|||
|
default: return "RESERVED";
|
|||
|
}
|
|||
|
}
|
|||
|
default: return "RESERVED";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private SlotNumber GetSlotNumber(int slotNumber, MotoRepeater.LinkEstablishment.SystemType systemType)
|
|||
|
{
|
|||
|
switch (slotNumber)
|
|||
|
{
|
|||
|
case (int)SlotNumber.Slot1: return SlotNumber.Slot1;
|
|||
|
case (int)SlotNumber.Slot2: return SlotNumber.Slot2;
|
|||
|
case 0x00:
|
|||
|
{
|
|||
|
switch (systemType)
|
|||
|
{
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.IP_SITE_CONNECT: return SlotNumber.Reserved;
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.CAPACITY_PLUS: return SlotNumber.RestChannel;
|
|||
|
case MotoRepeater.LinkEstablishment.SystemType.LINKED_CAPACITY_PLUS: return SlotNumber.SiteIPAddress;
|
|||
|
default: return SlotNumber.Reserved;
|
|||
|
}
|
|||
|
}
|
|||
|
default: return SlotNumber.Reserved;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private int ConvertCallSessionStatus4MessageBus(CallSessionStatus status)
|
|||
|
{
|
|||
|
switch (status)
|
|||
|
{
|
|||
|
case CallSessionStatus.CallInProgress: return (int)CallStatus.INPROGRESS;
|
|||
|
case CallSessionStatus.CallHang: return (int)CallStatus.HANGTIME;
|
|||
|
case CallSessionStatus.CallEnd: return (int)CallStatus.ENDED;
|
|||
|
default: return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private CallSessionStatus GetCallSessionStatus(int callSessionStatus)
|
|||
|
{
|
|||
|
switch (callSessionStatus)
|
|||
|
{
|
|||
|
case (int)CallSessionStatus.CallInProgress: return CallSessionStatus.CallInProgress;
|
|||
|
case (int)CallSessionStatus.CallHang: return CallSessionStatus.CallHang;
|
|||
|
case (int)CallSessionStatus.CallEnd: return CallSessionStatus.CallEnd;
|
|||
|
default: return CallSessionStatus.RESERVED;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private string GetChannelControlStatus(int chCtrlStatus)
|
|||
|
{
|
|||
|
switch (chCtrlStatus)
|
|||
|
{
|
|||
|
case (int)ChannelControlStatus.Received: return "Received";
|
|||
|
case (int)ChannelControlStatus.Transmiting: return "Transmiting";
|
|||
|
case (int)ChannelControlStatus.TransmissionSuccessful: return "TransmissionSuccessful";
|
|||
|
case (int)ChannelControlStatus.Declined: return "Declined";
|
|||
|
default: return "RESERVED";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region WIRELINE CLASSES
|
|||
|
|
|||
|
private static Int64 queryID = 0x01;
|
|||
|
|
|||
|
public class CSBKCall
|
|||
|
{
|
|||
|
public SlotNumber slotNumber = SlotNumber.Slot1;
|
|||
|
public Int64 callID
|
|||
|
{
|
|||
|
get { return _callID; }
|
|||
|
}
|
|||
|
private static Int64 _callID = 0x131313;
|
|||
|
public CallType callType = CallType.PreamblePrivateCSBKCall;
|
|||
|
public Int64 sourceID = 0;
|
|||
|
public Int64 targetID = 0;
|
|||
|
public AccessCriteria accessCriteria = AccessCriteria.PoliteAccess;
|
|||
|
public CallAttributes callAttributes = CallAttributes.SmartPTT;
|
|||
|
public PreambleDuration preambleDuration = PreambleDuration.MinDuration;
|
|||
|
public Int16 preambleValue = 0x03;
|
|||
|
|
|||
|
// added for current CSBK Call Status
|
|||
|
public ChannelControlStatus chnCtrlstatus = ChannelControlStatus.Declined;
|
|||
|
public Int64 crtCallID = 0;
|
|||
|
public Boolean isCSBKPreambleReceived = false;
|
|||
|
|
|||
|
public CSBKCall() { _callID++; }
|
|||
|
}
|
|||
|
|
|||
|
public class WirelineRegistration
|
|||
|
{
|
|||
|
public SlotNumber slotNumber = SlotNumber.Slot1;
|
|||
|
public static Int64 registrationPduID = BitConverter.ToInt32(new byte[] { 0x61, 0x01, 0x15, 0x43 }, 0);
|
|||
|
public readonly Int64 registrationID = 0x1;
|
|||
|
public RegistrationOperationCode regOpCode = RegistrationOperationCode.QueryRegStatus;
|
|||
|
public WirelineChannelStatus wirelineChannelStatus = WirelineChannelStatus.NotRegisteredWLStatus;
|
|||
|
public int numberOfRegistrationEntries = 0;
|
|||
|
public List<RegEntry> regEntriesList = new List<RegEntry>();
|
|||
|
|
|||
|
public WirelineRegistration() { }
|
|||
|
|
|||
|
// add a new entry for which the status will be broadcasted
|
|||
|
public void AddRegEntry(RegEntry entry)
|
|||
|
{
|
|||
|
this.numberOfRegistrationEntries++;
|
|||
|
regEntriesList.Add(entry);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class RegEntry
|
|||
|
{
|
|||
|
public AddressType addressType = AddressType.AllIndividualCall;
|
|||
|
public Int64 addressRangeStart = 0;
|
|||
|
public Int64 addressRangeEnd = 0;
|
|||
|
public CSBKAttributes csbkAttributes = CSBKAttributes.CSBKRegisteredService;
|
|||
|
public RegEntry(AddressType addressType, Int64 startID, Int64 endID)
|
|||
|
{
|
|||
|
this.addressType = addressType;
|
|||
|
this.addressRangeStart = startID;
|
|||
|
this.addressRangeEnd = endID;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class WirelineQueryRegistration
|
|||
|
{
|
|||
|
public SlotNumber slotNumber = SlotNumber.Slot1;
|
|||
|
public Int64 registrationPduID = 0;
|
|||
|
public RegistrationOperationCode regOpCode = RegistrationOperationCode.QueryRegStatus;
|
|||
|
|
|||
|
public WirelineQueryRegistration() { }
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region EVENT DELEGATES
|
|||
|
|
|||
|
public delegate void RadioStatusChangedDEl(Int64 radioID, SlotNumber slot, Boolean isEnabled);
|
|||
|
public event RadioStatusChangedDEl OnRadioStatusChanged;
|
|||
|
|
|||
|
public delegate void EmergencyReceivedDEl(Int64 radioID, SlotNumber slot);
|
|||
|
public event EmergencyReceivedDEl OnEmergencyChanged;
|
|||
|
|
|||
|
public delegate void RegistrationReceivedDEl(Boolean isValid, SlotNumber slot);
|
|||
|
public event RegistrationReceivedDEl OnRegistrationReceived;
|
|||
|
|
|||
|
|
|||
|
public delegate void CallStatusReceivedDEl(Int64 sourceID, Int64 targertID, int callType, int callStatus, SlotNumber slot);
|
|||
|
public event CallStatusReceivedDEl OnCallStatusReceived;
|
|||
|
|
|||
|
private delegate void ChannelControlStatusReceivedDel(Int64 callID, CallType callType, ChannelControlStatus chnCtrlStatus, SlotNumber slot);
|
|||
|
private event ChannelControlStatusReceivedDel OnChannelControlStatusReceived;
|
|||
|
|
|||
|
public delegate void CallSessionStatusReceivedDEl(Int64 sourceID, Int64 targertID, CallType callType, CallSessionStatus callSessionStatus, SlotNumber slot);
|
|||
|
public event CallSessionStatusReceivedDEl OnCallSesionStatusReceived;
|
|||
|
|
|||
|
public delegate void CSBKCallReceivedDEl(Int64 sourceID, Int64 targetID, CallType callType, SlotNumber slot);
|
|||
|
public event CSBKCallReceivedDEl OnCSBKCallReceived;
|
|||
|
|
|||
|
public delegate void AudioFrameReceivedDEl(byte[] audioFrame, SlotNumber slot);
|
|||
|
public event AudioFrameReceivedDEl OnAudioFrameReceived;
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|