Skip to content

Fixed IAR serial fgets fgetc #770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 9, 2014
Merged

Fixed IAR serial fgets fgetc #770

merged 2 commits into from
Dec 9, 2014

Conversation

GustavWi
Copy link
Contributor

@GustavWi GustavWi commented Dec 8, 2014

IAR's Dlib has some problems with unbuffered stream, however I found a workaround. setvbuf with these params generate a buffer with size 1.

  •    _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/\* Unset read mode */
    
    Is to remove read mode from _file after read because writes will otherwise be blocked.
  •    _file->_Rend = _file->_Wend;
    
  •    _file->_Next = _file->_Wend;
    
    If this is not set the last char from fgets will be rewritten next time (saved in buffer). So for instance if you send a \n to end a string sequence it would be a double new line. The other new line would be written as start of the next string.

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2014

I have a question if this workaround should not be placed somewhere else.. The toolchain specific things are currently in the retarget code file.

@GustavWi
Copy link
Contributor Author

GustavWi commented Dec 9, 2014

Hi I think this is what you meant, if the name of the functions is inappropriate you can change them later.
//Gustav

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2014

What problems are there with unbuffered streams? It might be beneficial for users, to have this as part of the commit, also the description provided above. For the next time ;) Or want to rebase?

@GustavWi
Copy link
Contributor Author

GustavWi commented Dec 9, 2014

setbuf(_file, NULL), and std::setvbuf(_file,NULL,_IONBF,NULL) should both give an unbuffered stream (the data is directly written to the input buffer). IAR sets a buffer anyway of size 512 bytes for these calls. Calling setvbuff(_file,buf,_IONBF,NULL) with a buffer that is not a NULL pointer sets the buffer to size one. Which means that as soon as a char is read it is written to the real buffer. If people are interested in looking at this further they can look at the files under ARM/src/dlib: fgets.c, fflush.c, xfrpep.c and xfwprep.c

@0xc0170
Copy link
Contributor

0xc0170 commented Dec 9, 2014

Thanks for an explanation. Please provide it in the commit next time. I'll attach it to the merge commit

0xc0170 added a commit that referenced this pull request Dec 9, 2014
Fix IAR serial fgets fgetc

Taken from PR #770:
setbuf(_file, NULL), and std::setvbuf(_file,NULL,_IONBF,NULL) should both give an unbuffered stream (the data is directly written to the input buffer). IAR sets a buffer anyway of size 512 bytes for these calls. Calling setvbuff(_file,buf,_IONBF,NULL) with a buffer that is not a NULL pointer sets the buffer to size one. Which means that as soon as a char is read it is written to the real buffer. If people are interested in looking at this further they can look at the files under ARM/src/dlib: fgets.c, fflush.c, xfrpep.c and xfwprep.c
@0xc0170 0xc0170 merged commit ea49132 into ARMmbed:master Dec 9, 2014
@kjbracey kjbracey mentioned this pull request Jan 30, 2018
@TTornblom
Copy link
Contributor

According to the standard, a BUFSIZ sized buffer should be allocated even if setbuf is called with a NULL buffer. The fourth argument to setvbuf is also a size_t, so using a NULL there is semantically incorrect.

setvbuf(fp, NULL, _IONBF, 0) will result in a size 1 buffer being used with IAR 8.20.2. I have not checked any older releases.

See:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/setbuf.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/setvbuf.html

@kjbracey
Copy link
Contributor

kjbracey commented Feb 8, 2018

That POSIX standard reads a bit weird, suggesting the size parameter is somehow significant if mode if _IONBF. The C standard is clearer, just saying

Except that it returns no value, the setbuf function is equivalent to the setvbuf
function invoked with the values _IOFBF for mode and BUFSIZ for size, or (if buf
is a null pointer), with the value _IONBF for mode.

Note size not being specified in the latter case, as it shouldn't matter.

So is the issue is that IAR allocates a size-byte buffer that it doesn't use/need because mode is _IONBF, or that it does actually perform buffering when mode is _IONBF and a size was given?

@kjbracey
Copy link
Contributor

kjbracey commented Feb 8, 2018

On top of this - do we need to be manually calling setbuf anyway? The call was there in Stream as a workaround for libraries not checking whether a file is a terminal or not (also Stream not saying that it is a terminal).

Does DLIB have a mechanism for us to tell it that an __opened file is a tty or not, so it can default buffering correctly? I can't see it.

C library retargeting often has such a mechanism alongside open/read/write as the C standard does require that behaviour:

As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

When opened, a stream is fully buffered if and only if it can be determined not to refer to
an interactive device.

@TTornblom
Copy link
Contributor

I don't see any mechanism similar to isatty() in Dlib, but will investigate it further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants