Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 1701 → Rev 1702

/C-OSD/arducam-osd/libraries/FastSerial/BetterStream.cpp
0,0 → 1,61
// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
//
// Copyright (c) 2010 Michael Smith. All rights reserved.
//
// This is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
 
//
// Enhancements to the Arduino Stream class.
//
 
#include <limits.h>
#include "BetterStream.h"
 
// Stream extensions////////////////////////////////////////////////////////////
 
void
BetterStream::print_P(const prog_char_t *s)
{
char c;
 
while ('\0' != (c = pgm_read_byte((const prog_char *)s++)))
write(c);
}
 
void
BetterStream::println_P(const prog_char_t *s)
{
print_P(s);
println();
}
 
void
BetterStream::printf(const char *fmt, ...)
{
va_list ap;
 
va_start(ap, fmt);
_vprintf(0, fmt, ap);
va_end(ap);
}
 
void
BetterStream::_printf_P(const prog_char *fmt, ...)
{
va_list ap;
 
va_start(ap, fmt);
_vprintf(1, fmt, ap);
va_end(ap);
}
 
int
BetterStream::txspace(void)
{
// by default claim that there is always space in transmit buffer
return(INT_MAX);
}
/C-OSD/arducam-osd/libraries/FastSerial/BetterStream.h
0,0 → 1,41
// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
//
// Copyright (c) 2010 Michael Smith. All rights reserved.
//
// This is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
 
#ifndef __BETTERSTREAM_H
#define __BETTERSTREAM_H
 
#include <Stream.h>
#include <avr/pgmspace.h>
#include "../AP_Common/AP_Common.h"
 
class BetterStream : public Stream {
public:
BetterStream(void) {
}
 
// Stream extensions
void print_P(const prog_char_t *);
void println_P(const prog_char_t *);
void printf(const char *, ...)
__attribute__ ((format(__printf__, 2, 3)));
void _printf_P(const prog_char *, ...);
__attribute__ ((format(__printf__, 2, 3)));
 
virtual int txspace(void);
 
#define printf_P(fmt, ...) _printf_P((const prog_char *)fmt, ## __VA_ARGS__)
 
private:
void _vprintf(unsigned char, const char *, va_list)
__attribute__ ((format(__printf__, 3, 0)));
};
 
#endif // __BETTERSTREAM_H
 
/C-OSD/arducam-osd/libraries/FastSerial/FastSerial.cpp
0,0 → 1,304
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
//
// Interrupt-driven serial transmit/receive library.
//
// Copyright (c) 2010 Michael Smith. All rights reserved.
//
// Receive and baudrate calculations derived from the Arduino
// HardwareSerial driver:
//
// Copyright (c) 2006 Nicholas Zambetti. All right reserved.
//
// Transmit algorithm inspired by work:
//
// Code Jose Julio and Jordi Munoz. DIYDrones.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
 
 
//#include "../AP_Common/AP_Common.h"
#include "FastSerial.h"
 
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
 
#if defined(UDR3)
# define FS_MAX_PORTS 4
#elif defined(UDR2)
# define FS_MAX_PORTS 3
#elif defined(UDR1)
# define FS_MAX_PORTS 2
#else
# define FS_MAX_PORTS 1
#endif
 
FastSerial::Buffer __FastSerial__rxBuffer[FS_MAX_PORTS];
FastSerial::Buffer __FastSerial__txBuffer[FS_MAX_PORTS];
uint8_t FastSerial::_serialInitialized = 0;
 
// Constructor /////////////////////////////////////////////////////////////////
 
FastSerial::FastSerial(const uint8_t portNumber, volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb, const uint8_t u2x,
const uint8_t portEnableBits, const uint8_t portTxBits) :
_ubrrh(ubrrh),
_ubrrl(ubrrl),
_ucsra(ucsra),
_ucsrb(ucsrb),
_u2x(u2x),
_portEnableBits(portEnableBits),
_portTxBits(portTxBits),
_rxBuffer(&__FastSerial__rxBuffer[portNumber]),
_txBuffer(&__FastSerial__txBuffer[portNumber])
{
setInitialized(portNumber);
begin(57600);
}
 
// Public Methods //////////////////////////////////////////////////////////////
 
void FastSerial::begin(long baud)
{
begin(baud, 0, 0);
}
 
void FastSerial::begin(long baud, unsigned int rxSpace, unsigned int txSpace)
{
uint16_t ubrr;
bool use_u2x = true;
 
// if we are currently open...
if (_open) {
// If the caller wants to preserve the buffer sizing, work out what
// it currently is...
if (0 == rxSpace)
rxSpace = _rxBuffer->mask + 1;
if (0 == txSpace)
txSpace = _txBuffer->mask + 1;
 
// close the port in its current configuration, clears _open
end();
}
 
// allocate buffers
if (!_allocBuffer(_rxBuffer, rxSpace ? : _default_rx_buffer_size) || !_allocBuffer(_txBuffer, txSpace ? : _default_tx_buffer_size)) {
end();
return; // couldn't allocate buffers - fatal
}
 
// reset buffer pointers
_txBuffer->head = _txBuffer->tail = 0;
_rxBuffer->head = _rxBuffer->tail = 0;
 
// mark the port as open
_open = true;
 
// If the user has supplied a new baud rate, compute the new UBRR value.
if (baud > 0) {
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600)
use_u2x = false;
#endif
 
if (use_u2x) {
*_ucsra = 1 << _u2x;
ubrr = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
ubrr = (F_CPU / 8 / baud - 1) / 2;
}
 
*_ubrrh = ubrr >> 8;
*_ubrrl = ubrr;
}
 
*_ucsrb |= _portEnableBits;
}
 
void FastSerial::end()
{
*_ucsrb &= ~(_portEnableBits | _portTxBits);
 
_freeBuffer(_rxBuffer);
_freeBuffer(_txBuffer);
_open = false;
}
 
int FastSerial::available(void)
{
if (!_open)
return (-1);
return ((_rxBuffer->head - _rxBuffer->tail) & _rxBuffer->mask);
}
 
int FastSerial::txspace(void)
{
if (!_open)
return (-1);
return ((_txBuffer->mask+1) - ((_txBuffer->head - _txBuffer->tail) & _txBuffer->mask));
}
 
int FastSerial::read(void)
{
uint8_t c;
 
// if the head and tail are equal, the buffer is empty
if (!_open || (_rxBuffer->head == _rxBuffer->tail))
return (-1);
 
// pull character from tail
c = _rxBuffer->bytes[_rxBuffer->tail];
_rxBuffer->tail = (_rxBuffer->tail + 1) & _rxBuffer->mask;
 
return (c);
}
 
int FastSerial::peek(void)
{
 
// if the head and tail are equal, the buffer is empty
if (!_open || (_rxBuffer->head == _rxBuffer->tail))
return (-1);
 
// pull character from tail
return (_rxBuffer->bytes[_rxBuffer->tail]);
}
 
void FastSerial::flush(void)
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of _rxBuffer->head but before writing
// the value to _rxBuffer->tail; the previous value of head
// may be written to tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of head but before writing
// the value to tail; the previous value of rx_buffer_head
// may be written to tail, making it appear as if the buffer
// were full, not empty.
_rxBuffer->head = _rxBuffer->tail;
 
// don't reverse this or there may be problems if the TX interrupt
// occurs after reading the value of _txBuffer->tail but before writing
// the value to _txBuffer->head.
_txBuffer->tail = _txBuffer->head;
}
 
#if defined(ARDUINO) && ARDUINO >= 100
size_t FastSerial::write(uint8_t c)
{
uint16_t i;
 
if (!_open) // drop bytes if not open
return 0;
 
// wait for room in the tx buffer
i = (_txBuffer->head + 1) & _txBuffer->mask;
 
// if the port is set into non-blocking mode, then drop the byte
// if there isn't enough room for it in the transmit buffer
if (_nonblocking_writes && i == _txBuffer->tail) {
return 0;
}
 
while (i == _txBuffer->tail)
;
 
// add byte to the buffer
_txBuffer->bytes[_txBuffer->head] = c;
_txBuffer->head = i;
 
// enable the data-ready interrupt, as it may be off if the buffer is empty
*_ucsrb |= _portTxBits;
 
// return number of bytes written (always 1)
return 1;
}
#else
void FastSerial::write(uint8_t c)
{
uint16_t i;
 
if (!_open) // drop bytes if not open
return;
 
// wait for room in the tx buffer
i = (_txBuffer->head + 1) & _txBuffer->mask;
while (i == _txBuffer->tail)
;
 
// add byte to the buffer
_txBuffer->bytes[_txBuffer->head] = c;
_txBuffer->head = i;
 
// enable the data-ready interrupt, as it may be off if the buffer is empty
*_ucsrb |= _portTxBits;
}
#endif
 
