Needing a scanf function for my app, I have written a simple subset. I
got the whole lot working really well with Borland C, then ported it to
MSP. That's when the REAL problems began.
First, I just couldn't get pointers to be passed at all. I simplified
the whole thing so that just sscanf is implemented (that saved one level
of indirection), and got that working at least for a couple of simple
tests.
However, when I add the -O switch to the compiler options, it stops
working. It's a bit complicated to explain the details, but basically
nothing gets assigned except strings and characters.
I'm using the 28-08-2002 build of the Windows version of MSPGCC - the
latest version won't compile at all, it just gives an internal compikler
error.
As the program is a big, apologies, but here it is. It runs on my own
prototype board on an MSP430F448 at 6MHz.
Any help much appreciated!
Paul Burke
The program:
#include <io.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define FALSE 0
#define TRUE 1
#define EOF -1
typedef unsigned int UINT;
typedef unsigned long ULONG;
void wait( ULONG cyc);
void UartInit( int port);
void uputc( char c, int port);
void uputs( int port, char * str);
UINT RxRdy(int port);
UINT ugetc( int port);
void putc0( char c);
void putc1( char c);
#define term_printf(format,args...) uprintf(putc1, format, args)
#define term_puts( str) uputs(1, str)
#define term_putc(c) putc1(c)
#define term_getc() ugetc(1)
char RxBuff[2][32];
int RxIptr[2];
int RxOptr[2];
unsigned char ticks;
unsigned char secs;
unsigned char mins;
unsigned int hrs;
int sscanf(char *str , char *ctl, void* arg,...);
const char scstr[] = "-1256 136 4512 -18567009 0xDEAD T String";
const char scstr2[] = "1256136451218567009DEADTStringandtherest";
int pa=125,pb,pc;
long pd;
int pe;
char pf[16];
char pg;
int main(void)
{
int c;
int i;
ULONG t;
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
FLL_CTL0 |= XTS_FLL; // Configure oscillator
UartInit(0); // Initialise both Uarts
UartInit(1);
_EINT(); // Enable interrupts
P5DIR = 0xff;
P5OUT = 0;
P6DIR |= 0x20; // P6.5 is Port 1 multiplexer output
P6OUT &= ~0x20; // Multiplexer to Audio/GPS header
while(1)
{
int nconvs ;
nconvs = sscanf( scstr, "%d %d %d %ld %x %c %s", &pa, &pb, &pc, &pd,
&pe, &pg, pf);
term_printf( "%d: a=%d, b=%d, c=%d, d=%ld, e=0x%x, f=%s, g=%c\r\n",
nconvs, pa,pb,pc,pd,pe,pf,pg);
nconvs = sscanf( scstr2, "%4d %3d %4d %8ld %4x %c %5s", &pa, &pb, &pc,
&pd, &pe, &pg, pf);
term_printf( "%d: a=%d, b=%d, c=%d, d=%ld, e=0x%x, f=%s, g=%c\r\n",
nconvs, pa,pb,pc,pd,pe,pf,pg);
term_getc();
}
return 0;
}
#define LIT 0
#define FMTW 1
#define FMTT 2
#define T_NONE 0
#define T_CHAR 1
#define T_INT 2
#define T_LONG 3
#define T_STR 4
int sscanf(char *ip , char *ctl, void *args,...)
{
void **arg; // Pointer to next arg
unsigned int nargs = 0; // Conversions completed
unsigned int mod = LIT;
unsigned int FieldWidth; // Width of field
int Sign; // Positive number
unsigned int base;
unsigned int Signed;
unsigned int Siz;
unsigned int Skip; // Suppression
unsigned int c;
char Leader = 0;
union { int i; long l;} val;
int i;
arg = &args;
while( *ctl) // Run along the format string
{
INPUT_SPACES: // Skip input string spaces
c = *(ip++);
if( !c)
return nargs; // Input finished
if( isspace(c))
goto INPUT_SPACES;
ip--; // Put back first nonspace
while( isspace( *ctl) ) // skip format string spaces
++ctl;
if( !ctl)
return nargs; // finished the format string
switch( mod)
{
case LIT:
if( *ctl == '%') // Start formatted convert?
{
base = 0;
FieldWidth = 0;
Sign = 1;
val.l = 0;
Skip = 0;
Siz = T_NONE;
mod = FMTW;
ctl++;
continue;
}
if( *(ctl++) != *(ip++) ) // Otherwise just a literal match
return nargs; // No match, so finished
continue;
case FMTW:
if( *ctl == '%') // Literal %
{
if( *(ip++) != '%')
return nargs;
ctl++;
mod = LIT;
continue;
}
FieldWidth = 0; // Presume infinite width
if( !isdigit( *ctl) )
{
mod = FMTT; // Not a digit, so try type
continue;
}
else // Numbers are field size
{
while( isdigit( *ctl))
FieldWidth = FieldWidth * 10 + (*(ctl++) - '0');
mod = FMTT;
continue;
}
case FMTT:
if( *ctl == 'l') // long
{
if( Siz == T_LONG)
return nargs; // Second l, so buggered up
Siz = T_LONG;
ctl++;
continue;
}
if( *ctl == 'd') // Decimal signed
{
if(base)
return nargs; // Second conversion spec, so buggered
up
if( !Siz) // Already long?
Siz = T_INT; // No, so INT
base = 10;
Signed = 1;
goto CVT;
}
if( *ctl == 'u') // Unsigned
{
if(base)
return nargs; // Second conversion spec, so buggered
up
if( !Siz) // Already long?
Siz = T_INT; // No, so INT
base = 10;
Signed = 0;
goto CVT;
}
if( *ctl == 'x') // Hex
{
if(base)
return nargs; // Second conversion spec, so buggered
up
if( !Siz) // Already long?
Siz = T_INT; // No, so INT
base = 16;
Signed = 0;
goto CVT;
}
if( *ctl == 'o') // Octal
{
if(base)
return nargs; // Second conversion spec, so buggered
up
if( !Siz) // Already long?
Siz = T_INT; // No, so INT
base = 8;
Signed = 0;
goto CVT;
}
if( *ctl == 'c') // Characters
{
if( base || ( Siz == T_LONG))
return nargs; // Second conversion spec, so buggered
up
Siz = T_CHAR;
base = -1;
goto CVT;
}
if( *ctl == 's') // String
{
if( base || ( Siz == T_LONG))
return nargs; // Second conversion spec, so buggered
up
Siz = T_STR;
base = -2;
goto CVT;
}
if( *ctl == '*') // Suppress
{
if(base || Siz || Skip || FieldWidth)
return nargs; // Got conversion spec, so buggered up
Skip = 1;
ctl++;
continue;
}
}
// Formatted now, so ready to convert the input!!
CVT:
switch( Siz)
{
case T_NONE:
break;
case T_CHAR:
if( !FieldWidth) // Not specified, default 1
FieldWidth = 1;
for( i=0; i < FieldWidth; i++)
{
int c = *(ip++);
if( !c) // Break on end of string
break;
if( c == EOF) // finish on EOF (if possible)
return nargs;
if( !Skip) // Skip or assign and increment pointer
*(char *)arg[nargs]++ = c;
}
break;
case T_STR:
for( i=0; (i < FieldWidth) || !FieldWidth ; i++)
{
int c = *(ip++);
if( !c || isspace(c)) // Finish on space or null
{
if( !Skip) // Assign if not blocked
*(char *)arg[nargs] = 0;
break;
}
if( c == EOF) // Check for input end/ error
return nargs;
if( !Skip)
*(char *)arg[nargs]++ = c;
}
break;
case T_INT:
case T_LONG:
{
// Run along the field until you have enough characters
// If FieldWidth not defined, it is infinite
for( i=0; (i<FieldWidth) || !FieldWidth; i++)
{
c = *(ip++);
if( c == EOF)
return nargs;
if( (base == 16) ? !isxdigit(c) : !isdigit(c))
{
if( (c == '-') && Signed)
{
Sign = -1;
i--;
continue;
}
else
{
if( base == 16)
{
if( (c == 'x') || (c == 'X'))
if( !val.l && !Leader)
{
Leader = 1;
i-=2;
continue;
}
else
return nargs;
}
else if( base == 8)
{
if( (c == 'o') || (c == 'O'))
if( !val.l && !Leader)
{
Leader = 1;
i--;
continue;
}
else
return nargs;
}
ip--;
break;
}
}
else
{
if( base == 16)
{
c = tolower(c);
if( c > '9')
c = c -'a'+10;
else
c -= '0';
}
else
c -= '0';
val.l = val.l * base + c ;
}
}
if( !Skip)
{
if( Siz == T_INT)
*(int *)arg[nargs] = val.i*Sign;
else
*(long *)arg[nargs] = val.l*Sign;
}
}
break;
}
if( !Skip)
nargs++; // On to the next parameter
ctl++;
mod = LIT; // Reset to literals
}
return nargs;
}
//**********************************************************/
//
// Serial Port Routines
//
//**********************************************************/
//_______________________________________________________
//
// Initialise Uarts
//
void Uart0_Init(void)
{
UTCTL0 = 0x10 /*SSEL0*/; // UCLK = ACLK
UBR00 = 0x71; // 1MHz 9600
UBR10 = 0x02; // 1MHz 9600
UMCTL0 = 0x00; // no modulation
ME1 |= 0xc0; /*UTXE0 + URXE0;*/ // Enable USART0 TXD/RXD
UCTL0 |= CHAR; // 8-bit character
UCTL0 &= 0xfe; // clear SWRST
IE1 |= URXIE0; // Enable USART0 RX interrupt
P2SEL |= 0x30; // P2.4,5 = USART0 TXD/RXD
P2DIR |= 0x10; // P2.4 output direction
RxIptr[0] = 0;
RxOptr[0] = 0;
}
void Uart1_Init(void)
{
UTCTL1 = 0x10 /*SSEL0*/; // UCLK = ACLK
UBR01= 0x71; // 1MHz 9600
UBR11 = 0x02; // 1MHz 9600
UMCTL1 = 0x00; // no modulation
ME2 |= 0x30; //UTXE1 + URXE1; // Enable USART1 TXD/RXD
UCTL1 |= CHAR; // 8-bit character
UCTL1 &= 0xfe; // clear SWRST
IE2 |= 0x10; //URXIE1; // Enable USART1 RX
interrupt
P4SEL |= 0x03; // P4.0,1 = USART1 TXD/RXD
P4DIR |= 0x01; // P4.0 output direction
RxIptr[1] = 0;
RxOptr[1] = 0;
}
void UartInit( int port)
{
if( port == 0)
Uart0_Init();
else if( port == 1)
Uart1_Init();
}
//_______________________________________________________
//
// Check for character ready
// If UART not exist, returns 1 (ready)
//
UINT RxRdy(int port)
{
if( port >1 )
return 1;
{
if( RxIptr[port] == RxOptr[port])
return 0;
return 1;
}
return 0;
}
//_______________________________________________________
//
// Get received character
//
UINT ugetc(int port)
{
int c;
if( port >1 )
return 0;
while( !RxRdy(port))
;
c = RxBuff[port][RxOptr[port]];
RxOptr[port] = (RxOptr[port]+1) & 31;
return c;
}
//_______________________________________________________
//
// Transmit a character
//
void putc0( char c)
{
while ((IFG1 & UTXIFG0) == 0)
;
// Wait for USART0 TX buffer ready
TXBUF0 = c;
}
void putc1( char c)
{
while ((IFG2 & UTXIFG1) == 0)
;
// Wait for USART1 TX buffer ready
TXBUF1 = c;
}
void uputc( char c, int port)
{
if( port > 1)
return;
if( port == 0)
putc0(c);
else
putc1(c);
}
void uputs( int port, char *str)
{
while( *str)
uputc( *(str++), port);
}
//_______________________________________________________
//
// Serial Interrupt routines
//
interrupt(UART0RX_VECTOR) usart0_rx(void)
{
RxBuff[0][ RxIptr[0]] = RXBUF0; // RXBUF0 to buffer
RxIptr[0] = (RxIptr[0]+1) & 31;
}
interrupt(UART1RX_VECTOR) usart1_rx(void)
{
RxBuff[1][ RxIptr[1]] = RXBUF1; // RXBUF1 to buffer
RxIptr[1] = (RxIptr[1]+1) & 31;
}
//**********************************************************
// Watchdog Timer interrupt service routine
interrupt (WDT_VECTOR) watchdog_timer(void)
{
char oddeven;
oddeven++;
ticks++;
if( ticks > 91 + (oddeven&1) )
{
ticks = 0;
secs++;
if( secs > 59)
{
secs = 0;
mins++;
if( mins > 59)
{
mins = 0;
hrs++;
}
}
}
}