1

Please take a look at following example (I have Java background):

const char* BT_ADDRESS = "abcd,ef,ghijkl";

void bar(const char* string) {
  ...
}

void foo() {
   bar("AT+BIND=" + BT_ADDRESS);
   bar("AT+LINK=" + BT_ADDRESS);
}

How to achieve this with "Arduino-C++" so BT_ADDRESS only has to be entered at one location?

  • That depends on what print does. – Majenko Oct 12 '15 at 20:14
-1

Get rid of strange print() and use standard stdout, fprintf() and % format tokens.

#include <stdio.h>
#include <Stream.h>

// printf to file support http://arduino.cc/playground/Main/Printf  
// we need fundamental FILE definitions and printf declarations
// apparently it eats 1k FLASH by saves to much copy&paste and hopefully even FLASH 

// create a output function
// This works because Serial.write, although of
// type virtual, already exists.
static int stream_putchar (char c, FILE *stream) {
    ((Stream*)(stream->udata))->write(c);
    return 0;
}

void SetupFileStream(FILE* file, Print* stream) {
    fdev_setup_stream(file, stream_putchar, NULL, _FDEV_SETUP_WRITE);
    file->udata = stream;
}

#ifdef UDRE0
// non interrupt transmit function
static int uart_putchar (char c, FILE *stream) {
    volatile byte *ucsrna = (byte*)(stream->udata);
    while ( !bitRead( ucsrna[0], UDRE0) ) {;}  // wait for transmit buffer is empty
    ucsrna[&UDR0-&UCSR0A] = c;
    return 0;
}

void SetupUartStream(FILE* file, volatile byte *ucsrna) {
    fdev_setup_stream(file, uart_putchar, NULL, _FDEV_SETUP_WRITE);
    file->udata = (void*) ucsrna;
}
#endif

#define INFO(fmt, args...) \
    fprintf_P(stderr, PROGSTR("INFO: " fmt), ## args);

// create a FILE structure to reference our UART output function in main project file
static FILE myStdOut = {0};
void setup() {
....
    Serial.begin(19200);
    SetupUartStream(&myStdOut, &UCSR0A);   // when debugging in AvrStudio then debugger is saturated by debug messages in user data empty interrupt handler if used buffered stream output
    // The uart is the standard output device STDOUT
    stdout = &myStdOut;
    stderr = stdout;
...
} 

....
const char* BT_ADDRESS_RAM = "abcd,ef,ghijkl";
const char* PROGMEM BT_ADDRESS_FLASH = "abcd,ef,ghijkl";


INFO("AT+BIND=%s", BT_ADDRESS_RAM);
INFO("AT+BIND=%S", BT_ADDRESS_FLASH);
  • print was just an example name of a method. – Thomas S. Oct 13 '15 at 5:01
  • If print() is just example and you need concatenated string (not streamed output) then you can use standard sprintf(), strcat() or so. Because you have initialized variable const char* you must do in runtime, bar("AT+LINK=" + BT_ADDRESS) is attempt to do it in compilation time. – TMa Oct 13 '15 at 7:25
  • Concatenating at compilation time (where possible) is what I need. – Thomas S. Oct 13 '15 at 10:11
  • Then you can use: #define BT_ADDRESS "abcd,ef,ghijkl" bar("AT+BIND" BT_ADDRESS); But you should clarify what means entered at one location, because it can mean to avoid copy pasting or to save FLASH memory avoiding duplicate strings there. – TMa Oct 13 '15 at 13:02
4

There is, as you may expect with C, many different ways of doing this.

The simplest is probably to use, instead of a const variable, a preprocessor macro.

In C you can concatenate string literals like this:

print("AT+BIND=" "abcd,ef,ghijkl");

Note the lack of anything but spaces between the strings - they are concatenated together. You can even do it on separate lines - it's a technique that is great for incredibly long strings.

Now you can, of course, replace one of those with a preprocessor macro:

#define BT_ADDRESS "abcd,ef,ghijkl"
print("AT+BIND=" BT_ADDRESS);
print("AT+LINK=" BT_ADDRESS);

The preprocessing replaces BT_ADDRESS with the string literal "abcd,ef,ghijkl" and all is well.

Other options, depending on what print does, is to expand it to take two const char * parameters and deal with them both separately. For instance, you might have:

void print(const char *command, const char *data) {
    Serial.print(command);
    Serial.println(data);
}

print("AT+BIND=", BT_ADDRESS);

If you don't know how many parameters you may want to pass you could use variadic arguments:

#include <stdarg.h>

void print(int count, ...) {
    va_list args;
    va_start args, count);

    for (int i = 0; i < count; i++) {
        const char *arg = va_arg(args, const char *);
        Serial.print(arg);
    }
    va_end(args);
}

print(2, "AT+BIND=", BT_ADDRESS);

Yet another option is to pre-format the data into a single string using the various string operators. For example:

int len = strlen("AT+BIND=") + strlen(BT_ADDRESS);
char temp[len + 1]; // Be sure to keep space for the terminating NULL.
strcpy(temp, "AT+BIND=");
strcat(BT_ADDRESS);
print(temp);

I could go on all night with different options... The first one using the preprocessor is probably easiest though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.