napoleon leoni / Mbed 2 deprecated DirectionalMicrophone

Dependencies:   C12832_lcd crossCorrelation mbed-rtos mbed

main.cpp

Committer:
nleoni
Date:
2014-03-26
Revision:
0:025037057a21

File content as of revision 0:025037057a21:

#include "mbed.h"
#include "rtos.h"
#include "C12832_lcd.h"
#include "stdint.h"
#include <string.h>
#include <math.h>
#include <stdio.h>

#define DEBUG


#define SAMPLINGPERIOD 60 //us, 20 us would correspond to a 50 kHz sampling rate
#define EVENTLENGTH 1000//number of sample to collect a full event
#define EVENTLOGSIZE 20 //Events are stored in this log, eventually read and cleared
#define TRIGGERHIGH 0xC000
#define TRIGGERLOW 0x4000
#define PRETRIGSAMPLES 20  //samples to keep prior to trigger time.
#define SAMPLEDELAY 20
#define BUFFER 20           //serial terminal input command buffer


//define signals
#define COMPARESIGNAL 0x01//use this signal to signal the onDAQ thread to check for a trigger.
#define PROCESSINGSIGNAL 0x10 //use this signal to start the processing thread

//There will be a thread checking on error conditions
//this Thread will print to a terminal causes of error conditions and the exit 
//the program
//signals related to error conditions
#define NULLPOINTER 0xE1


AnalogIn FLMic(p20),FRMic(p19);
AnalogOut FLMout(p18);
DigitalOut ISRcheck(p26);
DigitalOut circularCheck(p24);
LocalFileSystem local("local"); //use the MBED file system to store debug files

uint16_t FLMbuffer[EVENTLENGTH],FRMbuffer[EVENTLENGTH],flmLastValue,frmLastValue;
float eventLog[2][EVENTLOGSIZE]; //down the line make an event class, and have an array of events.
uint16_t *ptrflm,*ptrflmStart,*ptrfrm,*ptrfrmStart; //These pointers are used to implement a dual circular buffer architecture
int indexMax,delayMax;
int Max;

Ticker audioDAQ;

void acquireISR(void);//ISR routine for acquiring the microphone audio data
Thread *onDAQTrigger;
Thread *processingCrossCorr;
Serial pc(USBTX, USBRX);   //serial communication terminal

//define DirMic state type  
typedef enum {
    ACQUIRING,
    TRIGGERED,
    PROCESSING,
    IDLE            //state to enter for debugginr purposes    
} DicMicStateType;

DicMicStateType dicMicState;

/******************************************************************
*
*This 
*
*******************************************************************/
void readTerminal(void const *args){
    int tempLFM,tempRFM,i;
    char buffer[BUFFER];
    int filecounter;
    char *ptrChar;
    ptrChar=buffer;
    FILE *fp;
    char filename[16],outputstr[16];
    //Test pointers
    uint16_t testbuffer[10];
    pc.printf(">Enter a command: (a..arm acquisition; t..trigger acquisition; s..state; r..results)\n>");
    filecounter=0;
    while(1){
    //Note the choice of using getc instead of scanf to read the fortune cookie,
    //this is a non-blocking call and allows the rest of our threads to continue operating
    //only when a new character is typed this thread executes its body otherwise
    //it immediately yields to other threads.
        if( pc.readable() ){
            *ptrChar=pc.getc();
            pc.putc(*ptrChar);
            if((*ptrChar=='\n') || ((ptrChar-buffer)>=(BUFFER-1)) ){
                    if((ptrChar-buffer)>=(BUFFER-1)) *++ptrChar='\n';
                    *ptrChar='\0';
                    //Check the entered command
                    switch(buffer[0]){
                        case 'a': //arm command, to be used after a trigger event
                            dicMicState=ACQUIRING;
                            audioDAQ.attach_us(&acquireISR,200);
                           #ifdef DEBUG
                            pc.printf("State is %i\n",dicMicState);                         
                            #endif
                        break;
                        case 's': //check current state command
                        pc.printf("State is %i\n>",dicMicState); 
                        break;
                        case 'r': //check current state command
                        pc.printf("Last Correlation results: delay=%d\n>",delayMax); 
                        break;
                        case 'f': //pointer test command
                        fp=fopen("/local/out.txt", "w");
                        fprintf(fp, "Hello World!");
                        fclose(fp);
                        break;
                        case 'o': //output file
                        filecounter++;
                        sprintf(filename,"/local/data%d.txt",filecounter);
                        pc.printf("Data file:%s\n>",filename);
                        fp=fopen(filename, "w");  // Open filename on the local file system for writing
                        if(fp!=NULL){
                            for(i=0;i<EVENTLENGTH;i++){
                                tempLFM=(int)FLMbuffer[i]-0x8000;
                                tempRFM=(int)FRMbuffer[i]-0x8000;
                                sprintf(outputstr,"%d,%d%c",tempLFM,tempRFM,13);
                                pc.printf("%s",outputstr);
                                fprintf(fp,outputstr);
                            }//for i loop
                            fclose(fp);
                        } else {
                            pc.printf("Error Opening File\n>");
                        }//if fp!=null
  
                    }//end of switch
                    pc.printf(">Enter a command: (a..arm acquisition; t..trigger acquisition)\n>");
                    ptrChar=buffer;
            } else {
                ptrChar++;
            }//if ptrchar... check for buffer overflow
        }//if pc readable
        //A 100 ms wait seems like reasonable delay which allows operation of the remaining threads.
    Thread::wait(100);
    }//while(1)
}//thread function

