17

I am currently building a POS solution for my company. The hardest part is shopping for the cash drawer as I do not have much experience with them and would prefer a USB cash drawer. I have found a model I am interested in

CR-4005

http://www.thebarcodewarehouse.co.uk/epos-systems/cash-drawers/cr-4005-b/

The supplier includes a driver which can be found here

http://www.posiflexusa.com/driver.php

This allows you to open the drawer etc using a dll file. An example of the codes given are like so:

Public Declare Function OpenUSB Lib "usbcr.dll" () As Long

I have minor experience with C but with google I am sure I could figure this part out.

The issue I am having is that the solution is just effectively a website hosted offsite, what I need to be able to do is from the site issue commands to the client machine using it. So that when they complete a sale I can open the drawer for that particular machine.

What I need to clarify is how I go about doing this. For example, I would assume I install the driver on the client machine and plug the cash drawer in. Then when they access the site I need to execute the C command shown above to open the drawer. The problem i am having is wrapping my head around how this would work. Surely if I execute the command on the server it will effectively be looking at the servers usb ports and trying to open the drawer. Rather than issuing the command to the client machine. Therefore in order to work around this would it be possible to maybe have the c file on the clients machine and then I simply call a file on the site using something like

C:\Windows\execute.bat

Which in turn calls the c file on the client machine.

I understand I don't have a lot of information to provide as I am trying to figure this out before going ahead with the purchase and I am probably over complicating this but any pointers or info would be most appreciated. Also I am not completely set on this model, so if you know an alternative with some good documentation or an existing solution, I am open to this also.

Notes

I understand there could be a possible solution with chrome api calls

I could potentially install xampp and create a simple php files that calls an exe which does the necessary work. Therefore maybe accessing a local address on the client machine could be another potential idea (ie 127.0.0.1/open.php).

Update

My Website including the POS side of things is built and ready to go. This is built using PHP and is hosted on an external server. We access the site via a domain.

When the user performs a specific action on the external site, it needs to open the staff members local till drawer either by opening a local file (ie an exe that can open the drawer) or by accessing say a local webserver on the machine ie localhost/open.

The till drawer is the one listed above and it is connected via USB to the clients machine. No receipt printer is used.

The Humble Rat
  • 4,586
  • 6
  • 39
  • 73

4 Answers4

28

Let me get this straight:

  1. You did a web app which is a POS (presumably in PHP)
  2. Your users access the POS by a web browser on a local server
  3. You need to be able to open de cash drawer client side... (e.g. to give change back to customer)

Option 1:

Considering that:

  • You control the customer POS clients (as in you can install software and set policies)
  • You can install google chrome and set it as a requirement for your app

Then you could try using the native chrome USB library:

http://developer.chrome.com/apps/app_usb

It has it's caveats, yes, but chances are you may have luck and that the device can be opened with this. I've worked several years for a POS software company and both serial and usb cash drawers had a really really simple protocol that allowed us to open them even with FoxPro.

You would have to create a small chrome app that sends the command to open the drawer. This app should expose one function that could be called once you write the operation or commit the transaction to the server (e.g. when you saved a record of the sale) so you could attach a callback in jQuery o javascript that does this after you post the data and receive a succesful response.

Option 2:

Java applet:

I have no experience with this. But you may be able to use JNI (java native interface) to call native code. I'm not sure if the applet container is sandboxed in a way that does not allow you to do it, but these two links may come in handy:

How To Call Native (DLL) Code From Java Using JNI Calling C library routines from java

Option 3:

Doing it OS-wise:

Another option, and seems to be the easiest for me, is to map a keystroke at the OS level so that the combination executes certain command. You can see here a description of how to do it in windows. In linux (gnome and kde etc) this is very easy.

Once You did that, you could use this jQuery library, that "simulates" keystrokes, so, again, when you receive your response that the transaction is done and that you need to open de cash drawer you'll want to callback a function that executes a simulation keystroke that you previsouly had configured as per the article I gave you.

And of course, this command would run a locally native application which actually opens the drawer, can be in C/C++/C# or whatever the supported device API is. But I'm sure is a standard interface so you can code that app easily in any language. Here's a good start for C#.

Option 4:

Local web server.

