Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

re-directing stdio to embedded serial ports

109 views
Skip to first unread message

Bernie Mentink

unread,
Sep 24, 1996, 3:00:00 AM9/24/96
to

Hi all,

I am writing embedded code in GCC but do not know how to
re-direct the serial IO routines to the hardware serial port.

I have written code to send\receive chars to the port. How do
I get the standard C functions that use stdin/stdout i.e
GetChar() PutChar() printf() etc, to use them.

Many thanks for all the helpful replies.

Bernie.

--

____________________________________________________

Bernie Mentink email:men...@wronz.org.nz
fax:64-3-325-2717
Wool Research of New Zealand.
Lincoln,Christchurch,N.Z
>>>> PROMISE KEEPERS 1996 .. MEN of INTEGRITY! <<<<
____________________________________________________

Ralph Silverman

unread,
Sep 24, 1996, 3:00:00 AM9/24/96
to

Bernie Mentink (men...@wronz.org.nz) wrote:
: Hi all,

: Bernie.

: --

: ____________________________________________________

--
****************begin r.s. response**********************

best to go lower level...
look into;
read()
write()
.

****************end r.s. response************************
Ralph Silverman
z007...@bcfreenet.seflin.lib.fl.us


Jan Hyla

unread,
Sep 24, 1996, 3:00:00 AM9/24/96
to

In message <5297pv$h...@nntp.seflin.lib.fl.us>
z007...@bcfreenet.seflin.lib.fl.us (Ralph Silverman) writes:

> : Bernie.

> : --

> : ____________________________________________________

> --
> ****************begin r.s. response**********************

If this is for the SH (I am assuming this, having seen your previous
email) then somewhere in your dev system (Is it Cygnus?) there will
be a file called syscalls.c prototyping the required low level
functions that functions such as printf() will call e.g. write ().
These low level functions for the SH go through a trap handler (no
34). You will need to
implement a trap handler which then calls your low(er) level stuff.

e.g.(working example)

#include <sys/syscall.h>

#pragma interrupt
int trap_34_handler (int sys_fn, int param_0, int param_1, int param_2)

{
int file;
unsigned char *ptr;
int len;

if (sys_fn == SYS_write) {
file = param_0;
ptr = (unsigned char *) param_1;
len = param_2;
if (len) {
while (len--) {
writechar (*ptr++); /* Your low level routine */
}
return param_2;
}
}
return 0;
}


Enjoy. Let me know how you get on.
Jan Hyla, Bolton, UK (Jan....@zetnet.co.uk)
'Don't let me hear you say life's taking you nowhere Angel.'



Bill O. Gallmeister

unread,
Sep 25, 1996, 3:00:00 AM9/25/96
to

Good God. I don't know anything about the target your writing for,
but, assuming stdin, stdout, and stderr are macros for FILE * buffer
wrappers (like in most UNIX systems, and in fact any system I can
think of offhand), then wouldn't it be easier to close the underlying
FILE * by hand and reopen it as the file you want? All you would need
is a small magic initialization function. stdio implementations are
NOT generally that tough. Make sure to do the necessary setbuf()s.
That's an ANSI call as well, I believe.

For instance, is "stderr" is #defined as "&_iobuf[2]" in stdio.h, just
look up the definition of the iobuf structure. Find the FILE * or the
file descriptor. Close or fclose it. Open or fopen the redirected
location. dup2() the redirected descriptor if necessary. Whack it into
the iobuf structure.

Or, if you're running LynxOS, you do "app >& /dev/whatever"...

---
Bill O. Gallmeister Email: b...@fvc.com
First Virtual Corporation Direct: (408) 567-7238
Main: (408) 567-7200 Fax: (408) 988-7077

Bill O. Gallmeister

unread,
Sep 25, 1996, 3:00:00 AM9/25/96
to gnu-gcc-...@rutgers.edu

Michael Meissner

unread,
Sep 26, 1996, 3:00:00 AM9/26/96
to

Bernie Mentink (men...@wronz.org.nz) wrote:
| Hi all,
|
| I am writing embedded code in GCC but do not know how to
| re-direct the serial IO routines to the hardware serial port.
|
| I have written code to send\receive chars to the port. How do
| I get the standard C functions that use stdin/stdout i.e
| GetChar() PutChar() printf() etc, to use them.
|
| Many thanks for all the helpful replies.