//*****************************************************************************************
//Comparison thread
//This thread is called with a signal from the timer interrupt
//it checks whether a trigger level is exceeded and if so chanegs the state 
//to storage
void onDAQ(void const *args){
int sampleCounter=0;
    while(1){
        Thread::signal_wait(COMPARESIGNAL);
        //Here we check if signal exceeded trigger, currently only triggering on one mic
        switch(dicMicState){
        case ACQUIRING:
            if( ( (flmLastValue) > TRIGGERHIGH ) || ( (flmLastValue) < TRIGGERLOW ) ){//signal exceeded trigger

                dicMicState=TRIGGERED;
                #ifdef DEBUG
                pc.printf("State is %i\n>",dicMicState);
                #endif
            }
            sampleCounter=0;
            break;
        case TRIGGERED:
            if(sampleCounter==0) pc.printf("Entered countdown trigger phase\n>");
            sampleCounter++;
            if(sampleCounter>(EVENTLENGTH-PRETRIGSAMPLES)){
            //if(sampleCounter>100){
                dicMicState=PROCESSING; //switching states should be done prior to detaching the interrup...   
                #ifdef DEBUG
                pc.printf("State is %i\n>",dicMicState);
                Thread::wait(10);
                #endif
                processingCrossCorr->signal_set(PROCESSINGSIGNAL);           
                audioDAQ.detach();//detach interrupt, this allows gathering data after the trigger yet leaving PRETRIGSAMPLES before trigger time   
            }
        break;
        }
    }
}


//Processing thread 
void crossCorrelationThread(void const *args){
int i,j,k,ndelays,delay;

ndelays=2*SAMPLEDELAY+1;
int correlationArray[ndelays],tempLFM,tempRFM;
    //This thread waits for the processing signal and then perform one correlation calculation
    //This very simple cross correlation will for the time being have no Thread::wait....as it runs alone
    while(1){
        Thread::signal_wait(PROCESSINGSIGNAL); 
        Max=0;  //Store max computed value of correlation
        indexMax=0;
        delayMax=2*SAMPLEDELAY;//safe value to know if it did not run
        for(j=0;j<ndelays;j++){
            correlationArray[j]=0;
            delay=-SAMPLEDELAY+j;
            for(i=0;i<EVENTLENGTH;i++){
                //compute k
                    k=i+delay;
                    if(k<0) k=EVENTLENGTH+k; 
                    if(k>(EVENTLENGTH-1)) k=k-EVENTLENGTH;
                    tempLFM=(int)FLMbuffer[i]-0x8000;
                    tempRFM=(int)FRMbuffer[k]-0x8000;
                    correlationArray[j]+=tempLFM*tempRFM;
                }  //end of for i
            if(correlationArray[j]>Max){ 
                Max=correlationArray[j];
                indexMax=j;
                delayMax=delay;
            }
            #ifdef DEBUG//debugging printout of calculated correlation values
            pc.printf("Correlation[%i]=%.0f\n>",j,(double)correlationArray[j]);
            pc.printf("Max=%.0f\n>",(double)Max);
            pc.printf("delayMax=%.0f\n>",(double)delayMax);
            #endif
        }//end of for j loop
        pc.printf("Correlation results: delay=%i\n>",delayMax); 
        #ifdef DEBUG
        dicMicState=IDLE;//processing is done set to idle until manually armed
        #else
        dicMicState=ACQUIRING;  //the systems goes back to aqcuiring after finished processing
        audioDAQ.attach_us(&acquireISR,SAMPLINGPERIOD);
        #endif
    }//end of while loop for thread
}


int main() {
    pc.printf("Directional Microphone\n");
    audioDAQ.attach_us(&acquireISR,SAMPLINGPERIOD);
    ptrflm=FLMbuffer;
    ptrfrm=FRMbuffer;
    dicMicState=IDLE;
    #ifdef DEBUG
    pc.printf("State is %i\n",dicMicState);
    #endif
    Thread thread(onDAQ);
    onDAQTrigger=&thread;
    Thread thread2(crossCorrelationThread);
    processingCrossCorr=&thread2;
    Thread thread3(readTerminal);
    
    while(1) {
        
    }
}

void acquireISR(void){
    if(dicMicState==ACQUIRING || dicMicState==TRIGGERED ){
        #ifdef DEBUG
        ISRcheck=1;
        #endif
        if(ptrflm && ptrfrm){//check if pointer not null
        //Note that two calls to read_u16 take overall 50 us!!!
            *ptrflm=FLMic.read_u16();
            flmLastValue=*ptrflm;
            #ifdef DEBUG
            FLMout.write_u16(*ptrflm);
            #endif 
            *ptrfrm=FRMic.read_u16();
            frmLastValue=*ptrfrm;
            if( ((ptrflm-FLMbuffer)) >= (EVENTLENGTH-1) ){
                    ptrflm=FLMbuffer;//here we should wrap the pointer around the eventlength
                    ptrfrm=FRMbuffer;
                    #ifdef DEBUG//Confirm that pointer wraps to beginning of array
                                //Test passed!
                    circularCheck=!circularCheck;
                    #endif
                    } else {
                    ptrflm++;  
                    ptrfrm++;
               }
        } else {
            onDAQTrigger->signal_set(NULLPOINTER);
            exit(1);
        }
        onDAQTrigger->signal_set(COMPARESIGNAL);
        #ifdef DEBUG
        ISRcheck=0;
        #endif
    }
}