- 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="idp53896480"></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="idp53898736"></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="idp53900816"></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="idp53903120"></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="idp53905104"></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 transation, 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="idp53907376"></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="#idp53908880">1. putchar</a></span></dt><dt><span class="section"><a href="#idp53910768">2. getchar</a></span></dt><dt><span class="section"><a href="#idp53912864">3. flush</a></span></dt><dt><span class="section"><a href="#idp53914896">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 localy 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="idp53908880"></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="idp53910768"></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="idp53912864"></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.
- xo </p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="idp53914896"></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="idp53918848"></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="#idp53920256">1. ao_cmd_register</a></span></dt><dt><span class="section"><a href="#idp53928816">2. ao_cmd_lex</a></span></dt><dt><span class="section"><a href="#idp53930896">3. ao_cmd_put16</a></span></dt><dt><span class="section"><a href="#idp53932736">4. ao_cmd_put8</a></span></dt><dt><span class="section"><a href="#idp53934624">5. ao_cmd_white</a></span></dt><dt><span class="section"><a href="#idp53936688">6. ao_cmd_hex</a></span></dt><dt><span class="section"><a href="#idp53938736">7. ao_cmd_decimal</a></span></dt><dt><span class="section"><a href="#idp53940832">8. ao_match_word</a></span></dt><dt><span class="section"><a href="#idp53942912">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="idp53920256"></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="idp53928816"></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="idp53930896"></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="idp53932736"></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="idp53934624"></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="idp53936688"></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="idp53938736"></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="idp53940832"></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="idp53942912"></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="idp53945136"></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="#idp53947360">1. ao_usb_flush</a></span></dt><dt><span class="section"><a href="#idp53949504">2. ao_usb_putchar</a></span></dt><dt><span class="section"><a href="#idp53951680">3. ao_usb_pollchar</a></span></dt><dt><span class="section"><a href="#idp53953824">4. ao_usb_getchar</a></span></dt><dt><span class="section"><a href="#idp53955840">5. ao_usb_disable</a></span></dt><dt><span class="section"><a href="#idp53958672">6. ao_usb_enable</a></span></dt><dt><span class="section"><a href="#idp53960784">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="idp53947360"></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="idp53949504"></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="idp53951680"></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="idp53953824"></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="idp53955840"></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="idp53958672"></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="idp53960784"></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="idp53963008"></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="#idp53965024">1. ao_serial_getchar</a></span></dt><dt><span class="section"><a href="#idp53967056">2. ao_serial_putchar</a></span></dt><dt><span class="section"><a href="#idp53969024">3. ao_serial_drain</a></span></dt><dt><span class="section"><a href="#idp53971024">4. ao_serial_set_speed</a></span></dt><dt><span class="section"><a href="#idp53973056">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="idp53965024"></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="idp53967056"></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="idp53969024"></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="idp53971024"></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="idp53973056"></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="idp53975248"></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="#idp53975920">1. Radio Introduction</a></span></dt><dt><span class="section"><a href="#idp53983040">2. ao_radio_set_telemetry</a></span></dt><dt><span class="section"><a href="#idp53985200">3. ao_radio_set_packet</a></span></dt><dt><span class="section"><a href="#idp53987360">4. ao_radio_set_rdf</a></span></dt><dt><span class="section"><a href="#idp53989600">5. ao_radio_idle</a></span></dt><dt><span class="section"><a href="#idp53991648">6. ao_radio_get</a></span></dt><dt><span class="section"><a href="#idp53993680">7. ao_radio_put</a></span></dt><dt><span class="section"><a href="#idp53995616">8. ao_radio_abort</a></span></dt><dt><span class="section"><a href="#idp53997680">9. Radio Telemetry</a></span></dt><dd><dl><dt><span class="section"><a href="#idp53998976">9.1. ao_radio_send</a></span></dt><dt><span class="section"><a href="#idp54001120">9.2. ao_radio_recv</a></span></dt></dl></dd><dt><span class="section"><a href="#idp54003504">10. Radio Direction Finding</a></span></dt><dd><dl><dt><span class="section"><a href="#idp54004656">10.1. ao_radio_rdf</a></span></dt></dl></dd><dt><span class="section"><a href="#idp54006800">11. Radio Packet Mode</a></span></dt><dd><dl><dt><span class="section"><a href="#idp54008112">11.1. ao_packet_putchar</a></span></dt><dt><span class="section"><a href="#idp54010288">11.2. ao_packet_pollchar</a></span></dt><dt><span class="section"><a href="#idp54012368">11.3. ao_packet_slave_start</a></span></dt><dt><span class="section"><a href="#idp54014320">11.4. ao_packet_slave_stop</a></span></dt><dt><span class="section"><a href="#idp54016160">11.5. ao_packet_slave_init</a></span></dt><dt><span class="section"><a href="#idp54018192">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="idp53975920"></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="idp53983040"></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="idp53985200"></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="idp53987360"></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="idp53989600"></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="idp53991648"></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="idp53993680"></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="idp53995616"></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="idp53997680"></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="idp53998976"></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="idp54001120"></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="idp54003504"></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="idp54004656"></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="idp54006800"></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="idp54008112"></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="idp54010288"></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="idp54012368"></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="idp54014320"></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="idp54016160"></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="idp54018192"></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>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>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>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_start_scheduler">3.6. ao_start_scheduler</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_start_scheduler(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This is called from 'main' when the system is all
+initialized and ready to run. It will not return.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_clock_init">3.7. ao_clock_init</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_clock_init(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This initializes the main CPU clock and switches to it.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_timer_functions">4. Timer Functions</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_time">4.1. ao_time</h3>
+<div class="literalblock">
+<div class="content">
+<pre>uint16_t
+ao_time(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_delay">4.2. ao_delay</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_delay(uint16_t ticks);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Suspend the current task for at least 'ticks' clock units.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_timer_set_adc_interval">4.3. ao_timer_set_adc_interval</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_timer_set_adc_interval(uint8_t interval);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_timer_init">4.4. ao_timer_init</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_timer_init(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="sect1">
+<h2 id="_altos_mutexes">5. AltOS Mutexes</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_mutex_get">5.1. ao_mutex_get</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_mutex_get(__xdata uint8_t *mutex);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Acquires the specified mutex, blocking if the mutex is
+owned by another task.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_mutex_put">5.2. ao_mutex_put</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_mutex_put(__xdata uint8_t *mutex);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Releases the specified mutex, waking up all tasks waiting
+for it.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_dma_engine">6. DMA engine</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_cc1111_dma_engine">6.1. CC1111 DMA Engine</h3>
+<div class="sect3">
+<h4 id="_ao_dma_alloc">6.1.1. ao_dma_alloc</h4>
+<div class="literalblock">
+<div class="content">
+<pre>uint8_t
+ao_dma_alloc(__xdata uint8_t *done)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_set_transfer">6.1.2. ao_dma_set_transfer</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_set_transfer(uint8_t id,
+void __xdata *srcaddr,
+void __xdata *dstaddr,
+uint16_t count,
+uint8_t cfg0,
+uint8_t cfg1)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_start">6.1.3. ao_dma_start</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_start(uint8_t id);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Arm the specified DMA engine and await a
+signal from either hardware or software to
+start transferring data.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_ao_dma_trigger">6.1.4. ao_dma_trigger</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_trigger(uint8_t id)</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Trigger the specified DMA engine to start
+copying data.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_ao_dma_abort">6.1.5. ao_dma_abort</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_abort(uint8_t id)</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Terminate any in-progress DMA transaction,
+marking its 'done' variable with the
+AO_DMA_ABORTED bit.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_stm32l_dma_engine">6.2. STM32L DMA Engine</h3>
+<div class="sect3">
+<h4 id="_ao_dma_alloc_2">6.2.1. ao_dma_alloc</h4>
+<div class="literalblock">
+<div class="content">
+<pre>uint8_t ao_dma_done[];
+
+void
+ao_dma_alloc(uint8_t index);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Reserve a DMA engine for exclusive use by one
+driver.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_ao_dma_set_transfer_2">6.2.2. ao_dma_set_transfer</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_set_transfer(uint8_t id,
+void *peripheral,
+void *memory,
+uint16_t count,
+uint32_t ccr);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_set_isr">6.2.3. ao_dma_set_isr</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_set_isr(uint8_t index, void (*isr)(int))</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_start_2">6.2.4. ao_dma_start</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_start(uint8_t id);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_done_transfer">6.2.5. ao_dma_done_transfer</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_done_transfer(uint8_t id);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_dma_abort_2">6.2.6. ao_dma_abort</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_dma_abort(uint8_t id)</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Terminate any in-progress DMA transaction,
+marking its 'done' variable with the
+AO_DMA_ABORTED bit.</p>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_stdio_interface">7. Stdio interface</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_putchar">7.1. putchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+putchar(char c)</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Delivers a single character to the current console
+device.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_getchar">7.2. getchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>char
+getchar(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_flush">7.3. flush</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+flush(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Flushes the current console device output buffer. Any
+pending characters will be delivered to the target device.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_add_stdio">7.4. ao_add_stdio</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_add_stdio(char (*pollchar)(void),
+void (*putchar)(char),
+void (*flush)(void))</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This adds another console device to the available
+list.</p>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<p>'putchar' queues a character for output, flushing if the output buffer is
+full. It may block in this case.</p>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="sect1">
+<h2 id="_command_line_interface">8. Command line interface</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_cmd_register">8.1. ao_cmd_register</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_register(__code struct ao_cmds *cmds)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>struct ao_cmds {
+ char cmd;
+ void (*func)(void);
+ const char *help;
+};</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">ao_cmd_success</dt>
+<dd>
+<p>The command was parsed successfully. There is no need
+to assign this value, it is the default.</p>
+</dd>
+<dt class="hdlist1">ao_cmd_lex_error</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 class="hdlist1">ao_syntax_error</dt>
+<dd>
+<p>The command line is invalid for some reason other than
+invalid tokens.</p>
+</dd>
+</dl>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_cmd_lex">8.2. ao_cmd_lex</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_lex(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_cmd_put16">8.3. ao_cmd_put16</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_put16(uint16_t v);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Writes 'v' as four hexadecimal characters.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_cmd_put8">8.4. ao_cmd_put8</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_put8(uint8_t v);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Writes 'v' as two hexadecimal characters.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_cmd_white">8.5. ao_cmd_white</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_white(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_cmd_hex">8.6. ao_cmd_hex</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_hex(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_cmd_decimal">8.7. ao_cmd_decimal</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_decimal(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_match_word">8.8. ao_match_word</h3>
+<div class="literalblock">
+<div class="content">
+<pre>uint8_t
+ao_match_word(__code char *word)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_cmd_init">8.9. ao_cmd_init</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_cmd_init(void</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="sect1">
+<h2 id="_usb_target_device">9. USB target device</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_flush">9.1. ao_usb_flush</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_usb_flush(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_putchar">9.2. ao_usb_putchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_usb_putchar(char c);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_pollchar">9.3. ao_usb_pollchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>char
+ao_usb_pollchar(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_getchar">9.4. ao_usb_getchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>char
+ao_usb_getchar(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This uses ao_pollchar to receive the next character,
+blocking while ao_pollchar returns AO_READ_AGAIN.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_usb_disable">9.5. ao_usb_disable</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_usb_disable(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_enable">9.6. ao_usb_enable</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_usb_enable(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_usb_init">9.7. ao_usb_init</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_usb_init(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="sect1">
+<h2 id="_serial_peripherals">10. Serial peripherals</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<p>To prevent loss of data, AltOS provides receive and transmit
+fifos of 32 characters each.</p>
+</div>
+<div class="sect2">
+<h3 id="_ao_serial_getchar">10.1. ao_serial_getchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>char
+ao_serial_getchar(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Returns the next character from the receive fifo, blocking
+until a character is received if the fifo is empty.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_serial_putchar">10.2. ao_serial_putchar</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_serial_putchar(char c);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Adds a character to the transmit fifo, blocking if the
+fifo is full. Starts transmitting characters.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_serial_drain">10.3. ao_serial_drain</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_serial_drain(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Blocks until the transmit fifo is empty. Used internally
+when changing serial speeds.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_serial_set_speed">10.4. ao_serial_set_speed</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_serial_set_speed(uint8_t speed);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_serial_init">10.5. ao_serial_init</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_serial_init(void)</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="sect1">
+<h2 id="_cc1111cc1120cc1200_radio_peripheral">11. CC1111/CC1120/CC1200 Radio peripheral</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_radio_introduction">11.1. Radio Introduction</h3>
+<div class="paragraph">
+<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>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<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>
+<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>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<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>
+</div>
+<div class="paragraph">
+<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>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<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>
+</div>
+<div class="sect2">
+<h3 id="_ao_radio_set_telemetry">11.2. ao_radio_set_telemetry</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_set_telemetry(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_radio_set_packet">11.3. ao_radio_set_packet</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_set_packet(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_radio_set_rdf">11.4. ao_radio_set_rdf</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_set_rdf(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_radio_idle">11.5. ao_radio_idle</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_idle(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_ao_radio_get">11.6. ao_radio_get</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_get(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Acquires the radio mutex and then configures the radio
+frequency using the global radio calibration and channel
+values.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_radio_put">11.7. ao_radio_put</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_put(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Releases the radio mutex.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_ao_radio_abort">11.8. ao_radio_abort</h3>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_abort(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_radio_telemetry">11.9. Radio Telemetry</h3>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_radio_send">11.9.1. ao_radio_send</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_send(__xdata struct ao_telemetry *telemetry);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_radio_recv">11.9.2. ao_radio_recv</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_recv(__xdata struct ao_radio_recv *radio);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect2">
+<h3 id="_radio_direction_finding">11.10. Radio Direction Finding</h3>
+<div class="paragraph">
+<p>In radio direction finding mode, there’s just one function to
+use</p>
+</div>
+<div class="sect3">
+<h4 id="_ao_radio_rdf">11.10.1. ao_radio_rdf</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_radio_rdf(int ms);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This sends an RDF packet lasting for the specified amount
+of time. The maximum length is 1020 ms.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_radio_packet_mode">11.11. Radio Packet Mode</h3>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_packet_putchar">11.11.1. ao_packet_putchar</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_packet_putchar(char c);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_packet_pollchar">11.11.2. ao_packet_pollchar</h4>
+<div class="literalblock">
+<div class="content">
+<pre>char
+ao_packet_pollchar(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_packet_slave_start">11.11.3. ao_packet_slave_start</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_packet_slave_start(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This is available only on the slave side and starts a task
+to listen for packet data.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_ao_packet_slave_stop">11.11.4. ao_packet_slave_stop</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_packet_slave_stop(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Disables the packet slave task, stopping the radio receiver.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_ao_packet_slave_init">11.11.5. ao_packet_slave_init</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_packet_slave_init(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<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>
+<div class="sect3">
+<h4 id="_ao_packet_master_init">11.11.6. ao_packet_master_init</h4>
+<div class="literalblock">
+<div class="content">
+<pre>void
+ao_packet_master_init(void);</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Adds the 'p' packet forward command to start packet mode.</p>
+</div>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2020-10-22 16:37:05 -0600
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file