Category: Uncategorized

So recently I just finished Arabesque Opus. 100 No. 2 by Burgmuller. The song looked difficult at first but turned out to be actually pretty easy. First: By taking a look at the last chord we can easily identify that the song is written in A Minor. Second: The speed is fast pace using a 2/4 key signature.

The song starts with A minor triad on the left hand to start the beat of the tempo. This is something to note as sometimes you can go to fast on your left and your right has to go twice as fast to keep up, So it’s best to take this beat as slow as possible without messing up your timing. Next, it goes from A Minor to D/F then back to A. A Melody is built then it ends on a ‘E’ sforzando! Nice and loud.

The phrase repeats then goes into a fast pace left hand progression just like the right. Then is almost mirrored at the starts with an A to a D/F back to an A.

One big thing to note are the repeat bars to ensure you revert back to the correct bar to continue playing again.

and lastly ending on SF Fermata of A. Fermata has a long emphasis, so be aware.

A great list of symbol definition can be found here. https://melodyful.com/complete-list-of-music-symbols-with-their-meaning

So, In the last few weeks’s I have been converting my Large ESP8266 project to multiple .h Module files so I can carry functions over from project to project and at the same time have them centrally managed to update code / fix bugs so they carry over to all of my projects.

One important detail on how I do this is to be able to trigger function code from within the Main project as needed so I don’t have to handle user specific events within the Header file where it does not belong. So, I do this by using TypeDef and declaring a Prototype for my Callback function. In this case,

typedef void (*DHTFunctionCallback)(struct sensor_GlobalReading * MyReading);
DHTFunctionCallback DHTCallBack;

Then set the callback function,

init_ThermostatSettings(&myDHTFunctionCallback);

Set the callback in the Header file

void ICACHE_FLASH_ATTR init_ThermostatSettings(void * LDHTCallBack(struct sensor_GlobalReading MyReading))
{
if (LDHTCallBack != NULL)
{
    DHTCallBack = LDHTCallBack;
}
}

Then in my Header file I then check to see if the value is set != NULL. If so then I call it.

DHTCallBack(&GlobalReading);

The Main Function will get triggered and I can then access the variables stored in the STACK/HEAP depending on how I pass it to the caller from the callee.

void ICACHE_FLASH_ATTR myDHTFunctionCallback(struct sensor_GlobalReading * MyReading)
{
    os_printf("[%s]\r\n", __func__);
}

One thing to note for the LOVE OF ORANGE JUICE WATCH OUT FOR USE AFTER FREE ISSUES. If your doing this from an ASync call just be aware to Lock the thread/variables so you don’t crash or use Data that get’s falsely injected!

With this method you can just Include the Handler, Call the Coordinating Init Function and pass the &Address of a function matching the prototype and your off to the races!

Full Header and Main.C example
DHT.H
#ifndef dhtthermastat
#define dhtthermastat

#include "../library/common.h"
#include "../library/station.h"
#define ThermMemorySpaceSector 0x50
#define ThermMemorySpace 0x50000
#define DHT_MAXCOUNT 32000
#define DHT_NO_PIN -1
#define DHT_PACKET_SIZE 5

///NOTE: The call back points to a Global Structure named GlobalReading, This structure can / may change by the time user code executes. It may be best to copy the variable staticly.

typedef void (*DHTFunctionCallback)(struct sensor_GlobalReading * MyReading);
DHTFunctionCallback DHTCallBack;

int DHT_PIN = 0;

LOCAL struct espconn TCPOutGoingespconn; //This sends outgoing get request
static volatile os_timer_t CheckIPAndSend_timer;

enum sensor_type MySensor;
enum sensor_type
{
    MySensor_DHT11,MySensor_DHT22
};

struct __attribute__((__packed__)) ThermostatStruct{
    int programmed;
    enum sensor_type ThermostatType;
    int GPIO;
    int PowerMethod;
    BOOL PollingEnabled;
    int Polling;
    BOOL SendOnInit;
    BOOL SendOnInitOnlyIf;
    int tempatureDegrees;
    BOOL classification;
    BOOL DeepSleepAfterSend;
    int DeepSleepTime;
    BOOL Enabled;
    char Reserved[14]; //This fixes the 4 Byte Allignment in SPI Flash Read, 44bytes
};

struct ThermostatStruct ThermostatConfig;

struct sensor_GlobalReading{
    float temperature;
    float humidity;
    const char* source;
    uint8_t sensor_id[16];
    BOOL success;
};


void ICACHE_FLASH_ATTR DHT(void);
//struct sensor_GlobalReading * ICACHE_FLASH_ATTR readDHT(int force);
void DHTInit(enum sensor_type LMySensor, uint32_t GPIOPin, bool enablepolling, uint32_t polltime);

static inline float scale_humidity(int *data) {
  if (MySensor == MySensor_DHT11) {
    return data[0];
  } else {
    float humidity = data[0] * 256 + data[1];
    return humidity /= 10;
  }
}

static inline float scale_temperature(int *data) 
{
    if (MySensor == MySensor_DHT11) 
    {
        os_printf("MySensor DHT11");
        return data[2];
    } 
    else 
    {
        os_printf("MySensor DHT22");
        float temperature = data[2] & 0x7f;
        temperature *= 256;
        temperature += data[3];
        temperature /= 10;
        if (data[2] & 0x80)
        temperature *= -1;
        return temperature;
    }
}

struct sensor_GlobalReading GlobalReading = {
    .source = "DHT11", .success = 0
};

