Serial communication c++ SerialPort-Class - c++

First of all - I'm a student from Germany, so please excuse my bad english.
At the moment, I'm working on a Project which target is to controll servo Motors on an arduino board by Serial communication through xbee modules.
So now I'm studying the SerialPort but got Problems by using the write().
My plan is to send integer values seperated by a commata through my Serial Port.
Visual Studio Reports an error and says that there is no Argument type that fits.
I really don't know how to handle this problem, because I'm completely new to this whole programming topic.
#include <iostream>
using namespace std;
#using <System.dll>;
using namespace System;
using namespace System::IO::Ports;
using namespace System::Threading;
int main() {
unsigned char values[2] = { 50, 120 };
SerialPort^ mySerialPort = gcnew SerialPort("COM3");
mySerialPort->BaudRate = 9600;
mySerialPort->Open();
while (true) {
mySerialPort->Write(values);
}
}

You can fix it this way:
#include <iostream>
using namespace std;
#using <System.dll>
using namespace System;
using namespace System::IO::Ports;
using namespace System::Threading;
int main() {
// Managed array
cli::array<unsigned char> ^values = { 50, 120 };
SerialPort^ mySerialPort = gcnew SerialPort("COM3");
mySerialPort->BaudRate = 9600;
mySerialPort->Open();
while (true) {
// some work with values goes here...
// We should specify buffer offset and length
mySerialPort->Write(values, 0, values->Length);
}
}
As you noticed, you can also send this data as string:
mySerialPort->WriteLine(String::Format("val1 = {0}; val2 = {1}", values[0], values[1]));
But be warned that mySerialPort->Write() sends raw bytes, and mySerialPort->WriteLine() sends each character as a single byte.
For instance:
cli::array<unsigned char> ^buffer = {123};
// Send one single byte 0x7b
mySerialPort->Write(buffer, 0, buffer->Length);
// Send 3 bytes (0x49, 0x50, 0x51)
mySerialPort->WriteLine(String::Format("{0}", buffer[0]));

Related

Convert byte string to normal string in C++

I have the following situation:
I'm actually trying to read streamdata from a server into a label in Visual Studio:
//Receive a reply from the server
if((recv_size = recv(ConnectSocket , server_reply , 2000 , 0)) == SOCKET_ERROR){
MessageBox::Show("recv failed","");
//exit(1);
}
this->label1->Text = Convert::ToString(server_reply[0]);
example result:
ANAG;FCA;11:20:27;NL0010877643;FIAT CHRYSLER AUTO;16.85;0.0;0
when I get it into my program, I have it like:
657865...
which I think is the byte representation of the corresponding characters (eg.: 65 = A, 78 = N, etc.).
Question is: How do I convert these bytecodes into a normal string of characters?
The server seems to be sending byte data
Thanks in advance
You just need to create a string from it.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char byteArray[] = { 65, 78, 65, 71 }; // .... your input
std::string s(byteArray, sizeof(byteArray));
cout << s;
return 0;
}

Subscribe to WebSocket feed

I'm trying to access a WebSocket API using the cpprestsdk. The example code I have so far is:
#include <iostream>
#include <cpprest/ws_client.h>
using namespace std;
using namespace web;
using namespace web::websockets::client;
int main() {
websocket_client client;
client.connect("wss://api.poloniex.com").wait();
websocket_outgoing_message out_msg;
out_msg.set_utf8_message("test");
client.send(out_msg).wait();
client.receive().then([](websocket_incoming_message in_msg) {
return in_msg.extract_string();
}).then([](string body) {
cout << body << endl; // test
}).wait();
client.close().wait();
return 0;
}
The page (here) gives the following information:
In order to use the push API, connect to wss://api.poloniex.com and
subscribe to the desired feed [...] In order to receive ticker
updates, subscribe to "ticker".
I can't find out how to subscribe to a channel using this library.

Periodically send data to MATLAB from mexFile

