HYGROMAX 630 - Made with Maxim !!! (Final Submission)

Introduction
Hydroponics is the science of growing plants without soil. Nutrients are fed directly to the plant via nutrient solution in a very carefully monitored environment. This level of control allows us to predict various parameters such as yield, time to bear fruit, etc.
There are certain requirements that need to be met in order to be able to control this environment successfully. Sensors need to be scanned periodically, data collected, stored and available on the cloud for viewing and monitoring from a remote location.
The MAX32630FTHR suits this requirement perfectly. An ARM processor which comfortably processes all the sensor activity, SD Card on board which is used here to set up the unit (configuration), a gyro and accelerometer to monitor and alert the user if any disturbances occur and BLE to be able to use a mobile phone or tablet to view data and also to upload the data to the cloud.


BOM
MAX32630FTHR
MAX7219 - 4 nos.
74HC164 - 5 nos.
Light Dependent Resistors - 9 nos.
MH-Z14 CO2 sensor - 1 no.
pH Electrode - 3 nos.
Water Level Sensor - 3 nos.
DHT-11 - Humidity/Temperature Sensor - 3 nos.
74HC4067 - ADC MUX - 2 nos.


Schematics


Instructions
Discussed in previous blogs
Video
Just a small clip to show most of the sensors hooked up and the actuators kicking in to light up the unit or switch on the fans. Also seen in the clip are the BLE notifications coming in from the unit. Since we are using custom characteristics, the values are not recognized in any particular format and are also not named since this is a proprietary software that I am using to check the notifications..



Source Code
Code:
#include "mbed.h"
#include "max32630fthr.h"
#include "shiftreg.h"
#include "adc.h"
#include "Dht11.h"
#include "bmi160.h"
#include "ble/BLE.h"
#include "ble/services/BatteryService.h"
#include "ble/services/EnvironmentalService.h"
#include "DeviceInformationService.h"
#include "FATFileSystem.h"
#include "SDBlockDevice.h"


#define MAX_RELAYS                 8
#define MAX_ADC                    32
#define    MAX_SUBSYSTEMS            6        // temperature, humidity, pH, CO2, Oxygen, Water Level
#define    GYRO_TRIGGER            5.0        // no real need for this to be less than 20, really
#define GYRO_SCAN_INTERVAL        1.0      // seconds - consider bumping this to 200ms
#define    ADC_SETTLE_TIME            20    // milliseconds

#define    ALL_GREEN_OFFSET        204
#define    QUAD1_OFFSET            1
#define    QUAD2_OFFSET            16
#define    QUAD3_OFFSET            32
#define    QUAD4_OFFSET            2

//////////////////////////////////////
//
//ADC MUX INPUT DEFINITIONS

#define T1HUM                    0
#define T2HUM                    1
#define T3HUM                    2

#define T1CO2                    3
#define T2CO2                    4
#define T3CO2                    5

#define T1pH                    6
#define T2pH                    7
#define T3pH                    8

#define    T1WLEVEL                9
#define    T2WLEVEL                10
#define    T3WLEVEL                11

#define    T1L1                    16
#define    T1L2                    17
#define    T1L3                    18
#define    T2L1                    19
#define    T2L2                    20
#define    T2L3                    21
#define    T3L1                    22
#define    T3L2                    23
#define    T3L3                    24

//////////////////////////////////////

//RELAYS DEFINITIONS
#define    RELAY_T1_LIGHT1        0
#define    RELAY_T1_LIGHT2        1
#define    RELAY_T1_LIGHT3        2
#define    RELAY_T2_LIGHT1        3
#define    RELAY_T2_LIGHT2        4
#define    RELAY_T2_LIGHT3        5
#define    RELAY_T3_LIGHT1        6
#define    RELAY_T3_LIGHT2        7
#define    RELAY_T3_LIGHT3        8
#define    RELAY_T1_FAN        9
#define    RELAY_T2_FAN        10
#define    RELAY_T3_FAN        11
#define    RELAY_T1_OXYPUMP    12
#define    RELAY_T2_OXYPUMP    13
#define    RELAY_T3_OXYPUMP    14
#define    RELAY_T1_CO2        15
#define    RELAY_T2_CO2        16
#define    RELAY_T3_CO2        17



    ////////////////////////////////////////////////////////////////////////////
    // BMI160 Initialization
    I2C i2cBus(P5_7, P6_0);
    BMI160_I2C imu(i2cBus, BMI160_I2C::I2C_ADRS_SDO_LO);
    BMI160::AccConfig accConfig;
    BMI160::GyroConfig gyroConfig;
 
 


