Error with SparkIntervalTimer.h

Hello!

This is the first time I’m participating in the community. I’m here asking for your advice on an obstacle I’ve encountered by deploying a code that’s been already run on a Photon device, but with the Mesh devices (Argon and Xenon) I still haven’t been able to get it to work. It sends an error code (as shown on the next image) that the SparkIntervalTimer.h is not compatible with this devices, so it will not let me flash the code.

I really don’t understand quite clearly how that library is being used in my code. The things that I do with it are: controlling relays for some blinds, keep it listening to an IR receiver, publishing blind-status data to google sheets, and using an RGB led to show activity notifications.

SYSTEM_THREAD(ENABLED);

#include <IRremote.h>
#include <stdio.h>
#include <stdlib.h>

#define BLUE D2         // pin led azul
#define GREEN D3        // pin led verde
#define RED D4          // pin led azul
#define IR D6           // pin sensor IR
#define SENSOR1 D5      // pin sensor contacto
#define rType HIGH       // tipo de relevador
#define pType 2         // número de relevadores

const int L[3] = {RED, GREEN, BLUE};
const int R[6] = {A0, A1, A2, A3, A4, A5};              // pines relevadores
const int S[3] = {0,0,0};                               // ¿qué ventana tiene sensor?
const int T[6] = {16000,16500,0,0,0,0};         // delay relevadores
const String dispositivo = "Cocina";                    // nombre del dispositivo

int states [6] = {rType,rType,rType,rType,rType,rType};        // estado relevadores
int orden [3] = {0,0,0};
int ordenPrevia [3] = {0,0,0};
int delayRelay = 50;

unsigned long ordenMillis [3] = {0,0,0};                                        // timestamp de la orden
unsigned long transcurrido [6] = {0,0,0,0,0,0};        // tiempo transcurrido desde la orden

IRrecv irrecv(IR);
decode_results results;

void setup() {
    Serial.begin(9600);

    pinMode(BLUE, OUTPUT);                  // Inicializar pines de salida
    pinMode(GREEN, OUTPUT);                 //
    pinMode(RED, OUTPUT);                   //
    digitalWrite(RED, HIGH);                // Iniciar led RGB apagado
    digitalWrite(GREEN, HIGH);              //
    digitalWrite(BLUE, HIGH);               //

    for(int j=0; j<pType; j++){                             // Inicializar pines de relevadores
        pinMode(R[j], OUTPUT);                              //
        digitalWrite(R[j], rType == LOW ? LOW : HIGH);      //
    }                                                       //

    pinMode(SENSOR1, INPUT_PULLDOWN);            // Inicializar pin de sensor de ventana
    pinMode(IR, INPUT);                 // Inicializar pin de infrarrojo

    Particle.function("persiana", controlPersiana);         // Funciones de Particle
    Particle.subscribe("cocinaIR", handler, MY_DEVICES);

    irrecv.enableIRIn();                                // Iniciar receptor de infrarrojos
    irrecv.blink13(true);                                 //
}

void handler(const char *event, const char *data) {     // Checar lo de los apuntadores de tipos de archivos
    Serial.println(const_cast<char*>(data));
    controlPersiana(const_cast<char*>(data));
}

void loop() {
    apagadoRelevadores();       // Función de apagado de relevadores
    IRreceiver();               // Función lector de sensor IR
}

