Продольная проверка избыточности не удалась - PullRequest
3 голосов
/ 21 мая 2010

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

Алгоритм, который я использую, выглядит следующим образом (C #):

private static char GetLRC(string s, int start, int end)
{
    int result = 0;
    for (int i = start; i <= end; i++)
    {
        result ^= Convert.ToByte(s[i]);
    }
    return Convert.ToChar(result);
}

Это пример данных трека 3, которые не проходят проверку. На этой карте трек 2 совпал, но трек 1 также потерпел неудачу.

   0 1 2 3 4 5 6 7  8 9 A B C D E F
00 3 4 4 4 4 4 4 4  4 4 4 5 5 5 5 5 
10 5 5 5 5 5 6 6 6  6 6 6 6 6 6 6 7 
20 7 7 7 7 7 7 7 7  7 8 8 8 8 8 8 8 
30 8 8 8 9 9 9 9 9  9 9 9 9 9 0 0 0 
40 0 0 0 0 0 0 0 1  2 3 4 1 1 1 1 1 
50 1 1 1 1 1 2 2 2  2 2 2 2 2 2 2 3 
60 3 3 3 3 3 3 3 3 

Разделителем сектора является ';' и заканчивается на «?».

Байт LRC этой дорожки равен 0x30. К сожалению, вышеприведенный алгоритм вычисляет LRC 0x00 для следующего вычисления (извиняюсь за его длину. Я хочу быть тщательным):

00 ^ 3b = 3b ';'
3b ^ 33 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 31 = 39
39 ^ 32 = 0b
0b ^ 33 = 38
38 ^ 34 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 3f = 00 '?'

Если кто-нибудь может указать, как исправить мой алгоритм, я был бы признателен.

Спасибо, PaulH


Редактировать:

Так что вы можете видеть, пропускаю ли я случайно какие-либо байты в моем расчете LRC или включаю неправильные (последний символ "." На самом деле - "\ r"). Полные данные со всех трех треков:

   0 1 2 3 4 5 6 7  8 9 A B C D E F
00 % U V W X Y Z 0  1 2 3 4 5 6 7 8 
10 9 9 A B C D E F  G H I J K L M N 
20 O P Q R S T U V  W X Y Z 1 2 3 0 
30 1 2 3 4 5 6 7 8  9 A B C D E F G 
40 H I J K L M N O  P Q R S T ? 3 ; 
50 1 2 3 4 5 6 7 1  2 3 4 5 6 7 8 9 
60 0 1 2 3 4 5 6 7  8 9 0 1 2 3 4 5 
70 6 7 8 9 0 ? 5 ;  3 4 4 4 4 4 4 4 
80 4 4 4 5 5 5 5 5  5 5 5 5 5 6 6 6 
90 6 6 6 6 6 6 6 7  7 7 7 7 7 7 7 7 
A0 7 8 8 8 8 8 8 8  8 8 8 9 9 9 9 9 
B0 9 9 9 9 9 0 0 0  0 0 0 0 0 0 0 1 
C0 2 3 4 1 1 1 1 1  1 1 1 1 1 2 2 2 
D0 2 2 2 2 2 2 2 3  3 3 3 3 3 3 3 3 
E0 ? 0 .

Алгоритм GetLRC() переоборудован, как предлагается, только для байтов XOR, которые появляются нечетное число раз:

private static char GetLRC(string s, int start, int end)
{
    int result = 0;

    byte cur_byte = Convert.ToByte(s[start]);

    int count = 0;
    for (int i = start; i <= end; i++)
    {
        byte b = Convert.ToByte(s[i]);
        if (cur_byte != b)
        {
            if (count % 2 != 0)
            {
                result ^= cur_byte;
            }
            cur_byte = b;
            count = 0;
        }
        ++count;
    }

    if (count % 2 != 0)
    {
        result ^= cur_byte;
    }

    return Convert.ToChar(result);
}

Шаг вычислений, выполняемый новой функцией GetLRC():

00 ^ 3b = 3b ';'
3b ^ 33 = 08
08 ^ 31 = 39
39 ^ 32 = 0b
0b ^ 33 = 38
38 ^ 34 = 0c
0c ^ 33 = 3f
3f ^ 3f = 00 '?'

Вопрос: байт LRC исходит от самой карты или он добавляется микропрограммой считывателя? (то есть, возможно, это ошибка прошивки)

Ответы [ 3 ]

1 голос
/ 24 июня 2016

Алгоритм о LRC исправлен, но формат данных для расчета LRC может быть неправильным. (это зависит от вашего читателя MSR)

Существует два формата дорожек, определенных ANSI / ISO (Альфа и BCD). Кодировка двоичного кода отличается от кодировки ASCII.

В этом случае начальным стражем будет ';' поэтому формат должен быть BCD. (Страж альфа-старта '%')

LRC используется для вычисления "данных реального трека" (не включая бит четности),

Convert rule 
ASCII to BCD ->(ASCII - 0x30) 

    --Data Bits--    Parity 
    b1  b2  b3  b4   b5      Character  Function

    0   0   0   0    1        0 (0H)    Data
    1   0   0   0    0        1 (1H)      " 
    0   1   0   0    0        2 (2H)      " 
    1   1   0   0    1        3 (3H)      " 
    0   0   1   0    0        4 (4H)      " 
    1   0   1   0    1        5 (5H)      " 
    0   1   1   0    1        6 (6H)      " 
    1   1   1   0    0        7 (7H)      " 
    0   0   0   1    0        8 (8H)      " 
    1   0   0   1    1        9 (9H)      " 
    0   1   0   1    1        : (AH)    Control
    1   1   0   1    0        ; (BH)    Start Sentinel
    0   0   1   1    1        < (CH)    Control
    1   0   1   1    0        = (DH)    Field Separator
    0   1   1   1    0        > (EH)    Control
    1   1   1   1    1        ? (FH)    End Sentinel

В вашем образце

  1. Преобразование данных дорожки ASCII в формат BCD.
  2. Используйте данные BCD для расчета LRC, результат 0x00.
  3. Затем преобразовать LRC (BCD в ASCII), наконец, получите LRC = 0x30.

P.S. ASCII конвертировать в Альфа

    if(bASCII >= 0x20 && bASCII <= 0x5B)
    {
        return(bASCII - 0x20);
    }
    else if(bASCII >= 0x5C && bASCII <= 0x5F)
    {
        return(bASCII - 0x1F);
    }
1 голос
/ 21 мая 2010

Могу ли я сделать предложение? Сохраните ваши данные как длины пробега и делайте xor только если длина пробега нечетна, а затем делайте это только один раз (runLength & 0x01) раз. Это избавит от тонны бесполезной работы и прояснит, что происходит. Это дает:


Run Lengths:
(01,3b)(01,33)(10,34)(10,35)(10,36)(10,37)(10,38)(10,39)(10,30)
(01,31)(01,32)(01,33)(01,34)(10,31)(10,32)(09,33)(1,3f)

Выполнение четной / нечетной вещи дает:


3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 3f
        08-->39-->0B-->38-->0C-->3F-->00

Намного проще и чище смотреть. Я предполагаю, что, глядя на ваши данные, в вашем потоке данных есть еще 30 или 1 шорт. Если добавить еще 30, вы получите ответ:


3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 30 ^ 3F
        08-->39-->0B-->38-->0C-->3F-->0F-->30

Кроме того, я буду продолжать копать ...

Можете ли вы добавить некоторые утверждения или другие проверки для ваших входных параметров? Я не хотел бы видеть начало / конец за пределами границ, вызывающие волнение и / или пустую строку. Кроме того, есть ли возможность выключения по одному с началом конца? Инклюзивный / эксклюзивный диапазон данных? Это может составлять дополнительный 0x030 в конце ваших данных из 0, сохраненного в конце вашей дорожки 3, конвертируемого в 0x30. Кроме того, есть ли вероятность наличия поврежденных данных или поврежденного LRU? Очевидно, это именно то, что пытается проверить ваш чек. Возможно, что-то поймало?

0 голосов
/ 17 октября 2012

Ваш алгоритм не соответствует алгоритму LRC в статье Википедии .Вы уверены, что используете правильный алгоритм?

...