read() & write() API functions

Do the ‘int read (int fno, void * buf, int size);’ and
‘int write (int fno, const void * buf, int size);’
functions shown in the ApiReference (contained in ind_io.c) use ISRs or polling of the serial ports?

If I am using these functions to write a serial driver, do I need to enable the serial port interrupts and write ISRs, or is that taken care of by these functions?

There is only a single page entry in the ApiReference for each of these functions. Is any more information available?

(I’m using a ConnectCore Wi-9C with an NS9360)

Hi,

I have not used the precise module that you use but I have used NetOS on the ME EM and the 9p modules.

With all of these open() close(), read() and Write() all operate without any ISR work on your part. This is all done by the driver in NetOS.

Use tcgetattr(hPort, &stTermIOs) then change the termios structure follwed by tcsetattr(hPort, &stTermIOs) to configure the port.

open() requires some options, and I find that (O_RDWR | O_NONBLOCK) works for me to give a non blocking read. If you use a blocking read there does not appear to be any way to exit from the read if nothing comes into the port, so when I am waiting for input I read every few ticks unit I get what I want or timeout

Hi,

Thanks for the info about O_NONBLOCK, but I am still having problems. Are you using one thread for the
write() and read() for the serial port, or separate ones? If they are separate, what priority/preemption threshold do you use for each? I’m just trying to write a simple serial driver to send and receive data asynchronously to and from one of the serial ports. I’ve done this with ISRs before, but am not very familiar with using an RTOS.

Hi,

I have used a number of different applications; most simply use a single thread for both read and write. This tends to operate with a write followed by a read with a timeout. I do also have some finctionality where a main thread opens the port and then starts a seperate read thread which is passed the handle to the open port.

With the priorities it should work with the defaults set at NAGetAppDefaultAPIPriority() on both threads provided there are areas where you put waits in with tx_thread_sleep().

Overall to get things going I would simply start with a basic application that initially used the root thread applicationStart() to open the port and go into a loop writing a string and then sleeping for a second before repeating. You should then see the data being output. If you don’t get anything it may well be handshake problems so try disabling via tcsetatt().

Once that is working and you see characters coming out move code to seperate thread and check. Only when that works start on the Rx code

Hi,

I am at a point where I have opened a serial port (using O_RDWR | O_NONBLOCK) from the root thread, and then created a send thread with priority/preemtion threshold ‘2’, and a receive thread with pri/preemption ‘1’, and I have TXD jumpered to RXD. The send thread writes chars from a 100-char buffer which I have initialized from 0 to 99 in groups of 4 everytime I press any key. The receive thread has a while(1) loop which reads 10 chars into a receive buffer, increases the index by the return value of the read(), if it is >= 0, and does a tx_thread_sleep(3). This works well if I initialize the write buffer with values below 17, but if I initialize it as described above, it reads correctly from 0 to 16, but the next char read is 18, and then it does not read any more chars, even though they are being written. I’ve been trying to debug this, but haven’t figured it out. Any ideas? Thanks.

I do not think you mention. Are you using any kind of flow control?

I don’t think flow control is the problem.
I found that I can initialize the send data from ‘0’ to ‘z’ and have no problem, but if I initialize it from 0 to 99, I have a problem when it sends 17 (see code below). Is there something with the API write(), read() functions that would explain this?

for (j=0; j < 100; j++) {

// /* data: 0 to 99 */
// send1_data[j] = (char) j;

      /* data: '0' to 'z' */
   send1_data[j] = (char) (j - j/75*75+48);
}

HI,

The fact that your problem only occurs when you try to send 17, but you can send ‘0’ to ‘z’ indicates to me that you have software flow control enabled (XON/OFF). I am not quite certain but ‘17’ is about the value that is used for either XON or XOFF.

You should be able to sort this out with tcgetattr and tcsetattr. I have not got the detaails to hand at the moment but I think that you need to ensure that the ciflag and coflag fields in termios are set to zero to ensure that XON/OFF is disabled

You are correct, and I had figured this out over the weekend. I just needed to set the termios.c_iflag to 0, and then I was able to send and receive any value. I’m surprised in the API Reference where it gives information on the read() and write() functions, that it does not give any mention of flow control issues. Thanks for the response.

I have now been trying to send a set of 4-char messages from the SerialSend thread, and receive them in the SerialReceive thread. I want the receive to be blocking, so I don’t have to poll it, so I opened the port O_RDWR, instead of O_RDWR | O_NONBLOCK. I also started the SerialReceive thread first, and made both threads have priority/preemption threshold set to 2. But the program calls the read(), then the write(), and then hangs somewhere, without returning from either function. Do you have any ideas on what may be the problem? Thanks.

I have tried to do this sort of thing and I did have some success on older versions of NetOS where I used the O_DMA flag. Then I upgraded to 7.3 and found that the code that uses O_DMA flag was broken. At this point I gave up. From what I found once you call read() with out O_NONBLOCK and then call write() the write will also block until read completes.

The only way I have got read() and write() to work in seperate threads is by having the read() non blocking then using tx_thread_sleep() to delay for a few ticks.

If you do eventually get it to work I would be interested as Polling every few milliseconds does not seem very elegant to me

Thanks for this information. I also have Digi Support looking at it, and I will let you know if there is any resolution. I agree, it is a waste of resources if polling is the only way.

It’s been a while, but I wanted to let you know what I found out from Digi technical support about this:

“In reviewing the serial driver for the ConnectCore Wi-9C (/src/bsp/devices/common/newserial/mecury_serl.c, netos_serlread and netos_serlwrite) I find that there is a Mutex protecting use of the serial port, and if you have blocking enabled on the serial port and you call read, that mutex will be held until data is received regardless if you have data to write to the serial port. Instead of using blocking sockets, you could instead use non-blocking sockets. Alternatively you could only call read when there is data available.”

What I wound up doing after I got the above response, was to use two serial ports, one for send and one for receive, so that I could have a blocking read without blocking the write, and thus avoid polling. Not the most elegant solution either! Thanks again for your input.