How to convert string to int in processing - arduino

I am trying to make a hands free mouse using Arduino IDE and Processing IDE. I don't have a problem with serializing the code and converting to string, but when I try and convert the serial string into int the int goes to 0. I have tried to trim it and used integer.parseInt but it still gives me the error:
NumberFormatException : For input String:"".
Here is my code:
import processing.serial.*;
import java.awt.event.KeyListener;
import java.awt.Robot;
Serial myPort; // Create object from Serial class
Robot robot;
String val; // Data received from the serial port
boolean valtrue;
int xy = 0;
int x=0;
void setup()
{
String portName = Serial.list()[3];
myPort = new Serial(this, portName, 9600);
myPort.bufferUntil('.');
try {
robot = new Robot();
}
catch (Exception e) {
e.printStackTrace();
}
}
void draw() {
//reading serial port until \n
String sensorValue = myPort.readStringUntil('\n');
if (sensorValue != null) {
int value = Integer.parseInt(sensorValue.trim());
println(value);
}
}
If anyone is able to help, please answer.

Processing has an int() function that you can use instead of Integer.parseInt(). Behind the scenes the int() function is calling the Integer.parseInt() function, but it's shorter. Up to you.
But your error says it all: you're passing an empty String value "" into the parseInt() function. An empty String value can't be turned into a number, so you get the exception.
You're going to have to track down why your String value is empty, but that's what's causing this particular error. I will point out that the draw() function is called 60 times per second, and you're trying to read from your port every single time, so maybe you're reading faster than you're writing?

Related

Why do I need to send a message twice to trigger Indy's OnExecute event?