// Shift Register Initialization
ShiftOut sr(P3_5,P3_2,P3_3,24); // CLK, DATA, CLR  for the 3 74LS164's handling the relays
ShiftOut adcmux(P5_4,P5_5,P5_3,8); // CLK, DATA, CLR for the single 164 handling the ADC signal multiplexers
ShiftOut levelmon(P3_0,P3_1,P4_0,8); // CLK, DATA, CLR for the single 164 displaying level disturbances (dual LEDs)

// DHT-11 Initialization
Dht11 hum_sensor1(P5_6);
Dht11 hum_sensor2(P5_6);
Dht11 hum_sensor3(P5_6);

// SPI Initialization - for MAX7219
SPI spi(P5_1, P5_2, P5_0);          //  MOSI, MISO, SCLK - MISO not used here, though
DigitalOut cs(P3_4);                // Chip select (LOAD)

// On board LED
DigitalOut rLED(LED1, LED_OFF);
DigitalOut gLED(LED2, LED_OFF);
DigitalOut bLED(LED3, LED_OFF);

//Level Monitor Reset Pin

BatteryService *batteryServicePtr;
DeviceInformationService *deviceInformationServicePtr;
EnvironmentalService *environServicePtr;

char config_buffer[128];

const char     DEVICE_NAME[]        = "HYGROMAX630";
const uint16_t uuid16_list[]        = {    GattService::UUID_BATTERY_SERVICE,
                                        GattService::UUID_DEVICE_INFORMATION_SERVICE,
                                        GattService::UUID_ENVIRONMENTAL_SERVICE};

int    mon_temperature        =     77;    // farenheit
int mon_humidity        =    85;    // percentage
int mon_pH                =    75;    // pH*10
int mon_fans            =    7;    // powers of 2 format
int mon_lights            =    32; // powers of 2 format
int mon_waterlevel        =    80;    // percentage
int    mon_oxygen            =    1;    // 1 or 0
int    mon_co2                =    99;    // ppm

int    batteryPercentage    = 100;

Ticker sec_tick;
Ticker fivesecs_tick;
Ticker fifteensecs_tick;
Ticker eighteensecs_tick;
Ticker levelmon_tick;

int mc_seconds = 0;
int mc_minutes = 39;
int mc_hours = 10;
int mc_days = 17;
int start_hours = 0;
int start_minutes = 0;


int lightintensitytrigger = 500;   // probably needs further calibration
                                  // also, consider moving this to the SD card
                                 // along with the others

int lightdutycycle = 0;
int co2trigger = 0;
int pHtrigger = 0;
int lp_lights = 0;
int lp_oxygen = 0;
int lp_co2 = 0;


int    subsys_count = 0;

int adc_int;

float imuTemperature;
BMI160::SensorData accData;
BMI160::SensorData gyroData;
BMI160::SensorTime sensorTime;
int disturbed = 0;
int QUAD1 = 0;
int QUAD2 = 0;
int QUAD3 = 0;
int QUAD4 = 0;
 

int RELAYS[MAX_RELAYS];
int srcount = 0;
int adc_count = 3;  //0,1,2 - humidity

int TWOPOWERS[] = {1,
        2,
        4,
        8,
        16,
        32,
        64,
        128,
        256,
        512,
        1024,
        2048,
        4096,
        8192,
        16384,
        32768,
        65536,
        131072,
        262144,
        524288,
        1048576,
        2097152,
        4194304,
        8388608,
        16777216};

unsigned char ADC_SELECT[32] = {32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
                                16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};


unsigned char BUFFER_MSB[4][8];
unsigned char BUFFER_LSB[4][8];


void periodicCallback(void)
{
 
 
}

/* Restart Advertising on disconnection*/
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    BLE::Instance().gap().startAdvertising();
}

/* Connection */
void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
}