void IRreceiver(){
    /*    Función IRreceiver(): se usa para esperar una respuesta del control por infrarrojos.
            En caso afirmativo, recoge la lectura del sensor y la decodifica para comprobar, primero,
            si es una instrucción valida. De no ser así, pone el sensor en espera de una nueva instrucción.
            En caso de que se trate de una instrucción válida, revisa si el parámetro se encuentra dentro del
            rango esperado. De ser así, encuentra el código asignado a cada botón del control remoto y manda una
            instrucción a la función controlPersiana() para ejecutar la acción deseada. Caso contrario,
            termina la rutina y deja el sensor en espera de una nueva instrucción.
    */

    if (irrecv.decode(&results)){
        Serial.println(results.value);
        if ((results.value >= 0xFF0000 && results.value <= 0xFFFFFF) || results.value == 0xFFFFFFFF){
            switch (results.value) {
                // Photon Taller
                case 0xFFE817:
                    // persiana 1, down
                    Particle.publish("tallerIR", "11", PRIVATE);
                    break;
                case 0xFF9867:
                    // persiana 1, stop
                    Particle.publish("tallerIR", "12", PRIVATE);
                    break;
                case 0xFF906F:
                    // persiana 1, up
                    Particle.publish("tallerIR", "13", PRIVATE);
                    break;
                case 0xFF48B7:
                    // persiana 2, down
                    Particle.publish("tallerIR", "21", PRIVATE);
                    break;
                case 0xFFD827:
                    // persiana 2, stop
                    Particle.publish("tallerIR", "22", PRIVATE);
                    break;
                case 0xFFB847:
                    // persiana 2, up
                    Particle.publish("tallerIR", "23", PRIVATE);
                    break;

                // Photon Recamara
                case 0xFF6897:
                    // persiana 1, down
                    Particle.publish("recamaraIR", "11", PRIVATE);
                    break;
                case 0xFF8877:
                    // persiana 1, stop
                    Particle.publish("recamaraIR", "12", PRIVATE);
                    break;
                case 0xFFF807:
                    // persiana 1, up
                    Particle.publish("recamaraIR", "13", PRIVATE);
                    break;
                case 0xFFB24D:
                    // persiana 2, down
                    Particle.publish("recamaraIR", "21", PRIVATE);
                    break;
                case 0xFFA857:
                    // persiana 2, stop
                    Particle.publish("recamaraIR", "22", PRIVATE);
                    break;
                case 0xFFB04F:
                    // persiana 2, up
                    Particle.publish("recamaraIR", "23", PRIVATE);
                    break;

                // Photon Cocina
                case 0xFF38C7:
                    // persiana 1, down
                    controlPersiana("11");
                    break;
                case 0xFF50AF:
                    // persiana 1, stop
                    controlPersiana("12");
                    break;
                case 0xFF02FD:
                    // persiana 1, up
                    controlPersiana("13");
                    break;

                // Photon Balcon
                case 0xFF28D7:
                    // persiana 1, down
                    Particle.publish("balconIR", "11",PRIVATE);
                    break;
                case 0xFF7887:
                    // persiana 1, stop
                    Particle.publish("balconIR", "12",PRIVATE);
                    break;
                case 0xFF32CD:
                    // persiana 1, up
                    Particle.publish("balconIR", "13",PRIVATE);
                    break;
            }
        }
    irrecv.resume();
    }
}

int controlPersiana(String command){
    /*    Función controlPersiana(): se usa para esperar una instruccón vía web o control remoto (sensor IR) y así ejecutar
            la instrucción deseada en cuantro al control de los relevadores de descenso y ascenso de las persianas.
    */
    int numPers = command.charAt(0) - '0';
    int sensorVentana;

    if (S[numPers-1] == 1){
        sensorVentana = digitalRead(SENSOR1);
    } else sensorVentana = 1;

    if (sensorVentana == 1){
        int ledOn = numPers - 1;
        orden[ledOn] = command.charAt(1) - '0';

        int i1 = (numPers*2) - 2;
        int i2 = (numPers*2) - 1;

        if (orden[ledOn] == 1){
            // persiana down
            digitalWrite(L[ledOn], LOW);
            digitalWrite(R[i2], rType);
            delay(delayRelay);
            digitalWrite(R[i1], !rType);
            states [i1] = !rType;
            states [i2] = rType;
            if (ordenPrevia[ledOn] == 1) {
                ordenMillis[ledOn] = millis() - transcurrido[i1] - 1;
            } else if (ordenPrevia[ledOn] == 2) {
            } else ordenMillis[ledOn] = millis();
            String message = String::format("Persiana %d Bajando.", numPers);
            Particle.publish("googleDocs", "{\"detalles\":\"" + message + "\", \"dispositivo\":\""+ dispositivo + "\"}", 60, PRIVATE);
            return 1;
        } else if (orden[ledOn] == 2){
            // persiana stop
            digitalWrite(L[ledOn], HIGH);
            digitalWrite(R[i1], rType);
            digitalWrite(R[i2], rType);
            states [i1] = !rType;
            states [i2] = !rType;
            if (ordenPrevia[ledOn] == 1) {
                ordenMillis[ledOn] = millis() - transcurrido[i1] - 1;
            } else if (ordenPrevia[ledOn] == 3) {
                ordenMillis[ledOn] = millis() - transcurrido[i2] - 1;
            } else ordenMillis[ledOn] = millis();
            String message = String::format("Persiana %d Detenida.", numPers);
            Particle.publish("googleDocs", "{\"detalles\":\"" + message + "\", \"dispositivo\":\""+ dispositivo + "\"}", 60, PRIVATE);
            return 1;
        } else if (orden[ledOn] == 3){
            // persiana up
            digitalWrite(L[ledOn], LOW);
            digitalWrite(R[i1], rType);
            delay(delayRelay);
            digitalWrite(R[i2], !rType);
            states [i1] = rType;
            states [i2] = !rType;
            ordenMillis[ledOn] = millis();
            if (ordenPrevia[ledOn] == 3) {
                ordenMillis[ledOn] = millis() - transcurrido[i2] - 1;
            } else ordenMillis[ledOn] = millis();
           String message = String::format("Persiana %d Subiendo.", numPers);
            Particle.publish("googleDocs", "{\"detalles\":\"" + message + "\", \"dispositivo\":\""+ dispositivo + "\"}", 60, PRIVATE);
            return 1;
        } else return -1;
    } else return -1;
}

