Продольная проверка избыточности в Javascript

Я работаю с системой, которая включает в себя устройство Point of Sell (POS), я использую chrome serial для сканирования портов и возможности чтения данных кредитных карт.

Проблема, с которой я сталкиваюсь, заключается в том, что мне нужно объединить LRC из строки в следующем формате:

STX = '\ 002' (2 HEX) (начало текста)

LLL = Длина данных (не включает STX или ETX, но команда).

Command C50 {C = сообщение от ПК к POS, 50 фактический код, который "печатает" сообщение на POS}

ETX = '\ 003' (3 HEX) (конец текста)

LRC = Продольная проверка избыточности

Пример сообщения будет следующим:

'\002014C50HELLO WORLD\003'

Здесь мы можем видеть 002 как STX, 014 - длину от C50 до D и 003 как ETX.

Я нашел некоторые алгоритмы в C#, такие как этот или этот, и даже этот в Java, я даже видел этот вопрос, который был удален из SO в кеше Google, который фактически спрашивает то же, что и я, но у меня не было примеров или ответов.

Я также сделал этот алгоритм Java:

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;
}

и попытался передать его в Javascript (где я плохо знаю)

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();
}

и после псевдокода Википедии я попытался сделать это:

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;
}

Вот как я называю вышеуказанный метод:

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

Однако после попытки всех этих методов, я все еще не могу правильно отправить сообщение в POS. Я уже 3 дня пытаюсь это исправить и больше ничего не могу сделать, пока не закончу.

Есть кто-нибудь, кто знает другой способ подсчета LRC или что я здесь не так делаю? Мне нужно, чтобы это было с Javascritpt, поскольку POS соединяется с ПК через NodeJS.

О, кстати, код от convertStringToArrayBuffer находится в последовательной документации chrome, а именно:

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;
}

После тестирования я пришел с этим алгоритмом, который возвращает 'z' (нижний регистр) со следующим вводом: \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);
}

Однако с некоторыми более длинными входами и, особенно, при попытке прочитать данные карты, LRC иногда становится управляющим символом, что в моем случае, если я использую их в своей строке, может быть проблемой. Есть ли способ заставить LRC избегать этих персонажей? Или, возможно, я делаю это неправильно, и именно поэтому у меня есть эти символы в качестве вывода.

2 ответа

Решение

Я решил проблему LRC, рассчитав ее следующим методом, прочитав ответ @Jack A. и изменив его на этот:

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);
}

Объяснение того, что он делает:

1-е: преобразует полученную строку в эквивалент ASCII (charCodeAt()).

2-й: он вычисляет LRC, выполняя операцию XOR между последним вычисленным LRC (0 на 1-й итерации) и ASCII строки для каждого символа.

3-е: он конвертирует из ASCII в эквивалентный чат (fromCharCode()) и возвращает этот символ в основную функцию (или любую функцию, которая ее назвала).

Ваш алгоритм на основе псевдокода использует сложение. Для версии XOR попробуйте это:

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;
}

Я думаю, что ваша первоначальная попытка версии XOR не удалась, потому что вам нужно было получить код символа. number переменная все еще содержала строку, когда вы сделали result = result ^ numberТаким образом, результаты были, вероятно, не то, что вы ожидали.

Это SWAG, так как в данный момент у меня не установлен Node.JS, поэтому я не могу убедиться, что он будет работать.

Еще одна вещь, которая меня беспокоит, это кодировка символов. JavaScript использует UTF-16 для текста, поэтому преобразование любых не-ASCII символов в 8-битные байты может дать неожиданные результаты.

Другие вопросы по тегам