ReSpeaker DSP V02

Dependencies:   mbed MbedJSONValue

main.cpp

Committer:
Arkadi
Date:
2019-06-20
Revision:
14:8a4699aa69b5
Parent:
13:c0a13a99905e

File content as of revision 14:8a4699aa69b5:

////////////////////////////////////////
//      Tau_ReSpeaker_DSP V02         //
//  Arkadiraf@gmail.com - 08/06/2019  //
////////////////////////////////////////
/*
 Json Format: json:{"name":"dsp","mode":"off"}\r\n
*/



/*
   Board : Nucleo STM32F446RE
   Power Source : DC-DC 5V Regulator E5V Jumper
*/

/*
    Pinout:
    PC - Serial 2
    PA_2 (Tx) --> STLINK
    PA_3 (Rx) --> STLINK

    Switch - Serial 3
    PC_10 (Tx) --> SW_Rx
    PC_11 (Rx) --> SW_Tx

    Digital output
    PA_5 --> led (DigitalOut)
    PA_10 --> DSP_Trigger

    Digital Input
    PC_13 --> BTN (Blue)

    PA_6  --> Toggle Pin (Loop Freq D12)

    Analog Input
    PA_0 --> SIG_IN_DSP  (A0)

    Analog Output
    PA_4 --> SIG_OUT_DSP (A2)

*/

///////////////
// Libraries //
///////////////
#include "mbed.h"
#include "MbedJSONValue.h"
#include "chirp.h"
///////////////
// #defines  //
///////////////

//#define TOGGLE_IO_MODE  // loop frequency indicator

// UART debug modes:
//#define DEBUG_MOD1  // json packet recognise
//#define DEBUG_MOD2   // json parse
//#define DEBUG_MOD3   // dsp handler
//#define DEBUG_MOD10  // responsivity msges to gui

// PI variable
#define PI_DOUBLE (3.141592653589793238462)
#define PI_FLOAT  (3.14159f)

// json commad
#define MSG_BUFFER_SIZE 1024
#define HEADER_SIZE 5
#define FOOTER_SIZE 2

// Frequency counter
#define TICKS2TOGGLE 1000000

/////////////
// Objects //
/////////////
// json
MbedJSONValue guiCmd;

// uart
Serial pc(USBTX, USBRX);

// uart switch_dsp
Serial switch_dsp(PC_10, PC_11);

// digital
DigitalIn user_button(PC_13);
DigitalOut dsp_trigger(PA_10);// D2
DigitalOut led(PA_5);       // D13
DigitalOut mytoggle(PA_6);  // D12

// analog / define to init at mbed initialization. work directly with registers
AnalogOut dsp_output(PA_4);
AnalogIn dsp_input(PA_0);


// ADC/DAC declarations
ADC_HandleTypeDef hadc1;
DAC_HandleTypeDef hdac1;

///////////////
// variables //
///////////////

// Frequency counter
uint32_t toggleCounter = 0;
// toogle pin state
bool toggleCounterState = 0;
// toogle pin state
bool toggelState=0;

// json buffer
char json[MSG_BUFFER_SIZE];

// packet variables
struct packetMSG_struct {
    // recieve message variables
    uint8_t header[HEADER_SIZE];
    uint8_t footer[FOOTER_SIZE];
    uint8_t syncIndex; // sync index for header / footer
    uint8_t syncFlag; // 0 - waiting for header, 1 -  waiting for footer, 2 - verify footer, 3 - finish footer send to parser, flash buffer
    // buffer
    uint16_t bufferIndex; // buffer index
    uint8_t buffer[MSG_BUFFER_SIZE];
} ;
packetMSG_struct packetMSG;


// Dac Register for direct method of setting DAC value`s
__IO uint32_t Dac_Reg = 0;

// create function pointer
typedef void(*functionPtr)(void);
functionPtr FilterFunction;

// alternative functuin selection (faster mcu process)
volatile uint8_t operationMode = 1;
// 0 -  off
// 1 -  passthrough - no filter
// 2 -  highpass    - High Pass filter
// 3 -  hpf_trig    - High Pass filter + Trigger mode
// 4 -  gains_trig  - highpass filter + trigger mode + Gains vector

///////////////
// Functions //
///////////////

// init functions header //hadc1 needs to be defined preiod #incude
#include "adc_init.h" // initialize adc/dac directly for continious sample
#include "filters.h"

// nop operation
inline void NOP()
{
    __ASM volatile ("nop");    // one tick operation, Use to adjust frequency by slowing down the proccess
}

