## Serial Comm Ports for ever and ever… (Part 7)

Part 12345678

Oh nooooo. I missed that. Eventually, my serial comm port requires parity checking! This unexpetecd requirement forced me to revise the whole concept of bytes and bits reading in order to take into account the time necessary to compute parity and check it.

Here is a little reminder on parity

Parity helps insuring that the data bits received have not been altered during transmission. An extra bit is added next to data bits, which will be checked at arrival and compared to what it would be. The parity may be one of the following options

• ‘N’: none, no parity bit, no checking
• ‘M’: mark, always add a ‘1’ bit
• ‘S’: space, always add a ‘0’ bit
• ‘E’ or ‘O’: even or odd. Means that the number of data bits (1s) AND the parity bit must be an even or an odd number.

Example:
Transmit our good ol’ 0x55 which is: [lsb] 1010101 [msb] in binary. You can count four 1s, the parity of data bits is even. Now, if we decide to transmit in ‘E’ (Remember, even) mode, we do not need to add any other 1 to keep the parity even. So that the parity bit shall be ‘0’ and the data bits combined with the parity bit will look like: [lsb] 10101010 [msb]. If we decide to transmit in ‘O’ (Remember, odd) mode, we DO need an other 1 to make the parity odd. So that the parity bit shall be ‘1’ and the data bits combined with the parity bit will look like: [lsb] 10101011 [msb]

Computing parity is as easy as XORing bits, just like:

`byteParity = b0 ^ b1 ^ … bn;`

Setting the parity bit is also very easy:

```// even mode
parityBitValue = (byteParity & 0x01);
// odd mode
parityBitValue = (~byteParity & 0x01);```

These are the new functions and their overlaods.

The writing functions:

```void writeBytes(byte *ptrData, int bytes, int bytesOffset, long baudRate, int bits, char parity, int stopBits) {
// Write bytes to the Tx line of a custom serial port
int parityBitOffset = 0;
int startBitOffset = 1;
for (int j=0; j < bytes; j++) {
int byteValue = ptrData[bytesOffset+j];
byte bitValue;
int compositeBits = byteValue; // Initialize composite bits with data bits the LSB is 0 as start bit
compositeBits <> i) & 0x01);
}
// Parity bit 'E': Even, 'M': Mark (1), 'N': None, 'O': Odd, 'S': Space (0)
switch (parity) {
case PAR_EVEN:
// Make the whole set of bits even
bitValue = (parityValue & 0x01);
break;
case PAR_MARK:
// Fixed level
bitValue = 0x01;
break;
case PAR_ODD:
// Make the whole set of bits odd
bitValue = (~parityValue & 0x01);
break;
case PAR_SPACE:
// Fixed level
bitValue = 0x00;
break;
}
compositeBits |= (bitValue << (bits + startBitOffset));
parityBitOffset = 1;
}
// Append stop bit(s)
for (int i=0; i < stopBits; i++) {
compositeBits |= (1 << (startBitOffset + bits + parityBitOffset + i));
}
// Transfer bits
long time_interval = long(1000000 / baudRate); // in µs
long time_endOfBit;
long time_startOfByte = micros(); // Set reference time
for (int i=0; i < (startBitOffset + bits + parityBitOffset + stopBits); i++) {
bitValue = ((compositeBits >> i) & 0x01); // Extract bit value
SetLevel(PORTB, TxPin, bitValue); // Set bit on Tx Line
time_endOfBit = time_startOfByte + (time_interval * (i + 1));
while (micros() < time_endOfBit); // Wait until interval time has elapsed
}
}
}

void writeByte(byte byteValue, long baudRate, int bits, char parity, int stopBits) {
// Overlaoded function of writeBytes: Write  one byte to the Tx line of a custom serial port
byte value = byteValue;
writeBytes(&value, 1, 0, baudRate, bits, parity, stopBits);
}

void writeBytes(byte *pdata, int bytes) {
// Write  one or more byte(s) Simplified function
writeBytes(pdata, bytes, 0, def_baudRate, def_bits, def_parity, def_stopBits);
}```

```int readBytes(byte *ptrData, int bytes, int bytesOffset, long baudRate, int bits, char parity, int stopBits, int timeOut, byte *ptrErrorCode) {
// Read one or more incoming bytes
// Timout applies to each incoming byte
// Returns number of received bytes
byte lclErrorCode = ERR_NONE; // Set error code
byte parityBitValue;
int nbrReadBytes = 0; // Number of received bytes (may be # from the expected number of bytes)
int parityBits = 0; // Number of parity bits
if (parity != PAR_NONE)
parityBits = 1;
long time_startOfByte;
long interval = long(1000000 / baudRate); // Calculate sensing time intervals in µs
for (int j=0; j < bytes; j++) {
long abortTime = (millis() + timeOut); // Compute time above which timeout is triggered
while (GetLevel(PINB, RxPin) && (lclErrorCode == ERR_NONE)) { // Loop while logical level is high and no error occured
if (millis() > abortTime){ // Monitor timeout
lclErrorCode = ERR_TIMEOUT;
}
}
time_startOfByte = micros() + (interval >> 1); // now + half interval
if (lclErrorCode == ERR_NONE) {
byte parityValue = 0x00; // ParityValue = 1 if odd, 0 if even
byte stopBitValue = 0x01; // Yes one!
byte byteValue = 0x00; // Reset value
for (int i=0; i < (bits + parityBits + stopBits); i++) { // Read all bits
long time_nextBit = (time_startOfByte + (interval * (i + 1))); // Compute next half bit interval
while (micros() < time_nextBit); // Wait bit interval
byte bitValue = GetLevel(PINB, RxPin); // Sense bit level
if (i < bits) { // Count data bits
byteValue |= (bitValue << i); // Compute byte value (LSBs first)
parityValue ^= bitValue; // Compute parity
}
else if (i < (bits + parityBits)) { // compute parity bit
parityBitValue = bitValue; // Record parity bit value
}
else {
stopBitValue &= bitValue; // Check stop bit(s); one or more 0 set stopBitValue to 0
}
}
ptrData[bytesOffset + nbrReadBytes - 1] = byteValue; // Record byte value in vector of data
// Detect errors
if (stopBitValue != 0x01) {
lclErrorCode = ERR_FRAME;
}
else {
switch (parity) { // Decode parity errors
case PAR_EVEN:
if (parityBitValue != (parityValue & 0x01))
lclErrorCode = ERR_PARITY;
break;
case PAR_MARK:
if (parityBitValue != 0x01)
lclErrorCode = ERR_PARITY;
break;
case PAR_ODD:
if (parityBitValue != (~parityValue & 0x01))
lclErrorCode = ERR_PARITY;
break;
case PAR_SPACE:
if (parityBitValue != 0x00)
lclErrorCode = ERR_PARITY;
break;
}
}
}
}
*ptrErrorCode = lclErrorCode; // Update errorCode value