void apagadoRelevadores() {
    /*    Función apagadoRelevadores(): se usa para apagar los relevadores encendidos por controlPersiana(), transcurrido el tiempo
            de delay programado en el arreglo T.

            Nota: falta crear la forma en que almacene el tiempo transcurrido desde que se detuvo o puso en acción alguna persiana
            sin que haya subido o bajado completamente.
    */

    int ledOff;

    for (int h=0; h<6; h++){
        ledOff = ((((h % 2) == 0 ? h : (h-1)) + 2) / 2)-1;
        if (orden[ledOff] == 1) {
            if (transcurrido[h] >= T[h] && states[h] == !rType) {
                digitalWrite(R[h],rType);
                digitalWrite(L[ledOff],HIGH);
                transcurrido[h] = 0;
                ordenPrevia[ledOff] = 0;
                orden[ledOff] = 0;
                ordenMillis[ledOff] = 0;
                states [h] = rType;
            } else if (states[h] == !rType) {
                transcurrido[h] = millis() - ordenMillis[ledOff];
                ordenPrevia[ledOff] = 1;
            }
        } else if (orden[ledOff] == 2) {
            if (ordenPrevia[ledOff] == 1) {
                ordenMillis[ledOff] = millis() - transcurrido[h] - 1;
            } else if (ordenPrevia[ledOff] == 3) {
                ordenMillis[ledOff] = millis() - transcurrido[h] - 1;
            } else {
                ordenMillis[ledOff] = millis();
                ordenPrevia[ledOff] = 2;
            }
        } else if (orden[ledOff] == 3) {
            if (transcurrido[h] >= T[h] && states[h] == !rType) {
                digitalWrite(R[h],rType);
                digitalWrite(L[ledOff],HIGH);
                transcurrido[h] = 0;
                ordenPrevia[ledOff] = 0;
                orden[ledOff] = 0;
                ordenMillis[ledOff] = 0;
                states [h] = rType;
            } else if (states[h] == !rType) {
                transcurrido[h] = millis() - ordenMillis[ledOff];
                ordenPrevia[ledOff] = 3;
            }
        }
    }
}

So, any advice and help that you can provide me to get a workaround for this problem will be much appreciated. Thanks in advance :smiley:

@Axolopochtli, the SparkIntervalTimer library is used in the IRremote library. It provides access to the hardware timers in the Gen 2 STM32 processor to create timed interrupts that can go a low as 10us. The Gen3 mesh hardware uses a different processor, the Nordic nRF52840 which has completely different hardware including timers. In fact, in rc26 the firmware uses all but one hardware timer. It is my understanding that in future releases, there may be up to three hardware timers available for a new version of SparkIntervalTimer to use. However, I won’t be working on this new library until that time.

3 Likes

@peekay123 Thank you for the answer. I think I’ll get into finding a workaround to decode the IR sensor data. This Mesh hardware still has plenty of potential to be unlocked, which is quite exciting :smiley:

1 Like

Any chances this is still on the drawing board for the Mesh products? Seems like a lot of libraries rely on this one, and they’re all not usable at the moment.