void ICACHE_FLASH_ATTR renderHTTPThermostatrequest(char * Request)
{
    decodeHTML(Request);
    if (os_strlen(Request) > 127)
    {
        os_printf("Returning - GET VAR IS TOO BIG: %s\r\n", Request);
        return;
    }

    char HTTPGETSPLIT[128];
    os_memset(HTTPGETSPLIT, 0, 128);
    os_memcpy(&HTTPGETSPLIT, Request, os_strlen(Request));
    os_printf("Before Split: %s\r\n", HTTPGETSPLIT);
    char * Key = strstr(HTTPGETSPLIT, "=");
    if(Key == NULL)
    {
        os_printf("Returning - Not a valid Split: %s\r\n", HTTPGETSPLIT);
        return;
    }
    *Key = 0x0;
    char * Value = Key + 1;
    Key = HTTPGETSPLIT;

    os_printf("Key: %s\r\nValue: %s\r\n", Key, Value);

    os_printf("renderHTTPThermostatrequest Key: %s\r\nValue: %s\r\n", Key, Value);
    if (strcmp(Key, "Thermostat") == 0)
    {
        //os_strcpy(newconfig.ssid, Value);
        if (strcmp(Value, "DHT11") == 0)
        {
            os_printf("Setting to DHT11");
            ThermostatConfig.ThermostatType = MySensor_DHT11;
        }
        else
        {
            os_printf("Setting to DHT22");
            ThermostatConfig.ThermostatType = MySensor_DHT22;
        }
        os_printf("Thermastat Set to: ", Value);
        return;
    }
    else if (strcmp(Key, "GPIO") == 0)
    {
        ThermostatConfig.GPIO = atoi(Value);
        os_printf("GPIO set to %s - %d", Value, atoi(Value));
    }
    else if (strcmp(Key, "PowerMethod") == 0)
    {
        ThermostatConfig.PowerMethod = atoi(Value);
    }
    else if (strcmp(Key, "pollingEnabled") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.PollingEnabled = true;
        }
        else
        {
            ThermostatConfig.PollingEnabled = false;
        }
    }
    else if (strcmp(Key, "POLLING") == 0)
    {
        ThermostatConfig.Polling = atoi(Value);
        os_printf("Polling set to %s - %d", Value, atoi(Value));
    }
    else if (strcmp(Key, "SendOnInit") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.SendOnInit = true;
        }
        else
        {
            ThermostatConfig.SendOnInit = false;
        }
    }
    else if (strcmp(Key, "SendOnInitOnlyIf") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.SendOnInitOnlyIf = true;
        }
        else
        {
            ThermostatConfig.SendOnInitOnlyIf = false;
        }
    }
    else if (strcmp(Key, "tempatureDegrees") == 0)
    {
        ThermostatConfig.tempatureDegrees = atoi(Value);
    }
    else if (strcmp(Key, "classification") == 0)
    {
        if (strcmp(Value, "warmer") == 0)
        {
            ThermostatConfig.classification = true;
        }
        else if (strcmp(Value, "colder") == 0)
        {
            ThermostatConfig.classification = false;
        }
    }
    else if (strcmp(Key, "DeepSleepAfterPoll") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.DeepSleepAfterSend = true;
        }
        else if (strcmp(Value, "false") == 0)
        {
            ThermostatConfig.DeepSleepAfterSend = false;
        }
    }
    else if (strcmp(Key, "DeepSleepTime") == 0)
    {
        ThermostatConfig.DeepSleepTime = atoi(Value);
    }
    else if (strcmp(Key, "enabled") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.Enabled = true;
        }
        else
        {
            ThermostatConfig.Enabled = false;
        }

        //os_printf("ssid: \"%s\"\npw: \"%s\"\nProgrammed: %d\r\n",newconfig.ssid,newconfig.password,newconfig.programmed);
        ThermostatConfig.programmed = 1;
        //os_printf("Writing ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(APFlashStationConf)+sizeof(newconfig)));
        spi_flash_erase_sector(ThermMemorySpaceSector);
        SpiFlashOpResult writeResult = spi_flash_write(ThermMemorySpace, (uint32 *)&ThermostatConfig, sizeof(ThermostatConfig));
        if (writeResult == SPI_FLASH_RESULT_OK)
        {
            /*
            ThermostatConfig.programmed = 0;
            SpiFlashOpResult ReadResult = spi_flash_read(0x50000,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));     
            if (ReadResult == SPI_FLASH_RESULT_OK)
            {
                os_printf("Therm SPI Read SPI_FLASH_RESULT_OK\r\n");
                if(ThermostatConfig.programmed == 1)
                {
                    os_printf("\r\nSaved ThermostatConfig Information Found!!\r\nThermostatType: \"%d\"\nGPIO: \"%d\"\r\n", ThermostatConfig.ThermostatType, ThermostatConfig.GPIO);
                    if(ThermostatConfig.Enabled == true)
                    {
                        os_printf("Thermostat Enabled - Starting Polling at %d\r\n", ThermostatConfig.Polling);
                        DHTInit(MySensor_DHT11, ThermostatConfig.PollingEnabled, ThermostatConfig.Polling * 1000); //1000 = 1 Sec
                    }
                }
            }
            */

            os_printf("ThermSettings SavedSystem is rebooting...");     
            //os_delay_us(100000);
            os_printf("now...");        
            system_restart();
        }
        else if(writeResult == SPI_FLASH_RESULT_ERR)
        {
            os_printf("ThermSettings SPI_FLASH_RESULT_ERR...");
        }
        else if(writeResult == SPI_FLASH_RESULT_TIMEOUT)
        {
            os_printf("ThermSettings SPI_FLASH_RESULT_TIMEOUT...");
        }
        return;

    }
    else /* default: */
    {
        os_printf("No valid request Handler for - %s\r\n", Request); //Output last variable
        /*
        int i;
        for(i = 0; i < 10; i++) {
                os_printf("0x%02X ", Request[i]);
        }
        */
    }
}

