avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-libc-dev] Re: snprintf bug ?


From: Russell Strong
Subject: Re: [avr-libc-dev] Re: snprintf bug ?
Date: Thu, 13 Oct 2005 20:46:25 +1000

Hi,

The following is the full source and Makefile for my snprintf bug


/****************************************************************
 *                                                              *
 * Dasboot Navigation Module                                    *
 *                                                              *
 * Russell Strong <address@hidden> 21/9/2005              *
 *                                                              *
 * Designed for ATmega128.                                      *
 * FUSE settings for Jed Micro 570v1 module with 16Mhz crystal  *
 *                                                              *
 * Fuse Low Byte      = 0xff                                    *
 * Fuse High Byte     = 0x9f                                    *
 * Fuse Extended Byte = 0xfe                                    *
 * Calibration Byte   = 0xb2  --  Read Only                     *
 * Lock Bits          = 0xff                                    *
 *    BLB12 -> 1                                                *
 *    BLB11 -> 1                                                *
 *    BLB02 -> 1                                                *
 *    BLB01 -> 1                                                *
 *      LB2 -> 1                                                *
 *      LB1 -> 1                                                *
 *                                                              *
 ****************************************************************/

#define F_CPU 16000000UL
#include <avr/io.h>
#include <inttypes.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/wdt.h>

#define BUFFER_SIZE             100

#define MODULE_ID               "05"

#define MODULE_NAME_CMD         "("MODULE_ID"0)"
#define MODULE_VERSION_CMD      "("MODULE_ID"1)"
#define HEADING_CMD             "("MODULE_ID"2)"
#define GPGGA_CMD               "("MODULE_ID"3)"
#define GPGSV1_CMD              "("MODULE_ID"4)"
#define GPGSV2_CMD              "("MODULE_ID"5)"
#define GPGSV3_CMD              "("MODULE_ID"6)"
#define GPVTG_CMD               "("MODULE_ID"7)"
#define PGRME_CMD               "("MODULE_ID"8)"
#define PGRMT_CMD               "("MODULE_ID"9)"

#define MODULE_NAME             "NAV MODULE\r"
#define MODULE_VERSION          "M05 V1\r"

static unsigned char gps_buff_next = 0;
static char gps_buff[BUFFER_SIZE];
static unsigned char gps_timeout_count = 0;

static char gpgga  [BUFFER_SIZE] = "\r";
static char gpgsv1 [BUFFER_SIZE] = "\r";
static char gpgsv2 [BUFFER_SIZE] = "\r";
static char gpgsv3 [BUFFER_SIZE] = "\r";
static char gpvtg  [BUFFER_SIZE] = "\r";
static char pgrme  [BUFFER_SIZE] = "\r";
static char pgrmt  [BUFFER_SIZE] = "\r";
static char heading [BUFFER_SIZE] = "\r";

static unsigned char bus_buff_next = 0;
static char bus_buff[BUFFER_SIZE];

static unsigned char bus_resp_buff_next = 0;
static char bus_resp_buff[BUFFER_SIZE];

void setup_hardware (void) __attribute__ ((naked)) __attribute__
((section (".init1")));
void setup_hardware (void)
{
        _wdt_write (WDTO_2S);   // Enabled via the fuses, i.e. don't need to
enable here.
                                // Just set the period to 2 seconds.
        PORTA = 0xFE;   // pullups on, outputs low.
        DDRA = 0x01;    // bit 0 = bus drivers

        PORTB = 0xFF;   // pullups on
        PORTC = 0xFF;   // pullups on
        PORTD = 0xFF;   // pullups on
        PORTE = 0xFF;   // pullups on
        PORTF = 0xFF;   // pullups on
        PORTG = 0x1F;   // pullups on
}

/******************************************************************
 *                                                                *
 * GPS COMMUNICATIONS                                             *
 *                                                                *
 ******************************************************************/

static void test_gps_timeout (void)
{
        if (gps_timeout_count++ == 50) {
                cli();
                gpgga[0] = '\r';
                gpgga[1] = '\0';
                gpgsv1[0] = '\r';
                gpgsv1[1] = '\0';
                gpgsv2[0] = '\r';
                gpgsv2[1] = '\0';
                gpgsv3[0] = '\r';
                gpgsv3[1] = '\0';
                gpvtg[0] = '\r';
                gpvtg[1] = '\0';
                pgrme[0] = '\r';
                pgrme[1] = '\0';
                pgrmt[0] = '\r';
                pgrmt[1] = '\0';
                sei();
        }
}