Now that you mention having a local web server this could be an option, actually. But, why install XAMPP on client machines? There is a better way to do it. And the answer would be write a really really small and simple HTTP web server in C#/.NET. So following this approach you'll want to:

  1. Write an HTTP server in C#/.Net listening to a specific port (here's a guide, its barely 50 lines of code)
  2. In your C# code you'll want to either use any integration API coming with the hardware, P/Invoke to the C library (which I don't recommend) or simply using the send to USB port commands approach. And thus, it'll be simpler to open the drawer, print or do whatever you need from within C# which is OS integrated. (even for linux/mac with mono)
  3. Set up your code in C# so that the server only listens to local addresses so no one can open the till unless is the same network, heck, I would only allow 127.0.0.1 just for the sake of making sure only the local machine can open it.
  4. Put this compiled exe on windows autostart so that whenever the computer starts the mini web server that opens the till also starts.
  5. Just catch your callback whenever a transaction was succesful to the POS server and finally do something like:

    $.ajax({
        type: 'POST',
        dataType: 'json',
        data: 1,
        url: '127.0.0.1:8088/open',
        error: function() {
            alert('Could not open cash drawer');
        },
        success: function() {
            //do something else
        }
    });
    

So you'll be sending a POST request to the local machine which listens to the HTTP protocol in the 8088 port (or whatever you set up in your code) and then it'll handle internally the request as opening the drawer, if you throw an exception inside that code than you can return an HTTP 500 response from this C# mini webserver so that you catch it on the error handler of jquery (or whatever library that you use)

And I would highly recommend, like I told you, that this app only listens to local requests for security reasons, even if you are only doing a simple operation. It'll work because the client side jquery code is being called by the local machine.

You could also optimize the webserver app so that it read a .ini file or some settings file (.Net has the .config default which is the way to go) so that you can tweak it per-customer basis and you don't hardcode options.

Good luck! And let us know how you did it

Gustavo Rubio
  • 10,209
  • 8
  • 39
  • 57
  • I have some progress, I have managed to get the C file working to Open the till and I have installed autohotkley and can now execute the exe on a press of a few keys. SO definitely moving forwared. So the final stage it to execute the key presses ie CTRL+ALT+INSERT when the transaction has completed. I have been looking at simulating key presse but the answers all seem to be listening for a key press rather than executing a key press. Could you point me in the direction of the documentation for this? – The Humble Rat Feb 28 '14 at 14:41
  • @TheHumbleRat My bad, forgot to put the link to the jQuery simulate library, I edited my response. Anyway you can see the library here: https://github.com/j-ulrich/jquery-simulate-ext although I'm not sure if it is going to be possible to "send" the keystroke outside the sandboxed browser. – Gustavo Rubio Feb 28 '14 at 16:23
  • @TheHumbleRat Just added a fourth option, if you don't have experience on .NET I can help you a little bit. – Gustavo Rubio Feb 28 '14 at 16:55
  • I'll certainly gives this a shot, I am exploring a few avenues at the moment. Before this I never touched C, Chrome Apps/Chrome Extensions etc and have learned a ton in just one week of doing this, definitely the biggest challenge I've ever faced. Without your suggestions I'm sure I would be nowhere near the position I am currently in. Seriously big thanks for all the time you've taken so far, the effort is noticeable. I'll be sure to let you know the outcome and the solution (fingers crossed) when I get there. – The Humble Rat Feb 28 '14 at 17:35
  • Just did a quick test on some of my own servers and this method seems to do the trick, granted I am using xampp, but it's proof of concept. I'll definitely be using the C#/.NET HTTP approach you mention and will be sure to take your advice in terms of security. I am off work for the week, now I'm wondering about making my own exe file that installs the C# HTTP server, compiles the c code I have that opens the till , and also installs and activates the autohotkey mapping to open the till for managers. I think options 3 and 4 suit my environment (ie total control). Many thanks you're a genius! – The Humble Rat Feb 28 '14 at 18:40
  • @TheHumbleRat Glad to help! Let me know if you need more help with the code – Gustavo Rubio Feb 28 '14 at 18:49
  • Don't worry about that, I have a feeling I'll be back again before this process is over. – The Humble Rat Feb 28 '14 at 18:56
  • Sorry faux pas. I have not only accepted the answer, but awarded the bounty. – The Humble Rat Feb 28 '14 at 20:50
2

Not really an answer, though too long for a comment..