// Buffer management ///////////////////////////////////////////////////////////
 
bool FastSerial::_allocBuffer(Buffer *buffer, unsigned int size)
{
uint16_t mask;
uint8_t shift;
 
// init buffer state
buffer->head = buffer->tail = 0;
 
// Compute the power of 2 greater or equal to the requested buffer size
// and then a mask to simplify wrapping operations. Using __builtin_clz
// would seem to make sense, but it uses a 256(!) byte table.
// Note that we ignore requests for more than BUFFER_MAX space.
for (shift = 1; (1U << shift) < min(_max_buffer_size, size); shift++)
;
mask = (1 << shift) - 1;
 
// If the descriptor already has a buffer allocated we need to take
// care of it.
if (buffer->bytes) {
 
// If the allocated buffer is already the correct size then
// we have nothing to do
if (buffer->mask == mask)
return true;
 
// Dispose of the old buffer.
free(buffer->bytes);
}
buffer->mask = mask;
 
// allocate memory for the buffer - if this fails, we fail.
buffer->bytes = (uint8_t *) malloc(buffer->mask + 1);
 
return (buffer->bytes != NULL);
}
 
void FastSerial::_freeBuffer(Buffer *buffer)
{
buffer->head = buffer->tail = 0;
buffer->mask = 0;
if (NULL != buffer->bytes) {
free(buffer->bytes);
buffer->bytes = NULL;
}
}
 
/C-OSD/arducam-osd/libraries/FastSerial/FastSerial.h
0,0 → 1,334
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
//
// Interrupt-driven serial transmit/receive library.
//
// Copyright (c) 2010 Michael Smith. All rights reserved.
//
// Receive and baudrate calculations derived from the Arduino
// HardwareSerial driver:
//
// Copyright (c) 2006 Nicholas Zambetti. All right reserved.
//
// Transmit algorithm inspired by work:
//
// Code Jose Julio and Jordi Munoz. DIYDrones.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
// Boston, MA 02110-1301 USA
//
 
//
// Note that this library does not pre-declare drivers for serial
// ports; the user must explicitly create drivers for the ports they
// wish to use. This is less friendly than the stock Arduino driver,
// but it saves a few bytes of RAM for every unused port and frees up
// the vector for another driver (e.g. MSPIM on USARTs).
//
 
#ifndef FastSerial_h
#define FastSerial_h
 
// disable the stock Arduino serial driver
#ifdef HardwareSerial_h
# error Must include FastSerial.h before the Arduino serial driver is defined.
#endif
#define HardwareSerial_h
 
#include <inttypes.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#include "BetterStream.h"
 
 
/// @file FastSerial.h
/// @brief An enhanced version of the Arduino HardwareSerial class
/// implementing interrupt-driven transmission and flexible
/// buffer management.
///
/// Because Arduino libraries aren't really libraries, but we want to
/// only define interrupt handlers for serial ports that are actually
/// used, we have to force our users to define them using a macro.
///
/// FastSerialPort(<port name>, <port number>)
///
/// <port name> is the name of the object that will be created by the
/// macro. <port number> is the 0-based number of the port that will
/// be managed by the object.
///
/// Previously ports were defined with a different macro for each port,
/// and these macros are retained for compatibility:
///
/// FastSerialPort0(<port name>) creates <port name> referencing serial port 0
/// FastSerialPort1(<port name>) creates <port name> referencing serial port 1
/// FastSerialPort2(<port name>) creates <port name> referencing serial port 2
/// FastSerialPort3(<port name>) creates <port name> referencing serial port 3
///
/// Note that compatibility macros are only defined for ports that
/// exist on the target device.
///
 
/// @name Compatibility
///
/// Forward declarations for clients that want to assume that the
/// default Serial* objects exist.
///
/// Note that the application is responsible for ensuring that these
/// actually get defined, otherwise Arduino will suck in the
/// HardwareSerial library and linking will fail.
//@{
extern class FastSerial Serial;
extern class FastSerial Serial1;
extern class FastSerial Serial2;
extern class FastSerial Serial3;
//@}
 
/// The FastSerial class definition
///
class FastSerial: public BetterStream {
public:
 
/// Constructor
FastSerial(const uint8_t portNumber, volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, volatile uint8_t *ucsra,
volatile uint8_t *ucsrb, const uint8_t u2x, const uint8_t portEnableBits, const uint8_t portTxBits);
 
/// @name Serial API
//@{
virtual void begin(long baud);
virtual void end(void);
virtual int available(void);
virtual int txspace(void);
virtual int read(void);
virtual int peek(void);
virtual void flush(void);
#if defined(ARDUINO) && ARDUINO >= 100
virtual size_t write(uint8_t c);
#else
virtual void write(uint8_t c);
#endif
using BetterStream::write;
//@}
 
/// Extended port open method
///
/// Allows for both opening with specified buffer sizes, and re-opening
/// to adjust a subset of the port's settings.
///
/// @note Buffer sizes greater than ::_max_buffer_size will be rounded
/// down.
///
/// @param baud Selects the speed that the port will be
/// configured to. If zero, the port speed is left
/// unchanged.
/// @param rxSpace Sets the receive buffer size for the port. If zero
/// then the buffer size is left unchanged if the port
/// is open, or set to ::_default_rx_buffer_size if it is
/// currently closed.
/// @param txSpace Sets the transmit buffer size for the port. If zero
/// then the buffer size is left unchanged if the port
/// is open, or set to ::_default_tx_buffer_size if it
/// is currently closed.
///
virtual void begin(long baud, unsigned int rxSpace, unsigned int txSpace);
 
/// Transmit/receive buffer descriptor.
///
/// Public so the interrupt handlers can see it
struct Buffer {
volatile uint16_t head, tail; ///< head and tail pointers
uint16_t mask; ///< buffer size mask for pointer wrap
uint8_t *bytes; ///< pointer to allocated buffer
};
 
/// Tell if the serial port has been initialized
static bool getInitialized(uint8_t port) {
return (1<<port) & _serialInitialized;
}
 
// ask for writes to be blocking or non-blocking
void set_blocking_writes(bool blocking) {
_nonblocking_writes = !blocking;
}
 
private:
 
/// Bit mask for initialized ports
static uint8_t _serialInitialized;
 
/// Set if the serial port has been initialized
static void setInitialized(uint8_t port) {
_serialInitialized |= (1<<port);
}
 
// register accessors
volatile uint8_t * const _ubrrh;
volatile uint8_t * const _ubrrl;
volatile uint8_t * const _ucsra;
volatile uint8_t * const _ucsrb;
 
// register magic numbers
const uint8_t _u2x;
const uint8_t _portEnableBits; ///< rx, tx and rx interrupt enables
const uint8_t _portTxBits; ///< tx data and completion interrupt enables
 
 
// ring buffers
Buffer * const _rxBuffer;
Buffer * const _txBuffer;
bool _open;
 
// whether writes to the port should block waiting
// for enough space to appear
bool _nonblocking_writes;
 
/// Allocates a buffer of the given size
///
/// @param buffer The buffer descriptor for which the buffer will
/// will be allocated.
/// @param size The desired buffer size.
/// @returns True if the buffer was allocated successfully.
///
static bool _allocBuffer(Buffer *buffer, unsigned int size);
 
/// Frees the allocated buffer in a descriptor
///
/// @param buffer The descriptor whose buffer should be freed.
///
static void _freeBuffer(Buffer *buffer);
 
/// default receive buffer size
static const unsigned int _default_rx_buffer_size = 128;
 
/// default transmit buffer size
static const unsigned int _default_tx_buffer_size = 16;
 
/// maxium tx/rx buffer size
/// @note if we could bring the max size down to 256, the mask and head/tail
/// pointers in the buffer could become uint8_t.
///
static const unsigned int _max_buffer_size = 512;
};
 
// Used by the per-port interrupt vectors
extern FastSerial::Buffer __FastSerial__rxBuffer[];
extern FastSerial::Buffer __FastSerial__txBuffer[];
 
