Latest

Dependencies:   serial_terminal sample_hardware PLL_Config SDCard BMP280 Networkbits TextLCD SDBlockDevice

main.cpp

Committer:
Swabey89
Date:
2019-01-03
Revision:
32:8c9d8f2dfe89
Parent:
31:087e295cc859

File content as of revision 32:8c9d8f2dfe89:

#include "mbed.h"
#include <stm32f4xx.h>
#include "sample_hardware.hpp"
#include "Networking.hpp"
#include "serial_terminal.hpp"
#include "SDCard.hpp"
#include "rtos.h"
#include "events/mbed_events.h"
#include "LCDdisplay.hpp"
//#include "PLL_Config.c"

//Defines TEST FOR SD CARD MOUNT AND UNMOUNT
#define EDGE_FALLEN 0
#define EDGE_RISEN 1

//Signals
#define TAKE_SAMPLE 1
#define STORE_DATA 2


//Global variables


unsigned int newestIndex = BUFFERSIZE-1;    //First time it is incremented, it will be 0
unsigned int oldestIndex = BUFFERSIZE-1;
FILE* fp;
FATFileSystem* fs;

//Shared mutable variables VOLATILE
bool sd_init; //is it?
bool logging = false;
bool sampling = true;
float sample_rate = 15; //is it?
struct tm* timeData;
char cmdBuffer[256];
sensorData buffer[BUFFERSIZE];
RawSerial* pc;

//Thread synchronisation primatives
Semaphore spaceAvailable(BUFFERSIZE);
Semaphore samplesInBuffer(0, BUFFERSIZE);
Mutex bufferLock;

//Queues
EventQueue SDqueue(1024*EVENTS_EVENT_SIZE); //changed from 32
EventQueue LCDqueue(32*EVENTS_EVENT_SIZE);
EventQueue serialqueue(32*EVENTS_EVENT_SIZE);

//TEST
EventQueue printQueue(256*EVENTS_EVENT_SIZE);



//Threads
Thread producer_thread(osPriorityHigh);
Thread consumer_thread;
Thread serial_thread(osPriorityAboveNormal);
Thread SDqueue_thread; //take out queue in name?
Thread LCDqueue_thread;
Thread network_thread;

//TEST FOR SD CARD
Thread SDmount_thread;

//TEST FOR PRINTF


//Timers
Ticker sample;

//Function prototypes
void sampleISR(void);
void sampleProducer(void);
void sampleConsumer(void);
void serialISR(void);
void serialData(void);



//TEST FOR SD CARD MOUNT AND UNMOUNT
Timeout userswTimeOut;
int userswState = EDGE_FALLEN;
InterruptIn   usersw(USER_BUTTON);
void userswTimeOutHandler();
void userswRisingEdge();
void userswFallingEdge();
void SDmount();

Mutex printlock;
Mutex LCDlock;
Mutex timeLock;
Mutex SDlock;


//TEST FOR BUFFER CHANGES
unsigned int saveIndex = BUFFERSIZE-1;

int32_t Nspaces = BUFFERSIZE;
int32_t Nsamples;


//TEST FOR WATCHDOG
char threadstates = 0;

Timeout producer_tout;
Timeout consumer_tout;
Timeout serial_tout;
Timeout SD_tout;
Timeout LCD_tout;
Timeout network_tout;

Thread watchdog_thread(osPriorityHigh);

//TSET FOR PRINTF
Thread printf_thread;

void producer_toutISR(void);
void consumer_toutISR(void);
void serial_toutISR(void);
void SD_toutISR(void);
void LCD_toutISR(void);
void network_toutISR(void);
void watchdog(void);

void PLL_Config(void);

osThreadId main_thread;

#define PRODUCER 1<<0
#define CONSUMER 1<<1
#define SERIAL 1<<2
#define SD 1<<3
#define LCD 1<<4
#define NETWORK 1<<5