I am working on an application that works as a "man in the middle" to analyze a protocol (ISO 8583) sent over TCP/IP.
The main idea is to get the raw binary data and convert it to a string for parsing and decoding the protocol.
For this, I am using the TIdMappedPortTCP component.
I am testing with Hercules.
I am working with:
Windows 11 Home
Embarcadero® C++Builder 10.4 Version 27.0.40680.4203
Delphi and C++ Builder 10.4 Update 2
Indy 10.6.2.0
More context can be found in these questions:
Where can I find a fully working example of a TCP Client and Server for Indy in C++Builder?
Parsing bytes as BCD with Indy C++ Builder
The problem is that I have to send the message twice to trigger the OnExecute event. I think this might be length related but I haven't found the issue. Other than that the program does what is expected from it.
If I use this data in Hercules:
00 04 60 02
equivalent to:
"\x00\x04\x60\x02"
My program processes everything correctly:
Here is the code:
void __fastcall TForm1::MITMProxyExecute(TIdContext *AContext)
{
static int index;
TIdBytes ucBuffer;
UnicodeString usTemp1;
UnicodeString usTemp2;
int calculated_length;
// getting the length in Hexa
calculated_length = ReadMessageLength(AContext);
// reads data
AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length);
// displays string with calculated length and size of the data
usTemp2 = UnicodeString("calculated length = ");
usTemp2 += IntToStr(calculated_length);
usTemp2 += " ucBuffer.Length = ";
usTemp2 += IntToStr(ucBuffer.Length);
Display->Lines->Add(usTemp2);
// converts the binary data into a a Hex String for visualization
usTemp1 = BytesToHexString(ucBuffer);
// adds an index to distinguish from previous entries.
usTemp2 = IntToStr(index);
usTemp2 += UnicodeString(": ");
usTemp2 += usTemp1;
Display->Lines->Add(usTemp2);
index++;
}
Here is the code for the functions called there. By the way, is there a better way to convert the bytes to a hex string?
// Convert an array of bytes to a hexadecimal string
UnicodeString BytesToHexString(const TBytes& bytes)
{
// Create an empty UnicodeString to store the hexadecimal representation of the bytes
UnicodeString hexString;
// Iterate through each byte in the array
for (int i = 0; i < bytes.Length; i++)
{
// Convert the byte to a hexadecimal string and append it to the result string
hexString += IntToHex(bytes[i], 2);
}
// Return the hexadecimal string
return hexString;
}
// Read the first two bytes of an incoming message and interpret them as the length of the message
int ReadMessageLength(TIdContext *AContext)
{
int calculated_length;
// Use the 'ReadSmallInt' method to read the length of the message from the first two bytes
calculated_length = AContext->Connection->IOHandler->ReadSmallInt();
// converting from hex binary to hex string
UnicodeString bcdLength = UnicodeString().sprintf(L"%04x", calculated_length);
// converting from hex string to int
calculated_length = bcdLength.ToInt();
// decrease length
calculated_length -= 2;
return calculated_length;
}
UPDATE
I have created a class to update the TEditRich control. But the problem persist, I need to send the message twice to be processed and the application freezes when trying to close it. This is my class:
class TAddTextToDisplay : public TIdSync {
private:
UnicodeString textToAdd;
public:
__fastcall TAddTextToDisplay(UnicodeString str) {
// Store the input parameters in member variables.
textToAdd = str;
}
virtual void __fastcall DoSynchronize() {
if (textToAdd != NULL) {
// Use the input parameters here...
Form1->Display->Lines->Add(textToAdd);
}
}
void __fastcall setTextToAdd(UnicodeString str) {
textToAdd = str;
}
};
And this is how my new OnExecute event looks:
void __fastcall TForm1::MITMProxyExecute(TIdContext *AContext) {
static int index;
TIdBytes ucBuffer;
UnicodeString usTemp1;
UnicodeString usTemp2;
int calculated_length;
int bytes_remaining;
// getting the length in Hexa
calculated_length = ReadMessageLength(AContext);
if (!AContext->Connection->IOHandler->InputBufferIsEmpty()) {
// reads data
AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length);
// displays string with calculated length and size of the data
usTemp2 = UnicodeString("calculated length = ");
usTemp2 += IntToStr(calculated_length);
usTemp2 += " ucBuffer.Length = ";
usTemp2 += IntToStr(ucBuffer.Length);
TAddTextToDisplay *AddTextToDisplay = new TAddTextToDisplay(usTemp2);
AddTextToDisplay->Synchronize();
// converts the binary data into a a Hex String for visualization
usTemp1 = BytesToHexString(ucBuffer);
// adds an index to distinguish from previous entries.
usTemp2 = IntToStr(index);
usTemp2 += UnicodeString(": ");
usTemp2 += usTemp1;
AddTextToDisplay->setTextToAdd(usTemp2);
AddTextToDisplay->Synchronize();
delete AddTextToDisplay;
index++;
}
}
You really should not be reading from the IOHandler directly at all. You are getting your communication out of sync. TIdMappedPortTCP internally reads from the client before firing the OnExecute event, and reads from the target server before firing the OnOutboundData event. In both cases, the bytes received are made available in the TIdMappedPortContext::NetData property, which you are not processing at all.
You need to do all of your parsing using just the NetData only, iterating through its bytes looking for complete messages, and saving incomplete messages for future events to finish.
Try something more like this instead:
#include <IdGlobal.hpp>
#include <IdBuffer.hpp>
bool ReadMessageData(TIdBuffer *Buffer, int &Offset, TIdBytes &Data)
{
// has enough bytes?
if ((Offset + 2) > Buffer->Size)
return false;
// read the length of the message from the first two bytes
UInt16 binLength = Buffer->ExtractToUInt16(Offset);
// converting from hex binary to hex string
String bcdLength = String().sprintf(_D("%04hx"), binLength);
// converting from hex string to int
int calculated_length = bcdLength.ToInt() - 2;
// has enough bytes?
if ((Offset + 2 + calculated_length) > Buffer->Size)
return false;
// reads data
Data.Length = calculated_length;
Buffer->ExtractToBytes(Data, calculated_length, false, Offset + 2);
Offset += (2 + calculated_length);
return true;
}
void __fastcall TForm1::MITMProxyConnect(TIdContext *AContext)
{
AContext->Data = new TIdBuffer;
}
void __fastcall TForm1::MITMProxyDisconnect(TIdContext *AContext)
{
delete static_cast<TIdBuffer*>(AContext->Data);
AContext->Data = NULL;
}
void __fastcall TForm1::MITMProxyExecute(TIdContext *AContext)
{
static int index = 0;
TIdBuffer *Buffer = static_cast<TIdBuffer*>(AContext->Data);
Buffer->Write(static_cast<TIdMappedPortContext*>(AContext)->NetData);
Buffer->CompactHead();
TAddTextToDisplay *AddTextToDisplay = NULL;
TIdBytes ucBuffer;
int offset = 0;
while (ReadMessageData(Buffer, offset, ucBuffer))
{
String sTemp = String().sprintf(_D("%d: ucBuffer.Length = %d ucBuffer = %s"), index, ucBuffer.Length, ToHex(ucBuffer).c_str());
if (AddTextToDisplay)
AddTextToDisplay->setTextToAdd(sTemp);
else
AddTextToDisplay = new TAddTextToDisplay(sTemp);
AddTextToDisplay->Synchronize();
++index;
}
delete AddTextToDisplay;
if (offset > 0)
Buffer->Remove(offset);
}
Otherwise, if you want to do your own socket I/O, then you will have to use TIdTCPServer and TIdTCPClient directly instead of using TIdMappedPortTCP.