It sounds to me like you wish to call native code from a browser. That's not going to please lots of people, although I am aware of precisely one way to achieve this. It involves Internet Explorer and a COM server (activeX). IE can create an instance of the activeX program, which you'll need to write.

This activeX can then issue the command to the vendor-supplied DLL. The problem with this though, is that if I was sitting at one of the terminals and had a keyboard, I could also open the drawer. You'd also need a method of communicating the intent to open the drawer from the server to the client. I suppose you could use WebSockets to maintain a communication channel between the client and the server, through which you issue the intent to open the drawer.

This may be okay in a locked-down situation, though has all kinds of security concerns I've not considered nor mentioned here.

To recap, here's a possible solution:

  1. Establish a WebSocket connection between the client and the server.
  2. Issue a command via this channel to the client browser from the server.
  3. Catch this command in the browser and then create an ActiveX object.
  4. Using javascript, tell this activeX object to open the drawer.
  5. Inside the ActiveX object, respond to a request to open the drawer by calling the appropriate function in the vendor-supplied DLL.

I'd feel a little uneasy about implementing this personally (and would wish to be compensated handsomely).

Incidentally, you can control amongst other examples, MS Office in this manner - allowing you to create a spreadsheet/word doc/etc from within the browser, populating the new document with user entered info.

Here's a JS file I wrote for a project 18 months ago, that controls Excel.

//
// jsExcelObj.js
// 28/08/2012 

// the (only Excel) app instance - we only want to have 1
// **** don't access this variable directly ****
var jsExcelApp = null;

/*****************************************************************************
    Excel class
*****************************************************************************/
function startExcel()
{
    jsExcelApp = new ActiveXObject("Excel.Application");
}

function stopExcel()
{
    jsExcelApp.Quit();
    delete(jsExcelApp);
    jsExcelApp = null;
}

function jsExcelWorkbook(filename)
{
    if (jsExcelApp == null)
        startExcel(); //jsExcelApp = new ActiveXObject("Excel.Application");

    this.mFilename = filename;
    this.mExcelSheet = null;
    this.mWorkbook = jsExcelApp.Workbooks.Open(filename);

    this.close = function()
    {
        this.mWorkbook.Close(false);
        this.mFilename = null;
        this.mExcelSheet = null;
        this.mWorkbook = null;
    }

    this.open = function(filename)
    {
        if (jsExcelApp == null)
            startExcel();

        if (this.mFilename != null)
            this.close();

        this.mFilename = filename;
        this.mExcelSheet = null;
        this.mWorkbook = jsExcelApp.Workbooks.Open(filename);
    }

    this.setSheet = function(sheetName)
    {
        this.mExcelSheet = this.mWorkbook.Worksheets(sheetName);
    }

    this.getCellValue = function(column, row)
    {
        return this.mExcelSheet.Cells(row, column).value;
    }

    // returns the cells background colour as a html hex color value - e.g "7a554a"
    this.getCellColor = function(column, row)
    {
        var hexStrVel, r, g, b, decNum;

        decNum =  this.mExcelSheet.Cells(row, column).Interior.Color;
        // get a hexidecimal string representation of the number
        hexStrVal = decNum.toString(16);

        // pad to 6 bytes long
        while (hexStrVal.length < 6)
        {
            hexStrVal = "0" + hexStrVal;
        }

        // extract the 3 components
        r = hexStrVal.substr(4,2);
        g = hexStrVal.substr(2,2);
        b = hexStrVal.substr(0,2);

        return r+g+b; // return them in reverse order
    }
}

Using it is a simple as:

<script src='script/jsExcelObj.js'></script>
<script>
var fullyQualifiedPathToExcelWorkbook = "C:/someFile.xls";
var mExcel = new jsExcelWorkbook(fullyQualifiedPathToExcelWorkbook);
mExcel.setSheet("Sheet1");
var col1Row1 = mExcel.getCellValue(1, 1);
alert(col1Row1);
mExcel.close();
stopExcel();
</script>

I'm more than a little curious as to what other answers you'll get to this question. It sounds like a long march through a minefield from every perspective I can think of..

I would consider very seriously implementing my own server/client architecture using c++ and forget about using HTML/PHP. This may be because I know too little, or it may be because I know enough to see the dangers - I don't know!