/**
* This function is called when the ble initialization process has failed
*/
void onBleInitError(BLE &ble, ble_error_t error)
{
    /* Avoid compiler warnings */
    (void) ble;
    (void) error;
    /* Initialization error handling should go here */
}

/**
* Callback triggered when the ble initialization process has finished
*/
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        /* In case of error, forward the error handling to onBleInitError */
        onBleInitError(ble, error);
        return;
    }

    /* Ensure that it is the default instance of BLE */
    if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);
    ble.gap().onConnection(connectionCallback);

    /* Setup primary service. */
    deviceInformationServicePtr = new DeviceInformationService(ble, "Maxim", "FTHR", "00001", "0.1", "0.0", "0.0");
    batteryServicePtr = new BatteryService(ble, batteryPercentage);
    environServicePtr = new EnvironmentalService(ble);
 
    /* Setup advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(250); /* 250ms */
    ble.gap().startAdvertising();
}

void ClearLoadPin()
{
    cs = 0;                         // Set CS Low
}

void SetLoadPin()
{
    cs = 1;                         // Set CS High
}

/// Send two bytes to SPI bus
void SPI_Write2(unsigned char MSB, unsigned char LSB)
{
    spi.write(MSB);                 // Send two bytes
    spi.write(LSB);

}

void ReadADC(int select)
{
    float adc_f = 0.0;
    float adc_norm = 0.0;
 
    uint16_t adc_value;
    unsigned int overflow;
    ADC_StartConvert(ADC_CH_1_DIV_5, 0, 1); // AIN1 div 5
    overflow = (ADC_GetData(&adc_value) == E_OVERFLOW ? 1 : 0);
    printf("AIN1/5: 0x%04x%s  %d    %d\r\n", adc_value, overflow ? "*" : " ", ADC_SELECT[select], adc_value);
    adc_f = adc_value;
    adc_norm = (adc_f/1024.0)*100.0;
    adc_int = adc_norm;
    if(adc_int > 99)
        adc_int = 99;
}
/*
void TestADCMUX()
{
    ClearAllRelays();
    adcmux.setclr();

    if(adc_count==MAX_RELAYS)
    {
           adc_count = 3;  //0,1,2 - humidity
           wait(1.0);
    }
 
    adcmux.write(ADC_SELECT[adc_count]);
    wait_ms(1);
    ReadADC(adc_count);
 
    SetRelay(adc_count);
    int relay_data = GetRelayData();
    sr.write(relay_data);
    wait(1);
}
*/

/// Send eight control bytes to SPI bus to 4 7219's
void SPI_Write8(unsigned char MSB, unsigned char LSB)
{
    ClearLoadPin();
    spi.write(MSB);                 // Send two bytes to 4
    spi.write(LSB);
    spi.write(MSB);                 // Send two bytes to 3
    spi.write(LSB);
    spi.write(MSB);                 // Send two bytes to 2
    spi.write(LSB);
    spi.write(MSB);                 // Send two bytes to 1
    spi.write(LSB);
    SetLoadPin();
}

/// Send eight bytes to SPI bus to 4 7219's
void SPI_Write8BUF()
{
    for(int digit=0;digit<8;digit++)
    {
        ClearLoadPin();
 
        spi.write(BUFFER_MSB[3][digit]);                 // Send two bytes to 3
        spi.write(BUFFER_LSB[3][digit]);
        spi.write(BUFFER_MSB[2][digit]);                 // Send two bytes to 2
        spi.write(BUFFER_LSB[2][digit]);
        spi.write(BUFFER_MSB[1][digit]);                 // Send two bytes to 1
        spi.write(BUFFER_LSB[1][digit]);
        spi.write(BUFFER_MSB[0][digit]);                 // Send two bytes to 4
        spi.write(BUFFER_LSB[0][digit]);
 
        SetLoadPin();
    }
}
     
void SPI_WriteToBuf(int bufslot, int digit, unsigned char MSB, unsigned char LSB)
{
       BUFFER_MSB[bufslot][digit] = MSB;              
       BUFFER_LSB[bufslot][digit] = LSB;
     
}

void Update_MAX7219()
{
                 
          SPI_Write8BUF();
}