LOCAL bool ICACHE_FLASH_ATTR pollDHTCb()
{
    //Something is going on with Powermethod on GPIO15?
    os_printf("pollDHTCb()");
    if (ThermostatConfig.PowerMethod > 0)
    {
        os_printf("Turning on power to the DHT - Pin%d\r\n", ThermostatConfig.PowerMethod);
        PIN_FUNC_SELECT(g_pin_muxes[ThermostatConfig.PowerMethod], g_pin_funcs[ThermostatConfig.PowerMethod]);
        gpio_output_set((1 << ThermostatConfig.PowerMethod), 0, 0, 0); //Turn on power to the DHT
    }
    if(ThermostatConfig.programmed != 1)
    {
        os_printf("pollDHTCb, not programmed\r\n");
        return false;
    }
    int counter = 0;
    int laststate = 1;
    int i = 0;
    int bits_in = 0;
    int data[100];
    data[0] = data[1] = data[2] = data[3] = data[4] = 0;
    //disable interrupts, start of critical section
    //os_intr_lock();
    wdt_feed();
    // Wake up device, 250ms of high
    GPIO_OUTPUT_SET(DHT_PIN, 1);
    delay_ms(250);
    // Hold low for 20ms
    GPIO_OUTPUT_SET(DHT_PIN, 0);
    delay_ms(20);
    // High for 40us
    GPIO_OUTPUT_SET(DHT_PIN, 1);
    os_delay_us(40);
    GPIO_DIS_OUTPUT(DHT_PIN);
    i=0;
    while (GPIO_INPUT_GET(DHT_PIN) == 1) 
    {
        os_delay_us(3);
        if (i >= DHT_MAXCOUNT) 
        {
            goto fail;
        }
        i++;
    }
    i=0;
    while (GPIO_INPUT_GET(DHT_PIN) == 0) 
    {
        os_delay_us(3);
        if (i >= DHT_MAXCOUNT) 
        {
            goto fail;
        }
        i++;
    }

    counter = 0;
    while (counter < 40)
    {
        i=0;
        while (GPIO_INPUT_GET(DHT_PIN) == 1) 
        {
            os_delay_us(3);
            if (i >= DHT_MAXCOUNT) 
            {
                goto fail;
            }
            i++;
        }

        i=0;
        while (GPIO_INPUT_GET(DHT_PIN) == 0) 
        {
            os_delay_us(3);
            if (i >= DHT_MAXCOUNT) 
            {
                goto fail;
            }
            i++;
        }

        os_delay_us(47);
        data[bits_in / 8] <<= 1;
        if (GPIO_INPUT_GET(DHT_PIN) == 1)
        {
            data[bits_in / 8] |= 1;
            //os_printf("\r\nONE %d", counter);
        }
        else
        {
            //os_printf("\r\nZERO %d", counter);
        }
        bits_in++;
        counter++;
    }

    //Re-enable interrupts, end of critical section
    //os_intr_unlock();
    if (ThermostatConfig.PowerMethod > 0)
    {
        os_printf("Turning off power to DHT\r\n");
        gpio_output_set(0, (1 << ThermostatConfig.PowerMethod), 0, 0); //Turn off power to the DHT
    }

    if (bits_in < 40) {
        os_printf("Got too few bits: %d should be at least 40\r\n", bits_in);
        goto fail;
    }


    int checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF;

    //os_printf("DHT: %02x %02x %02x %02x [%02x] CS: %02x", data[0], data[1],data[2],data[3],data[4],checksum);

    if (data[4] != checksum) 
    {
        os_printf("Checksum was incorrect after %d bits. Expected %d but got %d\r\n", bits_in, data[4], checksum);
        goto fail;
    }

    GlobalReading.temperature = scale_temperature(data);
    GlobalReading.humidity = scale_humidity(data);
    os_printf("Temp =  %d *F, Hum = %d %%\n", (int)(GlobalReading.temperature * 1.8 + 32), (int)(GlobalReading.humidity));
    GlobalReading.success = 1;
    DHTCallBack(&GlobalReading); //Invoke Callback
    return true;

    fail:
        os_printf("Failed to get GlobalReading, dying\n");
        GlobalReading.success = 0;
        if (ThermostatConfig.PowerMethod > 0)
        {
            os_printf("Turning off power to DHT\r\n");
            gpio_output_set(0, (1 << ThermostatConfig.PowerMethod), 0, 0); //Turn off power to the DHT
        }
        return false;
}

LOCAL bool ICACHE_FLASH_ATTR pollDHT()
{
    if(ThermostatConfig.programmed != 1)
    {
        os_printf("Polling DHT, not programmed\r\n");
        return false;
    }
    os_printf("Polling DHT\r\n");
    if (pollDHTCb())  //Get Tempature from DHT
    {
        int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
        if (ThermostatConfig.SendOnInitOnlyIf)
        {
            if(ThermostatConfig.classification)
            {
                if (TempInF > ThermostatConfig.tempatureDegrees) //Warmer
                {
                    os_printf("Warmer: TempInF > ThermostatConfig.tempatureDegrees\r\n");
                    //Turn On LED
                    DHTCallBack(&GlobalReading);
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set(0, (1 << 2), 0, 0);
                }
                else
                {
                    //Turn OFF LED
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set((1 << 2), 0, 0, 0);
                }
            }
            else if(ThermostatConfig.classification) //Colder
            {
                if (TempInF < ThermostatConfig.tempatureDegrees)
                {
                    os_printf("Colder: TempInF < ThermostatConfig.tempatureDegrees\r\n");
                    //Turn On LED
                    DHTCallBack(&GlobalReading);
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set(0, (1 << 2), 0, 0);
                }
                else
                {
                    //Turn OFF LED
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set((1 << 2), 0, 0, 0);
                }
            }
        }
        else
        {
            os_printf("Sending on Poll\r\n");
        }
    }
}