I'm working right now on a Data Acquisition Tool completely written
in MATLAB. It was the wish of my colleagues that i write this thing in MATLAB
so that they can expand and modify it.
The Software needs to grab a picture from two connected USB cameras.
The API for these cameras is written in C++ and is documented -> Here.
Here is the Problem:
When i write a mex file which grabs a picture it includes the
initialization and configuration-loading of the cameras which
takes a long time. When i want to grab the pictures
this way it takes MATLAB over 1 second to perform the task.
The cameras are able, once initialized, to record and send 100 fps.
The minimum frame rate i need is 10 fps.
I need to be able to send every recorded picture back
to MATLAB. Because the recording session for which the
Acquisition Tool is needed takes approx 12 hours and we
need a Live Screen with some slight PostProcessing.
Is it possible to generate a loop within the mex File which
sends data to MATLAB, then waits for a return signal from MATLAB
and continues ?
This way i could initialize the cameras and send periodically
the images to MATLAB.
I'am a Beginner in C++ and it is quite possible that i
don't understand a fundamental concept why this
is not possible.
Thank you for any advice or sources where i could look.
Please find below the Code which initializes the Cameras
using the Pylon API provided by Basler.
// Based on the Grab_MultipleCameras.cpp Routine from Basler
/*
This routine grabs one frame from 2 cameras connected
via two USB3 ports. It directs the Output to MATLAB.
*/
// Include files to use the PYLON API.
#include <pylon/PylonIncludes.h>
#include <pylon/usb/PylonUsbIncludes.h>
#include <pylon/usb/BaslerUsbInstantCamera.h>
#include <pylon/PylonUtilityIncludes.h>
// Include Files for MEX Generation
#include <matrix.h>
#include <mex.h>
// Namespace for using pylon objects.
using namespace Pylon;
// We are lazy and use Basler USB namespace
using namespace Basler_UsbCameraParams;
// Standard namespace
using namespace std;
// Define Variables Globally to be remembered between each call
// Filenames for CamConfig
const String_t filenames[] = { "NodeMapCam1.pfs","NodeMapCam2.pfs" };
// Limits the amount of cameras used for grabbing.
static const size_t camerasToUse = 2;
// Create an array of instant cameras for the found devices and
// avoid exceeding a maximum number of devices.
CBaslerUsbInstantCameraArray cameras(camerasToUse);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// Automagically call PylonInitialize and PylonTerminate to ensure the pylon runtime system.
// is initialized during the lifetime of this object
PylonAutoInitTerm autoInitTerm;
try
{
// Get the transport layer factory
CTlFactory& tlFactory = CTlFactory::GetInstance();
// Get all attached devices and exit application if no device or USB Port is found.
DeviceInfoList_t devices;
ITransportLayer *pTL = dynamic_cast<ITransportLayer*>(tlFactory.CreateTl(BaslerUsbDeviceClass));
if (pTL == NULL)
{
throw RUNTIME_EXCEPTION("No USB transport layer available.");
}
if (pTL->EnumerateDevices(devices) == 0)
{
throw RUNTIME_EXCEPTION("No camera present.");
}
// Create and attach all Pylon Devices. Load Configuration
for (size_t i = 0; i < cameras.GetSize(); ++i)
{
cameras[i].Attach(tlFactory.CreateDevice(devices[i]));
}
// Open all cameras.
cameras.Open();
// Load Configuration and execute Trigger
for (size_t i = 0; i < cameras.GetSize(); ++i)
{
CFeaturePersistence::Load(filenames[i], &cameras[i].GetNodeMap());
}
if (cameras[0].IsOpen() && cameras[1].IsOpen())
{
mexPrintf("\nCameras are fired up and configuration is applied\n");
// HERE I WOULD LIKE TO GRAB PICTURES AND SEND THEM
// PERIODICALLY TO MATLAB.
}
}
catch (GenICam::GenericException &e)
{
// Error handling
mexPrintf("\nAn exception occured:\n");
mexPrintf(e.GetDescription());
}
return;
}
You could loop and send images back to MATLAB periodically, but how do you want it to be in the workspace (multiple 2D images, a huge 3D/4D array, cell, etc.)? I think the solution you are looking for is a stateful MEX file, which can be launched with an 'init' or 'new' command, and then called again repeatedly with 'capture' commands for an already initialized camera.
There is an example of how to do this in my GitHub. Start with class_wrapper_template.cpp and modify it for your commands (new, capture, delete, etc.). Here is a rough and untested example of how the core of it might look (also mirrored on Gist.GitHub):
// pylon_mex_camera_interface.cpp
#include "mex.h"
#include <vector>
#include <map>
#include <algorithm>
#include <memory>
#include <string>
#include <sstream>
//////////////////////// BEGIN Step 1: Configuration ////////////////////////
// Include your class declarations (and PYLON API).
#include <pylon/PylonIncludes.h>
#include <pylon/usb/PylonUsbIncludes.h>
#include <pylon/usb/BaslerUsbInstantCamera.h>
#include <pylon/PylonUtilityIncludes.h>
// Define class_type for your class
typedef CBaslerUsbInstantCameraArray class_type;
// List actions
enum class Action
{
// create/destroy instance - REQUIRED
New,
Delete,
// user-specified class functionality
Capture
};
// Map string (first input argument to mexFunction) to an Action
const std::map<std::string, Action> actionTypeMap =
{
{ "new", Action::New },
{ "delete", Action::Delete },
{ "capture", Action::Capture }
}; // if no initializer list available, put declaration and inserts into mexFunction
using namespace Pylon;
using namespace Basler_UsbCameraParams;
const String_t filenames[] = { "NodeMapCam1.pfs","NodeMapCam2.pfs" };
static const size_t camerasToUse = 2;
///////////////////////// END Step 1: Configuration /////////////////////////
// boilerplate until Step 2 below
typedef unsigned int handle_type;
typedef std::pair<handle_type, std::shared_ptr<class_type>> indPtrPair_type; // or boost::shared_ptr
typedef std::map<indPtrPair_type::first_type, indPtrPair_type::second_type> instanceMap_type;
typedef indPtrPair_type::second_type instPtr_t;
// getHandle pulls the integer handle out of prhs[1]
handle_type getHandle(int nrhs, const mxArray *prhs[]);
// checkHandle gets the position in the instance table
instanceMap_type::const_iterator checkHandle(const instanceMap_type&, handle_type);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
// static storage duration object for table mapping handles to instances
static instanceMap_type instanceTab;
if (nrhs < 1 || !mxIsChar(prhs[0]))
mexErrMsgTxt("First input must be an action string ('new', 'delete', or a method name).");
char *actionCstr = mxArrayToString(prhs[0]); // convert char16_t to char
std::string actionStr(actionCstr); mxFree(actionCstr);
for (auto & c : actionStr) c = ::tolower(c); // remove this for case sensitivity
if (actionTypeMap.count(actionStr) == 0)
mexErrMsgTxt(("Unrecognized action (not in actionTypeMap): " + actionStr).c_str());
// If action is not 'new' or 'delete' try to locate an existing instance based on input handle
instPtr_t instance;
if (actionTypeMap.at(actionStr) != Action::New && actionTypeMap.at(actionStr) != Action::Delete) {
handle_type h = getHandle(nrhs, prhs);
instanceMap_type::const_iterator instIt = checkHandle(instanceTab, h);
instance = instIt->second;
}
//////// Step 2: customize each action in the switch in mexFuction ////////
switch (actionTypeMap.at(actionStr))
{
case Action::New:
{
if (nrhs > 1 && mxGetNumberOfElements(prhs[1]) != 1)
mexErrMsgTxt("Second argument (optional) must be a scalar, N.");
handle_type newHandle = instanceTab.size() ? (instanceTab.rbegin())->first + 1 : 1;
// Store a new CBaslerUsbInstantCameraArray in the instance map
std::pair<instanceMap_type::iterator, bool> insResult =
instanceTab.insert(indPtrPair_type(newHandle, std::make_shared<class_type>(camerasToUse)));
if (!insResult.second) // sanity check
mexPrintf("Oh, bad news. Tried to add an existing handle."); // shouldn't ever happen
else
mexLock(); // add to the lock count
// return the handle
plhs[0] = mxCreateDoubleScalar(insResult.first->first); // == newHandle
// Get all attached devices and exit application if no device or USB Port is found.
CTlFactory& tlFactory = CTlFactory::GetInstance();
// Check if cameras are attached
ITransportLayer *pTL = dynamic_cast<ITransportLayer*>(tlFactory.CreateTl(BaslerUsbDeviceClass));
// todo: some checking here... (pTL == NULL || pTL->EnumerateDevices(devices) == 0)
// Create and attach all Pylon Devices. Load Configuration
CBaslerUsbInstantCameraArray &cameras = *instance;
DeviceInfoList_t devices;
for (size_t i = 0; i < cameras.GetSize(); ++i) {
cameras[i].Attach(tlFactory.CreateDevice(devices[i]));
}
// Open all cameras.
cameras.Open();
// Load Configuration and execute Trigger
for (size_t i = 0; i < cameras.GetSize(); ++i) {
CFeaturePersistence::Load(filenames[i], &cameras[i].GetNodeMap());
}
if (cameras[0].IsOpen() && cameras[1].IsOpen()) {
mexPrintf("\nCameras are fired up and configuration is applied\n");
break;
}
case Action::Delete:
{
instanceMap_type::const_iterator instIt = checkHandle(instanceTab, getHandle(nrhs, prhs));
(instIt->second).close(); // may be unnecessary if d'tor does it
instanceTab.erase(instIt);
mexUnlock();
plhs[0] = mxCreateLogicalScalar(instanceTab.empty()); // just info
break;
}
case Action::Capture:
{
CBaslerUsbInstantCameraArray &cameras = *instance; // alias for the instance
// TODO: create output array and capture a frame(s) into it
plhs[0] = mxCreateNumericArray(...);
pixel_type* data = (pixel_type*) mxGetData(plhs[0]);
cameras[0].GrabOne(...,data,...);
// also for cameras[1]?
}
}
default:
mexErrMsgTxt(("Unhandled action: " + actionStr).c_str());
break;
}
//////////////////////////////// DONE! ////////////////////////////////
}
// See github for getHandle and checkHandle
The idea is that you would call it once to init:
>> h = pylon_mex_camera_interface('new');
Then you would call it in a MATLAB loop to get frames:
>> newFrame{i} = pylon_mex_camera_interface('capture', h);
When you are done:
>> pylon_mex_camera_interface('delete', h)
You should wrap this with a MATLAB class. Derive from cppclass.m to do this easily. For a derived class example see pqheap.m.
Instead of sending data to MATLAB you should make your mex file store camera related settings so that it does not initialize in each call. One way to do this is to use two modes of calls for your mex file. An 'init' call and a call to get data. Pseudo code in MATLAB would be
cameraDataPtr = myMex('init');
while ~done
data = myMex('data', cameraDataPtr);
end
In your mex file, you should store the camera settings in a memory which is persistent across calls. One way to do this is using 'new' in c++. You should return this memory pointer as an int64 type to MATLAB which is shown as cameraDataPtr in the above code. When 'data' is asked for you should take cameraDataPtr as input and cast back to your camera settings. Say in C++, you have a CameraSettings object which stores all data related to camera then, a rough pseudo code in c++ would be
if prhs[0] == 'init' { // Use mxArray api to check this
cameraDataPtr = new CameraSettings; // Initialize and setup camera
plhs[0] = createMxArray(cameraDataPtr); // Use mxArray API to create int64 from pointer
return;
} else {
// Need data
cameraDataPtr = getCameraDataPtr(plhs[1]);
// Use cameraDataPtr after checking validity to get next frame
}
This works because mex files stay in memory once loaded until you clear them. You should use mexAtExit function to release camera resource when the mex file is unloaded from memory. You could also use 'static' to store your camera settings in c++ if this is the only place your mex file is going to be used. This will avoid writing some mxArray handling code for returning your c++ pointer.
If you wrap the call to this mex file inside a MATLAB object you can control the initialization and run-time process more easily and present a better API to your users.
I ran into the same problem and wanted to use a Basler camera with the mex API in Matlab. The contributions and hints here definitely helped me to come up with some ideas. However, there is a much simpler solution than the previously proposed one. It's not necessary to return the camera pointer to Matlab back, because objects will stay in memory across multiple mex calls. Here is a working code which I programmed with the new mex C++ API. Have fun with it.
Here is the C++ File which can be compiled with mex:
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <pylon/PylonIncludes.h>
#include <pylon/usb/PylonUsbIncludes.h>
#include <pylon/usb/BaslerUsbInstantCamera.h>
#include <pylon/PylonUtilityIncludes.h>
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <chrono>
#include <string>
using namespace matlab::data;
using namespace std;
using namespace Pylon;
using namespace Basler_UsbCameraParams;
using namespace GenApi;
using namespace cv;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function{
matlab::data::ArrayFactory factory;
double Number = 0;
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
std::ostringstream stream;
Pylon::CInstantCamera* camera;
INodeMap* nodemap;
double systemTime;
double cameraTime;
public:
MexFunction(){}
void operator()(ArgumentList outputs, ArgumentList inputs) {
try {
Number = Number + 1;
if(!inputs.empty()){
matlab::data::CharArray InputKey = inputs[0];
stream << "You called: " << InputKey.toAscii() << std::endl;
displayOnMATLAB(stream);
// If "Init" is the input value
if(InputKey.toUTF16() == factory.createCharArray("Init").toUTF16()){
// Important: Has to be closed
PylonInitialize();
IPylonDevice* pDevice = CTlFactory::GetInstance().CreateFirstDevice();
camera = new CInstantCamera(pDevice);
nodemap = &camera->GetNodeMap();
camera->Open();
camera->RegisterConfiguration( new CSoftwareTriggerConfiguration, RegistrationMode_ReplaceAll, Cleanup_Delete);
CharArray DeviceInfo = factory.createCharArray(camera -> GetDeviceInfo().GetModelName().c_str());
stream << "Message: Used Camera is " << DeviceInfo.toAscii() << std::endl;
displayOnMATLAB(stream);
}
// If "Grab" is called
if(InputKey.toUTF16() == factory.createCharArray("Grab").toUTF16()){
static const uint32_t c_countOfImagesToGrab = 1;
camera -> StartGrabbing(c_countOfImagesToGrab);
CGrabResultPtr ptrGrabResult;
Mat openCvImage;
CImageFormatConverter formatConverter;
CPylonImage pylonImage;
while (camera -> IsGrabbing()) {
camera -> RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
if (ptrGrabResult->GrabSucceeded()) {
formatConverter.Convert(pylonImage, ptrGrabResult);
Mat openCvImage = cv::Mat(ptrGrabResult->GetHeight(), ptrGrabResult->GetWidth(), CV_8UC1,(uint8_t *)pylonImage.GetBuffer(), Mat::AUTO_STEP);
const size_t rows = openCvImage.rows;
const size_t cols = openCvImage.cols;
matlab::data::TypedArray<uint8_t> Yp = factory.createArray<uint8_t>({ rows, cols });
for(int i = 0 ;i < openCvImage.rows; ++i){
for(int j = 0; j < openCvImage.cols; ++j){
Yp[i][j] = openCvImage.at<uint8_t>(i,j);
}
}
outputs[0] = Yp;
}
}
}
// if "Delete"
if(InputKey.toUTF16() == factory.createCharArray("Delete").toUTF16()){
camera->Close();
PylonTerminate();
stream << "Camera instance removed" << std::endl;
displayOnMATLAB(stream);
Number = 0;
//mexUnlock();
}
}
// ----------------------------------------------------------------
stream << "Anzahl der Aufrufe bisher: " << Number << std::endl;
displayOnMATLAB(stream);
// ----------------------------------------------------------------
}
catch (const GenericException & ex) {
matlabPtr->feval(u"disp", 0, std::vector<Array>({factory.createCharArray(ex.GetDescription()) }));
}
}
void displayOnMATLAB(std::ostringstream& stream) {
// Pass stream content to MATLAB fprintf function
matlabPtr->feval(u"fprintf", 0,
std::vector<Array>({ factory.createScalar(stream.str()) }));
// Clear stream buffer
stream.str("");
}
};
This mex File can be called from Matlab with the following commands:
% Initializes the camera. The camera parameters can also be loaded here.
NameOfMexFile('Init');
% Camera image is captured and sent back to Matlab
[Image] = NameOfMexFile('Grab');
% The camera connection has to be closed.
NameOfMexFile('Delete');
Optimization and improvements of this code are welcome. There are still problems with the efficiency of the code. An image acquisition takes about 0.6 seconds. This is mainly due to the cast from a cv::mat image to a TypedArray which is necessary to return it back to Matlab. See this line in the two loops: Yp[i][j] = openCvImage.at<uint8_t>(i,j);
I have not figured out how to make this more efficient yet. Furthermore, the code cannot be used to return multiple images back to Matlab.
Maybe someone has an idea or hint to make the conversion from cv::mat to a Matlab array type faster. I already mentioned the problem in another post. See here: How to Return a Opencv image cv::mat to Matlab with the Mex C++ API

