setup_photon.cpp - MAE221/Thermodynamics-Lab GitHub Wiki

/**
 * This code will run automatically on the photon.
 * By calling the 
 * 
 * If we flash all of the photons/argons with this code before sending
 * them to the students, the devices will be able to talk to matlab
 * over serial.
 * 
 * TODO
 * - Test the code THOROUGHLY
 * 
 * ref:
 * System modes: https://docs.particle.io/reference/device-os/firmware/photon/#system-modes
 * Serial ref: https://docs.particle.io/reference/device-os/firmware/photon/#serial
 * Photon source: https://github.com/particle-iot/device-os/tree/develop/user/inc
 * Arduino String ref: https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
 */
#include "Particle.h"
/**Dummy values so vscode works right.**/
    #ifndef PARTICLE_H
    extern Particle;
    extern Serial;
    typedef struct Servo_V Servo;
    typedef struct String_V String;

    enum pins {
        A0, A1, A2, A3, A4, A5, A6, A7,
        D0, D1, D2, D3, D4, D5, D6, D7,
        INPUT, OUTPUT
    }
    #endif	/* PARTICLE_H */
/**End: Dummy values**/
/**Varaibles needed for online accesss**/
    Servo myservo;   // Create servo object to control a servo
    int pos = 70;    // Store the position of the servo
    double pulse = -1;    //length of pulse
    int pulsePin = -1;      //pulse pin
    int servoPin = -1;      //servo pin
    int freq =2000;  // Set the frequency of the analogWrite()
    int reading[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Store the memory of the read data or the written

    int memory[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Store the memory of the read data or the written
    int t = 200; //Set milliseconds of averaging
    int readVar[18] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; //Stores whether the pin is reading (1), writing (0), or uninitialized(-1) or Servo (2)
    String strTemp =""; //memory as string
    String strTemp2 =""; // read as string
/**End: Varaibles needed for online accesss**/

SYSTEM_MODE(MANUAL); // runs w/o connecting to cloud
//SYSTEM_MODE(SEMI_AUTOMATIC);

// enum of integers that correspond to a command
enum comms {
    f_CONNECT = 1,
    f_GETPINMODE = 2,
    f_ISCONNECTED = 3,
    f_SETINPUT = 4,
    f_SETOUTPUT = 5,
    f_ANALOGREAD = 6,
    f_DIGITALREAD = 7,
    f_ANALOGWRITE = 8,
    f_DIGITALWRITE = 9,
    f_GETPIN = 10,
    f_DISCONNECT = 11
};

// 1 if the photon has connected with the cloud before, 0 if not.
int firstConnect = 0;

void setup() {
    // try to setup serial connection
    Serial.begin();
    delay(100);
    /*if (!Serial.isConnected()) {
        // assume you want to connect over IP
        expose();
    }*/
    
    // connect to internet; if you don't want it to do so
    // right off the bat, comment out this block
    {
        Particle.connect();
    }
    // expose functions
    expose();
    pinMode(A0, OUTPUT);
    analogWrite(A0, 0);
    pinMode(A1, OUTPUT);
    analogWrite(A1, 0);
    pinMode(A2, OUTPUT);
    analogWrite(A2, 0);
    pinMode(A3, OUTPUT);
    analogWrite(A3, 0);
    pinMode(A4, OUTPUT);
    analogWrite(A4, 0);
    pinMode(A5, OUTPUT);
    analogWrite(A5, 0);
    pinMode(D0, OUTPUT);
    digitalWrite(D0,0);
    pinMode(D1, OUTPUT);
    digitalWrite(D1,0);
    pinMode(D2, OUTPUT);
    digitalWrite(D2,0);
    pinMode(D3, OUTPUT);
    digitalWrite(D3,0);
    pinMode(D4, OUTPUT);
    digitalWrite(D4,0);
    pinMode(D5, OUTPUT);
    digitalWrite(D5,0);
    pinMode(D6, OUTPUT);
    digitalWrite(D6,0);
    pinMode(D7, OUTPUT);
    digitalWrite(D7,0);
}

void loop() {
    // first, check the serial connection
    if (Serial.available()) {
        // get first byte from the USB
        int comm = Serial.read();
        String arg = "";

        // find the command that was called
        switch (comm) {
            case f_DISCONNECT:
                Particle.disconnect();
                WiFi.off();
                {
                    int i = 1;
                    Serial.write(i);
                }
                break;
            case f_CONNECT:
                Particle.connect();
                // not sure if need to, but expose again
                expose();
            case f_ISCONNECTED:
                if (Particle.connected()) {
                    int i = 1;
                    Serial.write(i);
                } else {
                    int i = 0;
                    Serial.write(i);
                }
                break;

            case f_GETPINMODE:
                getStr(arg, 3);
                Serial.write(pMode(arg));
                break;

            case f_SETINPUT:
                getStr(arg, 3);
                Serial.write(setInput(arg));
                break;
            
            case f_SETOUTPUT:
                getStr(arg, 3);
                Serial.write(setOutput(arg));
                break;

            case f_ANALOGREAD:
                getStr(arg, 3);
                {
                    int res = aread(arg);
                    int mask = 0b0000000011111111;
                    Serial.write(res & mask);
                    Serial.write(res >> 8);
                }
                break;

            case f_DIGITALREAD:
                getStr(arg, 3);
                Serial.write(dread(arg));
                break;
            
            case f_ANALOGWRITE:
                getStr(arg, -1);
                {
                    int res = awrite(arg);
                    int mask = 0b0000000011111111;
                    Serial.write(res >> 8);
                    Serial.write(res & mask);
                }
                break;

            case f_DIGITALWRITE:
                getStr(arg, -1);
                Serial.write(dwrite(arg));
                break;

            case f_GETPIN:
                getStr(arg, 3);
                Serial.write(getPin(arg));
                break;
            
            default:
                Serial.write(-1);
                break;
        }
    } 
    
    // next, check the 
    if (Particle.connected()) {
        Particle.process();
    }

    /**The rest of this function is required whether offline or not;
     * it stores the data from the pins in memory so they can be returned
     * in the function calls
     */
        //Read through the analog pins
        for(int m =0;m<t;m++)
        {
            for(int n = 10;n<=17;n++)
            {
                // If the pin is a writing pin
                if(readVar[n] == 0)
                {
                    //Write the value
                    analogWrite(n,memory[n]);//, freq);
                }
                // If the pin is a reading pin
                else if (readVar[n] == 1)
                {
                    //Iterate t times with a 1 ms delay to average out the analog reads
                        reading[n] += analogRead(n);
                        delay(1);
                    //Store the average value into memory
                }
            }
        }
        for(int n = 10;n<=17;n++)
        {
        if (readVar[n] == 1)
            {
            memory[n] = int(reading[n]/t);
            reading[n] = 0;
            }
        }

        //Read through the digital pins
        for(int n = 0;n<=7;n++)
        {
        //If a writing pin
            if(readVar[n] == 0)
            {
                //Write the value to the pin
                digitalWrite(n,memory[n]);
            }
            //If a reading pin
            else if (readVar[n] == 1)
            {
                //Read the value of the pin
                memory[n]=digitalRead(n);
            }
        }

        // Initialize null strings

        strTemp = "";
        strTemp2 = "";

        //Concatenate array values into the string
        for(int n = 0;n<17;n+=1)
        {
            strTemp.concat(String(memory[n]));
            strTemp.concat(',');
            strTemp2.concat(String(readVar[n]));
            strTemp2.concat(',');
        }
        strTemp.concat(String(memory[17]));
        strTemp2.concat(String(readVar[17]));
    /**End: required stuff section**/
}

/*
Function that exposes all other functions to the cloud.
*/
void expose() {
    Particle.function("move",slide);                //Particle function to relate slide to move
    Particle.function("attachServo",attachServo);   //Particle function to attachServo
    Particle.function("detachServo",detachServo);   //Particle function to detachServo
    Particle.function("setInput",setInput);         //Particle function to set the pinMode to input
    Particle.function("setOutput",setOutput);       //Particle function to set the pinMode to output
    Particle.function("pinMode",pMode);             //Particle function to get the pinMode where Input is 1 and Output is 0
    Particle.function("getPin",getPin);             //Particle function to translate string of pin to integer number
    Particle.function("analogWrite",awrite);        //Particle function to write value to analog pin
    Particle.function("analogRead",aread);          //Particle function to read analog pin
    Particle.function("digitalWrite",dwrite);       //Particle function to write value to digital pin
    Particle.function("digitalRead",dread);         //Particle function to read value from digital pin
    Particle.function("setFreq",setf);              //Particle function to set the analog write frequency
    Particle.function("getPulse",getPulse);         //Particle function to get the input frequency on an analog pin
    Particle.function("setAvgTime",setAvgTime);         //Particle function to get the input frequency on an analog pin

    Particle.variable("position",pos);              //Particle variable to get the position of the servo
    Particle.variable("frequency",freq);            //Particle variable to get the frequency of the analog write
    Particle.variable("String",strTemp);            //Particle variable to get the memory string
    Particle.variable("String2",strTemp2);          //Particle variable to get the read string
    Particle.variable("String2",strTemp2);          //Particle variable to get the read string
    Particle.variable("pulse",pulse);            //Particle variable to get the frequency of the analog write
}

/*
Tries to grab len bytes from Serial and puts the bytes in str as
chars. str must be an arduino String object. This function either 
reads len bytes or reads the number of bytes available if there 
are less than len bytes left. 
Returns the number of bytes read (including any null bytes).

NOTE: if len == -1, the string can be infinite.
*/
int getStr(String& str, int len) {
    int amt = 0;
    char lastChar = 'a';
    int avail = Serial.available();

    while (amt < avail && amt != len) {
        lastChar = (char)Serial.read(); // assumes data only in 1 byte even int is 32 bit
        amt++;
        str += lastChar;
    }

    return amt;
}

/********************IP ONLY FUNCTIONS**********************
 ***********************************************************
 ***********************************************************
 ***********************************************************
 ***********************************************************/ 
    int slide(String angle) //spark function slide will take the string it receives (turn) and output it as "angle"
    {
        myservo.write(angle.toInt()); //convert angle to an integer and
        pos = angle.toInt();  //set position as the angle
        delay(10);
        return pos; //necessary for the servo
    }

    int getPin(String pin) //Translate the string of the pin to an integer
    {
        if(pin.equals("A1")){
            return A1;
        }
        else if(pin.equals("A2")){
            return A2;
        }
        else if(pin.equals("A3")){
            return A3;
        }
        else if(pin.equals("A4")){
            return A4;
        }
        else if(pin.equals("A5")){
            return A5;
        }
        else if(pin.equals("A6")){
            return A6;
        }
        else if(pin.equals("A7")){
            return A7;
        }
        else if(pin.equals("A0")){
            return A0;
        }
        else if(pin.equals("D0")){
            return D0;
        }
        else if(pin.equals("D1")){
            return D1;
        }
        else if(pin.equals("D2")){
            return D2;
        }
        else if(pin.equals("D3")){
            return D3;
        }
        else if(pin.equals("D4")){
            return D4;
        }
        else if(pin.equals("D5")){
            return D5;
        }
        else if(pin.equals("D6")){
            return D6;
        }
        else if(pin.equals("D7")){
            return D7;
        }
        else{
            return -1;
        }
    }

    int attachServo(String pin) //Attach a servo to a pin
    {
        int p = getPin(pin); //convert pin to an integer
        if(p>-1 && readVar[p]==-1)
        {
            myservo.attach(p);
            servoPin = p;
            delay(10);
            readVar[p] = 2;
            return p;
        }
            return -1;
    }

    int detachServo(String pin) //Detach a servo to a pin
    {
            myservo.detach(); //convert pin to an integer
            readVar[servoPin] = -1;
            servoPin = -1;
            delay(10);
            return 1;
    }

    int setInput(String pin)    //Set the pin to an input pin
    {
        int p = getPin(pin);
        if(p>-1 && readVar[p]==-1)
        {
            pinMode(p, INPUT);
            readVar[p] = 1;
            return 1;
        }
            return -1;
    }

    int setOutput(String pin)   //Set the pin to an output pin
    {
        int p = getPin(pin);
        if(p>-1 && readVar[p]==-1)
        {
            pinMode(p, OUTPUT);
            readVar[p] = 0;
            return 1;
        }
            return -1;
    }

    int pMode(String pin)       //Get whether a pin is input(1) or output(0)
    {
        int p = getPin(pin);
        if (getPinMode(p)==INPUT)
        {
        return 1;
        }
        return 0;
    }

    int awrite(String pin)  //Takes an input argument with syntax "pin,value" ex. "A0,255"
    {
        int t = pin.indexOf(",");
        int p = getPin(pin.substring(0,t));
        //int t2 = pin.indexOf(",",t);
        int t3 = pin.lastIndexOf(",");
        String p1 = pin.substring(t3+1);
        int val = p1.toInt();
        //pinMode(p,OUTPUT);
        

        readVar[p] = 0;

        memory[p] = val;
        return val;
    }

    int aread(String pin) //Read analog value from a pin
    {
        int p = getPin(pin);
        return memory[p];

    }

    int dwrite(String pin) //write a value to a digital pin
    {
        int t = pin.indexOf(",");
        int p = getPin(pin.substring(0,t));
        //int t2 = pin.indexOf(",",t);
        int t3 = pin.lastIndexOf(",");
        String p1 = pin.substring(t3+1);
        int val = p1.toInt();

            if(abs(val)==0){
                memory[p] = 0;
                return 0;
            }
            else{
                memory[p] = 1;
                    return 1;
            }

        return val;
    }

    int dread(String pin)   //Read a value from a digital pin
    {

        int p = getPin(pin);
        return memory[p];

    }

    int setAvgTime(String val)   //Read a value from a digital pin
    {

        int t = val.toInt();
        return t;

    }

    int setf(String fre)    //Set the frequency of the analog write
    {
        freq =fre.toInt();
        return freq;
    }

    int getPulse(String pin) //get the tone of the analog read
    {
        pulsePin = getPin(pin);
        setInput(pin);
        pinMode(pulsePin,INPUT);
        double duration = pulseIn(pulsePin, HIGH);
        duration += pulseIn(pulsePin, LOW);
        return  1.0/(duration/1000000.0);;

    }
/**END: IP functions, Vars, and Values**/