serial data truncated by termios on embedded device - c

I am working on a C program listening to the serial port running on an ARM Linux embedded device.
Other sets of data work fine, but always when I send a particular set of data, the beginning of the set is truncated. What is truncated is the following (slsniff program output running on the target):
Device --> ^ (094) { (123) <STX> (002) <BS> (008) <STX> (002) <NUL> (000) <NUL> (000) <STX> (002) <SOH> (001) <ETX> (003)
I have debugged enough to be fairly certain this is caused by some termios constant, which is using the end of text ETX to truncate.
Right now I am down to:
struct termios t;
t.c_lflag &= ~(ICANON | IEXTEN | ECHO);
t.c_iflag &= ~ICRNL;
t.c_cc[VMIN] = 1; /* Character-at-a-time input */
t.c_cc[VTIME] = 0; /* with blocking */
The set separator character is a CR 0x0d, that seems to work fine in all cases.
Any help greatly appreciated.
Best regards,
Bert

Answer was:
cfmakeraw as explained at http://linux.die.net/man/3/termios

Related

STM32 bare metal USB implementation

UPDATE
For anyone interested, here is a step-by-step instruction and explanation on how to build a bare metal USB-Stack, how to tackle such a project and what you need to know for each step: STM32USB#GitHub
TLDR:
I have a STM32G441 and want to implement a USB driver without the use of any HAL Libraries, just using CMSIS - for learning experience, for space and because what I want to do would require to change the hal anyway.
But I can't get this thing to receive anything. I'm stuck trying to get the Device Address, which is never handed to the code. The hal middleware works just fine, so it's not a HW issue.
What I'm doing
I'm enabling the USB clock (correctly as I assume, because it can send ACK signals using my Logic Analyzer), power up the USB peripheral as defined in the datasheet, enable all the necessary Interrupts and handle the reset event by initializing the BTable and Endpoint 0. Now I expect to receive a CTR-Interrupt which never appears.
Reference Manual
Clock
The μC runs on a 25MHz HSE clock. The USB periphery runs on the PLL Q clock at ~48MHz, RCC settings were verified with the CubeMX clock configurator. AHB runs at half speed, because I get a bus error hard fault if I try to run it at full speed, but that's another question. The System Clock is set to 143.75MHz.
RCC->CR |= RCC_CR_HSEON | RCC_CR_HSION;
// Configure PLL (R=143.75, Q=47.92)
RCC->CR &= ~RCC_CR_PLLON;
while (RCC->CR & RCC_CR_PLLRDY) {
}
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE | RCC_PLLCFGR_PLLM_0 | (23 << RCC_PLLCFGR_PLLN_Pos) | RCC_PLLCFGR_PLLQ_1;
RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLQEN;
RCC->CR |= RCC_CR_PLLON;
// Select PLL as main clock, AHB/2 > otherwise Bus Error Hard Fault
RCC->CFGR |= RCC_CFGR_HPRE_3 | RCC_CFGR_SW_PLL;
// Select & Enable IO Clocks (PLL > USB, ADC; HSI16 > UART)
RCC->CCIPR = RCC_CCIPR_CLK48SEL_0 | RCC_CCIPR_ADC12SEL_1 | RCC_CCIPR_USART1SEL_1 | RCC_CCIPR_USART2SEL_1 | RCC_CCIPR_USART3SEL_1 | RCC_CCIPR_UART4SEL_1;
RCC->AHB2ENR |= RCC_AHB2ENR_ADC12EN | RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN | RCC_AHB2ENR_GPIOCEN;
RCC->APB1ENR1 |= RCC_APB1ENR1_USBEN | RCC_APB1ENR1_UART4EN | RCC_APB1ENR1_USART3EN | RCC_APB1ENR1_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// Enable DMAMUX & DMA1 Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMAMUX1EN | RCC_AHB1ENR_DMA1EN;
USB Memory
As far as I know, the USB BTable and endpoint buffers need to be placed in the USB-SRAM, not in regular SRAM. I've added some linker directives to create a section for that, which seems to work just fine according to the memory analyzer. Mem2Usb just recalculates the offset from absolute to relative to the USB-SRAM offset.
#define __USB_MEM __attribute__((section(".usbbuf")))
#define __USBBUF_BEGIN 0x40006000
#define __MEM2USB(X) (((int)X - __USBBUF_BEGIN))
First question: The access is only allowed to be 16 Bytes wide. But, contrary to e.g. STM32F103 there is no need for padding as it seems. The memory tool has some problems displaying this region, because it is only handling WORD access while the tool uses DWORD access, but copying the memory allocated by the HAL word by word also shows no padding. Is that correct? So I should be able to use all 1024 bytes, not just seeing them but only having 512. This is also the reason why mem2usb does not divide the address by 2.
Then I create some structures for the BTable and the zero-endpoint. The BTable ends up at 0x40006000 by default. Endpoint 0 has a rx and a tx buffer with max 64 bytes as per USB spec. The alignments are taken from the Reference manual. The memory is not automatically zeroed out.
typedef struct {
unsigned short ADDR_TX;
unsigned short COUNT_TX;
unsigned short ADDR_RX;
unsigned short COUNT_RX;
} USB_BTABLE_ENTRY;
__ALIGNED(8)
__USB_MEM
static USB_BTABLE_ENTRY BTable[8] = {0};
__ALIGNED(2)
__USB_MEM
static char EP0_Buf[2][64] = {0};
Initialization
Enabling the NVIC, then power up, wait 1μs until clock is stable as per datasheet, then clear reset state, clear pending interrupts, enable interrupts and last enable the internal pull up to start enumeration.
NVIC_SetPriority(USB_HP_IRQn, 0);
NVIC_SetPriority(USB_LP_IRQn, 0);
NVIC_SetPriority(USBWakeUp_IRQn, 0);
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
USB->CNTR &= ~USB_CNTR_PDWN;
// Wait 1μs until clock is stable
SysTick->LOAD = 100;
SysTick->VAL = 0;
SysTick->CTRL = 1;
while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0) {
}
SysTick->CTRL = 0;
USB->CNTR &= ~USB_CNTR_FRES;
USB->ISTR = 0;
USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_WKUPM | USB_CNTR_SUSPM | USB_CNTR_ESOFM;
USB->BCDR |= USB_BCDR_DPPU;
USB Reset
Now the host sends a reset signal, which is triggered correctly. During the reset signal, I initialize the BTable and EP0. I set EP0 to ACK on RX and NACK on TX requests, as do other bare metal USB examples and the HAL (they are toggle, not write, but the register is in a known state of 0x00 as the hardware resets them on a reset). Lastly I put the USB peripheral in enable mode and reset the device address to 0.
if ((USB->ISTR & USB_ISTR_RESET) != 0) {
USB->ISTR = ~USB_ISTR_RESET;
// Enable EP0
USB->BTABLE = __MEM2USB(BTable);
BTable[0].ADDR_TX = __MEM2USB(EP0_Buf[0]);
BTable[0].COUNT_TX = 0;
BTable[0].ADDR_RX = __MEM2USB(EP0_Buf[1]);
BTable[0].COUNT_RX = (1 << 15) | (1 << 10);
USB->EP0R = USB_EP_CONTROL | (2 << 4) | (3 << 12);
USB->CNTR = USB_CNTR_CTRM | USB_CNTR_RESETM;
USB->DADDR = USB_DADDR_EF;
}
Debugging shows that the BTable is indeed at 0x40006000 and the Buffer address is written (I assume) correctly. The EP0 register was compared to a working HAL implementation and they are the same at that point.
Here I'm stuck
I expect the host to send the device address next (it doesn't, it sends a sleep and a wakeup and then another reset first), which will trigger the CRT interrupt (which is masked). Point is, it never does. And I don't know why. The host sends the request just fine and the device sends an ACK on that request just fine (logic analyzer), but the CRT is never triggered. Any ideas what else I can try or where to look?
Update
I've now compared the messages from my implementation with the HAL ones. The interrupt now handles the exact same messages in the exact same order and the USB-Registers also contain exactly the same values for every request. I've changed the BTable and USB-SRAM layout to contain the exact same values as the HAL after the Reset-Interrupt.
I had to implement the SUSP and WKUP for this to work, which was probably one of the things thats missing. Now they both behave exactly the same. It turns out, the problem is that I never receive a proper SOF-Package. The HAL gets its first SOF directly after the second reset (HW-Reset > 2x ESOF > SUSP > WKUP > RESET > (Optional 1 ESOF) > SOF), while mine gets an ERR instead of the SOF.
Looks like the error is not related to the USB registers or USB-SRAM. Next step will be to compare all registers I can think of as relevant between the two implementations. Maybe I forgot a clock?
Spend almost a week. Just to figure out I misconfigured my 48MHz clock source...
RCC->CCIPR = RCC_CCIPR_CLK48SEL_0 | ...
This sets the CLK48SEL to Reserved (01), not the PLLQ-Clock (10)...
RCC->CCIPR = RCC_CCIPR_CLK48SEL_1 | ...
Now I get the SOF packages and the CTR alright. May that question serve as a USB bare metal reference in the future.

MAX77651 Can't read register with i2c

I am trying to test the i2c communication of the MAX77651 chip before programming it.
So here is my setup to do so:
I have an UMFT4222ev connected to my Linux laptop by USB. This chip has his SCL and SDA linked to the SDA and SCL of my MAX77651 thanks to the Evaluation Kit for the MAX77651. My MAX77651evkit is powered with 3,7V on the Vbatt pin.
I also installed the mraa librarie from git hub and the libft4222. I know mraa is well installed because i tried it with and example.
I was told that the mraa library takes in charge the setup of the FT4222 so i only used mraa functions to make my program.
I searched on the website of Maxim integrated the i2c slave address and one register where i could read data and check if everyting is working. I then read the i2c protocol of communication to read a single register which is available here : https://datasheets.maximintegrated.com/en/ds/MAX77650-MAX77651.pdf at the page 78.
With all those informations I tried to make my "test program". I solved the compiling errors but when I execute the program I can't get what is in the register which should be 0xFF.
Here is my program:
#include "stdio.h"
#include "syslog.h"
#include "string.h"
#include "unistd.h"
#include "mraa/i2c.h"
#include "mraa.h"
#define I2C_ADDR 0x48
int
main(int argc, char *argv[])
{
uint8_t *message;
*message=0XAC;
int i,j,k;
char reg_a_lire = 0x06;
mraa_init();
mraa_i2c_context i2c;
i2c = mraa_i2c_init(0);
mraa_i2c_frequency(i2c,MRAA_I2C_FAST);
mraa_i2c_address(i2c, I2C_ADDR);
mraa_i2c_write_byte(i2c,0x90);
mraa_i2c_read(i2c, message,1);
mraa_i2c_write_byte(i2c,reg_a_lire);
mraa_init();
mraa_i2c_write_byte(i2c,0x91);
mraa_i2c_read(i2c, message,1);
mraa_i2c_read(i2c, message,1);
printf("%02X \n", *message);
mraa_i2c_stop(i2c);
return 0;
}
Here is the actual output :
alex#cyclonit-laptop ~/Test_alex/tests $ ./a.out
AC
And i would like to get FF instead of AC.
I think my error could come from something i missed to initialize the FT4222 or from the MAX77651 which I maybe did nt power up correctly and its not sufficient to put 3,7V on Vbatt. But maybe this is a problem with my program because i don't know much about uint8_t and I made something wrong.
I am hoping someone has experience with FT4222 and/or MAX77651 and can help me.
I think you are confused by pg. 75 of the MAX77651 datasheet.
ADDRESS | 7-BIT SLAVE ADDRESS | 8-BIT WRITE ADDRESS | 8-BIT READ ADDRESS
Main Address | 0x48, 0b 100 1000 | 0x90, 0b 1001 0000 | 0x91, 0b 1001 0001
(ADDR = 1)* | | |
-------------+---------------------+---------------------+-------------------
Main Address | 0x40, 0b 100 0000 | 0x80, 0b 1000 0000 | 0x81, 0b 1000 0001
(ADDR = 0)* | | |
Depending on your view of the I²C specification, you either use the 7-bit address or use both 8-bit addresses. The reason is that the first I²C transaction sends the following 8 bit:
76543210
\_____/\-- R/#W
\------ 7-bit Slave Address
In your case that's 0x48 shifted one bit to the left followed by either a 1 for read mode or a 0 for write mode. Notice that
(0x40 << 1) | 0x00 == 0x80 == 8-bit Write Address (ADDR = 0)
(0x40 << 1) | 0x01 == 0x81 == 8-bit Read Address (ADDR = 0)
(0x48 << 1) | 0x00 == 0x90 == 8-bit Write Address (ADDR = 1)
(0x48 << 1) | 0x01 == 0x91 == 8-bit Read Address (ADDR = 1)
Some people like to use the slave address while other people prefer to give separate addresses so it's clear what the first byte of communication will look like.
So you should remove the extraneous mraa_i2c_write_byte(i2c, ...); lines from your code, as their intention seems to be to send the read or write address to the slave.
Check out the MRAA library API reference. There are functions that abstract reading and writing registers, either byte-wide [8-bit] registers or word-wide [16-bit] registers:
mraa_i2c_read_byte_data
mraa_i2c_read_bytes_data
mraa_i2c_write_byte_data
In both cases you should check the return codes to know if the action succeeded. In your case, your message is likely not altered, because there was a stop/error condition beforehand, because the slave did either not ACK its slave address or it did not ACK the 0x90/0x91 data bytes you mistakenly sent, as they don't show up in the Programmer's Guide as valid addresses.
Another issue is that you try to read register INTM_GLBL (0x06; Global Interrupt Mask Register) using two consecutive read operations. I'm not sure if your intention is to read register 0x06 twice or if you intended to read INT_M_CHG (0x07; Global Interrupt Mask for Charger), because that's not what it will do. Notice the description on pg. 78 of the datasheet:
Note that when the MAX77650/MAX77651 receive a stop
they do not modify their register pointer.
This is typical behavior for I²C slaves that support multi-byte/sequential reads. You will have to issue a sequential read operation for multiple bytes of data if you want to read multiple registers, e.g. using mraa_i2c_read_bytes_data.
Something like the following might get you on the right track. It is supposed to read the CID and CLKS settings and wait forever if a read error occurred. If successful, it will disable charging, all outputs, setup the red LED to blink once every other second and -- as soon as you uncomment it -- transition the On/Off Controller into On Via Software state to enable bias and the LED.
#define MAX77651_SLA 0x48u
#define CNFG_GLBL_REG 0x10u
#define CID_REG 0x11u
#define CNFG_CHG_B_REG 0x19u
#define CNFG_SBB0_B_REG 0x2Au
#define CNFG_SBB1_B_REG 0x2Cu
#define CNFG_SBB2_B_REG 0x2Eu
#define CNFG_LDO_B_REG 0x39u
#define CNFG_LED1_A_REG 0x41u
#define CNFG_LED1_B_REG 0x44u
#define CNFG_LED_TOP_REG 0x46u
int main(int argc, char *argv[]) {
uint8_t data;
int res;
mraa_init();
mraa_i2c_context i2c0;
i2c0 = mraa_i2c_init(0);
mraa_i2c_frequency(i2c0, MRAA_I2C_STD);
mraa_i2c_address(i2c0, MAX77651_SLA);
res = mraa_i2c_read_byte_data(i2c0, CID_REG);
if (res < 0) {
printf("Reading CID_REG failed.\n");
mraa_i2c_stop(i2c0);
while(1);
}
data = res;
printf("CID_REG: CLKS = %02X CID = %02X\n", ((data & 0x70u) >> 4), (data & 0x0Fu));
/* you should check return values here */
mraa_i2c_write_byte_data(i2c0, 0x00u /* CHG_EN = off */, CNFG_CHG_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_LDO = off */, CNFG_LDO_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB0 = off */, CNFG_SBB0_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB1 = off */, CNFG_SBB1_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB2 = off */, CNFG_SBB2_B_REG);
/* set up red led to toggle every second */
mraa_i2c_write_byte_data(i2c0, 0x17u /* P = 1s, D = 50% */, CNFG_LED1_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x98u /* FS = 6.4mA, BRT = 5.0mA */, CNFG_LED1_A_REG);
mraa_i2c_write_byte_data(i2c0, 0x01u /* EN_LED_MSTR = on */, CNFG_LED_TOP_REG);
// DANGER ZONE: enable only when you know what this is supposed to do
//mraa_i2c_write_byte_data(i2c0, 0x10u /* SBIA_EN = on, SBIA_LPM = normal */, CNFG_GLBL_REG);
mraa_i2c_stop(i2c0);
while(1);
}
I managed to read I2C registers of MAX77651.
First looking at the hardware part I had to make sure that VIO had the right voltage like #FRob said in hid comment.
Then for the software, I stopped using the mraa library because i could'nt control everything. I used the FT4222 library which allowed me to open and initiate the FT4222 device. I took some part of the I2C example in this library for the initialization of the device. Then I noticed that I had to first use the FT4222's write function to send the register i wanted to read , then simply use the read function to get my result. Those are the two steps required.
I won't post the whole program i made as it is mainly taken from the I2C example for initialization but here is the part I added to read my register 0X06 which is supposed to contain 0xFF:
uint8 resultat=0x11;
uint8 *p_resultat=&resultat;
int chiffre;
slaveAddr
uint16 bytesToWrite2 = 1;
uint16 bytesWritten2=1;
uint8 valeur= 0x06; // REGISTER TO READ
uint8 *p_valeur=&valeur;
FT4222_I2CMaster_Write(ftHandle,slaveAddr,
p_valeur,bytesToWrite2,&bytesWritten); //INDICATES WHICH REGISTER TO
// READ
chiffre = FT4222_I2CMaster_Read(ftHandle,
slaveAddr,p_resultat,1, &bytesRead); // READ REGISTER
printf("The content of the register %02X is : %02X \n " ,
valeur,resultat); // DISPLAY RESULT
printf("reading success if : %d = 0 \n " , chiffre);
// READING SUCCESS ?
With this code and the initialization i get the following result :
alex#cyclonit-laptop ~/Downloads/libft4222-1.2.1.4/examples $ ./a.out
Device 0 is interface A of mode-0 FT4222H:
0x0403601c FT4222 A
Chip version: 42220200, LibFT4222 version: 01020104
The content of the register 06 is : FF
reading success if : 0 = 0
Skipping interface B of mode-0 FT4222H.
If someone has the same problem you are free to ask me your question by answering this post.I am very thankful to the people here who helped me!

serial port not responding

I wrote a program that communicate with serial port, using termios, this program will read serial port in non-blocking mode and write response to serial port once it read data. If there is no data read from serial port, the program will do other thing, on next loop, the program read serial port again.
now the question is, after sometimes gone, maybe several minutes, or maybe several hours, the serial port don't respond to my program any more. Even I execute echo 'HB\n' > /dev/ttyUSB0(then the serial port should respond 'HACK'), it doesn't respond any more..
I even don't known when the serial port is 'dead', I don't have any clue.. it 'dead' untimed.
here is my configuration:
/// set local mode options
//tminfo.c_lflag |= ICANON;
tminfo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/// set control mode options
tminfo.c_cflag |= (CLOCAL | CREAD);
tminfo.c_cflag |= HUPCL;
// set hardware flow control
tminfo.c_cflag &= ~CRTSCTS;
// set how many bits in a character
tminfo.c_cflag &= ~CSIZE;
tminfo.c_cflag |= CS8;
// set parity mode (default to odd validation), this option (PARENB) will both enable input and output parity checking
tminfo.c_cflag &= ~PARENB; // we don't need prity checking now
/// set input mode options
// set input parity checking
tminfo.c_iflag &= ~INPCK;
tminfo.c_cflag &= ~CSTOPB;
/// set output mode options
tminfo.c_oflag &= ~OPOST;
tminfo.c_cc[VMIN] = 1;
tminfo.c_cc[VTIME] = 1;
/// set line speed, defaults to 38400bps, both for input and output
// this call will set both input and output speed
cfsetspeed(&tminfo, B38400);
It's hard to debug the serial in this situation. I really can't figure out what cause the serial port 'dead' on earth. I'm nearly crazy...
what the possible reason? Any help will be appreciated!
update:
I have wrote some code to the other end of the serial port, when it receive 'HB', it will respond 'HACK'

Default settings for IrDA discovery (baud, bits, stop, parity, flow control, etc)

I'm attempting to write a tool that uses IrDA to communicate with Uwatec dive computers...on a Mac. The USB IrDA device I'm using provides a serial device (/dev/cu.IrDA-IrCOMM0 and /dev/tty.IrDA-IrCOMM0) that can be used to send and receive data. Unfortunately, the Mac does not provide an IrDA socket layer.
I've confirmed using the command line tool that shipped with the device driver that it can listen and receive IrDA communications from other devices. However, while the command line tool tells me it is communicating at 9600 baud, the rest of the settings (bits, stop bit, parity, flow control, etc) are not presented back to me.
I've tried writing my own program to listen to the data, but it is unable to receive any data and I believe the reason is because these settings are not correct. So, assuming that I'm just trying to listen to the 9600 baud IrDA discovery packets that are being sent around, what are the other settings I need to use?
If it helps, here's the snippet of code I'm currently using to set the communication parameters -- which doesn't work:
#define DEVICE "/dev/cu.IrDA-IrCOMM0"
int main(void) {
FILE *device;
struct termios ttystate;
device = fopen(DEVICE, "rw");
//get the terminal state
tcgetattr(fileno(device), &ttystate);
//turn off canonical mode and echo
ttystate.c_lflag &= ~(ICANON | ECHO);
//minimum of number input read.
ttystate.c_cc[VMIN] = 1;
cfsetspeed(&ttystate, B9600); // Set 9600 baud····
ttystate.c_cflag |= (CS8 | // Use 8 bit words
PARENB | // parity enable
PARODD | // odd parity
CCTS_OFLOW | // CTS flow control of output
CRTS_IFLOW);// RTS flow control of input
//set the terminal attributes.
tcsetattr(fileno(device), TCSANOW, &ttystate);
return EXIT_SUCCESS;
}
Below is the IrDA initialization code I used for EXAR XR17C15 on Linux.
Additionally you have to set baudrate as its not set in this example.
I hope this helps.
//
// Set up IrDA hardware interface through UART
bool CeIrDA::SetupIrDA()
{
struct termios termios;
tcgetattr(hComPort, &termios);
cfmakeraw(&termios);
termios.c_iflag = IGNPAR;
termios.c_oflag = 0;
termios.c_cc[VTIME] = 1; // timeout in 0.1s between 2 characters
termios.c_cc[VMIN] = 1; // min # of characters
tcsetattr(hComPort, TCSANOW, &termios);
xrioctl_rw_reg input;
struct timespec delay = {0, 500};
struct timespec delayrem;
//EFR: Allowing Enhanced Functions and RTS/DTR flow control
input.reg=0x09;
input.regvalue=0x50;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//MCR: Flow control RTS enabled
input.reg=0x04;
input.regvalue=0x40;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//MCR: RTS pin high
input.reg=0x04;
input.regvalue=0x00;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//MCR: RTS pin low
input.reg=0x04;
input.regvalue=0x02;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//MCR: Infrared Mode
input.reg=0x04;
input.regvalue=0x42;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//EFR: Allowing Enhanced Functions and RTS/DTR flow control
input.reg=0x09;
input.regvalue=0x40;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//LCR: Allowing changes of DLL and DLM
input.reg=0x03;
input.regvalue=0x80;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//DLL: Speed configuration
input.reg=0x00;
input.regvalue=0x02;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//DLM: Speed configuration
input.reg=0x01;
input.regvalue=0x00;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
//LCR: configuration for parity, word length....
input.reg=0x03;
input.regvalue=0x03;
ioctl(hComPort,WRITE,&input);
nanosleep(&delay, &delayrem);
return true;
}

Reading raw bytes from a serial port

I'm trying to read raw bytes from a serial port sent by a IEC 870-5-101 win32 protocol simulator with a program written in C running on Linux 32bit.
It's working fine for byte values like 0x00 - 0x7F. But for values beginning from 0x80 to 0xAF the high bit is wrong, e.g.:
0x7F -> 0x7F //correct
0x18 -> 0x18 //correct
0x79 -> 0x79 //correct
0x80 -> 0x00 //wrong
0xAF -> 0x2F //wrong
0xFF -> 0x7F //wrong
After digging around for two days now, I have no idea, what's causing this.
This is my config of the serial port:
cfsetispeed(&config, B9600);
cfsetospeed(&config, B9600);
config.c_cflag |= (CLOCAL | CREAD);
config.c_cflag &= ~CSIZE; /* Mask the character size bits */
config.c_cflag |= (PARENB | CS8); /* Parity bit Select 8 data bits */
config.c_cflag &= ~(PARODD | CSTOPB); /* even parity, 1 stop bit */
config.c_cflag |= CRTSCTS; /*enable RTS/CTS flow control - linux only supports rts/cts*/
config.c_iflag &= ~(IXON | IXOFF | IXANY); /*disable software flow control*/
config.c_oflag &= ~OPOST; /* enable raw output */
config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* enable raw input */
config.c_iflag &= ~(INPCK | PARMRK); /* DANGEROUS no parity check*/
config.c_iflag |= ISTRIP; /* strip parity bits */
config.c_iflag |= IGNPAR; /* DANGEROUS ignore parity errors*/
config.c_cc[VTIME] = 1; /*timeout to read a character in tenth of a second*/
I'm reading from the serial port with:
*bytesread = read((int) fd, in_buf, BytesToRead);
Right after this operation "in_buf" contains the wrong byte, so I guess there's something wrong with my config, which is a port from a win32 DCB structure.
Thanks for any ideas!
Based on your examples, only the 8th bit (the high bit) is wrong, and it's wrong by being always 0. You are setting ISTRIP in your line discipline on the Linux side, and that would cause this. ISTRIP does not, as the comment in the C code claims, strip parity bits. It strips the 8th data bit.
If ISTRIP is set, valid input bytes shall first be stripped to seven bits; otherwise, all eight bits shall be processed. IEEE Std 1003.1, 2004 Edition, chapter 11, General Terminal Interface

Resources