Getting error with sending SMS with AT Commands?

Please have a look at the following code:
#pragma once
using namespace System::IO::Ports;
using namespace System::Text::RegularExpressions;
using namespace System::Collections::Generic;
ref class SMS
{
public:
SMS(void);
void sendMessage();
private:
System::IO::Ports::SerialPort ^port;
};
And the cpp file
#include "StdAfx.h"
#include "SMS.h"
SMS::SMS(void)
{
//Initialize the Serial Port
port = gcnew System::IO::Ports::SerialPort();
port->PortName = "COM12";
port->BaudRate = 9600;
port->Parity = Parity::None;
port->DataBits = 8;
port->StopBits = StopBits::One;
port->Handshake = Handshake::RequestToSend;
port->DtrEnable = true;
port->RtsEnable = true;
port->NewLine = System::Environment::NewLine;
if(!port->IsOpen)
{
port->Open();
}
//Set message format
port->WriteLine("AT+CMGF=1");
//Turn off echo
port->WriteLine("ATE0");
//Set memory configurations
port->WriteLine("AT+CPMS=\"ME\",\"ME\",\"ME\"");
}
//This method will send the SMS
void SMS::sendMessage()
{
if(!port->IsOpen)
{
port->Open();
}
port->WriteLine("AT+CMGS=\"012121212\"");
port->WriteLine("Test Message From C#");
port->WriteLine(System::Convert::ToString((char)(26)));
port->Close();
}
I am trying to send SMS by accessing the dongle. The port is correct and the dongle also fine because it responded to my friend's code few hours back. What am I doing wrong here? Have I done anything incorrect with C++/CLI ? AT Commands?
try adding "CR" "LF" (Carriage Return and Line Feed characters) after each AT command, some GSM dongles (like SIM900) needem in order to work. I hope this helps
Regards
if for win32,..
prefer using
HFILE OpenFile(
LPCSTR lpFileName, // pointer to filename
LPOFSTRUCT lpReOpenBuff, // pointer to buffer for file information
UINT uStyle // action and attributes
);
with other events,...
if using SMS gateway with modem AT command capability, that's fine for direct read and write to COM port
if U using cell phone, many of this will not work. example nokia 6070, 3100 model group
best test it using hyperterminal.
I used CBuildre6 for
https://sites.google.com/site/xpressdms/rosegarden
cheer.