void DHTInit(enum sensor_type LMySensor, uint32_t GPIOPin, bool enablepolling, uint32_t polltime) 
{
    os_printf("[%s]\r\n", __func__);
    MySensor = LMySensor;
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
    //PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO0_U);
    PIN_FUNC_SELECT(g_pin_muxes[GPIOPin], g_pin_funcs[GPIOPin]);
    PIN_PULLUP_EN(g_pin_muxes[GPIOPin]);
    DHT_PIN = GPIOPin;
    if (enablepolling)
    {
        os_printf("DHT Setup for type %d, poll interval of %d using GPIO %d, Starting Timer...\r\n", LMySensor, (int)polltime, GPIOPin);
        static ETSTimer dhtTimer;
        os_timer_setfn(&dhtTimer, pollDHT, NULL);
        os_timer_arm(&dhtTimer, polltime, 1);
    }
    else
    {
        os_printf("DHT Setup for type %d using GPIO %d\n", LMySensor, GPIOPin);
    }

}


char * DOMAIN = "controllingTheInter.net";
bool sentAlert=false;

//char requestText[128];
//  int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
//  int humidity = (int)GlobalReading.humidity;
//  os_sprintf(requestText,"GET /esp8266.php?ssid=myssid&IP=MyIp&ID=MyId /HTTP/1.1\r\nUser-Agent: F%dH%d\r\nHost: %s\r\nAccept: */*\r\n\r\n", TempInF, humidity, DOMAIN);
//  os_printf("Sending: %s", requestText);
//  espconn_send(conn,requestText,128);
//  sentAlert=true;

//Add code to support new sockets sending data.
void ICACHE_FLASH_ATTR LoadStationAndSendData(struct sensor_GlobalReading MyReading)
{
    init_station(NULL, NULL, NULL);     
    //LoadAccessPoint();
    //os_timer_setfn(&CheckIPAndSend_timer, (os_timer_func_t *)network_check_ip_send_therm, (void *)&MyReading);
    //os_timer_arm(&CheckIPAndSend_timer, 1000, 1);
}

SpiFlashOpResult ICACHE_FLASH_ATTR Set_ThermostatSettings(enum sensor_type LThermostatType, int LGPIO, int LPowerMethod, bool LPollingEnabled, int LPolling, bool LSendOnInit, bool LSendOnInitOnlyIf, int LtempatureDegrees, char * LClassification, bool LDeepSleepAfterSend, int LDeepSleepTime, int LEnabled, char * LReserved)
{
    os_printf("[%s]\r\n", __func__);
    ThermostatConfig.ThermostatType = LThermostatType;
    DHT_PIN = LGPIO;
    ThermostatConfig.GPIO = LGPIO;
    ThermostatConfig.PowerMethod = LPowerMethod;
    ThermostatConfig.PollingEnabled = LPollingEnabled;
    ThermostatConfig.Polling = LPolling;
    ThermostatConfig.SendOnInit = LSendOnInit;
    ThermostatConfig.SendOnInitOnlyIf = LSendOnInitOnlyIf;
    ThermostatConfig.tempatureDegrees = LtempatureDegrees;
    if (LClassification != NULL)
    {
        if (strcmp(LClassification, "warmer") == 0)
        {
            ThermostatConfig.classification = true;
        }
        else if (strcmp(LClassification, "colder") == 0)
        {
            ThermostatConfig.classification = false;
        }
    }
    ThermostatConfig.DeepSleepAfterSend = LDeepSleepAfterSend;
    ThermostatConfig.DeepSleepTime = LDeepSleepTime;
    ThermostatConfig.Enabled = LEnabled;
    ThermostatConfig.programmed = 1;
    //os_printf("Writing ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(APFlashStationConf)+sizeof(newconfig)));
    spi_flash_erase_sector(ThermMemorySpaceSector);
    SpiFlashOpResult writeResult = spi_flash_write(ThermMemorySpace, (uint32 *)&ThermostatConfig, sizeof(ThermostatConfig));
    if (writeResult == SPI_FLASH_RESULT_OK)
    {
        //os_printf("ThermSettings SavedSystem is rebooting...");       
        //os_delay_us(100000);
        //os_printf("now...");      
        //system_restart();
    }
    else if(writeResult == SPI_FLASH_RESULT_ERR)
    {
        os_printf("ThermSettings SPI_FLASH_RESULT_ERR...");
    }
    else if(writeResult == SPI_FLASH_RESULT_TIMEOUT)
    {
        os_printf("ThermSettings SPI_FLASH_RESULT_TIMEOUT...");
    }
    return writeResult;
}