/// MAX7219 initialisation
void Init_MAX7219(void)
{
    SPI_Write8(0x09, 0xFF);         // Decoding on
    SPI_Write8(0x0A, 0x08);         // Brightness to intermediate
    SPI_Write8(0x0B, 0x07);         // Scan limit = 7
    SPI_Write8(0x0C, 0x01);         // Normal operation mode
    SPI_Write8(0x0F, 0x0F);         // Enable display test
    wait_ms(100);                   // 500 ms delay
    /*
    SPI_Write8(0x01, 0x00);         // Clear row 0.
    SPI_Write8(0x02, 0x00);         // Clear row 1.
    SPI_Write8(0x03, 0x00);         // Clear row 2.
    SPI_Write8(0x04, 0x00);         // Clear row 3.
    SPI_Write8(0x05, 0x00);         // Clear row 4.
    SPI_Write8(0x06, 0x00);         // Clear row 5.
    SPI_Write8(0x07, 0x00);         // Clear row 6.
    SPI_Write8(0x08, 0x00);         // Clear row 7.
    */
    SPI_Write8(0x0F, 0x00);         // Disable display test
    wait_ms(100);
}

int GetRelayData()
{
    int rd = 0;
    for(int i=0;i<MAX_RELAYS;i++)
        if(RELAYS[i])
            rd += TWOPOWERS[i];
    return(rd);
}


void ScanLight()
{
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T1L1]);
    wait_ms(1);
    printf("Light T1L1 - ");
    ReadADC(T1L1);
    SPI_WriteToBuf(1,0,1,13);
    SPI_WriteToBuf(1,1,2,1);
    SPI_WriteToBuf(1,2,3,(adc_int/10));
    SPI_WriteToBuf(1,3,4,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T1L2]);
    wait_ms(1);
    printf("Light T1L2 -");
    ReadADC(T1L2);
    SPI_WriteToBuf(1,4,5,(adc_int/10));
    SPI_WriteToBuf(1,5,6,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T1L3]);
    wait_ms(1);
    printf("Light T1L3 - ");
    ReadADC(T1L3);
    SPI_WriteToBuf(1,6,7,(adc_int/10));
    SPI_WriteToBuf(1,7,8,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T2L1]);
    wait_ms(1);
    printf("Light T2L1 - ");
    ReadADC(T2L1);
    SPI_WriteToBuf(2,0,1,13);
    SPI_WriteToBuf(2,1,2,1);
    SPI_WriteToBuf(2,2,3,(adc_int/10));
    SPI_WriteToBuf(2,3,4,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T2L2]);
    wait_ms(1);
    printf("Light T2L2 - ");
    ReadADC(T2L2);
    SPI_WriteToBuf(2,4,5,(adc_int/10));
    SPI_WriteToBuf(2,5,6,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T2L3]);
    wait_ms(1);
    printf("Light T2L3 - ");
    ReadADC(T2L3);
    SPI_WriteToBuf(2,6,7,(adc_int/10));
    SPI_WriteToBuf(2,7,8,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T3L1]);
    wait_ms(1);
    printf("Light T3L1 - ");
    ReadADC(T3L1);
    SPI_WriteToBuf(3,0,1,13);
    SPI_WriteToBuf(3,1,2,1);
    SPI_WriteToBuf(3,2,3,(adc_int/10));
    SPI_WriteToBuf(3,3,4,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T3L2]);
    wait_ms(1);
    printf("Light T3L2 -  ");
    ReadADC(T3L2);
    SPI_WriteToBuf(3,4,5,(adc_int/10));
    SPI_WriteToBuf(3,5,6,(adc_int%10));
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T3L3]);
    wait_ms(1);
    printf("Light T3L3 - ");
    ReadADC(T3L3);
    SPI_WriteToBuf(3,6,7,(adc_int/10));
    SPI_WriteToBuf(3,7,8,(adc_int%10));
 
}