// Serial Event function
void rxCallback(void);

// initialize packet struct
void initPacket(void);

// Packet Parser
void parsePacket(void);

// DSP Packet Handler
void dspPacket(void);

// DSP Param Packet Handler
void dspParamPacket(void);

// DSP Filter Packet Handler
void dspFilterPacket(void);

// DSP Play Packet Handler
void dspPlayPacket(void);

// initialize DSP
void initDSP(void);

////////////////////////
//  Main Code Setup : //
////////////////////////
int main()
{
    // init packet:
    initPacket();

    // initialize DSP
    initDSP();

    pc.baud(57600);
    switch_dsp.baud(57600);


    // pc is used for debbuging, in  application mode the commands are from the switch_dsp.
    // attach serial event interrupt
    pc.attach(&rxCallback, Serial::RxIrq);

    // attach serial event interrupt
    switch_dsp.attach(&rxCallback, Serial::RxIrq);

#ifdef DEBUG_MOD1
    pc.printf("ReSpeaker Test \r\n");
#endif

    ///////////////////////
    //  Main Code Loop : //
    ///////////////////////
    while(1) {
        // run selected filter
        if (operationMode == 0) {
            offMode();
        } else if (operationMode == 1) {
            passthrough();
        } else if (operationMode == 2) {
            highpass();
        } else if (operationMode == 3) {
            highpassTrig();
        } else if (operationMode == 4) {
            GainsTrig();    
        }
        // more elegant but much slower option:
        //FilterFunction();
#ifdef TOGGLE_IO_MODE
        // toggle pin, Loop frequency indicator
        toggelState=!toggelState;
        mytoggle.write(toggelState);
#endif
        // Frequency counter
        toggleCounter++;
        if (toggleCounter == TICKS2TOGGLE) {
            toggleCounter=0;
            toggleCounterState = !toggleCounterState;
            dsp_trigger.write(toggleCounterState);
        }
    } // end loop
} // end main

///////////////
// Functions //
///////////////

// initialize DSP
void initDSP(void)
{
    // init dac
    ADC1_Init();
    DAC1_Init();

    HAL_ADC_Start(&hadc1);
    HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

    // define Dac Register for direct method of setting DAC value`s
    Dac_Reg = (uint32_t) (hdac1.Instance);
    Dac_Reg += __HAL_DHR12R1_ALIGNEMENT(DAC_ALIGN_12B_R);

    // intialize filter function pointer
    FilterFunction = offMode;//highpass_filter;
    operationMode = 0 ;
}

// Serial Event function
void rxCallback(void)
{
    while ((pc.readable()) || (switch_dsp.readable())) {
        // read icoming
        uint8_t in_byte=0;
        //led = !led;
        if (pc.readable()) {
            in_byte = pc.getc();
        } else if (switch_dsp.readable()) {
            in_byte = switch_dsp.getc();
        }
#ifdef DEBUG_MOD1
        pc.putc(in_byte);
#endif
        // detect start message , end message
        switch (packetMSG.syncFlag) {
                // waiting for header
            case 0: {
                if (packetMSG.header[packetMSG.syncIndex] == in_byte) {
                    packetMSG.syncIndex++;
                    if (packetMSG.syncIndex == HEADER_SIZE) { // finish header SYNC
                        packetMSG.syncFlag = 1; // start collecting data, wait for footer
                        packetMSG.bufferIndex = 0;
                        packetMSG.syncIndex=0;
                    }
                } else { // reinit sync
                    packetMSG.syncIndex=0;
                }
                //pc.printf("case 0 , %d  \r\n",packetMSG.syncIndex);
                break;
            }
            // waiting for footer
            case 1: {
                // add byte to buffer
                packetMSG.buffer[packetMSG.bufferIndex] = in_byte;
                packetMSG.bufferIndex++;
                if (packetMSG.bufferIndex >= MSG_BUFFER_SIZE) { // buffer overflow
                    // reset buffer
                    packetMSG.bufferIndex = 0;
                    packetMSG.syncIndex = 0;
                    packetMSG.syncFlag = 0;
                } else if (packetMSG.footer[packetMSG.syncIndex] == in_byte) { // footer char recieved
                    packetMSG.syncIndex++;
                    packetMSG.syncFlag=2; // move to verify footer
                }
                //pc.printf("case 2 , %d  \r\n",packetMSG.syncIndex);
                break;
            }
            // verify footer
            case 2: {
                // add byte to buffer
                packetMSG.buffer[packetMSG.bufferIndex] = in_byte;
                packetMSG.bufferIndex++;
                if (packetMSG.bufferIndex >= MSG_BUFFER_SIZE) { // buffer overflow
                    // reset buffer
                    packetMSG.bufferIndex = 0;
                    packetMSG.syncIndex = 0;
                    packetMSG.syncFlag = 0;
                } else if (packetMSG.footer[packetMSG.syncIndex] == in_byte) { // footer char recieved
                    packetMSG.syncIndex++;
                    if (packetMSG.syncIndex == FOOTER_SIZE) { // finish footer SYNC
                        packetMSG.syncFlag = 3;
                        // copy packet to json buffer
                        memcpy (&json, &packetMSG.buffer, packetMSG.bufferIndex);
                        json[packetMSG.bufferIndex]=NULL; // end with NULL to indicate end of string
                        // copy packet to json buffer with sprintf
                        //sprintf(json, "%.*s", packetMSG.bufferIndex, packetMSG.buffer );
                        // send msg to parse.
                        parsePacket();
                        // reset buffer
                        packetMSG.bufferIndex = 0;
                        packetMSG.syncIndex = 0;
                        packetMSG.syncFlag = 0;
                    }
                } else { // footer broke restart wait for footer
                    packetMSG.syncFlag=1;
                    // verify that it didnt broke on first footer char
                    if (packetMSG.footer[0] == in_byte) {
                        packetMSG.syncIndex=1;
                    } else {
                        packetMSG.syncIndex=0;
                    }
                }
                break;
            }
            default: {
                pc.printf("Sonmething went wrong \r\n");
                break;
            }
        } // end switch
    }// end uart readable
} // end rxCallback