static void process_gps_message (void)
{
        // GPGGA
        if (gps_buff[4]=='G' && gps_buff[5]=='A') {
                strcpy (gpgga, gps_buff+7);
                return;
        }

        // GPGSV
        if (gps_buff[4]=='S' && gps_buff[5]=='V') {
                unsigned char comma_count=0, i=0;
                while (comma_count < 2) {
                        if ((gps_buff[i] == '\0') || (i == BUFFER_SIZE-1))
                                return;
                        if (gps_buff[i] == ',')
                                comma_count++;
                        i++;
                }
                switch (gps_buff[i]) {
                        case '1':
                                strcpy (gpgsv1, gps_buff+7);
                                break;
                        case '2':
                                strcpy (gpgsv2, gps_buff+7);
                                break;
                        case '3':
                                strcpy (gpgsv3, gps_buff+7);
                                break;
                        default:
                                break;
                }
                return;
        }

        // GPVTG
        if (gps_buff[4]=='T' && gps_buff[5]=='G') {
                strcpy (gpvtg, gps_buff+7);
                return;
        }

        // PGRME
        if (gps_buff[4]=='M' && gps_buff[5]=='E') {
                strcpy (pgrme, gps_buff+7);
                return;
        }

        // PGRMT
        if (gps_buff[4]=='M' && gps_buff[5]=='T')
                strcpy (pgrmt, gps_buff+7);
}

SIGNAL (SIG_USART0_RECV)
{
        char c = UDR0;

        gps_timeout_count = 0;

        if (c == '$') {
                gps_buff[0] = c;
                gps_buff_next = 1;
                return;
        }

        if (gps_buff_next == BUFFER_SIZE-2) {
                gps_buff_next = 0;
                return;
        }

        gps_buff[gps_buff_next++] = c;
        if (c == '*') {
                gps_buff[gps_buff_next++] = '\r';
                gps_buff[gps_buff_next] = '\0';
                process_gps_message ();
                gps_buff_next = 0;
        }
}

/******************************************************************
 *                                                                *
 * DASBOOT BUS COMMUNICATIONS                                     *
 *                                                                *
 ******************************************************************/

static inline void start_bus_transmit (void)
{
        if (bus_resp_buff[0] != '\0') {
                PORTA |= _BV(0);
                bus_resp_buff_next = 1;
                UDR1 = bus_resp_buff[0];
                UCSR1B |= _BV(UDRIE1);
        }
}

static inline void process_bus_message ()
{
        if (strcmp(bus_buff, HEADING_CMD) == 0) {
                strcpy(bus_resp_buff, heading);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, GPGGA_CMD) == 0) {
                strcpy(bus_resp_buff, gpgga);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, GPVTG_CMD) == 0) {
                strcpy(bus_resp_buff, gpvtg);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, PGRME_CMD) == 0) {
                strcpy(bus_resp_buff, pgrme);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, GPGSV1_CMD) == 0) {
                strcpy(bus_resp_buff, gpgsv1);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, GPGSV2_CMD) == 0) {
                strcpy(bus_resp_buff, gpgsv2);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, GPGSV3_CMD) == 0) {
                strcpy(bus_resp_buff, gpgsv3);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, PGRMT_CMD) == 0) {
                strcpy(bus_resp_buff, pgrmt);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, MODULE_NAME_CMD) == 0) {
                strcpy(bus_resp_buff, MODULE_NAME);
                start_bus_transmit();
                return;
        }
        if (strcmp(bus_buff, MODULE_VERSION_CMD) == 0) {
                strcpy(bus_resp_buff, MODULE_VERSION);
                start_bus_transmit();
                return;
        }
}

SIGNAL (SIG_USART1_RECV)
{
        char c = UDR1;

        if (c == '(') {
                bus_buff[0] = c;
                bus_buff_next = 1;
                return;
        }

        if (bus_buff_next == BUFFER_SIZE-1) {
                bus_buff_next = 0;
                return;
        }

        bus_buff[bus_buff_next++] = c;
        if (c == ')') {
                bus_buff[bus_buff_next] = '\0';
                process_bus_message ();
                bus_buff_next = 0;
        }
}

SIGNAL (SIG_USART1_DATA)
{
        char c = bus_resp_buff[bus_resp_buff_next++];

        if (c == '\0')
                UCSR1B &= ~_BV(UDRIE1);
        else
                UDR1 = c;
}