void ScanHumidity()
{
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T1HUM]);
    wait_ms(ADC_SETTLE_TIME);
    hum_sensor1.read();
    wait_ms(ADC_SETTLE_TIME);
    float ftemp1 = hum_sensor1.getFahrenheit();
    int ihum = hum_sensor1.getHumidity();
    printf("T: %f, H: %d\r\n",ftemp1 , ihum);
    SPI_WriteToBuf(1,0,1,12);
    SPI_WriteToBuf(1,1,2,10);
    SPI_WriteToBuf(1,2,3,(ihum/10));
    SPI_WriteToBuf(1,3,4,(ihum%10));
    int itemp = ftemp1;
    SPI_WriteToBuf(1,5,6,(itemp/10));
    SPI_WriteToBuf(1,6,7,(itemp%10));
    SPI_WriteToBuf(1,7,8,14);
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T2HUM]);
    wait_ms(ADC_SETTLE_TIME);
    hum_sensor2.read();
    wait_ms(ADC_SETTLE_TIME);
    float ftemp2 = hum_sensor2.getFahrenheit();
    ihum = hum_sensor2.getHumidity();
    printf("T: %f, H: %d\r\n",ftemp2 , ihum);
    SPI_WriteToBuf(2,0,1,12);
    SPI_WriteToBuf(2,1,2,10);
    SPI_WriteToBuf(2,2,3,(ihum/10));
    SPI_WriteToBuf(2,3,4,(ihum%10));
    itemp = ftemp2;
    SPI_WriteToBuf(2,5,6,(itemp/10));
    SPI_WriteToBuf(2,6,7,(itemp%10));
    SPI_WriteToBuf(2,7,8,14);
 
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T3HUM]);
    wait_ms(ADC_SETTLE_TIME);
    hum_sensor3.read();
    wait_ms(ADC_SETTLE_TIME);
    float ftemp3 = hum_sensor3.getFahrenheit();
    ihum = hum_sensor3.getHumidity();
    printf("T: %f, H: %d\r\n",ftemp3 , ihum);
    SPI_WriteToBuf(3,0,1,12);
    SPI_WriteToBuf(3,1,2,10);
    SPI_WriteToBuf(3,2,3,(ihum/10));
    SPI_WriteToBuf(3,3,4,(ihum%10));
    itemp = ftemp3;
    SPI_WriteToBuf(3,5,6,(itemp/10));
    SPI_WriteToBuf(3,6,7,(itemp%10));
    SPI_WriteToBuf(3,7,8,14);
    /*
    if((ftemp1>80.0)||(ftemp2>80.0)||(ftemp3>80))
    {
        RELAYS[21] = 1;
        RELAYS[22] = 1;
        RELAYS[23] = 1;
    } 
    else
    {
        RELAYS[21] = 0;
        RELAYS[22] = 0;
        RELAYS[23] = 0;     
    }
    int relay_data = GetRelayData();
    sr.write(relay_data);
    */
}

void ScanCO2()
{
    adcmux.setclr();
    adcmux.write(ADC_SELECT[T1CO2]);
    wait_ms(1);
    printf("CO2  T1CO2 - ");
    ReadADC(T1CO2);
    SPI_WriteToBuf(1,0,1,14);
    SPI_WriteToBuf(1,1,2,14);
    SPI_WriteToBuf(1,2,3,10);
    SPI_WriteToBuf(1,3,4,(adc_int/10));
    SPI_WriteToBuf(1,4,5,(adc_int%10));
 
    SPI_WriteToBuf(2,0,1,14);
    SPI_WriteToBuf(2,1,2,14);
    SPI_WriteToBuf(2,2,3,10);
    SPI_WriteToBuf(2,3,4,(adc_int/10));
    SPI_WriteToBuf(2,4,5,(adc_int%10));
 
    SPI_WriteToBuf(3,0,1,14);
    SPI_WriteToBuf(3,1,2,14);
    SPI_WriteToBuf(3,2,3,10);
    SPI_WriteToBuf(3,3,4,(adc_int/10));
    SPI_WriteToBuf(3,4,5,(adc_int%10));
}

void ScanOxygen()
{
    if(RELAYS[RELAY_T1_OXYPUMP] == 1)
        printf("Oxygen Flow is ON \r\n");
    else
        printf("Oxygen Flow is OFF \r\n");
}


