8 years, 5 months ago.

How can i 'relocate' serial functions to a new .cpp and still use them from within the main?

Hello kind Sirs,

It has been a long time since I tried my hand at coding and I am moving from C to C++. Consequently I am having a little trouble separating and passing information between my functions if they are declared in separate cpp files. I understand that it is likely due to my poor understanding of how classes and other OO features work, any help would be much appreciated.

Anyway, here is the gig... I have a main.cpp which has 4 functions (plus main) and the purpose is to create a serial object which allows the user to type and receive any number of characters (not exceeding the buffer). I managed to do this when all of the functions reside within the main.

here is the code for this:

main.cpp

#include "mbed.h"
// Example that prints to the screen and recieves input string from the PC via UART
// use SPRINTF(tx_line,'message') to input a string to the buffer, send line function then sends the buffer over UART
// readline will wait (for interrupts) until enter has been input, then it copys it to 'rx_line'.

Serial device(USBTX, USBRX);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
 
 
void Tx_interrupt();            // prototypes
void Rx_interrupt();
void send_line();
void read_line();
 

const int buffer_size = 255;    // Circular buffers for serial TX and RX data - used by interrupt routines
char tx_buffer[buffer_size+1];  // Circular buffer pointers
char rx_buffer[buffer_size+1];

volatile int tx_in=0;           // volatile makes read-modify-write atomic 
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;

char tx_line[80];               // Line buffers for sprintf and sscanf
char rx_line[80];
 
 
int main() {
    device.baud(9600);
    device.attach(&Rx_interrupt, Serial::RxIrq);    // Setup a serial interrupt function to receive data
    device.attach(&Tx_interrupt, Serial::TxIrq);    // Setup a serial interrupt function to transmit data
 
    while (1) 
    {
        sprintf(tx_line,"This text is copied into txline \n\r");    //Txline is used by 'send line' 
        send_line();                                                // Copy tx line buffer to large tx buffer for tx interrupt routine
        read_line();                                                // Read line filles the RXBuffer (upto an enter) and copies to rx line
        device.printf("\n\r '%s' \n\r ",rx_line);
    }
}

 

void read_line() // Read a line from the large rx buffer from rx interrupt routine
{
    int i = 0;
    NVIC_DisableIRQ(UART1_IRQn);                // Start Critical Section - don't interrupt while changing global buffer variables
    while ((i==0) || (rx_line[i-1] != 0x0d))    // Loop reading rx buffer characters until end of line character 
    {
        if (rx_in == rx_out)                    // Wait if buffer empty
        {
            NVIC_EnableIRQ(UART1_IRQn);         // End Critical Section - need to allow rx interrupt to get new characters for buffer
            while (rx_in == rx_out) 
            {
            }

            NVIC_DisableIRQ(UART1_IRQn);        // Start Critical Section - don't interrupt while changing global buffer variables
        }
        rx_line[i] = rx_buffer[rx_out];
        i++;
        rx_out = (rx_out + 1); //% buffer_size;
    }
    NVIC_EnableIRQ(UART1_IRQn);                 // End Critical Section
    rx_line[i-1] = 0;
    return;
}
 
 

void Rx_interrupt() 
{
    led1=1;

    while ((device.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) // Loop just in case more than one character is in UART's receive FIFO buffer,Stop if buffer full
    {
        rx_buffer[rx_in] = device.getc();
        device.putc(rx_buffer[rx_in]);
        rx_in = (rx_in + 1); //% buffer_size;
    }
    led1=0;

    return;
}
 
 

void send_line() // Copy tx line buffer to large tx buffer for tx interrupt routine
{
    int i = 0;
    char temp_char;
    bool empty;

    NVIC_DisableIRQ(UART1_IRQn);                    // Start Critical Section - don't interrupt while changing global buffer variables
    empty = (tx_in == tx_out);
    while ((i==0) || (tx_line[i-1] != 0x0d))        // do  atleast once and while carage return is not detected) Wait if buffer full
    {
        if (((tx_in + 1) % buffer_size) == tx_out) // End Critical Section - need to let interrupt routine empty buffer by sending
        {
            NVIC_EnableIRQ(UART1_IRQn);
            while (((tx_in + 1) % buffer_size) == tx_out) 
            {
            
            }
            NVIC_DisableIRQ(UART1_IRQn);            // Start Critical Section - don't interrupt while changing global buffer variables
        }
        tx_buffer[tx_in] = tx_line[i];              //copy the characters from txline to tx buffer
        i++;                                        // increment line counter
        tx_in = (tx_in + 1) % buffer_size;          // increment buffer counter
    }
    if (device.writeable() && (empty)) 
    {
        temp_char = tx_buffer[tx_out];              //take current character into a temp
        tx_out = (tx_out + 1) % buffer_size;        //increment 'out' pointer
        device.putc(temp_char);                     //send character
    }
    NVIC_EnableIRQ(UART1_IRQn); // End Critical Section
    return;
}
 
 
 void Tx_interrupt() {
    led2=1;

    while ((device.writeable()) && (tx_in != tx_out)) // Loop to fill more than one character in UART's transmit FIFO buffer,Stop if buffer empty
    {
        device.putc(tx_buffer[tx_out]);
        tx_out = (tx_out + 1) % buffer_size;
    }
    led2=0;
    return;
}
 

However, I have tried to move all of the serial functions to a separate cpp and things are getting confusing. How do I create an instance of serial in the main and then read/write/use/manipulate from within another function inside a different CPP file?

Essentially, how do I declare external functions to take a serial object (or a pointer to) created in the main.

Thanks

2 Answers

8 years, 5 months ago.

There are no classes or objects involved in that code which means this is really just c code rather than c++, you can do it exactly the same way in c++ as you would in c.

Create two new files, serial.h and serial.cpp

serial.h contains the function prototypes e.g.

void Tx_interrupt();            // prototypes
void Rx_interrupt();
void send_line();
void read_line();

And then in serial.cpp you start with #include "Serial.h" and the rest of your code for the serial port.

In main.cpp just include the seril.h file at the start and those functions will be available to you but all of their internal workings will be hidden.

The c++ way would be to define a class that inherited Serial and added the extra functionality required to the base class. You'd split the files in much the same way but the way you'd access things would be a little different. If you only need one serial port then the way you have it works fine, the c++ method would be cleaner if you wanted to have multiple serial ports with the same added functionality.

Accepted Answer
8 years, 5 months ago.

Andy's option is generally the best, however as alternative you can also use 'extern'.

In your other .cpp file just define:

extern Serial device;

And you can use it also.

Yep, all working now simply by declaring the object external ; ) Thanks Guys

posted by Jonathan Storey 05 Oct 2015