SIGNAL (SIG_USART1_TRANS)
{
        if (!(UCSR1B & _BV(UDRIE1)))
                PORTA &= ~_BV(0);
}

/******************************************************************
 *                                                                *
 * COMPASS COMMUNICATIONS (mostly)                                *
 *                                                                *
 ******************************************************************/

#define HDG_CNT 60

static int headings[HDG_CNT] = {0};

static void insert_heading (hdg)
{
        static unsigned char next = 0;
        headings[next] = hdg;
        next = (next + 1) % HDG_CNT;
}

static int delta_heading (hdg, base_hdg)
{
        int cw, ccw;
        cw = hdg - base_hdg;
        if (cw < 0)
                cw += 3600;
        ccw = base_hdg - hdg;
        if (ccw < 0)
                ccw += 3600;
        if (cw < ccw)
                return cw;
        else
                return -ccw;
}

static void update_heading_string (int hdg_reading)
{
        long delta = 0;
        unsigned char i;
        static int base_hdg = 0;
//      static char heading_tmp[5];     // This works
        char heading_tmp[5];            // This doesn't work

        insert_heading (hdg_reading);

        for (i=0;i<HDG_CNT;i++)
                delta += delta_heading (headings[i], base_hdg);

        base_hdg += delta / HDG_CNT;
        if (base_hdg >= 3600)
                base_hdg -= 3600;
        else if (base_hdg < 0)
                base_hdg += 3600;
        
        snprintf (heading_tmp, 5, "%04X", base_hdg);

        // store heading ready for bus transmission
        cli();
        heading[0] = heading_tmp[0];
        heading[1] = heading_tmp[1];
        heading[2] = heading_tmp[2];
        heading[3] = heading_tmp[3];
        heading[4] = '\r';
        heading[5] = '\0';
        sei();
}

int main () __attribute__ ((naked));
int main ()
{
        // For some reason, initiallizing USART 1 in section .init1
        // causes the USART to have the wrong baud rate after a power on reset.
        // However resetting using the reset switch, would install the correct
        // settings. It would appear that USART1 takes longer than the rest of
        // the MCU to become stable after power is applied.  This is why 
        // peripheral initiallisation has been moved to the main function.
        // PIN directions and initial values are still done in section .init1
        // And I did tried this on multiple MCUs.

        // USART 0 GPS Interface
        UBRR0H = 0x01; // 4800 8N1 ( actual 4808 bps )
        UBRR0L = 0x9F;
        UCSR0A = _BV(UDRE0) | _BV(U2X0);
        UCSR0B = _BV(RXEN0) | _BV(RXCIE0);

        // USART 1 DASBOOT BUS Interface
        UBRR1H = 0x00; // 57600 8N1 ( actual 57142 bps )
        UBRR1L = 0x22;
        UCSR1A = _BV(UDRE1) | _BV(U2X1);
        UCSR1B = _BV(RXEN1) | _BV(TXEN1) | _BV(RXCIE1) | _BV(TXCIE1);

        // Compass TWI Interface
        TWSR |= _BV(TWPS0);     // TWI Prescaler ( / 4 )
        TWBR = 0x26;            // TWI Bit Rate ( 50000 bps )

        sei ();

        for(;;) {
                unsigned char heading_byte_1, heading_byte_2;

                wdt_reset ();   

                _delay_ms (100.0);  // FIXME - not behaving as expected ? check 
on CRO

                // Test for GPS timeout
                test_gps_timeout ();

                // Send start condition
                TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);

                // Wait for TWINT flag set. This indicates that the START
                // condition has been transmitted.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI Status Register. Mask Prescalar bits.
                // If status different from START goto error.
                if ((TWSR & 0xF8) != 0x08) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Load SLA_W into TWDR register.  Clear TWINT bit in TWCR
                // to start transmission of address
                // 0xC0 is address with write bit of CMPS03
                TWDR = 0xC0;
                TWCR = _BV(TWINT) | _BV(TWEN);

                // Wait for TWINT flag set.  This indicates that the SLA_W
                // has been transmitted, and ACK/NACK has been received.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI status register. Mask prescalar bits.
                // If status different from MT_SLA_ACK goto error.
                if ((TWSR & 0xF8) != 0x18) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Load DATA into TWDR register.  Clear TWINT bit in TWCR to
                // start transmission of data.
                // Send 0x02 to CMPS03 to read register 2,3.
                TWDR = 0x02;
                TWCR = _BV(TWINT) | _BV(TWEN);

                // Wait for TWINT flag set.  This indicates that the DATA has
                // been transmitted, and ACK/NACK has been recieved
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI status register.  Mask prescalar bits.
                // If status different from MT_DATA_ACK goto error.
                if ((TWSR & 0xF8) != 0x28) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Send repeated start condition.
                TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);

                // Wait for TWINT flag set. This indicates that the REPEATED
                // START condition has been transmitted.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI Status Register. Mask Prescalar bits.
                // If status different from REPEATED START goto error.
                if ((TWSR & 0xF8) != 0x10) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Load SLA_R into TWDR register.  Clear TWINT bit in TWCR
                // to start transmission of address
                // 0xC1 is address with read bit of CMPS03
                TWDR = 0xC1;
                TWCR = _BV(TWINT) | _BV(TWEN);

                // Wait for TWINT flag set. This indicates that the SLA_R
                // has been transmitted.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI Status Register. Mask Prescalar bits.
                // If status different from MT_SLA_R_ACK goto error.
                if ((TWSR & 0xF8) != 0x40) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Clear TWINT bit in TWCR to start receiving the first data
                // byte.  Set TWEA to generate an ack condition when byte 
