using System; using System.Threading; using System.Text; using Microsoft.SPOT; namespace CPF { public static class Iridium { public enum Status { Idle, Checking }; private static A3LA _modem; private static byte[] _message; private static byte[] _response; private static int _responseLength; private static int _originatedStatus; private static int _originatedSeqnum; private static int _terminatedStatus; private static int _terminatedSeqnum; private static int _lengthOfMobileTerminatedMessage; private static int _numberOfQueuedMessagesAwaitingReception; private static StructQueue.qStruct _qe; private static Object _iridiumLock; private static ByteString _bs; private static Thread _pollingThread; private static AutoResetEvent _checkSignalQuality; private static int _timeBetweenRetriesInMs; private static int _maximumRetries; private static int _minimumSignalQuality; private static StringBuilder _signalQualityMessage; private static StringBuilder _retriesMessage; private static StringBuilder _failedMessage; private static StringBuilder _msg; private static double _voltage; private static bool _busyCheckingSQ; public static void PowerOn(string comPort, int baudRate = 19200) { if (_modem == null) { _modem = new A3LA(comPort, baudRate); _iridiumLock = new Object(); _response = new byte[2048]; _message = new byte[2048]; _bs = new ByteString(); _qe.byteArray = new Byte[StructQueue.qRecordWidth]; _modem.PowerOn(); _modem.ClearMobileOriginatedSequenceNumber(); _modem.ClearBuffers(A3LA.BuffersToClear.BothOriginatedAndTerminated); _pollingThread = new Thread(new ThreadStart(AwaitSufficientSignaLQuality)); _checkSignalQuality = new AutoResetEvent(false); _timeBetweenRetriesInMs = 10000; _maximumRetries = 3; _minimumSignalQuality = 1; _signalQualityMessage = new StringBuilder("Signal Quality = "); _retriesMessage = new StringBuilder(" Retries = "); _failedMessage = new StringBuilder("Retries exhausted, insufficient signal quality"); _msg = new StringBuilder(256); _voltage = Double.NaN; _busyCheckingSQ = false; _pollingThread.Start(); } } private static void AwaitSufficientSignaLQuality() { int retries; while (true) { _checkSignalQuality.WaitOne(); for (retries = _maximumRetries; retries > 0; retries--) { int sq = _modem.SignalQuality(); _msg.Clear(); _msg.Append(_signalQualityMessage + sq.ToString() + _retriesMessage + retries.ToString()); EngrLogger.writeToColumns(EngrLogger.ColumnNums.comment, EngrLogger.getPrefix(_msg)); if (sq >= _minimumSignalQuality) break; if (retries > 1) Thread.Sleep(_timeBetweenRetriesInMs); } if (retries > 0) { _modem.Register(); // So that the Iridium network can route MT messages to us... UpdatePosition(_voltage); } else { EngrLogger.writeToColumns(EngrLogger.ColumnNums.comment, EngrLogger.getPrefix(_failedMessage)); } lock (_iridiumLock) { _busyCheckingSQ = false; } } } public static void ReportPosition(int retries, int timeBetweenRetries, double batteryVoltage) { lock (_iridiumLock) { if (!_busyCheckingSQ) { _maximumRetries = retries; _timeBetweenRetriesInMs = timeBetweenRetries; _voltage = batteryVoltage; _busyCheckingSQ = true; _checkSignalQuality.Set(); } } } private static void UpdatePosition(double batteryVoltage) { _bs.Clear(); _bs.Append(uBlox.Last_GGA_MessageReceived()); _bs.Append(IridiumStrings.BVMSG, IridiumStrings.BVMSG.Length); String s = batteryVoltage.ToString("F2"); _bs.Append(s); _bs.Append(IridiumStrings.SILLYSUM, IridiumStrings.SILLYSUM.Length); Array.Clear(_qe.byteArray, 0, _qe.byteArray.Length); Array.Copy(_bs.GetByteArray(), 0, _qe.byteArray, 0, _bs.Length); _qe.errorCode = (int)_modem.SendTextMessage(_qe.byteArray, _bs.Length); if (_qe.errorCode == (int)A3LA.Response.Match) { _modem.Status(out _originatedStatus, out _originatedSeqnum, out _terminatedStatus, out _terminatedSeqnum, out _lengthOfMobileTerminatedMessage, out _numberOfQueuedMessagesAwaitingReception); _qe.errorCode = _originatedStatus; _modem.ClearBuffers(A3LA.BuffersToClear.MobileOriginated); if (_qe.errorCode == A3LA.MO_TransferredSuccessfully) { _qe.errorCode = _numberOfQueuedMessagesAwaitingReception + 1; QueueMessage(StructQueue.QRecordType.PositionReport); if ((_terminatedStatus == 1) && (_lengthOfMobileTerminatedMessage > 0)) { Array.Clear(_qe.byteArray, 0, _qe.byteArray.Length); _modem.ReceiveTextMessage(_qe.byteArray, out _responseLength); QueueMessage(StructQueue.QRecordType.MT_MessageArrived); do { _modem.Status(out _originatedStatus, out _originatedSeqnum, out _terminatedStatus, out _terminatedSeqnum, out _lengthOfMobileTerminatedMessage, out _numberOfQueuedMessagesAwaitingReception); if ((_terminatedStatus == 1) && (_lengthOfMobileTerminatedMessage > 0)) { Array.Clear(_qe.byteArray, 0, _qe.byteArray.Length); _modem.ReceiveTextMessage(_qe.byteArray, out _responseLength); QueueMessage(StructQueue.QRecordType.MT_MessageArrived); } } while (_numberOfQueuedMessagesAwaitingReception > 0); } } } } private static void QueueMessage(StructQueue.QRecordType eventType) { _qe.timeStamp = DateTime.Now; _qe.state = Program.CPFState; _qe.qRecordType = eventType; _qe.errorCode = _terminatedStatus + A3LA.MT_Offset; lock (_iridiumLock) { Program.sQueue.Enqueue(_qe); } } public static void PowerOff() { _pollingThread.Abort(); } } }