PayXpert - User documentation

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

RS232 specifications are more complex than any other, it implies a strict data structure and data exchange workflow. This section will only talk about technical specifications regarding RS232, the concert data structure will be fully explained in other section.

So USB/RS232 means cash register and POS will be linked thanks to a cable, USB or RS232. The type of cable does not matter, the communication will work the same way in Concert. Unlike WIFI, USB/RS232 is half-duplex, it means cash register and POS cannot emit and receive messages simultaneously.

This is the list of speeds (baud or symbols/s) that PayXpress supports:

Baud

Is supported?

1200

(tick)

9600

(tick)

19200

(tick)

38400

(tick)

57600

(tick)

115200

(tick)

Each frame is composed of max 512 data bytes.

A data byte will be composed of 7 bits of data and a bit of parity.

The parity used in concert specifications is EVEN. It means the number of raised bits (1 bit) is always even in a data byte. If the 7 bits of data contain a even raised bits number, parity bit is 0, if it is odd, parity bit is 1.

 

byte_1.png
byte_2.png

This is a security control to prevent any tampering of the data. Regarding the 7 bits of data, they are ASCII-7 and the range of supported characters begins to 0x20 (hex) SPACE until 0x7F (hex) DEL. You can find the list of supported characters in this table.

In a frame, the first data byte is a command that defines the meaning of the frame. All the commands are described in the table below:

NAME

DESCRIPTION

HEX VALUE

ENQ

Ask to open a new session

0x05

ACK

Positive reception acknowledge

0x06

NAK

Negative reception acknowledge

0x15

STX

Start of a message content

0x02

ETX

End of a message content

0x03

EOT

End of the session

0x04

There is no parity bit for command data byte

For your information, most of the time, depending on the software, STX (0x02), ETX (0x03) and LRC characters will not be visible on screen because they are not printable text. For example, Confluence does not display them so when a frame will be used as example, it will be a picture instead of text.

The specifications define the order of commands when cash register and POS communicate. Like in Ethernet/WIFI, the POS is in a waiting state and it is up to the cash register to initiate the communication.

  • ENQ is always the first command to be sent, it opens a new session receiver side

  • ACK is sent by the receiver to confirm that it successfully received the sender message

  • NAK in the other hand is sent by the receiver to confirm that it did not receive the sender message or data controls failed

  • STX and ETX are always sent together like this “STX<message>ETXlrc”. Sometimes, the word “message” in Concert specifications is used to refer to the entire frame

lrc stands for longitudinal redundancy check. It works like a checksum, it is computed using every bytes from <message> + ETX byte. You can use online websites such as this one if you want to compute lrc value and compare it to the received one you got. Once the message is received, the receiver computes on its side lrc and compare its value to the sent one, if it does not match, an error will be thrown

 This exchange data flow is fully explained below with diagram and tables.

data_exch.png

Constant/variables names

Name

Description

N1

Emitting frame counter. Max value is 3

N2

Session counter. Max value is 3

T0

Current timer, value 0 means no timer

T1

Timer, 500ms for POS, 600ms for cash register

RECEIPT

Receipt status, possible values are OK and NOK

EMIT

Emitting status, possible values are OK, ABORT and NOK

Listening procedure for cash register & POS

State

Event

R0

Standby

R1

Waiting ENQ

R2

Waiting STX

R3

Waiting EOT

Start listening

N1 = 0, N2 = 0

=> R1

T0 = 0

=> R1

Ignored

Ignored

ENQ receipt

Ignored

T0 = T1
N1 = N1 + 1
N2 = N2 + 1

emit ACK

=> R2

Ignored

Ignored

STX<message>ETX receipt and there is no data control error

Ignored

Ignored

T0 = T1
emit ACK

=> R3

Ignored

STX<message>ETX receipt but
lrc is incorrect or
parity error

Ignored

Ignored

If N1 < 3
N1 = N1 + 1
T0 = T1
emit NAK

=> R2


if N1 = 3 and N2 < 3
N1 = 0
emit NAK

=> R1


if N1 = 3 and N2 = 3
emit NAK
RECEIPT = NOK

=> R0

 

Timeout

Ignored

Ignored

Same as [STX/ETX receipt but lrc is incorrect or there is a parity error/R2] above

RECEIPT = OK

=> R0

EOT receipt

Ignored

Ignored

Ignored

RECEIPT = OK