/// Generic Rx/Tx vectors for a serial port - needs to know magic numbers
///
#define FastSerialHandler(_PORT, _RXVECTOR, _TXVECTOR, _UDR, _UCSRB, _TXBITS) \
ISR(_RXVECTOR, ISR_BLOCK) \
{ \
uint8_t c; \
uint16_t i; \
\
/* read the byte as quickly as possible */ \
c = _UDR; \
/* work out where the head will go next */ \
i = (__FastSerial__rxBuffer[_PORT].head + 1) & __FastSerial__rxBuffer[_PORT].mask; \
/* decide whether we have space for another byte */ \
if (i != __FastSerial__rxBuffer[_PORT].tail) { \
/* we do, move the head */ \
__FastSerial__rxBuffer[_PORT].bytes[__FastSerial__rxBuffer[_PORT].head] = c; \
__FastSerial__rxBuffer[_PORT].head = i; \
} \
} \
ISR(_TXVECTOR, ISR_BLOCK) \
{ \
/* if there is another character to send */ \
if (__FastSerial__txBuffer[_PORT].tail != __FastSerial__txBuffer[_PORT].head) { \
_UDR = __FastSerial__txBuffer[_PORT].bytes[__FastSerial__txBuffer[_PORT].tail]; \
/* increment the tail */ \
__FastSerial__txBuffer[_PORT].tail = \
(__FastSerial__txBuffer[_PORT].tail + 1) & __FastSerial__txBuffer[_PORT].mask; \
} else { \
/* there are no more bytes to send, disable the interrupt */ \
if (__FastSerial__txBuffer[_PORT].head == __FastSerial__txBuffer[_PORT].tail) \
_UCSRB &= ~_TXBITS; \
} \
} \
struct hack
 
//
// Portability; convert various older sets of defines for U(S)ART0 up
// to match the definitions for the 1280 and later devices.
//
#if !defined(USART0_RX_vect)
# if defined(USART_RX_vect)
# define USART0_RX_vect USART_RX_vect
# define USART0_UDRE_vect USART_UDRE_vect
# elif defined(UART0_RX_vect)
# define USART0_RX_vect UART0_RX_vect
# define USART0_UDRE_vect UART0_UDRE_vect
# endif
#endif
 
#if !defined(USART1_RX_vect)
# if defined(UART1_RX_vect)
# define USART1_RX_vect UART1_RX_vect
# define USART1_UDRE_vect UART1_UDRE_vect
# endif
#endif
 
#if !defined(UDR0)
# if defined(UDR)
# define UDR0 UDR
# define UBRR0H UBRRH
# define UBRR0L UBRRL
# define UCSR0A UCSRA
# define UCSR0B UCSRB
# define U2X0 U2X
# define RXEN0 RXEN
# define TXEN0 TXEN
# define RXCIE0 RXCIE
# define UDRIE0 UDRIE
# endif
#endif
 
