/*
Copyright 2010 GHI Electronics LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
using System;
using System.Collections;
using System.Text;
using System.Threading;
using GHIElectronics.NETMF.USBClient;
using Microsoft.SPOT;
namespace Fez.IO
{
public delegate void MessageFunc(string value);
public delegate void Action();
///
/// FezTermHost class is the terminal object which runs on the Fez and
/// listens for commands.
///
public class FezTermHost
{
public event MessageFunc MessageReceived;
public event Action Stopped;
USBC_CDC port;
int isRunning = 0;
byte delim;
public FezTermHost(byte delim)
{
this.delim = delim;
}
public bool IsRunning
{
get { return isRunning == 1; }
}
public void Start()
{
if (Interlocked.CompareExchange(ref isRunning, 1, 0) == 0)
{
InitCDC();
}
}
public void Stop()
{
if (Interlocked.CompareExchange(ref isRunning, 0, 1) == 1)
{
USBClientController.Stop();
MessageReceived = null;
Debug.Print("FezTerm Stopped.");
var ev = Stopped;
if (ev != null) ev();
}
}
///
/// Start the CDC (virtual comm) port on the current debug session.
/// This will stop the current session and restart with a new driver which will create the dual channel.
/// To reattach debugger channel, you need to hit "Break All" and then Continue. You should then have
/// a new V-Comm port on the PC and a comm port on the fez.
///
private void InitCDC()
{
Debug.Print("Hit Break All in VS to reattach debugger to port, then Run Continue.");
port = USBClientController.StandardDevices.StartCDC_WithDebugging();
port.ReadTimeout = -1; // Block waiting for chars.
while (true)
{
if (USBClientController.GetState() != USBClientController.State.Running)
{
Debug.Print("waiting to connect.");
Thread.Sleep(600);
}
else
{
Debug.Print("CDC connected.");
break;
}
}
// Start read loop on new thread.
new Thread(ReadLoop).Start();
}
private void ReadLoop()
{
isRunning = 1;
while (isRunning == 1)
{
string line = ReadLine(); // Blocking call.
var ev = MessageReceived;
if (ev != null)
ev(line);
}
}
///
/// Simple loop that reads single chars until delim byte
/// and returns the string. We could improve perf by reading more chars per read.
///
///
private string ReadLine()
{
// Read and buffer chars until a newline char.
ArrayList line = new ArrayList();
byte[] buf = new byte[1];
int count = 0;
while ((count = this.port.Read(buf, 0, 1)) > 0)
{
if (buf[0] == delim)
break;
line.Add(buf[0]);
}
// Convert ArrayList to char[] using UTF8 encoding.
byte[] bytes = new byte[line.Count];
for(int i=0; i
/// We write messages, not lines, using delim and message marker.
///
///
/// Number of bytes written.
public int WriteMessage(string message)
{
if (message == null) throw new ArgumentNullException("message");
if (this.isRunning != 1) return 0;
// Write reply appending newLine delim.
byte[] ba = Encoding.UTF8.GetBytes(message);
this.port.Write(ba, 0, ba.Length);
this.port.Write(new byte[] { delim }, 0, 1); // write msg marker.
return ba.Length + 1;
}
}
}