From c5b2e55330798c48996561674adcfdf8d11f257e Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Fri, 28 Aug 2015 07:22:18 -0700 Subject: [PATCH 01/50] Change to 3.5 from 4.0 framework There is no reason to use the 4.0 framework for this project. Remove any reference to 4.0 libraries and make a 3.5 project. Also removed all unused includes. --- .../Apex7000_BillValidator.csproj | 3 +- Apex7000_BillValidator/ApexValidator.cs | 9 +--- Apex7000_BillValidator/Commands.cs | 4 -- Apex7000_BillValidator/DataContracts.cs | 7 +-- Apex7000_BillValidator/Events.cs | 4 -- .../Apex7000_BillValidator_Test.csproj | 7 +-- Apex7000_BillValidator_Test/App.config | 8 ++-- Apex7000_BillValidator_Test/App.xaml.cs | 8 +--- .../MainWindow.xaml.cs | 16 +------ .../Properties/Resources.Designer.cs | 44 ++++++++----------- .../Properties/Settings.Designer.cs | 24 +++++----- 11 files changed, 42 insertions(+), 92 deletions(-) diff --git a/Apex7000_BillValidator/Apex7000_BillValidator.csproj b/Apex7000_BillValidator/Apex7000_BillValidator.csproj index 0dbee9c..1b9f168 100644 --- a/Apex7000_BillValidator/Apex7000_BillValidator.csproj +++ b/Apex7000_BillValidator/Apex7000_BillValidator.csproj @@ -9,7 +9,7 @@ Properties Apex7000_BillValidator Apex7000_BillValidator - v4.0 + v3.5 512 @@ -35,7 +35,6 @@ - diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index 427048a..151e541 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -1,13 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Threading; -using System.IO; -using System.IO.Ports; using System.Globalization; +using System.IO.Ports; +using System.Threading; namespace Apex7000_BillValidator { diff --git a/Apex7000_BillValidator/Commands.cs b/Apex7000_BillValidator/Commands.cs index 299c759..0fe1254 100644 --- a/Apex7000_BillValidator/Commands.cs +++ b/Apex7000_BillValidator/Commands.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Apex7000_BillValidator { diff --git a/Apex7000_BillValidator/DataContracts.cs b/Apex7000_BillValidator/DataContracts.cs index 6c34252..b2c155f 100644 --- a/Apex7000_BillValidator/DataContracts.cs +++ b/Apex7000_BillValidator/DataContracts.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace Apex7000_BillValidator { diff --git a/Apex7000_BillValidator/Events.cs b/Apex7000_BillValidator/Events.cs index 773e4f4..05aecaf 100644 --- a/Apex7000_BillValidator/Events.cs +++ b/Apex7000_BillValidator/Events.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Apex7000_BillValidator { diff --git a/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj b/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj index 60665b6..0964c06 100644 --- a/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj +++ b/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj @@ -9,10 +9,11 @@ Properties Apex7000_BillValidator_Test Apex7000_BillValidator_Test - v4.5 + v3.5 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 + AnyCPU @@ -37,13 +38,9 @@ - - - 4.0 - diff --git a/Apex7000_BillValidator_Test/App.config b/Apex7000_BillValidator_Test/App.config index 8e15646..343984d 100644 --- a/Apex7000_BillValidator_Test/App.config +++ b/Apex7000_BillValidator_Test/App.config @@ -1,6 +1,6 @@ - + - - - \ No newline at end of file + + + diff --git a/Apex7000_BillValidator_Test/App.xaml.cs b/Apex7000_BillValidator_Test/App.xaml.cs index b20efe5..7772c43 100644 --- a/Apex7000_BillValidator_Test/App.xaml.cs +++ b/Apex7000_BillValidator_Test/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace Apex7000_BillValidator_Test { diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml.cs b/Apex7000_BillValidator_Test/MainWindow.xaml.cs index 9acfe80..436dd76 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml.cs +++ b/Apex7000_BillValidator_Test/MainWindow.xaml.cs @@ -1,18 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Apex7000_BillValidator; +using System; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using Apex7000_BillValidator; namespace Apex7000_BillValidator_Test { diff --git a/Apex7000_BillValidator_Test/Properties/Resources.Designer.cs b/Apex7000_BillValidator_Test/Properties/Resources.Designer.cs index b52b898..aa51ecd 100644 --- a/Apex7000_BillValidator_Test/Properties/Resources.Designer.cs +++ b/Apex7000_BillValidator_Test/Properties/Resources.Designer.cs @@ -1,17 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace Apex7000_BillValidator_Test.Properties -{ - - +namespace Apex7000_BillValidator_Test.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -22,48 +22,40 @@ namespace Apex7000_BillValidator_Test.Properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Apex7000_BillValidator_Test.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/Apex7000_BillValidator_Test/Properties/Settings.Designer.cs b/Apex7000_BillValidator_Test/Properties/Settings.Designer.cs index 97d9baa..93324e0 100644 --- a/Apex7000_BillValidator_Test/Properties/Settings.Designer.cs +++ b/Apex7000_BillValidator_Test/Properties/Settings.Designer.cs @@ -1,28 +1,24 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace Apex7000_BillValidator_Test.Properties -{ - - +namespace Apex7000_BillValidator_Test.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } From 2ff5be7a02947d6a546df8020d729046f7a45115 Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Fri, 28 Aug 2015 07:23:57 -0700 Subject: [PATCH 02/50] Discard in buffer after reading This is to prevent messages from collecting on the input buffer. This helps during debugging if you are setting breakpoints and stopping for more than 50ms at a time. Since to poll rate is so slow, this will not affect regular operation of the acceptor. Also show how to capture the denomination during the OnEscrow event in the test app. --- Apex7000_BillValidator/ApexValidator.cs | 1 + Apex7000_BillValidator_Test/MainWindow.xaml.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index 151e541..e103d19 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -213,6 +213,7 @@ private void Read() byte[] buffer = new byte[11]; port.Read(buffer, 0, 11); + port.DiscardInBuffer(); byte t3 = buffer[3]; byte t4 = buffer[4]; diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml.cs b/Apex7000_BillValidator_Test/MainWindow.xaml.cs index 436dd76..c4e61be 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml.cs +++ b/Apex7000_BillValidator_Test/MainWindow.xaml.cs @@ -53,6 +53,7 @@ void validator_BillStacked(object sender, EventArgs e) void validator_OnEscrow(object sender, int denomination) { validator.Stack(); + Console.WriteLine("${0}", denomination); } void validator_PowerUp(object sender, EventArgs e) From ec9f1ee3719785aa1cbc4e4bf34444c5255ee92e Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Fri, 28 Aug 2015 11:58:42 -0700 Subject: [PATCH 03/50] Restructure the API to be more like the Java API Add support for both escrow and non-escrow mode. Fix possible missed message state wear bill could stay in escrow forever without hearing the stack/reject message. Cleaned up constructors and added a bunch of ugly state variables. TODO abstract out the state variable into another class and work from that to make things read easier. --- Apex7000_BillValidator/ApexValidator.cs | 519 ++++++++++++------ Apex7000_BillValidator/Commands.cs | 8 +- Apex7000_BillValidator/DataContracts.cs | 25 +- Apex7000_BillValidator/DebugBuffer.cs | 50 ++ Apex7000_BillValidator/Events.cs | 7 + .../MainWindow.xaml.cs | 14 +- 6 files changed, 426 insertions(+), 197 deletions(-) create mode 100644 Apex7000_BillValidator/DebugBuffer.cs diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index e103d19..3c7ad79 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -8,137 +8,376 @@ namespace Apex7000_BillValidator { public partial class ApexValidator { + // ms + private static readonly int POLL_RATE = 200; + // seconds + private static readonly int SLAVE_DEAD_LIMIT = 10; + private SerialPort port = null; - private byte lastResponse = Response.Idle; private COMPort comPort = COMPort.COM1; - private readonly object mutex = new object(); - public bool isConnected = false; - private int reconnectAttempts = 0; + + // State variables for tracking between events and states + private volatile byte ack = 0; + + // Slaves last state + private volatile Response lastResponse = Response.Idle; + + // Track if we have already reported the cashbox state. We always + // raise the cashbox missing event but report cashbox attached event + // only once. + private volatile bool cashboxPresent = true; + + // Escrow mode allows you to manually call Stack() or Reject() on each + // escrowed note. If false, we stack any valid note automatically. + private volatile bool isEscrowMode = false; + + // If true, the slave is reporting that a note is in escrow + private volatile bool isEcrowed = false; + + // Last reported credit from slave + private volatile byte credit = 0; + + // Additional feature: async flag to tell the slave + // to ACCEPT or REJECT the note next time the master polls + private volatile EscrowCommands escrowCommand = EscrowCommands.None; + + // If true the underlying comm port is in the open state + private volatile bool isConnected = false; + + // Integer poll rate between 50 and 5000 ms + private int pollRate = POLL_RATE; + + // Track comm timeout from slave device private DateTime escrowTimeout = DateTime.MinValue; + private int reconnectAttempts = 0; + + // Used to map between reported value and actual currency denomination private CultureInfo currentCulture; private CurrencyMap currentCurrencyMap; - + + private readonly object mutex = new object(); + + /// + /// Creates a new ApexValidator using the current system culture and not in + /// escrow mode + /// + /// public ApexValidator(string comm) { comPort = (COMPort)Enum.Parse(typeof(COMPort), comm); + new ApexValidator(comPort, CultureInfo.CurrentCulture, false); } - public ApexValidator(COMPort comm) + /// + /// Creates a new ApexValidator using the specified system culture and not in + /// escrow mode + /// + /// + public ApexValidator(string comm, CultureInfo culture) { - comPort = comm; + comPort = (COMPort)Enum.Parse(typeof(COMPort), comm); + new ApexValidator(comPort, culture, false); } - public ApexValidator(COMPort comm, string culture) + /// + /// Creates a new ApexValidator using the current system culture and not in + /// escrow mode + /// + /// + public ApexValidator(COMPort comm) { - comPort = comm; - currentCulture = new CultureInfo(culture); + new ApexValidator(comm, CultureInfo.CurrentCulture, false); } + /// + /// Creates a new ApexValidator using the specified system culture and not in + /// escrow mode + /// + /// public ApexValidator(COMPort comm, CultureInfo culture) { - comPort = comm; - currentCulture = culture; + new ApexValidator(comm, culture, false); } - public ApexValidator(string comm, CultureInfo culture) + /// + /// Creates a new ApexValidator using the specified system culture in + /// escrow mode + /// + /// + public ApexValidator(string comm, CultureInfo culture, bool escrowModeEnabled) { comPort = (COMPort)Enum.Parse(typeof(COMPort), comm); - currentCulture = culture; + new ApexValidator(comPort, culture, false); } + /// + /// Creates a new ApexValidator using the specified system culture and in + /// escrow mode + /// + /// + public ApexValidator(COMPort comm, CultureInfo culture, bool escrowModeEnabled) + { + comPort = comm; + currentCulture = culture; + this.isEscrowMode = escrowModeEnabled; + } + /// + /// Close the underlying comm port + /// public void Close() { port.Close(); } + /// + /// Connect to the device and begin speaking rs232 + /// public void Connect() { - //if (port != null) - // port.DataReceived -= port_DataReceived; - - port = new SerialPort(comPort.ToString(), 9600, Parity.Even, 7, StopBits.One); - port.ReadTimeout = 500; - //port.DataReceived += port_DataReceived; - try + lock (mutex) { - port.Open(); - } - catch(Exception e) - { - /* Handle this better? */ - if (OnError != null) + port = new SerialPort(comPort.ToString(), 9600, Parity.Even, 7, StopBits.One); + port.ReadTimeout = 500; + + try { - OnError(this, ErrorTypes.PortError); + port.Open(); } - else + catch (Exception e) { - throw e; + //return; + if (OnError != null) + { + OnError(this, ErrorTypes.PortError); + } } - } - byte[] wakeup = Request.BaseMessage; - - lock(mutex) + startRS232Loop(); + } + } + + /// + /// Gets or sets the poll rate in milliseconds. The polled system is designed for the master to request + /// information from the slave at a periodic rate. The rate can be as slow as 5 seconds or as fast as + /// 50 msec between each poll. The popular rate is fast since the overall system performance + /// (bills per minute accepted) will be slower at slower polling rates. While feeding the bill into the + /// acceptor, the acceptor will miss a few polls, because it is reading the bill and not servicing the + /// serial interface (Typical for acceptors using this protocol). + /// + /// Min: 50 Max: 5000 + public int PollRate + { + get { - Write(wakeup); - Read(); + return pollRate; } + set + { + // Allow floor of 50 ms, celing of 5 seconds + if (value < 50 || value > 5000) + { + throw new ArgumentOutOfRangeException("Minimum value is 50ms, maximum value is 5000 ms"); + } + + pollRate = value; + } + } + + /// + /// Polls the slave and processes messages accordingly + /// + private void startRS232Loop() + { Thread ackThread = new Thread((fn) => { - while(true) + while (true) { - lock (mutex) - { - Write(Request.BaseMessage); - Read(); - } - Thread.Sleep(200); + speakToSlave(); + + //TimeSpan ts = DateTime.Now - escrowTimeout; + //if (ts.TotalSeconds >= SLAVE_DEAD_LIMIT) + //{ + + // //Let's reconnect and make sure everything is still good + // Reconnect(); + // Reject(); + + //} + + + Thread.Sleep(pollRate); } }); ackThread.IsBackground = true; ackThread.Start(); - } + /// + /// Safely reconnect to the slave device + /// private void Reconnect() { - lock(mutex) - { - port = new SerialPort(comPort.ToString(), 9600, Parity.Even, 7, StopBits.One); - port.ReadTimeout = 500; - try + // Try to close the port before we re instantiate. If this + // explodes there are bigger issues + port.Close(); + + // Let the port cool off (close base stream, etc.) + Thread.Sleep(100); + + Connect(); + } + + /// + /// The main parsing routine + /// + private void speakToSlave() + { + // # basic message 0 1 2 3 4 5 6 7 + // start, len, ack, bills,escrow,resv'd,end, checksum + var data = Request.BaseMessage; + + // Toggle message number (ack #) if last message was okay and not a re-send request. + data[2] = (byte)(0x10 | this.ack); + this.ack ^= 1; + + // If we have a valid note in escrow decide if + // we have to wait for the host to accept/reject + // or if we can just stack. + if (this.isEcrowed) + { + if (!this.isEscrowMode) { - port.Open(); + + // Not escrow mode, we have a non-zero credit so just stack + data[4] |= 0x20; + + } - catch (Exception e) + else { - //return; - if (OnError != null) + // Otherwise do what the host tells us to do. + switch (escrowCommand) { - OnError(this, ErrorTypes.PortError); + case EscrowCommands.Stack: + // set stack bit + data[4] |= 0x20; + escrowCommand = EscrowCommands.Pending; + break; + + case EscrowCommands.Reject: + // set reject bit + data[4] |= 0x40; + escrowCommand = EscrowCommands.Pending; + break; + + case EscrowCommands.Pending: + // Wait indefiniately for acecpt/reject command or complete + break; + + case EscrowCommands.None: + escrowCommand = EscrowCommands.Pending; + OnEscrow(this, credit); + break; } } + } + + + + // Set the checksum + data = Checksum(data); + + // Attempt to write data to slave + Write(data); + + // Blocks until all 11 bytes are read or we give up + var resp = Read(); + + + // POSSIBLE FUNCTION EXIT!! + // No data was read, return!! + if (resp.Length == 0) + return; + + + + // With the exception of Stacked and Returned, only we can + // only be in one state at once + lastResponse = (Response)resp[3]; + + // Only one state will be reported at once TODO + + + // Mask away rest of message to see if a note is in escrow + isEcrowed = (resp[3] & 4) == 0x04 ? true : false; + + + // Multiple event may be reported at once + if ((resp[4] & 0x01) == 0x01) + Cheated(this, null); + + if ((resp[4] & 0x02) == 0x02) + Rejected(this, null); + + if ((resp[4] & 0x04) == 0x04) + Jammed(this, null); + + if ((resp[4] & 0x08) == 0x08) + CashboxFull(this, null); + + + // Check for cassette missing + if ((resp[4] & 0x10) != 0x10) + { + + this.cashboxPresent = false; + + CashboxRemoved(this, null); - byte[] wakeup = Request.BaseMessage; - lock (mutex) - { - Write(wakeup); - Read(); - } } - } + // Only report the cashbox attached 1 time after it is re-attached + else if (!this.cashboxPresent) + { + + this.cashboxPresent = true; + + CashboxAttached(this, null); + + } + + // Credit bits are 3-5 of data byte 3 + var value = (byte)((resp[5] & 0x38) >> 3); + if (value != 0) + { + credit = value; + + } + + + // Per the spec, credit message is issued by master after stack event is + // sent by the slave. + if ((lastResponse & Response.Stacked) == Response.Stacked) + { + OnCredit(this, credit); + } + + + } + + /// + /// Synchronous write function that allows for up to 3 attempts to write to port. + /// + /// private void Write(byte[] data) { - data = Checksum(data); - if (port != null) { try @@ -146,7 +385,7 @@ private void Write(byte[] data) port.Write(data, 0, data.Length); reconnectAttempts = 0; } - catch(Exception e) + catch (Exception e) { isConnected = false; Thread.Sleep(1000); @@ -164,7 +403,7 @@ private void Write(byte[] data) OnError(this, ErrorTypes.WriteError); } } - } + } } else { @@ -175,21 +414,16 @@ private void Write(byte[] data) } } - private byte[] Checksum(byte[] msg) - { - List tmp = new List(msg); - byte checksum = (byte)(msg[1] ^ msg[2]); - for(int i = 3; i < msg.Length - 1; i++) - { - checksum ^= msg[i]; - } - - tmp.Add(checksum); - return tmp.ToArray(); - } - private void Read() + /// + /// Synchronous read function that allows for up to 3 attempts to read from port. + /// + /// + private byte[] Read() { + // Create empty array to hold incoming data + byte[] buffer = new byte[0]; + if (port.IsOpen) { int waitCount = 0; @@ -198,123 +432,42 @@ private void Read() waitCount++; if (waitCount >= 5) { - /* Don't report error if validator is in accepting state as this can take some time */ - //if (OnError != null && lastResponse != Response.Accepting) - //{ - OnError(this, ErrorTypes.Timeout); - //} - - return; + OnError(this, ErrorTypes.Timeout); + return buffer; } Thread.Sleep(100); } - byte[] buffer = new byte[11]; + // Resize to 11 bytes since we have data to read + buffer = new byte[11]; port.Read(buffer, 0, 11); port.DiscardInBuffer(); - byte t3 = buffer[3]; - byte t4 = buffer[4]; - - if ((t3 & 1) == Response.Idle) - { - //Only if the box has been recently removed - if ((t4 & 0x10) == Response.CassetteRemoved) - { - if (lastResponse != Response.CassetteRemoved) - { - lastResponse = Response.CassetteRemoved; - if (CashboxRemoved != null) - { - CashboxRemoved(this, null); - } - } - } - else - { - - //Normal idle response - if (lastResponse == Response.CassetteRemoved) - { - if (CashboxAttached != null) - { - CashboxAttached(this, null); - } - } - - if (!isConnected) - { - isConnected = true; - if (PowerUp != null) - { - PowerUp(this, null); - } - } - - lastResponse = Response.Idle; - } - - Write(Request.Ack); - } - if ((t3 & 2) == Response.Accepting) - { - if (lastResponse != Response.Accepting) - { - lastResponse = Response.Accepting; - } - } - if ((t3 & 4) == Response.Escrow) - { - - if (lastResponse != Response.Escrow) - { - if (escrowTimeout == DateTime.MinValue) - { - escrowTimeout = DateTime.Now; - } - else - { - TimeSpan ts = DateTime.Now - escrowTimeout; - if (ts.TotalSeconds >= 10) - { - //Let's reconnect and make sure everything is still good - Reconnect(); - Reject(); - } - } - - lastResponse = Response.Escrow; - - byte bill = (byte)((buffer[5] & 0x38) >> 3); + // Reset the timeout clock + escrowTimeout = DateTime.MinValue; + } - if (OnEscrow != null) - OnEscrow(this, BillParser.getDenomFromByte(bill, currentCulture)); - } - } - if ((t3 & 8) == Response.Stacking) - { - if (lastResponse != Response.Stacking) - { - lastResponse = Response.Stacking; + return buffer; + } - if (BillStacked != null) - { - BillStacked(this, null); - } - } - } - if ((t3 & 0x20) == Response.Returned) - { - if (lastResponse != Response.Returned) - { - //This screws with the box when it is removed - //lastResponse = Response.Returned; - Write(Request.Ack); - } - } + /// + /// XOR checksum of only the data portion of the message + /// + /// + /// + private byte[] Checksum(byte[] msg) + { + List tmp = new List(msg); + byte checksum = (byte)(msg[1] ^ msg[2]); + for (int i = 3; i < msg.Length - 1; i++) + { + checksum ^= msg[i]; } + + tmp.Add(checksum); + return tmp.ToArray(); } } } diff --git a/Apex7000_BillValidator/Commands.cs b/Apex7000_BillValidator/Commands.cs index 0fe1254..d84594d 100644 --- a/Apex7000_BillValidator/Commands.cs +++ b/Apex7000_BillValidator/Commands.cs @@ -6,14 +6,14 @@ public partial class ApexValidator { public void Stack() { - escrowTimeout = DateTime.MinValue; - Write(Request.Stack); + // Set flag to accept + this.escrowCommand = EscrowCommands.Stack; } public void Reject() { - escrowTimeout = DateTime.MinValue; - Write(Request.Reject); + // Set flag to reject + this.escrowCommand = EscrowCommands.Reject; } } } diff --git a/Apex7000_BillValidator/DataContracts.cs b/Apex7000_BillValidator/DataContracts.cs index b2c155f..0ee4b89 100644 --- a/Apex7000_BillValidator/DataContracts.cs +++ b/Apex7000_BillValidator/DataContracts.cs @@ -38,19 +38,30 @@ public enum ErrorTypes PortError } - public struct Response + [System.Flags] + public enum Response : byte { - public static readonly byte Idle = 0x01; - public static readonly byte Accepting = 0x02; - public static readonly byte Escrow = 0x04; - public static readonly byte Stacking = 0x08; - public static readonly byte Returned = 0x20; + Idle = 1, + Accepting = 2, + Escrow = 4, + Stacking = 8, + Stacked = 16, + Returning = 32, + Returned = 64 + } - public static readonly byte CassetteRemoved = 0x00; + public enum EscrowCommands + { + None, + Pending, + Stack, + Reject } public struct Request { + // basic message 0 1 2 3 4 5 6 7 + // start, len, ack, bills,escrow,resv'd,end, checksum public static readonly byte[] BaseMessage = { 0x02, 0x08, 0x10, 0x7F, 0x10, 0x00, 0x03 }; public static readonly byte[] Ack = { 0x02, 0x08, 0x11, 0x7F, 0x10, 0x00, 0x03 }; public static readonly byte[] Escrow = { 0x02, 0x08, 0x11, 0x7F, 0x10, 0x00, 0x03 }; diff --git a/Apex7000_BillValidator/DebugBuffer.cs b/Apex7000_BillValidator/DebugBuffer.cs new file mode 100644 index 0000000..7a96900 --- /dev/null +++ b/Apex7000_BillValidator/DebugBuffer.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Apex7000_BillValidator +{ + public class DataEntry + { + private Flows flows; + private int p; + + public DataEntry(byte[] data, Flows flow, int p) + { + var dt = DateTime.Now; + Timestamp = String.Format("{0}:{1}:{2}", dt.Minute, dt.Second, dt.Millisecond); + Data = data; + Flow = flow; + ThreadID = p; + } + + public byte[] Data { get; private set; } + public string PrintableData + { + get + { + return ByteArrayToString(Data); + } + } + public Flows Flow { get; private set; } + + public String Timestamp { get; private set; } + + public int ThreadID { get; private set; } + + public static string ByteArrayToString(byte[] ba) + { + StringBuilder hex = new StringBuilder(ba.Length * 2); + foreach (byte b in ba) + hex.AppendFormat("{0:X2} ", b); + return hex.ToString(); + } + + } + + public enum Flows { + Master, + Slave + } +} diff --git a/Apex7000_BillValidator/Events.cs b/Apex7000_BillValidator/Events.cs index 05aecaf..6f2a0a4 100644 --- a/Apex7000_BillValidator/Events.cs +++ b/Apex7000_BillValidator/Events.cs @@ -5,12 +5,19 @@ namespace Apex7000_BillValidator public partial class ApexValidator { public event EventHandler PowerUp; + public event EventHandler Cheated; + public event EventHandler Rejected; + public event EventHandler Jammed; + public event EventHandler CashboxFull; public event EventHandler BeginEscrow; public event EventHandler BillStacked; public event EventHandler ClearLastError; public event EventHandler CashboxRemoved; public event EventHandler CashboxAttached; + public delegate void OnCreditEventHandler(object sender, int denomination); + public event OnCreditEventHandler OnCredit; + public delegate void OnEscrowEventHandler(object sender, int denomination); public event OnEscrowEventHandler OnEscrow; diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml.cs b/Apex7000_BillValidator_Test/MainWindow.xaml.cs index c4e61be..0e60044 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml.cs +++ b/Apex7000_BillValidator_Test/MainWindow.xaml.cs @@ -1,5 +1,6 @@ using Apex7000_BillValidator; using System; +using System.Globalization; using System.Windows; namespace Apex7000_BillValidator_Test @@ -18,10 +19,12 @@ public MainWindow() void MainWindow_Loaded(object sender, RoutedEventArgs e) { - //validator = new ApexValidator(COMPort.COM10, "en-US"); - validator = new ApexValidator(COMPort.COM2); + // Testing on CAN firmware using escrow mode + validator = new ApexValidator(COMPort.COM4, new CultureInfo("en-CA"), true); + //validator = new ApexValidator(COMPort.COM4); validator.PowerUp += validator_PowerUp; validator.OnEscrow += validator_OnEscrow; + validator.OnCredit += validator_OnCredit; validator.BillStacked += validator_BillStacked; validator.OnError += validator_OnError; validator.CashboxAttached += validator_CashboxAttached; @@ -53,7 +56,12 @@ void validator_BillStacked(object sender, EventArgs e) void validator_OnEscrow(object sender, int denomination) { validator.Stack(); - Console.WriteLine("${0}", denomination); + Console.WriteLine("Escrowed ${0}", denomination); + } + + private void validator_OnCredit(object sender, int denomination) + { + Console.WriteLine("Credited ${0}", denomination); } void validator_PowerUp(object sender, EventArgs e) From 7660ddfa873fa2f0e7276175328078834df70d17 Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Fri, 28 Aug 2015 12:06:41 -0700 Subject: [PATCH 04/50] Tested against version 0.7 of OpenNETCF This uses the serial port alternate and works fine on my system. YMMV. Be sure to grab the dll from http://sourceforge.net/projects/serialportnet/ and add it as a reference to the ApexValidator project. Remove the using System.IO.SerialPort reference. Make sure that the OpenNETCF dll is in the same directory as your application that you are testing. --- Apex7000_BillValidator/Apex7000_BillValidator.csproj | 3 +++ Apex7000_BillValidator/ApexValidator.cs | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Apex7000_BillValidator/Apex7000_BillValidator.csproj b/Apex7000_BillValidator/Apex7000_BillValidator.csproj index 1b9f168..57b5f02 100644 --- a/Apex7000_BillValidator/Apex7000_BillValidator.csproj +++ b/Apex7000_BillValidator/Apex7000_BillValidator.csproj @@ -31,6 +31,9 @@ 4 + + ..\..\..\lib\SerialPort.dll + diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index 3c7ad79..550abdc 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -1,7 +1,10 @@ -using System; +using OpenNETCF.IO.Ports; +using System; using System.Collections.Generic; using System.Globalization; -using System.IO.Ports; +// Using alternative to SIP +// using System.IO.Ports; + using System.Threading; namespace Apex7000_BillValidator From b3e73d575eb7d8cb6a596c3940e52b943158de2e Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Tue, 1 Sep 2015 13:36:45 -0700 Subject: [PATCH 05/50] Starting java rewrite --- .../Apex7000_BillValidator.csproj | 2 + Apex7000_BillValidator/ApexValidator.cs | 333 +++++++----------- Apex7000_BillValidator/Commands.cs | 4 +- Apex7000_BillValidator/DataContracts.cs | 23 +- Apex7000_BillValidator/DebugBuffer.cs | 19 +- Apex7000_BillValidator/Events.cs | 92 ++++- Apex7000_BillValidator/RS232Config.cs | 153 ++++++++ Apex7000_BillValidator_Test/MainWindow.xaml | 3 +- .../MainWindow.xaml.cs | 25 +- 9 files changed, 403 insertions(+), 251 deletions(-) create mode 100644 Apex7000_BillValidator/RS232Config.cs diff --git a/Apex7000_BillValidator/Apex7000_BillValidator.csproj b/Apex7000_BillValidator/Apex7000_BillValidator.csproj index 57b5f02..49e74cf 100644 --- a/Apex7000_BillValidator/Apex7000_BillValidator.csproj +++ b/Apex7000_BillValidator/Apex7000_BillValidator.csproj @@ -45,8 +45,10 @@ + + + <factory name="simple"> + <factory-data> + simple data + </factory-data> + </factory> + + <!-- a factory configuration with XML sub elements --> + <factory name="complex"> + <factory-data> + <child foo="bar"> + <subchild>foobar</subchild> + </child> + </factory-data> + </factory> + </slf> + + + + + + Indicates the factory Type + + + + + The slf4net configuration section to define which type to use. + + + + + Defines the to use. + + + + + Provides common runtime validation functionality. + + + + + Makes sure a given argument is not null. + + Type of the argument. + The submitted parameter value. + The name of the argument. + If + is a null reference. + + + + A base class for factories which created named logger + instance. + + + + + instances manufacture + instances by name. These factory methods may create new instances + or retrieve cached / pooled instances depending on the the + name of the requested logger. + + + + + Returns an appropriate instance as specified by the name parameter. + + The name of the logger to return. + + + + A cache of named loggers + + + + + An object which is used for locking + + + + + Obtains an instance that is identified by + the given name. + + The logger name. + A factory that can be identified by the + given name in the target output for this logger + + + + Constructs a logger with the given name + + The logger name. + A logger with the given name. + + + + A no operation implementation of the + which simply returns a instance. + + + + + Singleton instance. + + + + + Private constructor. A reference to the Singleton + instance of this class is available through the + static property. + + + + + Obtains an instance that is identified by + the given name. + + The logger name. + An instance + + + + Provides access to the singleton instance of + the class. + + + + + Common interface for logger factories that can + be initialized with custom configuration data. + + + + + Inits the plug-in with configured factory data. + + Retrieved factory settings. + This parameter is null if no configuration at all + was found. + + + + Responsible for finding and creating + instances which are being used to create loggers of a given implementation. + + + + + Determines a factory which in turn creates an + instance based on a + request for a named logger. + + A factory which in turn is responsible for creating + a given implementation. + + + + Common interface of an arbitrary implementation that provides + logging capabilities. + + + + + Logs a message at the DEBUG level. + + The message to log. + + + + Logs a message at the DEBUG level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the DEBUG level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the DEBUG level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the DEBUG level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the DEBUG level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the TRACE level. + + The message to log. + + + + Logs a message at the TRACE level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the TRACE level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the TRACE level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the TRACE level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the TRACE level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the INFO level. + + The message to log. + + + + Logs a message at the INFO level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the INFO level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the INFO level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the INFO level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the INFO level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the WARN level. + + The message to log. + + + + Logs a message at the WARN level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the WARN level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the WARN level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the WARN level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the WARN level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the ERROR level. + + The message to log. + + + + Logs a message at the ERROR level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the ERROR level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the ERROR level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the ERROR level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the ERROR level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Gets this logger's name. + + + + + Is the logger instance enabled for the DEBUG level? + + + + + Is the logger instance enabled for the TRACE level? + + + + + Is the logger instance enabled for the INFO level? + + + + + Is the logger instance enabled for the WARN level? + + + + + Is the logger instance enabled for the ERROR level? + + + + + Provides a global repository that provides access to + instances. This class ensures that both the + and methods always return a valid + instance - if no matching logger can be resolved, + the service automatically falls back to a instance. + + + + + The current initialization state + + + + + A temporary factory that can be used during initialization + + + + + A fallback factory used when initialization fails + + + + + Lock object + + + + + Provides access to the logger factory + + + + + Sets the factory resolver used to get the + + The resolver to use. If null is passed, the will be used. + + + + Discards customizations and resets the configured logger + facilities to their defaults. + + + + + Returns a logger named according to the name parameter using the . + + The name of the logger + logger + + + + Returns a logger named according to the type parameter using the . + + The type of the logger + logger + + + + Returns the instance in use. + + + + + LoggerFactory initialization states + + + + + Logger factory is not initialized + + + + + Initialization is currently ongoing + + + + + Initialization failed + + + + + Intialization succeeded + + + + + Fell back to a No Operation factory + + + + + Serves as base class for named logger implementations providing serialization capabilities. + + + + + Constructs a logger instance with the given name. + + the logger name + + + + Constructs an un-named logger + + + + + Sets the object data into the serialization info using an IObjectReference serialization helper class + + + + + The name of this logger - typically this is written to the + log itself along with the formatted message. + + + + + Deserialization constructor + + + + + A no operation implementation of the + interface, which doesn't log anything. Use this implementation + in order not to have to check for null references when + using an .
+ This logger implementation is a Singleton. You can get the singleton + instance through the property. +
+
+ + + Singleton instance. + + + + + Private constructor. A reference to the Singleton + instance of this class is available through the + static property. + + + + + Logs a message at the DEBUG level. + + The message to log. + + + + Logs a message at the DEBUG level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the DEBUG level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the DEBUG level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the DEBUG level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the DEBUG level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the TRACE level. + + The message to log. + + + + Logs a message at the TRACE level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the TRACE level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the TRACE level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the TRACE level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the TRACE level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the INFO level. + + The message to log. + + + + Logs a message at the INFO level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the INFO level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the INFO level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the INFO level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the INFO level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the WARN level. + + The message to log. + + + + Logs a message at the WARN level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the WARN level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the WARN level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the WARN level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the WARN level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the ERROR level. + + The message to log. + + + + Logs a message at the ERROR level according to the specified and . + + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs a message at the ERROR level according to the specified and . + + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the ERROR level. + + The exception to log. + Additional information regarding the + logged exception. + + + + Logs an exception and an additional message at the ERROR level + + The exception to log + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Logs an exception and an additional message at the ERROR level + + The exception to log. + An which provides + culture-specific formatting capabilities. + A composite format string that contains placeholders for the + arguments. + An array containing zero or more objects + to format. + + + + Provides access to the singleton instance of + the class. + + + + + Always returns "NOP". + + + + + Is the logger instance enabled for the DEBUG level? + + + + + Is the logger instance enabled for the TRACE level? + + + + + Is the logger instance enabled for the INFO level? + + + + + Is the logger instance enabled for the WARN level? + + + + + Is the logger instance enabled for the ERROR level? + + + + + Resolves factories to be used for logger instantiation based + on settings taken from the application's default configuration + file (App.config or Web.config). + + + + + The name of the SLF configuration section + + + + + Default constructor using the standard configuration section name + + + + + Constructor where a custom configuration section name is used. + + The name of the configuration section + + + + Returns the instance in use. + + + + + + Loads the resolver configuration from the application's config file. + + + + + Reads the and instantiates the ILoggerFactory defined in configuration. + + + + + + Creates a factory based on a given configuration. + If the factory provides invalid information, an error is logged through + the internal logger, and a returned. + + The configuration that provides type + information for the that is being created. + Factory instance. + + + + A resolver that always returns a , + which in turn creates a instance. + + + + + The logger factory instance. + + + + + Singleton instance. + + + + + Private constructor. A reference to the Singleton + instance of this class is available through the + static property. + + + + + Determines a factory which cab create an + instance based on a + request for a named logger. + + A factory which in turn is responsible for creating + a given implementation. + + + + Provides access to the singleton instance of + the class. + + + + diff --git a/packages/slf4net.0.1.32.1/slf4net.0.1.32.1.nupkg b/packages/slf4net.0.1.32.1/slf4net.0.1.32.1.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..04fb29fab64a9d008370386afab0d34a71da474f GIT binary patch literal 18808 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 Date: Tue, 1 Sep 2015 15:52:28 -0700 Subject: [PATCH 07/50] Bug fixes in StrongPort and implementation --- .gitignore | 1 + Apex7000_BillValidator/ApexValidator.cs | 12 ++++++++++-- Apex7000_BillValidator/Serial/StrongPort.cs | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 91757b6..245f8ee 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ Apex7000_BillValidator_Test\obj\* Apex7000_BillValidator/obj/ Apex7000_BillValidator_Test/bin/ Apex7000_BillValidator_Test/obj/ +Apex7000_BillValidator/bin/ diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index 03924d2..0531105 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -93,6 +93,10 @@ private void startRS232Loop() ackThread.Start(); } + /// + /// Write data to port and notify client of any errors they should know about. + /// + /// byte[] private void WriteWrapper(byte[] data) { try @@ -112,6 +116,10 @@ private void WriteWrapper(byte[] data) } } + /// + /// Read data from the port and notify client of any errors they should know about. + /// + /// private byte[] ReadWrapper() { try @@ -169,10 +177,10 @@ private void speakToSlave() // Attempt to write data to slave config.pushDebugEntry(DebugBufferEntry.DebugBufferEntryAsMaster(data, Thread.CurrentThread.ManagedThreadId)); - port.Write(data); + WriteWrapper(data); // Blocks until all 11 bytes are read or we give up - var resp = port.Read(); + var resp = ReadWrapper(); config.pushDebugEntry(DebugBufferEntry.DebugBufferEntryAsSlave(resp, Thread.CurrentThread.ManagedThreadId)); // POSSIBLE FUNCTION EXIT!! diff --git a/Apex7000_BillValidator/Serial/StrongPort.cs b/Apex7000_BillValidator/Serial/StrongPort.cs index 9795205..732e106 100644 --- a/Apex7000_BillValidator/Serial/StrongPort.cs +++ b/Apex7000_BillValidator/Serial/StrongPort.cs @@ -42,6 +42,7 @@ public StrongPort(string portName) try { + port.Open(); this._internalSerialStream = port.BaseStream; this._serialPort = port; this._serialPort.DiscardInBuffer(); From 25a3f904a7f204a49c19353cc9befdc3f98f4d26 Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Tue, 1 Sep 2015 15:52:44 -0700 Subject: [PATCH 08/50] Add more UI features to test app --- Apex7000_BillValidator_Test/MainWindow.xaml | 144 +++++++++++++++++- .../MainWindow.xaml.cs | 22 ++- 2 files changed, 160 insertions(+), 6 deletions(-) diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml b/Apex7000_BillValidator_Test/MainWindow.xaml index 3882109..a7baecd 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml +++ b/Apex7000_BillValidator_Test/MainWindow.xaml @@ -1,9 +1,145 @@  - - + + + + + + diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml.cs b/Apex7000_BillValidator_Test/MainWindow.xaml.cs index f7cee1c..993f5eb 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml.cs +++ b/Apex7000_BillValidator_Test/MainWindow.xaml.cs @@ -1,5 +1,6 @@ using Apex7000_BillValidator; using System; +using System.Collections.Generic; using System.Globalization; using System.Windows; @@ -13,6 +14,21 @@ public partial class MainWindow : Window private ApexValidator validator; private RS232Config config; + private static Dictionary currencyMap = new Dictionary(); + private Dictionary cashbox = new Dictionary(); + + // Configure our map + static MainWindow() + { + currencyMap.Add(1, 1); + currencyMap.Add(2, 2); + currencyMap.Add(3, 5); + currencyMap.Add(4, 10); + currencyMap.Add(5, 20); + currencyMap.Add(6, 50); + currencyMap.Add(7, 100); + } + public MainWindow() { InitializeComponent(); @@ -52,12 +68,14 @@ void validator_BillStacked(object sender, EventArgs e) void validator_OnEscrow(object sender, int denomination) { validator.Stack(); - Console.WriteLine("Escrowed ${0}", denomination); + if(currencyMap.ContainsKey(denomination)) + Console.WriteLine("Escrowed ${0}", currencyMap[denomination]); } private void validator_OnCredit(object sender, int denomination) { - Console.WriteLine("Credited ${0}", denomination); + if (currencyMap.ContainsKey(denomination)) + Console.WriteLine("Credited ${0}", currencyMap[denomination]); } void validator_PowerUp(object sender, EventArgs e) From a9fbbc38007423ff02188d972229eb7b1dd50e40 Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Tue, 1 Sep 2015 20:35:01 -0700 Subject: [PATCH 09/50] Make consistent states vs events in the context of RS-232 Name all states in a States enum. Make the event names start with "is" for states and "on" for events. Also, add a kill bool to the main loop thread so we can safely shutdown a port. --- Apex7000_BillValidator/ApexValidator.cs | 80 ++++++++++++++++++------- Apex7000_BillValidator/DataContracts.cs | 4 +- Apex7000_BillValidator/Events.cs | 21 +++---- Apex7000_BillValidator/RS232Config.cs | 7 +-- 4 files changed, 75 insertions(+), 37 deletions(-) diff --git a/Apex7000_BillValidator/ApexValidator.cs b/Apex7000_BillValidator/ApexValidator.cs index 0531105..135dd78 100644 --- a/Apex7000_BillValidator/ApexValidator.cs +++ b/Apex7000_BillValidator/ApexValidator.cs @@ -10,6 +10,7 @@ public partial class ApexValidator { private readonly object mutex = new object(); + private static readonly slf4net.ILogger log = slf4net.LoggerFactory.GetLogger(typeof(StrongPort)); #region Fields private StrongPort port = null; @@ -30,6 +31,9 @@ public ApexValidator(RS232Config config) /// public void Close() { + // This will kill the comms loop + config.IsRunning = false; + port.Disconnect(); } @@ -49,16 +53,20 @@ public void Connect() try { port.Connect(); + + + // Only start if we connect without error + startRS232Loop(); + } catch (Exception e) { if (OnError != null) { + log.Error(e.Message); NotifyError(ErrorTypes.PortError); } } - - startRS232Loop(); } } @@ -68,9 +76,19 @@ public void Connect() private void startRS232Loop() { - Thread ackThread = new Thread((fn) => + if (config.IsRunning) { - while (true) + log.Error("Already running RS-232 Comm loop... Exiting now..."); + return; + } + + Thread speakThread = new Thread((fn) => + { + + config.IsRunning = true; + + // Set toggle flag so we can kill this loop + while (config.IsRunning) { speakToSlave(); @@ -88,9 +106,11 @@ private void startRS232Loop() Thread.Sleep(config.PollRate); } + }); - ackThread.IsBackground = true; - ackThread.Start(); + + speakThread.IsBackground = true; + speakThread.Start(); } /// @@ -102,16 +122,21 @@ private void WriteWrapper(byte[] data) try { port.Write(data); - } catch(PortException pe) + + } + catch(PortException pe) { switch(pe.ErrorType) { - case PortErrors.WriteError: + case ExceptionTypes.WriteError: OnError(this, ErrorTypes.WriteError); break; - case PortErrors.PortError: + case ExceptionTypes.PortError: OnError(this, ErrorTypes.PortError); break; + + default: + throw pe.GetBaseException(); } } } @@ -126,16 +151,17 @@ private byte[] ReadWrapper() { return port.Read(); - } catch(PortException pe) + } + catch(PortException pe) { switch (pe.ErrorType) { - case PortErrors.WriteError: - OnError(this, ErrorTypes.WriteError); - break; - case PortErrors.PortError: - OnError(this, ErrorTypes.PortError); + case ExceptionTypes.Timeout: + OnError(this, ErrorTypes.Timeout); break; + + default: + throw pe.GetBaseException(); } return new byte[0]; @@ -176,12 +202,12 @@ private void speakToSlave() } // Attempt to write data to slave - config.pushDebugEntry(DebugBufferEntry.DebugBufferEntryAsMaster(data, Thread.CurrentThread.ManagedThreadId)); + config.pushDebugEntry(DebugBufferEntry.AsMaster(data)); WriteWrapper(data); // Blocks until all 11 bytes are read or we give up var resp = ReadWrapper(); - config.pushDebugEntry(DebugBufferEntry.DebugBufferEntryAsSlave(resp, Thread.CurrentThread.ManagedThreadId)); + config.pushDebugEntry(DebugBufferEntry.AsSlave(resp)); // POSSIBLE FUNCTION EXIT!! // No data was read, return!! @@ -209,10 +235,22 @@ private void speakToSlave() // With the exception of Stacked and Returned, only we can // only be in one state at once - config.PreviousResponse = (Response)resp[3]; + config.PreviousResponse = (States)resp[3]; + + // Only one state will be reported at once with the exception of idle + if ((config.PreviousResponse & States.Idle) == States.Idle) + IsIdling(this, null); - // Only one state will be reported at once - // TODO + if ((config.PreviousResponse & States.Accepting) == States.Accepting) + IsAccepting(this, null); + else if ((config.PreviousResponse & States.Stacking) == States.Stacking) + IsStacking(this, null); + else if ((config.PreviousResponse & States.Stacked) == States.Stacked) + OnBillStacked(this, null); + else if ((config.PreviousResponse & States.Returning) == States.Returning) + IsReturning(this, null); + else if ((config.PreviousResponse & States.Returned) == States.Returned) + OnBillReturned(this, null); // Mask away rest of message to see if a note is in escrow @@ -264,7 +302,7 @@ private void speakToSlave() // Per the spec, credit message is issued by master after stack event is // sent by the slave. - if ((config.PreviousResponse & Response.Stacked) == Response.Stacked) + if ((config.PreviousResponse & States.Stacked) == States.Stacked) { config.EscrowCommand = EscrowCommands.None; diff --git a/Apex7000_BillValidator/DataContracts.cs b/Apex7000_BillValidator/DataContracts.cs index 7c98623..28acbde 100644 --- a/Apex7000_BillValidator/DataContracts.cs +++ b/Apex7000_BillValidator/DataContracts.cs @@ -42,11 +42,11 @@ public enum ErrorTypes } [System.Flags] - public enum Response : byte + public enum States : byte { Idle = 1, Accepting = 2, - Escrow = 4, + Escrowed = 4, Stacking = 8, Stacked = 16, Returning = 32, diff --git a/Apex7000_BillValidator/Events.cs b/Apex7000_BillValidator/Events.cs index e5a810e..e372dc1 100644 --- a/Apex7000_BillValidator/Events.cs +++ b/Apex7000_BillValidator/Events.cs @@ -5,11 +5,11 @@ namespace Apex7000_BillValidator public partial class ApexValidator { // States, not really events (byte 1) - public event EventHandler OnIdling; - public event EventHandler OnAccepting; - public event EventHandler OnEscrowed; - public event EventHandler OnStacking; - public event EventHandler OnReturning; + public event EventHandler IsIdling; + public event EventHandler IsAccepting; + // Escrow belongs here but requires an arg so it is further down + public event EventHandler IsStacking; + public event EventHandler IsReturning; // Events that are reported in the state byte public event EventHandler OnBillStacked; @@ -19,7 +19,7 @@ public partial class ApexValidator public event EventHandler OnCashboxAttached; // Errors, credit, other (byte 3) - public event EventHandler PowerUp; + public event EventHandler OnPowerUp; /// /// Raised once a note has been successfully stacked. @@ -38,13 +38,13 @@ public partial class ApexValidator /// Object that raised event /// Index 1-7 of the denomination in escrow. See /// you bill acceptors documentation for the corresponding dollar value. - public delegate void OnEscrowEventHandler(object sender, int denomination); - public event OnEscrowEventHandler OnEscrow; + public delegate void IsEscrowedEventHandler(object sender, int denomination); + public event IsEscrowedEventHandler IsEscrowed; public delegate void OnErrorEventHandler(object sender, ErrorTypes type); public event OnErrorEventHandler OnError; - + #region Private private void HandleEvent(EventHandler eventInst) { HandleEvent(eventInst, null); @@ -78,7 +78,7 @@ protected virtual void NotifyCredit(int e) /// protected virtual void NotifyEscrow(int e) { - OnEscrowEventHandler handler = OnEscrow; + IsEscrowedEventHandler handler = IsEscrowed; if (handler != null) { handler(this, e); @@ -97,5 +97,6 @@ protected virtual void NotifyError(ErrorTypes e) handler(this, e); } } + #endregion } } diff --git a/Apex7000_BillValidator/RS232Config.cs b/Apex7000_BillValidator/RS232Config.cs index 8656523..7919d63 100644 --- a/Apex7000_BillValidator/RS232Config.cs +++ b/Apex7000_BillValidator/RS232Config.cs @@ -106,12 +106,12 @@ public int PollRate /// /// Slaves last state /// - public Response PreviousResponse { get; internal set; } + public States PreviousResponse { get; internal set; } /// - /// Returns true if underlying port is connected + /// Returns true if the communication thread is running normally /// - public bool IsConnected { get; internal set; } + public bool IsRunning { get; internal set; } #endregion #region Internal State @@ -138,7 +138,6 @@ public int PollRate // Track comm timeout from slave device internal DateTime EscrowTimeout { get; set; } - internal int ReconnectAttempts { get; set; } internal void pushDebugEntry(DebugBufferEntry entry) { From b9f0142cef765079d1e23c99e0bb0d6173c4b92e Mon Sep 17 00:00:00 2001 From: Cory Todd Date: Tue, 1 Sep 2015 20:35:25 -0700 Subject: [PATCH 10/50] Update to reflect latest API changes Add bill bank for data binding demo --- .../Apex7000_BillValidator_Test.csproj | 1 + Apex7000_BillValidator_Test/BillBank.cs | 138 ++++++++++++++++++ Apex7000_BillValidator_Test/MainWindow.xaml | 14 +- .../MainWindow.xaml.cs | 44 +++++- 4 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 Apex7000_BillValidator_Test/BillBank.cs diff --git a/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj b/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj index 0964c06..82ad356 100644 --- a/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj +++ b/Apex7000_BillValidator_Test/Apex7000_BillValidator_Test.csproj @@ -58,6 +58,7 @@ App.xaml Code + MainWindow.xaml Code diff --git a/Apex7000_BillValidator_Test/BillBank.cs b/Apex7000_BillValidator_Test/BillBank.cs new file mode 100644 index 0000000..f860142 --- /dev/null +++ b/Apex7000_BillValidator_Test/BillBank.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace Apex7000_BillValidator_Test +{ + partial class MainWindow : INotifyPropertyChanged + { + #region Fields + private int bill1 = 0; + private int bill2 = 0; + private int bill3 = 0; + private int bill4 = 0; + private int bill5 = 0; + private int bill6 = 0; + private int bill7 = 0; + #endregion + + #region Properties + public int Bill1 + { + get { return bill1; } + set + { + bill1 = value; + NotifyPropertyChanged("Bill1"); + } + } + + public int Bill2 + { + get { return bill2; } + set + { + bill2 = value; + NotifyPropertyChanged("Bill2"); + } + } + + public int Bill3 + { + get { return bill3; } + set + { + bill3 = value; + NotifyPropertyChanged("Bill3"); + } + } + + public int Bill4 + { + get { return bill4; } + set + { + bill4 = value; + NotifyPropertyChanged("Bill4"); + } + } + + public int Bill5 + { + get { return bill5; } + set + { + bill5 = value; + NotifyPropertyChanged("Bill5"); + } + } + + public int Bill6 + { + get { return bill6; } + set + { + bill6 = value; + NotifyPropertyChanged("Bill6"); + } + } + + public int Bill7 + { + get { return bill7; } + set + { + bill7 = value; + NotifyPropertyChanged("Bill7"); + } + } + #endregion + + internal int AddCredit(int denom) + { + switch(denom) + { + case 1: + return Bill1++; + case 2: + return Bill2++; + case 3: + return Bill3++; + case 4: + return Bill4++; + case 5: + return Bill5++; + case 6: + return Bill6++; + case 7: + return Bill7++; + + default: + // Illegal value + return 0; + } + } + + + #region Private Helpers + + #region INotifyPropertyChanged Members + + public event PropertyChangedEventHandler PropertyChanged; + + + #endregion + + private void NotifyPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + #endregion + } +} diff --git a/Apex7000_BillValidator_Test/MainWindow.xaml b/Apex7000_BillValidator_Test/MainWindow.xaml index a7baecd..b44c80d 100644 --- a/Apex7000_BillValidator_Test/MainWindow.xaml +++ b/Apex7000_BillValidator_Test/MainWindow.xaml @@ -66,13 +66,13 @@