void UpdateClock()
{
    int sec_tens = mc_seconds / 10;
    int sec_units = mc_seconds % 10;
    int min_tens = mc_minutes / 10;
    int min_units = mc_minutes % 10;
    int hour_tens = mc_hours / 10;
    int hour_units = mc_hours % 10;
    int day_tens = mc_days / 10;
    int day_units = mc_days % 10;
 
    SPI_WriteToBuf(0,0,1,hour_tens);
    SPI_WriteToBuf(0,1,2,hour_units);
    SPI_WriteToBuf(0,2,3,min_tens);
    SPI_WriteToBuf(0,3,4,min_units);
    SPI_WriteToBuf(0,4,5,sec_tens);
    SPI_WriteToBuf(0,5,6,sec_units);
    SPI_WriteToBuf(0,6,7,day_tens);
    SPI_WriteToBuf(0,7,8,day_units);
 
    // Get our ADC mux to fire every 2 seconds without setting up an extra ticker for this
    if((mc_seconds % 2)==0)
    {
        if(subsys_count==MAX_SUBSYSTEMS)
            subsys_count = 0;
        int selected_disp = subsys_count % MAX_SUBSYSTEMS;
        switch (selected_disp)
        {
        case 0:
            //Light
            ScanLight();
            break;
        case 1:
            // Humidity Temperature
            ScanHumidity();
            break;
        case 2:
            // Oxygen
            //ScanOxygen();
            break;
        case 3:
            //CO2
            ScanCO2();
            break;
        case 4:
            //pH
            //ScanpH();
            break;
        case 5:
            //Water Level
            //ScanWaterLevel();
            break;
        }
        subsys_count++;
    } // mc_seconds % 2
 
    Update_MAX7219();


    Update_MAX7219();
}

void MonitorLevel()
{
    imu.getGyroAccXYZandSensorTime(accData, gyroData, sensorTime, accConfig.range, gyroConfig.range);
    imu.getTemperature(&imuTemperature);
 
    if(!disturbed)
    {
     
       //    QUADRANTS
       //
       //     2     1
       //  
       //     3     4
     
       int xval = gyroData.xAxis.scaled;
       int yval = gyroData.yAxis.scaled;
       //int zval = gyroData.zAxis.scaled; // we'll come back for this some other day
     
       if((QUAD1!=0)||(QUAD2!=0)||(QUAD3!=0)||(QUAD4!=0))
            disturbed = 1;
     
       if(xval > GYRO_TRIGGER)  // 3 or 4 lowered
          if(yval > GYRO_TRIGGER) // 4
              QUAD4 = 1;
          else if(yval < -(GYRO_TRIGGER))  //3
              QUAD3 = 1;
          else // 3 and 4
              QUAD3 = QUAD4 = 1;
       else if(xval < -(GYRO_TRIGGER))  // 1 or 2 lowered
          if(yval > GYRO_TRIGGER) // 1
              QUAD1 = 1;
          else if(yval < -(GYRO_TRIGGER))  //2
              QUAD2 = 1;
          else
              QUAD1 = QUAD2 = 1;
       else if(yval > GYRO_TRIGGER) // 1 and 4
          QUAD1 = QUAD4 = 1;
       else if(yval < -(GYRO_TRIGGER)) // 2 and 3
          QUAD2 = QUAD3 = 1;
       // else // basically, all is well - no disturbance
       //    QUAD1 = QUAD2 = QUAD3 = QUAD4 = 0;
    }  // if(!disturbed)

    levelmon.setclr();
    int level_pattern = ALL_GREEN_OFFSET;
    if(QUAD1==1)
        level_pattern += QUAD1_OFFSET;
    if(QUAD2==1)
        level_pattern += QUAD2_OFFSET;
    if(QUAD3==1)
        level_pattern += QUAD3_OFFSET;
    if(QUAD4==1)
        level_pattern += QUAD4_OFFSET;
 
    levelmon.write(level_pattern);
 

}

void SetRelay(int relno)
{
    RELAYS[relno] = 1;
}

void ClearRelay(int relno)
{
    RELAYS[relno] = 0;
}

void ClearAllRelays(){
    for(int i=0;i<MAX_RELAYS;i++)
        RELAYS[i] = 0;
    sr.setclr();
}



void TestAllRelays()
{
    if(srcount==MAX_RELAYS)
    {
       srcount = 0;
       ClearAllRelays();
    }
    SetRelay(srcount);
    int relay_data = GetRelayData();
    sr.write(relay_data);
    printf("RELAYS SWITCHED ON - %d\r\n", relay_data);
    wait_ms(10);
    srcount++;
}


