ECE 4180 - Final Project Team / Mbed 2 deprecated WalkieTalkie

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

main.cpp

Committer:
jacksacane
Date:
2018-04-29
Revision:
41:9ed924a1f2e0
Parent:
34:d73e95bbdbed
Parent:
40:4f7d95c68d29
Child:
44:a4f81588fcd5

File content as of revision 41:9ed924a1f2e0:

#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);

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;

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 oldPipe = pipe;
    int width = 5;
    switch (channel) {
        case 0:      // Channel 0
            rxAddr = txAddr = 0xC2C2C2C2C0;
            pipe = NRF24L01P_PIPE_P0;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            break;
        case 1:      // Channel 1
            rxAddr = txAddr = 0xC2C2C2C2C1;
            pipe = NRF24L01P_PIPE_P1;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            break;
        case 2:      // Channel 2
            rxAddr = txAddr = 0xC2C2C2C2C2;
            pipe = NRF24L01P_PIPE_P2;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            break;
        case 4:      // Channel 3
            rxAddr = txAddr = 0xC2C2C2C2C3;
            pipe = NRF24L01P_PIPE_P3;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            break;
        case 8:      // Channel 4
            rxAddr = txAddr = 0xC2C2C2C2C4;
            pipe = NRF24L01P_PIPE_P4;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            break;
        case 16:     // Channel 5
            rxAddr = txAddr = 0xC2C2C2C2C5;
            pipe = NRF24L01P_PIPE_P5;
            if (pipe != oldPipe) {
                my_nrf24l01p.setRxAddress(rxAddr, width, pipe);
                my_nrf24l01p.setTxAddress(txAddr, width);
            }
            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();
}

// Callback interrupt from the button to shift into receive mode
void enterRecieveMode() {
    mode = RECEIVE;
    rxbuff.clear();
}

// 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("TX: 0x%010llX", txAddr);
        uLCD.locate(0, 6);
        uLCD.printf("RX: 0x%010llX", rxAddr);
        uLCD.locate(0, 8);
        
        switch (mode) {
            case RECEIVE:
                uLCD.printf("Mode:    Receiving");
                break;
            case TRANSMIT:
                uLCD.printf("Mode: Transmitting");
                break;
        }
        
        // Maybe add some graphics too idk
        Thread::wait(500);
    }
}

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
    while (1) {
        myled4 = !myled4;
        setChannel(); // Poll the DIP switch and change channels accordingly
        Thread::wait(100);
    }
}