=> R0

Other characters

Ignored

Ignored

Ignored

Ignored

Emitting procedure for cash register

State

Event

E0

Standby

E1

Start emitting

E2

Waiting ACK

E3

Waiting ACK

E4

Waiting Timeout

Start emitting

N1 = 0, N2 = 0

=> E1

T0 = 0
N2 = N2 + 1

=> E2

Ignored

 

Ignored

ACK receipt

Ignored

Ignored

T0 = 0
N1 = N1 + 1
emit STX<data>ETXlrc

=> E3

 

Ignored

ENQ receipt

Ignored

Ignored

emit EOT
EMIT = ABORT

=> E0

 

Same as [NAK receipt or other characters or parity error/E3] below

EMIT = ABORT
N1 = N2
T0 = T1
emit ACK

=> R2

NAK receipt or other characters or parity error

Ignored

Ignored

If N2 < 3
T0 = 0
emit EOT

=> E4


if N2 = 3
emit EOT
EMIT = NOK

=> E0

If N1 < 3
N1 = N1 + 1
T0 = T1
emit STX<data>ETXlrc

=> E3


if N1 = 3 and N2 < 3
N1 = 0
emit EOT

=> E4


if N1 = 3 and N2 = 3
emit EOT
EMIT = NOK

=> E0

Ignored

Timeout

Ignored

Ignored

Same as [NAK receipt or other characters or parity error/E2] above

Same as [NAK receipt or other characters or parity error/E3] above

=> E1

Developer implementation notes

Unlike Ethernet/WIFI, USB/RS232 connection does not allow any multithreading processus. Do not start any new request if there is already one in running, it will lead to errors for both of them.

Parity and LRC controls on STX<message>ETXlrc receipt can be performed both in the same time because they only concern one frame and the same data. As a reminder, parity control is only done on ASCII-7 data bytes (no command byte) and LRC is computed from all ASCII-7 data bytes + ETX byte. This is a code snippet (kotlin) which performs both controls:

fun isParityBitOrLrcOk(frame: List<Byte>, lrc: Byte? = null): Boolean {
    var isParityAndLrcOk = false
    var computedLrc: Byte = 0x0
    // frame only contains ASCII-7 data bytes
    for (byte in frame) {
        val oneBitsCount = byte.countOneBits()
        // oneBitsCount is odd, there is a parity error
        if (oneBitsCount % 2 != 0) {
            return isParityAndLrcOk 
        }
        // LRC Computation
        if (lrc != null)
            computedLrc = computedLrc xor byte
    }
    // Frame does not contain ETX command, do a XOR using ETX value manually
    if (lrc != null && frame.last() != 0x03.toByte())
        computedLrc = computedLrc xor 0x03
    // Compare incoming LRC to the computed one
    return lrc == null || computedLrc == lrc
}

Same thing has to be done during the message building when cash register wants to send a message to the POS. This is a code snippet (kotlin) which builds the data to be sent with parity and lrc computation:

fun buildChunksForEmit(dataToSend: String): String {
    val commandStringBuilder = StringBuilder()
    var computedLrc: Byte = 0x0
    commandStringBuilder.append("02") // STX
    for (char in dataToSend) {
        val binaryRepresentation = char.code.toByte()
        val oneBitsCount = binaryRepresentation.countOneBits()
        val isOdd = oneBitsCount % 2 != 0
        val binaryRepresentationWithParity = 
            if (isParityCheckEnabled && isOdd) it.raiseBit(8)
            else it
        computedLrc = computedLrc xor binaryRepresentationWithParity 
        commandStringBuilder.append(
            binaryRepresentationWithParity
                .toUByte()
                .toInt()
                .toString(16)
        )    
    }
    // padStart ensure LRC hex representation length will always be 2
    val lrcAsString =
        (computedLrc xor 0x03)
            .toUByte()
            .toInt()
            .toString(16)
            .padStart(2, '0')
    val etxAndLrc = "03$lrcAsString" // ETX + LRC
    commandStringBuilder.append(etxAndLrc)
    return commandStringBuilder.toString()
}

If you want to use the code snippet above, please be careful, it builds a hex representation of the string, so each byte will become two chars. It is helpful for debugging/logs but make sure when you are sending this hex string that you convert each two chars couples in one byte before.

“02” => 0x00 + 0x02

(error)

“02” => 0x02

(tick)

  • No labels