Overloading function handling char and String

I'm making a function to handle a message, then print the message using Serial.println(). I have it working, but ran into an issue I can't explain. The first sample code below works, the second (swapping the order of my function declaration) will compile and load, but causes the Teensy 4.1 to crash. I'm using PlatformIO on VSCode.
Can anyone tell me what is wrong with the second code, and why it will compile without error, but not run?
This works:
#include <Arduino.h>
void LogMsg(const char *msg){
Serial.println(msg);
}
void LogMsg(String s){ LogMsg(s.c_str()); }
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
This compiles, loads, but crashes, causing continuous resets:
#include <Arduino.h>
void LogMsg(String s){ LogMsg(s.c_str()); } // <-- swapped order
void LogMsg(const char *msg){ // <-- swapped order
Serial.println(msg);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
Edit: The definition of void LogMsg(String s) was changed to reflect error in original and the simplification suggested by #hcheung. Behavior remains the same. The first instance works, the second crashes.
C strings are terminated with '\0'. So toCharArray() will append a null character to your Ardunio String. Otherwise you would have to provide a length with the char pointer everytime you want to use that string.
Your char array must be big enough to fit this extra character or you will cause an access violation if toCharArray does not throw an exception first.

Receiving a string through UART in STM32F4

I've written this code to receive a series of char variable through USART6 and have them stored in a string. But the problem is first received value is just a junk! Any help would be appreciated in advance.
while(1)
{
//memset(RxBuffer, 0, sizeof(RxBuffer));
i = 0;
requestRead(&dt, 1);
RxBuffer[i++] = dt;
while (i < 11)
{
requestRead(&dt, 1);
RxBuffer[i++] = dt;
HAL_Delay(5);
}
function prototype
static void requestRead(char *buffer, uint16_t length)
{
while (HAL_UART_Receive_IT(&huart6, buffer, length) != HAL_OK)
HAL_Delay(10);
}
First of all, the HAL_Delay seems to be redundant. Is there any particular reason for it?
The HAL_UART_Receive_IT function is used for non-blocking mode. What you have written seems to be more like blocking mode, which uses the HAL_UART_Receive function.
Also, I belive you need something like this:
Somewhere in the main:
// global variables
volatile uint8_t Rx_byte;
volatile uint8_t Rx_data[10];
volatile uint8_t Rx_indx = 0;
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
And then the callback function:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == UART1) { // Current UART
Rx_data[Rx_indx++] = Rx_byte; // Add data to Rx_Buffer
}
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
}
The idea is to receive always only one byte and save it into an array. Then somewhere check the number of received bytes or some pattern check, etc and then process the received frame.
On the other side, if the number of bytes is always same, you can change the "HAL_UART_Receive_IT" function and set the correct bytes count.

arduino json on the serial stream

