Latest firmware released to Spark Build

@RWB

@RWB

Yes! This adds

  1. Reliability, Reliability, Reliability: The core will re-connection in ~20 seconds or less, on CFOD, wifi resets with no address within 30 seconds or no wifi reconnect after being connected. (try it pull the WAN plug on your AP or router, or if you have a wifi switch (or the ability (openwrt) to do a “wifi down”, “wifi” commands on your router)

  2. A complete re-write of TI/Sparks CC3000 driver

  3. A refactoring of TI event handle to add reliability timeouts on network actions like connect etc.

  4. Numerous fixes for memory over-wites in TI driver and Spark Protocol

  5. Moved time base to the core-common-lib

  6. PANIC - any Faults will blink the RGB led in a red blink pattern of …—… (SOS) N Blinks …—… repeat.
    (for release build this is cut short but the WDT @zachary - we need a ticket for this)

Where N is one of the panic codes below:

1	(Faults,RGB_COLOR_RED,HardFault) 
2	(Faults,RGB_COLOR_RED,NMIFault)
3	(Faults,RGB_COLOR_RED,MemManage)
4	(Faults,RGB_COLOR_RED,BusFault)
5	(Faults,RGB_COLOR_RED,UsageFault)
6	(Cloud,RGB_COLOR_RED,InvalidLenth)
7	(System,RGB_COLOR_RED,Exit)
8	(System,RGB_COLOR_RED,OutOfHeap)
9	(System,RGB_COLOR_RED,SPIOverRun)
10	(Softare,RGB_COLOR_RED,AssertionFailure)
11	(Softare,RGB_COLOR_RED,InvalidCase)
  1. Added SPARK_ASSERT a macro to PANIC on assertion failure

  2. Full runtime and compile time controlled logging (like log4j) For now only avaiable under a local build (There is a ticket in to get a DEBUG setting in the WebIDE)

To use it

define DEBUG_BUILD=y on make command line

Add the following to your Application.cpp

    void debug_output_(const char *p)
    {
      static boolean once = false;
     if (!once)
       {
         once = true;
         Serial1.begin(115200); // You can choose where the debug goes 
       }
    
     Serial1.print(p);
    }

The API looks like and supports printf format specifies.


LOG("Want %d more cores",count);
WARN("Running %s on cores only %d more left",,"Low",count);
DEBUG("connection closed %d",retValue);
ERROR("Flash write Failed @0x%0x",badd_address);
PANIC(HardFault,"Hit Hardfault");

Output looks like:

0003187040:<DEBUG> int Spark_Connect() (639):connet
0003187179:<DEBUG> int Spark_Connect() (641):connected connect=0
0003233369:<DEBUG> void loop1() (164):0 total Bytes Read
0003233374:<DEBUG> virtual void TCPClient::stop() (175):closesocket=134277261
0003233381:<DEBUG> void loop1() (166):connection closed state 4
0003235908:<DEBUG> void loop1() (84):connecting
0003235916:<DEBUG> virtual int TCPClient::connect(IPAddress, uint16_t) (61):socket=1
0003236023:<DEBUG> virtual int TCPClient::connect(IPAddress, uint16_t) (78):connected=1
0003236037:<DEBUG> void loop1() (97): Send
0003236042:<DEBUG> void loop1() (99): Sent
0003260515:<DEBUG> int Spark_Disconnect() (648):
0003260519:<DEBUG> int Spark_Disconnect() (653):send
0003260524:<DEBUG> int Spark_Disconnect() (656):Close
0003260529:<DEBUG> int Spark_Disconnect() (659):Closed retVal=-57
0003260535:<DEBUG> int Spark_Connect() (617):socket
0003260540:<DEBUG> int Spark_Connect() (619):socketed sparkSocket=0
0003260546:<DEBUG> int Spark_Connect() (639):connet
0003261230:<DEBUG> int Spark_Connect() (641):connected connect=0
0003311025:<DEBUG> void loop1() (164):0 total Bytes Read
0003311030:<DEBUG> virtual void TCPClient::stop() (175):closesocket=134277261
0003311037:<DEBUG> void loop1() (166):connection closed state 4
0003313554:<DEBUG> void loop1() (84):connecting
0003313561:<DEBUG> virtual int TCPClient::connect(IPAddress, uint16_t) (61):socket=1
0003313668:<DEBUG> virtual int TCPClient::connect(IPAddress, uint16_t) (78):connected=1
0003313682:<DEBUG> void loop1() (97): Send
0003313687:<DEBUG> void loop1() (99): Sent
0003334431:<DEBUG> int Spark_Disconnect() (648):
0003334435:<DEBUG> int Spark_Disconnect() (653):send
0003334440:<DEBUG> int Spark_Disconnect() (656):Close
0003334445:<DEBUG> int Spark_Disconnect() (659):Closed retVal=-57
0003334451:<DEBUG> int Spark_Connect() (617):socket
0003334456:<DEBUG> int Spark_Connect() (619):socketed sparkSocket=0

My test app, does http get, 1 UDP receive , and 1 UDP sendto but only on a CodeSoucery tool stream build. This is because CS builds the app using less memory.

But now if you app uses too much memory not you will get an OutOfHeap PANIC (SOS 8 blinks SOS)


/* Includes ------------------------------------------------------------------*/  
#include "application.h"


#define RENEW_INTERVAL      5*1000      // 30 secs
#define RETRY_INTERVAL      5*1000      // 10 secs
#define RESPONSE_INTERVAL   1*1000       // 1 sec
#define LET_IT_FILL_INTERVAL   3*1000       // 1 sec

TCPClient client;
char server[] = "nscdg.com";

// IO
int led = D2;

// Globals
volatile int state = 0;
volatile int wait = 0;
volatile int loopwait = 10;

volatile int tries = 0;
volatile int store = 0;
volatile int hash = 0;

volatile char command[32];
volatile int command_i=0;


#include "application.h"

uint8_t buffer[TCPCLIENT_BUF_MAX_SIZE+1]; // for EOT
int loops = 0;
int total = 0;
int wcl=2;


#define SERVER_IP 10,10,0,1
//------------------------------
#define SERVER_PORT 9999
#define WAIT_TIME 3000

UDP udpClient;
IPAddress serverAddress(SERVER_IP);

void setup2() {
  pinMode(D2,OUTPUT);
}

system_tick_t lastMillis = (system_tick_t) -WAIT_TIME;

char buf[50];


void loop2() {
    if(millis() > lastMillis + WAIT_TIME){
        udpClient.begin(SERVER_PORT);
        udpClient.beginPacket(serverAddress,SERVER_PORT);
        snprintf(buf, sizeof(buf),"tick %ld", lastMillis);
        udpClient.write(buf);
        udpClient.endPacket();
        lastMillis = millis();
        DEBUG("tick ************ %ld",lastMillis);
        digitalWrite(D2,HIGH);
        delay(20);
        digitalWrite(D2,LOW);
        udpClient.stop();

  }
}


UDP Udp2;
void setup3()
{

    DEBUG("UDB RX");

    pinMode(led, OUTPUT);
    // Button resistorless
    state = 0;
    wait = RETRY_INTERVAL;
    Udp2.begin(8738);
    // Connecting
}

void loop3()
{
      delay(1);
      if (++loops == 100) {
          loops = 0;
        int packetSize = Udp2.parsePacket();
        DEBUG("parsePacket %d", packetSize);
        if(packetSize > 0)
        {
          int count = Udp2.read(buffer,sizeof(buffer));
          buffer[count] = '\0';
          DEBUG("read %d %s", count, buffer);
          total += count;
        }
      }
}




int bad_mod = 0;
int bad_every = 0;
void setup1()
{

    LOG("Test TCP BAD Every %d Usage!",bad_every);

    pinMode(led, OUTPUT);
    // Button resistorless
    state = 0;
    wait = RETRY_INTERVAL;

    // Connecting
}

void loop1()
{
    delay(1);
    switch(state){
        case 0:
            // Waiting for next time
            wait-=10;
            if(wait<0){
                wait = 0;
                state = 1;
            }
            break;
        case 1:
            // Connecting
            bad_mod++;
            DEBUG("connecting");
            total = 0;
            if (client.connect(server, 80)){
                state = 2;
            }else{
                DEBUG("connection failed state 1");
                wait = RETRY_INTERVAL;
                state = 0;
            }
            break;
        case 2:
            // Requesting
            if(client.connected()){
                DEBUG (" Send");
                client.println("GET /t.php HTTP/1.0\r\n\r\n");
                if (bad_every  && ((bad_mod % bad_every) == 0))
                  {
                    DEBUG (" Sent but not Reading it!");
                    wait = 1000 * 18; // longer then spark com time
                    state = -2;
                  } else {
                      DEBUG (" Sent Doing Read");
                      wait = RETRY_INTERVAL;
                      state = -3;

                  }
            }else{
                DEBUG("connection lost state 2");
                wait = RETRY_INTERVAL;
                state = 0;
            }
            break;

        case -2:
          if ((wait % 500) ==0) {
              DEBUG("Waiting client.status()=%d",client.status()) ;
          }
#if defined(GOOD)
          if (!client.status()) {
              state = 4;
              DEBUG("Waiting Aborted - Closing") ;
          }
#endif
          wait--;

          if(wait<0){
              wait = 0;
              state = 4;
          }
          break;

        case -3:
          if (client.available()) {
              DEBUG ("Ready");
              state = 3;
              loops = 0;
          }
          wait--;
          if(wait<0){
              wait = 0;
              state = 4;
          }
          break;

        case 3: {
          if(!client.connected()){
              wait = 1;
              state = 4;
          } else {
              // Receiving
            int count = client.available();
            if (count) {
                  DEBUG("client.available() %d", count);
                  // Print response to serial
                  DEBUG("client.peek %d", client.peek());

                  count = client.read(buffer, arraySize(buffer));
                  buffer[count] ='\0';
                  char *p = strstr((const char *)buffer,"0.1.2.3");
                  if (p)
                    {
                     total = -(p-(char*)buffer);
                    }
                  total += count;
                  DEBUG("client.read() %d", count);
                  debug_output_((const char*)buffer);
                  debug_output_("\r\n");
             }
          }
        }
            break;
        case 4:
          DEBUG("\r\n\r\n");
          DEBUG("%d total Bytes Read\r\n\r\n",total);
            // Disconnecting
            if(client.connected()){
                client.stop();
                DEBUG("connection closed state 4");
                wait = RENEW_INTERVAL;
                state = 0;
            }else{
                DEBUG("connection closed by server state 4");
                wait = RENEW_INTERVAL;
                state = 0;
            }
            break;
      }
}



/* Function prototypes -------------------------------------------------------*/
int tinkerDigitalRead(String pin);
int tinkerDigitalWrite(String command);
int tinkerAnalogRead(String pin);
int tinkerAnalogWrite(String command);

/* This function is called once at start up ----------------------------------*/
void setup()
{
	//Setup the Tinker application here

	//Register all the Tinker functions

        setup1();
        setup2();
        setup3();
	Spark.function("digitalread", tinkerDigitalRead);
	Spark.function("digitalwrite", tinkerDigitalWrite);

	Spark.function("analogread", tinkerAnalogRead);
	Spark.function("analogwrite", tinkerAnalogWrite);

}

/* This function loops forever --------------------------------------------*/
void loop()
{
	loop1();
	loop2();
	loop3();
	//This will run in a loop
}

void debug_output_(const char *p)
{
  static boolean once = false;
 if (!once)
   {
     once = true;
     Serial1.begin(115200);
   }

 Serial1.print(p);
}


/*********************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin 
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
	else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin 
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT);
		return analogRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT);
		return analogRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	String value = command.substring(3);

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else return -2;
}

4 Likes