void EverySecond()
{

    gLED = !gLED;
    bLED = !bLED;
    rLED = !rLED; /* Blink LED while we're waiting for BLE events */

 
    batteryServicePtr->updateBatteryLevel(batteryPercentage);
 
    environServicePtr->updateTemperature(mon_temperature);
    environServicePtr->updateHumidity(mon_humidity);
 
    environServicePtr->updatepH(mon_pH);
    environServicePtr->updateLights(mon_lights);
    environServicePtr->updateWaterLevel(mon_waterlevel);
    environServicePtr->updateOxygen(mon_oxygen);
    environServicePtr->updateFans(mon_fans);
    environServicePtr->updateCO2(mon_co2);
 
    /*
 
    printf("\033[H");  //home
    printf("\033[0J");  //erase from cursor to end of screen
 
    printf("ACC xAxis = %s%4.3f\r\n", "\033[K", accData.xAxis.scaled);
    printf("ACC yAxis = %s%4.3f\r\n", "\033[K", accData.yAxis.scaled);
    printf("ACC zAxis = %s%4.3f\r\n\n", "\033[K", accData.zAxis.scaled);
 
    printf("GYRO xAxis = %s%5.1f\r\n", "\033[K", gyroData.xAxis.scaled);
    printf("GYRO yAxis = %s%5.1f\r\n", "\033[K", gyroData.yAxis.scaled);
    printf("GYRO zAxis = %s%5.1f\r\n\n", "\033[K", gyroData.zAxis.scaled);
 
    printf("Sensor  Time = %s%f\r\n", "\033[K", sensorTime.seconds);
    printf("Sensor  Temperature = %s%5.3f\r\n", "\033[K", imuTemperature);
 
    printf("%d        %d\r\n\n",QUAD2,QUAD1);
    printf("%d        %d\r\n\n",QUAD3,QUAD4);
 
    */
    if(mc_seconds==59){
        mc_seconds=0;
        if(mc_minutes==59)
        {
            mc_minutes=0;
            if(mc_hours==23)
            {
                mc_hours=0;
                mc_days++;
            }
            else
                mc_hours++;
        }
        else
            mc_minutes++;
    }
    else
        mc_seconds++;
 
    UpdateClock();
 
 
}


void LevelResetFunc()
{
    disturbed = 0;
    QUAD1 = QUAD2 = QUAD3 = QUAD4 = 0;


}



void LoadConfigParam(int entry)
{
    int mc_int;
    mc_int = atoi(config_buffer);
    switch (entry)
        {
        case 0:
            //Current Time
            printf("Start with %d\r\n", mc_int);
            mc_days = mc_int % 100;
            mc_int = (mc_int - mc_days)/100;
            printf("Now at %d\r\n",mc_int);
            mc_seconds = mc_int % 100;
            mc_int = (mc_int - mc_seconds)/100;
            printf("Now at %d\r\n",mc_int);
            mc_minutes = mc_int % 100;
            mc_int = (mc_int - mc_minutes)/100;
            printf("Now at %d\r\n",mc_int);
            mc_hours = mc_int % 100;
         
            printf("System Clock Reset to %d hours, %d minutes, %d seconds (%d Days)\r\n", mc_hours, mc_minutes, mc_seconds, mc_days);
            break;
        case 1:
            // Cycle Start Time
            start_minutes = mc_int % 100;
            start_hours = (mc_int - start_minutes)/100;
            printf("Cycle Starts at %d hours and %d minutes\r\n", start_hours, start_minutes);
            break;
        case 2:
            //Light Duty Cycle
            lightdutycycle = mc_int;
            printf("Light Duty Cycle set at %d hours\r\n", mc_int);
            break;
        case 3:
            // CO2 PPM Trigger
            co2trigger = mc_int;
            printf("CO2 Trigger set at %d (ppm)\r\n", co2trigger);
            break;
        case 4:
            // pH Trigger
            pHtrigger = mc_int;
            printf("pH Trigger set at %d (Scale x10)\r\n",pHtrigger);
            break;
        case 5:
            // Lights - Low Power
            lp_lights = mc_int;
            printf("Lights on Low Power Mode - %d\r\n",lp_lights);
        case 6:
            // Oxygen - Low Power
            lp_oxygen = mc_int;
            printf("Oxygen on Low Power Mode - %d\r\n",lp_oxygen);
            break;
        case 7:
            // CO2 - Low Power
            lp_co2 = mc_int;
            printf("CO2 on Low Power Mode - %d\r\n",lp_co2);
            break;
        }
}

