ECE 4180 - Final Project Team / Mbed 2 deprecated WalkieTalkie

Dependencies:   mbed 4DGL-uLCD-SE mbed-rtos nRF24L01P

main.cpp

Committer:
drechtmann3
Date:
2018-04-29
Revision:
45:805f92c68d55
Parent:
44:a4f81588fcd5

File content as of revision 45:805f92c68d55:

#include "uLCD_4DGL.h"
#include "mbed.h"
#include "rtos.h"

#include "Microphone.h"
#include "Speaker.h"
#include "HUD.h"
#include "nRF24L01P.h"

#include "CircularBuf.h"
#include "CircularBuf.cpp" // Hack to get templates to work

// How many times larger the buffer should be
#define FIFO_BUFFER_SCALE  250
// How maybe bytes to send over RF
#define DATA_PACKET_SIZE   32
// How quickly to sample the mic / play the speaker
#define SAMPLE_PERIOD   1/8000.0


Serial pc(USBTX, USBRX);
DigitalOut myled1(LED1); // Mic data sent over RF
DigitalOut myled2(LED2); // Speaker data recieved over RF
DigitalOut myled3(LED3); // Sampled mic / played the speaker
DigitalOut myled4(LED4); // Heartbeat

Speaker spkr(p18);
Microphone mic(p16);
Mutex u;

uLCD_4DGL uLCD(p28, p27, p29);                      // serial tx, serial rx, reset pin;

nRF24L01P my_nrf24l01p(p5, p6, p7, p8, p9, p10);    // mosi, miso, sck, csn, ce, irq
CircularBuf<uint8_t> txbuff( FIFO_BUFFER_SCALE * DATA_PACKET_SIZE );
CircularBuf<uint8_t> rxbuff( FIFO_BUFFER_SCALE * DATA_PACKET_SIZE );
Ticker sampler; //10:41 am 4/20

InterruptIn button(p12); //changed DitialIn to InterruptIn at 5:54 4/18/18
BusIn channel(p21, p22, p23, p24, p25);

int rfFreq;
int dataRate;
unsigned long long rxAddr, txAddr;
int pipe = 0;
int channelNum = -1;

enum operatingMode {
    RECEIVE = 0,
    TRANSMIT
};

operatingMode mode;

// Cheap nonbranching min function
int min(int a, int b)
{
    return a * (int)(a <= b) + b * (int)(b < a);
}

// Sets the channel of the RF device based on which swtiches are flipped
// by changing RX/TX pipes
// TODO: Make sure we don't have to restart the device or anything to change this
void setChannel()
{
    int oldChannel = channelNum;
    //int oldPipe = pipe;
    //int width = 5;
    switch (channel) {
        case 0:      // Channel 0
            //rxAddr = txAddr = 0xC2C2C2C2C0;
            //pipe = NRF24L01P_PIPE_P0;
            channelNum = 0;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                u.lock();
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        case 1:      // Channel 1
            //rxAddr = txAddr = 0xC2C2C2C2C1;
            //pipe = NRF24L01P_PIPE_P1;
            channelNum = 1;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        case 2:      // Channel 2
            //rxAddr = txAddr = 0xC2C2C2C2C2;
            //pipe = NRF24L01P_PIPE_P2;
            channelNum = 2;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                u.lock();
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        case 4:      // Channel 3
            //rxAddr = txAddr = 0xC2C2C2C2C3;
            //pipe = NRF24L01P_PIPE_P3;
            channelNum = 3;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                u.lock();
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        case 8:      // Channel 4
            //rxAddr = txAddr = 0xC2C2C2C2C4;
            //pipe = NRF24L01P_PIPE_P4;
            channelNum = 4;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                u.lock();
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        case 16:     // Channel 5
            //rxAddr = txAddr = 0xC2C2C2C2C5;
            //pipe = NRF24L01P_PIPE_P5;
            channelNum = 5;
            if (channelNum != oldChannel) {
                //my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                //my_nrf24l01p.setTxAddress(txAddr, width);
                rfFreq = channelNum + NRF24L01P_MIN_RF_FREQUENCY;
                my_nrf24l01p.setRfFrequency(rfFreq);
                u.lock();
                uLCD.locate(0, 0);
                uLCD.printf("Freq: %d MHz", rfFreq);
                uLCD.locate(0, 2);
                uLCD.printf("Channel: %d ", channelNum);
                uLCD.locate(0, 10);
                u.unlock();
            }
            break;
        default:
            break;
    }

    //pc.printf("Pipe = %d\r\n", pipe);

    // TODO: Don't force it to the default RF frequency
    //channelNum = 2;

    //my_nrf24l01p.setRfFrequency(channelNum + NRF24L01P_MIN_RF_FREQUENCY);
}