void ICACHE_FLASH_ATTR init_ThermostatSettings(void * LDHTCallBack(struct sensor_GlobalReading MyReading))
{
    os_printf("[%s]\r\n", __func__);
    //os_printf("GlobalReading ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(FlashStationConf)+sizeof(APFlashStationConf)));
    //SpiFlashOpResult ReadResult = spi_flash_read(WifiMemorySpace+sizeof(FlashStationConf)+sizeof(APFlashStationConf),(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));
    SpiFlashOpResult ReadResult = spi_flash_read(ThermMemorySpace,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));        
    if (ReadResult == SPI_FLASH_RESULT_OK)
    {
        os_printf("Therm SPI Read SPI_FLASH_RESULT_OK\r\n");
        if(ThermostatConfig.programmed == 1)
        {
            os_printf("Saved ThermostatConfig Information Found!!\r\nThermostatType: \"%d\"\nGPIO: \"%d\"\r\nTempature: \"%d\"\r\n", ThermostatConfig.ThermostatType, ThermostatConfig.GPIO, ThermostatConfig.tempatureDegrees);
            if(ThermostatConfig.Enabled == true)
            {
                if (LDHTCallBack != NULL)
                {
                    DHTCallBack = LDHTCallBack;
                }
                os_printf("Thermostat Enabled - Starting Polling at %d\r\n", ThermostatConfig.Polling);
                DHTInit(ThermostatConfig.ThermostatType, ThermostatConfig.GPIO, ThermostatConfig.PollingEnabled, ThermostatConfig.Polling * 1000 * 60); //1000 = 1 Sec

                if (ThermostatConfig.SendOnInit)
                {
                    if (pollDHTCb()) //This gets the raw value
                    {//This part may be able to be turned into a function
                        int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
                        if (ThermostatConfig.SendOnInitOnlyIf)
                        {
                            if(ThermostatConfig.classification)
                            {
                                if (TempInF > ThermostatConfig.tempatureDegrees) //Warmer
                                {
                                    os_printf("Warmer: TempInF > ThermostatConfig.tempatureDegrees\r\n");
                                    //wifi_set_opmode(STATION_MODE);
                                    //LoadStation();
                                    DHTCallBack(&GlobalReading);
                                    //Turn On LED
                                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                                    gpio_output_set(0, (1 << 2), 0, 0);
                                }
                            }
                            else if(ThermostatConfig.classification) //Colder
                            {
                                if (TempInF < ThermostatConfig.tempatureDegrees)
                                {
                                    os_printf("Colder: TempInF < ThermostatConfig.tempatureDegrees\r\n");
                                    DHTCallBack(&GlobalReading);
                                    //Turn On LED
                                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                                    gpio_output_set(0, (1 << 2), 0, 0);
                                    //wifi_set_opmode(STATION_MODE);
                                    //LoadStation();    
                                }
                            }
                        }
                        else
                        {
                            //wifi_set_opmode(STATION_MODE);
                            //LoadStation();
                        }
                        if(ThermostatConfig.DeepSleepAfterSend && false)
                        {
                                //SET_PERI_REG_MASK(UART_CONF0(0),  UART_TXFIFO_RST);//RESET    FIFO
                                //CLEAR_PERI_REG_MASK(UART_CONF0(0),    UART_TXFIFO_RST);
                                os_printf("Going to sleep for %d\r\n", ThermostatConfig.DeepSleepTime);
                                deep_sleep_set_option(2);
                                system_deep_sleep(ThermostatConfig.DeepSleepTime * 60000 * 1000); //UC to Minutes
                        }
                    }
                }
            }
        }
        else
        {
            os_printf("\r\nNo ThermostatConfig Information Found!!\r\n");
        }
    }
    else if(ReadResult == SPI_FLASH_RESULT_ERR)
    {
        os_printf("SPI_FLASH_RESULT_ERR");
    }
    else if(ReadResult == SPI_FLASH_RESULT_TIMEOUT)
    {
        os_printf("SPI_FLASH_RESULT_TIMEOUT");
    }

    //os_printf("SizeOf(ThermostatConfig) = %d\r\n", sizeof(ThermostatConfig));
}
#endif

Main.C

//https://www.mikrocontroller.net/attachment/263828/The-ESP8266-Book-August-2015.pdf
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "ip_addr.h"
#include "mem.h"
#include "user_interface.h"
#include "lwip/stats.h"
#include "espconn.h"

#include "c_types.h" ////ONE WIRE

#include "../library/uart.h" //Copy these from your Driver Lib to your local folder
#include "../library/gpio16.h" //Copy these from your Driver Lib to your local folder

#include "../library/common.h"
#include "../library/dht.h"
#include "../library/station.h"
#include "../library/sockets.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1
os_event_t user_procTaskQueue[user_procTaskQueueLen];

void ICACHE_FLASH_ATTR StationConnected()
{
    os_printf("[%s]\r\n", __func__);
    //Creates Timer Socket
    uint8 FreeSocket = GetFreeSocket();
    os_strcpy(MySendDataStruct[FreeSocket].Name, "MyThermSocket");
    MySendDataStruct[FreeSocket].Domain = DOMAIN;
    os_sprintf(MySendDataStruct[FreeSocket].DataToSend, "GET /esp8266.php?ssid=myssid&IP=MyIp2&ID=MyId2 /HTTP/1.1\r\nUser-Agent: SomeAgent\r\nHost: %s\r\nAccept: */*\r\n\r\n", MySendDataStruct[FreeSocket].Domain);
    StartSendingSocketTimer(FreeSocket);
}

void ICACHE_FLASH_ATTR myDHTFunctionCallback(struct sensor_GlobalReading * MyReading)
{
    os_printf("[%s]\r\n", __func__);
    //init_station("Thermastat.local", true, &StationConnected);
    //init_sockets(NULL, NULL, NULL, NULL); //Do not override Socket.H callbacks
}

void ICACHE_FLASH_ATTR sdk_init_done_cb(void) 
{ 
    os_printf("[%s] initializing ESP8266!\r\n", __func__);

    SpiFlashOpResult ReadResult = spi_flash_read(ThermMemorySpace,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));        
    if (ReadResult != SPI_FLASH_RESULT_OK || ThermostatConfig.programmed != 1 || true) //If not set, Set it..
    {
        os_printf("Setting's not found, Calling Set_ThermostatSettings");
        //NOTE: Don't use GPIO16/D0, This is reserved.
        //DHT22 GPIO=GPIO0/D3 Power=GPIO15/D8 PollingEnabled Interval=1Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=NULL classification DeepSleepAfterSend DeepSleepTime Enabled Reserved
        SpiFlashOpResult writeResult = Set_ThermostatSettings(MySensor_DHT22, 0, 15, true, 1, true, false, NULL, NULL, false, NULL, true, NULL);
        //DHT22 GPIO=GPIO0/D3 Power=GPIO4/D2 PollingEnabled Interval=1Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=NULL classification=warmer/colder DeepSleepAfterSend DeepSleepTime Enabled Reserved
        //Set_ThermostatSettings(MySensor_DHT22, 0, 4, true, 1, true, false, NULL, "warmer", false, 5, true, NULL);
        if (writeResult == SPI_FLASH_RESULT_OK)
        {
            init_ThermostatSettings(&myDHTFunctionCallback);
        }
    }
    else
    {
        init_ThermostatSettings(&myDHTFunctionCallback);
    }

}

