5. I/O interface

A callback driven I/O interface is used to read/write serial data in different configurations.

5.1. Struct

The IO interface is a struct that consists of 3 things: a write callback, a read callback, and some user data. The user data is tacked on the end of the read/write callbacks.

<<typedefs>>=
typedef struct txtvm_io txtvm_io;
<<structs>>=
struct txtvm_io {
    int (*read)(int,char*,void*);
    int (*write)(int,char*,void*);
    void *ud;
};

The read callback requests to read a number bytes into a supplied buffer. It returns the number of bytes actually read. A negative value is an error.

The write callback requests to write a number of bytes in a supplied buffer. It returns the number of bytes actually written. A negative value is an error.

5.2. Initialize

Initialize the IO with txtvm_io_init. This will make it do nothing.

<<funcdefs>>=
void txtvm_io_init(txtvm_io *io);
<<funcs>>=
void txtvm_io_init(txtvm_io *io)
{
    io->read = NULL;
    io->write = NULL;
    io->ud = NULL;
}

5.3. Calling Read/Write callbacks

Call the read callback with txtvm_io_read. Will return -1 if there is no read callback.

<<funcdefs>>=
int txtvm_io_read(txtvm_io *io, int sz, char *buf);
<<funcs>>=
int txtvm_io_read(txtvm_io *io, int sz, char *buf)
{
    if (io->read == NULL) return -1;
    return io->read(sz, buf, io->ud);
}

Writing is done in a similar way with txtvm_io_write. It will also return -1 if no write callback is to be found.

<<funcdefs>>=
int txtvm_io_write(txtvm_io *io, int sz, char *buf);
<<funcs>>=
int txtvm_io_write(txtvm_io *io, int sz, char *buf)
{
    if (io->write == NULL) return -1;
    return io->write(sz, buf, io->ud);
}

5.4. Read-Only Memory Buffer Setup

This setup configures things to read bytes from a memory buffer. Writing is disabled.

<<funcdefs>>=
void txtvm_io_readbuf(txtvm_io *io,
                      txtvm_io_readbuf_data *data);
<<funcs>>=
<<readbuf>>
void txtvm_io_readbuf(txtvm_io *io,
                      txtvm_io_readbuf_data *data)
{
    io->read = readbuf;
    io->write = NULL;
    io->ud = data;
}

The reader callback struct is embedded inside of a struct for the serial parser. This new struct is initialized with both the memory buffer to read from, as well as the size.

<<typedefs>>=
typedef struct {
    unsigned long pos;
    unsigned long sz;
    const char *buf;
} txtvm_io_readbuf_data;

Internally, the struct keeps track of the buffer offset position.

Reading from the buffer is a matter of making sure the requested block size is in bounds, adjusting if needed, copying the chunk, then updating the offset position.

<<readbuf>>=
static int readbuf(int sz, char *buf, void *ud)
{
    txtvm_io_readbuf_data *r;
    int i;

    r = ud;

    if (r->pos >= r->sz) return 0;

    if ((r->pos + sz) >= r->sz) {
        sz = r->sz - r->pos;
    }

    for (i = 0; i < sz; i++) {
        buf[i] = r->buf[r->pos + i];
    }

    r->pos += sz;
    return sz;
}

5.5. Write-Only Memory Buffer Setup

Sets up the I/O interface to write content to a buffer with a maximum capacity. If it reaches that point, it returns an error.

<<funcdefs>>=
void txtvm_io_writebuf(txtvm_io *io,
                       txtvm_io_writebuf_data *data);
<<funcs>>=
<<writebuf>>
void txtvm_io_writebuf(txtvm_io *io,
                       txtvm_io_writebuf_data *data)
{
    io->read = NULL;
    io->write = writebuf;
    io->ud = data;
}
<<typedefs>>=
typedef struct {
    unsigned long pos;
    unsigned long sz;
    char *buf;
} txtvm_io_writebuf_data;
<<writebuf>>=
static int writebuf(int sz, char *buf, void *ud)
{
    txtvm_io_writebuf_data *w;
    int i;

    w = ud;

    if (w->pos >= w->sz) return 0;

    if ((w->pos + sz) >= w->sz) {
        sz = w->sz - w->pos;
    }

    for (i = 0; i < sz; i++) {
        w->buf[w->pos + i] = buf[i];
    }

    w->pos += sz;
    return sz;
}

5.6. I/O Errors

5.6.1. Incomplete Write

<<errorlist>>=
ERRORCODE(TXTVM_INCOMPLETE_WRITE, "Incomplete write.")

5.6.2. Incomplete Read

<<errorlist>>=
ERRORCODE(TXTVM_INCOMPLETE_READ, "Incomplete read.")



prev | home | next