// initialize packet struct
void initPacket(void)
{
    // init variables to default:
    packetMSG.header[0] = 'j';
    packetMSG.header[1] = 's';
    packetMSG.header[2] = 'o';
    packetMSG.header[3] = 'n';
    packetMSG.header[4] = ':';

    packetMSG.footer[0]= 13; // /r
    packetMSG.footer[1]= 10; // /n

    packetMSG.syncIndex=0; // sync index for header / footer
    packetMSG.syncFlag=0; // 0 - waiting for header, 1 -  waiting for footer, 2 - verify footer, 3 - finish footer send to parser, flash buffer
    packetMSG.bufferIndex=0; // buffer index
}// end init Packet struct



// Packet Parser
void parsePacket(void)
{
    string targetName;
#ifdef DEBUG_MOD2
    // write buffer to screen
    //pc.printf("%d, %.*s", packetMSG.bufferIndex ,packetMSG.bufferIndex, packetMSG.buffer );
    pc.printf("%s", json);
#endif

    // GUI message format Switch: {"name":"switch","mic":0, "spk": [0,1,0,0,0]}
    parse(guiCmd, json);

    // get target:
    targetName = guiCmd["name"].get<string>(); // switch / dsp

#ifdef DEBUG_MOD2
    // send parsed values
    pc.printf("targetName: %s \r\n", targetName.c_str());
#endif

    // select handler based on target mcu
    if (targetName == "dsp") {
        dspPacket();
    } else if (targetName == "dspParam") {
        dspParamPacket();
    } else if (targetName == "dspFilter") {
        dspFilterPacket();
    } else if (targetName == "dspPlay") {
        dspPlayPacket();
    } else {
#ifdef DEBUG_MOD2
        // unrecognised target
        pc.printf("unrecognised target: %s \r\n", targetName.c_str());
#endif
    }
    // led blink
    led = !led;
}// end parse

            
// DSP Packet Handler
void dspPacket(void)
{
    string modeType;
    // get operation mode
    modeType = guiCmd["mode"].get<string>();

#ifdef DEBUG_MOD10
    // send parsed values
    pc.printf("mode: %s\r\n", modeType.c_str());
    //switch_dsp.printf("mode: %s\r\n", modeType.c_str());
#endif
    // selected operation mode
    if ( modeType == "off" ) {
        FilterFunction = offMode;
        operationMode = 0 ;
    } else if( modeType == "passthrough" ) {
        FilterFunction = passthrough;
        operationMode = 1 ;
    } else if( modeType == "highpass" ) {
        FilterFunction = highpass;
        operationMode = 2 ;
    } else if( modeType == "hpf_trig" ) {
        FilterFunction = highpassTrig;
        operationMode = 3 ;
    } else if( modeType == "gain_trig" ) {
        FilterFunction = GainsTrig;
        operationMode = 4 ;
    } else {
        switch_dsp.printf("undefined mode %s \r\n", modeType.c_str());
        FilterFunction = offMode;
        operationMode = 0 ;
    }
    // succesfull parse
    switch_dsp.printf("{\"Ack\":\"dsp\",\"mode\":\"%s\"}\r\n",modeType.c_str());
}// end dspPacket
// DSP Param Packet Handler
void dspParamPacket(void)
{
    // get values.
    signalGain      = ((float)guiCmd["gain"].get<int>())/1000; // issue in parsing doubles when the number is round
    trigTresh       = ((float)guiCmd["trigTresh"].get<int>()) / 100.0f;
    trigDelaySet    = (uint32_t)guiCmd["trigPass"].get<int>();
    trigPause       = (uint32_t)guiCmd["trigPause"].get<int>();

    trigDelay = trigDelaySet;
#ifdef DEBUG_MOD10
    // send parsed values
    pc.printf("SignalGain: %.3f , trigTresh: %.3f , trigDelaySet %d , trigPause: %d\r\n", signalGain , trigTresh , trigDelaySet , trigPause);
#endif
    // succesfull parse
    switch_dsp.printf("{\"Ack\":\"dspParam\",\"SignalGain\":%.3f,\"trigTresh\":%.3f,\"trigDelaySet\":%d,\"trigPause\":%d}\r\n", signalGain , trigTresh , trigDelaySet , trigPause);
} // end dspParamPacket