///
/// Macro defining a FastSerial port instance.
///
#define FastSerialPort(_name, _num) \
FastSerial _name(_num, \
&UBRR##_num##H, \
&UBRR##_num##L, \
&UCSR##_num##A, \
&UCSR##_num##B, \
U2X##_num, \
(_BV(RXEN##_num) | _BV(TXEN##_num) | _BV(RXCIE##_num)), \
(_BV(UDRIE##_num))); \
FastSerialHandler(_num, \
USART##_num##_RX_vect, \
USART##_num##_UDRE_vect, \
UDR##_num, \
UCSR##_num##B, \
_BV(UDRIE##_num))
 
///
/// Compatibility macros for previous FastSerial versions.
///
/// Note that these are not conditionally defined, as the errors
/// generated when using these macros for a board that does not support
/// the port are better than the errors generated for a macro that's not
/// defined at all.
///
#define FastSerialPort0(_portName) FastSerialPort(_portName, 0)
#define FastSerialPort1(_portName) FastSerialPort(_portName, 1)
#define FastSerialPort2(_portName) FastSerialPort(_portName, 2)
#define FastSerialPort3(_portName) FastSerialPort(_portName, 3)
 
#endif // FastSerial_h
/C-OSD/arducam-osd/libraries/FastSerial/examples/FastSerial/FastSerial.pde
0,0 → 1,71
// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
 
//
// Example code for the FastSerial driver.
//
// This code is placed into the public domain.
//
 
//
// Include the FastSerial library header.
//
// Note that this causes the standard Arduino Serial* driver to be
// disabled.
//
#include <FastSerial.h>
 
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
 
# undef PSTR
# define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); \
(prog_char_t *)&__c[0];}))
 
//
// Create a FastSerial driver that looks just like the stock Arduino
// driver.
//
FastSerialPort0(Serial);
 
//
// To create a driver for a different serial port, on a board that
// supports more than one, use the appropriate macro:
//
//FastSerialPort2(Serial2);
 
 
void setup(void)
{
//
// Set the speed for our replacement serial port.
//
Serial.begin(115200);
 
//
// Test printing things
//
Serial.print("test");
Serial.println(" begin");
Serial.println(1000);
Serial.println(1000, 8);
Serial.println(1000, 10);
Serial.println(1000, 16);
Serial.println_P(PSTR("progmem"));
Serial.printf("printf %d %u %#x %p %f %S\n", -1000, 1000, 1000, 1000, 1.2345, PSTR("progmem"));
Serial.printf_P(PSTR("printf_P %d %u %#x %p %f %S\n"), -1000, 1000, 1000, 1000, 1.2345, PSTR("progmem"));
Serial.println("done");
}
 
void
loop(void)
{
int c;
 
//
// Perform a simple loopback operation.
//
c = Serial.read();
if (-1 != c)
Serial.write(c);
}
 
/C-OSD/arducam-osd/libraries/FastSerial/examples/FastSerial/Makefile
0,0 → 1,2
BOARD = mega
include ../../../AP_Common/Arduino.mk
/C-OSD/arducam-osd/libraries/FastSerial/ftoa_engine.S
0,0 → 1,532
/* Copyright (c) 2005, Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/* $Id: ftoa_engine.S,v 1.3 2009/04/01 23:11:00 arcanum Exp $ */
 
#ifndef __DOXYGEN__
 
#include "macros.inc"
#include "ftoa_engine.h"
 
#if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
# define AVR_ENH_LPM 1
#else
# define AVR_ENH_LPM 0
#endif
 
/*
int __ftoa_engine (double val, char *buf,
unsigned char prec, unsigned char maxdgs)
Input:
val - value to convert
buf - output buffer address
prec - precision: number of decimal digits is 'prec + 1'
maxdgs - (0 if unused) precision restriction for "%f" specification
 
Output:
return - decimal exponent of first digit
buf[0] - flags (FTOA_***)
buf[1],... - decimal digits
Number of digits:
maxdgs == 0 ? prec+1 :
(buf[0] & FTOA_CARRY) == 0 || buf[1] != '1' ?
aver(1, maxdgs+exp, prec+1) :
aver(1, masdgs+exp-1, prec+1)
 
Notes:
* Output string is not 0-terminated. For possibility of user's buffer
usage in any case.
* If used, 'maxdgs' is a number of digits for value with zero exponent.
*/
 
/* Input */
#define maxdgs r16
#define prec r18
#define buf_lo r20
#define buf_hi r21
#define val_lo r22
#define val_hi r23
#define val_hlo r24
#define val_hhi r25
 
/* Float value parse */
#define flag r19
 
/* Multiplication of mantisses */
#define exp_sv r17
#define mlt_1 r19 /* lowest result byte */
#define mlt_2 r14
#define mlt_3 r15
#define mlt_4 r20
#define mlt_5 r21
#define mlt_6 r28
#define mlt_7 r29
 
/* Conversion to string */
#define pwr_2 r1 /* lowest byte of 'powr10' element */
#define pwr_3 r17
#define pwr_4 r19
#define pwr_5 r22
#define pwr_6 r25
#define pwr_7 r0
#define digit r23
#define exp10 r24
 
/* Fixed */
#define zero r1
 
/* ASSEMBLY_CLIB_SECTION */
.global __ftoa_engine
.type __ftoa_engine, "function"
__ftoa_engine:
 
/* --------------------------------------------------------------------
Float value parse.
*/
; limit 'prec'
cpi prec, 8
brlo 1f
ldi prec, 7
1:
; init.
clr flag
X_movw XL, buf_lo
; val_hhi := exponent, sign test and remove
#if FTOA_MINUS != 1
# error FTOA_MINUS must be 1: add with carry used
#endif
lsl val_hhi
adc flag, zero ; FTOA_MINUS
sbrc val_hlo, 7
ori val_hhi, 1
; zero test
adiw val_hlo, 0
cpc val_lo, zero
cpc val_hi, zero
brne 3f
; return 0
ori flag, FTOA_ZERO
subi prec, -2
2: st X+, flag
ldi flag, '0'
dec prec
brne 2b
ret ; r24,r25 == 0
3:
; infinity, NaN ?
#if FTOA_NAN != 2 * FTOA_INF
# error Must: FTOA_NAN == 2*FTOA_INF: 'rjmp' is absent
#endif
cpi val_hhi, 0xff
brlo 6f
cpi val_hlo, 0x80
cpc val_hi, zero
cpc val_lo, zero
breq 5f
subi flag, -FTOA_INF ; FTOA_NAN
5: subi flag, -FTOA_INF
6:
; write flags byte
st X+, flag
; hidden bit
cpi val_hhi, 1
brlo 7f ; if subnormal value
ori val_hlo, 0x80
7: adc val_hhi, zero
; pushes
push r29
push r28
push r17
push r16
push r15
push r14
 
/* --------------------------------------------------------------------
Multiplication of mantisses (val and table).
At the begin:
val_hlo .. val_lo - input value mantisse
val_hhi - input value exponent
X - second byte address (string begin)
At the end:
mlt_7 .. mlt_2 - multiplication result
exp10 - decimal exponent
*/
 
; save
mov exp_sv, val_hhi
; Z := & base10[exp / 8] (sizeof(base10[0]) == 5)
andi val_hhi, ~7
lsr val_hhi ; (exp/8) * 4
mov ZL, val_hhi
lsr val_hhi
lsr val_hhi ; exp/8
add ZL, val_hhi ; (exp/8) * 5
clr ZH
subi ZL, lo8(-(.L_base10))
sbci ZH, hi8(-(.L_base10))
; highest mantissa byte (mult. shifting prepare)
clr val_hhi
; result initializ.
clr mlt_1
clr mlt_2
clr mlt_3
X_movw mlt_4, mlt_2
X_movw mlt_6, mlt_2
 
; multiply to 1-st table byte
#if AVR_ENH_LPM
lpm r0, Z+
#else
lpm
adiw ZL, 1
#endif
sec ; for loop end control
ror r0
; addition
10: brcc 11f
add mlt_1, val_lo
adc mlt_2, val_hi
adc mlt_3, val_hlo
adc mlt_4, val_hhi
adc mlt_5, zero
; arg shift
11: lsl val_lo
rol val_hi
rol val_hlo
rol val_hhi
; next bit
lsr r0
brne 10b
 
; second table byte
#if AVR_ENH_LPM
lpm r0, Z+ ; C flag is stay 1
#else
lpm
adiw ZL, 1
sec
#endif
ror r0
; addition
12: brcc 13f
add mlt_2, val_hi ; val_hi is the least byte now
adc mlt_3, val_hlo
adc mlt_4, val_hhi
adc mlt_5, val_lo
adc mlt_6, zero
; arg shift
13: lsl val_hi
rol val_hlo
rol val_hhi
rol val_lo
; next bit
lsr r0
brne 12b
 
; 3-t table byte
#if AVR_ENH_LPM
lpm r0, Z+ ; C flag is stay 1
#else
lpm
adiw ZL, 1
sec
#endif
ror r0
; addition
14: brcc 15f
add mlt_3, val_hlo ; val_hlo is the least byte now
adc mlt_4, val_hhi
adc mlt_5, val_lo
adc mlt_6, val_hi
adc mlt_7, zero
; arg shift
15: lsl val_hlo
rol val_hhi
rol val_lo
rol val_hi
; next bit
lsr r0
brne 14b
 
; 4-t table byte
#if AVR_ENH_LPM
lpm r0, Z+ ; C flag is stay 1
#else
lpm
#endif
ror r0
; addition
16: brcc 17f
add mlt_4, val_hhi ; val_hhi is the least byte now
adc mlt_5, val_lo
adc mlt_6, val_hi
adc mlt_7, val_hlo
; arg shift
17: lsl val_hhi
rol val_lo
rol val_hi
rol val_hlo
; next bit
lsr r0
brne 16b
 
; decimal exponent
#if AVR_ENH_LPM
lpm exp10, Z
#else
adiw ZL, 1
lpm
mov exp10, r0
#endif
 
; result shift: mlt_7..2 >>= (~exp & 7)
com exp_sv
andi exp_sv, 7
breq 19f
18: lsr mlt_7
ror mlt_6
ror mlt_5
ror mlt_4
ror mlt_3
ror mlt_2
dec exp_sv
brne 18b
19:
 
/* --------------------------------------------------------------------
Conversion to string.
 
Registers usage:
mlt_7 .. mlt_2 - new mantissa (multiplication result)
pwr_7 .. pwr_2 - 'powr10' table element
Z - 'powr10' table pointer
X - output string pointer
maxdgs - number of digits
prec - number of digits stays to output
exp10 - decimal exponent
digit - conversion process
 
At the end:
X - end of buffer (nonfilled byte)
exp10 - corrected dec. exponent
mlt_7 .. mlt_2 - remainder
pwr_7 .. pwr_2 - last powr10[] element
 
Notes:
* It is possible to leave out powr10'x table with subnormal value.
Result: accuracy degrease on the rounding phase. No matter: high
precision with subnormals is not needed. (Now 0x00000001 is converted
exactly on prec = 5, i.e. 6 digits.)
*/
 
; to find first digit
ldi ZL, lo8(.L_powr10)
ldi ZH, hi8(.L_powr10)
set
; 'pwr10' element reading
.L_digit:
X_lpm pwr_2, Z+
X_lpm pwr_3, Z+
X_lpm pwr_4, Z+
X_lpm pwr_5, Z+
X_lpm pwr_6, Z+
X_lpm pwr_7, Z+
; 'digit' init.
ldi digit, '0' - 1
; subtraction loop
20: inc digit
sub mlt_2, pwr_2
sbc mlt_3, pwr_3
sbc mlt_4, pwr_4
sbc mlt_5, pwr_5
sbc mlt_6, pwr_6
sbc mlt_7, pwr_7
brsh 20b
; restore mult
add mlt_2, pwr_2
adc mlt_3, pwr_3
adc mlt_4, pwr_4
adc mlt_5, pwr_5
adc mlt_6, pwr_6
adc mlt_7, pwr_7
; analisys
brtc 25f
cpi digit, '0'
brne 21f ; this is the first digit finded
dec exp10
rjmp .L_digit
; now is the first digit
21: clt
; number of digits
subi maxdgs, 1
brlo 23f ; maxdgs was 0
add maxdgs, exp10
brpl 22f
clr maxdgs
22: cp maxdgs, prec
brsh 23f
mov prec, maxdgs
23: inc prec
mov maxdgs, prec
; operate digit
25: cpi digit, '0' + 10
brlo 27f
; overflow, digit > '9'
ldi digit, '9'
26: st X+, digit
dec prec
brne 26b
rjmp .L_up
; write digit
27: st X+, digit
dec prec
brne .L_digit
 
/* --------------------------------------------------------------------
Rounding.
*/
.L_round:
; pwr10 /= 2
lsr pwr_7
ror pwr_6
ror pwr_5
ror pwr_4
ror pwr_3
ror pwr_2
; mult -= pwr10 (half of last 'pwr10' value)
sub mlt_2, pwr_2
sbc mlt_3, pwr_3
sbc mlt_4, pwr_4
sbc mlt_5, pwr_5
sbc mlt_6, pwr_6
sbc mlt_7, pwr_7
; rounding direction?
brlo .L_rest
; round to up
.L_up:
inc prec
ld digit, -X
inc digit
cpi digit, '9' + 1
brlo 31f
ldi digit, '0'
31: st X, digit
cpse prec, maxdgs
brsh .L_up
; it was a carry to master digit
ld digit, -X ; flags
ori digit, FTOA_CARRY ; 'C' is not changed
st X+, digit
brlo .L_rest ; above comparison
; overflow
inc exp10
ldi digit, '1'
32: st X+, digit
ldi digit, '0'
dec prec
brne 32b
; restore
.L_rest:
clr zero
pop r14
pop r15
pop r16
pop r17
pop r28
pop r29
; return
clr r25
sbrc exp10, 7 ; high byte
com r25
ret
 
.size __ftoa_engine, . - __ftoa_engine
 
/* --------------------------------------------------------------------
Tables. '.L_powr10' is placed first -- for subnormals stability.
*/
.section .progmem.data,"a",@progbits
 
.type .L_powr10, "object"
.L_powr10:
.byte 0, 64, 122, 16, 243, 90 ; 100000000000000
.byte 0, 160, 114, 78, 24, 9 ; 10000000000000
.byte 0, 16, 165, 212, 232, 0 ; 1000000000000
.byte 0, 232, 118, 72, 23, 0 ; 100000000000
.byte 0, 228, 11, 84, 2, 0 ; 10000000000
.byte 0, 202, 154, 59, 0, 0 ; 1000000000
.byte 0, 225, 245, 5, 0, 0 ; 100000000
.byte 128, 150, 152, 0, 0, 0 ; 10000000
.byte 64, 66, 15, 0, 0, 0 ; 1000000
.byte 160, 134, 1, 0, 0, 0 ; 100000
.byte 16, 39, 0, 0, 0, 0 ; 10000
.byte 232, 3, 0, 0, 0, 0 ; 1000
.byte 100, 0, 0, 0, 0, 0 ; 100
.byte 10, 0, 0, 0, 0, 0 ; 10
.byte 1, 0, 0, 0, 0, 0 ; 1
.size .L_powr10, . - .L_powr10
 
.type .L_base10, "object"
.L_base10:
.byte 44, 118, 216, 136, -36 ; 2295887404
.byte 103, 79, 8, 35, -33 ; 587747175
.byte 193, 223, 174, 89, -31 ; 1504632769
.byte 177, 183, 150, 229, -29 ; 3851859889
.byte 228, 83, 198, 58, -26 ; 986076132
.byte 81, 153, 118, 150, -24 ; 2524354897
.byte 230, 194, 132, 38, -21 ; 646234854
.byte 137, 140, 155, 98, -19 ; 1654361225
.byte 64, 124, 111, 252, -17 ; 4235164736
.byte 188, 156, 159, 64, -14 ; 1084202172
.byte 186, 165, 111, 165, -12 ; 2775557562
.byte 144, 5, 90, 42, -9 ; 710542736
.byte 92, 147, 107, 108, -7 ; 1818989404
.byte 103, 109, 193, 27, -4 ; 465661287
.byte 224, 228, 13, 71, -2 ; 1192092896
.byte 245, 32, 230, 181, 0 ; 3051757813
.byte 208, 237, 144, 46, 3 ; 781250000
.byte 0, 148, 53, 119, 5 ; 2000000000
.byte 0, 128, 132, 30, 8 ; 512000000
.byte 0, 0, 32, 78, 10 ; 1310720000
.byte 0, 0, 0, 200, 12 ; 3355443200
.byte 51, 51, 51, 51, 15 ; 858993459
.byte 152, 110, 18, 131, 17 ; 2199023256
.byte 65, 239, 141, 33, 20 ; 562949953
.byte 137, 59, 230, 85, 22 ; 1441151881
.byte 207, 254, 230, 219, 24 ; 3689348815
.byte 209, 132, 75, 56, 27 ; 944473297
.byte 247, 124, 29, 144, 29 ; 2417851639
.byte 164, 187, 228, 36, 32 ; 618970020
.byte 50, 132, 114, 94, 34 ; 1584563250
.byte 129, 0, 201, 241, 36 ; 4056481921
.byte 236, 161, 229, 61, 39 ; 1038459372
.size .L_base10, . - .L_base10
 
.end
#endif /* !__DOXYGEN__ */
/C-OSD/arducam-osd/libraries/FastSerial/ftoa_engine.h
0,0 → 1,48
/* Copyright (c) 2005, Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/* $Id: ftoa_engine.h 1218 2007-02-18 13:18:41Z dmix $ */
 
#ifndef _FTOA_ENGINE_H
#define _FTOA_ENGINE_H
 
#ifndef __ASSEMBLER__
 
int __ftoa_engine (double val, char *buf,
unsigned char prec, unsigned char maxdgs);
 
#endif
 
/* '__ftoa_engine' return next flags (in buf[0]): */
#define FTOA_MINUS 1
#define FTOA_ZERO 2
#define FTOA_INF 4
#define FTOA_NAN 8
#define FTOA_CARRY 16 /* Carry was to master position. */
 
#endif /* !_FTOA_ENGINE_H */
/C-OSD/arducam-osd/libraries/FastSerial/keywords.txt
0,0 → 1,7
FastSerial KEYWORD1
begin KEYWORD2
end KEYWORD2
available KEYWORD2
read KEYWORD2
flush KEYWORD2
write KEYWORD2
/C-OSD/arducam-osd/libraries/FastSerial/macros.inc
0,0 → 1,365
/* Copyright (c) 2002, 2005, 2006, 2007 Marek Michalkiewicz
Copyright (c) 2006 Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
 
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/*
macros.inc - macros for use in assembler sources
 
Contributors:
Created by Marek Michalkiewicz <marekm@linux.org.pl>
*/
 
#include <avr/io.h>
//#include "sectionname.h"
 
/* if not defined, assume old version with underscores */
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__ _
#endif
 
#ifndef __REGISTER_PREFIX__
#define __REGISTER_PREFIX__
#endif
 
/* the assembler line separator (just in case it ever changes) */
#define _L $
 
#define CONCAT1(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a ## b
 
#define _U(x) CONCAT1(__USER_LABEL_PREFIX__, x)
 
#define _R(x) CONCAT1(__REGISTER_PREFIX__, x)
 
/* these should help to fix the "can't have function named r1()" bug
which may require adding '%' in front of register names. */
 
#define r0 _R(r0)
#define r1 _R(r1)
#define r2 _R(r2)
#define r3 _R(r3)
#define r4 _R(r4)
#define r5 _R(r5)
#define r6 _R(r6)
#define r7 _R(r7)
#define r8 _R(r8)
#define r9 _R(r9)
#define r10 _R(r10)
#define r11 _R(r11)
#define r12 _R(r12)
#define r13 _R(r13)
#define r14 _R(r14)
#define r15 _R(r15)
#define r16 _R(r16)
#define r17 _R(r17)
#define r18 _R(r18)
#define r19 _R(r19)
#define r20 _R(r20)
#define r21 _R(r21)
#define r22 _R(r22)
#define r23 _R(r23)
#define r24 _R(r24)
#define r25 _R(r25)
#define r26 _R(r26)
#define r27 _R(r27)
#define r28 _R(r28)
#define r29 _R(r29)
#define r30 _R(r30)
#define r31 _R(r31)
 
#ifndef __tmp_reg__
#define __tmp_reg__ r0
#endif
 
#ifndef __zero_reg__
#define __zero_reg__ r1
#endif
 
#if __AVR_MEGA__
#define XJMP jmp
#define XCALL call
#else
#define XJMP rjmp
#define XCALL rcall
#endif
 
/* used only by fplib/strtod.S - libgcc internal function calls */
#define PROLOGUE_SAVES(offset) XJMP (__prologue_saves__ + 2 * (offset))
#define EPILOGUE_RESTORES(offset) XJMP (__epilogue_restores__ + 2 * (offset))
 
#if FLASHEND > 0x10000 /* ATmega103 */
#define BIG_CODE 1
#else
#define BIG_CODE 0
#endif
 
#ifndef __AVR_HAVE_MOVW__
# if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
# define __AVR_HAVE_MOVW__ 1
# endif
#endif
 
#ifndef __AVR_HAVE_LPMX__
# if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
# define __AVR_HAVE_LPMX__ 1
# endif
#endif
 
#ifndef __AVR_HAVE_MUL__
# if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
# define __AVR_HAVE_MUL__ 1
# endif
#endif
 
/*
Smart version of movw:
- uses "movw" if possible (supported by MCU, and both registers even)
- handles overlapping register pairs correctly
- no instruction generated if source and destination are the same
(may expand to 0, 1 or 2 instructions).
*/
 
.macro X_movw dst src
.L_movw_dst = -1
.L_movw_src = -1
.L_movw_n = 0
.irp reg, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
r30,r31
.ifc \reg,\dst
.L_movw_dst = .L_movw_n
.endif
.ifc \reg,\src
.L_movw_src = .L_movw_n
.endif
.L_movw_n = .L_movw_n + 1
.endr
.L_movw_n = 0
.irp reg, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
R30,R31
.ifc \reg,\dst
.L_movw_dst = .L_movw_n
.endif
.ifc \reg,\src
.L_movw_src = .L_movw_n
.endif
.L_movw_n = .L_movw_n + 1
.endr
.if .L_movw_dst < 0
.L_movw_n = 0
.rept 32
.if \dst == .L_movw_n
.L_movw_dst = .L_movw_n
.endif
.L_movw_n = .L_movw_n + 1
.endr
.endif
.if .L_movw_src < 0
.L_movw_n = 0
.rept 32
.if \src == .L_movw_n
.L_movw_src = .L_movw_n
.endif
.L_movw_n = .L_movw_n + 1
.endr
.endif
.if (.L_movw_dst < 0) || (.L_movw_src < 0)
.err ; Invalid 'X_movw' arg.
.endif
.if ((.L_movw_src) - (.L_movw_dst)) /* different registers */
.if (((.L_movw_src) | (.L_movw_dst)) & 0x01)
.if (((.L_movw_src)-(.L_movw_dst)) & 0x80) /* src < dest */
mov (.L_movw_dst)+1, (.L_movw_src)+1
mov (.L_movw_dst), (.L_movw_src)
.else /* src > dest */
mov (.L_movw_dst), (.L_movw_src)
mov (.L_movw_dst)+1, (.L_movw_src)+1
.endif
.else /* both even -> overlap not possible */
#if defined(__AVR_HAVE_MOVW__) && __AVR_HAVE_MOVW__
movw \dst, \src
#else
mov (.L_movw_dst), (.L_movw_src)
mov (.L_movw_dst)+1, (.L_movw_src)+1
#endif
.endif
.endif
.endm
 
/* Macro 'X_lpm' extends enhanced lpm instruction for classic chips.
Usage:
X_lpm reg, dst
where
reg is 0..31, r0..r31 or R0..R31
dst is z, Z, z+ or Z+
It is possible to omit both arguments.
 
Possible results for classic chips:
lpm
lpm / mov Rd,r0
lpm / adiw ZL,1
lpm / mov Rd,r0 / adiw ZL,1
For enhanced chips it is one instruction always.
 
ATTENTION: unlike enhanced chips SREG (S,V,N,Z,C) flags are
changed in case of 'Z+' dst. R0 is scratch.
*/
.macro X_lpm dst=r0, src=Z
 
/* dst evaluation */
.L_lpm_dst = -1
 
.L_lpm_n = 0
.irp reg, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, \
r10,r11,r12,r13,r14,r15,r16,r17,r18,r19, \
r20,r21,r22,r23,r24,r25,r26,r27,r28,r29, \
r30,r31
.ifc \reg,\dst
.L_lpm_dst = .L_lpm_n
.endif
.L_lpm_n = .L_lpm_n + 1
.endr
 
.L_lpm_n = 0
.irp reg, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, \
R10,R11,R12,R13,R14,R15,R16,R17,R18,R19, \
R20,R21,R22,R23,R24,R25,R26,R27,R28,R29, \
R30,R31
.ifc \reg,\dst
.L_lpm_dst = .L_lpm_n
.endif
.L_lpm_n = .L_lpm_n + 1
.endr
 
.if .L_lpm_dst < 0
.L_lpm_n = 0
.rept 32
.if \dst == .L_lpm_n
.L_lpm_dst = .L_lpm_n
.endif
.L_lpm_n = .L_lpm_n + 1
.endr
.endif
 
.if (.L_lpm_dst < 0)
.err ; Invalid dst arg of 'X_lpm' macro.
.endif
 
/* src evaluation */
.L_lpm_src = -1
.L_lpm_n = 0
.irp reg, z,Z,z+,Z+
.ifc \reg,\src
.L_lpm_src = .L_lpm_n
.endif
.L_lpm_n = .L_lpm_n + 1
.endr
 
.if (.L_lpm_src < 0)
.err ; Invalid src arg of 'X_lpm' macro.
.endif
 
/* instruction(s) */
.if .L_lpm_src < 2
.if .L_lpm_dst == 0
lpm
.else
#if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
lpm .L_lpm_dst, Z
#else
lpm
mov .L_lpm_dst, r0
#endif
.endif
.else
.if (.L_lpm_dst >= 30)
.err ; Registers 30 and 31 are inhibited as 'X_lpm *,Z+' dst.
.endif
#if defined(__AVR_HAVE_LPMX__) && __AVR_HAVE_LPMX__
lpm .L_lpm_dst, Z+
#else
lpm
.if .L_lpm_dst
mov .L_lpm_dst, r0
.endif
adiw r30, 1
#endif
.endif
.endm
 
/*
LPM_R0_ZPLUS_INIT is used before the loop to initialize RAMPZ
for future devices with RAMPZ:Z auto-increment - [e]lpm r0, Z+.
 
LPM_R0_ZPLUS_NEXT is used inside the loop to load a byte from
the program memory at [RAMPZ:]Z to R0, and increment [RAMPZ:]Z.
 
The argument in both macros is a register that contains the
high byte (bits 23-16) of the address, bits 15-0 should be in
the Z (r31:r30) register. It can be any register except for:
r0, r1 (__zero_reg__ - assumed to always contain 0), r30, r31.
*/
 
.macro LPM_R0_ZPLUS_INIT hhi
#if __AVR_ENHANCED__
#if BIG_CODE
out AVR_RAMPZ_ADDR, \hhi
#endif
#endif
.endm
 
.macro LPM_R0_ZPLUS_NEXT hhi
#if __AVR_ENHANCED__
#if BIG_CODE
/* ELPM with RAMPZ:Z post-increment, load RAMPZ only once */
elpm r0, Z+
#else
/* LPM with Z post-increment, max 64K, no RAMPZ (ATmega83/161/163/32) */
lpm r0, Z+
#endif
#else
#if BIG_CODE
/* ELPM without post-increment, load RAMPZ each time (ATmega103) */
out AVR_RAMPZ_ADDR, \hhi
elpm
adiw r30,1
adc \hhi, __zero_reg__
#else
/* LPM without post-increment, max 64K, no RAMPZ (AT90S*) */
lpm
adiw r30,1
#endif
#endif
.endm
/C-OSD/arducam-osd/libraries/FastSerial/ntz.h
0,0 → 1,54
/* Copyright (c) 2007, Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/* $Id: ntz.h 1217 2007-02-18 13:18:05Z dmix $ */
 
#ifndef _NTZ_H
#define _NTZ_H
 
/* Number of Tail Zeros: ntz(x)= (ffs(x) ? ffs(x)-1 : 16)
It works with all: cpp, gcc and gas expressions. */
#define ntz(x) \
( (1 & (((x) & 1) == 0)) \
+ (1 & (((x) & 3) == 0)) \
+ (1 & (((x) & 7) == 0)) \
+ (1 & (((x) & 017) == 0)) \
+ (1 & (((x) & 037) == 0)) \
+ (1 & (((x) & 077) == 0)) \
+ (1 & (((x) & 0177) == 0)) \
+ (1 & (((x) & 0377) == 0)) \
+ (1 & (((x) & 0777) == 0)) \
+ (1 & (((x) & 01777) == 0)) \
+ (1 & (((x) & 03777) == 0)) \
+ (1 & (((x) & 07777) == 0)) \
+ (1 & (((x) & 017777) == 0)) \
+ (1 & (((x) & 037777) == 0)) \
+ (1 & (((x) & 077777) == 0)) \
+ (1 & (((x) & 0177777) == 0)) )
 
#endif /* !_NTZ_H */
/C-OSD/arducam-osd/libraries/FastSerial/ultoa_invert.S
0,0 → 1,216
/* Copyright (c) 2005,2007 Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/* $Id: ultoa_invert.S 1944 2009-04-01 23:12:20Z arcanum $ */
 
#ifndef __DOXYGEN__
 
#include "macros.inc"
#include "ntz.h"
#include "xtoa_fast.h"
 
/* --------------------------------------------------------------------
char * __ultoa_invert (unsigned long val, char * str, int base)
 
This function is intended for usage as internal printf's one.
It differs from others of `xtoa_fast' family:
* srt[] will NOT 0 terminated.
* Sequence of digits is inverted.
* It returns pointer to first byte after a string.
* Only `XTOA_UPPER' flag is operated.
Notes:
* base: check only 8 and 16, all others are treated as 10.
(internal printf's function).
*/
 
/* Input */
#define v_lo r22
#define v_hi r23
#define v_hlo r24
#define v_hhi r25
#define str_lo r20
#define str_hi r21
#define base r18
#define flags r19
 
/* Used */
#define v_fifth r26 /* val: bits 39..32 */
#define t_lo r18 /* temporary for shifted `val' */
#define t_hi r19
#define t_hlo r20
#define t_hhi r21
#define symb r20 /* write to string */
#define cnt r27 /* shift loop counter, local arg */
 
/* Fixed */
#define rzero r1
 
/* ASSEMBLY_CLIB_SECTION */
.global __ultoa_invert
.type __ultoa_invert, "function"
 
__ultoa_invert:
X_movw ZL, str_lo
clr v_fifth ; needed for all (ultoa_lsr)
cpi base, 8
breq .L_oct
cpi base, 16
breq .L_hex
 
; decimal format
clt ; flag of val == 0
.L_dec_loop:
push v_lo ; to calculate remander
; val &= ~1
andi v_lo, ~1
; val += 2
subi v_lo, lo8(-2)
sbci v_hi, hi8(-2)
sbci v_hlo, hlo8(-2)
sbci v_hhi, hhi8(-2)
sbci v_fifth, hhi8(-2)
; val += val/2
ldi cnt, 1
rcall .L_div_add
; val += val/16
ldi cnt, 4
rcall .L_div_add
; val += val/256
add v_lo, v_hi
adc v_hi, v_hlo
adc v_hlo, v_hhi
adc v_hhi, v_fifth
adc v_fifth, rzero
; val += val/65536
add v_lo, v_hlo
adc v_hi, v_hhi
adc v_hlo, v_fifth
adc v_hhi, rzero
adc v_fifth, rzero
; val += val >> 32
add v_lo, v_fifth
adc v_hi, rzero
adc v_hlo, rzero
adc v_hhi, rzero
adc v_fifth, rzero
; division result: val /= 16
rcall .L_lsr_4 ; v_fitth := 0
brne 1f
set ; T := Z flag
1:
; rem: val_original - 10*val
pop t_hi
#if defined(__AVR_ENHANCED__) && __AVR_ENHANCED__
ldi t_lo, 10
mul t_lo, v_lo
clr r1
#else
mov r0, v_lo
lsl r0
sub t_hi, r0
lsl r0
lsl r0
#endif
sub t_hi, r0
; output digit
subi t_hi, lo8(-'0')
st Z+, t_hi
; quotient == 0 ?
brtc .L_dec_loop
; end of string
.L_eos:
X_movw r24, ZL
ret
 
; octal format
.L_oct:
mov symb, v_lo
andi symb, 7
subi symb, lo8(-'0')
st Z+, symb
ldi cnt, 3
rcall .L_lsr
brne .L_oct
rjmp .L_eos
 
; hex format
.L_hex:
mov symb, v_lo
andi symb, 0x0f
subi symb, lo8(-'0')
cpi symb, '9' + 1
brlo 3f
subi symb, lo8('9' + 1 - 'a')
sbrc flags, ntz(XTOA_UPPER) - 8
subi symb, lo8('a' - 'A')
3: st Z+, symb
rcall .L_lsr_4
brne .L_hex
rjmp .L_eos
.L_lsr_4:
ldi cnt, 4
.L_lsr:
lsr v_fifth
ror v_hhi
ror v_hlo
ror v_hi
ror v_lo
dec cnt
brne .L_lsr
; tst
sbiw v_hlo, 0 ; only Z flag is needed
cpc v_lo, rzero
cpc v_hi, rzero
ret
 
.L_div_add:
; copy to temporary
X_movw t_lo, v_lo
X_movw t_hlo, v_hlo
mov r0, v_fifth
; lsr temporary
7: lsr r0
ror t_hhi
ror t_hlo
ror t_hi
ror t_lo
dec cnt
brne 7b
; add
add v_lo, t_lo
adc v_hi, t_hi
adc v_hlo, t_hlo
adc v_hhi, t_hhi
adc v_fifth, r0 ; here r0 == 0
ret
 
.size __ultoa_invert, . - __ultoa_invert
.end
 
#endif /* !__DOXYGEN__ */
/C-OSD/arducam-osd/libraries/FastSerial/vprintf.cpp
0,0 → 1,534
// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
/*
Adapted from the avr-libc vfprintf:
 
Copyright (c) 2002, Alexander Popov (sasho@vip.bg)
Copyright (c) 2002,2004,2005 Joerg Wunsch
Copyright (c) 2005, Helmut Wallner
Copyright (c) 2007, Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
 
/* From: Id: printf_p_new.c,v 1.1.1.9 2002/10/15 20:10:28 joerg_wunsch Exp */
/* $Id: vfprintf.c,v 1.18.2.1 2009/04/01 23:12:06 arcanum Exp $ */
 
#include "BetterStream.h"
 
#include <avr/pgmspace.h>
#include <stdarg.h>
#include <string.h>
extern "C" {
#include "ftoa_engine.h"
#include "ntz.h"
#include "xtoa_fast.h"
}
 
// workaround for GCC bug c++/34734
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
#undef PSTR
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
 
#define GETBYTE(flag, mask, pnt) ({ \
unsigned char __c; \
asm ( \
"sbrc %2,%3 \n\t" \
"lpm %0,Z+ \n\t" \
"sbrs %2,%3 \n\t" \
"ld %0,Z+ " \
: "=r" (__c), \
"+z" (pnt) \
: "r" (flag), \
"I" (ntz(mask)) \
); \
__c; \
})
 
#define FL_ZFILL 0x01
#define FL_PLUS 0x02
#define FL_SPACE 0x04
#define FL_LPAD 0x08
#define FL_ALT 0x10
#define FL_WIDTH 0x20
#define FL_PREC 0x40
#define FL_LONG 0x80
 
#define FL_PGMSTRING FL_LONG
#define FL_NEGATIVE FL_LONG
 
#define FL_ALTUPP FL_PLUS
#define FL_ALTHEX FL_SPACE
 
#define FL_FLTUPP FL_ALT
#define FL_FLTEXP FL_PREC
#define FL_FLTFIX FL_LONG
 
#ifdef DESKTOP_BUILD
void
BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap)
{
char *str = NULL;
int i;
char *fmt2 = strdup(fmt);
for (i=0; fmt2[i]; i++) {
// cope with %S
if (fmt2[i] == '%' && fmt2[i+1] == 'S') {
fmt2[i+1] = 's';
}
}
vasprintf(&str, fmt2, ap);
for (i=0; str[i]; i++) {
write(str[i]);
}
free(str);
free(fmt2);
}
#else
void
BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap)
{
unsigned char c; /* holds a char from the format string */
unsigned char flags;
unsigned char width;
unsigned char prec;
unsigned char buf[11]; /* size for -1 in octal, without '\0' */
 
for (;;) {
 
/*
* Process non-format characters
*/
for (;;) {
c = GETBYTE (in_progmem, 1, fmt);
if (!c) return;
if (c == '%') {
c = GETBYTE (in_progmem, 1, fmt);
if (c != '%') break;
}
/* emit cr before lf to make most terminals happy */
if (c == '\n')
write('\r');
write(c);
}
 
flags = 0;
width = 0;
prec = 0;
/*
* Process format adjustment characters, precision, width.
*/
do {
if (flags < FL_WIDTH) {
switch (c) {
case '0':
flags |= FL_ZFILL;
continue;
case '+':
flags |= FL_PLUS;
/* FALLTHROUGH */
case ' ':
flags |= FL_SPACE;
continue;
case '-':
flags |= FL_LPAD;
continue;
case '#':
flags |= FL_ALT;
continue;
}
}
 
if (flags < FL_LONG) {
if (c >= '0' && c <= '9') {
c -= '0';
if (flags & FL_PREC) {
prec = 10*prec + c;
continue;
}
width = 10*width + c;
flags |= FL_WIDTH;
continue;
}
if (c == '.') {
if (flags & FL_PREC)
return;
flags |= FL_PREC;
continue;
}
if (c == 'l') {
flags |= FL_LONG;
continue;
}
if (c == 'h')
continue;
}
break;
} while ( (c = GETBYTE (in_progmem, 1, fmt)) != 0);
 
/*
* Handle floating-point formats E, F, G, e, f, g.
*/
if (c >= 'E' && c <= 'G') {
flags |= FL_FLTUPP;
c += 'e' - 'E';
goto flt_oper;
 
} else if (c >= 'e' && c <= 'g') {
 
int exp; /* exponent of master decimal digit */
int n;
unsigned char vtype; /* result of float value parse */
unsigned char sign; /* sign character (or 0) */
unsigned char ndigs;
 
flags &= ~FL_FLTUPP;
 
flt_oper:
if (!(flags & FL_PREC))
prec = 6;
flags &= ~(FL_FLTEXP | FL_FLTFIX);
if (c == 'e')
flags |= FL_FLTEXP;
else if (c == 'f')
flags |= FL_FLTFIX;
else if (prec > 0)
prec -= 1;
 
if (flags & FL_FLTFIX) {
vtype = 7; /* 'prec' arg for 'ftoa_engine' */
ndigs = prec < 60 ? prec + 1 : 60;
} else {
if (prec > 7) prec = 7;
vtype = prec;
ndigs = 0;
}
exp = __ftoa_engine (va_arg(ap,double), (char *)buf, vtype, ndigs);
vtype = buf[0];
sign = 0;
if ((vtype & FTOA_MINUS) && !(vtype & FTOA_NAN))
sign = '-';
else if (flags & FL_PLUS)
sign = '+';
else if (flags & FL_SPACE)
sign = ' ';
 
if (vtype & (FTOA_NAN | FTOA_INF)) {
const char *p;
ndigs = sign ? 4 : 3;
if (width > ndigs) {
width -= ndigs;
if (!(flags & FL_LPAD)) {
do {
write(' ');
} while (--width);
}
} else {
width = 0;
}
if (sign)
write(sign);
p = PSTR("inf");
if (vtype & FTOA_NAN)
p = PSTR("nan");
while ( (ndigs = pgm_read_byte((const prog_char *)p)) != 0) {
if (flags & FL_FLTUPP)
ndigs += 'I' - 'i';
write(ndigs);
p++;
}
goto tail;
}
 
/* Output format adjustment, number of decimal digits in buf[] */
if (flags & FL_FLTFIX) {
ndigs += exp;
if ((vtype & FTOA_CARRY) && buf[1] == '1')
ndigs -= 1;
if ((signed char)ndigs < 1)
ndigs = 1;
else if (ndigs > 8)
ndigs = 8;
} else if (!(flags & FL_FLTEXP)) { /* 'g(G)' format */
if (exp <= prec && exp >= -4)
flags |= FL_FLTFIX;
while (prec && buf[1+prec] == '0')
prec--;
if (flags & FL_FLTFIX) {
ndigs = prec + 1; /* number of digits in buf */
prec = prec > exp
? prec - exp : 0; /* fractional part length */
}
}
/* Conversion result length, width := free space length */
if (flags & FL_FLTFIX)
n = (exp>0 ? exp+1 : 1);
else
n = 5; /* 1e+00 */
if (sign) n += 1;
if (prec) n += prec + 1;
width = width > n ? width - n : 0;
/* Output before first digit */
if (!(flags & (FL_LPAD | FL_ZFILL))) {
while (width) {
write(' ');
width--;
}
}
if (sign) write(sign);
if (!(flags & FL_LPAD)) {
while (width) {
write('0');
width--;
}
}
if (flags & FL_FLTFIX) { /* 'f' format */
 
n = exp > 0 ? exp : 0; /* exponent of left digit */
do {
if (n == -1)
write('.');
flags = (n <= exp && n > exp - ndigs)
? buf[exp - n + 1] : '0';
if (--n < -prec)
break;
write(flags);
} while (1);
if (n == exp
&& (buf[1] > '5'
|| (buf[1] == '5' && !(vtype & FTOA_CARRY))) )
{
flags = '1';
}
write(flags);
} else { /* 'e(E)' format */
 
/* mantissa */
if (buf[1] != '1')
vtype &= ~FTOA_CARRY;
write(buf[1]);
if (prec) {
write('.');
sign = 2;
do {
write(buf[sign++]);
} while (--prec);
}
 
/* exponent */
write(flags & FL_FLTUPP ? 'E' : 'e');
ndigs = '+';
if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY) != 0)) {
exp = -exp;
ndigs = '-';
}
write(ndigs);
for (ndigs = '0'; exp >= 10; exp -= 10)
ndigs += 1;
write(ndigs);
write('0' + exp);
}
 
