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 { /// /// An implementation of the abstract class SipClientClass, used for Excera /// public class SipClientClassExcera : SipClientClassSimoco { #region Fields private ExceraSipMessageGenerator _sipMessageGenerator = new ExceraSipMessageGenerator(); #endregion /// /// Constructor for the SipClientClassExcera /// /// domain name, name or IP address of sip server /// port number of the sip server /// port number of the local computer used for sip protocol /// user name on the sip server /// interval to send sip registration requests. Value is in seconds /// Miliseconds for the buffer that stores the received voice packets /// Number of ms to wait before the sip request times out /// Local Ip adress. If not specified, the class will search for a local ip on the same network with the repeater's ip 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 /// /// Method used to send a Ping command to an Excera radio /// /// The Excera ID of the radio public override void SendPing(string idToSendPing) { base.SendExceraPing(idToSendPing); } #endregion #region Non-Public Members Overrinding /// /// Function that processes all the received Sip Message requests /// /// The Sip Message request /// The ID of the sender 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 EmergencyReceived; #endregion } }