Im using the BLuno arduino,
Its connecting fine to my iOS phone, sending and receiving messages.
Now I want to use arduino json to parse messages from my phone,
The serial connection receives data fine, but Im doing something wrong taking the stream to parse with the json library...
I get the error:
deserializeJson() failed: InvalidInput
The code:
#include <ArduinoJson.h>
StaticJsonDocument<400> doc;
void setup() {
Serial.begin(115200);
}
void loop()
{
if (Serial.available() > 0)
{
String s = Serial.readStringUntil("#"); // Until CR (Carriage Return)
s.replace("#", "");
Serial.println(s);
DeserializationError error = deserializeJson(doc, s);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
int value = doc["value"];
Serial.println(Serial.println(value));
IS
deserializeJson(doc, s);
correct?, I try to send different values, from the phone:
I just need to parse a key value pair, but none of the following ways worked:
{'a':'b'}
or
"{"a":"b"}"
or
{\"a\":\"b\"}
Where is my problem please?
how to format the {"a":"b"}
so the serial likes it for parsing?
There is nothing wrong with your code and ArduinoJson method, the
{'a':'b'} "{"a":"b"}" {\"a\":\"b\"}
is not a valid JSON object nor a serialised string representation of a JSON object.
If you JSON consists of multiple objects, the correct format should be:
[{"a": "b"},{"a": "b"},{"a": "b"}]
and with the serialised string representation should be like this:
"[{\"a\": \"b\"},{\"a\": \"b\"},{\"a\": \"b\"}]"
It is always a good idea to utilise one of those online JSON Validator to valid your JSON object during your development.
Update
Looks like that you had updated your question, based on your update, there are two problems in your code:
if the JSON object is {"a":"b"}, then there is no doc["value"] in the deserialised data, it should be doc["a"] to access the value "b".
the doc["a"] will not be int as in your int value = doc["value"], doc["value"] return a pointer to a char.
Here will be the code that produce the correct value.
void loop() {
char s[] = "{\"a\":\"b\"}";
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, s);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
const char* value = doc["a"];
Serial.println(value);
while(1) {};
}

using an integer function return value to return a pointer

I am writing a serial command interpreter. The user will send a text string to the interpreter and it will do stuff and return an integer (either data or a code depending on what the user requested). But I want to expand the interpreter and allow the user to get an array of data or other structure in response to their query.
Can I use the integer return value to return a pointer to EEPROM (or global variable) address? And have the user follow the pointer to the memory location? Based on the query they sent, they would know if the return value is a pointer or data integer.
for example if I want to return
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
} theCurve;
can I use a function like this?
int serialResponse(char * command) {
// interpret command here
return &theCurve;
}
Can you send a memory address through serial interface?
YES
Can your user access EEPROM through serial interface, using that address?
Not directly. Your MCU has to relay the data between your user and the EEPROM.
I wrote a small test program and confirmed that it is possible. I can pass the address from the function as an integer and then re-cast it in my calling function. It needs to address a global variable or at least on that is available in the calling function.
char res[10];
void loop {
b = function();
Serial.println((char *)b);
}
int function() {
return int(&res[0]);
}
I would not recommend casting a pointer into an integer because it won't work on computer architectures where an int has fewer bits than a pointer.
Lexical Parsers - like what you're writing - often arrange to return a token type, and place the token value in a union that the caller can access. The nice thing about structuring your code in that way is that it's extensible to whatever data types you want, and it will work no matter what C++ platform you're running on.
Here's an example of a token parser that can parse integers and your curve_t:
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
};
union TokenValue {
int i; // type = TOKEN_TYPE_INT
struct curve_t *pCurve; // type = TOKEN_TYPE_P_CURVE
};
enum TokenType {
TOKEN_TYPE_UNKNOWN = 0,
TOKEN_TYPE_INT,
TOKEN_TYPE_P_CURVE
};
curve_t theCurve;
TokenValue tokenValue;
/*
* Parses the given command,
* setting the parsed value in tokenValue,
* returning the type of value (a TOKEN_TYPE_*).
*/
TokenType serialResponse(char * command) {
if (command[0] == 'a') { // TO DO: your code will test something else.
// We want to return an integer
tokenValue.i = 1234; // TO DO: in your code, instead set the integer value from command
return TOKEN_TYPE_INT;
}
if (command[0] == 'b') { // TO DO: your code will test something else.
// We want to return a pointer to theCurve.
// TO DO: Fill in the values of theCurve, for example theCurve.param[0]
tokenValue.pCurve = &theCurve;
return TOKEN_TYPE_P_CURVE;
}
// Else
return TOKEN_TYPE_UNKNOWN;
}
void setup() {
//TO DO: move this code to where it belongs in your Sketch
//TO DO: parse a command
char command[10] = "and so...";
// TO DO: read the command.
// Process the command
enum TokenType t;
t = serialResponse(command);
if (t == TOKEN_TYPE_INT) {
// The command result is an integer
int i = tokenValue.i;
// TO DO: process the integer.
} else if (t == TOKEN_TYPE_P_CURVE) {
// The command result is a curve
curve_t *pCurve = tokenValue.pCurve;
// TO DO: process the Curve.
} else {
// unrecognized command. TO DO: handle the error.
}
}
void loop() {
// put your main code here, to run repeatedly:
}
If you insist on using the cast of an int to a pointer (which I admit is a lot simpler), you could add a test for int size problems to your setup():
void setup() {
Serial.begin(9600);
if (sizeof(int) < sizeof(curve_t *)) {
Serial.println("cast won't work");
for (;;) {} // hang here forever.
}
}

Resources