Any examples of using objects from the OBEX?
I have noticed that the PropGCC has an example using TV Text but I found it a bit vague and was hoping there are other examples I can look at to get familiar with _Driver.H and how to implement the hooks into stdio.
While I'm on this I was wondering about the px.bat file mentioned in tv_text.h. Does this need to be used on any OBEX object? If so where is it located?
While I'm on this I was wondering about the px.bat file mentioned in tv_text.h. Does this need to be used on any OBEX object? If so where is it located?
Comments
You should be able to take any SPIN demo "driver" from OBEX and convert it to a C program assuming the SPIN/PASM interface is "clean" - that is not interdependent. The Mems Accelerator, Mouse, TV, and VGA demos are all clean as far as I can tell. Some examples where the interface is not clean are the Graphics demo and Keyboard demo.
Configuring the standard library driver interface is described here: http://propgcc.googlecode.com/hg/doc/Library.html#drivers
Using a driver is very simple. Writing a driver is a matter of providing functions like open, read, write, and close.
One simple example for using a driver is in the xbasic demo.
I decided to use the full duplex serial driver for xbasic so I could use copy/paste for a demo. The stock 1 COG LMM serial IO has limits because input must be polled - it works fine if you don't do copy/paste.
To add the full duplex serial driver to xbasic all I had to do was paste this snippet in the main file:
/* list of drivers we can use */ #include <sys/driver.h> // more extern _Driver _FullDuplexSerialDriver; _Driver *_driverlist[] = { &_FullDuplexSerialDriver, };
Nothing to it. It works because GCC has the ability to overload features. That's just one of several GCC super powers.
In this case, the first and only location in the list is the full duplex serial driver. The first location is reserved for the console and is the reason you don't have to define special printf functions. If you want smaller printf functions that do not use floating point, etc... you can add the " -D__simple_printf " flag when compiling with the standard library.
Writing a driver takes more work.
That process has not been fully explained, but the TV Text demo has example code. As you say, it is vague.
For a standard library driver, you need to define the functions, and add the functions to a _Driver array.
One of the simplest possible examples of a driver is the null driver. The null driver is used in some cases where you don't want anything to happen - it is often used in Linux output redirection if you don't want some program to print stuff.
/* * null device driver (like /dev/null) * * Copyright (c) Parallax Inc. 2011 * MIT Licensed (see end of file) */ #include <stdio.h> #include <time.h> #include <cog.h> #include <sys/driver.h> #include <errno.h> int _null_write(FILE *fp, unsigned char *buf, int size) { return size; } int _null_read(FILE *fp, unsigned char *buf, int size) { return 0; } int _null_fopen(FILE *fp, const char *str, const char *mode) { return 0; } const char _NullPrefix[] = "NUL:"; _Driver _NullDriver = { _NullPrefix, _null_fopen, NULL, _null_read, _null_write, NULL, NULL, NULL, NULL }; /* +-------------------------------------------------------------------- ¦ TERMS OF USE: MIT License +-------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------ */
The null driver does nothing, that's why it's so simple. But it does illustrate the basics of a driver. It provides functions and glues them together in the _Driver array. Here's a brief example where all driver functions are illustrated.
// Define the driver list _Driver _ExampleDriver = { Example_prefix, // prefix is the driver name -defined as char *some_prefix = "EXAMPLE:"; Example_fopen, // setup the driver, maybe start a COG, maybe create a file on a disk Example_fclose, // release driver resources Example_read, // the input function ... read from a sensor? Example_write, // the output function ... write to a port? Example_fseek, // typically used for disk drives Example_remove, // typically used to remove a file on a disk };
The driver functions do anything you want them to do. The _Driver array tells the program what function code to use for the driver to call when you say "fopen", etc... In the case of the full duplex serial driver shown in the xbasic example, any print output translates to the write function automatically because that's what the first _Driver slot is for.
In the TV example, these functions are defined:
const char TvPrefix[] = "TV:"; Tv_fopen(FILE *fp, const char *str, const char *mode) Tv_fclose(FILE *fp) Tv_write(FILE *fp, unsigned char *buf, int count)
The _Driver array looks like this:
_Driver TvDriver = { TvPrefix, Tv_fopen, Tv_fclose, _null_read, Tv_write, NULL, /* seek; not applicable */ NULL, /* remove; not applicable */ };
The c3file demo also uses a generic driver. The source code is not in one of our test distributions, but it follows the same idea.
+1 for "GCC Super Powers"
Jazzed, can I get a few words on what "clean" means? Right now, I'm authoring some PASM, and have some targeted for a project, and am unsure about "clean". Best sort it right now.
@potatohead,
Basically it means that we should use mail-boxes for sharing information between the host language and the PASM driver. The PASM should stand alone independent of symbols or functions outside of the DAT block.
For example, the Graphics driver references fontptr which is a long in the PASM, but is given a value in the SPIN start method. In this case, I had to rewrite the Graphics initialization for use with C. I have seen lots of inter-dependencies with SPIN/PASM drivers.
Now, if the same driver was rewritten in GAS, you could share variables between GAS and C. The demos/toggle/gas_toggle program shows how to do this.
However, in some ways, I would like to see no inter-dependencies in any ASM at all. That would allow loading PASM code as needed which could save HUB memory space. We do that quite a bit in the loader.
There are probably other things we've learned as a group about this subject that would apply.
Thanks,
--Steve
Method 1:
Cogstart with block address passed via PAR, longs are read or written to in a periodic way to change modes, or communicate a state.
Method 2:
Cogstart with block address in PAR, arguments are dropped into the block of longs, then one in particular is written, triggering some action in that COG, that when complete, results in that same command long being written to again to signal done/ready.
Both are basically the same mechanics.
Are you saying GAS has to assemble those to make use of them? Or...?
**I'll look up the font pointer example. I think you mean "poke it in", where the cog image is modified prior to cog start. If so, agreed. That one isn't good. But do the means above work reasonably well?
To explicitly refer to an external symbol (without passing it in PAR) you need to rely on GAS, which can export the symbol reference in a form the linker can resolve. The gas toggle example shows how to do this.
Eric