Serial communication timeout in C++ with Arduino

The code below is what I am using to send and receive information from my Arduino. My problem is when the Arduino is first plugged in. Reading from it hangs because the command doesn't return anything because there is nothing there yet so my whole program crashes. How can I add a time-out to the read function, which is arduino->ReadLine();, that causes the issue? That way will it keep going after a second?
#include "stdafx.h"
#include <iostream>
using namespace System;
using namespace System::IO::Ports;
int main(int argc, char* argv[])
{
using namespace std;
String^ portName;
int baudRate=9600;
portName="COM4";
// Arduino settings.
SerialPort^ arduino;
arduino = gcnew SerialPort(portName, baudRate);
// Open port.
try
{
arduino->Open();
{
if (strcmp(argv[1],"-send")==0) {
String^ command = gcnew String(reinterpret_cast<const char*>(argv[2]));
if (String::Compare(command,"int6")==0) {
arduino->Write("^");
}
else
arduino->Write(command);
}
if(strcmp(argv[1],"-get")==0) {
String^ command = gcnew String(reinterpret_cast<const char*>(argv[2]));
arduino->WriteLine(command);
String^ result = arduino->ReadLine();
Console::Write(result);
}
}
Set arduino->ReadTimeout = duration_in_ms and then catch TimeoutException.
In addition to the timeout your code should loop until the BytesToRead property of the SerialPort is greater than zero
while (arduino->BytesToRead==0) {}
You could keep track of how long you have looped and exit gracefully with a user message if there is nothing received from the arduino within the expected time frame.