Class Program is where my code starts. I start a thread function ProcessCommandsLoop(). Before going into an endless loop, the ProcessCommandsLoop() function calls new PrototypeDevice(), and in the constructor for PrototypeDevice(), I call the constructor for class IntermecIF2(). The IntermecIF2() constructor starts the RS232DataReader thread.
namespace SmartTruckRaptor
{
public partial class Program
{
private AutoResetEvent StartEvent;
private int StartTimer;
private GT.Timer DelayStartTimer;
private KioskTouchScreen TouchScreenServer;
/// <summary>
///This method is run when the mainboard is powered up or reset.
/// </summary>
void ProgramStarted()
{
try
{
KioskUtilities.StartWatchDogKicker(this, Mainboard);
//Initialize the Glide touch screen user interface object
TouchScreenServer = new KioskTouchScreen();
StartEvent = new AutoResetEvent(false);
StartTimer = 3;
DelayStartTimer = new GT.Timer(1000, GT.Timer.BehaviorType.RunContinuously); // every second (1000ms)
DelayStartTimer.Tick += new GT.Timer.TickEventHandler(DelayStartTimer_Tick);
DelayStartTimer.Start();
ThreadStart starter = new ThreadStart(ProcessCommandsLoop);
Thread th = new Thread(starter);
th.Start();
}
catch (Exception ex)
{
KioskUtilities.LogException("ProgramStarted() exception", ex);
KioskUtilities.Reboot();
}
}
/// <summary>
/// Count down X seconds, then set the StartEvent to start the program
/// Needed to give debugger time to attach and NETMF to initialize
/// </summary>
/// <param name="timer"></param>
void DelayStartTimer_Tick(GT.Timer timer)
{
if (StartTimer > 0)
{
Debug.Print("Waiting for debugger - time = " + StartTimer.ToString());
--StartTimer;
}
else
{
StartEvent.Set();
DelayStartTimer.Stop();
}
}
/// <summary>
/// Endless loop to poll for commands from the DeviceHive server. This must be in a thread so that
/// the main thread is not blocked and the GHI dispatcher runs to service Gadgeteer devices.
/// </summary>
void ProcessCommandsLoop()
{
try
{
bool rv = false;
//wait for Gadgeteer system to start up and debugger to attach if needed
StartEvent.WaitOne();
PrototypeDevice Raptor = new PrototypeDevice(ethernet_ENC28,
rs232, rs2322, rs2323, rs2324, rs485,
relay_X1, keypad_KP16, display_T43, sdCard, temperatureHumidity, TouchScreenServer);
if (Raptor.Init())
{
//Cobra ethernet TCP/IP is started
while (true)
{
//keep trying to connect until connected
while (!rv)
{
rv = Raptor.Connect();
}
//keep processing commands until error
while (rv)
{
rv = Raptor.ProcessCommands();
}
}
}
else
{
Debug.Print("ProcessCommandsLoop() error - Cobra Ethernet cannot be started");
}
}
catch (Exception ex)
{
//This is the top-level exception catch
KioskUtilities.LogException("ProcessCommandsLoop() exception", ex);
KioskUtilities.Reboot();
}
finally
{
Debug.Print("Command processing has exited");
KioskUtilities.Reboot();
}
}
}
}
/// <summary>
/// Class to handle writing text to the ProLite display and traffic light control
/// A type of "EquipmentEngine" so it can be an equipment item in the DeviceHive Server
/// </summary>
public class IntermecIF2 : EquipmentEngine
{
public event IF2EventHandler IF2Event;
private int LoggingLevel;
private SystemConfigData systemData;
private GTME.RS232 RS232RFID;
private const string StateParameter = "state"; //for DeviceHive notification
private const string DeviceTypeName = "Intermec IF2 RFID reader"; //for DeviceHive registration
private const int MaxRxDataQueueSize = 2000; //limit on qty of chars to put on RS232 received data Queue
private const int Baud_Rate = 115200;
private ByteQueue RxDataQueue;
private AutoResetEvent RxDataEvent;
//private int RxDataQueueSizeExpected;
private byte[] RxDataBuf;
//private int RxDataCount;
private byte[] RS232Data;
private int RS232Count;
private StringBuilder RxLine;
private Queue RxLineQueue;
private Queue AsyncLineQueue;
private AutoResetEvent RxLineQueueEvent;
private AutoResetEvent AsyncLineQueueEvent;
private ArrayList RxLineList;
private Object SendDataLock;
private DeviceEngine ThisDevice;
public bool InUse { get; set; }
/// <summary>
/// Constructs a IntermecIF2 RFID reader class by given parameters
/// </summary>
/// <param name="dev">Parent device</param>
/// <param name="_rs232RFID">RFID reader RS232 port</param>
/// <param name="_LoggingLevel">Logging detail level</param>
/// <param name="Code">Equipment code</param>
public IntermecIF2( DeviceEngine dev, GTME.RS232 _rs232RFID, SystemConfigData _systemData, SmartTruckConfigData _SmartTruckData, string Code)
: base(dev)
{
Debug.Print("Initializing " + Code);
code = Code;
name = Code;
type = DeviceTypeName; // v6
ThisDevice = dev;
systemData = _systemData;
LoggingLevel = _systemData.LoggingLevel;
RS232RFID = _rs232RFID;
InUse = (_rs232RFID != null);
//RxDataQueueSizeExpected = 0;
RxDataQueue = new ByteQueue(MaxRxDataQueueSize);
RxDataEvent = new AutoResetEvent(false);
SendDataLock = new Object();
RxDataBuf = new byte[MaxRxDataQueueSize];
//RxDataCount = 0;
RS232Data = new byte[MaxRxDataQueueSize];
RS232Count = 0;
RxLine = new StringBuilder();
RxLineQueue = new Queue();
AsyncLineQueue = new Queue();
RxLineQueueEvent= new AutoResetEvent(false);
AsyncLineQueueEvent = new AutoResetEvent(false); ;
RxLineList = new ArrayList();
if (InUse)
{
RS232RFID.Initialize(_SmartTruckData.IntermecBaudRate, GTI.Serial.SerialParity.None, GTI.Serial.SerialStopBits.One, 8, GTI.Serial.HardwareFlowControl.NotRequired);
if (!ThisDevice.isPassThroughModeActive)
{
//RS232RFID.serialPort.DataReceived += new GTI.Serial.DataReceivedEventHandler(IntermecIF2_DataReceived);
ThreadStart DataReaderThreadStarter = new ThreadStart(RS232DataReader);
Thread DataReaderThread = new Thread(DataReaderThreadStarter);
DataReaderThread.Start();
ThreadStart InputMessageThreadStarter = new ThreadStart(RxDataReceiver);
Thread InputMessageThread = new Thread(InputMessageThreadStarter);
InputMessageThread.Start();
ThreadStart AsynchronousEventThreadStarter = new ThreadStart(AsynchronousEventReceiver);
Thread AsynchronousEventThread = new Thread(AsynchronousEventThreadStarter);
AsynchronousEventThread.Start();
}
}
Debug.Print("Done initializing " + Code);
}
Here is my Queue class:
public class ByteQueue
{
int Qsize; // maximum number of elements
int Qstart; // index of oldest element
int Qend; // index at which to write new element
byte[] elementsQ; // vector of elements
public Object SyncRoot { get; set; }
/// <summary>
/// Construct Queue of bytes,given the maximum number of bytes
/// </summary>
/// <param name="_size"></param>
public ByteQueue(int _size)
{
Qsize = _size + 1; // include space for empty element
Qstart = 0;
Qend = 0;
elementsQ = new byte[Qsize];
SyncRoot = new Object();
}
/// <summary>
/// Make the Queue empty
/// </summary>
public void Clear()
{
Qstart = 0;
Qend = 0;
}
/// <summary>
/// Copy Queue to a byte array starting at an offset into the array
/// </summary>
/// <param name="Buffer"></param>
/// <returns>Count of bytes copied</returns>
public int CopyTo(byte[] Buffer, int BufindexStart)
{
int Bufindex = BufindexStart;
int count = 0;
int Qindex = Qstart;
int i = 0;
while ((Qindex != Qend) && (Bufindex < Buffer.Length))
{
Buffer[Bufindex++] = elementsQ[Qindex];
count++;
i = Qindex + 1;
if (i >= Qsize) i = 0;
Qindex = i;
}
return count;
}
/// <summary>
/// Returns the count of bytes in the Queue
/// </summary>
public int Count
{
get
{
int result = 0;
if (Qend > Qstart)
result = Qend - Qstart;
else if (Qstart > Qend)
result = Qsize - (Qstart - Qend);
else
result = 0;
return result;
}
}
/// <summary>
/// Test if Queue is full
/// </summary>
/// <returns></returns>
public bool isFull()
{
int i;
i = Qend + 1;
if (i >= Qsize) i = 0;
return i == Qstart;
}
/// <summary>
/// Test if Queue is empty
/// </summary>
/// <returns></returns>
public bool isEmpty()
{
return Qend == Qstart;
}
/// <summary>
/// Write an element to the end of the Queue, if it is not yet full.
/// App must first call !isFull() to make sure Queue is not full.
/// </summary>
/// <param name="elem"></param>
public void Enqueue(byte elem)
{
if (!isFull())
{
elementsQ[Qend] = elem;
int i = Qend + 1;
if (i >= Qsize) i = 0;
Qend = i;
}
}
/// <summary>
/// Read and remove oldest element.
/// App must first call !isEmpty() to make sure Queue is not empty.
/// </summary>
/// <returns></returns>
public byte Dequeue()
{
byte elem = 0;
if (!isEmpty())
{
elem = elementsQ[Qstart];
int i = Qstart + 1;
if (i >= Qsize) i = 0;
Qstart = i;
}
return elem;
}
}