void ReadConfig()
{
    SDBlockDevice sd(P0_5,P0_6,P0_4,P0_7); // mosi, miso, sclk, cs
    FATFileSystem fs("fs");
 
    printf("Mounting the filesystem on \"/fs\". ");
    fs.mount(&sd);
 
    FILE* fd = fopen("/fs/config.txt", "r");
 

    int entry = 0;
    while(fgets(config_buffer, 128, fd)) {
        LoadConfigParam(entry);
        entry++;
    }
 
    /*
    char ch = fgetc(fd);
    while(!feof(fd)){
       printf("%c",ch);
       ch = fgetc(fd);
    }

 
    fclose(fd);
}


int main()
{
    uint32_t i = 0;
    LowPowerTicker ticker;
    BLE &ble = BLE::Instance();
    ble.init(bleInitComplete);
 
    /* SpinWait for initialization to complete. This is necessary because the
     * BLE object is used in the main loop below. */
    while (ble.hasInitialized() == false) { /* spin loop */ }
    sec_tick.attach(&EverySecond,1.0);
    //ticker.attach(periodicCallback, 1.5);
 
    // MAX32630FTHR Initialization
    MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
 
    // Initialize ADC
    ADC_Init();
 
    // BMI160 Initialization
    i2cBus.frequency(400000);
 
    cs = 1;                         // CS initially High
    spi.format(8,0);                // 8-bit format, mode 0,0
    spi.frequency(1000000);         // SCLK = 1 MHz
 
    Init_MAX7219();                 // Initialize the LED controller
   
    uint32_t failures = 0;
     
    if(imu.setSensorPowerMode(BMI160::GYRO, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
    {
        printf("Failed to set gyroscope power mode\n");
        failures++;
    }
    wait_ms(100);
 
    if(imu.setSensorPowerMode(BMI160::ACC, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
    {
        printf("Failed to set accelerometer power mode\n");
        failures++;
    }
    wait_ms(100);
 

    //example of using getSensorConfig
    if(imu.getSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
    {
        printf("ACC Range = %d\r\n", accConfig.range);
        printf("ACC UnderSampling = %d\r\n", accConfig.us);
        printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
        printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
    }
    else
    {
        printf("Failed to get accelerometer configuration\r\n");
        failures++;
    }
 
    //example of setting user defined configuration
    accConfig.range = BMI160::SENS_4G;
    accConfig.us = BMI160::ACC_US_OFF;
    accConfig.bwp = BMI160::ACC_BWP_2;
    accConfig.odr = BMI160::ACC_ODR_8;
    if(imu.setSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
    {
        printf("ACC Range = %d\r\n", accConfig.range);
        printf("ACC UnderSampling = %d\r\n", accConfig.us);
        printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
        printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
    }
    else
    {
        printf("Failed to set accelerometer configuration\r\n");
        failures++;
    }
 

    if(imu.getSensorConfig(gyroConfig) == BMI160::RTN_NO_ERROR)
    {
        printf("GYRO Range = %d\r\n", gyroConfig.range);
        printf("GYRO BandWidthParam = %d\r\n", gyroConfig.bwp);
        printf("GYRO OutputDataRate = %d\r\n\n", gyroConfig.odr);
    }
    else
    {
        printf("Failed to get gyroscope configuration\r\n");
        failures++;
    }

 
    /////////////////////////////////////////////////////////////////////////////////////
 
 
 
    fivesecs_tick.attach(&LevelResetFunc,5.0);


 
    levelmon_tick.attach(&MonitorLevel,GYRO_SCAN_INTERVAL);    // GYRO SCAN INTERVAL
 
    ReadConfig();
 
    while (1) {
        if (++i == 1000) {
           i = 0;
        }     
        ble.waitForEvent();
        //int relay_data = GetRelayData();
        //sr.write(relay_data);
    } // while(1)
}

Blog entry information

Author
avitron
Views
454
Last update

More entries in General

More entries from avitron

Share this entry

Top