-1

I followed a tutorial on youtube to develop a program in c++ to send a short message over a serialport and listen for a response. I am using the Serialport library(not the default c++ one, an external one) (https://github.com/greiman/SerialPort/blob/master/SerialPort/SerialPort.h). The program in the video uses the port 10 to communicate, but I want the user to be able to enter a specific port which the program then uses to communicate. But i'm struggling with the assignment of a variable. The library has a class called Serialport, that takes a char pointer as a parameter like so:

char* port;
SerialPort arduino(port);

The guy in the video then gives the char pointer the value of a String, like so:

char* port = "\\\\.\\COM10";

and then the code works flawlessly. Which I find odd for several reasons.

First of all, "port" is a pointer, so shoulnd't it be pointing to some other value? like so:

char port1 = 'a';
char* port2 = port1;

second of all, why does he use a char pointer to point to a string? and why does that work?

i've tried using a variable instead of assigning the value to the pointer directly, so that the user can enter the port they want to use, like so:

string portone;
cout << "specify port: " << endl;
cin >> portone;
string porttwo = "\\\\.\\COM" + portone;
port = porttwo;

But then vs studio tells me "there is no suitable conversion function from string to char".

so, in conclusion i'm asking:

why does this:

char* port = "\\\\.\\COM10";

work, but this:

string portone = "\\\\.\\COM10";
char* porttwo = portone;

does not.

And is there any way to assign a variable value to the char pointer to let the user specify the port?

my entire code:

#include<iostream>
#include<string>
#include<stdlib.h>

using namespace std;
#include"SerialPort.h"

char output[MAX_DATA_LENGTH];
char incomingData[MAX_DATA_LENGTH];
// change the name of the port with the port name of your computer
// must remember that the backslashes are essential so do not remove them
char* port;

int main() {
    string data;
    string portone;
    cout << "Escribi el port: " << endl;
    cin >> portone;
    string porttwo = "\\\\.\\COM" + portone;
    port = porttwo;
    SerialPort arduino(port);
    if (arduino.isConnected()) {
        cout << "Conectado" << endl << endl;
    }
    else {
        cout << "Puerto 10 vacio" << endl << endl;
    }
    if (arduino.isConnected()) {
        cout << "Escribi el string: " << endl;
        cin >> data;
        char* charArray = new char[data.size() + 1];
        copy(data.begin(), data.end(), charArray);
        charArray[data.size()] = '\n';
        arduino.writeSerialPort(charArray, MAX_DATA_LENGTH);
        arduino.readSerialPort(output, MAX_DATA_LENGTH);

        cout << "Respuesta: " << output << endl;

        delete[] charArray;
    }
    cout << "Terminado" << endl << endl;
    system("PAUSE");
    return 0;
}


 


 

serialport class:

#include "SerialPort.h"

SerialPort::SerialPort(char *portName)
{
    this->connected = false;

    this->handler = CreateFileA(static_cast<LPCSTR>(portName),
                                GENERIC_READ | GENERIC_WRITE,
                                0,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
    if (this->handler == INVALID_HANDLE_VALUE){
        if (GetLastError() == ERROR_FILE_NOT_FOUND){
            printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
        }
    else
        {
            printf("ERROR!!!");
        }
    }
    else {
        DCB dcbSerialParameters = {0};

        if (!GetCommState(this->handler, &dcbSerialParameters)) {
            printf("failed to get current serial parameters");
        }
        else {
            dcbSerialParameters.BaudRate = CBR_9600;
            dcbSerialParameters.ByteSize = 8;
            dcbSerialParameters.StopBits = ONESTOPBIT;
            dcbSerialParameters.Parity = NOPARITY;
            dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;

            if (!SetCommState(handler, &dcbSerialParameters))
            {
                printf("ALERT: could not set Serial port parameters\n");
            }
            else {
                this->connected = true;
                PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
                Sleep(ARDUINO_WAIT_TIME);
            }
        }
    }
}

SerialPort::~SerialPort()
{
    if (this->connected){
        this->connected = false;
        CloseHandle(this->handler);
    }
}

int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesRead;
    unsigned int toRead = 0;

    ClearCommError(this->handler, &this->errors, &this->status);

    if (this->status.cbInQue > 0){
        if (this->status.cbInQue > buf_size){
            toRead = buf_size;
        }
        else toRead = this->status.cbInQue;
    }

    if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;

    return 0;
}

bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesSend;

    if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
        ClearCommError(this->handler, &this->errors, &this->status);
        return false;
    }
    else return true;
}

bool SerialPort::isConnected()
{
    return this->connected;
}

links:

youtube vid: https://www.youtube.com/watch?v=8BWjyZxGr5o

serialport.h: https://github.com/greiman/SerialPort/blob/master/SerialPort/SerialPort.h

  • A string literal has the type `const char[]` - that's how it is defined in the C++ standard. Any kind of `string` (such as `std::string`) is a class, defined in some library. You can get a `const char*` from your `std::string` via the `c_str()` member function – UnholySheep Jul 16 '22 at 22:09
  • And as far as your question if a pointer "shoulnd't it be pointing to some other value" you should find a discussion of how arrays become pointers, like a character arrays that represents string literals, in your C++ textbook; and everything should be crystal clear. – Sam Varshavchik Jul 16 '22 at 22:34

1 Answers1

1
char* port = "\\\\.\\COM10";

and then the code works flawlessly. Which I find odd for several reasons.

First of all, "port" is a pointer, so shoulnd't it be pointing to some other value? like so:

char port1 = 'a';
char* port2 = port1;
char *port = "whatever";

is creating a variable (named port) that points at a value (the characters you put inside the quotes). It's basically telling the compiler to store the string you specified somewhere in memory (but we don't care much exactly where), then create a variable (named port, in this case) holding its address.

As far as your second example goes, yes, you could create a pointer referring to the value in some other variable, but you need one minor change. A pointer holds an address, so you need to take the address of that variable, so your example would work more like this:

char port1 = 'a';
char *port2 = &port1;

Note, however, that the name of an array normally evaluates to the address of the beginning of the array, so in this case we don't need to use the address-of operator (we just get the address by default):

static char portCharacters[] = "\\\\.\\COM10";
char *port1 = portCharacters;

This is almost the same as the first example you gave. The minor difference is that in this case we've given a name directly to the storage where the characters are stored, and also to a pointer to that location.

A couple other points worth noting here:

  • in C it's pretty routine to assume that a char * will point at a NUL-terminated string. That is, that it'll point to the beginning of an array of characters with a '\0' byte signalling the end of the array. That's not necessarily the case with the char *port1 = &port2; case, so we have to be kind of careful with it, to assure against accidentally trying to use it like a string, when it's really only referring to a single character.
  • In current C++, you can't actually do char *a = "foo";. You need to use char const *a = "foo"; (or, equivalently) const char *a = "foo";. This doesn't really change anything materially--trying to modify a string literal gives undefined behavior, and will often fail (e.g., get your program killed). But by requiring the const there, a modern compiler will enforce this by stopping your code from compiling if you try to modify a string literal (though if you insist, you can bypass that).
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111