using System; using System.IO.Ports; using System.Text; using System.Threading; using HWModules; using SWModules; namespace SensorModules { // This is a Singleton instantiation based on // C# in Depth, Third Edition Jon Skeet // http://csharpindepth.com/Articles/General/Singleton.aspx // "a singleton is a class which only allows a single instance of itself to be created, and usually gives simple access to that instance" public sealed class Optode1 : Aandera4330Optode { private Optode1() : base("OPTODE1", "COM6", 9600, Parity.None, 8, StopBits.One, 5000, 20, false, 10) { } private static Optode1 instance; public static Optode1 Instance { get { return instance ?? (instance = new Optode1()); } } } public class Aandera4330Optode { HWModules.MotherBoard motherboard = MotherBoard.Instance; private static byte[] txBytes = new byte[64]; //MEASUREMENT 4330 1532 // O2Concentration[uM] 2.644894E+02 AirSaturation[%] 9.722411E+01 // Temperature[Deg.C] 2.217678E+01 CalPhase[Deg] 2.919595E+01 // TCPhase[Deg] 2.919595E+01 C1RPh[Deg] 3.770208E+01 // C2RPh[Deg] 8.506126E+00 C1Amp[mV] 8.645895E+02 // C2Amp[mV] 9.500998E+02 RawTemp[mV] 1.244538E+02 public enum OptodeSampleFields : int { O2Conc = 0, AirSat, TOpt, CalPhase, TCPhase, C1RPh, C2RPh, C1Amp, C2Amp, RawTemp } private NativeUART IOPort; public Aandera4330Optode (string id, string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, bool useSTX, byte STX) { IOPort = new NativeUART(id, QRecordType.Optode, processMessage, portName, baudRate, parity, dataBits, stopBits, readTimeout, writeTimeout, useSTX, STX); } private static byte[] setPasskeyLow = UTF8Encoding.UTF8.GetBytes("Set Passkey(1)\r\n"); private static byte[] setPasskeyHigh = UTF8Encoding.UTF8.GetBytes("Set Passkey(1000)\r\n"); private static byte[] disableText = UTF8Encoding.UTF8.GetBytes("Set Enable Text(no)\r\n"); private static byte[] enableText = UTF8Encoding.UTF8.GetBytes("Set Enable Text(yes)\r\n"); private static byte[] disableAirSat = UTF8Encoding.UTF8.GetBytes("Set Enable AirSaturation(no)\r\n"); private static byte[] disableRawdata = UTF8Encoding.UTF8.GetBytes("Set Enable Rawdata(no)\r\n"); private static byte[] disableCommTimeout = UTF8Encoding.UTF8.GetBytes("Set Comm TimeOut(Always On)\r\n"); private static byte[] disableSleep = UTF8Encoding.UTF8.GetBytes("Set Enable Sleep(no)\r\n"); private static byte[] save = UTF8Encoding.UTF8.GetBytes("Save\r\n"); public void init() { if (!IOPort.IsOpen) IOPort.Open(); IOPort.DiscardInBuffer(); IOPort.DiscardOutBuffer(); setProperties(); getConfig(); doSample(); } private void getConfig() { MessageQueue msgQ = MessageQueue.Instance; //send a crlf IOPort.WriteByte(10); IOPort.WriteByte(13); EngrLogger.Comment("Optode: Set passkey high"); IOPort.Write(setPasskeyHigh, 0, setPasskeyHigh.Length); Thread.Sleep(250); msgQ.processQ(); getAll(); Thread.Sleep(250); msgQ.processQ(); } private void setProperties() { MessageQueue msgQ = MessageQueue.Instance; //send a crlf IOPort.WriteByte(10); IOPort.WriteByte(13); EngrLogger.Comment("Optode: Set passkey high"); IOPort.Write(setPasskeyHigh, 0, setPasskeyHigh.Length); Thread.Sleep(250); msgQ.processQ(); EngrLogger.Comment("Optode: Disable text"); IOPort.Write(disableText, 0, disableText.Length); Thread.Sleep(250); msgQ.processQ(); EngrLogger.Comment("Optode: Disable air sat"); IOPort.Write(disableAirSat, 0, disableAirSat.Length); Thread.Sleep(250); msgQ.processQ(); EngrLogger.Comment("Optode: Disable comm timeout"); IOPort.Write(disableCommTimeout, 0, disableCommTimeout.Length); Thread.Sleep(250); msgQ.processQ(); EngrLogger.Comment("Optode: Disable sleep"); IOPort.Write(disableSleep, 0, disableSleep.Length); Thread.Sleep(250); msgQ.processQ(); } public void powerUp() { EngrLogger.writeToColumns("Powering up 4330 Optode"); motherboard.EnableChannelPower(MotherBoard.ChannelNames.OptodeChannel); Thread.Sleep(3000); init(); } public void powerDown() { EngrLogger.writeToColumns("Powering down 4330 Optode"); motherboard.DisableChannelPower(MotherBoard.ChannelNames.OptodeChannel); } public enum commands : int { none = 0, getAll, doSample } public static bool waitingForResponse = false; public static bool gotResponse = false; private static readonly StringBuilder getAllResponse = new StringBuilder("#\r"); public static byte[] expectedResponse = new byte[64]; public static int expectedResponseLength = 0; //private static int numRetries = 0; //private static readonly int maxNumRetries = 3; //private static TimeSpan wfrStartTime = new TimeSpan(); //private static readonly TimeSpan wfrTimeout = new TimeSpan(0, 0, 30); //private static readonly string wfrFail = "Optode waitingForResponse expended all retries"; private static StringBuilder sbTemp = new StringBuilder(128); //public static int waitForResponse(commands commandNum) //{ // if (waitingForResponse) // //Do this after the first call to this method // { // if (gotResponse) // //success // { // waitingForResponse = false; // return (1); // } // else if ((Microsoft.SPOT.Hardware.Utility.GetMachineTime() - wfrStartTime) > wfrTimeout) // //if timeout has expired, try again up to the max number of retries // { // if (numRetries > maxNumRetries) // { // //Debug.Print(wfrFail); // Array.Clear(qS.byteArray, 0, qS.byteArray.Length); // Array.Copy(UTF8Encoding.UTF8.GetBytes(wfrFail), qS.byteArray, wfrFail.Length); // qS.timeStamp = DateTime.Now; // qS.state = SV.CurrentState; // qS.qRecordType = StructQueue.QRecordType.Optode; // Program.sQueue.Enqueue(qS); // return (-1); // } // else // { // waitingForResponse = false; // sbTemp.Clear(); // sbTemp.Append("Optode waitingForResponse try number "); // sbTemp.Append(numRetries); // //Debug.Print(sbTemp.ToString()); // return (0); // } // } // else // return (0); // } // else // //Do this the first time the method is called and after a timeout // { // switch (commandNum) // { // case commands.getAll: // Array.Copy(UTF8Encoding.UTF8.GetBytes(getAllResponse.ToString()), expectedResponse, getAllResponse.Length); // expectedResponseLength = getAllResponse.Length; // //Debug.Print(DateTime.Now.TimeOfDay.ToString() + " Sending getAll command"); // getAll(); // break; // } // wfrStartTime = Microsoft.SPOT.Hardware.Utility.GetMachineTime(); // numRetries = numRetries + 1; // gotResponse = false; // waitingForResponse = true; // return (0); // } //} private static StringBuilder wakeUpCmd = new StringBuilder("\r"); public void wakeUp() { //Debug.Print("Sending Wake Up"); EngrLogger.writeToColumns("Sending Optode Wakeup"); Array.Clear(txBytes, 0, txBytes.Length); Array.Copy(Encoding.UTF8.GetBytes(wakeUpCmd.ToString()), txBytes, wakeUpCmd.Length); IOPort.Write(txBytes, 0, wakeUpCmd.Length); } private const string doSampleCmd = "Do Sample\r\n"; private const string doSampleHeader = "Sending Optode Do Sample"; public void doSample() { //Debug.Print("Sending Optode wakeup and Do Sample"); EngrLogger.writeToColumns(doSampleHeader); //Array.Clear(qS.byteArray, 0, qS.byteArray.Length); //Array.Copy(UTF8Encoding.UTF8.GetBytes(doSampleHeader), qS.byteArray, doSampleHeader.Length); //qS.state = SV.CurrentState; //qS.qRecordType = StructQueue.QRecordType.Optode; //qS.timeStamp = DateTime.Now; //Program.sQueue.Enqueue(qS); //wakeUp(); ////TODO P0 SHORTEN/// REMOVE /// //Thread.Sleep(500); Array.Clear(txBytes, 0, txBytes.Length); Array.Copy(Encoding.UTF8.GetBytes(doSampleCmd.ToString()), txBytes, doSampleCmd.Length); IOPort.Write(txBytes, 0, doSampleCmd.Length); } private const string getAllCmd = "get all\r\n"; public void getAll() { //Debug.Print("Sending Get All"); EngrLogger.writeToColumns("Sending Optode GetAll"); //wakeUp(); //Thread.Sleep(500); Array.Clear(txBytes, 0, txBytes.Length); Array.Copy(Encoding.UTF8.GetBytes(getAllCmd), txBytes, getAllCmd.Length); IOPort.Write(txBytes, 0, getAllCmd.Length); } private const string getConfigXMLCmd = "get ConfigXML\r\n"; public void getConfigXML() { //Debug.Print("Sending Get ConfigXML"); EngrLogger.writeToColumns("Sending Optode Get ConfigXML"); //wakeUp(); //Thread.Sleep(500); Array.Clear(txBytes, 0, txBytes.Length); Array.Copy(Encoding.UTF8.GetBytes(getConfigXMLCmd), txBytes, getConfigXMLCmd.Length); IOPort.Write(txBytes, 0, getConfigXMLCmd.Length); } private const string getDataXMLCmd = "get DataXML\r\n"; public void getDataXML() { //Debug.Print("Sending Get DataXML"); EngrLogger.writeToColumns("Sending Optode Get DataXML"); //wakeUp(); //Thread.Sleep(500); Array.Clear(txBytes, 0, txBytes.Length); Array.Copy(Encoding.UTF8.GetBytes(getDataXMLCmd), txBytes, getDataXMLCmd.Length); IOPort.Write(txBytes, 0, getDataXMLCmd.Length); } private static int msgLength = 0; private static readonly StringBuilder OptodeHeader = new StringBuilder("Optode Message"); private static readonly byte[] dataHeader = UTF8Encoding.UTF8.GetBytes("4330"); public void processMessage(QRecord qRecord) { for (int i = 0; i < qRecord.byteArray.Length; i++) { if (qRecord.byteArray[i] == 9) qRecord.byteArray[i] = 44; } if(SV.Pressure == double.NaN) EngrLogger.writeToColumns(EngrLiterals.ColumnNums.dateTime, qRecord.timeStamp, EngrLiterals.ColumnNums.state, qRecord.state, EngrLiterals.ColumnNums.comment, OptodeHeader, EngrLiterals.ColumnNums.TOpt, qRecord.byteArray); else EngrLogger.writeToColumns(EngrLiterals.ColumnNums.dateTime, qRecord.timeStamp, EngrLiterals.ColumnNums.state, qRecord.state, EngrLiterals.ColumnNums.comment, OptodeHeader, EngrLiterals.ColumnNums.pressure, SV.Pressure, EngrLiterals.ColumnNums.TOpt, qRecord.byteArray); //check for expectedResponse anywhere in the SBE41 response message msgLength = qRecord.byteArray.Length; if (Aandera4330Optode.waitingForResponse) { if (msgLength > Aandera4330Optode.expectedResponseLength) { for (int j = 0; j < msgLength - Aandera4330Optode.expectedResponseLength; j++) { for (int k = 0; k < Aandera4330Optode.expectedResponseLength; k++) { if (qRecord.byteArray[j + k] != Aandera4330Optode.expectedResponse[k]) { Aandera4330Optode.gotResponse = false; break; } } } Aandera4330Optode.gotResponse = true; } } if (SciLogger.sampling(SciLogger.Instruments.Optode) && !SciLogger.posted(SciLogger.Instruments.Optode)) { if ( (GHI.Utilities.Arrays.Contains(qRecord.byteArray, 0, 8, dataHeader, 0, dataHeader.Length)) > -1) { SciLogger.postSample(SciLogger.Instruments.Optode, qRecord.byteArray); sbTemp.Clear(); sbTemp.Append("Optode post: "); sbTemp.Append(SafeEncoding.GetChars(qRecord.byteArray)); EngrLogger.writeToColumns(sbTemp); } } } } }