void ICACHE_FLASH_ATTR user_init()
{

    //void  uart0_tx_buffer(uint8   *buf,   uint16  len)
    uart_div_modify(0, UART_CLK_FREQ / 115200);
    wifi_set_opmode(0);
    wifi_set_sleep_type( NONE_SLEEP_T );

    ETS_GPIO_INTR_DISABLE();// Disable gpio interrupts
    gpio_init();

    //Start os task
    system_init_done_cb(sdk_init_done_cb);
    //system_os_task(loop, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen); //Task to Signal for later
}

OooOoOo, Look what I received yesterday. So, I really can take this two different ways.

1: The D.A. agrees with my stance that the court error’d in interpreting the Statues CVC 40801-40805 / CEC 1271(C), Doubtful 2: They don’t give two structured object’s about traffic cases and will leave it to the justices to reverse if there was indeed a legal error, More likely.

However, in any case, it’s best that they didn’t respond with a rebuttal and hey, this saves me from having to do an oral argument in front of the Justice Panel, which I wouldn’t of minded for the learning experience.

So, in my environment now we are having Isilon performance issues where a single file is taking anywhere from 20ms to 6 seconds in response time to deliver access to a file. I am currently working on getting Smart connect Advanced setup to get stronger control over our connects to our resource pools. We currently own 4 x210 bricks in our environment and have a file policy setup to replicate data to them for faster read access (SSD equipped). Now to my surprise while working with Dell it seems that if you create another pool, your x210 nodes can be a member of both pools and a virtual¬†interface can be added to the x210’s so they then have two IP’s assigned to them. We can then assign a 2nd Smartconnect name to Pool1 and then point our highly sensitive servers to the new pool. This will give them a dedicated line to the SSD storage vs. having it fight with other servers on that same IP interface. I would be surprised if the difference¬†was large but Dell seems to be pretty certain that well see an improvement even though it will still remain on the same physical devices.

Well this weekend turned out wonderful. I manage to finish this little piece of and this solution saved me a HUGE mount of heap space. This function I wrote to cycle through flash memory and format SprintF on the fly from Flash memory instead of having to double buffer the formatted HTML page. In my case my HTML page is around 4-8k depending on what I am loading, thats over half the ESP’s heapspace just to send results to the client, YIKES! Now those day’s are over ūüôā

uint16 flashsprintf(char * dest, uint32_t address, char * Terminator, int n, ...)
{
    int i = 0;
    int val;
    int sizeofTerminator = os_strlen(Terminator);

    va_list ap;
    va_start(ap, n);

    uint16 destindex = 0;
    uint16 addressindex = 0;
    char buffer[4];
    bool percentflag = false; //This Flag is used for if the last char is a %
    while(true)
    {
        system_soft_wdt_feed();
        if (spi_flash_read(address+(addressindex*4), buffer, 4) != 0)
        {
            os_printf("Read failed at offset=0x%02x index=%d\r\n", address, index);
            return 0;
        }
        os_printf("string: %d - %c%c%c%c\r\n", (addressindex*4), *(buffer), *(buffer+1), *(buffer+2), *(buffer+3));
        addressindex++;
        for (i=0; i<=3; i++)
        {   
            if (percentflag)
            {
                switch(buffer[i]) 
                {
                    case 's'  :
                    val=va_arg(ap,char *);
                    destindex += os_sprintf(dest+destindex, "%s", val);
                    break; /* optional */

                    case 'd'  :
                    val=va_arg(ap,int);
                    destindex += os_sprintf(dest+destindex, "%d", val);
                    break; /* optional */

                    /* you can have any number of case statements */
                    default : /* Optional */
                    os_printf("Unknown ");

                }
                os_printf("Removing %%");
                percentflag = false;
                continue;
            }

            if (buffer[i] == '%')
            {
                os_printf("Setting %%");
                percentflag = true;
                continue;
            }
            else
            {
                *(dest+destindex)=buffer[i];
                destindex++;
                if (os_strncmp((dest+destindex-sizeofTerminator), Terminator, sizeofTerminator) == 0)
                {
                    *(dest+destindex)=0x00;
                    os_printf("Exiting");
                    return destindex;
                }
            }
        }
    }

    os_printf("done");
    va_end(ap);
    return destindex; //Returns SizeOf Resource
}

So lately I’ve been working on the Isilon quite a bit and we have a couple PAC servers that travel through the Netscalers here in our environment.
These netscalers are used as the Server’s default gateway for routing traffic. However using them as a source to route all data isn’t a great thing to do from a performance perspective, So some static routes are created to help make it’s backend NAS connections a bit faster.

First execute “Route Print” and note the Interface number, in this case 12,11,13,14,1

C:>route print

Interface List
12…02 00 4c 4f 4f 50 ……Npcap Loopback Adapter
11…ec b1 d7 3d 7d 8e ……Intel(R) Ethernet Connection I217-LM
13…00 50 56 c0 00 01 ……VMware Virtual Ethernet Adapter for VMnet1
14…00 50 56 c0 00 08 ……VMware Virtual Ethernet Adapter for VMnet8
1………………………Software Loopback Interface 1
===========================================================================

We would like to target 11 in this case.
Also note we need the word “MASK” in the middle or the command will not be parsed correctly
Giving -p for a persistent change, All connections to 10.246.x.240 will not route through 10.246.x.1

route -p add 10.246.x.240 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.241 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.242 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.243 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11

UPDATE: Latest Src: http://controllingtheinter.net/2018/03/05/esp8266-nonos-sdk-sprintf-stright-from-flash/

