Beispiel #1
0
void main(void) {
	volatile packet_t *p;
	volatile uint8_t t=20;
	uint8_t chan;
	char c;

	gpio_data(0);
	
	gpio_pad_dir_set( 1ULL << LED );
        /* read from the data register instead of the pad */
	/* this is needed because the led clamps the voltage low */
	gpio_data_sel( 1ULL << LED);

	/* trim the reference osc. to 24MHz */
	trim_xtal();

	uart_init(UART1, 115200);

	vreg_init();

	maca_init();

        /* sets up tx_on, should be a board specific item */
        *GPIO_FUNC_SEL2 = (0x01 << ((44-16*2)*2));
	gpio_pad_dir_set( 1ULL << 44 );

	set_power(0x0f); /* 0dbm */
	chan = 0;
	set_channel(chan); /* channel 11 */

	*MACA_MACPANID = 0xaaaa;
	*MACA_MAC16ADDR = 0x1111;
	*MACA_TXACKDELAY = 68; /* 68 puts the tx ack at about the correct spot */
	set_prm_mode(AUTOACK);

	print_welcome("rftest-rx");
	while(1) {		

		/* call check_maca() periodically --- this works around */
		/* a few lockup conditions */
		check_maca();

		if((p = rx_packet())) {
			/* print and free the packet */
			printf("autoack-rx --- ");
			print_packet(p);
			maca_free_packet(p);
		}

		if(uart1_can_get()) {
			c = uart1_getc();
			if(c == 'z') t++;
			if(c == 'x') t--;
			*MACA_TXACKDELAY = t;
			printf("tx ack delay: %d\n\r", t);
		}

	}
}
Beispiel #2
0
// read len bytes from serial
void readData(byte *bData, int len)
{
    while (len-- > 0)
    {
        *bData = uart1_getc();
        bData++;
    }
}
Beispiel #3
0
//Hilfsfunktion:
void flushdata(void)
{
	uint8_t blank = 0;

	for(uint8_t i = 0; i < 20; i++)
	{
		blank = uart1_getc();            
	}
}
Beispiel #4
0
// Get a string from the ring buffer.
// If bytes are in the buffer, the receive function will run as long
// as the buffer is not empty.
void receiveStringUART ( char* inputString, uint8_t stringSize )
{
	// Received character and error bitmask.
	unsigned int inputChar;
	
	// Get a character from the ring buffer.
	// Do this in a loop as long as new data is in the buffer.
	for(uint8_t charIndex = 0; charIndex<stringSize-1; charIndex++)
	{
		// Get byte from the buffer.
		// uart_getc returns the data byte and an error code.
		inputChar = uart1_getc();

		// Evaluate the error code to see if any data was passed.
		// If no data was passed...
		if ( inputChar & UART_NO_DATA )
		{
			//... append end of string character.
			// This will also clear the input string if nothing was received.
			inputString[charIndex] = '\0';
			// Exit the loop.
			break;
		}
		// Evaluate error codes.
		// In case of frame error...
		else if ( inputChar & UART_FRAME_ERROR )
		{
			//... send back error message.
			uart1_puts_P("UART Frame Error: ");
		}
		// In case of overrun error...
		else if ( inputChar & UART_OVERRUN_ERROR )
		{
			//... send back error message.
			// Overrun, a character already present in the UART UDR register was 
			// not read by the interrupt handler before the next character arrived,
			// one or more received characters have been dropped
			uart1_puts_P("UART Overrun Error: ");
		}
		// In case of buffer overflow...
		else if ( inputChar & UART_BUFFER_OVERFLOW )
		{
			//... send back error message.
			uart1_puts_P("Buffer overflow error: "); 
			// We are not reading the receive buffer fast enough,
			// one or more received character have been dropped 
		}
		// Finally, assemble the character to a string.
		inputString[charIndex] = inputChar;
	}
	// Return the pointer to the received string.
//	return inputString;
}
Beispiel #5
0
void main(void) {

	uart1_init(INC,MOD,SAMP);
	
	while(1) {
		if(uart1_can_get()) {
			/* Receive buffer isn't empty */
			/* read a byte and write it to the transmit buffer */
			uart1_putc(uart1_getc());
		}
	}
	
}
Beispiel #6
0
int main(void) 
{
	int x = 32768;
	
	trim_xtal();
	uart_init(UART1, 115200);
	rtc_init();
	
	printf("pwm test\r\n");
	pwm_init_stopped(TMR0, 12000000, x);
	pwm_init_stopped(TMR1, 12000000, x);
	TMR0->ENBL |= TMR_ENABLE_BIT(TMR0) | TMR_ENABLE_BIT(TMR1);

	for(;;) {
		printf("duty %d = %d%%\r\n", x, ((x * 100 + 32768) / 65536));
		switch(uart1_getc()) {
		case '[': x -= 1; break;
		case ']': x += 1; break;
		case '-': x -= 32; break;
		case '=': x += 32; break;
		case '_': x -= 512; break;
		case '+': x += 512; break;

		case '`': x = 65535 * 0/10; break;
		case '1': x = 65535 * 1/10; break;
		case '2': x = 65535 * 2/10; break;
		case '3': x = 65535 * 3/10; break;
		case '4': x = 65535 * 4/10; break;
		case '5': x = 65535 * 5/10; break;
		case '6': x = 65535 * 6/10; break;
		case '7': x = 65535 * 7/10; break;
		case '8': x = 65535 * 8/10; break;
		case '9': x = 65535 * 9/10; break;
		case '0': x = 65535 * 10/10; break;

		}
		x &= 65535;
		pwm_duty(TMR0, x);
	}
}
Beispiel #7
0
void main(void) {
	volatile packet_t *p;
	char c;
	uint16_t r=30; /* start reception 100us before ack should arrive */
	uint16_t end=180; /* 750 us receive window*/

	/* trim the reference osc. to 24MHz */
	trim_xtal();

	uart_init(UART1, 115200);

	vreg_init();

	maca_init();

	set_channel(0); /* channel 11 */
//	set_power(0x0f); /* 0xf = -1dbm, see 3-22 */
//	set_power(0x11); /* 0x11 = 3dbm, see 3-22 */
	set_power(0x12); /* 0x12 is the highest, not documented */

        /* sets up tx_on, should be a board specific item */
	GPIO->FUNC_SEL_44 = 1;	 
	GPIO->PAD_DIR_SET_44 = 1;	 

	GPIO->FUNC_SEL_45 = 2;	 
	GPIO->PAD_DIR_SET_45 = 1;	 

	*MACA_RXACKDELAY = r;
	
	printf("rx warmup: %d\n\r", (int)(*MACA_WARMUP & 0xfff));

	*MACA_RXEND = end;

	printf("rx end: %d\n\r", (int)(*MACA_RXEND & 0xfff));

	set_prm_mode(AUTOACK);

	print_welcome("rftest-tx");

	while(1) {		
	    		
		/* call check_maca() periodically --- this works around */
		/* a few lockup conditions */
		check_maca();

		while((p = rx_packet())) {
			if(p) {
				printf("RX: ");
				print_packet(p);
				free_packet(p);
			}
		}

		if(uart1_can_get()) {
			c = uart1_getc();

			switch(c) {
			case 'z':
				r++;
				if(r > 4095) { r = 0; }
				*MACA_RXACKDELAY = r;
				printf("rx ack delay: %d\n\r", r);
				break;
			case 'x':
				if(r == 0) { r = 4095; } else { r--; }
				*MACA_RXACKDELAY = r;
				printf("rx ack delay: %d\n\r", r);
				break;
			case 'q':
				end++;
				if(r > 4095) { r = 0; }
				*MACA_RXEND = end;
				printf("rx end: %d\n\r", end);
				break;
			case 'w':
				end--;
				if(r == 0) { r = 4095; } else { r--; }
				*MACA_RXEND = end;
				printf("rx end: %d\n\r", end);
				break;
			default:
				p = get_free_packet();
				if(p) {
					fill_packet(p);
					
					printf("autoack-tx --- ");
					print_packet(p);
					
					tx_packet(p);				
				}
				break;
			}
		}
		
	}

}
void check_wlan_cmd()
{
	static unsigned char cmdstate = WLANCMD_NONE;	// Status des aktuellen Befehls
	static unsigned char cindex = 0;		// Position in wlan_string (global)
	unsigned int c;						// zum Verarbeiten des aktuellen Zeichens
	unsigned char exit;					// für while-Schleifen-Ausstieg
	unsigned char uarterror;			// UART Empfangsfehler

	exit = 0;

	while(!exit)
	{
		// uart0_getc() returns in the lower byte the received character and in the higher byte (bitmask) the last receive error
		// UART_NO_DATA is returned when no data is available.

		uarterror = 0;
		//c = uart0_getc();	//

		#if defined( WLAN_UART_NR )	// WLAN_UART_NR = 1
			c = uart1_getc();
		#else // WLAN_UART_NR = 0
			c = uart0_getc();
		#endif	// WLAN_UART_NR




		if ( c & UART_NO_DATA )	//no data available from UART
		{
			exit = 1;
		}
		else	// data available
		{

			// new data available from UART - check for Frame or Overrun error

			if ( c & UART_FRAME_ERROR )
			{
				// Framing Error detected, i.e no stop bit detected
				uarterror = 1;
			}
			if ( c & UART_OVERRUN_ERROR )
			{
				// Overrun, a character already present in the UART UDR register was
				// not read by the interrupt handler before the next character arrived,
				// one or more received characters have been dropped
				uarterror = 2;
			}
			if ( c & UART_BUFFER_OVERFLOW )
			{
				// We are not reading the receive buffer fast enough,  one or more received character have been dropped
				uarterror = 3;
			}

			// empfangenes Zeichen verarbeiten

			if (!uarterror)	// falls kein Fehler aufgetreten ist
			{
				char d = (char)c;

				if (d == 60)	// > Befehl beginnt
				{

					cmdstate = WLANCMD_STARTED;	// ab nun Zeichen nach wlan_string übernehmen
					cindex = 0;
					memset(wlan_string, 0, UART_MAXSTRLEN+1);
				}
				else if (d == 62)	// > abschließendes Zeichen wurde empfangen
				{
					if (cmdstate == WLANCMD_STARTED) { befehl_auswerten(); }
					cmdstate = WLANCMD_NONE;
				}
				else
				{
					if (cmdstate == WLANCMD_STARTED)	// Zeichen in Befehl übernehmen
					{
						if (cindex < UART_MAXSTRLEN)
						{
							wlan_string[cindex] = d;
							cindex++;
						}
						else { cmdstate = WLANCMD_NONE; }	// Befehl ist zu lange - muss ignoriert werden!
					}
				}
			}
			else { cmdstate = WLANCMD_NONE; }	// bei uarterror bisherige Befehlsdaten verwerfen
		}


	} // end while loop


} //end check_wlan_cmd()
Beispiel #9
0
int main(void) {

	mc1322x_init();

	/* m12_init() flips the mux switch */

	/* trims the main crystal load capacitance */
	if (!FORCE_ECONOTAG_I && CRM->SYS_CNTLbits.XTAL32_EXISTS) {
		/* M12 based econotag */
		PRINTF("trim xtal for M12\n\r");
		CRM->XTAL_CNTLbits.XTAL_CTUNE = (M12_CTUNE_4PF << 4) | M12_CTUNE;
		CRM->XTAL_CNTLbits.XTAL_FTUNE = M12_FTUNE;

		/* configure pullups for low power */
		GPIO->FUNC_SEL.GPIO_63 = 3;
		GPIO->PAD_PU_SEL.GPIO_63 = 0;
		GPIO->FUNC_SEL.SS = 3;
		GPIO->PAD_PU_SEL.SS = 1;
		GPIO->FUNC_SEL.VREF2H = 3;
		GPIO->PAD_PU_SEL.VREF2H = 1;
		GPIO->FUNC_SEL.U1RTS = 3;
		GPIO->PAD_PU_SEL.U1RTS = 1;

	} else {
		/* econotag I */
		PRINTF("trim xtal for Econotag I\n\r");
		CRM->XTAL_CNTLbits.XTAL_CTUNE = (ECONOTAG_CTUNE_4PF << 4) | ECONOTAG_CTUNE;
		CRM->XTAL_CNTLbits.XTAL_FTUNE = ECONOTAG_FTUNE;
	}

	/* create mac address if blank*/
	if (mc1322x_config.eui == 0) {
		/* mac address is blank */
		/* construct a new mac address based on IAB or OUI definitions */

		/* if an M12_SERIAL number is not defined */
		/* generate a random extension in the Redwire experimental IAB */
		/* The Redwire IAB (for development only) is: */
		/* OUI: 0x0050C2 IAB: 0xA8C */
		/* plus a random 24-bit extension */
		/* Otherwise, construct a mac based on the M12_SERIAL */
		/* Owners of an Econotag I (not M12 based) can request a serial number from Redwire */
		/* to use here */

		/* M12 mac is of the form "EC473C4D12000000" */
		/* Redwire's OUI: EC473C */
		/* M12: 4D12 */
		/* next six nibbles are the M12 serial number as hex */
		/* e.g. if the barcode reads: "12440021" = BDD1D5 */
		/* full mac is EC473C4D12BDD1D5 */

#if (M12_SERIAL == 0)
                /* use random mac from experimental range */
		mc1322x_config.eui = (0x0050C2A8Cull << 24) | (*MACA_RANDOM & (0xffffff));
#else
		/* construct mac from serial number */
		mc1322x_config.eui = (0xEC473C4D12ull << 24) | M12_SERIAL;
#endif
		mc1322x_config_save(&mc1322x_config);		
	} 
	
	/* configure address on maca hardware and RIME */
	contiki_maca_set_mac_address(mc1322x_config.eui);

#if NETSTACK_CONF_WITH_IPV6
	memcpy(&uip_lladdr.addr, &linkaddr_node_addr.u8, sizeof(uip_lladdr.addr));
	queuebuf_init();
	NETSTACK_RDC.init();
	NETSTACK_MAC.init();
	NETSTACK_NETWORK.init();
  #if DEBUG_ANNOTATE
	print_netstack();
  #endif
#if ! SLIP_RADIO
	process_start(&tcpip_process, NULL);
#endif
  #if DEBUG_ANNOTATE
	print_lladdrs();
  #endif
#endif /* endif NETSTACK_CONF_WITH_IPV6 */

	process_start(&sensors_process, NULL);

	print_processes(autostart_processes); 
	autostart_start(autostart_processes);

	/* Main scheduler loop */
	while(1) {
		check_maca();

		if(uart1_input_handler != NULL) {
			if(uart1_can_get()) {
				uart1_input_handler(uart1_getc());
			}
		}
		
		process_run();
	}
	
	return 0;
}
Beispiel #10
0
uint8_t um6_rwc(uint8_t um6_register, uint8_t batch, uint8_t r_w_c, uint16_t um6_result[], uint8_t data_size)
{
	uint8_t checksum0 = 0;
	uint8_t checksum1 = 0;
	uint16_t checksum = 0;
	uint8_t pt_is_batch = 0;
	if(batch > 0)
	{
		pt_is_batch = PT_IS_BATCH;
	}

	if(r_w_c == UM6_DATA_READ)
		checksum = ('s'+'n'+'p' + (pt_is_batch | batch) + um6_register);
	else if(r_w_c == UM6_DATA_WRITE)
		checksum = ('s'+'n'+'p' + (PT_HAS_DATA | pt_is_batch | batch) + um6_register);
	else if(r_w_c == UM6_DATA_CMD)
		checksum = ('s'+'n'+'p' + um6_register);
	checksum1 = checksum >> 8;
	checksum0 = checksum & 0xff;

	uart1_putc('s');
	uart1_putc('n');
	uart1_putc('p');
	if(r_w_c == UM6_DATA_READ)
		uart1_putc(pt_is_batch | batch); //PT
	else if(r_w_c == UM6_DATA_WRITE)
		uart1_putc(PT_HAS_DATA | pt_is_batch | batch);
	else //if(r_w_c == UM6_DATA_CMD)
		uart1_putc(0);
	uart1_putc(um6_register); //ADR
	uart1_putc(checksum1); //Checksum1
	uart1_putc(checksum0); //Checksum1

	uint8_t data[8] = {0};
	uint16_t data_sum = 0;

	//if((r_w_c == UM6_DATA_CMD) || (r_w_c == UM6_DATA_WRITE))
	//	_delay_ms(25); //UM6 braucht dann etwas Zeit zum Antworten

	uint8_t new_dat = uart1_getc();
	if(new_dat & UART_NO_DATA)
	{
		//no data
		return 7;
	}
	else if(new_dat == 's')
	{
		if(uart1_getc() == 'n')
		{
			if(uart1_getc() == 'p')
			{
				uint8_t r_w_c_batch = uart1_getc();
				if( ((r_w_c_batch == (PT_HAS_DATA | pt_is_batch | batch)) && (r_w_c == UM6_DATA_READ)) ||
						((r_w_c_batch == 0) && (r_w_c == UM6_DATA_WRITE)) || //== 0 wegen COMMAND_COMPLETE
						((r_w_c_batch == 0) && (r_w_c == UM6_DATA_CMD)))
				{
					if(uart1_getc() == um6_register)
					{	
						uint8_t i_stop = 0;
						if(batch > 0)
						{
							i_stop = batch;
						}
						else
						{
							i_stop = 4; //1 Register
						}

						for(uint8_t i = 0; i<i_stop; i++)
						{
							data[i] = uart1_getc();
							data_sum += data[i];
						}
						checksum1 = uart1_getc();
						checksum0 = uart1_getc();
						checksum = ((checksum1 << 8) | checksum0);
						if( ((checksum == ('s' + 'n' + 'p' + (PT_HAS_DATA | pt_is_batch | batch) + um6_register + data_sum)) && (r_w_c == UM6_DATA_READ)) ||
								((checksum == 0) && (r_w_c == UM6_DATA_WRITE)) ||
								((checksum == 0) && (r_w_c == UM6_DATA_CMD)))
						{
							for(uint8_t i = 0; i < data_size; i++)
							{
								um6_result[i] = (data[(i*2)+1] | (data[(i*2)]<<8));
							}

							return 0;
						}
						else
						{
							flushdata();
							return 1;
						}
					}
					else
					{
						flushdata();
						return 2;
					}
				}
				else
				{
					flushdata();
					return 3;
				}
			}
			else
			{
				flushdata();
				return 4;
			}
		}
		else
		{
			flushdata();
			return 5;
		}
	}
	else
	{
		flushdata();
		return 6;
	}
}
Beispiel #11
0
int main(void) {
	nvmType_t type=0;
	nvmErr_t err;
	volatile uint8_t c;
	volatile uint32_t i;
	volatile uint32_t buf[4];
	volatile uint32_t len=0;
	volatile uint32_t state = SCAN_X;
	volatile uint32_t addr,data;


	uart_init(UART1, 115200);
	disable_irq(UART1);

	vreg_init();

	dbg_putstr("Detecting internal nvm\n\r");

	err = nvm_detect(gNvmInternalInterface_c, &type);
		
	dbg_putstr("nvm_detect returned: 0x");
	dbg_put_hex(err);
	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");
	
	err = nvm_read(gNvmInternalInterface_c, type, (uint8_t *)nvm_base, NVM_BASE, 0x100);
	dbg_putstr("nvm_read returned: 0x");
	dbg_put_hex(err);
	dbg_putstr("\n\r");

	/* erase the flash */
	nvm_setsvar(0);
	err = nvm_erase(gNvmInternalInterface_c, type, 0x40000000);

	dbg_putstr("nvm_erase returned: 0x");
	dbg_put_hex(err);
	dbg_putstr("\n\r");

	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");

	err = nvm_write(gNvmInternalInterface_c, type, (uint8_t *)nvm_base, NVM_BASE, 0x100);
	dbg_putstr("nvm_write returned: 0x");
	dbg_put_hex(err);
	dbg_putstr("\n\r");

	/* say we are ready */
	len = 0;
	putstr("ready");
	flushrx();

	/* read the length */
	for(i=0; i<4; i++) {
		c = uart1_getc();
		/* bail if the first byte of the length is zero */
		len += (c<<(i*8));
	}

	dbg_putstr("len: ");
	dbg_put_hex32(len);
	dbg_putstr("\n\r");
	
	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");

	putstr("flasher done\n\r");

	state = SCAN_X; addr=0;
	while((c=getc())) {
		if(state == SCAN_X) {
			/* read until we see an 'x' */
			if(c==0) { break; }
			if(c!='x'){ continue; } 	
			/* go to read_chars once we have an 'x' */
			state = READ_CHARS;
			i = 0; 
		}
		if(state == READ_CHARS) {
			/* read all the chars up to a ',' */
			((uint8_t *)buf)[i++] = c;
			/* after reading a ',' */
			/* goto PROCESS state */
			if((c == ',') || (c == 0)) { state = PROCESS; }				
		}
		if(state == PROCESS) {
			if(addr==0) {
				/*interpret the string as the starting address */
				addr = to_u32(buf);				
			} else {
				/* string is data to write */
				data = to_u32(buf);
				putstr("writing addr ");
				put_hex32(NVM_BASE+addr);
				putstr(" data ");
				put_hex32(data);
				err = nvm_write(gNvmInternalInterface_c, type, (uint8_t *)&data, NVM_BASE+addr, 4);
				addr += 4;
				putstr(" err ");
				put_hex32(err);
				putstr("\n\r");
			}
			/* look for the next 'x' */
			state=SCAN_X;
		}
	}
        putstr("process flasher done\n\r");

	while(1) {continue;};
}
Beispiel #12
0
void main(void) {
	nvmType_t type=0;
	nvmErr_t err;
	volatile uint8_t c;
	volatile uint32_t i;
	volatile uint32_t buf[4];
	volatile uint32_t len=0;
	volatile uint32_t state = SCAN_X;
	volatile uint32_t addr,data;


	uart_init(INC, MOD, SAMP);
	disable_irq(UART1);

	vreg_init();

	dbg_putstr("Detecting internal nvm\n\r");

	err = nvm_detect(gNvmInternalInterface_c, &type);
		
	dbg_putstr("nvm_detect returned: 0x");
	dbg_put_hex(err);
	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");
	
	/* erase the flash */
	err = nvm_erase(gNvmInternalInterface_c, type, 0x7fffffff); 

	dbg_putstr("nvm_erase returned: 0x");
	dbg_put_hex(err);
	dbg_putstr("\n\r");

	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");

	/* say we are ready */
	len = 0;
	putstr("ready");
	flushrx();

	/* read the length */
	for(i=0; i<4; i++) {
		c = uart1_getc();
		/* bail if the first byte of the length is zero */
		len += (c<<(i*8));
	}

	dbg_putstr("len: ");
	dbg_put_hex32(len);
	dbg_putstr("\n\r");
	
	/* write the OKOK magic */

#if BOOT_OK
	((uint8_t *)buf)[0] = 'O'; ((uint8_t *)buf)[1] = 'K'; ((uint8_t *)buf)[2] = 'O'; ((uint8_t *)buf)[3] = 'K';	
#elif BOOT_SECURE
	((uint8_t *)buf)[0] = 'S'; ((uint8_t *)buf)[1] = 'E'; ((uint8_t *)buf)[2] = 'C'; ((uint8_t *)buf)[3] = 'U';	
#else
	((uint8_t *)buf)[0] = 'N'; ((uint8_t *)buf)[1] = 'O'; ((uint8_t *)buf)[2] = 'N'; ((uint8_t *)buf)[3] = 'O';
#endif

	dbg_putstr(" type is: 0x");
	dbg_put_hex32(type);
	dbg_putstr("\n\r");

	/* don't make a valid boot image if the received length is zero */
	if(len == 0) {
		((uint8_t *)buf)[0] = 'N'; 
		((uint8_t *)buf)[1] = 'O'; 
		((uint8_t *)buf)[2] = 'N'; 
		((uint8_t *)buf)[3] = 'O';
	}
	
	err = nvm_write(gNvmInternalInterface_c, type, (uint8_t *)buf, 0, 4);

	dbg_putstr("nvm_write returned: 0x");
	dbg_put_hex(err);
	dbg_putstr("\n\r");

	/* write the length */
	err = nvm_write(gNvmInternalInterface_c, type, (uint8_t *)&len, 4, 4);

	/* read a byte, write a byte */
	for(i=0; i<len; i++) {
		c = getc();	       
		err = nvm_write(gNvmInternalInterface_c, type, (uint8_t *)&c, 8+i, 1); 
	}

	putstr("flasher done\n\r");

	state = SCAN_X; addr=0;
	while((c=getc())) {
		if(state == SCAN_X) {
			/* read until we see an 'x' */
			if(c==0) { break; }
			if(c!='x'){ continue; } 	
			/* go to read_chars once we have an 'x' */
			state = READ_CHARS;
			i = 0; 
		}
		if(state == READ_CHARS) {
			/* read all the chars up to a ',' */
			((uint8_t *)buf)[i++] = c;
			/* after reading a ',' */
			/* goto PROCESS state */
			if((c == ',') || (c == 0)) { state = PROCESS; }				
		}
		if(state == PROCESS) {
			if(addr==0) {
				/*interpret the string as the starting address */
				addr = to_u32(buf);				
			} else {
				/* string is data to write */
				data = to_u32(buf);
				putstr("writing addr ");
				put_hex32(addr);
				putstr(" data ");
				put_hex32(data);
				putstr("\n\r");
				err = nvm_write(gNvmInternalInterface_c, 1, (uint8_t *)&data, addr, 4);
				addr += 4;
			}
			/* look for the next 'x' */
			state=SCAN_X;
		}
	}

	while(1) {continue;};
}