4

I'm working with a system that integrates a Point of Sell (POS) device, I use chrome serial to scan ports and be able to read credit card data.

The problem I'm facing is that I need to concat the LRC from a string in this format:

STX = '\002' (2 HEX) (Start of text)

LLL = Length of data (doesn't include STX or ETX but command).

Command C50 {C = A message from PC to POS, 50 the actual code that "prints" a message on POS}

ETX = '\003' (3 HEX) (End of text)

LRC = Longitudinal Redundancy Check

A message example would be as follows:

'\002014C50HELLO WORLD\003'

Here we can see 002 as STX, 014 is the length from C50 to D, and 003 as ETX.

I found some algorithms in C# like this one or this one and even this one in Java, I even saw this question that was removed from SO on Google's cache, which actually asks the same as I but had no examples or answers.

I also made this Java algorithm:

private int calculateLRC(String str) {
    int result = 0;
    for (int i = 0; i < str.length(); i++) {
        String char1 = str.substring(i, i + 1);
        char[] char2 = char1.toCharArray();
        int number = char2[0];
        result = result ^ number;
    }
    return result;
}

and tried passing it to Javascript (where I have poor knowledge)

function calculateLRC2(str) {
    var result = 0;
    for (var i = 0; i < str.length; i++) {
        var char1 = str.substring(i, i + 1);
        //var char2[] = char1.join('');
        var number = char1;
        result = result ^ number;
    }
    return result.toString();
}

and after following the Wikipedia's pseudocode I tried doing this:

function calculateLRC(str) {
    var buffer = convertStringToArrayBuffer(str);
    var lrc;
    for (var i = 0; i < str.length; i++) {
        lrc = (lrc + buffer[i]) & 0xFF;
    }
    lrc = ((lrc ^ 0xFF) + 1) & 0xFF;
    return lrc;
}

This is how I call the above method:

var finalMessage = '\002014C50HELLO WORLD\003'
var lrc = calculateLRC(finalMessage);
console.log('lrc: ' + lrc);
finalMessage = finalMessage.concat(lrc);
console.log('finalMessage: ' + finalMessage);

However after trying all these methods, I still can't send a message to POS correctly. I have 3 days now trying to fix this thing and can't do anything more unless I finish it.

Is there anyone that knows another way to calculate LRC or what am I doing wrong here? I need it to be with Javascritpt since POS comunicates with PC through NodeJS.

Oh btw the code from convertStringToArrayBuffer is on the chrome serial documentation which is this one:

var writeSerial=function(str) {
  chrome.serial.send(connectionId, convertStringToArrayBuffer(str), onSend);
}
// Convert string to ArrayBuffer
var convertStringToArrayBuffer=function(str) {
  var buf=new ArrayBuffer(str.length);
  var bufView=new Uint8Array(buf);
  for (var i=0; i<str.length; i++) {
    bufView[i]=str.charCodeAt(i);
  }
  return buf;
}

Edit After testing I came with this algorithm which returns a 'z' (lower case) with the following input: \002007C50HOLA\003.

function calculateLRC (str) {
    var bytes = [];
    var lrc = 0;
    for (var i = 0; i < str.length; i++) {
        bytes.push(str.charCodeAt(i));
    }
    for (var i = 0; i < str.length; i++) {
        lrc ^= bytes[i];
        console.log('lrc: ' + lrc);
        //console.log('lrcString: ' + String.fromCharCode(lrc));
    }
    console.log('bytes: ' + bytes);
    return String.fromCharCode(lrc);
}

However with some longer inputs and specialy when trying to read card data, LRC becomes sometimes a Control Character which in my case that I use them on my String, might be a problem. Is there a way to force LRC to avoid those characters? Or maybe I'm doing it wrong and that's why I'm having those characters as output.

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Do you know which type of LRC is required by your POS device? There are two different algorithms in your code samples and in the wiki article you linked (one using addition and one using XOR). – Jack A. Sep 08 '15 at 17:38
  • @JackA. hello, it uses XOR form – Frakcool Sep 08 '15 at 17:42

2 Answers2

2

I solved LRC issue by calculating it with the following method, after reading @Jack A.'s answer and modifying it to this one:

function calculateLRC (str) {
    var bytes = [];
    var lrc = 0;
    for (var i = 0; i < str.length; i++) {
        bytes.push(str.charCodeAt(i));
    }
    for (var i = 0; i < str.length; i++) {
        lrc ^= bytes[i];
    }
    return String.fromCharCode(lrc);
}

Explanation of what it does:

1st: it converts the string received to it's ASCII equivalent (charCodeAt()).

2nd: it calculates LRC by doing a XOR operation between last calculated LRC (0 on 1st iteration) and string's ASCII for each char.

3rd: it converts from ASCII to it's equivalent chat (fromCharCode()) and returns this char to main function (or whatever function called it).

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
1

Your pseudocode-based algorithm is using addition. For the XOR version, try this:

function calculateLRC(str) {
    var buffer = convertStringToArrayBuffer(str);
    var lrc = 0;
    for (var i = 0; i < str.length; i++) {
        lrc = (lrc ^ buffer[i]) & 0xFF;
    }
    return lrc;
}

I think your original attempt at the XOR version was failing because you needed to get the character code. The number variable still contained a string when you did result = result ^ number, so the results were probably not what you expected.

This is a SWAG since I don't have Node.JS installed at the moment so I can't verify it will work.

Another thing I would be concerned about is character encoding. JavaScript uses UTF-16 for text, so converting any non-ASCII characters to 8-bit bytes may give unexpected results.

Jack A.
  • 4,245
  • 1
  • 20
  • 34
  • I bet I'm having unexpecetd results because of 8 bit bytes, I always get a 0 when `console.log('lrc: ' + lrc);` is executed... I'll try debuging it and see what's happening. Thanks. If it works I'll accept later :) – Frakcool Sep 08 '15 at 18:16
  • 1
    Applying the XOR operator (`^`) to a string and a number appears to always return the number. See, for example: http://jsfiddle.net/ttycfeax/ . So your original XOR implementation would always return zero because you were not converting to a number using `charCodeAt`. Your "HELLO WORLD" test should not have problems with extended characters. – Jack A. Sep 08 '15 at 19:45
  • I modified a little your algorithm, now it sends a message to POS, however message isn't showing on POS screen, I have a theory about it, my LRC sometimes becomes a [control character](http://ascii.cl/control-characters.htm) and it might be a problem, is there a way I could force LRC to avoid those chars? Or are they valid chars on an LRC calculation? See edit for algorithm edit. – Frakcool Sep 09 '15 at 19:14
  • actually the error for not showing message on POS screen was because of a typo, but still the control character is it ok to have them? or can I avoid them? – Frakcool Sep 09 '15 at 20:12
  • As far as I understand, the LRC itself could be any 8-bit number, which may or may not be a value that can be interpreted as a printable character. – Jack A. Sep 09 '15 at 20:40