You asked for it…
Here is a program file. It’s still pretty much a shell, but it functions well. The purpose of this routine is to take the printer language (in this case a manufacturers propritary set not unlike PCL or ESC/POS) and port it through a bluetooth link via SPP and to a printer that utilizes a USB connection. The printer protocol requires bi-directional data because the printer sends back a variety of status data and fonts etc etc. The USB Printer class would not work for this as it only sends back IEEE 1284 printer status (parallel port emulation).
Now some might ask why not just use a serial printer…well the problem is that serial printers tend to communicate at slower baud rates. With this setup I can communicate at 921.6kbps over bluetooth to the FEZ and from there at the full USB 2.0 speeds which are much faster.
Next I’d like to use the bluetooth module (or one from a different manufacturer) and utilize some other method of data transfer to get up to 3mbps. Have not really explored this fully yet, but it seems plausable. Anybody have experience with this?
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System;
using System.IO.Ports;
using System.Threading;
using System.Text;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.USBHost;
using GHIElectronics.NETMF.System;
using GHIElectronics.NETMF.Hardware;
namespace innoagg
{
public class Program
{
//pointersd
static SerialPort UART; //serial port
static USBH_RawDevice USB; //usb device
static USBH_RawDevice.Pipe USB_PIPE_IN; //data pipe
static USBH_RawDevice.Pipe USB_PIPE_OUT; //data pipe
static Thread USB_Data_In_Handler; //thread for data to the device
//set DIO's
static OutputPort DTR = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.UEXT9, true); //dtr pin output to serial device
static InterruptPort DSR = new InterruptPort((Cpu.Pin)FEZ_Pin.Digital.UEXT10, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth); //dsr input pin from serial device
static OutputPort LED_Act = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false); //board LED
//flags
static bool COMMAND_MODE = false; //command mode status flag
const int COMMAND_MODE_TIMEOUT = 2000; //command input time window
Thread CMD_TIMEOUT; //allows for command input window
//usb sepcification constants
const byte bRequest_GET_STATUS = 0x00;
const byte bRequest_CLEAR_FEATURE = 0x01;
const byte bRequest_SET_FEATURE = 0x03;
const byte bRequest_SET_ADDRESS = 0x05;
const byte bRequest_GET_DESCRIPTOR = 0x06;
const byte bRequest_SET_DESCRIPTOR = 0x07;
const byte bRequest_GET_CONFIGURATION = 0x08;
const byte bRequest_SET_CONFIGURATION = 0x09;
const byte bRequest_GET_INTERFACE = 0x0A;
const byte bRequest_SET_INTERFACE = 0x0B;
const byte bRequest_SYNCH_FRAME = 0x0C;
const byte bRequest_GET_PORT_STATUS = 0x01;
const byte bmRequestType_GET_PORT_STATUS = 0xA1;
//data handling settings
const int USB_CHUNK_SIZE = 4 * 1024;
const int USB_CHUNK_TIMEOUT = 500;
const int USB_CHUNK_RETRIES = 5;
const int USB_CHUNK_NORMAL_DELAY = 0;
const int USB_CHUNK_FAILED_DELAY = 250;
const int USB_READ_INTERVAL = 100;
const int UART_CHUNK_SIZE = 8;
const int UART_CHUNK_TIMEOUT = 500;
const int UART_CHUNK_RETRIES = 5;
const int UART_CHUNK_NORMAL_DELAY = 0;
const int UART_CHUNK_FAILED_DELAY = 250;
const bool PIN_ON = false;
const bool PIN_OFF = true;
public static void Mainx()
{
DTR.Write(true);
DTR.Write(false);
DTR.Write(true);
}
public static void Main()
{
//subscribe to usb host events
USBHostController.DeviceConnectedEvent += OnDeviceConnected;
USBHostController.DeviceDisconnectedEvent += OnDeviceDisconnected;
try
{
//configure the UART connection
UART = new SerialPort("COM2");
UART.BaudRate = 230400;
UART.DataBits = 8;
UART.Parity = Parity.None;
UART.StopBits = StopBits.One;
UART.Handshake = Handshake.RequestToSend;
UART.Open();
if (UART.IsOpen)
{
//subscribe to UART events
UART.DataReceived += new SerialDataReceivedEventHandler(OnRecvUARTData);
UART.ErrorReceived += new SerialErrorReceivedEventHandler(OnUARTError);
Debug.Print("COM Port Opened");
//set the event handler for DSR
DSR.OnInterrupt += new NativeEventHandler(OnDSR);
}
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
LED_Act.Write(false);
Thread.Sleep(Timeout.Infinite);
}
static void OnDeviceDisconnected(USBH_Device device)
{
Debug.Print("Device disconnected");
if (USB_Data_In_Handler.ThreadState == ThreadState.Running)
{
USB_Data_In_Handler.Abort();
}
DTR.Write(PIN_OFF);
}
static void OnDeviceConnected(USBH_Device device)
{
//configure the USB Host connection to device
//create the device
Debug.Print("Device Detected");
try
{
//check for cases not to attempt a device connection
//if there is no UART open at this point then no sense connecting to USB.
while (!UART.IsOpen)
{
Thread.Sleep(100); //sleep a little to see if we can break out here...
if (UART.IsOpen) { break; }
}
if (device.TYPE == USBH_DeviceType.Printer)
{
Debug.Print("Printer Detected");
USB = new USBH_RawDevice(device);
// Get descriptors
//USB_Descriptors.DeviceDescriptor dd = USB.GetDeviceDescriptor();
USB_Descriptors.ConfigurationDescriptor cd = USB.GetConfigurationDescriptors(0);
// communication endpoints
USB_Descriptors.EndpointDescriptor USB_EP_IN = null; //for data from device
USB_Descriptors.EndpointDescriptor USB_EP_OUT = null; //for data to device
// BULK OUT
USB_EP_OUT = cd.interfaces[0].endpoints[1]; // get endpoint
USB_PIPE_OUT = USB.OpenPipe(USB_EP_OUT);
USB_PIPE_OUT.TransferTimeout = USB_CHUNK_TIMEOUT;
Debug.Print("BULK OUT pipe set");
// BULK IN
USB_EP_IN = cd.interfaces[0].endpoints[0]; // get endpoint
USB_PIPE_IN = USB.OpenPipe(USB_EP_IN);
USB_PIPE_IN.TransferTimeout = USB_CHUNK_TIMEOUT;
Debug.Print("BULK IN pipe Set");
//set configuration
USB.SendSetupTransfer(0x00, bRequest_SET_CONFIGURATION, cd.bConfigurationValue, 0x00);
//setup thread to handle data inbound from device
USB_Data_In_Handler = new Thread(usb_DataIn);
USB_Data_In_Handler.Priority = ThreadPriority.Normal;
//flush the buffers before we indicate ready
UART.DiscardInBuffer();
UART.DiscardOutBuffer();
UART.Flush();
//signal to the PC host that the device is OK with DTR signal
DTR.Write(PIN_ON);
//start the usb pipe in handler
USB_Data_In_Handler.Start();
}
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
LED_Act.Write(false);
}
static void usb_dataOut(byte[] data)
{
//check for condition where a write operation can't happen
if (DTR.Read())
{
Debug.Print("Can't write data to USB pipe when device is not ready");
return;
}
//send the data out to the usb bulk out pipe
LED_Act.Write(true);
try
{
Debug.Print("Sending " + data.Length + " bytes out USB out pipe");
int offset = 0;
int retries = USB_CHUNK_RETRIES;
while (offset < data.Length && retries > 0)
{
int count = System.Math.Min(USB_CHUNK_SIZE, data.Length - offset);
int chunkEnd = offset + count;
retries = USB_CHUNK_RETRIES;
while (offset < chunkEnd && retries-- > 0)
{
int writeCount = 0;
try
{
writeCount += USB_PIPE_OUT.TransferData(data, offset, chunkEnd - offset);
offset += writeCount;
}
catch { LED_Act.Write(false); }
if (writeCount == 0)
{
Debug.Print("USB chunk failed to send at offset " + offset.ToString() + ", len " + (chunkEnd - offset).ToString());
Thread.Sleep(USB_CHUNK_FAILED_DELAY);
}
else
{
Thread.Sleep(USB_CHUNK_NORMAL_DELAY);
}
}
}
if (retries > 0)
{
Debug.Print("out bulk completed");
}
else
{
Debug.Print("out bulk failed");
}
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
LED_Act.Write(false);
}
static void uart_datOut(byte[] data)
{
//send data out the UART to the host PC
LED_Act.Write(true);
try
{
int offset = 0;
int retries = UART_CHUNK_RETRIES;
while (offset < data.Length && retries > 0)
{
int count = System.Math.Min(UART_CHUNK_SIZE, data.Length - offset);
int chunkEnd = offset + count;
Debug.Print("Sending " + count + " bytes out UART");
retries = UART_CHUNK_RETRIES;
while (offset < chunkEnd && retries-- > 0)
{
int writeCount = 0;
try
{
writeCount = UART.Write(data, offset, chunkEnd - offset);
offset += writeCount;
}
catch { LED_Act.Write(false); }
if (writeCount == 0)
{
Debug.Print("UART chunk failed to send at offset " + offset.ToString() + ", len " + (chunkEnd - offset).ToString());
Thread.Sleep(UART_CHUNK_FAILED_DELAY);
}
else
{
Thread.Sleep(UART_CHUNK_NORMAL_DELAY);
}
}
}
if (retries > 0)
{
Debug.Print("uart out completed");
}
else
{
Debug.Print("uart out failed");
}
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
LED_Act.Write(false);
}
static void usb_DataIn()
{
//data returned on the BULK IN pipe gets sent out the UART
//Maximum data is wMaxPacketSize
byte[] usbData = new byte[USB_PIPE_IN.PipeEndpoint.wMaxPacketSize];
int count = 0;
//Read every USB_READ_INTERVAL
while (true)
{
Thread.Sleep(USB_READ_INTERVAL);
try
{
count = USB_PIPE_IN.TransferData(usbData, 0, usbData.Length);
}
catch (Exception ex)
{
//usbData = null;
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
//TODO: process the outbound data with an additional formatted status bytes
//from various sensors and local processing
//need to devise a method to make multiple channels of data
if (UART.IsOpen)
{
if (count > 0)
{
try
{
byte[] pData = new byte[count];
Array.Copy(usbData, pData, count);
uart_datOut(pData);
pData = null;
Debug.Print("Data Relayed");
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
}
}
}
}
static void OnDSR(uint port, uint state, DateTime time)
{
Debug.Print("DSR State:" + state.ToString());
//use this as a trigger to toggle command mode
if (state == 1) //PC host disconnect
{
COMMAND_MODE = true;
Debug.Print("Command mode ON");
Thread CMD_TIMEOUT = new Thread(ResetCommandMode);
CMD_TIMEOUT.Start();
}
}
static void ResetCommandMode()
{
Thread.Sleep(COMMAND_MODE_TIMEOUT);
COMMAND_MODE = false;
Debug.Print("Command mode OFF");
}
static void OnRecvUARTData(object sender, SerialDataReceivedEventArgs e)
{
//Process inbound UART data from PC host.
try
{
byte[] inBuffer = new byte[UART.BytesToRead];
int count = 0;
//check for command mode status based on DSR pin
if (COMMAND_MODE)
{
//read command
count = UART.Read(inBuffer, 0, inBuffer.Length);
if (count > 0)
{
//echo command the data back to PC host
UART.Write(inBuffer, 0, inBuffer.Length);
//TODO: add command processing here
}
}
else
{
//Relay data to the USB host processor
count = UART.Read(inBuffer, 0, inBuffer.Length);
if (count > 0) {usb_dataOut(inBuffer);}
}
}
catch (Exception ex)
{
Debug.Print(ex.Message + "\r\n" + ex.ToString());
}
}
static void OnUARTError(object sender, SerialErrorReceivedEventArgs e)
{
Debug.Print("UART Error");
}
}
}