diff options
Diffstat (limited to 'AltOS/doc/altos.html')
-rw-r--r-- | AltOS/doc/altos.html | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/AltOS/doc/altos.html b/AltOS/doc/altos.html new file mode 100644 index 0000000..dea05ee --- /dev/null +++ b/AltOS/doc/altos.html @@ -0,0 +1,817 @@ +<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>AltOS</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="AltOS"><div class="titlepage"><div><div><h1 class="title"><a name="id2287738"></a>AltOS</h1></div><div><h2 class="subtitle">Altos Metrum Operating System</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Keith</span> <span class="surname">Packard</span></h3></div></div><div><p class="copyright">Copyright © 2010 Keith Packard</p></div><div><div class="legalnotice" title="Legal Notice"><a name="id2569423"></a><p> + This document is released under the terms of the + <a class="ulink" href="http://creativecommons.org/licenses/by-sa/3.0/" target="_top"> + Creative Commons ShareAlike 3.0 + </a> + license. + </p></div></div><div><div class="revhistory"><table border="1" width="100%" summary="Revision history"><tr><th align="left" valign="top" colspan="2"><b>Revision History</b></th></tr><tr><td align="left">Revision 0.1</td><td align="left">22 November 2010</td></tr><tr><td align="left" colspan="2">Initial content</td></tr></table></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#id2555194">1. Overview</a></span></dt><dt><span class="chapter"><a href="#id2579104">2. Programming the 8051 with SDCC</a></span></dt><dd><dl><dt><span class="section"><a href="#id2572549">8051 memory spaces</a></span></dt><dd><dl><dt><span class="section"><a href="#id2587147">__data</a></span></dt><dt><span class="section"><a href="#id2574082">__idata</a></span></dt><dt><span class="section"><a href="#id2585502">__xdata</a></span></dt><dt><span class="section"><a href="#id2568787">__pdata</a></span></dt><dt><span class="section"><a href="#id2564890">__code</a></span></dt><dt><span class="section"><a href="#id2570929">__bit</a></span></dt><dt><span class="section"><a href="#id2558641">__sfr, __sfr16, __sfr32, __sbit</a></span></dt></dl></dd><dt><span class="section"><a href="#id2565185">Function calls on the 8051</a></span></dt><dd><dl><dt><span class="section"><a href="#id2557511">__reentrant functions</a></span></dt><dt><span class="section"><a href="#id2558653">Non __reentrant functions</a></span></dt><dt><span class="section"><a href="#id2587007">__interrupt functions</a></span></dt><dt><span class="section"><a href="#id2570923">__critical functions and statements</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#id2578729">3. Task functions</a></span></dt><dd><dl><dt><span class="section"><a href="#id2566460">ao_add_task</a></span></dt><dt><span class="section"><a href="#id2549662">ao_exit</a></span></dt><dt><span class="section"><a href="#id2588863">ao_sleep</a></span></dt><dt><span class="section"><a href="#id2555754">ao_wakeup</a></span></dt><dt><span class="section"><a href="#id2578893">ao_alarm</a></span></dt><dt><span class="section"><a href="#id2565595">ao_wake_task</a></span></dt><dt><span class="section"><a href="#id2561847">ao_start_scheduler</a></span></dt><dt><span class="section"><a href="#id2571836">ao_clock_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2574991">4. Timer Functions</a></span></dt><dd><dl><dt><span class="section"><a href="#id2568218">ao_time</a></span></dt><dt><span class="section"><a href="#id2581923">ao_delay</a></span></dt><dt><span class="section"><a href="#id2581648">ao_timer_set_adc_interval</a></span></dt><dt><span class="section"><a href="#id2586062">ao_timer_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2589986">5. AltOS Mutexes</a></span></dt><dd><dl><dt><span class="section"><a href="#id2570322">ao_mutex_get</a></span></dt><dt><span class="section"><a href="#id2555486">ao_mutex_put</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2582719">6. CC1111 DMA engine</a></span></dt><dd><dl><dt><span class="section"><a href="#id2579029">ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#id2568950">ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#id2576818">ao_dma_start</a></span></dt><dt><span class="section"><a href="#id2586065">ao_dma_trigger</a></span></dt><dt><span class="section"><a href="#id2570488">ao_dma_abort</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2571669">7. SDCC Stdio interface</a></span></dt><dd><dl><dt><span class="section"><a href="#id2583460">putchar</a></span></dt><dt><span class="section"><a href="#id2569848">getchar</a></span></dt><dt><span class="section"><a href="#id2584689">flush</a></span></dt><dt><span class="section"><a href="#id2578522">ao_add_stdio</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2577396">8. Command line interface</a></span></dt><dd><dl><dt><span class="section"><a href="#id2573332">ao_cmd_register</a></span></dt><dt><span class="section"><a href="#id2573326">ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#id2569393">ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#id2565433">ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#id2587125">ao_cmd_white</a></span></dt><dt><span class="section"><a href="#id2583867">ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#id2589264">ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#id2578518">ao_match_word</a></span></dt><dt><span class="section"><a href="#id2589111">ao_cmd_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2573826">9. CC1111 USB target device</a></span></dt><dd><dl><dt><span class="section"><a href="#id2567131">ao_usb_flush</a></span></dt><dt><span class="section"><a href="#id2582959">ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#id2589206">ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#id2550786">ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#id2569256">ao_usb_disable</a></span></dt><dt><span class="section"><a href="#id2566705">ao_usb_enable</a></span></dt><dt><span class="section"><a href="#id2566594">ao_usb_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2575764">10. CC1111 Serial peripheral</a></span></dt><dd><dl><dt><span class="section"><a href="#id2576363">ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#id2552673">ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#id2553935">ao_serial_drain</a></span></dt><dt><span class="section"><a href="#id2564334">ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#id2574349">ao_serial_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#id2580359">11. CC1111 Radio peripheral</a></span></dt><dd><dl><dt><span class="section"><a href="#id2552360">ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#id2581777">ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#id2585369">ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#id2573544">ao_radio_idle</a></span></dt><dt><span class="section"><a href="#id2551519">ao_radio_get</a></span></dt><dt><span class="section"><a href="#id2586346">ao_radio_put</a></span></dt><dt><span class="section"><a href="#id2590004">ao_radio_abort</a></span></dt><dt><span class="section"><a href="#id2565052">ao_radio_send</a></span></dt><dt><span class="section"><a href="#id2569083">ao_radio_recv</a></span></dt><dt><span class="section"><a href="#id2583861">ao_radio_rdf</a></span></dt><dt><span class="section"><a href="#id2590408">ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#id2587711">ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#id2590396">ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#id2563331">ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#id2562720">ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#id2574661">ao_packet_master_init</a></span></dt></dl></dd></dl></div><div class="chapter" title="Chapter 1. Overview"><div class="titlepage"><div><div><h2 class="title"><a name="id2555194"></a>Chapter 1. Overview</h2></div></div></div><p> + AltOS is a operating system built for the 8051-compatible + processor found in the TI cc1111 microcontroller. It's designed + to be small and easy to program with. The main features are: + </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Multi-tasking. While the 8051 doesn't provide separate + address spaces, it's often easier to write code that operates + in separate threads instead of tying everything into one giant + event loop. + </p></li><li class="listitem"><p>Non-preemptive. This increases latency for thread + switching but reduces the number of places where context + switching can occur. It also simplifies the operating system + design somewhat. Nothing in the target system (rocket flight + control) has tight timing requirements, and so this seems like + a reasonable compromise. + </p></li><li class="listitem"><p>Sleep/wakeup scheduling. Taken directly from ancient + Unix designs, these two provide the fundemental scheduling + primitive within AltOS. + </p></li><li class="listitem"><p>Mutexes. As a locking primitive, mutexes are easier to + use than semaphores, at least in my experience. + </p></li><li class="listitem"><p>Timers. Tasks can set an alarm which will abort any + pending sleep, allowing operations to time-out instead of + blocking forever. + </p></li></ul></div><p> + </p><p> + The device drivers and other subsystems in AltOS are + conventionally enabled by invoking their _init() function from + the 'main' function before that calls + ao_start_scheduler(). These functions initialize the pin + assignments, add various commands to the command processor and + may add tasks to the scheduler to handle the device. A typical + main program, thus, looks like: + </p><pre class="programlisting"> + void + main(void) + { + ao_clock_init(); + + /* Turn on the LED until the system is stable */ + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_RED); + ao_timer_init(); + ao_cmd_init(); + ao_usb_init(); + ao_monitor_init(AO_LED_GREEN, TRUE); + ao_rssi_init(AO_LED_RED); + ao_radio_init(); + ao_packet_slave_init(); + ao_packet_master_init(); + #if HAS_DBG + ao_dbg_init(); + #endif + ao_config_init(); + ao_start_scheduler(); + } + </pre><p> + As you can see, a long sequence of subsystems are initialized + and then the scheduler is started. + </p></div><div class="chapter" title="Chapter 2. Programming the 8051 with SDCC"><div class="titlepage"><div><div><h2 class="title"><a name="id2579104"></a>Chapter 2. Programming the 8051 with SDCC</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2572549">8051 memory spaces</a></span></dt><dd><dl><dt><span class="section"><a href="#id2587147">__data</a></span></dt><dt><span class="section"><a href="#id2574082">__idata</a></span></dt><dt><span class="section"><a href="#id2585502">__xdata</a></span></dt><dt><span class="section"><a href="#id2568787">__pdata</a></span></dt><dt><span class="section"><a href="#id2564890">__code</a></span></dt><dt><span class="section"><a href="#id2570929">__bit</a></span></dt><dt><span class="section"><a href="#id2558641">__sfr, __sfr16, __sfr32, __sbit</a></span></dt></dl></dd><dt><span class="section"><a href="#id2565185">Function calls on the 8051</a></span></dt><dd><dl><dt><span class="section"><a href="#id2557511">__reentrant functions</a></span></dt><dt><span class="section"><a href="#id2558653">Non __reentrant functions</a></span></dt><dt><span class="section"><a href="#id2587007">__interrupt functions</a></span></dt><dt><span class="section"><a href="#id2570923">__critical functions and statements</a></span></dt></dl></dd></dl></div><p> + The 8051 is a primitive 8-bit processor, designed in the mists + of time in as few transistors as possible. The architecture is + highly irregular and includes several separate memory + spaces. Furthermore, accessing stack variables is slow, and the + stack itself is of limited size. While SDCC papers over the + instruction set, it is not completely able to hide the memory + architecture from the application designer. + </p><div class="section" title="8051 memory spaces"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2572549"></a>8051 memory spaces</h2></div></div></div><p> + The __data/__xdata/__code memory spaces below were completely + separate in the original 8051 design. In the cc1111, this + isn't true—they all live in a single unified 64kB address + space, and so it's possible to convert any address into a + unique 16-bit address. SDCC doesn't know this, and so a + 'global' address to SDCC consumes 3 bytes of memory, 1 byte as + a tag indicating the memory space and 2 bytes of offset within + that space. AltOS avoids these 3-byte addresses as much as + possible; using them involves a function call per byte + access. The result is that nearly every variable declaration + is decorated with a memory space identifier which clutters the + code but makes the resulting code far smaller and more + efficient. + </p><div class="section" title="__data"><div class="titlepage"><div><div><h3 class="title"><a name="id2587147"></a>__data</h3></div></div></div><p> + The 8051 can directly address these 128 bytes of + memory. This makes them precious so they should be + reserved for frequently addressed values. Oh, just to + confuse things further, the 8 general registers in the + CPU are actually stored in this memory space. There are + magic instructions to 'bank switch' among 4 banks of + these registers located at 0x00 - 0x1F. AltOS uses only + the first bank at 0x00 - 0x07, leaving the other 24 + bytes available for other data. + </p></div><div class="section" title="__idata"><div class="titlepage"><div><div><h3 class="title"><a name="id2574082"></a>__idata</h3></div></div></div><p> + There are an additional 128 bytes of internal memory + that share the same address space as __data but which + cannot be directly addressed. The stack normally + occupies this space and so AltOS doesn't place any + static storage here. + </p></div><div class="section" title="__xdata"><div class="titlepage"><div><div><h3 class="title"><a name="id2585502"></a>__xdata</h3></div></div></div><p> + This is additional general memory accessed through a + single 16-bit address register. The CC1111F32 has 32kB + of memory available here. Most program data should live + in this memory space. + </p></div><div class="section" title="__pdata"><div class="titlepage"><div><div><h3 class="title"><a name="id2568787"></a>__pdata</h3></div></div></div><p> + This is an alias for the first 256 bytes of __xdata + memory, but uses a shorter addressing mode with + single global 8-bit value for the high 8 bits of the + address and any of several 8-bit registers for the low 8 + bits. AltOS uses a few bits of this memory, it should + probably use more. + </p></div><div class="section" title="__code"><div class="titlepage"><div><div><h3 class="title"><a name="id2564890"></a>__code</h3></div></div></div><p> + All executable code must live in this address space, but + you can stick read-only data here too. It is addressed + using the 16-bit address register and special 'code' + access opcodes. Anything read-only should live in this space. + </p></div><div class="section" title="__bit"><div class="titlepage"><div><div><h3 class="title"><a name="id2570929"></a>__bit</h3></div></div></div><p> + The 8051 has 128 bits of bit-addressible memory that + lives in the __data segment from 0x20 through + 0x2f. Special instructions access these bits + in a single atomic operation. This isn't so much a + separate address space as a special addressing mode for + a few bytes in the __data segment. + </p></div><div class="section" title="__sfr, __sfr16, __sfr32, __sbit"><div class="titlepage"><div><div><h3 class="title"><a name="id2558641"></a>__sfr, __sfr16, __sfr32, __sbit</h3></div></div></div><p> + Access to physical registers in the device use this mode + which declares the variable name, it's type and the + address it lives at. No memory is allocated for these + variables. + </p></div></div><div class="section" title="Function calls on the 8051"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2565185"></a>Function calls on the 8051</h2></div></div></div><p> + Because stack addressing is expensive, and stack space + limited, the default function call declaration in SDCC + allocates all parameters and local variables in static global + memory. Just like fortran. This makes these functions + non-reentrant, and also consume space for parameters and + locals even when they are not running. The benefit is smaller + code and faster execution. + </p><div class="section" title="__reentrant functions"><div class="titlepage"><div><div><h3 class="title"><a name="id2557511"></a>__reentrant functions</h3></div></div></div><p> + All functions which are re-entrant, either due to recursion + or due to a potential context switch while executing, should + be marked as __reentrant so that their parameters and local + variables get allocated on the stack. This ensures that + these values are not overwritten by another invocation of + the function. + </p><p> + Functions which use significant amounts of space for + arguments and/or local variables and which are not often + invoked can also be marked as __reentrant. The resulting + code will be larger, but the savings in memory are + frequently worthwhile. + </p></div><div class="section" title="Non __reentrant functions"><div class="titlepage"><div><div><h3 class="title"><a name="id2558653"></a>Non __reentrant functions</h3></div></div></div><p> + All parameters and locals in non-reentrant functions can + have data space decoration so that they are allocated in + __xdata, __pdata or __data space as desired. This can avoid + consuming __data space for infrequently used variables in + frequently used functions. + </p><p> + All library functions called by SDCC, including functions + for multiplying and dividing large data types, are + non-reentrant. Because of this, interrupt handlers must not + invoke any library functions, including the multiply and + divide code. + </p></div><div class="section" title="__interrupt functions"><div class="titlepage"><div><div><h3 class="title"><a name="id2587007"></a>__interrupt functions</h3></div></div></div><p> + Interrupt functions are declared with with an __interrupt + decoration that includes the interrupt number. SDCC saves + and restores all of the registers in these functions and + uses the 'reti' instruction at the end so that they operate + as stand-alone interrupt handlers. Interrupt functions may + call the ao_wakeup function to wake AltOS tasks. + </p></div><div class="section" title="__critical functions and statements"><div class="titlepage"><div><div><h3 class="title"><a name="id2570923"></a>__critical functions and statements</h3></div></div></div><p> + SDCC has built-in support for suspending interrupts during + critical code. Functions marked as __critical will have + interrupts suspended for the whole period of + execution. Individual statements may also be marked as + __critical which blocks interrupts during the execution of + that statement. Keeping critical sections as short as + possible is key to ensuring that interrupts are handled as + quickly as possible. + </p></div></div></div><div class="chapter" title="Chapter 3. Task functions"><div class="titlepage"><div><div><h2 class="title"><a name="id2578729"></a>Chapter 3. Task functions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2566460">ao_add_task</a></span></dt><dt><span class="section"><a href="#id2549662">ao_exit</a></span></dt><dt><span class="section"><a href="#id2588863">ao_sleep</a></span></dt><dt><span class="section"><a href="#id2555754">ao_wakeup</a></span></dt><dt><span class="section"><a href="#id2578893">ao_alarm</a></span></dt><dt><span class="section"><a href="#id2565595">ao_wake_task</a></span></dt><dt><span class="section"><a href="#id2561847">ao_start_scheduler</a></span></dt><dt><span class="section"><a href="#id2571836">ao_clock_init</a></span></dt></dl></div><p> + This chapter documents how to create, destroy and schedule AltOS tasks. + </p><div class="section" title="ao_add_task"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2566460"></a>ao_add_task</h2></div></div></div><pre class="programlisting"> + void + ao_add_task(__xdata struct ao_task * task, + void (*start)(void), + __code char *name); + </pre><p> + This initializes the statically allocated task structure, + assigns a name to it (not used for anything but the task + display), and the start address. It does not switch to the + new task. 'start' must not ever return; there is no place + to return to. + </p></div><div class="section" title="ao_exit"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2549662"></a>ao_exit</h2></div></div></div><pre class="programlisting"> + void + ao_exit(void) + </pre><p> + This terminates the current task. + </p></div><div class="section" title="ao_sleep"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2588863"></a>ao_sleep</h2></div></div></div><pre class="programlisting"> + void + ao_sleep(__xdata void *wchan) + </pre><p> + This suspends the current task until 'wchan' is signaled + by ao_wakeup, or until the timeout, set by ao_alarm, + fires. If 'wchan' is signaled, ao_sleep returns 0, otherwise + it returns 1. This is the only way to switch to another task. + </p><p> + Because ao_wakeup wakes every task waiting on a particular + location, ao_sleep should be used in a loop that first + checks the desired condition, blocks in ao_sleep and then + rechecks until the condition is satisfied. If the + location may be signaled from an interrupt handler, the + code will need to block interrupts by using the __critical + label around the block of code. Here's a complete example: + </p><pre class="programlisting"> + __critical while (!ao_radio_done) + ao_sleep(&ao_radio_done); + </pre><p> + </p></div><div class="section" title="ao_wakeup"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2555754"></a>ao_wakeup</h2></div></div></div><pre class="programlisting"> + void + ao_wakeup(__xdata void *wchan) + </pre><p> + Wake all tasks blocked on 'wchan'. This makes them + available to be run again, but does not actually switch + to another task. Here's an example of using this: + </p><pre class="programlisting"> + if (RFIF & RFIF_IM_DONE) { + ao_radio_done = 1; + ao_wakeup(&ao_radio_done); + RFIF &= ~RFIF_IM_DONE; + } + </pre><p> + Note that this need not be enclosed in __critical as the + ao_sleep block can only be run from normal mode, and so + this sequence can never be interrupted with execution of + the other sequence. + </p></div><div class="section" title="ao_alarm"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2578893"></a>ao_alarm</h2></div></div></div><pre class="programlisting"> + void + ao_alarm(uint16_t delay) + </pre><p> + Schedules an alarm to fire in at least 'delay' ticks. If + the task is asleep when the alarm fires, it will wakeup + and ao_sleep will return 1. + </p><pre class="programlisting"> + ao_alarm(ao_packet_master_delay); + __critical while (!ao_radio_dma_done) + if (ao_sleep(&ao_radio_dma_done) != 0) + ao_radio_abort(); + </pre><p> + In this example, a timeout is set before waiting for + incoming radio data. If no data is received before the + timeout fires, ao_sleep will return 1 and then this code + will abort the radio receive operation. + </p></div><div class="section" title="ao_wake_task"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2565595"></a>ao_wake_task</h2></div></div></div><pre class="programlisting"> + void + ao_wake_task(__xdata struct ao_task *task) + </pre><p> + Force a specific task to wake up, independent of which + 'wchan' it is waiting for. + </p></div><div class="section" title="ao_start_scheduler"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2561847"></a>ao_start_scheduler</h2></div></div></div><pre class="programlisting"> + void + ao_start_scheduler(void) + </pre><p> + This is called from 'main' when the system is all + initialized and ready to run. It will not return. + </p></div><div class="section" title="ao_clock_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2571836"></a>ao_clock_init</h2></div></div></div><pre class="programlisting"> + void + ao_clock_init(void) + </pre><p> + This turns on the external 48MHz clock then switches the + hardware to using it. This is required by many of the + internal devices like USB. It should be called by the + 'main' function first, before initializing any of the + other devices in the system. + </p></div></div><div class="chapter" title="Chapter 4. Timer Functions"><div class="titlepage"><div><div><h2 class="title"><a name="id2574991"></a>Chapter 4. Timer Functions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2568218">ao_time</a></span></dt><dt><span class="section"><a href="#id2581923">ao_delay</a></span></dt><dt><span class="section"><a href="#id2581648">ao_timer_set_adc_interval</a></span></dt><dt><span class="section"><a href="#id2586062">ao_timer_init</a></span></dt></dl></div><p> + AltOS sets up one of the cc1111 timers to run at 100Hz and + exposes this tick as the fundemental unit of time. At each + interrupt, AltOS increments the counter, and schedules any tasks + waiting for that time to pass, then fires off the ADC system to + collect current data readings. Doing this from the ISR ensures + that the ADC values are sampled at a regular rate, independent + of any scheduling jitter. + </p><div class="section" title="ao_time"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2568218"></a>ao_time</h2></div></div></div><pre class="programlisting"> + uint16_t + ao_time(void) + </pre><p> + Returns the current system tick count. Note that this is + only a 16 bit value, and so it wraps every 655.36 seconds. + </p></div><div class="section" title="ao_delay"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2581923"></a>ao_delay</h2></div></div></div><pre class="programlisting"> + void + ao_delay(uint16_t ticks); + </pre><p> + Suspend the current task for at least 'ticks' clock units. + </p></div><div class="section" title="ao_timer_set_adc_interval"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2581648"></a>ao_timer_set_adc_interval</h2></div></div></div><pre class="programlisting"> + void + ao_timer_set_adc_interval(uint8_t interval); + </pre><p> + This sets the number of ticks between ADC samples. If set + to 0, no ADC samples are generated. AltOS uses this to + slow down the ADC sampling rate to save power. + </p></div><div class="section" title="ao_timer_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2586062"></a>ao_timer_init</h2></div></div></div><pre class="programlisting"> + void + ao_timer_init(void) + </pre><p> + This turns on the 100Hz tick using the CC1111 timer 1. It + is required for any of the time-based functions to + work. It should be called by 'main' before ao_start_scheduler. + </p></div></div><div class="chapter" title="Chapter 5. AltOS Mutexes"><div class="titlepage"><div><div><h2 class="title"><a name="id2589986"></a>Chapter 5. AltOS Mutexes</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2570322">ao_mutex_get</a></span></dt><dt><span class="section"><a href="#id2555486">ao_mutex_put</a></span></dt></dl></div><p> + AltOS provides mutexes as a basic synchronization primitive. Each + mutexes is simply a byte of memory which holds 0 when the mutex + is free or the task id of the owning task when the mutex is + owned. Mutex calls are checked—attempting to acquire a mutex + already held by the current task or releasing a mutex not held + by the current task will both cause a panic. + </p><div class="section" title="ao_mutex_get"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2570322"></a>ao_mutex_get</h2></div></div></div><pre class="programlisting"> + void + ao_mutex_get(__xdata uint8_t *mutex); + </pre><p> + Acquires the specified mutex, blocking if the mutex is + owned by another task. + </p></div><div class="section" title="ao_mutex_put"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2555486"></a>ao_mutex_put</h2></div></div></div><pre class="programlisting"> + void + ao_mutex_put(__xdata uint8_t *mutex); + </pre><p> + Releases the specified mutex, waking up all tasks waiting + for it. + </p></div></div><div class="chapter" title="Chapter 6. CC1111 DMA engine"><div class="titlepage"><div><div><h2 class="title"><a name="id2582719"></a>Chapter 6. CC1111 DMA engine</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2579029">ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#id2568950">ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#id2576818">ao_dma_start</a></span></dt><dt><span class="section"><a href="#id2586065">ao_dma_trigger</a></span></dt><dt><span class="section"><a href="#id2570488">ao_dma_abort</a></span></dt></dl></div><p> + The CC1111 contains a useful bit of extra hardware in the form + of five programmable DMA engines. They can be configured to copy + data in memory, or between memory and devices (or even between + two devices). AltOS exposes a general interface to this hardware + and uses it to handle radio and SPI data. + </p><p> + Code using a DMA engine should allocate one at startup + time. There is no provision to free them, and if you run out, + AltOS will simply panic. + </p><p> + During operation, the DMA engine is initialized with the + transfer parameters. Then it is started, at which point it + awaits a suitable event to start copying data. When copying data + from hardware to memory, that trigger event is supplied by the + hardware device. When copying data from memory to hardware, the + transfer is usually initiated by software. + </p><div class="section" title="ao_dma_alloc"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2579029"></a>ao_dma_alloc</h2></div></div></div><pre class="programlisting"> + uint8_t + ao_dma_alloc(__xdata uint8_t *done) + </pre><p> + Allocates a DMA engine, returning the identifier. Whenever + this DMA engine completes a transfer. 'done' is cleared + when the DMA is started, and then receives the + AO_DMA_DONE bit on a successful transfer or the + AO_DMA_ABORTED bit if ao_dma_abort was called. Note that + it is possible to get both bits if the transfer was + aborted after it had finished. + </p></div><div class="section" title="ao_dma_set_transfer"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2568950"></a>ao_dma_set_transfer</h2></div></div></div><pre class="programlisting"> + void + ao_dma_set_transfer(uint8_t id, + void __xdata *srcaddr, + void __xdata *dstaddr, + uint16_t count, + uint8_t cfg0, + uint8_t cfg1) + </pre><p> + Initializes the specified dma engine to copy data + from 'srcaddr' to 'dstaddr' for 'count' units. cfg0 and + cfg1 are values directly out of the CC1111 documentation + and tell the DMA engine what the transfer unit size, + direction and step are. + </p></div><div class="section" title="ao_dma_start"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2576818"></a>ao_dma_start</h2></div></div></div><pre class="programlisting"> + void + ao_dma_start(uint8_t id); + </pre><p> + Arm the specified DMA engine and await a signal from + either hardware or software to start transferring data. + </p></div><div class="section" title="ao_dma_trigger"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2586065"></a>ao_dma_trigger</h2></div></div></div><pre class="programlisting"> + void + ao_dma_trigger(uint8_t id) + </pre><p> + Trigger the specified DMA engine to start copying data. + </p></div><div class="section" title="ao_dma_abort"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2570488"></a>ao_dma_abort</h2></div></div></div><pre class="programlisting"> + void + ao_dma_abort(uint8_t id) + </pre><p> + Terminate any in-progress DMA transation, marking its + 'done' variable with the AO_DMA_ABORTED bit. + </p></div></div><div class="chapter" title="Chapter 7. SDCC Stdio interface"><div class="titlepage"><div><div><h2 class="title"><a name="id2571669"></a>Chapter 7. SDCC Stdio interface</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2583460">putchar</a></span></dt><dt><span class="section"><a href="#id2569848">getchar</a></span></dt><dt><span class="section"><a href="#id2584689">flush</a></span></dt><dt><span class="section"><a href="#id2578522">ao_add_stdio</a></span></dt></dl></div><p> + AltOS offers a stdio interface over both USB and the RF packet + link. This provides for control of the device localy or + remotely. This is hooked up to the stdio functions in SDCC by + providing the standard putchar/getchar/flush functions. These + automatically multiplex the two available communication + channels; output is always delivered to the channel which + provided the most recent input. + </p><div class="section" title="putchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2583460"></a>putchar</h2></div></div></div><pre class="programlisting"> + void + putchar(char c) + </pre><p> + Delivers a single character to the current console + device. + </p></div><div class="section" title="getchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2569848"></a>getchar</h2></div></div></div><pre class="programlisting"> + char + getchar(void) + </pre><p> + Reads a single character from any of the available + console devices. The current console device is set to + that which delivered this character. This blocks until + a character is available. + </p></div><div class="section" title="flush"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2584689"></a>flush</h2></div></div></div><pre class="programlisting"> + void + flush(void) + </pre><p> + Flushes the current console device output buffer. Any + pending characters will be delivered to the target device. + xo </p></div><div class="section" title="ao_add_stdio"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2578522"></a>ao_add_stdio</h2></div></div></div><pre class="programlisting"> + void + ao_add_stdio(char (*pollchar)(void), + void (*putchar)(char), + void (*flush)(void)) + </pre><p> + This adds another console device to the available + list. + </p><p> + 'pollchar' returns either an available character or + AO_READ_AGAIN if none is available. Significantly, it does + not block. The device driver must set 'ao_stdin_ready' to + 1 and call ao_wakeup(&ao_stdin_ready) when it receives + input to tell getchar that more data is available, at + which point 'pollchar' will be called again. + </p><p> + 'putchar' queues a character for output, flushing if the output buffer is + full. It may block in this case. + </p><p> + 'flush' forces the output buffer to be flushed. It may + block until the buffer is delivered, but it is not + required to do so. + </p></div></div><div class="chapter" title="Chapter 8. Command line interface"><div class="titlepage"><div><div><h2 class="title"><a name="id2577396"></a>Chapter 8. Command line interface</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2573332">ao_cmd_register</a></span></dt><dt><span class="section"><a href="#id2573326">ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#id2569393">ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#id2565433">ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#id2587125">ao_cmd_white</a></span></dt><dt><span class="section"><a href="#id2583867">ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#id2589264">ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#id2578518">ao_match_word</a></span></dt><dt><span class="section"><a href="#id2589111">ao_cmd_init</a></span></dt></dl></div><p> + AltOS includes a simple command line parser which is hooked up + to the stdio interfaces permitting remote control of the device + over USB or the RF link as desired. Each command uses a single + character to invoke it, the remaining characters on the line are + available as parameters to the command. + </p><div class="section" title="ao_cmd_register"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2573332"></a>ao_cmd_register</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_register(__code struct ao_cmds *cmds) + </pre><p> + This registers a set of commands with the command + parser. There is a fixed limit on the number of command + sets, the system will panic if too many are registered. + Each command is defined by a struct ao_cmds entry: + </p><pre class="programlisting"> + struct ao_cmds { + char cmd; + void (*func)(void); + const char *help; + }; + </pre><p> + 'cmd' is the character naming the command. 'func' is the + function to invoke and 'help' is a string displayed by the + '?' command. Syntax errors found while executing 'func' + should be indicated by modifying the global ao_cmd_status + variable with one of the following values: + </p><div class="variablelist"><dl><dt></dt><dd><p> + The command was parsed successfully. There is no + need to assign this value, it is the default. + </p></dd><dt></dt><dd><p> + A token in the line was invalid, such as a number + containing invalid characters. The low-level + lexing functions already assign this value as needed. + </p></dd><dt></dt><dd><p> + The command line is invalid for some reason other + than invalid tokens. + </p></dd></dl></div><p> + </p></div><div class="section" title="ao_cmd_lex"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2573326"></a>ao_cmd_lex</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_lex(void); + </pre><p> + This gets the next character out of the command line + buffer and sticks it into ao_cmd_lex_c. At the end of the + line, ao_cmd_lex_c will get a newline ('\n') character. + </p></div><div class="section" title="ao_cmd_put16"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2569393"></a>ao_cmd_put16</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_put16(uint16_t v); + </pre><p> + Writes 'v' as four hexadecimal characters. + </p></div><div class="section" title="ao_cmd_put8"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2565433"></a>ao_cmd_put8</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_put8(uint8_t v); + </pre><p> + Writes 'v' as two hexadecimal characters. + </p></div><div class="section" title="ao_cmd_white"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2587125"></a>ao_cmd_white</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_white(void) + </pre><p> + This skips whitespace by calling ao_cmd_lex while + ao_cmd_lex_c is either a space or tab. It does not skip + any characters if ao_cmd_lex_c already non-white. + </p></div><div class="section" title="ao_cmd_hex"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2583867"></a>ao_cmd_hex</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_hex(void) + </pre><p> + This reads a 16-bit hexadecimal value from the command + line with optional leading whitespace. The resulting value + is stored in ao_cmd_lex_i; + </p></div><div class="section" title="ao_cmd_decimal"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2589264"></a>ao_cmd_decimal</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_decimal(void) + </pre><p> + This reads a 32-bit decimal value from the command + line with optional leading whitespace. The resulting value + is stored in ao_cmd_lex_u32 and the low 16 bits are stored + in ao_cmd_lex_i; + </p></div><div class="section" title="ao_match_word"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2578518"></a>ao_match_word</h2></div></div></div><pre class="programlisting"> + uint8_t + ao_match_word(__code char *word) + </pre><p> + This checks to make sure that 'word' occurs on the command + line. It does not skip leading white space. If 'word' is + found, then 1 is returned. Otherwise, ao_cmd_status is set to + ao_cmd_syntax_error and 0 is returned. + </p></div><div class="section" title="ao_cmd_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2589111"></a>ao_cmd_init</h2></div></div></div><pre class="programlisting"> + void + ao_cmd_init(void + </pre><p> + Initializes the command system, setting up the built-in + commands and adding a task to run the command processing + loop. It should be called by 'main' before ao_start_scheduler. + </p></div></div><div class="chapter" title="Chapter 9. CC1111 USB target device"><div class="titlepage"><div><div><h2 class="title"><a name="id2573826"></a>Chapter 9. CC1111 USB target device</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2567131">ao_usb_flush</a></span></dt><dt><span class="section"><a href="#id2582959">ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#id2589206">ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#id2550786">ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#id2569256">ao_usb_disable</a></span></dt><dt><span class="section"><a href="#id2566705">ao_usb_enable</a></span></dt><dt><span class="section"><a href="#id2566594">ao_usb_init</a></span></dt></dl></div><p> + The CC1111 contains a full-speed USB target device. It can be + programmed to offer any kind of USB target, but to simplify + interactions with a variety of operating systems, AltOS provides + only a single target device profile, that of a USB modem which + has native drivers for Linux, Windows and Mac OS X. It would be + easy to change the code to provide an alternate target device if + necessary. + </p><p> + To the rest of the system, the USB device looks like a simple + two-way byte stream. It can be hooked into the command line + interface if desired, offering control of the device over the + USB link. Alternatively, the functions can be accessed directly + to provide for USB-specific I/O. + </p><div class="section" title="ao_usb_flush"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2567131"></a>ao_usb_flush</h2></div></div></div><pre class="programlisting"> + void + ao_usb_flush(void); + </pre><p> + Flushes any pending USB output. This queues an 'IN' packet + to be delivered to the USB host if there is pending data, + or if the last IN packet was full to indicate to the host + that there isn't any more pending data available. + </p></div><div class="section" title="ao_usb_putchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2582959"></a>ao_usb_putchar</h2></div></div></div><pre class="programlisting"> + void + ao_usb_putchar(char c); + </pre><p> + If there is a pending 'IN' packet awaiting delivery to the + host, this blocks until that has been fetched. Then, this + adds a byte to the pending IN packet for delivery to the + USB host. If the USB packet is full, this queues the 'IN' + packet for delivery. + </p></div><div class="section" title="ao_usb_pollchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2589206"></a>ao_usb_pollchar</h2></div></div></div><pre class="programlisting"> + char + ao_usb_pollchar(void); + </pre><p> + If there are no characters remaining in the last 'OUT' + packet received, this returns AO_READ_AGAIN. Otherwise, it + returns the next character, reporting to the host that it + is ready for more data when the last character is gone. + </p></div><div class="section" title="ao_usb_getchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2550786"></a>ao_usb_getchar</h2></div></div></div><pre class="programlisting"> + char + ao_usb_getchar(void); + </pre><p> + This uses ao_pollchar to receive the next character, + blocking while ao_pollchar returns AO_READ_AGAIN. + </p></div><div class="section" title="ao_usb_disable"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2569256"></a>ao_usb_disable</h2></div></div></div><pre class="programlisting"> + void + ao_usb_disable(void); + </pre><p> + This turns off the USB controller. It will no longer + respond to host requests, nor return characters. Calling + any of the i/o routines while the USB device is disabled + is undefined, and likely to break things. Disabling the + USB device when not needed saves power. + </p><p> + Note that neither TeleDongle nor TeleMetrum are able to + signal to the USB host that they have disconnected, so + after disabling the USB device, it's likely that the cable + will need to be disconnected and reconnected before it + will work again. + </p></div><div class="section" title="ao_usb_enable"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2566705"></a>ao_usb_enable</h2></div></div></div><pre class="programlisting"> + void + ao_usb_enable(void); + </pre><p> + This turns the USB controller on again after it has been + disabled. See the note above about needing to physically + remove and re-insert the cable to get the host to + re-initialize the USB link. + </p></div><div class="section" title="ao_usb_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2566594"></a>ao_usb_init</h2></div></div></div><pre class="programlisting"> + void + ao_usb_init(void); + </pre><p> + This turns the USB controller on, adds a task to handle + the control end point and adds the usb I/O functions to + the stdio system. Call this from main before + ao_start_scheduler. + </p></div></div><div class="chapter" title="Chapter 10. CC1111 Serial peripheral"><div class="titlepage"><div><div><h2 class="title"><a name="id2575764"></a>Chapter 10. CC1111 Serial peripheral</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2576363">ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#id2552673">ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#id2553935">ao_serial_drain</a></span></dt><dt><span class="section"><a href="#id2564334">ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#id2574349">ao_serial_init</a></span></dt></dl></div><p> + The CC1111 provides two USART peripherals. AltOS uses one for + asynch serial data, generally to communicate with a GPS device, + and the other for a SPI bus. The UART is configured to operate + in 8-bits, no parity, 1 stop bit framing. The default + configuration has clock settings for 4800, 9600 and 57600 baud + operation. Additional speeds can be added by computing + appropriate clock values. + </p><p> + To prevent loss of data, AltOS provides receive and transmit + fifos of 32 characters each. + </p><div class="section" title="ao_serial_getchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2576363"></a>ao_serial_getchar</h2></div></div></div><pre class="programlisting"> + char + ao_serial_getchar(void); + </pre><p> + Returns the next character from the receive fifo, blocking + until a character is received if the fifo is empty. + </p></div><div class="section" title="ao_serial_putchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2552673"></a>ao_serial_putchar</h2></div></div></div><pre class="programlisting"> + void + ao_serial_putchar(char c); + </pre><p> + Adds a character to the transmit fifo, blocking if the + fifo is full. Starts transmitting characters. + </p></div><div class="section" title="ao_serial_drain"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2553935"></a>ao_serial_drain</h2></div></div></div><pre class="programlisting"> + void + ao_serial_drain(void); + </pre><p> + Blocks until the transmit fifo is empty. Used internally + when changing serial speeds. + </p></div><div class="section" title="ao_serial_set_speed"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2564334"></a>ao_serial_set_speed</h2></div></div></div><pre class="programlisting"> + void + ao_serial_set_speed(uint8_t speed); + </pre><p> + Changes the serial baud rate to one of + AO_SERIAL_SPEED_4800, AO_SERIAL_SPEED_9600 or + AO_SERIAL_SPEED_57600. This first flushes the transmit + fifo using ao_serial_drain. + </p></div><div class="section" title="ao_serial_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2574349"></a>ao_serial_init</h2></div></div></div><pre class="programlisting"> + void + ao_serial_init(void) + </pre><p> + Initializes the serial peripheral. Call this from 'main' + before jumping to ao_start_scheduler. The default speed + setting is AO_SERIAL_SPEED_4800. + </p></div></div><div class="chapter" title="Chapter 11. CC1111 Radio peripheral"><div class="titlepage"><div><div><h2 class="title"><a name="id2580359"></a>Chapter 11. CC1111 Radio peripheral</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id2552360">ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#id2581777">ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#id2585369">ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#id2573544">ao_radio_idle</a></span></dt><dt><span class="section"><a href="#id2551519">ao_radio_get</a></span></dt><dt><span class="section"><a href="#id2586346">ao_radio_put</a></span></dt><dt><span class="section"><a href="#id2590004">ao_radio_abort</a></span></dt><dt><span class="section"><a href="#id2565052">ao_radio_send</a></span></dt><dt><span class="section"><a href="#id2569083">ao_radio_recv</a></span></dt><dt><span class="section"><a href="#id2583861">ao_radio_rdf</a></span></dt><dt><span class="section"><a href="#id2590408">ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#id2587711">ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#id2590396">ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#id2563331">ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#id2562720">ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#id2574661">ao_packet_master_init</a></span></dt></dl></div><p> + The CC1111 radio transceiver sends and receives digital packets + with forward error correction and detection. The AltOS driver is + fairly specific to the needs of the TeleMetrum and TeleDongle + devices, using it for other tasks may require customization of + the driver itself. There are three basic modes of operation: + </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p> + Telemetry mode. In this mode, TeleMetrum transmits telemetry + frames at a fixed rate. The frames are of fixed size. This + is strictly a one-way communication from TeleMetrum to + TeleDongle. + </p></li><li class="listitem"><p> + Packet mode. In this mode, the radio is used to create a + reliable duplex byte stream between TeleDongle and + TeleMetrum. This is an asymmetrical protocol with + TeleMetrum only transmitting in response to a packet sent + from TeleDongle. Thus getting data from TeleMetrum to + TeleDongle requires polling. The polling rate is adaptive, + when no data has been received for a while, the rate slows + down. The packets are checked at both ends and invalid + data are ignored. + </p><p> + On the TeleMetrum side, the packet link is hooked into the + stdio mechanism, providing an alternate data path for the + command processor. It is enabled when the unit boots up in + 'idle' mode. + </p><p> + On the TeleDongle side, the packet link is enabled with a + command; data from the stdio package is forwarded over the + packet link providing a connection from the USB command + stream to the remote TeleMetrum device. + </p></li><li class="listitem"><p> + Radio Direction Finding mode. In this mode, TeleMetrum + constructs a special packet that sounds like an audio tone + when received by a conventional narrow-band FM + receiver. This is designed to provide a beacon to track + the device when other location mechanisms fail. + </p></li></ol></div><p> + </p><div class="section" title="ao_radio_set_telemetry"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2552360"></a>ao_radio_set_telemetry</h2></div></div></div><pre class="programlisting"> + void + ao_radio_set_telemetry(void); + </pre><p> + Configures the radio to send or receive telemetry + packets. This includes packet length, modulation scheme and + other RF parameters. It does not include the base frequency + or channel though. Those are set at the time of transmission + or reception, in case the values are changed by the user. + </p></div><div class="section" title="ao_radio_set_packet"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2581777"></a>ao_radio_set_packet</h2></div></div></div><pre class="programlisting"> + void + ao_radio_set_packet(void); + </pre><p> + Configures the radio to send or receive packet data. This + includes packet length, modulation scheme and other RF + parameters. It does not include the base frequency or + channel though. Those are set at the time of transmission or + reception, in case the values are changed by the user. + </p></div><div class="section" title="ao_radio_set_rdf"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2585369"></a>ao_radio_set_rdf</h2></div></div></div><pre class="programlisting"> + void + ao_radio_set_rdf(void); + </pre><p> + Configures the radio to send RDF 'packets'. An RDF 'packet' + is a sequence of hex 0x55 bytes sent at a base bit rate of + 2kbps using a 5kHz deviation. All of the error correction + and data whitening logic is turned off so that the resulting + modulation is received as a 1kHz tone by a conventional 70cm + FM audio receiver. + </p></div><div class="section" title="ao_radio_idle"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2573544"></a>ao_radio_idle</h2></div></div></div><pre class="programlisting"> + void + ao_radio_idle(void); + </pre><p> + Sets the radio device to idle mode, waiting until it reaches + that state. This will terminate any in-progress transmit or + receive operation. + </p></div><div class="section" title="ao_radio_get"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2551519"></a>ao_radio_get</h2></div></div></div><pre class="programlisting"> + void + ao_radio_get(void); + </pre><p> + Acquires the radio mutex and then configures the radio + frequency using the global radio calibration and channel + values. + </p></div><div class="section" title="ao_radio_put"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2586346"></a>ao_radio_put</h2></div></div></div><pre class="programlisting"> + void + ao_radio_put(void); + </pre><p> + Releases the radio mutex. + </p></div><div class="section" title="ao_radio_abort"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2590004"></a>ao_radio_abort</h2></div></div></div><pre class="programlisting"> + void + ao_radio_abort(void); + </pre><p> + Aborts any transmission or reception process by aborting the + associated DMA object and calling ao_radio_idle to terminate + the radio operation. + </p></div><p> + In telemetry mode, you can send or receive a telemetry + packet. The data from receiving a packet also includes the RSSI + and status values supplied by the receiver. These are added + after the telemetry data. + </p><div class="section" title="ao_radio_send"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2565052"></a>ao_radio_send</h2></div></div></div><pre class="programlisting"> + void + ao_radio_send(__xdata struct ao_telemetry *telemetry); + </pre><p> + This sends the specific telemetry packet, waiting for the + transmission to complete. The radio must have been set to + telemetry mode. This function calls ao_radio_get() before + sending, and ao_radio_put() afterwards, to correctly + serialize access to the radio device. + </p></div><div class="section" title="ao_radio_recv"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2569083"></a>ao_radio_recv</h2></div></div></div><pre class="programlisting"> + void + ao_radio_recv(__xdata struct ao_radio_recv *radio); + </pre><p> + This blocks waiting for a telemetry packet to be received. + The radio must have been set to telemetry mode. This + function calls ao_radio_get() before receiving, and + ao_radio_put() afterwards, to correctly serialize access + to the radio device. This returns non-zero if a packet was + received, or zero if the operation was aborted (from some + other task calling ao_radio_abort()). + </p></div><p> + In radio direction finding mode, there's just one function to + use + </p><div class="section" title="ao_radio_rdf"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2583861"></a>ao_radio_rdf</h2></div></div></div><pre class="programlisting"> + void + ao_radio_rdf(int ms); + </pre><p> + This sends an RDF packet lasting for the specified amount + of time. The maximum length is 1020 ms. + </p></div><p> + Packet mode is asymmetrical and is configured at compile time + for either master or slave mode (but not both). The basic I/O + functions look the same at both ends, but the internals are + different, along with the initialization steps. + </p><div class="section" title="ao_packet_putchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2590408"></a>ao_packet_putchar</h2></div></div></div><pre class="programlisting"> + void + ao_packet_putchar(char c); + </pre><p> + If the output queue is full, this first blocks waiting for + that data to be delivered. Then, queues a character for + packet transmission. On the master side, this will + transmit a packet if the output buffer is full. On the + slave side, any pending data will be sent the next time + the master polls for data. + </p></div><div class="section" title="ao_packet_pollchar"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2587711"></a>ao_packet_pollchar</h2></div></div></div><pre class="programlisting"> + char + ao_packet_pollchar(void); + </pre><p> + This returns a pending input character if available, + otherwise returns AO_READ_AGAIN. On the master side, if + this empties the buffer, it triggers a poll for more data. + </p></div><div class="section" title="ao_packet_slave_start"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2590396"></a>ao_packet_slave_start</h2></div></div></div><pre class="programlisting"> + void + ao_packet_slave_start(void); + </pre><p> + This is available only on the slave side and starts a task + to listen for packet data. + </p></div><div class="section" title="ao_packet_slave_stop"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2563331"></a>ao_packet_slave_stop</h2></div></div></div><pre class="programlisting"> + void + ao_packet_slave_stop(void); + </pre><p> + Disables the packet slave task, stopping the radio receiver. + </p></div><div class="section" title="ao_packet_slave_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2562720"></a>ao_packet_slave_init</h2></div></div></div><pre class="programlisting"> + void + ao_packet_slave_init(void); + </pre><p> + Adds the packet stdio functions to the stdio package so + that when packet slave mode is enabled, characters will + get send and received through the stdio functions. + </p></div><div class="section" title="ao_packet_master_init"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2574661"></a>ao_packet_master_init</h2></div></div></div><pre class="programlisting"> + void + ao_packet_master_init(void); + </pre><p> + Adds the 'p' packet forward command to start packet mode. + </p></div></div></div></body></html> |