enhzflep
  • 12,927
  • 2
  • 32
  • 51
  • It certainly seems as though every step I take another issue appears. I have pretty much built a pos system without a struggle. It now seems that opening the drawer may take the same time the whole project has taken so far! Many thanks for your input though, makes things a bit clearer in my mind, definitely a few characters too long for a comment. I'll see what answers I get, but i have a feeling this will end up being the accepted answer. I have been developing with chrome and would ideally want to stick with this, but I may not have a choice. Thanks again, regards – The Humble Rat Feb 19 '14 at 11:53
  • :laughs: At times, programming reminds me of some of the maths we did at uni. A seemingly innocent 1/2 line question takes page upon page to answer! Another possible alternative would be to host the IWebBroswer2 object inside a native application. This would eliminate some hurdles and introduce others - you'd still be stuck with IE though. :( - unless Qt or WxWidgets implement their own flavour of a HTML control (complete with scripting ability) - Mozilla used to implement an ActiveX server in their browser - perhaps Chrome does too. In any case, you're welcome. An interesting question! – enhzflep Feb 19 '14 at 12:20
  • Many thanks for your input, everything you said definitely put me onto the path of understanding my problem. I have accepted an answer that is specific to my environment, but your help was definitely crucial to this success. – The Humble Rat Feb 28 '14 at 20:48
  • You're welcome. Thanks to your question I've now been exposed to the native Chrome usb library. Win-win! So thanks. :) Hope the project goes well. – enhzflep Mar 01 '14 at 07:56
1

Given the client machines presumably will be to some degree under your control, my understanding is all you need is a simple Remote Procedure Call system, I think that insisting the code must be run through a browser is unnecessarily difficult. My recommendation instead would to have a daemon (or service given we are in Windows land) running on the client machine which will respond to a remote request to control the cash draw. This program can be a completely separate program to the browser. You then have the server, upon a client opening a webpage send a packet to the client's IP address which will trigger this service on the client to control the cash draw.

I am unfortunately too rusty with windows C programming to give an example but will try and break this down as simply as possible:

On the client machines, run a daemon, which will accept connections on a particular port (only from the server's IP address of course to avoid just anyone connecting and controlling it. You could also use security certificates but that goes beyond the scope of this answer.) After accepting connections on this port it will respond to a set of packets which it can be sent which will correspond to actions on the cash draw. This can effectively be a simple C program which will listen on a socket then run functions in that DLL when it receives data.

On the server you will need a program that responds to a client's attempt to access a particular webpage, you can hook this into PHP such that PHP will run a program on the server when the page is accessed, I assume you already know how to do this from what has been said in the question. This program will then open a connection to the IP of the client as given in the HTTP request and send a cash draw command to the socket the client's service is listening on. This should cause the client to do something with the draw. (you must hope the client is not masquerading an IP address however.)

Finally you need the webpage to allow the client to request these commands from the server, there are a number of security concerns, particularly relating to the security of the client service but these are all relatively simple to overcome. This should also only take about 150 lines of code for a simple implementation. It also avoids any odd platform specific or browser specific code and completely avoids websockets.

I hope this helps, if it is in any way unclear please leave a comment.

Vality
  • 6,577
  • 3
  • 27
  • 48
1

Are you using an epson-compatible receipt printer (ESC/POS language)? If so, you can use an ethernet printer and access the printer using PHP to pop a printer-connected cash drawer.

Here is a code snippet from something I have done before:

<?php

$texttoprint = $_POST['printthis']; 
$texttoprint = stripslashes($texttoprint); 

$fp = fsockopen("192.168.10.30", 9100, $errno, $errstr, 10); 
if (!$fp) { 
    echo "$errstr ($errno)<br />\n"; 
} else { 
    fwrite($fp, "\033\100"); 
    $out = $texttoprint . "\r\n"; 
    fwrite($fp, $out); 
    fwrite($fp, "\012\012\012\012\012\012\012\012\012\033\151\010\004\001"); 
    fclose($fp); 
} 

?>

See http://files.support.epson.com/pdf/general/escp2ref.pdf for details on print codes.

As someone with years of POS experience, the best advice I could give you about creating a POS from scratch is this: DON'T DO IT!

There are some free or open-source solutions out there that do what you probably need them to, but even if you end up paying for something, it will be much less of a headache than building a POS. Sorry if that's not what you wanted to hear, but I've seen so many people try, especially web-based (which is also a bad idea for many other reasons).

David A
  • 36
  • 4