goto tail;
}
 
/*
* Handle string formats c, s, S.
*/
{
const char * pnt;
size_t size;
 
switch (c) {
 
case 'c':
buf[0] = va_arg (ap, int);
pnt = (char *)buf;
size = 1;
goto no_pgmstring;
 
case 's':
pnt = va_arg (ap, char *);
size = strnlen (pnt, (flags & FL_PREC) ? prec : ~0);
no_pgmstring:
flags &= ~FL_PGMSTRING;
goto str_lpad;
 
case 'S':
// pgmstring: // not yet used
pnt = va_arg (ap, char *);
size = strnlen_P (pnt, (flags & FL_PREC) ? prec : ~0);
flags |= FL_PGMSTRING;
 
str_lpad:
if (!(flags & FL_LPAD)) {
while (size < width) {
write(' ');
width--;
}
}
while (size) {
write(GETBYTE (flags, FL_PGMSTRING, pnt));
if (width) width -= 1;
size -= 1;
}
goto tail;
}
}
 
/*
* Handle integer formats variations for d/i, u, o, p, x, X.
*/
if (c == 'd' || c == 'i') {
long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
flags &= ~(FL_NEGATIVE | FL_ALT);
if (x < 0) {
x = -x;
flags |= FL_NEGATIVE;
}
c = __ultoa_invert (x, (char *)buf, 10) - (char *)buf;
 
} else {
int base;
 
if (c == 'u') {
flags &= ~FL_ALT;
base = 10;
goto ultoa;
}
 
flags &= ~(FL_PLUS | FL_SPACE);
 
switch (c) {
case 'o':
base = 8;
goto ultoa;
case 'p':
flags |= FL_ALT;
/* no break */
case 'x':
if (flags & FL_ALT)
flags |= FL_ALTHEX;
base = 16;
goto ultoa;
case 'X':
if (flags & FL_ALT)
flags |= (FL_ALTHEX | FL_ALTUPP);
base = 16 | XTOA_UPPER;
ultoa:
c = __ultoa_invert ((flags & FL_LONG)
? va_arg(ap, unsigned long)
: va_arg(ap, unsigned int),
(char *)buf, base) - (char *)buf;
flags &= ~FL_NEGATIVE;
break;
 
default:
return;
}
}
 