// Callback interrupt from the button to shift into transmit mode
void enterTransmitMode()
{
    mode = TRANSMIT;
    txbuff.clear();
//   u.lock();
//    uLCD.locate(0, 10);
//   uLCD.printf("Mode:    Transmitting");
//     u.unlock();
}

// Callback interrupt from the button to shift into receive mode
void enterRecieveMode()
{
    mode = RECEIVE;
    rxbuff.clear();
    //    u.lock();
    //  uLCD.locate(0, 10);
//   uLCD.printf("Mode:    Receiving");
    // u.unlock();
}

// Called every SAMPLE_PERIOD ms to sample the mic or output data into the speaker
void sampleData()
{
    // Depending on the mode, only sample the mic or output data to the speaker
    if (mode == RECEIVE) {
        // Get speaker sample from buffer
        // If there is no data in the buffer, it will just output 0 to the write function
        uint8_t speakerSample = 0;
        rxbuff.pop(&speakerSample, 1);

        // Output into the actual speaker
        spkr.write(speakerSample);
    } else {
        // Get mic sample and place into buffer
        uint8_t micSample = mic.getData();
        txbuff.push(&micSample, 1);

        // Make sure the speaker is actually off
        spkr.turnOff();
    }

    // TODO: This will have to be removed later on once we actually crank up the sample rate
    myled3 = !myled3;
}

// Communicates to the other MBED using RF
void commThread()
{
    // We want this in it's own thread so we don't have to worry about the
    // timings screwing anything else up
    // It can't be in an interrupt because of that
    while (true) {
        // Change what we are sending based on what mode we are in
        if (mode == RECEIVE) {
            // Make sure something is there to read
            if (my_nrf24l01p.readable( NRF24L01P_PIPE_P0 )) {
                uint8_t spkrPacket[DATA_PACKET_SIZE];

                // Remove entire packet of data from the bus
                int numReceived =  my_nrf24l01p.read( NRF24L01P_PIPE_P0, (char*) spkrPacket, DATA_PACKET_SIZE );

                // Place into buffer to play speaker in another thread
                // Only place into the buffer the number of bytes received
                rxbuff.push(spkrPacket, min(DATA_PACKET_SIZE, numReceived));

                //pc.printf("Receiviing....\n\r");
                myled2 = !myled2;
            }
        } else { // mode == TRANSMIT
            if (txbuff.size() >= DATA_PACKET_SIZE) {
                uint8_t micPacket[DATA_PACKET_SIZE];

                // Pull an entire packet of data from the mic sample buffer
                int numPopped = txbuff.pop(micPacket, DATA_PACKET_SIZE);
                //   rxbuff.push(micPacket, DATA_PACKET_SIZE);

                // Send the entire buffer to the other device
                // TODO: We just assume that DATA_PACKET_SIZE bytes were popped, this may
                //       not be the case
                my_nrf24l01p.write( NRF24L01P_PIPE_P0, (char*) micPacket, DATA_PACKET_SIZE );

                myled1 = !myled1;
            }
        }

        //pc.printf("TX Size %d RX Size%d Mode %d\n\r", txbuff.size(), rxbuff.size(), mode);
        Thread::yield();
        //Thread::wait(10);
    }
}

