using System; using System.Threading; using System.IO.Ports; using System.Text; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; namespace DEV { public class SerialReadBufferOverflow : System.Exception { public SerialReadBufferOverflow() : base() { } } public class FramingError : System.Exception { public FramingError() : base() { } } public class OverrunError : System.Exception { public OverrunError() : base() { } } public class ReceiverOverflow: System.Exception { public ReceiverOverflow() : base() { } } public class ReceiveParityError : System.Exception { public ReceiveParityError() : base() { } } public class TX_BufferFull: System.Exception { public TX_BufferFull() : base() { } } public class Channel_WTF : System.Exception { public Channel_WTF() : base() { } } public delegate void StreamHandler(byte[] buffer); // This class enables building simple user interfaces to send and receive data over a serial port. // Incoming serial data is handled in an event-driven manner. public class Channel : IDisposable { private SerialPort _port; private byte _readBufferIndex = 0; private byte[] _readBuffer = new byte[100]; private bool _continueReading = false; private UTF8Encoding _encoding = new UTF8Encoding(); private Thread _readThread; // Method to be called back once the input has been received for this option or item in a series of inputs public StreamHandler Callback { get; set; } public byte Terminator { get; set; } public Channel(string port, Int32 baudRate) { Callback = null; Terminator = 0x0A; _port = new SerialPort(port, baudRate, Parity.None, 8, StopBits.One); _port.ReadTimeout = Timeout.Infinite; _port.WriteTimeout = 20; _port.Open(); _port.ErrorReceived += new SerialErrorReceivedEventHandler(ErrorOccurredHandler); } // Immediately send a line of text to the serial port public void Send(string line) { byte[] bytes = _encoding.GetBytes(line); _port.Write(bytes, 0, bytes.Length); } // Immediately send a line of text to the serial port public void Send(byte[] _buffer) { _port.Write(_buffer, 0, _buffer.Length); } // Start accepting user input from the serial port public void Start() { _continueReading = true; _readThread = new Thread(ReadLoop); _readThread.Start(); } // Stop accepting input from the serial port public void Stop() { _continueReading = false; if (_readThread.ThreadState == ThreadState.WaitSleepJoin) // If the read thread is sleeping _readThread.Abort(); // take a hammer to end the thread } // Starts waiting for data in order to fire DataReceived event. private void ReadLoop() { while (_continueReading) { try { if (_readBufferIndex < _readBuffer.Length) _port.Read(_readBuffer, _readBufferIndex, 1); else throw new SerialReadBufferOverflow(); if (_readBuffer[_readBufferIndex] == Terminator) { // Null terminate the character string _readBuffer[_readBufferIndex] = 0; // Process the input Callback(_readBuffer); // Flush the read buffer _readBufferIndex = 0; _readBuffer[_readBufferIndex] = 0; } else { _readBufferIndex++; } } // wait for some data (set _readBufferSize to 1 to wait for any data) catch (ThreadAbortException) { return; } // (if we were aborted, pass away silently) } } // Free up the resources public void Dispose() { _port.Flush(); _port.Close(); _port = null; _readBuffer = null; _encoding = null; Callback = null; } private void ErrorOccurredHandler(object sender, SerialErrorReceivedEventArgs e) { switch (e.EventType) { case SerialError.Frame: // throw new FramingError(); break; case SerialError.Overrun: throw new OverrunError(); case SerialError.RXOver: throw new ReceiverOverflow(); case SerialError.RXParity: throw new ReceiveParityError(); case SerialError.TXFull: throw new TX_BufferFull(); default: throw new Channel_WTF(); } } } }