int main() {   
    PLL_Config();
    main_thread = Thread::gettid();
    timeData = new tm;
    pc = new RawSerial(USBTX, USBRX, 115200);
    
    //Initialisations
    SDcard();   
    
    //Power on self test
    post();
       
    //Start threads
    SDqueue_thread.start(callback(&SDqueue, &EventQueue::dispatch_forever));
    LCDqueue_thread.start(callback(&LCDqueue, &EventQueue::dispatch_forever));
    serial_thread.start(callback(&serialqueue, &EventQueue::dispatch_forever));
    network_thread.start(network);
    producer_thread.start(sampleProducer);
    consumer_thread.start(sampleConsumer);
    
    //TEST
    LCDqueue.call_every(5000, LCD_display);
    
    //TEST FOR SD CARD
    //SDmount_thread.start(SDmount);
    
    //TEST FOR WATCGDOG
    watchdog_thread.start(watchdog);
    
    //TEST FOR PRINTFQUEUE
    printf_thread.start(callback(&printQueue, &EventQueue::dispatch_forever));
    
   
    //Attach ISRs
    sample.attach(&sampleISR, sample_rate);  //Allow sampling to start  
    pc->attach(serialISR, Serial::RxIrq);
    
    //TEST FOR SD CARD MOUNT AND UNMOUNT
    usersw.rise(&userswRisingEdge);    
    
    //Flash to indicate goodness
    while(true) {
        //greenLED = !greenLED;
        //Thread::wait(500);    
    }
}

/*
FUNCITONS BELOW NEED MOVING?
*/

void sampleISR()
{
    producer_thread.signal_set(TAKE_SAMPLE);   
}
    
void serialISR()
{
    pc->attach(NULL, Serial::RxIrq);
    serialqueue.call(serialData);
}

void serialData()
{    
    static int i = 0;
    
    if (pc->readable())
    {
        cmdBuffer[i] = pc->getc();
        if (i != 29)
        {
            
            if (cmdBuffer[i] == '\b')
            {
                i = (i ? i-1 : 0);  
            }
            else if (cmdBuffer[i] == '\r')
            {
                cmdBuffer[i+1]==NULL;
                serialqueue.call(serialterm);
                i = 0;                                
            }
            else i++;
        }
        else
        {
            serialqueue.call(serialterm);
            i = 0;
        }
    }
    pc->attach(serialISR, Serial::RxIrq);
}


void sampleProducer()
{
    while(true)
    {
        //High priority thread 
        Thread::signal_wait(TAKE_SAMPLE);
        //wd_thread.signal_set(PROD_SIGNAL);
        //prod_stat = 0;        
        Nspaces = spaceAvailable.wait(0); //Non-blocking
        bufferLock.lock();
        producer_tout.attach(producer_toutISR, TOUT_TIME_DEF);
               
        //Update buffer     
         
        if ((newestIndex == oldestIndex) && (Nspaces==0))
        {
            //printQueue.call(printf, "oldest index being increased\n\r");
            oldestIndex = (oldestIndex+1) % BUFFERSIZE;     
        }
            
        newestIndex = (newestIndex+1) % BUFFERSIZE;  //CIRCULAR 
        /*     
        buffer[newestIndex].updatetemp(sensor.getTemperature());
        buffer[newestIndex].updatepress(sensor.getPressure());
        buffer[newestIndex].updatelight(adcIn.read());
        buffer[newestIndex].updateTime();
        */
        
        double temp_r = sensor.getTemperature();
        double press_r = sensor.getPressure();
        float light_r = adcIn.read();
        
        buffer[newestIndex].updatetemp(temp_r);
        buffer[newestIndex].updatepress(press_r);
        buffer[newestIndex].updatelight(light_r);
        buffer[newestIndex].updateTime();
               
        if (Nspaces != 0)
        {   
            Nspaces--;            
        } 
          
        samplesInBuffer.release();
             
        //Pass onto queues
        //LCDqueue.call(LCD_display,temp_r,press_r,light_r);
        //LCDqueue.call(LCD_display, &buffer[newestIndex]);
        
        if(logging)
        {
            /*
            printlock.lock();
            pc->printf("Sample placed in buffer at position %d\r\n", newestIndex);
            pc->printf("Number of spaces available in buffer:%d\r\n\n",Nspaces);
            printlock.unlock();  
            */
            printQueue.call(printf, "Sample placed in buffer at position %d\r\nNumber of spaces available in buffer:%d\r\n\n", newestIndex, Nspaces); 
        }
        
        bufferLock.unlock();
        producer_tout.detach();
    }
}

