SafeDispatch/SipComponent/SipClientClassExcera.cs
2024-02-22 18:43:59 +02:00

178 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Independentsoft.Sip;
using Independentsoft.Sip.Methods;
using SipComponent.Excera;
namespace SipComponent
{
/// <summary>
/// An implementation of the abstract class SipClientClass, used for Excera
/// </summary>
public class SipClientClassExcera : SipClientClassSimoco
{
#region Fields
private ExceraSipMessageGenerator _sipMessageGenerator = new ExceraSipMessageGenerator();
#endregion
/// <summary>
/// Constructor for the SipClientClassExcera
/// </summary>
/// <param name="repeaterIP">domain name, name or IP address of sip server</param>
/// <param name="repeaterSipPort">port number of the sip server</param>
/// <param name="localSipPort">port number of the local computer used for sip protocol</param>
/// <param name="userName">user name on the sip server</param>
/// <param name="registrationInterval">interval to send sip registration requests. Value is in seconds</param>
/// <param name="bufferMiliseconds">Miliseconds for the buffer that stores the received voice packets</param>
/// <param name="requestTimeout">Number of ms to wait before the sip request times out</param>
/// <param name="localIPAddress">Local Ip adress. If not specified, the class will search for a local ip on the same network with the repeater's ip</param>
public SipClientClassExcera(string repeaterIP, int repeaterSipPort, int localSipPort,
string userName, int registrationInterval, int bufferMiliseconds, int requestTimeout, string localIPAddress = null)
:base(repeaterIP, repeaterSipPort, localSipPort, userName, registrationInterval, bufferMiliseconds, requestTimeout, localIPAddress)
{
}
#region Public Members
/// <summary>
/// Method used to send a Ping command to an Excera radio
/// </summary>
/// <param name="idToSendPing">The Excera ID of the radio</param>
public override void SendPing(string idToSendPing)
{
base.SendExceraPing(idToSendPing);
}
#endregion
#region Non-Public Members Overrinding
/// <summary>
/// Function that processes all the received Sip Message requests
/// </summary>
/// <param name="sipMessageRequest">The Sip Message request</param>
/// <param name="senderID">The ID of the sender</param>
protected override void ProcessReceivedSipMessage(Request sipMessageRequest, string senderID)
{
if (sipMessageRequest.Header.Contains("Ais-Msg-id"))
{
string msgId = sipMessageRequest.Header["Ais-Msg-id"];
if (msgId.Contains("emerg-alarm"))
{
EmergencyReceived?.Invoke(this, new SipEventArgs(senderID));
}
}
// Handle messages when working with Excera
// Get Ais-Msg-Options Header value - this is used for Gps periodically reports
if (sipMessageRequest.Header.Contains("Ais-Msg-Options"))
{
string ais_options = sipMessageRequest.Header["Ais-Msg-Options"];
switch (ais_options)
{
case "service-attributes;transmission-type=raw;coding=nmea;rate=half":
// GPS periodically report
double lat, lon, speed;
DateTime time;
// Get latitude, longitude, speed and time
Simoco.Utils.GPSInfo(Convert.FromBase64String(sipMessageRequest.Body), out lat, out lon, out speed, out time);
// Raise Event
OnGpsPeriodicallyReportReceived(new GpsDataEventArgs(
senderID, lat, lon, speed, time));
break;
case "service-attributes; coding=iso8":
// Management message report
// Get the Type and the command bytes
byte[] data = Convert.FromBase64String(sipMessageRequest.Body);
byte type = SipComponent.Simoco.SP6.GetType(data);
byte command = SipComponent.Simoco.SP6.GetCommand(data);
switch (type)
{
case 0:
// GPS position report
byte[] nmeaData = new byte[10];
Array.Copy(data, 5, nmeaData, 0, nmeaData.Length);
// Get latitude, longitude, speed and time from nmea data
Simoco.Utils.GPSInfo(nmeaData, out lat, out lon, out speed, out time);
// Raise event
OnSimocoGpsReportReceived(new GpsDataEventArgs(senderID, lat, lon, speed, time));
break;
case 1:
// Device status
switch (command)
{
case 1:
// Device status report
// Sent on request or when alarm conditions change
// Is sent to remote radio to acknowledge receipt of alarm conditions
// Get GPS from status report
Simoco.Utils.GetGPSFromStatusReport(data, out lat, out lon);
Simoco.AlarmType alarmType = Simoco.SP6.GetAlarmType(data);
if (alarmType != Simoco.AlarmType.NO_ALARM)
{
// Save the message in a dictionary
// It have to be resent to the radio to confirm the receipt
AddSimocoAlarmToDictionary(senderID, sipMessageRequest.Body);
}
// Raise event
OnSimocoStatusReportReceived(new SimocoDeviceStatusReportEventArgs(
senderID, lat, lon, alarmType));
break;
}
break;
case 255:
// Ping
int nbOfReceivedBytes = data.Length - 5;
byte[] pingData = new byte[nbOfReceivedBytes];
Array.Copy(data, 5, pingData, 0, pingData.Length);
if (HandleSimocoPingResponse(senderID, pingData))
{
// Fire Event
OnSimocoPingResponseReceived(new SipEventArgs(senderID));
}
break;
}
break;
default:
// This is surelly incorect - TO DO
// Sms from Simoco
string text = sipMessageRequest.Body;
if (text != null) // body is null in case of status message - future implementation - TO DO
{
OnSmsReceived(new SmsReceivedEventsArgs(senderID,
Encoding.BigEndianUnicode.GetString(Convert.FromBase64String(text))
));
}
break;
}
}
}
internal override SipMessageGenerator SipMessageGenerator
{
get
{
return _sipMessageGenerator;
}
}
#endregion
#region events
public event EventHandler<SipEventArgs> EmergencyReceived;
#endregion
}
}