/*
* Format integers.
*/
{
unsigned char len;
 
len = c;
if (flags & FL_PREC) {
flags &= ~FL_ZFILL;
if (len < prec) {
len = prec;
if ((flags & FL_ALT) && !(flags & FL_ALTHEX))
flags &= ~FL_ALT;
}
}
if (flags & FL_ALT) {
if (buf[c-1] == '0') {
flags &= ~(FL_ALT | FL_ALTHEX | FL_ALTUPP);
} else {
len += 1;
if (flags & FL_ALTHEX)
len += 1;
}
} else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
len += 1;
}
 
if (!(flags & FL_LPAD)) {
if (flags & FL_ZFILL) {
prec = c;
if (len < width) {
prec += width - len;
len = width;
}
}
while (len < width) {
write(' ');
len++;
}
}
width = (len < width) ? width - len : 0;
 
if (flags & FL_ALT) {
write('0');
if (flags & FL_ALTHEX)
write(flags & FL_ALTUPP ? 'X' : 'x');
} else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
unsigned char z = ' ';
if (flags & FL_PLUS) z = '+';
if (flags & FL_NEGATIVE) z = '-';
write(z);
}
while (prec > c) {
write('0');
prec--;
}
do {
write(buf[--c]);
} while (c);
}
tail:
/* Tail is possible. */
while (width) {
write(' ');
width--;
}
} /* for (;;) */
}
#endif // DESKTOP_BUILD
/C-OSD/arducam-osd/libraries/FastSerial/xtoa_fast.h
0,0 → 1,48
/*
Adapted from avr-libc:
 
Copyright (c) 2005, Dmitry Xmelkov
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
 
/* $Id: xtoa_fast.h 1223 2007-02-18 13:33:09Z dmix $ */
 
#ifndef _XTOA_FAST_H_
#define _XTOA_FAST_H_
 
#ifndef __ASSEMBLER__
 
/* Internal function for use from `printf'. */
char * __ultoa_invert (unsigned long val, char *s, int base);
 
#endif /* ifndef __ASSEMBLER__ */
 
/* Next flags are to use with `base'. Unused fields are reserved. */
#define XTOA_PREFIX 0x0100 /* put prefix for octal or hex */
#define XTOA_UPPER 0x0200 /* use upper case letters */
 
#endif /* _XTOA_FAST_H_ */