If you are using newlib (either from the public release or from a Cygnus
distribution), you replace the following stubs. The libgloss directory
contains some of the stubs we've written for different boards.

File: libc.info, Node: Stubs, Next: Reentrant Syscalls, Up: Syscalls

Definitions for OS interface
============================

This is the complete set of system definitions (primarily
subroutines) required; the examples shown implement the minimal
functionality required to allow `libc' to link, and fail gracefully
where OS services are not available.

Graceful failure is permitted by returning an error code. A minor
complication arises here: the C library must be compatible with
development environments that supply fully functional versions of these
subroutines. Such environments usually return error codes in a global
`errno'. However, the Cygnus C library provides a *macro* definition
for `errno' in the header file `errno.h', as part of its support for
reentrant routines (*note Reentrancy: Reentrancy.).

The bridge between these two interpretations of `errno' is
straightforward: the C library routines with OS interface calls capture
the `errno' values returned globally, and record them in the
appropriate field of the reentrancy structure (so that you can query
them using the `errno' macro from `errno.h').

This mechanism becomes visible when you write stub routines for OS
interfaces. You must include `errno.h', then disable the macro, like
this:

#include <errno.h>
#undef errno
extern int errno;

The examples in this chapter include this treatment of `errno'.

`_exit'
Exit a program without cleaning up files. If your system doesn't
provide this, it is best to avoid linking with subroutines that
require it (`exit', `system').

`close'
Close a file. Minimal implementation:

int close(int file){
return -1;
}

`environ'
A pointer to a list of environment variables and their values.
For a minimal environment, this empty list is adequate:

char *__env[1] = { 0 };
char **environ = __env;

`execve'
Transfer control to a new process. Minimal implementation (for a
system without processes):

#include <errno.h>
#undef errno
extern int errno;
int execve(char *name, char **argv, char **env){
errno=ENOMEM;
return -1;
}

`fork'
Create a new process. Minimal implementation (for a system
without processes):

#include <errno.h>
#undef errno
extern int errno;
int fork() {
errno=EAGAIN;
return -1;
}

`fstat'
Status of an open file. For consistency with other minimal
implementations in these examples, all files are regarded as
character special devices. The `sys/stat.h' header file required
is distributed in the `include' subdirectory for this C library.

#include <sys/stat.h>
int fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}

`getpid'
Process-ID; this is sometimes used to generate strings unlikely to
conflict with other processes. Minimal implementation, for a
system without processes:

int getpid() {
return 1;
}

`isatty'
Query whether output stream is a terminal. For consistency with
the other minimal implementations, which only support output to
`stdout', this minimal implementation is suggested:

int isatty(int file){
return 1;
}

`kill'
Send a signal. Minimal implementation:

#include <errno.h>
#undef errno
extern int errno;
int kill(int pid, int sig){
errno=EINVAL;
return(-1);
}

`link'
Establish a new name for an existing file. Minimal implementation:

#include <errno.h>
#undef errno
extern int errno;
int link(char *old, char *new){
errno=EMLINK;
return -1;
}

`lseek'
Set position in a file. Minimal implementation:

int lseek(int file, int ptr, int dir){
return 0;
}

`read'
Read from a file. Minimal implementation:

int read(int file, char *ptr, int len){
return 0;
}

`sbrk'
Increase program data space. As `malloc' and related functions
depend on this, it is useful to have a working implementation. The
following suffices for a standalone system; it exploits the symbol
`end' automatically defined by the GNU linker.

caddr_t sbrk(int incr){
extern char end; /* Defined by the linker */
static char *heap_end;
char *prev_heap_end;

if (heap_end == 0) {
heap_end = &end;
}
prev_heap_end = heap_end;
heap_end += incr;
return (caddr_t) prev_heap_end;
}

`stat'
Status of a file (by name). Minimal implementation:

int stat(char *file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}

`times'
Timing information for current process. Minimal implementation:

int times(struct tms *buf){
return -1;
}

`unlink'
Remove a file's directory entry. Minimal implementation:

#include <errno.h>
#undef errno
extern int errno;
int unlink(char *name){
errno=ENOENT;
return -1;
}

`wait'
Wait for a child process. Minimal implementation:
#include <errno.h>
#undef errno
extern int errno;
int wait(int *status) {
errno=ECHILD;
return -1;
}

`write'
Write a character to a file. `libc' subroutines will use this
system routine for output to all files, *including* `stdout'--so
if you need to generate any output, for example to a serial port
for debugging, you should make your minimal `write' capable of
doing this. The following minimal implementation is an incomplete
example; it relies on a `writechar' subroutine (not shown;
typically, you must write this in assembler from examples provided
by your hardware manufacturer) to actually perform the output.

int write(int file, char *ptr, int len){
int todo;

for (todo = 0; todo < len; todo++) {
writechar(*ptr++);
}
return len;
}

If newlib has been compiled for use with reentrant calls, you need to replace
the following:

File: libc.info, Node: Reentrant Syscalls, Prev: Stubs, Up: Syscalls

Reentrant covers for OS subroutines
===================================

Since the system subroutines are used by other library routines that
require reentrancy, `libc.a' provides cover routines (for example, the
reentrant version of `fork' is `_fork_r'). These cover routines are
consistent with the other reentrant subroutines in this library, and
achieve reentrancy by using a reserved global data block (*note
Reentrancy: Reentrancy.).

`_open_r'
A reentrant version of `open'. It takes a pointer to the global
data block, which holds `errno'.

int _open_r(void *REENT,
const char *FILE, int FLAGS, int MODE);

`_close_r'
A reentrant version of `close'. It takes a pointer to the global
data block, which holds `errno'.

int _close_r(void *REENT, int FD);

`_lseek_r'
A reentrant version of `lseek'. It takes a pointer to the global
data block, which holds `errno'.

off_t _lseek_r(void *REENT,
int FD, off_t POS, int WHENCE);

`_read_r'
A reentrant version of `read'. It takes a pointer to the global
data block, which holds `errno'.

long _read_r(void *REENT,
int FD, void *BUF, size_t CNT);

`_write_r'
A reentrant version of `write'. It takes a pointer to the global
data block, which holds `errno'.

long _write_r(void *REENT,
int FD, const void *BUF, size_t CNT);

`_fork_r'
A reentrant version of `fork'. It takes a pointer to the global
data block, which holds `errno'.

int _fork_r(void *REENT);

`_wait_r'
A reentrant version of `wait'. It takes a pointer to the global
data block, which holds `errno'.

int _wait_r(void *REENT, int *STATUS);

`_stat_r'
A reentrant version of `stat'. It takes a pointer to the global
data block, which holds `errno'.

int _stat_r(void *REENT,
const char *FILE, struct stat *PSTAT);

`_fstat_r'
A reentrant version of `fstat'. It takes a pointer to the global
data block, which holds `errno'.

int _fstat_r(void *REENT,
int FD, struct stat *PSTAT);

`_link_r'
A reentrant version of `link'. It takes a pointer to the global
data block, which holds `errno'.

int _link_r(void *REENT,
const char *OLD, const char *NEW);

`_unlink_r'
A reentrant version of `unlink'. It takes a pointer to the global
data block, which holds `errno'.

int _unlink_r(void *REENT, const char *FILE);

`_sbrk_r'
A reentrant version of `sbrk'. It takes a pointer to the global
data block, which holds `errno'.

char *_sbrk_r(void *REENT, size_t INCR);

--
Michael Meissner, Cygnus Support (East Coast)
4th floor, 955 Massachusetts Avenue, Cambridge, MA 02139, USA
meis...@cygnus.com, 617-354-5416 (office), 617-354-7161 (fax)

Michael Meissner

unread,
Sep 26, 1996, 3:00:00 AM9/26/96
to gnu-gcc-...@rutgers.edu

Craig Franck

unread,
Sep 28, 1996, 3:00:00 AM9/28/96
to