// DSP Filter Packet Handler
void dspFilterPacket(void)
{
    // get values.
    FilterSections  = (guiCmd["Sections"].get<int>());
    Gscale          = ((float)(guiCmd["Gscale"].get<int>()))/10000.0f; // issue in parsing doubles

    // get SOSMat
    for (int jj=0 ; jj < FilterSections ; jj++) {
        for (int ii=0 ; ii < 6 ; ii++) {
            SOSMat[jj][ii] = ((float)guiCmd["SOSMat"][ii+jj*6].get<int>())/10000.0f;
        }
    }
#ifdef DEBUG_MOD10
    // send parsed values
    pc.printf("FilterSections: %d , Gscale: %.3f\r\n", FilterSections , Gscale);
    pc.printf("SOSMat \r\n");
    for (int jj=0 ; jj < FilterSections ; jj++) {
        pc.printf("%.3f , %.3f , %.3f , %.3f , %.3f , %.3f \r\n",SOSMat[jj][0] ,SOSMat[jj][1],SOSMat[jj][2],SOSMat[jj][3] ,SOSMat[jj][4] ,SOSMat[jj][5]);
    }
#endif
    // succesfull parse
    switch_dsp.printf("{\"Ack\":\"dspFilter\",\"FilterSections\":%d,\"Gscale\":%.3f}\r\n", FilterSections , Gscale);
} // end dspFilterPacket

// DSP Play Packet Handler
void dspPlayPacket(void)
{
    // get values.
    float playGain      = ((float)guiCmd["gain"].get<int>())/1000; // issue in parsing doubles when the number is round
    uint32_t playFile       = (uint32_t)guiCmd["file"].get<int>(); // file to play

    // succesfull parse
    switch_dsp.printf("{\"Ack\":\"dspPlay\",\"file\":%d,\"gain\":%.3f}\r\n", playFile, playGain);
            //////////////////////////////////////////////////////////////////
            // Temp mode - need to update file selection ,  gain settings   //
            //////////////////////////////////////////////////////////////////
            __disable_irq();    // Disable Interrupts
            // generate chirp out
            for (int ii=0; ii<NUM_SAMPLES; ii++) {
                // toogle io for loop frequency
                toggelState=!toggelState;
                mytoggle.write(toggelState);
                // generate delay for 1MHz Sample rate
                for (int jj=0; jj<31; jj++) {
                    NOP();
                }
                // micro nops :)
                NOP();
                NOP();
                NOP();
                NOP();
                NOP();
                NOP();
                NOP();
                // Output value using DAC
                // HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, ADCValueOut);
                *(__IO uint32_t *) Dac_Reg = chirpData[ii];
            }
            // Output value using DAC
            // HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, ADCValueOut);
            *(__IO uint32_t *) Dac_Reg = (uint16_t)(4095/2);
            __enable_irq();     // Enable Interrupts
            
            // Option to reset play mode after file has been played
            //operationMode = 0;
} // end dspPlayPacket