So, One of my ESP projects requires a Large HTML file being massaged and sent out with Data to display to the client. What I currently do now is use SpiRead and read it into a Malloc that is the size of the HTML. Then after I use OS_SprintF on the string and add the coordinating¬†information into the HTML. That works great, However minor issue. After the HTML grows in development the HTML gets into the size of around 6-8k, Allocating 16k of Memory just to send out an HTML file can become a challenge for the ESP due to the lack of heap memory. This is just a prototype but I’m developing on the idea of reading the Spi 4 bytes at a time and calling SprintF accordingly whenever I see %s. %d. %c etc etc. I am not done at the moment but I am working on idea’s on simple ways to accomplish this.

#include <stdarg.h> //Required for VAList
void flashsprintf(char *s, uint32_t address, int n, …)
{

int ret;
int val;
va_list ap;
va_start(ap, n);

int numberOfVars = 0;
int i, ii = 0;
char * ss = s; //Backup Ptr
for (numberOfVars=0; s[i]; s[i]==’%’ ? numberOfVars++ : *s++);
s = ss; //RestorePtr

os_printf(“start\r\n”);
for (i=0; i<=(os_strlen(s)-1); i++)
{
//os_printf(“%d-%c\r\n”, i, s[i]);
if (s[i] == ‘%’)
{
switch(s[i+1])
{
case ‘s’¬† :
val=va_arg(ap,char *);
break; /* optional */

case ‘d’¬† :
os_printf(“Dec “);
val=va_arg(ap,int);
break; /* optional */

/* you can have any number of case statements */
default : /* Optional */
os_printf(“Unknown “);
}
}
}

os_printf(“%d”, i);

for (ii=0;ii<i;ii++)
{
val=va_arg(ap,int);
os_printf (” %d”,val);
}
//ret = vsprintf(s, fmt, ap);
va_end(ap);
return ret;
}

 

 

As additional step I tried to rewrite this code using Visual Studio the Mike’s operating system kind had to expand my knowledge on how SprintF reports are neat the hood. One things I found kind of interesting is that when you pass an argument to a C function that does have a set amount of parameters SprintF uses an internal function called VA_list that is used to parse through each corner and then clean up the stack afterwards allowing the function to return back to the callee properly. I would assume I would have to do is do an SPI read and mimic the same type of logic to accomplish what I’m looking for. In the end I believe I can redo some heap memory usage by approximately 40% which is a huge deal when you only have 32K of heap to work with.¬†I’m not done with this code yet. This is more brainstorming pseudocode for me. I’ll come back and update this code when i come up with more of a polished solution.

 

#include “stdafx.h”
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h> //Required for VAList
#define _CRT_SECURE_NO_WARNINGS
int flashsprintf(char *buffer, char *s, int¬†n, …)
{
int ret;
void * val;
void * args[4];
va_list ap;
va_start(ap, n);
int numberOfVars = 0;
int i, ii, index = 0;
char * ss = s; //Backup Ptr
for (numberOfVars = 0; s[numberOfVars]; s[numberOfVars] == ‘%’ ? numberOfVars++ : *s++);
s = ss; //RestorePtr
printf(“start\r\n“);
for (i = 0; i <= (strlen(s) – 1); i++)
{
//os_printf(“%d-%c\r\n“, i, s[i]);
if (s[i] == ‘%’)
{
switch (s[i + 1])
{
case ‘s’:
args[index] = va_arg(ap, char *);
index++;
break; /* optional */
case ‘d’:
//int *p1 = (int *)malloc(sizeof(int));
//p1 = &va_arg(ap, int);
//args[index] = p1;
args[index] = (void *)va_arg(ap, int);
index++;
break; /* optional */
   /* you can have any number of case statements */
//default: /* Optional */
//printf(“Unknown “);
}
}
}
switch (index – 1)
{
case 0:
sprintf(buffer, s, args[0]);
case 1:
sprintf(buffer, s, args[0], args[1]);
case 2:
sprintf(buffer, s, args[0], args[1], args[2]);
default:
printf(“default”);
}
printf(“%d”, i);
/*
for (ii = 0; ii<i; ii++)
{
val = va_arg(ap, int);
printf(” %d”, val);
}
*/
//ret = vsprintf(s, fmt, ap);
va_end(ap);
return 0;
}
int main()
{
char buffer[512];
flashsprintf(buffer, “%s%d%s”, 3, “test”, 5, “tester”);
    return 0;
}

 

So back a few years ago since before I moved over working on the ESP family, I was an Atmel junkie. One of the thing’s that came in real handy was working with Software UART and the ATTiny84. It was a real great learning experience and I got really really burned with the DIV8 fuse being enabled on chip’s by default. I wanted to post my work here because I’m sure someone else may need it for the AT84 or 4313 2313 etc etc. Now the code below can be improved but the main thing to really take home is the caluclating the baud sleep while in the function. #define SleepRX9600 104 //= (1/ 9600) #define SleepRX4800 180 //= (1/ 4800) #define sleepTransmitString4800 208 #define sleepTransmitString9600 104 ¬† Now one thing to take home is if you want to transfer at 9600 baud over a second just take 1 / baud to get your uS sleep time. After you get it rocking you adjust the numbers to match the clock cycles of your added code. Sending data is almost mirrored logic. In this case I was working with a GPS, Once the string is received you can parse it just as if it is any other string in C. ¬†