void sampleConsumer()
{
    while(true)
    {
        //static time_t seconds; //possibly move into if(sd_init)
        //write to the SD card from oldestindex up to newestIndex.
        
        Nsamples = samplesInBuffer.wait(); //Block if no samples to take - acquires
        
        bufferLock.lock(); //Moved to here from below to try and ensure timer is started only when the buffer can be used
        consumer_tout.attach(consumer_toutISR,TOUT_TIME_DEF);
        
        if (sd_init)
        {     
            /*
            char fileDate[30];
            timeLock.lock();
            seconds = time(NULL);
            timeData = localtime(&seconds);
            
            //set_time(mktime(timeData));
            
            strftime(fileDate, 30, "sd/log_%d_%m_%y.csv", timeData);
            timeLock.unlock();           
            
            fp = fopen(fileDate,"a"); //ISSUE
            if (fp == NULL)
            {
                printlock.lock();
                pc->printf("WARNING: FILE COULD NOT BE OPENED\r\n\n");
                sd_init = false;
                printlock.unlock();  
                samplesInBuffer.release();
            }
            else
            {
                //Nested locks probably a bad idea!
                //bufferLock.lock();

                SDlock.lock();             
                oldestIndex = (oldestIndex+1) % BUFFERSIZE;
                //fprintf(fp,"%s,%5.2f,%5.2f,%5.2f\r", buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight());           
                SDqueue.call(SDaddSample,buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight());
                SDlock.unlock();
                
                if(logging)
                {
                    printlock.lock();
                    pc->printf("Log file %s updated with sample from position %d in buffer\r\n",fileDate,oldestIndex);
                    pc->printf("newestIndex position %d\r\n",newestIndex);
                    pc->printf("oldestIndex position %d\r\n\n",oldestIndex);
                    printlock.unlock();  
                }
                
                //bufferLock.unlock();          
                fclose(fp); 
                */
                oldestIndex = (oldestIndex+1) % BUFFERSIZE;
                //fprintf(fp,"%s,%5.2f,%5.2f,%5.2f\r", buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight());           
                SDqueue.call(SDaddSample,buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight(), oldestIndex);                
            }      
        else
        {
            samplesInBuffer.release();   
        } 
        bufferLock.unlock();
        consumer_tout.detach();     
    }       
    
}

//TEST FOR MOUNTING AND UNMOUNTING SD CARD
//Interrupt service routine for handling the timeout


void userswTimeOutHandler() {
    userswTimeOut.detach();            //Stop the timeout counter firing

    //Which event does this follow?
    switch (userswState) {
    case EDGE_RISEN:    
        usersw.fall(&userswFallingEdge);  //Now wait for a falling edge
        break;
    case EDGE_FALLEN:
        usersw.rise(&userswRisingEdge);   //Now wait for a rising edge
        break;
    } //end switch 
}

//Interrupt service routine for a rising edge (press)
void userswRisingEdge() {
    usersw.rise(NULL);             //Disable detecting more rising edges
    userswState = EDGE_RISEN;      //Flag state
    userswTimeOut.attach(&userswTimeOutHandler, 0.2);    //Start timeout timer
}

//Interrupt service routive for SW1 falling edge (release)
void userswFallingEdge() {
    usersw.fall(NULL);                         //Disable this interrupt    
    //SDmount_thread.signal_set(SIGNAL_SD);
    SDqueue.call(SDmount);
    userswState = EDGE_FALLEN;                 //Flag state
    userswTimeOut.attach(&userswTimeOutHandler, 0.2);    //Start timeout counter - may want to increase this  
}