"Bill O. Gallmeister" <b...@fvc.com> wrote:
>Good God. I don't know anything about the target your writing for,
>but, assuming stdin, stdout, and stderr are macros for FILE * buffer
>wrappers (like in most UNIX systems, and in fact any system I can
>think of offhand), then wouldn't it be easier to close the underlying
>FILE * by hand and reopen it as the file you want? All you would need
>is a small magic initialization function. stdio implementations are
>NOT generally that tough. Make sure to do the necessary setbuf()s.
>That's an ANSI call as well, I believe.
>
>For instance, is "stderr" is #defined as "&_iobuf[2]" in stdio.h, just
>look up the definition of the iobuf structure. Find the FILE * or the
>file descriptor. Close or fclose it. Open or fopen the redirected
>location. dup2() the redirected descriptor if necessary. Whack it into
>the iobuf structure.

That is an interesting thought. My stderr is defined as (&_streams[2]).
If you use what is defined for stderr that can not be ANSI C, because
it could be whatever name the implementator came up with.

Also, Plauger in "The Standard C Library" page 252 admonishes not to
mess around with a FILE pointer. "Don't try to peek inside the data
object it points to, not even if a particular implementation provides
a declaration of FILE within <stdio.h>". Also "the address returned
by fopen may be magic". I thought that you should use the functions
defined in the standard, and "whackin'" things into the structure
defined by the FILE declaration was not a good idea.

--
Craig
clfr...@worldnet.att.net
Manchester, NH
"What Java revolution?" -- Bjarne Stroustrup

Bernie Mentink

unread,
Sep 29, 1996, 3:00:00 AM9/29/96
to Jan Hyla

Jan Hyla wrote:
>
> #pragma interrupt
> int trap_34_handler (int sys_fn, int param_0, int param_1, int param_2)
>
> {
> int file;
> unsigned char *ptr;
> int len;
>
> if (sys_fn == SYS_write) {
> file = param_0;
> ptr = (unsigned char *) param_1;
> len = param_2;
> if (len) {
> while (len--) {
> writechar (*ptr++); /* Your low level routine */
> }
> return param_2;
> }
> }
> return 0;
> }
>
>
> Enjoy. Let me know how you get on.
> Jan Hyla, Bolton, UK (Jan....@zetnet.co.uk)
> 'Don't let me hear you say life's taking you nowhere Angel.'
>
>

Hi Jan,

Thanks for your reply.
Yes, I am programming for the SH1
The 'write()' routine in syscalls.c is :-

-------------------------------------------------
int
_write ( int file,
char *ptr,
int len)
{
return __trap34 (SYS_write, file, ptr, len);
}
------------------------------------------------

Please explain how traps work?, I have yet to use
soft interrupts.

Why do the low level functions use trap34, or any trap for
that matter?

Do I need to change the name of your routine to:-
_trap34(int sys_fn, int param_0,int param_1,int param_2)

What return value does read() & write() have to return to the
higher level functions.

Do I have to provide a vector to the handler?


Forgive the questions ... steep leaning curve.

Regards,

Bernie Mentink

unread,
Sep 30, 1996, 3:00:00 AM9/30/96
to Jan Hyla

Jochen Klein

unread,
Sep 30, 1996, 3:00:00 AM9/30/96
to

Craig Franck wrote:
>
> Also, Plauger in "The Standard C Library" page 252 admonishes not to
> mess around with a FILE pointer. "Don't try to peek inside the data
> object it points to, not even if a particular implementation provides
> a declaration of FILE within <stdio.h>". Also "the address returned
> by fopen may be magic". I thought that you should use the functions
> defined in the standard, and "whackin'" things into the structure
> defined by the FILE declaration was not a good idea.
>
You might want to take a look at:

FILE *freopen (Path, Type, Stream)
char *Path, *Type;
FILE *Stream;

The freopen subroutine substitutes the named file in place of the open
stream.
The original stream is closed regardless of whether the openx subroutine
succeeds. The freopen subroutine returns a pointer to the FILE structure
associated with Stream. The freopen subroutine is typically used to
attach
the pre-opened streams associated with standard input (stdin), standard
output (stdout), and the stderr file to other files.

Jochen
--
Dipl.-Inform. Jochen Klein | IBM European Networking Center
VNET: HEIDELBG(KLEIN) | Systems and Network Management
Tel: +49-6221-59-4534 | Vangerowstr. 18
Fax: +49-6221-59-3300 | D-69155 Heidelberg

0 new messages