void GetGPSData(int UART_INCOMMING_DATAPORT) {
    PCMSK0 &= ~(1 << UART_GPSRX_INTERRUPT); //Disable Interrupt Trigger for just GPS 
    \
    _delay\ _us(SleepRX4800 * 1.5);
    for (uint8_t i = 0; i < 8; i += 1) {
      if (PINA & (1 << UART_GPSRX_INTERRUPT)) //RX PIN IS HIGH 
      {
        uart_GPS_rx_buffer[uart_GPS_rx_buff_end] |= (1 << i); //RX PIN IS HIGH, try not to change any code here its timing sensitive 
      } else {
        uart_GPS_rx_buffer[uart_GPS_rx_buff_end] &= ~(1 << i); //RX PIN IS LOW 
      }
      if (i != (UART_RX_BUFFER_SIZE - 1)) {\
        _delay\ _us(SleepRX4800);

      }

    }
    if (uart_GPS_rx_buff_end == 0x0) {
      if (uart_GPS_rx_buffer[0] != '$') {
        PCMSK0 &= ~(1 << UART_WIFIRX_INTERRUPT);
        PCMSK0 |= (1 << UART_GPSRX_INTERRUPT);
        return;
      }
    }
    if (uart_GPS_rx_buffer[uart_GPS_rx_buff_end] == 0x0A)
    //This checks to see if the Last char that was sent is a LineFeed 
    {
      uart_GPS_rx_buffer[uart_GPS_rx_buff_end + 1] = 0x00;
      if (Counter == 3) {
        transmitstr9600((char * )
          "Sending to Cellphone\xd\xa", UART_DEBUG_TX_PIN);
        transmit((char * ) uart_GPS_rx_buffer, UART_WiFly_TX_PIN);
        Counter = 0;
      } else {
        transmitstr9600((char * ) uart_GPS_rx_buffer, UART_DEBUG_TX_PIN);
        Counter++;
      }
      PCMSK0 |= (1 << UART_WIFIRX_INTERRUPT);
      uart_GPS_rx_buff_end = 0;
      for (uint8_t i = 0; i < UART_RX_BUFFER_SIZE; i++) {
        uart_GPS_rx_buffer[i] = 0;
      }
    } else {
      PCMSK0 |= (1 << UART_GPSRX_INTERRUPT);
      uart_GPS_rx_buff_end++;
    } //
    \
    _delay\ _us(sleep); //Get past stop bit }       
    void transmitstr4800(char StringToSend[], int PAPin) {
      int a = 0;
      while (StringToSend[a] != 0x0) //Look for Null Terminator 
      { // low for start bit PORTA &= ~(1 << PAPin); //Startbit 
        \
        _delay\ _us(sleepTransmitString4800); // data bits 
        for (int i = 0; i <= 7; i++) {
          if (StringToSend[a] & (1 << i)) {
            PORTA |= (1 << PAPin);
          } else {
            PORTA &= ~(1 << PAPin);
          }\
          _delay\ _us(sleepTransmitString4800);
        }
        PORTA |= (1 << PAPin); //Stopbit 
        \
        _delay\ _us(sleepTransmitString4800 * 4);
        a++;
      }
    } 
    void UART_INITIALIZE() 
    {
        uart_GPS_rx_buff_end = 0;
        uart_GPS_rx_buff_position = 0;
        for (uint8_t i = 0; i < UART_RX_BUFFER_SIZE; i++) {
          uart_GPS_rx_buffer[i] = 0;
    }
        void UART_INITIALIZE_RX() { /* RX pin input and with pullup */
          /* 
                 UART_RX_DDR &= ~(1<<UART_GPSRX_PIN); 
                 UART_RX_PORT |= 1<<UART_GPSRX_PIN; */ //
          PCMSK0 |= (1 << UART_WIFIRX_INTERRUPT); //Enable interrupts on GPS PA3 //
          PCMSK0 |= (1 << UART_GPSRX_INTERRUPT); //Enable interrupts on GPS PA2 
          sei();
        }
        void UART_EnableRECV() {
          GIMSK |= (1 << UART_RX_INTERRUPT_PORT); //Enable interrupts period for PCI0 (PCINT7:0), This setups Interrupt for All pins 0-7 
        }
        void UART_DisableRECV() {
            GIMSK |= (1 << UART_RX_INTERRUPT_PORT); //Enable interrupts period for PCI0 (PCINT7:0), This setups Interrupt for All pins 0-7 
        }

Prepost: Trial http://controllingtheinter.net/2018/02/12/cvc22350-traffic-trial-unsafe-speed/

Update: Appellee’s Opening Brief Response http://controllingtheinter.net/2018/03/07/appellees-opening-brief-response-from-district-attorneys-office/

Well the big day just passed for my opening brief. I sat on this for about a good three months contemplating on the format and doing research on the best way to tackle this issue. The problem with legal docs is that they’re not very abundant when it comes to seeing the actual paperwork being filed by others. There’s a bunch of case laws that you can easily look up but you can never see what the defense and prosecution explicitly stated and how they said it which is kind of important. So from gathering what I could I threw this together and submitted to the appellate court I don’t expect a response for at least a good month and 1/2 to 2 months so fingers crossed. ¬† ¬†

So this weekend someone asked me about an issue they had with the Cisco POE switch being very noisy. He sent me this link he found where a SysAdmin went and found replacement fan’s for his switch to quiet them down. http://wahlnetwork.com/2014/12/21/diy-project-replacing-stock-cisco-sg300-52-fans-silence/

The fan’s currently in the switch are: https://www.digikey.com/product-detail/en/delta-electronics/EFB0412MD-R00/603-1581-ND/2560704

He suggested if this fan would work as a replacement: https://www.digikey.com/product-detail/en/ebm-papst-inc/412-2/381-2459-ND/592230

After a brief¬†look into¬†the datasheet, I found that the current fan vs. the new fan did not have a “Tach” to read PWM to get a return value on how fast the fan is moving, it did, however, have a Stop Rotation Detection method through the third wire. In this case, the replacement fan he suggested would spur a large number of false positives for error’s as the line should only go HIGH when the fan is jammed verses every 1/10000 of a second for its speed. So I instead dug through my box to locate an L7808CV Positive 8V voltage regulator. I found 8V make’s the fan extremely¬†quiet and kicks the speed down. I ended up testing it with my bench variable power supply¬†before concluding the 8V was the value I wanted. I quickly threw together a board and hot-snotted the unit to the back of the SG200 and what do you know, quiet as a ninja and no fan alerts.