//TEST FOR WATCHDOG

//ISR
void producer_toutISR(void)
{
    threadstates |= PRODUCER;
}

void consumer_toutISR(void)
{
    threadstates |= CONSUMER;   
}

void serial_toutISR(void)
{
    threadstates |= SERIAL;   
}

void SD_toutISR(void)
{
    threadstates |= SD;   
}

void LCD_toutISR(void)
{
    threadstates |= LCD;   
}

void network_toutISR(void)
{
    threadstates |= NETWORK;   
}

void watchdog(void)
{
    while(true)
    {
        Thread::wait(10000);
 
        if(threadstates)
        {
            producer_thread.terminate();
            consumer_thread.terminate();
            serial_thread.terminate();
            SDqueue_thread.terminate();
            LCDqueue_thread.terminate();
            network_thread.terminate();
            printf_thread.terminate();
            
            pc->printf("THREAD PSW: 0x%x\n\r", threadstates);
            
            switch (threadstates)
            {
                case (PRODUCER) : 
                    pc->printf("PRODUCER THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("PRODUCER\nDEADLOCK");
                    break;
                
                case (CONSUMER) : 
                    pc->printf("CONSUMER THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("CONSUMER\nDEADLOCK");
                    break;
                
                case (SERIAL) : 
                    pc->printf("SERIAL THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("SERIAL\nDEADLOCK");
                    break;
                
                case (SD) : 
                    pc->printf("SD CARD THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("SD CARD\nDEADLOCK");
                    break;
                
                case (LCD) : 
                    pc->printf("LCD THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("LCD\nDEADLOCK");
                    break;
                
                case (NETWORK) : 
                    pc->printf("NETWORK THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("NETWORK\nDEADLOCK");
                    break;
                
                default:
                    pc->printf("MULTIPLE THREAD DEADLOCK\r\n\n");
                    lcd.cls();
                    lcd.printf("DEADLOCK");
                    break;
            }
        
            for (int i = 0;i<50;i++)
            {
                redLED = 1;
                wait(0.05);
                redLED = 0;
                wait(0.05);
            }
            NVIC_SystemReset();
        }       
        else if (logging) 
        {
            /*
            printlock.lock(); 
            pc->printf("WATCHDOG RAN WITH NO DEADLOCKED THREADS\r\n\n"); 
            printlock.unlock();
            */
            printQueue.call(printf,"WATCHDOG RAN WITH NO DEADLOCKED THREADS\r\n\n"); 
        } 
    }
}

void PLL_Config(void)
{
    

//*******************************************************************************
//*            PLL (clocked by HSI) used as System clock source                 *
//*                         By Stuart MacVeigh                                  *
//*******************************************************************************

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;  //enable power interface clock source
    PWR->CR |= PWR_CR_VOS;

    
        #define PLL_N   180         //SYSTEM CLOCK SPEED (FCY (MHz))
        #define HSI     16000000    //INTERAL OSC FREQUENCY
        
        #define PLL_M   (HSI/2000000)       //Fcy = Fxtal x PLL_N/(PLL_P x PLL_M)
        #define PLL_P   2
        #define PLL_Q   7
    // HCLK = SYSCLK / 1
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;        //CORE CLOCK = 180MHZ
    
    // PCLK2 = HCLK / 2
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV4;       //PERIPHERAL CLOCK 2 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ
    
    // PCLK1 = HCLK / 4
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;       //PERIPHERAL CLOCK 1 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ

    // Configure the main PLL
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);

    // Enable the main PLL
    RCC->CR |= RCC_CR_PLLON;

    // Wait till the main PLL is ready
    while(!(RCC->CR & RCC_CR_PLLRDY));
   
    // Configure Flash prefetch, Instruction cache, Data cache and wait state
    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

    // Select the main PLL as system clock source
    RCC->CFGR &=~ RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    // Wait till the main PLL is used as system clock source
    while ((RCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    
//******************************************************************************
//*            END PLL (CLOCKED BY HSI) SETUP CODE                             *
//******************************************************************************
    
}