// Displays the current info to the LCD display
/*void lcdThread()
{
    while (1) {
        uLCD.locate(0, 0);
        uLCD.printf("Freq: %d MHz", rfFreq);
        uLCD.locate(0, 2);
        uLCD.printf("Rate: %d kbps", dataRate);
        uLCD.locate(0, 4);
        uLCD.printf("Addr: 0x%010llX", txAddr);
        uLCD.locate(0, 6);
        //uLCD.printf("RX: 0x%010llX", rxAddr);
        uLCD.printf("Channel: %d", channelNum);
        uLCD.locate(0, 10);

        switch (mode) {
            case RECEIVE:
                uLCD.printf("Mode:    Receiving");
                break;
            case TRANSMIT:
                uLCD.line(0, 8, 127, 8, BLACK);
                uLCD.printf("Mode: Transmitting");
                break;
        }

        // Maybe add some graphics too idk
        Thread::wait(1000);
    }
}*/

int main()
{
    //Thread lcd;
    Thread comm;

    // Set up the nrf24l01p
    my_nrf24l01p.setAirDataRate(2000);  // 2Mbs
    rfFreq = my_nrf24l01p.getRfFrequency();
    dataRate = my_nrf24l01p.getAirDataRate();
    rxAddr = my_nrf24l01p.getRxAddress();
    txAddr = my_nrf24l01p.getTxAddress();

    my_nrf24l01p.setTransferSize(DATA_PACKET_SIZE);

    my_nrf24l01p.setReceiveMode();
    my_nrf24l01p.enable();

    pc.printf( "nRF24L01+ Frequency    : %d MHz\r\n",  rfFreq );
    pc.printf( "nRF24L01+ Output power : %d dBm\r\n",  my_nrf24l01p.getRfOutputPower() );
    pc.printf( "nRF24L01+ Data Rate    : %d kbps\r\n", my_nrf24l01p.getAirDataRate() );
    pc.printf( "nRF24L01+ TX Address   : 0x%010llX\r\n", txAddr );
    pc.printf( "nRF24L01+ RX Address   : 0x%010llX\r\n", rxAddr );

    pc.printf("Finished starting up....\n\r");

    mode = RECEIVE;

    // Initialize the uLCD
    uLCD.baudrate(3000000);
    uLCD.background_color(BLACK);

    // Spawn threads
    //lcd.start(lcdThread);
    comm.start(commThread);

    // Setup the button to enter transmit mode when pushed down
    // and recieve when release
    button.mode(PullUp);
    button.fall(&enterTransmitMode);
    button.rise(&enterRecieveMode);

    // Setup sampler to sample at a specific frequency
    sampler.attach(&sampleData, SAMPLE_PERIOD);

    // Heartbeat thread
    u.lock();
    uLCD.locate(0, 0);
    uLCD.printf("Freq: %d MHz", rfFreq);
    uLCD.locate(0, 2);
    uLCD.printf("Channel: %d", channelNum);
    uLCD.locate(0, 4);
    uLCD.printf("Addr: 0x%010llX", txAddr);
    uLCD.locate(0, 6);
    uLCD.printf("RX: 0x%010llX", rxAddr);
    uLCD.locate(0, 10);
    uLCD.printf("Mode: Receiving");
    u.unlock();
    int oldmode = -1;
    
    while (1) {
        myled4 = !myled4;
        setChannel(); // Poll the DIP switch and change channels accordingly
        if (mode == 0 && not(oldmode == mode)) {
            uLCD.locate(6, 10);
            uLCD.printf("Rx");
            oldmode = mode;
        } else if  (mode == 1 && not(oldmode == mode)) {
            uLCD.locate(6, 10);
            uLCD.printf("Tx");
            oldmode = mode;
        }
        Thread::wait(100);
    }
}