Converting String for Delphi to std::string for C++ - c++

I am developing a device (ESP32) and there is a rxValue variable that defined as below;
std::string rxValue = pCharacteristic->getValue(); <- ESP32 (C++) side
But I need to send data (string or character) from Delphi App via SetValueAs... method but when I use
Characteristics.SetValueAsString('b'); <- Delphi side (but problematic)
EDIT: I'm adding SetValueAsString procedure here
procedure TBluetoothGattCharacteristic.SetValueAsString(const AValue: string; IsUTF8: Boolean);
begin
if IsUTF8 then
Value := TEncoding.UTF8.GetBytes(AValue)
else
Value := TEncoding.Unicode.GetBytes(AValue);
end;
Arduino serial monitor shows me a strange character (square) and command cannot be executed.
for (int i = 0; i < rxValue.length(); i++) { <- ESP32 (C++) side
Serial.print(rxValue[i]);
}
if (rxValue.find("a") != -1) {
digitalWrite(LED, HIGH);
}
As a result, what is the way of sending a string from Delphi to C++ (ESP32 board) as std::string. In addition (I didn't want to ask a little question separately.) What is the way of exact comparing rxValue with string? I mean if rxValue is exact same as abcdef execute a command?
Thanks right now..

The problem has become more complex after diving into deep. The main problem was 8-Bit / 16-Bit string incompatibility as #RemyLebeau pointed out and #David Heffernan was correct because you cannot use be used std::string for interop across programming languages.
So I've decided to convert my data to 8Bit AnsiString and send but this time I saw that Delphi doesn't support AnsiChar and Ansistring in mobile compilers anymore (you can read here and here).
So I cannot use 8-Bit strings in Delphi mobile (there are many people they ask "why" to Embarcadero because this means that you cannot use devices that use 8-Bit (many of IoT devices) ) but thank goodness, there are some good people solve this problem with a custom library (you can find the source here).
After adding this library to my app and execute the command like below, problem has been solved;
Characteristics.SetValueAsString(RawByteString('b'));
BUT answer is: You can't use std::string this way, it's not suitable for interop.

Related

Parsing NMEA sentences from serial

I want to use TinyGPS++ on an Arduino to parse NMEA data and display information on an OLED display. But, instead of using software serial and the TX/RX pins, the NMEA data will be received by USB.
I followed the examples from TinyGPS++, but i encountered two problems:
1)
Only the first 64 characters are received by the Arduino, when i send one NMEA sentence over the serial monitor (Windows, Arduino 1.6.9). How can I overcome this restriction? I help myself by deleting a couple of decimal places, but this is not the preferred way to go.
2)
In the TinyGPS++ BasicExample a sample NMEA string is defined in the read-only memory:
// A sample NMEA stream.
const char *gpsStream =
"$GPRMC,045103.0,A,3014.0,N,09748.0,W,36.88,65.02,030913,,,A*7C\r\n"
"$GPGGA,045104.0,3014.0,N,09749.0,W,1,09,1.2,211.6,M,-22.5,M,,*62\r\n"
"$GPRMC,045200.0,A,3014.0,N,09748.0,W,36.88,65.02,030913,,,A*77\r\n"
"$GPGGA,045201.0,3014.0,N,09749.0,W,1,09,1.2,211.6,M,-22.5,M,,*6C\r\n"
"$GPRMC,045251.0,A,3014.0,N,09748.0,W,36.88,65.02,030913,,,A*7D\r\n"
"$GPGGA,045252.0,3014.0,N,09749.0,W,1,09,1.2,211.6,M,-22.5,M,,*6F\r\n";
and parsed by
while (*gpsStream) {
Serial.print(*gpsStream);
gps.encode(*gpsStream++);
}
I receive my NMEA (unfortunately only one line) this way:
if (Serial.available()) {
while (Serial.available() > 0) {
if(index < 80)
{
inChar = Serial.read();
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
and try to parse it by:
index = 0;
while (index < 80) {
gps.encode(inData[index]);
Serial.print(inData[index]);
index++;
}
But this does not work as desired. Checking if the location isValid() always returns not to be true.
Unfortunately, i have several possible sources for this undesired behavior.
The too short sentences (unlikely)
Incorrect way of reading the data over serial.
I only submit one line.
Something else.
I am not that experienced with neither NMEA, nor the serial data communication, and i have only little experience with Arduino/C. Can you point me into a direction how to solve for this (these) problems?
Basically, you do not need to accumulate NMEA characters. Just feed them to the GPS library as you receive them. You don't provide the entire loop, but it is very common to have a problem there, too.
After struggling with several GPS libraries and their examples, I eventually wrote NeoGPS. It is faster and smaller than all other libraries, it validates the checksum, and the examples are structured correctly. Unlike other libraries, NeoGPS does not store GPS values as floating-point values, so it is able to retain the full accuracy of your GPS device.
If you'd like to try it, be sure to follow the Installation instructions. The NMEA.ino example will emit one line of info (CSV format) for each batch of GPS sentences that you send, ending with the default RMC sentence. Be sure to modify it to use the Serial object instead of gps_port, or simply define it that way:
#define gps_port Serial
It will also show the number of characters that have been parsed, how many good sentences have been received, and how many sentences had checksum errors. That could help with debugging if you are not generating the checksum correctly. This site is useful, too.
Those CSV lines will be sent back over the USB port (to the PC), but you can easily change it to send specific fields to the OLED (see NMEAloc.ino).
Although it is possible to develop something on a PC and then port it to an embedded environment like the Arduino, you have to be careful about (1) linear program structure and (2) ignoring resource limits (program size, MCU speed and RAM). There are a number of quirks with the Arduino environment that usually make it frustrating to port a "sketch" to/from a PC. :P

Can I decode € (euro sign) as a char and not as a wstring/wchar?

Let's try explain my problem. I have to receive a message from a server (programmed in delphi) and do some things with that message in the client side (which is the side I programm, in c++).
Let's say that the message is: "Hello €" that means that I have to work with std::wstring as €(euro sign) needs 2 bytes instead of 1 byte, so knowing that I have made all my work with wstrings and if I set the message it works fine. Now, I have to receive the real one from the server, and here comes the problem.
The person on the server side is sending that message as a string. He uses a EncodeString() function in delphi and he says that he is not gonna change it. So my question is: If I Decode that string into a string in c++, and then I convert it into a wstring, will it work? Or will I have problems and have other message on my string var instead of "Hello €".
If yes, if I can receive that string with no problem, then I have another problem. The function that I have to use to decode the string is void DecodeString(char *buffer, int length);
so normally if you receive a text, you do something like:
char Text[255];
DescodeString(Text, length); // length is a number decoded before
So... can I decode it with no problem and have in Text the "Hello €" message? with that I'll just need to convert it and get the wstring.
Thank you
EDIT:
I'll add another example. If i know that the server is going to send me always a text of length 30 max, in the server they do something like:
EncodeByte(lengthText);
EncodeString(text)
and in the client you do:
int length;
char myText[30];
DecodeByte(length);
DecodeString(myText,length);
and then, you can work with myText as a string lately.
Hope that helps a little more. I'm sorry for not having more information but I'm new in that work and I don't know much more about the server.
EDIT 2
Trying to summarize... The thing is that I have to receive a message and do something with it, with the tool I said I have to decode it. So as de DecodeString() needs a char and I need a wstring, I just need a way to get the data received by the server, decode it with decodeString() and get it into a wstring, but I don't really know if its possible, and if it is, I'm not sure about how to do it and what type of vars use to get it
EDIT 3
Finally! I know what code pages are using. Seems that the client uses the ANSI ones and that the server doesn't, so.. I'll have to tell to the person who does that part to change it to the ANSI ones. Thanks everybody for helping me with my big big ignorance about the existence of code pages.
Since you're using wstring, I guess that you are on Windows (wstring isn't popular on *nix).
If so, you need the Delphi app to send you UTF-16, which you can use in the wstring constructor. Example:
char* input = "\x0ac\x020"; // UTF-16 encoding for euro sign
wchar_t* input2 = reinterpret_cast<wchar_t*>(input);
wstring ws(input2);
If you're Linux/Mac, etc, you need to receive UTF-32.
This method is far from perfect though. There can be pitfalls and edge cases for unicodes beyond 0xffff (chinese, etc). Supporting that probably requires a PhD.

What charset detector for unknown webpage encoding can be used in C++ application?

I use C++, Qt 4.8.5, Visual Studio 2010. I'd like to create Windows GUI application which downloads some web pages. Note that my program is built in 32 bit mode and should be run in 32 and 64 bit Windows environment. I don't need to use Qt webkit. I need to analyze web pages. But the problem is character encoding. What charset auto-detection C/C++ library can be used in the case of absent charset information? MLang can't be used, because it is COM based. Extreme accuracy of detection is not required. I will prefer simple API and simple Windows friendly build instructions.
When there is no information about the encoding, the only way is to convert the data using many encodings and choose the best result. Evaluation of the result depends on your goal. For example, this function tries to choose between CP1251 and UTF-8 encodings assuming that the data represents text in Russian:
QString detect_encoding(const QByteArray &array) {
QString alphabet = QString::fromUtf8("АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя");
QString try_utf = QString::fromUtf8(array);
QString try_win = QTextCodec::codecForName("cp1251")->
toUnicode(try_utf.toLatin1());
int count_utf = 0, count_win = 0;
for(int i = 0; i < try_utf.length(); i++) {
if (alphabet.contains(try_utf[i])) {
count_utf++;
}
}
for(int i = 0; i < try_win.length(); i++) {
if (alphabet.contains(try_win[i])) {
count_win++;
}
}
if (count_win > count_utf) {
return try_win;
} else {
return try_utf;
}
}
There are quite few encodings that can represent Russian. You only need to add them to the comparation. The same approach should work for any language or combination of several languages, you just need to change the alphabet setting and encodings. (I advise to refactor this function. In current state it's just an illustration rather than a piece of production code.)
When there is no specific target language, decoding data without information about encoding is hardly possible. Also arbitrary page can contain some special symbols that can confuse detector. There is no universal way. I wish every site used UTF-8.

getting the local system date time and converting it to a string (MFC C++)

I have inherited some MFC C++ code (it's an ActiveX OCX control running on a Windows Mobile 6.5 device) and I need to acquire the system date and time and append it as part of an existing string which gets passed via the com port to another device.
I can get the system date and time, but I can not figure out how to convert that into a string so that I can append it (via strcat.)
I've found a number of different answers on Google and Bing for what at first glance seemed like such a simple problem... :( but I don't know enough MFC C++ to adapt any of it to my needs. Any help would be greatly appreciated.
CTime t = CTime::GetCurrentTime();
CString s = t.Format( "%A, %B %d, %Y" );
char * str = (LPCTSTR) s;
Note, I believe that str is only valid while s is in scope. Probably should copy it off somewhere if you need it to be around after s is destroyed. If you are passing it to strcat() you're probably OK.
In MFC the following code is for current date in MMDDYYYY format.
CTime t = CTime::GetCurrentTime();
CString strDate = t.Format("%m%d%Y");

Get latency from host in C++

Using C++, I would like to use a command/class to get the latency time from pinging a host to use in my program. I tried using the ping command but there was no easy way to gather the time since its included with other statistical information. I was hoping for an easier approach.
The ping tool is usually implemented in C and works by sending ICMP Echo request packets over a raw socket,. The system time is recorded -- usually with gettimeofday on under posix -- when the Echo request is made and again when an Echo reply (if any) is received to determine the round-trip time. You can put the same functionality in your C++ application using sockets.
Otherwise, extracting the information from a ping system call is probably easier than you think. The key is to open a pipe to allow reading of the standard output of the ping command (see popen or _popen). A regular expression (e.g. "time=([0-9]*)") could be used to pluck out the desired data. If you don't have a regex library available, then extracting this data only requires fairly trivial string manipulation. The STL string class provides several algorithms that may be of use.
if you don't like regexes you can always loop through the output, looking for t followed by i followed by m followed by e followed by = by just stepping through the output string one piece at a time. store the pointer to the char after =, then step through futher and replace the next space by a zero. you now have a string with the latency, converting to a number can be done with the existing conversion functions.
e.g. if the output is in char* output with length stored in unsigned int length and the matched string needs to go in char* match...
for(unsigned int i = 4; i < length; ++i)
{
if(output[i] == '=')
{
if((output[i-4] = 't') && (output[i-3] = 'i') && (output[i-2] = 'm') && (output[i-1] = 'e'))
{
match = &(output[i+1]);
while(output[i] != ' ') ++i;
output[i] = 0;
break;
}
}
}
regexes are nicer though... they make your code look a lot a tider and readable. although if you don't have a library for them it will be faster to just implement it like this... :)
If you are using Windows, you can use win32 api function https://learn.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho2.