received.
                TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);

                // Wait for TWINT flag set. This indicates that DATA
                // has been recieved and ACK or NACK is set.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI Status Register. Mask Prescalar bits.
                // If status different from DATA byte recieved with ACK then
                // goto error.
                if ((TWSR & 0xF8) != 0x50) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Save the first data byte
                heading_byte_1 = TWDR;

                // Clear TWINT bit in TWCR to start receiving the second data
                // byte. Set TWEA to generate a NAK condition when byte 
received.
                TWCR = _BV(TWINT) | _BV(TWEN);

                // Wait for TWINT flag set. This indicates that DATA
                // has been recieved and ACK or NACK is set.
                while (!(TWCR & _BV(TWINT)));

                // Check value of TWI Status Register. Mask Prescalar bits.
                // If status different from DATA byte recieved with NAK then
                // goto error.
                if ((TWSR & 0xF8) != 0x58) {
                        TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
                        continue;
                }

                // Save the second data byte
                heading_byte_2 = TWDR;

                // Stop condition
                TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);

                // update heading for bus tranmission
                update_heading_string (heading_byte_1 * 256 + heading_byte_2);
        }
}




PRG         =navigation
OBJ         =navigation.o
MCU_TARGET     = atmega128
OPTIMIZE       = -O2

DEFS       =
LIBS       =

# You should not have to change anything below here.

CC           = avr-gcc

# Override is only needed by avr-lib build system.

override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS       = -Wl,-Map,$(PRG).map

OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump

all: $(PRG).elf lst text eeprom

$(PRG).elf: $(OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)

clean:
        rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak 
        rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)

lst:  $(PRG).lst

%.lst: %.elf
        $(OBJDUMP) -h -S $< > $@

# Rules for building the .text rom images

text: hex bin srec

hex:  $(PRG).hex
bin:  $(PRG).bin
srec: $(PRG).srec

%.hex: %.elf
        $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.srec: %.elf
        $(OBJCOPY) -j .text -j .data -O srec $< $@

%.bin: %.elf
        $(OBJCOPY) -j .text -j .data -O binary $< $@

# Rules for building the .eeprom rom images

eeprom: ehex ebin esrec

ehex:  $(PRG)_eeprom.hex
ebin:  $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec

%_eeprom.hex: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@

%_eeprom.srec: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@

%_eeprom.bin: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@

# Every thing below here is used by avr-libc's build system and can be
ignored
# by the casual user.

FIG2DEV          = fig2dev
EXTRA_CLEAN_FILES       = *.hex *.bin *.srec

dox: eps png pdf

eps: $(PRG).eps
png: $(PRG).png
pdf: $(PRG).pdf

%.eps: %.fig
        $(FIG2DEV) -L eps $< $@

%.pdf: %.fig
        $(FIG2DEV) -L pdf $< $@

%.png: %.fig
        $(FIG2DEV) -L png $< $@



On Thu, 2005-10-13 at 09:53 +0200, Joerg Wunsch wrote:
> As Russell Strong wrote:
> 
> > Am I doing something illegal? Do snprintf pointers need to be
> > static?
> 
> No, and no.
> 
> Can you provide a full, compilable example that demonstrates the
> problem?
> 

Attachment: signature.asc
Description: This is a digitally signed message part


reply via email to

[Prev in Thread] Current Thread [Next in Thread]