using System;
using System.IO.Ports;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.Win32;
namespace MakingThings
{
public interface PacketIO
{
bool Open();
void Close();
bool IsOpen();
void SendPacket( byte[] packet, int length );
int ReceivePacket( byte[] packet );
}
public abstract class UsbPacketBase: PacketIO
{
protected UsbPacketBase()
{
StuffChars = new Byte[4];
StuffChars[EndIndex] = End;
StuffChars[EscIndex] = Esc;
StuffChars[EscEndIndex] = EscEnd;
StuffChars[EscEscIndex] = EscEsc;
}
///
/// Open the serial port that the board is connected to.
///
/// True on success, false on fail.
public bool Open()
{
PortName = GetPortName();
//PortName = "COM1";
if (PortName == null)
return false;
return PortOpen( PortName );
}
///
/// Close the serial port that the board is currently connected to.
/// If the port is not already open, this has no effect.
///
public void Close()
{
PortClose( );
}
///
/// Query the open state of the serial port.
///
/// True if the port is open, false if it is not.
public bool IsOpen()
{
return PortIsOpen();
}
///
/// Send a packet of bytes out over the serial port.
///
/// The byte array to be sent.
/// The length of the byte array to be sent.
public void SendPacket(byte[] packet, int length)
{
if (!IsOpen())
Open();
if (!IsOpen())
return;
//Console.WriteLine("SendPacket:");
PortWrite(StuffChars, EndIndex, 1);
//Console.WriteLine(" End");
for (int i = 0; i < length; i++)
{
int c = packet[i];
if (c == End)
{
//Console.WriteLine(" Esc");
PortWrite(StuffChars, EscIndex, 1);
//Console.WriteLine(" EscEnd");
PortWrite(StuffChars, EscEndIndex, 1);
}
else
{
if (c == Esc)
{
//Console.WriteLine(" Esc");
PortWrite(StuffChars, EscIndex, 1);
//Console.WriteLine(" EscEsc");
PortWrite(StuffChars, EscEscIndex, 1);
}
else
{
//Console.WriteLine(" " + c);
PortWrite(packet, i, 1);
}
}
}
PortWrite(StuffChars, EndIndex, 1);
//Console.WriteLine(" End");
}
///
/// Receive a packet of bytes from the serial port.
///
/// The buffer to be read into.
/// Returns the number of bytes read, or 0 on failure.
public int ReceivePacket(byte[] buffer)
{
if (!IsOpen())
Open();
if (!IsOpen())
return 0;
int index = 0;
// Skip until there's an End character
while (PortReadByte() != End)
;
// Now we have a End we can start getting actual chars
int c;
bool escaped = false;
do
{
c = PortReadByte();
if (c != End)
{
if (escaped)
{
if (c == EscEnd)
buffer[index++] = End;
if (c == EscEsc)
buffer[index++] = Esc;
escaped = false;
}
else
{
if (c == Esc)
escaped = true;
else
buffer[index++] = (byte)c;
}
}
} while (c != End);
return index;
}
///
/// Read the name and parameters of the serial port that the board is connected to.
///
/// Prints the name and parameters to the Console.
///
/// The COM port name the board is connected to.
private string GetPortName()
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey(RegistryLocalMachinePath);
string[] topNames = rk.GetSubKeyNames();
// Print the contents of the array to the console.
foreach (string ts in topNames)
{
// Console.WriteLine("Top: " + ts);
try
{
RegistryKey srk = rk.OpenSubKey(ts);
string[] subNames = srk.GetSubKeyNames();
foreach (string ss in subNames)
{
RegistryKey trk = srk.OpenSubKey(ss);
if ((string)trk.GetValue("Class", "") == "Ports" &&
(string)trk.GetValue("ClassGUID", "") == MakingThingsUsbGuid &&
(string)trk.GetValue("DeviceDesc", "") == MakingThingsUsbDesc)
{
Console.WriteLine("Usb: " + ss);
Console.WriteLine(" " + trk.GetValue("FriendlyName", ""));
RegistryKey prk = trk.OpenSubKey("Device Parameters");
string portName = (string)prk.GetValue("PortName", "");
Console.WriteLine(" " + portName);
// If this doesn't work, there will be an exception, taking us away
try
{
if (PortOpen(portName))
{
Thread.Sleep(1000);
// It did work. This is us. Return.
PortClose();
return portName;
}
}
catch
{
Console.WriteLine(" Open Exception");
}
}
}
}
catch (System.Exception)
{
}
}
return null;
}
private const string RegistryLocalMachinePath = "SYSTEM\\CURRENTCONTROLSET\\ENUM\\USB";
private const string MakingThingsUsbGuid = "{4D36E978-E325-11CE-BFC1-08002BE10318}";
private const string MakingThingsUsbDesc = "Make Controller Kit";
// Byte stuffing
// ... characters
private const int End = 192;
private const int Esc = 219;
private const int EscEnd = 220;
private const int EscEsc = 221;
// ... indicies into the little byte array
private const int EndIndex = 0;
private const int EscIndex = 1;
private const int EscEndIndex = 2;
private const int EscEscIndex = 3;
Byte[] StuffChars;
private string PortName;
public string Name
{
get { return PortName; }
}
abstract public bool PortOpen(string portName);
abstract public void PortClose();
abstract public bool PortIsOpen();
abstract public int PortReadByte();
abstract public int PortWrite(byte[] buffer, int index, int count);
}
public class UsbPacket : UsbPacketBase
{
public override bool PortOpen( string portName )
{
if ( Port == null )
{
Port = new SerialPort();
Port.PortName = portName;
try
{
Port.Open();
Port.DtrEnable = true;
}
catch
{
Port = null;
return false;
}
}
return true;
}
public override void PortClose()
{
if (Port != null)
{
Port.Close();
Port = null;
}
}
public override bool PortIsOpen()
{
return (Port != null);
}
public override int PortReadByte()
{
int c;
c = Port.ReadByte();
//Console.WriteLine("R " + c);
return c;
}
public override int PortWrite(byte[] buffer, int index, int count)
{
if (Port != null)
{
Port.Write(buffer, index, count);
return count;
}
else
return 0;
}
private SerialPort Port;
}
///
/// UdpPacket provides packetIO over UDP
///
public class UdpPacket : PacketIO
{
public UdpPacket()
{
RemoteHostName = "192.168.0.200";
RemotePort = 10000;
LocalPort = 10000;
socketsOpen = false;
}
~UdpPacket()
{
if (IsOpen())
Close();
}
///
/// Open a UDP socket and create a UDP sender.
///
/// The default values with which a UdpPacket is created are:
/// - Address of the board to send to - 192.168.0.200
/// - Remote port to send to - 10000
/// - Local port to listen on - 10000
///
/// True on success, false on failure.
public bool Open()
{
try
{
Sender = new UdpClient();
Receiver = new UdpClient(localPort);
socketsOpen = true;
return true;
}
catch
{
}
return false;
}
///
/// Close the socket currently listening, and destroy the UDP sender device.
///
public void Close()
{
Sender.Close();
Receiver.Close();
socketsOpen = false;
}
///
/// Query the open state of the UDP socket.
///
/// True if open, false if closed.
public bool IsOpen()
{
return socketsOpen;
}
///
/// Send a packet of bytes out via UDP.
///
/// The packet of bytes to be sent.
/// The length of the packet of bytes to be sent.
public void SendPacket(byte[] packet, int length)
{
if (!IsOpen())
Open();
if (!IsOpen())
return;
Sender.Send(packet, length, remoteHostName, remotePort);
}
///
/// Receive a packet of bytes over UDP.
///
/// The buffer to be read into.
/// The number of bytes read, or 0 on failure.
public int ReceivePacket(byte[] buffer)
{
if (!IsOpen())
Open();
if (!IsOpen())
return 0;
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 0);
byte[] incoming = Receiver.Receive( ref iep );
int count = Math.Min(buffer.Length, incoming.Length);
System.Array.Copy(incoming, buffer, count);
return count;
}
private UdpClient Sender;
private UdpClient Receiver;
private bool socketsOpen;
private string remoteHostName;
private int remotePort;
private int localPort;
///
/// The address of the board that you're sending to.
///
public string RemoteHostName
{
get
{
return remoteHostName;
}
set
{
remoteHostName = value;
}
}
///
/// The remote port that you're sending to.
///
public int RemotePort
{
get
{
return remotePort;
}
set
{
remotePort = value;
}
}
///
/// The local port you're listening on.
///
public int LocalPort
{
get
{
return localPort;
}
set
{
localPort = value;
}
}
}
}