diff options
author | Bdale Garbee <bdale@gag.com> | 2017-12-21 19:50:56 -0700 |
---|---|---|
committer | Bdale Garbee <bdale@gag.com> | 2017-12-21 19:50:56 -0700 |
commit | e28ff195f95038471b14a8d1dc641b65ea365f5a (patch) | |
tree | d06ae1118f46cbbb6be47b36635055ee6698d88b /AltOS/doc/altos.html | |
parent | 6dd7e1afeae8d166373e47a627a9bd4b361462ec (diff) |
update docs
Diffstat (limited to 'AltOS/doc/altos.html')
-rw-r--r-- | AltOS/doc/altos.html | 1629 |
1 files changed, 630 insertions, 999 deletions
diff --git a/AltOS/doc/altos.html b/AltOS/doc/altos.html index 421fb2e..7ca6a09 100644 --- a/AltOS/doc/altos.html +++ b/AltOS/doc/altos.html @@ -1,1004 +1,635 @@ -<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.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302637457168"></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"><a name="idm46302611036384"></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 style="border-style:solid; width:100%;" summary="Revision History"><tr><th align="left" valign="top" colspan="2"><b>Revision History</b></th></tr><tr><td align="left">Revision 1.1</td><td align="left">05 November 2012</td></tr><tr><td align="left" colspan="2">Portable version</td></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 class="toc"><dt><span class="chapter"><a href="#idm46302610177888">1. Overview</a></span></dt><dt><span class="chapter"><a href="#idm46302610940496">2. AltOS Porting Layer</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302610938992">1. Low-level CPU operations</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302610937760">1.1. ao_arch_block_interrupts/ao_arch_release_interrupts</a></span></dt><dt><span class="section"><a href="#idm46302610935712">1.2. ao_arch_save_regs, ao_arch_save_stack, - ao_arch_restore_stack</a></span></dt><dt><span class="section"><a href="#idm46302610933424">1.3. ao_arch_wait_interupt</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302610930880">2. GPIO operations</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302610929712">2.1. GPIO setup</a></span></dt><dt><span class="section"><a href="#idm46302611109712">2.2. Reading and writing GPIO pins</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#idm46302611104464">3. Programming the 8051 with SDCC</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611102368">1. 8051 memory spaces</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611100432">1.1. __data</a></span></dt><dt><span class="section"><a href="#idm46302611098256">1.2. __idata</a></span></dt><dt><span class="section"><a href="#idm46302611096816">1.3. __xdata</a></span></dt><dt><span class="section"><a href="#idm46302611095408">1.4. __pdata</a></span></dt><dt><span class="section"><a href="#idm46302611093904">1.5. __code</a></span></dt><dt><span class="section"><a href="#idm46302611092464">1.6. __bit</a></span></dt><dt><span class="section"><a href="#idm46302611090960">1.7. __sfr, __sfr16, __sfr32, __sbit</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302611089424">2. Function calls on the 8051</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611087952">2.1. __reentrant functions</a></span></dt><dt><span class="section"><a href="#idm46302611085760">2.2. Non __reentrant functions</a></span></dt><dt><span class="section"><a href="#idm46302611083616">2.3. __interrupt functions</a></span></dt><dt><span class="section"><a href="#idm46302611082048">2.4. __critical functions and statements</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#idm46302611079984">4. Task functions</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611078928">1. ao_add_task</a></span></dt><dt><span class="section"><a href="#idm46302611076672">2. ao_exit</a></span></dt><dt><span class="section"><a href="#idm46302605188160">3. ao_sleep</a></span></dt><dt><span class="section"><a href="#idm46302605184560">4. ao_wakeup</a></span></dt><dt><span class="section"><a href="#idm46302605181568">5. ao_alarm</a></span></dt><dt><span class="section"><a href="#idm46302605178288">6. ao_start_scheduler</a></span></dt><dt><span class="section"><a href="#idm46302605176320">7. ao_clock_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605174224">5. Timer Functions</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605172720">1. ao_time</a></span></dt><dt><span class="section"><a href="#idm46302605170688">2. ao_delay</a></span></dt><dt><span class="section"><a href="#idm46302605168768">3. ao_timer_set_adc_interval</a></span></dt><dt><span class="section"><a href="#idm46302605166640">4. ao_timer_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605164448">6. AltOS Mutexes</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605162576">1. ao_mutex_get</a></span></dt><dt><span class="section"><a href="#idm46302605160736">2. ao_mutex_put</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605158672">7. DMA engine</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605155232">1. CC1111 DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605154560">1.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#idm46302605152384">1.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605150112">1.3. ao_dma_start</a></span></dt><dt><span class="section"><a href="#idm46302605148096">1.4. ao_dma_trigger</a></span></dt><dt><span class="section"><a href="#idm46302605146176">1.5. ao_dma_abort</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605144032">2. STM32L DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605143360">2.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#idm46302605141360">2.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605139104">2.3. ao_dma_set_isr</a></span></dt><dt><span class="section"><a href="#idm46302605136944">2.4. ao_dma_start</a></span></dt><dt><span class="section"><a href="#idm46302605134640">2.5. ao_dma_done_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605132656">2.6. ao_dma_abort</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#idm46302605130384">8. Stdio interface</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605128880">1. putchar</a></span></dt><dt><span class="section"><a href="#idm46302605126912">2. getchar</a></span></dt><dt><span class="section"><a href="#idm46302605124816">3. flush</a></span></dt><dt><span class="section"><a href="#idm46302605122784">4. ao_add_stdio</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605118752">9. Command line interface</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605117344">1. ao_cmd_register</a></span></dt><dt><span class="section"><a href="#idm46302605108608">2. ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#idm46302605106528">3. ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#idm46302605104688">4. ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#idm46302605102800">5. ao_cmd_white</a></span></dt><dt><span class="section"><a href="#idm46302605100736">6. ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#idm46302605098688">7. ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#idm46302605096592">8. ao_match_word</a></span></dt><dt><span class="section"><a href="#idm46302605094512">9. ao_cmd_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605092288">10. USB target device</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605090064">1. ao_usb_flush</a></span></dt><dt><span class="section"><a href="#idm46302605087920">2. ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605085744">3. ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#idm46302605083600">4. ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#idm46302605081584">5. ao_usb_disable</a></span></dt><dt><span class="section"><a href="#idm46302605078752">6. ao_usb_enable</a></span></dt><dt><span class="section"><a href="#idm46302605076640">7. ao_usb_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605074416">11. Serial peripherals</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605072400">1. ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#idm46302605070368">2. ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605068400">3. ao_serial_drain</a></span></dt><dt><span class="section"><a href="#idm46302605066400">4. ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#idm46302605064368">5. ao_serial_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#idm46302605062176">12. CC1111 Radio peripheral</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605061504">1. Radio Introduction</a></span></dt><dt><span class="section"><a href="#idm46302605054896">2. ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#idm46302605052800">3. ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#idm46302605050704">4. ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#idm46302605048576">5. ao_radio_idle</a></span></dt><dt><span class="section"><a href="#idm46302605046640">6. ao_radio_get</a></span></dt><dt><span class="section"><a href="#idm46302605044720">7. ao_radio_put</a></span></dt><dt><span class="section"><a href="#idm46302605042944">8. ao_radio_abort</a></span></dt><dt><span class="section"><a href="#idm46302605040992">9. Radio Telemetry</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605039728">9.1. ao_radio_send</a></span></dt><dt><span class="section"><a href="#idm46302605037568">9.2. ao_radio_recv</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605035168">10. Radio Direction Finding</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605034048">10.1. ao_radio_rdf</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605032016">11. Radio Packet Mode</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605030736">11.1. ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605028624">11.2. ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#idm46302605026656">11.3. ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#idm46302605024768">11.4. ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#idm46302605022912">11.5. ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#idm46302605020944">11.6. ao_packet_master_init</a></span></dt></dl></dd></dl></dd></dl></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302610177888"></a>Chapter 1. Overview</h1></div></div></div><p> - AltOS is a operating system built for a variety of - microcontrollers used in Altus Metrum devices. It has a simple - porting layer for each CPU while providing a convenient - operating enviroment for the developer. AltOS currently - supports three different CPUs: - </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p> - STM32L series from ST Microelectronics. This ARM Cortex-M3 - based microcontroller offers low power consumption and a - wide variety of built-in peripherals. Altus Metrum uses - this in the TeleMega, MegaDongle and TeleLCO projects. - </p></li><li class="listitem"><p> - CC1111 from Texas Instruments. This device includes a - fabulous 10mW digital RF transceiver along with an - 8051-compatible processor core and a range of - peripherals. This is used in the TeleMetrum, TeleMini, - TeleDongle and TeleFire projects which share the need for - a small microcontroller and an RF interface. - </p></li><li class="listitem"><p> - ATmega32U4 from Atmel. This 8-bit AVR microcontroller is - one of the many used to create Arduino boards. The 32U4 - includes a USB interface, making it easy to connect to - other computers. Altus Metrum used this in prototypes of - the TeleScience and TelePyro boards; those have been - switched to the STM32L which is more capable and cheaper. - </p></li></ul></div><p> - Among the features of AltOS are: - </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>Multi-tasking. While microcontrollers often don'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(); +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>AltOS</title><link rel="stylesheet" type="text/css" href="am.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /></head><body><div xml:lang="en" class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a id="idm1"></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><code class="email"><<a class="email" href="mailto:keithp@keithp.com">keithp@keithp.com</a>></code></div></div><div><p class="copyright">Copyright © 2012 Keith Packard</p></div><div><div class="legalnotice"><a id="idm13"></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><a href="altos-revhistory.html">Revision History</a></div></div><hr /></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="chapter"><a href="#_overview">1. Overview</a></span></dt><dt><span class="chapter"><a href="#_altos_porting_layer">2. AltOS Porting Layer</a></span></dt><dd><dl><dt><span class="section"><a href="#_low_level_cpu_operations">2.1. Low-level CPU operations</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_arch_block_interrupts_ao_arch_release_interrupts">2.1.1. ao_arch_block_interrupts/ao_arch_release_interrupts</a></span></dt><dt><span class="section"><a href="#_ao_arch_save_regs_ao_arch_save_stack_ao_arch_restore_stack">2.1.2. ao_arch_save_regs, ao_arch_save_stack, ao_arch_restore_stack</a></span></dt><dt><span class="section"><a href="#_ao_arch_wait_interupt">2.1.3. ao_arch_wait_interupt</a></span></dt></dl></dd><dt><span class="section"><a href="#_gpio_operations">2.2. GPIO operations</a></span></dt><dd><dl><dt><span class="section"><a href="#_gpio_setup">2.2.1. GPIO setup</a></span></dt><dt><span class="section"><a href="#_reading_and_writing_gpio_pins">2.2.2. Reading and writing GPIO pins</a></span></dt></dl></dd><dt><span class="section"><a href="#_8051_memory_spaces">2.3. 8051 memory spaces</a></span></dt><dd><dl><dt><span class="section"><a href="#_data">2.3.1. __data</a></span></dt><dt><span class="section"><a href="#_idata">2.3.2. __idata</a></span></dt><dt><span class="section"><a href="#_xdata">2.3.3. __xdata</a></span></dt><dt><span class="section"><a href="#_pdata">2.3.4. __pdata</a></span></dt><dt><span class="section"><a href="#_code">2.3.5. __code</a></span></dt><dt><span class="section"><a href="#_bit">2.3.6. __bit</a></span></dt><dt><span class="section"><a href="#_emphasis_sfr_emphasis_sfr16_emphasis_sfr32_emphasis_sbit">2.3.7. <span class="emphasis"><em>sfr, </em></span>sfr16, <span class="emphasis"><em>sfr32, </em></span>sbit</a></span></dt></dl></dd><dt><span class="section"><a href="#_function_calls_on_the_8051">2.4. Function calls on the 8051</a></span></dt><dd><dl><dt><span class="section"><a href="#_reentrant_functions">2.4.1. __reentrant functions</a></span></dt><dt><span class="section"><a href="#_non___reentrant_functions">2.4.2. Non __reentrant functions</a></span></dt><dt><span class="section"><a href="#_interrupt_functions">2.4.3. __interrupt functions</a></span></dt><dt><span class="section"><a href="#_critical_functions_and_statements">2.4.4. __critical functions and statements</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#_task_functions">3. Task functions</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_add_task">3.1. ao_add_task</a></span></dt><dt><span class="section"><a href="#_ao_exit">3.2. ao_exit</a></span></dt><dt><span class="section"><a href="#_ao_sleep">3.3. ao_sleep</a></span></dt><dt><span class="section"><a href="#_ao_wakeup">3.4. ao_wakeup</a></span></dt><dt><span class="section"><a href="#_ao_alarm">3.5. ao_alarm</a></span></dt><dt><span class="section"><a href="#_ao_start_scheduler">3.6. ao_start_scheduler</a></span></dt><dt><span class="section"><a href="#_ao_clock_init">3.7. ao_clock_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_timer_functions">4. Timer Functions</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_time">4.1. ao_time</a></span></dt><dt><span class="section"><a href="#_ao_delay">4.2. ao_delay</a></span></dt><dt><span class="section"><a href="#_ao_timer_set_adc_interval">4.3. ao_timer_set_adc_interval</a></span></dt><dt><span class="section"><a href="#_ao_timer_init">4.4. ao_timer_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_altos_mutexes">5. AltOS Mutexes</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_mutex_get">5.1. ao_mutex_get</a></span></dt><dt><span class="section"><a href="#_ao_mutex_put">5.2. ao_mutex_put</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_dma_engine">6. DMA engine</a></span></dt><dd><dl><dt><span class="section"><a href="#_cc1111_dma_engine">6.1. CC1111 DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_dma_alloc">6.1.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#_ao_dma_set_transfer">6.1.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#_ao_dma_start">6.1.3. ao_dma_start</a></span></dt><dt><span class="section"><a href="#_ao_dma_trigger">6.1.4. ao_dma_trigger</a></span></dt><dt><span class="section"><a href="#_ao_dma_abort">6.1.5. ao_dma_abort</a></span></dt></dl></dd><dt><span class="section"><a href="#_stm32l_dma_engine">6.2. STM32L DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_dma_alloc_2">6.2.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#_ao_dma_set_transfer_2">6.2.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#_ao_dma_set_isr">6.2.3. ao_dma_set_isr</a></span></dt><dt><span class="section"><a href="#_ao_dma_start_2">6.2.4. ao_dma_start</a></span></dt><dt><span class="section"><a href="#_ao_dma_done_transfer">6.2.5. ao_dma_done_transfer</a></span></dt><dt><span class="section"><a href="#_ao_dma_abort_2">6.2.6. ao_dma_abort</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#_stdio_interface">7. Stdio interface</a></span></dt><dd><dl><dt><span class="section"><a href="#_putchar">7.1. putchar</a></span></dt><dt><span class="section"><a href="#_getchar">7.2. getchar</a></span></dt><dt><span class="section"><a href="#_flush">7.3. flush</a></span></dt><dt><span class="section"><a href="#_ao_add_stdio">7.4. ao_add_stdio</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_command_line_interface">8. Command line interface</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_cmd_register">8.1. ao_cmd_register</a></span></dt><dt><span class="section"><a href="#_ao_cmd_lex">8.2. ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#_ao_cmd_put16">8.3. ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#_ao_cmd_put8">8.4. ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#_ao_cmd_white">8.5. ao_cmd_white</a></span></dt><dt><span class="section"><a href="#_ao_cmd_hex">8.6. ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#_ao_cmd_decimal">8.7. ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#_ao_match_word">8.8. ao_match_word</a></span></dt><dt><span class="section"><a href="#_ao_cmd_init">8.9. ao_cmd_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_usb_target_device">9. USB target device</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_usb_flush">9.1. ao_usb_flush</a></span></dt><dt><span class="section"><a href="#_ao_usb_putchar">9.2. ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#_ao_usb_pollchar">9.3. ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#_ao_usb_getchar">9.4. ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#_ao_usb_disable">9.5. ao_usb_disable</a></span></dt><dt><span class="section"><a href="#_ao_usb_enable">9.6. ao_usb_enable</a></span></dt><dt><span class="section"><a href="#_ao_usb_init">9.7. ao_usb_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_serial_peripherals">10. Serial peripherals</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_serial_getchar">10.1. ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#_ao_serial_putchar">10.2. ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#_ao_serial_drain">10.3. ao_serial_drain</a></span></dt><dt><span class="section"><a href="#_ao_serial_set_speed">10.4. ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#_ao_serial_init">10.5. ao_serial_init</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_cc1111_cc1120_cc1200_radio_peripheral">11. CC1111/CC1120/CC1200 Radio peripheral</a></span></dt><dd><dl><dt><span class="section"><a href="#_radio_introduction">11.1. Radio Introduction</a></span></dt><dt><span class="section"><a href="#_ao_radio_set_telemetry">11.2. ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#_ao_radio_set_packet">11.3. ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#_ao_radio_set_rdf">11.4. ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#_ao_radio_idle">11.5. ao_radio_idle</a></span></dt><dt><span class="section"><a href="#_ao_radio_get">11.6. ao_radio_get</a></span></dt><dt><span class="section"><a href="#_ao_radio_put">11.7. ao_radio_put</a></span></dt><dt><span class="section"><a href="#_ao_radio_abort">11.8. ao_radio_abort</a></span></dt><dt><span class="section"><a href="#_radio_telemetry">11.9. Radio Telemetry</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_radio_send">11.9.1. ao_radio_send</a></span></dt><dt><span class="section"><a href="#_ao_radio_recv">11.9.2. ao_radio_recv</a></span></dt></dl></dd><dt><span class="section"><a href="#_radio_direction_finding">11.10. Radio Direction Finding</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_radio_rdf">11.10.1. ao_radio_rdf</a></span></dt></dl></dd><dt><span class="section"><a href="#_radio_packet_mode">11.11. Radio Packet Mode</a></span></dt><dd><dl><dt><span class="section"><a href="#_ao_packet_putchar">11.11.1. ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#_ao_packet_pollchar">11.11.2. ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#_ao_packet_slave_start">11.11.3. ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#_ao_packet_slave_stop">11.11.4. ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#_ao_packet_slave_init">11.11.5. ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#_ao_packet_master_init">11.11.6. ao_packet_master_init</a></span></dt></dl></dd></dl></dd></dl></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_overview"></a>Chapter 1. Overview</h1></div></div></div><p>AltOS is a operating system built for a variety of +microcontrollers used in Altus Metrum devices. It has a simple +porting layer for each CPU while providing a convenient +operating enviroment for the developer. AltOS currently +supports three different CPUs:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> +STM32L series from ST Microelectronics. This ARM Cortex-M3 +based microcontroller offers low power consumption and a +wide variety of built-in peripherals. Altus Metrum uses this +in the TeleMega, MegaDongle and TeleLCO projects. +</li><li class="listitem"> +CC1111 from Texas Instruments. This device includes a +fabulous 10mW digital RF transceiver along with an +8051-compatible processor core and a range of +peripherals. This is used in the TeleMetrum, TeleMini, +TeleDongle and TeleFire projects which share the need for a +small microcontroller and an RF interface. +</li><li class="listitem"> +ATmega32U4 from Atmel. This 8-bit AVR microcontroller is one +of the many used to create Arduino boards. The 32U4 includes +a USB interface, making it easy to connect to other +computers. Altus Metrum used this in prototypes of the +TeleScience and TelePyro boards; those have been switched to +the STM32L which is more capable and cheaper. +</li></ul></div><p>Among the features of AltOS are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> +Multi-tasking. While microcontrollers often don’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. +</li><li class="listitem"> +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. +</li><li class="listitem"> +Sleep/wakeup scheduling. Taken directly from ancient +Unix designs, these two provide the fundemental scheduling +primitive within AltOS. +</li><li class="listitem"> +Mutexes. As a locking primitive, mutexes are easier to +use than semaphores, at least in my experience. +</li><li class="listitem"> +Timers. Tasks can set an alarm which will abort any +pending sleep, allowing operations to time-out instead of +blocking forever. +</li></ul></div><p>The device drivers and other subsystems in AltOS are +conventionally enabled by invoking their _init() function from +the <span class="emphasis"><em>main</em></span> 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="literallayout">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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302610940496"></a>Chapter 2. AltOS Porting Layer</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302610938992">1. Low-level CPU operations</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302610937760">1.1. ao_arch_block_interrupts/ao_arch_release_interrupts</a></span></dt><dt><span class="section"><a href="#idm46302610935712">1.2. ao_arch_save_regs, ao_arch_save_stack, - ao_arch_restore_stack</a></span></dt><dt><span class="section"><a href="#idm46302610933424">1.3. ao_arch_wait_interupt</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302610930880">2. GPIO operations</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302610929712">2.1. GPIO setup</a></span></dt><dt><span class="section"><a href="#idm46302611109712">2.2. Reading and writing GPIO pins</a></span></dt></dl></dd></dl></div><p> - AltOS provides a CPU-independent interface to various common - microcontroller subsystems, including GPIO pins, interrupts, - SPI, I2C, USB and asynchronous serial interfaces. By making - these CPU-independent, device drivers, generic OS and - application code can all be written that work on any supported - CPU. Many of the architecture abstraction interfaces are - prefixed with ao_arch. - </p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302610938992"></a>1. Low-level CPU operations</h2></div></div></div><p> - These primitive operations provide the abstraction needed to - run the multi-tasking framework while providing reliable - interrupt delivery. - </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302610937760"></a>1.1. ao_arch_block_interrupts/ao_arch_release_interrupts</h3></div></div></div><pre class="programlisting"> - static inline void - ao_arch_block_interrupts(void); - - static inline void - ao_arch_release_interrupts(void); - </pre><p> - These disable/enable interrupt delivery, they may not - discard any interrupts. Use these for sections of code that - must be atomic with respect to any code run from an - interrupt handler. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302610935712"></a>1.2. ao_arch_save_regs, ao_arch_save_stack, - ao_arch_restore_stack</h3></div></div></div><pre class="programlisting"> - static inline void - ao_arch_save_regs(void); + /* 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"><div class="titlepage"><div><div><h1 class="title"><a id="_altos_porting_layer"></a>Chapter 2. AltOS Porting Layer</h1></div></div></div><p>AltOS provides a CPU-independent interface to various common +microcontroller subsystems, including GPIO pins, interrupts, +SPI, I2C, USB and asynchronous serial interfaces. By making +these CPU-independent, device drivers, generic OS and +application code can all be written that work on any supported +CPU. Many of the architecture abstraction interfaces are +prefixed with ao_arch.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_low_level_cpu_operations"></a>2.1. Low-level CPU operations</h2></div></div></div><p>These primitive operations provide the abstraction needed to +run the multi-tasking framework while providing reliable +interrupt delivery.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_arch_block_interrupts_ao_arch_release_interrupts"></a>2.1.1. ao_arch_block_interrupts/ao_arch_release_interrupts</h3></div></div></div><pre class="literallayout">static inline void +ao_arch_block_interrupts(void); - static inline void - ao_arch_save_stack(void); +static inline void +ao_arch_release_interrupts(void);</pre><p>These disable/enable interrupt delivery, they may not +discard any interrupts. Use these for sections of code that +must be atomic with respect to any code run from an +interrupt handler.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_arch_save_regs_ao_arch_save_stack_ao_arch_restore_stack"></a>2.1.2. ao_arch_save_regs, ao_arch_save_stack, ao_arch_restore_stack</h3></div></div></div><pre class="literallayout">static inline void +ao_arch_save_regs(void); - static inline void - ao_arch_restore_stack(void); - </pre><p> - These provide all of the support needed to switch between - tasks.. ao_arch_save_regs must save all CPU registers to the - current stack, including the interrupt enable - state. ao_arch_save_stack records the current stack location - in the current ao_task structure. ao_arch_restore_stack - switches back to the saved stack, restores all registers and - branches to the saved return address. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302610933424"></a>1.3. ao_arch_wait_interupt</h3></div></div></div><pre class="programlisting"> - #define ao_arch_wait_interrupt() - </pre><p> - This stops the CPU, leaving clocks and interrupts - enabled. When an interrupt is received, this must wake up - and handle the interrupt. ao_arch_wait_interrupt is entered - with interrupts disabled to ensure that there is no gap - between determining that no task wants to run and idling the - CPU. It must sleep the CPU, process interrupts and then - disable interrupts again. If the CPU doesn't have any - reduced power mode, this must at the least allow pending - interrupts to be processed. - </p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302610930880"></a>2. GPIO operations</h2></div></div></div><p> - These functions provide an abstract interface to configure and - manipulate GPIO pins. - </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302610929712"></a>2.1. GPIO setup</h3></div></div></div><p> - These macros may be invoked at system initialization time to - configure pins as needed for system operation. One tricky - aspect is that some chips provide direct access to specific - GPIO pins while others only provide access to a whole - register full of pins. To support this, the GPIO macros - provide both port+bit and pin arguments. Simply define the - arguments needed for the target platform and leave the - others undefined. - </p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idm46302610927744"></a>2.1.1. ao_enable_output</h4></div></div></div><pre class="programlisting"> - #define ao_enable_output(port, bit, pin, value) - </pre><p> - Set the specified port+bit (also called 'pin') for output, - initializing to the specified value. The macro must avoid - driving the pin with the opposite value if at all - possible. - </p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idm46302611115152"></a>2.1.2. ao_enable_input</h4></div></div></div><pre class="programlisting"> - #define ao_enable_input(port, bit, mode) - </pre><p> - Sets the specified port/bit to be an input pin. 'mode' is - a combination of one or more of the following. Note that - some platforms may not support the desired mode. In that - case, the value will not be defined so that the program - will fail to compile. - </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p> - AO_EXTI_MODE_PULL_UP. Apply a pull-up to the pin; a - disconnected pin will read as 1. -</p></li><li class="listitem"><p> - AO_EXTI_MODE_PULL_DOWN. Apply a pull-down to the pin; - a disconnected pin will read as 0. -</p></li><li class="listitem"><p> - 0. Don't apply either a pull-up or pull-down. A - disconnected pin will read an undetermined value. -</p></li></ul></div><p> - </p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611109712"></a>2.2. Reading and writing GPIO pins</h3></div></div></div><p> - These macros read and write individual GPIO pins. - </p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idm46302611108640"></a>2.2.1. ao_gpio_set</h4></div></div></div><pre class="programlisting"> - #define ao_gpio_set(port, bit, pin, value) - </pre><p> - Sets the specified port/bit or pin to the indicated value - </p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idm46302611106800"></a>2.2.2. ao_gpio_get</h4></div></div></div><pre class="programlisting"> - #define ao_gpio_get(port, bit, pin) - </pre><p> - Returns either 1 or 0 depending on whether the input to - the pin is high or low. - </p></div></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302611104464"></a>Chapter 3. Programming the 8051 with SDCC</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302611102368">1. 8051 memory spaces</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611100432">1.1. __data</a></span></dt><dt><span class="section"><a href="#idm46302611098256">1.2. __idata</a></span></dt><dt><span class="section"><a href="#idm46302611096816">1.3. __xdata</a></span></dt><dt><span class="section"><a href="#idm46302611095408">1.4. __pdata</a></span></dt><dt><span class="section"><a href="#idm46302611093904">1.5. __code</a></span></dt><dt><span class="section"><a href="#idm46302611092464">1.6. __bit</a></span></dt><dt><span class="section"><a href="#idm46302611090960">1.7. __sfr, __sfr16, __sfr32, __sbit</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302611089424">2. Function calls on the 8051</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302611087952">2.1. __reentrant functions</a></span></dt><dt><span class="section"><a href="#idm46302611085760">2.2. Non __reentrant functions</a></span></dt><dt><span class="section"><a href="#idm46302611083616">2.3. __interrupt functions</a></span></dt><dt><span class="section"><a href="#idm46302611082048">2.4. __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><p> - When built on other architectures, the various SDCC-specific - symbols are #defined as empty strings so they don't affect the compiler. - </p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302611102368"></a>1. 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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611100432"></a>1.1. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611098256"></a>1.2. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611096816"></a>1.3. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611095408"></a>1.4. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611093904"></a>1.5. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611092464"></a>1.6. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611090960"></a>1.7. __sfr, __sfr16, __sfr32, __sbit</h3></div></div></div><p> - Access to physical registers in the device use this mode - which declares the variable name, its type and the - address it lives at. No memory is allocated for these - variables. - </p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302611089424"></a>2. 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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611087952"></a>2.1. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611085760"></a>2.2. 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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611083616"></a>2.3. __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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302611082048"></a>2.4. __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. AltOS doesn't use this form in shared - code as other compilers wouldn't know what to do. Use - ao_arch_block_interrupts and ao_arch_release_interrupts instead. - </p></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302611079984"></a>Chapter 4. Task functions</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302611078928">1. ao_add_task</a></span></dt><dt><span class="section"><a href="#idm46302611076672">2. ao_exit</a></span></dt><dt><span class="section"><a href="#idm46302605188160">3. ao_sleep</a></span></dt><dt><span class="section"><a href="#idm46302605184560">4. ao_wakeup</a></span></dt><dt><span class="section"><a href="#idm46302605181568">5. ao_alarm</a></span></dt><dt><span class="section"><a href="#idm46302605178288">6. ao_start_scheduler</a></span></dt><dt><span class="section"><a href="#idm46302605176320">7. ao_clock_init</a></span></dt></dl></div><p> - This chapter documents how to create, destroy and schedule AltOS tasks. - </p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302611078928"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302611076672"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605188160"></a>3. 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 around the block of code. Here's a complete - example: - </p><pre class="programlisting"> - ao_arch_block_interrupts(); - while (!ao_radio_done) - ao_sleep(&ao_radio_done); - ao_arch_release_interrupts(); - </pre><p> - </p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605184560"></a>4. 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 block interrupts 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605181568"></a>5. ao_alarm</h2></div></div></div><pre class="programlisting"> - void - ao_alarm(uint16_t delay); +static inline void +ao_arch_save_stack(void); - void - ao_clear_alarm(void); - </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. ao_clear_alarm resets any pending - alarm so that it doesn't fire at some arbitrary point in the - future. - </p><pre class="programlisting"> - ao_alarm(ao_packet_master_delay); - ao_arch_block_interrupts(); - while (!ao_radio_dma_done) - if (ao_sleep(&ao_radio_dma_done) != 0) - ao_radio_abort(); - ao_arch_release_interrupts(); - ao_clear_alarm(); - </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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605178288"></a>6. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605176320"></a>7. ao_clock_init</h2></div></div></div><pre class="programlisting"> - void - ao_clock_init(void); - </pre><p> - This initializes the main CPU clock and switches to it. - </p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605174224"></a>Chapter 5. Timer Functions</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605172720">1. ao_time</a></span></dt><dt><span class="section"><a href="#idm46302605170688">2. ao_delay</a></span></dt><dt><span class="section"><a href="#idm46302605168768">3. ao_timer_set_adc_interval</a></span></dt><dt><span class="section"><a href="#idm46302605166640">4. ao_timer_init</a></span></dt></dl></div><p> - AltOS sets up one of the CPU 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 sensors to - collect current data readings. Doing this from the ISR ensures - that the values are sampled at a regular rate, independent - of any scheduling jitter. - </p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605172720"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605170688"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605168768"></a>3. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605166640"></a>4. ao_timer_init</h2></div></div></div><pre class="programlisting"> - void - ao_timer_init(void) - </pre><p> - This turns on the 100Hz tick. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605164448"></a>Chapter 6. AltOS Mutexes</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605162576">1. ao_mutex_get</a></span></dt><dt><span class="section"><a href="#idm46302605160736">2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605162576"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605160736"></a>2. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605158672"></a>Chapter 7. DMA engine</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605155232">1. CC1111 DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605154560">1.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#idm46302605152384">1.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605150112">1.3. ao_dma_start</a></span></dt><dt><span class="section"><a href="#idm46302605148096">1.4. ao_dma_trigger</a></span></dt><dt><span class="section"><a href="#idm46302605146176">1.5. ao_dma_abort</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605144032">2. STM32L DMA Engine</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605143360">2.1. ao_dma_alloc</a></span></dt><dt><span class="section"><a href="#idm46302605141360">2.2. ao_dma_set_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605139104">2.3. ao_dma_set_isr</a></span></dt><dt><span class="section"><a href="#idm46302605136944">2.4. ao_dma_start</a></span></dt><dt><span class="section"><a href="#idm46302605134640">2.5. ao_dma_done_transfer</a></span></dt><dt><span class="section"><a href="#idm46302605132656">2.6. ao_dma_abort</a></span></dt></dl></dd></dl></div><p> - The CC1111 and STM32L both contain a useful bit of extra - hardware in the form of a number of 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 both internal and external devices. - </p><p> - Because the CC1111 and STM32L DMA engines are different, the - interface to them is also different. As the DMA engines are - currently used to implement platform-specific drivers, this - isn't yet a problem. - </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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605155232"></a>1. CC1111 DMA Engine</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605154560"></a>1.1. ao_dma_alloc</h3></div></div></div><pre class="programlisting"> - uint8_t - ao_dma_alloc(__xdata uint8_t *done) - </pre><p> - Allocate a DMA engine, returning the identifier. '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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605152384"></a>1.2. ao_dma_set_transfer</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605150112"></a>1.3. ao_dma_start</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605148096"></a>1.4. ao_dma_trigger</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605146176"></a>1.5. ao_dma_abort</h3></div></div></div><pre class="programlisting"> - void - ao_dma_abort(uint8_t id) - </pre><p> - Terminate any in-progress DMA transaction, marking its - 'done' variable with the AO_DMA_ABORTED bit. - </p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605144032"></a>2. STM32L DMA Engine</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605143360"></a>2.1. ao_dma_alloc</h3></div></div></div><pre class="programlisting"> - uint8_t ao_dma_done[]; +static inline void +ao_arch_restore_stack(void);</pre><p>These provide all of the support needed to switch +between tasks.. ao_arch_save_regs must save all CPU +registers to the current stack, including the +interrupt enable state. ao_arch_save_stack records the +current stack location in the current ao_task +structure. ao_arch_restore_stack switches back to the +saved stack, restores all registers and branches to +the saved return address.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_arch_wait_interupt"></a>2.1.3. ao_arch_wait_interupt</h3></div></div></div><pre class="literallayout">#define ao_arch_wait_interrupt()</pre><p>This stops the CPU, leaving clocks and interrupts +enabled. When an interrupt is received, this must wake up +and handle the interrupt. ao_arch_wait_interrupt is entered +with interrupts disabled to ensure that there is no gap +between determining that no task wants to run and idling the +CPU. It must sleep the CPU, process interrupts and then +disable interrupts again. If the CPU doesn’t have any +reduced power mode, this must at the least allow pending +interrupts to be processed.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_gpio_operations"></a>2.2. GPIO operations</h2></div></div></div><p>These functions provide an abstract interface to configure and +manipulate GPIO pins.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_gpio_setup"></a>2.2.1. GPIO setup</h3></div></div></div><p>These macros may be invoked at system +initialization time to configure pins as +needed for system operation. One tricky aspect +is that some chips provide direct access to +specific GPIO pins while others only provide +access to a whole register full of pins. To +support this, the GPIO macros provide both +port+bit and pin arguments. Simply define the +arguments needed for the target platform and +leave the others undefined.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="_ao_enable_output"></a>ao_enable_output</h4></div></div></div><pre class="literallayout">#define ao_enable_output(port, bit, pin, value)</pre><p>Set the specified port+bit (also called <span class="emphasis"><em>pin</em></span>) +for output, initializing to the specified +value. The macro must avoid driving the pin +with the opposite value if at all possible.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="_ao_enable_input"></a>ao_enable_input</h4></div></div></div><pre class="literallayout">#define ao_enable_input(port, bit, mode)</pre><p>Sets the specified port/bit to be an input +pin. <span class="emphasis"><em>mode</em></span> is a combination of one or more of +the following. Note that some platforms may +not support the desired mode. In that case, +the value will not be defined so that the +program will fail to compile.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> +AO_EXTI_MODE_PULL_UP. Apply a pull-up to the +pin; a disconnected pin will read as 1. +</li><li class="listitem"> +AO_EXTI_MODE_PULL_DOWN. Apply a pull-down to +the pin; a disconnected pin will read as 0. +</li><li class="listitem"> +0. Don’t apply either a pull-up or +pull-down. A disconnected pin will read an +undetermined value. +</li></ul></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_reading_and_writing_gpio_pins"></a>2.2.2. Reading and writing GPIO pins</h3></div></div></div><p>These macros read and write individual GPIO pins.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="_ao_gpio_set"></a>ao_gpio_set</h4></div></div></div><pre class="literallayout">#define ao_gpio_set(port, bit, pin, value)</pre><p>Sets the specified port/bit or pin to +the indicated value</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="_ao_gpio_get"></a>ao_gpio_get</h4></div></div></div><pre class="literallayout">#define ao_gpio_get(port, bit, pin)</pre><p>Returns either 1 or 0 depending on +whether the input to the pin is high +or low. +== Programming the 8051 with SDCC</p><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><p>When built on other architectures, the various SDCC-specific +symbols are #defined as empty strings so they don’t affect the +compiler.</p></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_8051_memory_spaces"></a>2.3. 8051 memory spaces</h2></div></div></div><p>The <span class="emphasis"><em>data/</em></span>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 +<span class="emphasis"><em>global</em></span> 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"><div class="titlepage"><div><div><h3 class="title"><a id="_data"></a>2.3.1. __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 <span class="emphasis"><em>bank switch</em></span> 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"><div class="titlepage"><div><div><h3 class="title"><a id="_idata"></a>2.3.2. __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"><div class="titlepage"><div><div><h3 class="title"><a id="_xdata"></a>2.3.3. __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"><div class="titlepage"><div><div><h3 class="title"><a id="_pdata"></a>2.3.4. __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"><div class="titlepage"><div><div><h3 class="title"><a id="_code"></a>2.3.5. __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 <span class="emphasis"><em>code</em></span> +access opcodes. Anything read-only should live in this space.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_bit"></a>2.3.6. __bit</h3></div></div></div><p>The 8051 has 128 bits of bit-addressible memory that +lives in the <span class="emphasis"><em>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 </em></span>data segment.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_emphasis_sfr_emphasis_sfr16_emphasis_sfr32_emphasis_sbit"></a>2.3.7. <span class="emphasis"><em>sfr, </em></span>sfr16, <span class="emphasis"><em>sfr32, </em></span>sbit</h3></div></div></div><p>Access to physical registers in the device use this mode +which declares the variable name, its type and the +address it lives at. No memory is allocated for these +variables.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_function_calls_on_the_8051"></a>2.4. 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"><div class="titlepage"><div><div><h3 class="title"><a id="_reentrant_functions"></a>2.4.1. __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"><div class="titlepage"><div><div><h3 class="title"><a id="_non___reentrant_functions"></a>2.4.2. 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 +<span class="emphasis"><em>xdata, </em></span>pdata or <span class="emphasis"><em>data space as desired. This can avoid +consuming </em></span>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"><div class="titlepage"><div><div><h3 class="title"><a id="_interrupt_functions"></a>2.4.3. __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 <span class="emphasis"><em>reti</em></span> 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"><div class="titlepage"><div><div><h3 class="title"><a id="_critical_functions_and_statements"></a>2.4.4. __critical functions and statements</h3></div></div></div><p>SDCC has built-in support for suspending interrupts during +critical code. Functions marked as <span class="emphasis"><em>critical will have +interrupts suspended for the whole period of +execution. Individual statements may also be marked as +</em></span>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. AltOS doesn’t use this form in shared +code as other compilers wouldn’t know what to do. Use +ao_arch_block_interrupts and ao_arch_release_interrupts instead.</p></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_task_functions"></a>Chapter 3. Task functions</h1></div></div></div><p>This chapter documents how to create, destroy and schedule +AltOS tasks.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_add_task"></a>3.1. ao_add_task</h2></div></div></div><pre class="literallayout">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. <span class="emphasis"><em>start</em></span> must not ever return; there is no place +to return to.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_exit"></a>3.2. ao_exit</h2></div></div></div><pre class="literallayout">void +ao_exit(void)</pre><p>This terminates the current task.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_sleep"></a>3.3. ao_sleep</h2></div></div></div><pre class="literallayout">void +ao_sleep(__xdata void *wchan)</pre><p>This suspends the current task until <span class="emphasis"><em>wchan</em></span> is signaled +by ao_wakeup, or until the timeout, set by ao_alarm, +fires. If <span class="emphasis"><em>wchan</em></span> 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 around the block of code. Here’s a complete +example:</p><pre class="literallayout">ao_arch_block_interrupts(); +while (!ao_radio_done) + ao_sleep(&amp;ao_radio_done); +ao_arch_release_interrupts();</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_wakeup"></a>3.4. ao_wakeup</h2></div></div></div><pre class="literallayout">void +ao_wakeup(__xdata void *wchan)</pre><p>Wake all tasks blocked on <span class="emphasis"><em>wchan</em></span>. 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="literallayout">if (RFIF &amp; RFIF_IM_DONE) { + ao_radio_done = 1; + ao_wakeup(&amp;ao_radio_done); + RFIF &amp;= ~RFIF_IM_DONE; +}</pre><p>Note that this need not block interrupts 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_alarm"></a>3.5. ao_alarm</h2></div></div></div><pre class="literallayout">void +ao_alarm(uint16_t delay); - void - ao_dma_alloc(uint8_t index); - </pre><p> - Reserve a DMA engine for exclusive use by one - driver. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605141360"></a>2.2. ao_dma_set_transfer</h3></div></div></div><pre class="programlisting"> - void - ao_dma_set_transfer(uint8_t id, - void *peripheral, - void *memory, - uint16_t count, - uint32_t ccr); - </pre><p> - Initializes the specified dma engine to copy data between - 'peripheral' and 'memory' for 'count' units. 'ccr' is a - value directly out of the STM32L documentation and tells the - DMA engine what the transfer unit size, direction and step - are. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605139104"></a>2.3. ao_dma_set_isr</h3></div></div></div><pre class="programlisting"> - void - ao_dma_set_isr(uint8_t index, void (*isr)(int)) - </pre><p> - This sets a function to be called when the DMA transfer - completes in lieu of setting the ao_dma_done bits. Use this - when some work needs to be done when the DMA finishes that - cannot wait until user space resumes. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605136944"></a>2.4. ao_dma_start</h3></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. - 'ao_dma_done[index]' 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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605134640"></a>2.5. ao_dma_done_transfer</h3></div></div></div><pre class="programlisting"> - void - ao_dma_done_transfer(uint8_t id); - </pre><p> - Signals that a specific DMA engine is done being used. This - allows multiple drivers to use the same DMA engine safely. - </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605132656"></a>2.6. ao_dma_abort</h3></div></div></div><pre class="programlisting"> - void - ao_dma_abort(uint8_t id) - </pre><p> - Terminate any in-progress DMA transaction, marking its - 'done' variable with the AO_DMA_ABORTED bit. - </p></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605130384"></a>Chapter 8. Stdio interface</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605128880">1. putchar</a></span></dt><dt><span class="section"><a href="#idm46302605126912">2. getchar</a></span></dt><dt><span class="section"><a href="#idm46302605124816">3. flush</a></span></dt><dt><span class="section"><a href="#idm46302605122784">4. ao_add_stdio</a></span></dt></dl></div><p> - AltOS offers a stdio interface over USB, serial and the RF - packet link. This provides for control of the device locally or - remotely. This is hooked up to the stdio functions by providing - the standard putchar/getchar/flush functions. These - automatically multiplex the available communication channels; - output is always delivered to the channel which provided the - most recent input. - </p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605128880"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605126912"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605124816"></a>3. 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. - </p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605122784"></a>4. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605118752"></a>Chapter 9. Command line interface</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605117344">1. ao_cmd_register</a></span></dt><dt><span class="section"><a href="#idm46302605108608">2. ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#idm46302605106528">3. ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#idm46302605104688">4. ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#idm46302605102800">5. ao_cmd_white</a></span></dt><dt><span class="section"><a href="#idm46302605100736">6. ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#idm46302605098688">7. ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#idm46302605096592">8. ao_match_word</a></span></dt><dt><span class="section"><a href="#idm46302605094512">9. 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, serial 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605117344"></a>1. 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 class="variablelist"><dt><span class="term">ao_cmd_success</span></dt><dd><p> - The command was parsed successfully. There is no - need to assign this value, it is the default. - </p></dd><dt><span class="term">ao_cmd_lex_error</span></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><span class="term">ao_syntax_error</span></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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605108608"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605106528"></a>3. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605104688"></a>4. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605102800"></a>5. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605100736"></a>6. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605098688"></a>7. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605096592"></a>8. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605094512"></a>9. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605092288"></a>Chapter 10. USB target device</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605090064">1. ao_usb_flush</a></span></dt><dt><span class="section"><a href="#idm46302605087920">2. ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605085744">3. ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#idm46302605083600">4. ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#idm46302605081584">5. ao_usb_disable</a></span></dt><dt><span class="section"><a href="#idm46302605078752">6. ao_usb_enable</a></span></dt><dt><span class="section"><a href="#idm46302605076640">7. ao_usb_init</a></span></dt></dl></div><p> - AltOS contains a full-speed USB target device driver. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605090064"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605087920"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605085744"></a>3. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605083600"></a>4. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605081584"></a>5. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605078752"></a>6. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605076640"></a>7. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605074416"></a>Chapter 11. Serial peripherals</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605072400">1. ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#idm46302605070368">2. ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605068400">3. ao_serial_drain</a></span></dt><dt><span class="section"><a href="#idm46302605066400">4. ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#idm46302605064368">5. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605072400"></a>1. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605070368"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605068400"></a>3. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605066400"></a>4. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605064368"></a>5. 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"><div class="titlepage"><div><div><h1 class="title"><a name="idm46302605062176"></a>Chapter 12. CC1111 Radio peripheral</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#idm46302605061504">1. Radio Introduction</a></span></dt><dt><span class="section"><a href="#idm46302605054896">2. ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#idm46302605052800">3. ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#idm46302605050704">4. ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#idm46302605048576">5. ao_radio_idle</a></span></dt><dt><span class="section"><a href="#idm46302605046640">6. ao_radio_get</a></span></dt><dt><span class="section"><a href="#idm46302605044720">7. ao_radio_put</a></span></dt><dt><span class="section"><a href="#idm46302605042944">8. ao_radio_abort</a></span></dt><dt><span class="section"><a href="#idm46302605040992">9. Radio Telemetry</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605039728">9.1. ao_radio_send</a></span></dt><dt><span class="section"><a href="#idm46302605037568">9.2. ao_radio_recv</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605035168">10. Radio Direction Finding</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605034048">10.1. ao_radio_rdf</a></span></dt></dl></dd><dt><span class="section"><a href="#idm46302605032016">11. Radio Packet Mode</a></span></dt><dd><dl><dt><span class="section"><a href="#idm46302605030736">11.1. ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#idm46302605028624">11.2. ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#idm46302605026656">11.3. ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#idm46302605024768">11.4. ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#idm46302605022912">11.5. ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#idm46302605020944">11.6. ao_packet_master_init</a></span></dt></dl></dd></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605061504"></a>1. Radio Introduction</h2></div></div></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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605054896"></a>2. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605052800"></a>3. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605050704"></a>4. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605048576"></a>5. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605046640"></a>6. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605044720"></a>7. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605042944"></a>8. 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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605040992"></a>9. Radio Telemetry</h2></div></div></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605039728"></a>9.1. ao_radio_send</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605037568"></a>9.2. ao_radio_recv</h3></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></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605035168"></a>10. Radio Direction Finding</h2></div></div></div><p> - In radio direction finding mode, there's just one function to - use - </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605034048"></a>10.1. ao_radio_rdf</h3></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></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idm46302605032016"></a>11. Radio Packet Mode</h2></div></div></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605030736"></a>11.1. ao_packet_putchar</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605028624"></a>11.2. ao_packet_pollchar</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605026656"></a>11.3. ao_packet_slave_start</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605024768"></a>11.4. ao_packet_slave_stop</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605022912"></a>11.5. ao_packet_slave_init</h3></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"><div class="titlepage"><div><div><h3 class="title"><a name="idm46302605020944"></a>11.6. ao_packet_master_init</h3></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></div></body></html> +void +ao_clear_alarm(void);</pre><p>Schedules an alarm to fire in at least <span class="emphasis"><em>delay</em></span> +ticks. If the task is asleep when the alarm fires, it +will wakeup and ao_sleep will return 1. ao_clear_alarm +resets any pending alarm so that it doesn’t fire at +some arbitrary point in the future.</p><pre class="literallayout">ao_alarm(ao_packet_master_delay); +ao_arch_block_interrupts(); +while (!ao_radio_dma_done) +if (ao_sleep(&amp;ao_radio_dma_done) != 0) +ao_radio_abort(); +ao_arch_release_interrupts(); +ao_clear_alarm();</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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_start_scheduler"></a>3.6. ao_start_scheduler</h2></div></div></div><pre class="literallayout">void +ao_start_scheduler(void);</pre><p>This is called from <span class="emphasis"><em>main</em></span> when the system is all +initialized and ready to run. It will not return.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_clock_init"></a>3.7. ao_clock_init</h2></div></div></div><pre class="literallayout">void +ao_clock_init(void);</pre><p>This initializes the main CPU clock and switches to it.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_timer_functions"></a>Chapter 4. Timer Functions</h1></div></div></div><p>AltOS sets up one of the CPU 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 sensors to +collect current data readings. Doing this from the ISR ensures +that the values are sampled at a regular rate, independent +of any scheduling jitter.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_time"></a>4.1. ao_time</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_delay"></a>4.2. ao_delay</h2></div></div></div><pre class="literallayout">void +ao_delay(uint16_t ticks);</pre><p>Suspend the current task for at least <span class="emphasis"><em>ticks</em></span> clock units.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_timer_set_adc_interval"></a>4.3. ao_timer_set_adc_interval</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_timer_init"></a>4.4. ao_timer_init</h2></div></div></div><pre class="literallayout">void +ao_timer_init(void)</pre><p>This turns on the 100Hz tick. It is required for any of the +time-based functions to work. It should be called by <span class="emphasis"><em>main</em></span> +before ao_start_scheduler.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_altos_mutexes"></a>Chapter 5. AltOS Mutexes</h1></div></div></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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_mutex_get"></a>5.1. ao_mutex_get</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_mutex_put"></a>5.2. ao_mutex_put</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h1 class="title"><a id="_dma_engine"></a>Chapter 6. DMA engine</h1></div></div></div><p>The CC1111 and STM32L both contain a useful bit of extra +hardware in the form of a number of 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 both internal and external devices.</p><p>Because the CC1111 and STM32L DMA engines are different, the +interface to them is also different. As the DMA engines are +currently used to implement platform-specific drivers, this +isn’t yet a problem.</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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_cc1111_dma_engine"></a>6.1. CC1111 DMA Engine</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_alloc"></a>6.1.1. ao_dma_alloc</h3></div></div></div><pre class="literallayout">uint8_t +ao_dma_alloc(__xdata uint8_t *done)</pre><p>Allocate a DMA engine, returning the +identifier. <span class="emphasis"><em>done</em></span> 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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_set_transfer"></a>6.1.2. ao_dma_set_transfer</h3></div></div></div><pre class="literallayout">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 <span class="emphasis"><em>srcaddr</em></span> to <span class="emphasis"><em>dstaddr</em></span> for <span class="emphasis"><em>count</em></span> +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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_start"></a>6.1.3. ao_dma_start</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_trigger"></a>6.1.4. ao_dma_trigger</h3></div></div></div><pre class="literallayout">void +ao_dma_trigger(uint8_t id)</pre><p>Trigger the specified DMA engine to start +copying data.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_abort"></a>6.1.5. ao_dma_abort</h3></div></div></div><pre class="literallayout">void +ao_dma_abort(uint8_t id)</pre><p>Terminate any in-progress DMA transaction, +marking its <span class="emphasis"><em>done</em></span> variable with the +AO_DMA_ABORTED bit.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_stm32l_dma_engine"></a>6.2. STM32L DMA Engine</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_alloc_2"></a>6.2.1. ao_dma_alloc</h3></div></div></div><pre class="literallayout">uint8_t ao_dma_done[]; + +void +ao_dma_alloc(uint8_t index);</pre><p>Reserve a DMA engine for exclusive use by one +driver.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_set_transfer_2"></a>6.2.2. ao_dma_set_transfer</h3></div></div></div><pre class="literallayout">void +ao_dma_set_transfer(uint8_t id, +void *peripheral, +void *memory, +uint16_t count, +uint32_t ccr);</pre><p>Initializes the specified dma engine to copy +data between <span class="emphasis"><em>peripheral</em></span> and <span class="emphasis"><em>memory</em></span> for +<span class="emphasis"><em>count</em></span> units. <span class="emphasis"><em>ccr</em></span> is a value directly out +of the STM32L documentation and tells the DMA +engine what the transfer unit size, direction +and step are.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_set_isr"></a>6.2.3. ao_dma_set_isr</h3></div></div></div><pre class="literallayout">void +ao_dma_set_isr(uint8_t index, void (*isr)(int))</pre><p>This sets a function to be called when the DMA +transfer completes in lieu of setting the +ao_dma_done bits. Use this when some work +needs to be done when the DMA finishes that +cannot wait until user space resumes.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_start_2"></a>6.2.4. ao_dma_start</h3></div></div></div><pre class="literallayout">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. <span class="emphasis"><em>ao_dma_done[index]</em></span> +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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_done_transfer"></a>6.2.5. ao_dma_done_transfer</h3></div></div></div><pre class="literallayout">void +ao_dma_done_transfer(uint8_t id);</pre><p>Signals that a specific DMA engine is done +being used. This allows multiple drivers to +use the same DMA engine safely.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_dma_abort_2"></a>6.2.6. ao_dma_abort</h3></div></div></div><pre class="literallayout">void +ao_dma_abort(uint8_t id)</pre><p>Terminate any in-progress DMA transaction, +marking its <span class="emphasis"><em>done</em></span> variable with the +AO_DMA_ABORTED bit.</p></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_stdio_interface"></a>Chapter 7. Stdio interface</h1></div></div></div><p>AltOS offers a stdio interface over USB, serial and the RF +packet link. This provides for control of the device locally or +remotely. This is hooked up to the stdio functions by providing +the standard putchar/getchar/flush functions. These +automatically multiplex the available communication channels; +output is always delivered to the channel which provided the +most recent input.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_putchar"></a>7.1. putchar</h2></div></div></div><pre class="literallayout">void +putchar(char c)</pre><p>Delivers a single character to the current console +device.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_getchar"></a>7.2. getchar</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_flush"></a>7.3. flush</h2></div></div></div><pre class="literallayout">void +flush(void)</pre><p>Flushes the current console device output buffer. Any +pending characters will be delivered to the target device.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_add_stdio"></a>7.4. ao_add_stdio</h2></div></div></div><pre class="literallayout">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><span class="emphasis"><em>pollchar</em></span> returns either an available character or +AO_READ_AGAIN if none is available. Significantly, it does +not block. The device driver must set <span class="emphasis"><em>ao_stdin_ready</em></span> to +1 and call ao_wakeup(&ao_stdin_ready) when it receives +input to tell getchar that more data is available, at +which point <span class="emphasis"><em>pollchar</em></span> will be called again.</p><p><span class="emphasis"><em>putchar</em></span> queues a character for output, flushing if the output buffer is +full. It may block in this case.</p><p><span class="emphasis"><em>flush</em></span> 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"><div class="titlepage"><div><div><h1 class="title"><a id="_command_line_interface"></a>Chapter 8. Command line interface</h1></div></div></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, serial 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_register"></a>8.1. ao_cmd_register</h2></div></div></div><pre class="literallayout">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="literallayout">struct ao_cmds { + char cmd; + void (*func)(void); + const char *help; +};</pre><p><span class="emphasis"><em>cmd</em></span> is the character naming the command. <span class="emphasis"><em>func</em></span> is the +function to invoke and <span class="emphasis"><em>help</em></span> is a string displayed by the +<span class="emphasis"><em>?</em></span> command. Syntax errors found while executing <span class="emphasis"><em>func</em></span> +should be indicated by modifying the global ao_cmd_status +variable with one of the following values:</p><div class="variablelist"><dl class="variablelist"><dt><span class="term"> +ao_cmd_success +</span></dt><dd> +The command was parsed successfully. There is no need +to assign this value, it is the default. +</dd><dt><span class="term"> +ao_cmd_lex_error +</span></dt><dd> +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. +</dd><dt><span class="term"> +ao_syntax_error +</span></dt><dd> +The command line is invalid for some reason other than +invalid tokens. +</dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_lex"></a>8.2. ao_cmd_lex</h2></div></div></div><pre class="literallayout">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 (<span class="emphasis"><em>\n</em></span>) +character.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_put16"></a>8.3. ao_cmd_put16</h2></div></div></div><pre class="literallayout">void +ao_cmd_put16(uint16_t v);</pre><p>Writes <span class="emphasis"><em>v</em></span> as four hexadecimal characters.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_put8"></a>8.4. ao_cmd_put8</h2></div></div></div><pre class="literallayout">void +ao_cmd_put8(uint8_t v);</pre><p>Writes <span class="emphasis"><em>v</em></span> as two hexadecimal characters.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_white"></a>8.5. ao_cmd_white</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_hex"></a>8.6. ao_cmd_hex</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_decimal"></a>8.7. ao_cmd_decimal</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_match_word"></a>8.8. ao_match_word</h2></div></div></div><pre class="literallayout">uint8_t +ao_match_word(__code char *word)</pre><p>This checks to make sure that <span class="emphasis"><em>word</em></span> occurs on the +command line. It does not skip leading white space. If +<span class="emphasis"><em>word</em></span> 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_cmd_init"></a>8.9. ao_cmd_init</h2></div></div></div><pre class="literallayout">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 <span class="emphasis"><em>main</em></span> before +ao_start_scheduler.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_usb_target_device"></a>Chapter 9. USB target device</h1></div></div></div><p>AltOS contains a full-speed USB target device driver. 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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_flush"></a>9.1. ao_usb_flush</h2></div></div></div><pre class="literallayout">void +ao_usb_flush(void);</pre><p>Flushes any pending USB output. This queues an <span class="emphasis"><em>IN</em></span> +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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_putchar"></a>9.2. ao_usb_putchar</h2></div></div></div><pre class="literallayout">void +ao_usb_putchar(char c);</pre><p>If there is a pending <span class="emphasis"><em>IN</em></span> 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 <span class="emphasis"><em>IN</em></span> packet for delivery.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_pollchar"></a>9.3. ao_usb_pollchar</h2></div></div></div><pre class="literallayout">char +ao_usb_pollchar(void);</pre><p>If there are no characters remaining in the last <span class="emphasis"><em>OUT</em></span> +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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_getchar"></a>9.4. ao_usb_getchar</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_disable"></a>9.5. ao_usb_disable</h2></div></div></div><pre class="literallayout">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 v0.2 nor TeleMetrum v1 +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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_enable"></a>9.6. ao_usb_enable</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_usb_init"></a>9.7. ao_usb_init</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h1 class="title"><a id="_serial_peripherals"></a>Chapter 10. Serial peripherals</h1></div></div></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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_serial_getchar"></a>10.1. ao_serial_getchar</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_serial_putchar"></a>10.2. ao_serial_putchar</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_serial_drain"></a>10.3. ao_serial_drain</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_serial_set_speed"></a>10.4. ao_serial_set_speed</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_serial_init"></a>10.5. ao_serial_init</h2></div></div></div><pre class="literallayout">void +ao_serial_init(void)</pre><p>Initializes the serial peripheral. Call this from <span class="emphasis"><em>main</em></span> +before jumping to ao_start_scheduler. The default speed +setting is AO_SERIAL_SPEED_4800.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="_cc1111_cc1120_cc1200_radio_peripheral"></a>Chapter 11. CC1111/CC1120/CC1200 Radio peripheral</h1></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_radio_introduction"></a>11.1. Radio Introduction</h2></div></div></div><p>The CC1111, CC1120 and CC1200 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"> +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. +</li><li class="listitem"> +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. +</li></ol></div><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 +<span class="emphasis"><em>idle</em></span> 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><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"> +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. +</li></ol></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_set_telemetry"></a>11.2. ao_radio_set_telemetry</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_set_packet"></a>11.3. ao_radio_set_packet</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_set_rdf"></a>11.4. ao_radio_set_rdf</h2></div></div></div><pre class="literallayout">void +ao_radio_set_rdf(void);</pre><p>Configures the radio to send RDF <span class="emphasis"><em>packets</em></span>. An RDF <span class="emphasis"><em>packet</em></span> +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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_idle"></a>11.5. ao_radio_idle</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_get"></a>11.6. ao_radio_get</h2></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_put"></a>11.7. ao_radio_put</h2></div></div></div><pre class="literallayout">void +ao_radio_put(void);</pre><p>Releases the radio mutex.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ao_radio_abort"></a>11.8. ao_radio_abort</h2></div></div></div><pre class="literallayout">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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_radio_telemetry"></a>11.9. Radio Telemetry</h2></div></div></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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_radio_send"></a>11.9.1. ao_radio_send</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_radio_recv"></a>11.9.2. ao_radio_recv</h3></div></div></div><pre class="literallayout">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></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_radio_direction_finding"></a>11.10. Radio Direction Finding</h2></div></div></div><p>In radio direction finding mode, there’s just one function to +use</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_radio_rdf"></a>11.10.1. ao_radio_rdf</h3></div></div></div><pre class="literallayout">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></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_radio_packet_mode"></a>11.11. Radio Packet Mode</h2></div></div></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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_putchar"></a>11.11.1. ao_packet_putchar</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_pollchar"></a>11.11.2. ao_packet_pollchar</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_slave_start"></a>11.11.3. ao_packet_slave_start</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_slave_stop"></a>11.11.4. ao_packet_slave_stop</h3></div></div></div><pre class="literallayout">void +ao_packet_slave_stop(void);</pre><p>Disables the packet slave task, stopping the radio receiver.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_slave_init"></a>11.11.5. ao_packet_slave_init</h3></div></div></div><pre class="literallayout">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"><div class="titlepage"><div><div><h3 class="title"><a id="_ao_packet_master_init"></a>11.11.6. ao_packet_master_init</h3></div></div></div><pre class="literallayout">void +ao_packet_master_init(void);</pre><p>Adds the <span class="emphasis"><em>p</em></span> packet forward command to start packet mode.</p></div></div></div></div></body></html>
\ No newline at end of file |