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++;
   }
  }
 }
}

Reply via email to