back-and-forth unix domain sockets lock - python

I am writing two programs one in c++ and the other in Python to communicate with each other using unix domain sockets. What I am trying to do is have c++ code send a number to the python code, which in turn send another number back to c++. This goes on till c++ code runs out of numbers to send and the execution stops. Below are my codes. I can't seem to run them past the first iteration of the loop.
I run Python first:
python code.py /tmp/1 /tmp/2
Then I run the c++ code:
./code /tmp/1 /tmp/2
Here is the output:
C++ output:
sent 0
Listening
Connection successful
received 5
sent 1
Listening
Python output:
listening ...
received (0,)
>5
sent 5
listening ...
C++ Code:
static int connFd;
int main(int argc, char* argv[])
{
int recv_sock,
send_sock;
struct sockaddr_un server, client;
///////////////////////////////////////////
//
// setup send
//
///////////////////////////////////////////
/* Create socket on which to send. */
send_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (send_sock < 0)
{
perror("opening unix socket");
exit(1);
}
/* Construct name of socket to send to. */
client.sun_family = AF_UNIX;
strcpy(client.sun_path, argv[1]);
if (connect(send_sock, (struct sockaddr *) &client, sizeof(struct sockaddr_un)) < 0)
{
close(send_sock);
perror("connecting stream socket");
exit(1);
}
///////////////////////////////////////////
//
// setup recv
//
///////////////////////////////////////////
recv_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(recv_sock< 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char*) &server, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[2]);
//bind socket
if(bind(recv_sock, (struct sockaddr *)&server, sizeof(server)) < 0)
{
cerr << "Cannot bind" << endl;
return 0;
}
listen(recv_sock, 10);
int X;
for (int i = 0; i < 10; i++)
{
write(send_sock, &i, sizeof(i));
cout << "sent " << i << endl;
cout << "Listening" << endl;
connFd = accept(recv_sock, 0, 0);
if (connFd < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
cout << "Connection successful" << endl;
read(connFd, &X, sizeof(X));
cout << "received " << X << endl;
}
usleep(2000000);
}
close(send_sock);
close(recv_sock);
unlink(argv[2]);
unlink(argv[1]);
return 0;
}
Python Code:
import socket,os,struct, glob, sys
import random
send_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
recv_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(sys.argv[1])
except OSError:
pass
recv_socket.bind(sys.argv[1])
recv_socket.listen(10)
while 1:
print "listening ..."
conn, addr = recv_socket.accept()
data = conn.recv(4)
p = struct.unpack('i',data)
print 'received ', p
if p is '9':
break
l = int(raw_input(">"))
a = struct.pack('i', l)
send_socket.connect(sys.argv[2])
send_socket.sendall(a)
print 'sent ', l
send_socket.close()
conn.close()
recv_socket.close()
What am I doing wrong in this approach? Do I need to use threads?
Thanks

You handle differently the send and receive sockets in your C++ code: the send socket is bound once at the start of the program whereas the receive socket accepts a new connection at each iteration.
Your current Python implementation accepts a new connection on recv_socket and connects send_socket at each iteration which explains the issue that you are facing.
The most efficient fix would be to connect each socket once prior to the loop unless you have a good reason to open a new connection at each iteration. Here are the corresponding code listings:
C++
static int connFd;
int main(int argc, char *argv[]) {
int recv_sock, send_sock;
struct sockaddr_un server, client;
///////////////////////////////////////////
//
// setup send
//
///////////////////////////////////////////
/* Create socket on which to send. */
send_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (send_sock < 0) {
perror("opening unix socket");
exit(1);
}
/* Construct name of socket to send to. */
client.sun_family = AF_UNIX;
strcpy(client.sun_path, argv[1]);
if (connect(send_sock, (struct sockaddr *)&client,
sizeof(struct sockaddr_un)) < 0) {
close(send_sock);
perror("connecting stream socket");
exit(1);
}
///////////////////////////////////////////
//
// setup recv
//
///////////////////////////////////////////
recv_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (recv_sock < 0) {
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char *)&server, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[2]);
// bind socket
if (::bind(recv_sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
cerr << "Cannot bind" << endl;
return 0;
}
listen(recv_sock, 10);
connFd = accept(recv_sock, 0, 0);
if (connFd < 0) {
cerr << "Cannot accept connection" << endl;
return 0;
} else {
cout << "Connection successful" << endl;
}
int X;
for (int i = 0; i < 10; i++) {
write(send_sock, &i, sizeof(i));
cout << "sent " << i << endl;
cout << "Listening" << endl;
read(connFd, &X, sizeof(X));
cout << "received " << X << endl;
usleep(2000000);
}
close(send_sock);
close(recv_sock);
unlink(argv[2]);
unlink(argv[1]);
return 0;
}
Python
recv_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
send_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(sys.argv[1])
except OSError:
pass
recv_socket.bind(sys.argv[1])
recv_socket.listen(10)
conn, addr = recv_socket.accept()
send_socket.connect(sys.argv[2])
while 1:
print "listening ..."
data = conn.recv(4)
p = struct.unpack('i',data)
print 'received ', p
if p is '9':
break
l = int(raw_input(">"))
a = struct.pack('i', l)
send_socket.sendall(a)
print 'sent ', l
send_socket.close()
conn.close()
recv_socket.close()

Related

C6011 in C++ and Python project

I am in my third CS class online and I have done ok until now but I am really struggling with this. My code runs fine through the menu and input validation just fine but then as soon as I call a function from the python file I get the dereferencing null pointer message as follows " EXCEPTION UNHANDLED: Unhandled exception at 0x1DD09F27 (python36.dll) in moduleSixCppAndPython.exe: 0xC0000005: Access violation reading location 0x00000004. occurred".
I'm going to try to include my c++ code so forgive me if i mess this it up.. this is my first time using stackoverflow. the sections underlined in my IDE are the line as follows:
pFunc = PyDict_GetItemString(pDict, procname); // this one get like a red X next to it
...
Py_DECREF(pValue); // this line is underlined
all issues are coming from the "int callIntFunc(string proc, int param)" funtion
main is not really finished yet so i'm not super concerned with that unless that's where my problem is coming from...
any guidance at all would be very greatly appreciated!
#include <Python.h>
#include <iostream>
#include <Windows.h>
#include <cmath>
#include <string>
#include <conio.h>
using namespace std;
bool CONTINUE_RUN = true;
int displayMenu() {
int userInput = 0;
while (true) {
cout << "1: Display a Multiplication Table" << endl;
cout << "2: Double a Value" << endl;
cout << "3: Exit" << endl;
cout << "Enter your selection as a number 1, 2, or 3." << endl;
while (!(cin >> userInput)) {
system("cls");
cout << "ERROR: Please enter 1, 2, or 3" << endl;
cout << "1: Display a Multiplication Table" << endl;
cout << "2: Double a Value" << endl;
cout << "3: Exit" << endl;
cout << "Enter your selection as a number 1, 2, or 3." << endl;
cin.clear();
cin.ignore(123, '\n');
}
if (userInput == 1) {
break;
}
if (userInput == 2) {
break;
}
if (userInput == 3) {
CONTINUE_RUN = false;
break;
}
else {
system("cls");
cout << "ERROR: Please enter 1, 2, or 3" << endl;
continue;
}
}
return userInput;
}
int userData() {
int pickNum;
system("cls");
cout << "Please enter an integer: " << endl;
while (!(cin >> pickNum)) {
system("cls");
cout << "ERROR: Please enter an INTEGER:";
cin.clear();
cin.ignore(123, '\n');
}
return pickNum;
}
int callIntFunc(string proc, int param)
{
char* procname = new char[proc.length() + 1];
std::strcpy(procname, proc.c_str());
PyObject* pName, * pModule, * pDict, * pFunc, * pValue = nullptr, * presult = nullptr;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyUnicode_FromString((char*)"PythonCode");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, procname);
if (PyCallable_Check(pFunc))
{
pValue = Py_BuildValue("(i)", param);
PyErr_Print();
presult = PyObject_CallObject(pFunc, pValue);
PyErr_Print();
}
else
{
PyErr_Print();
}
//printf("Result is %d\n", _PyLong_AsInt(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
// clean
delete[] procname;
return _PyLong_AsInt(presult);
}
int main(){
while (CONTINUE_RUN == true) {
int userNumber = 0;
int menuValue = displayMenu();
if (menuValue == 1) {
userNumber = userData();
system("cls");
int token = callIntFunc("MultiplicationTable", userNumber);
cout << "Press any key to continue" << endl;
_getch();
}
if (menuValue == 2) {
userNumber = userData();
system("cls");
cout << callIntFunc("DoubleValue", userNumber);
cout << "Press any key to continue" << endl;
_getch();
}
}
cout << "GOODBYE" << endl;
}
OK so a big THANK YOU to #PaulMcKenzie in the comments for pointing me in the right direction...
Turns out the issue was not in my .cpp file but in fact in the .py file that it was reading.
I had used the Python syntax :
print(namedVariable + "someString" + (evaluatedCalculation))
Now while this was technically correct for some instances it was creating unpredictable results when passed from my .py file back to my .cpp file. The error was flagging in my .cpp file so the real error that was made was that. I had tunnel vision in trying to find the error solely in the .cpp file and not anywhere else. PLEASE forgive a rookie of his rookie mistake here !
To fix this, I altered the syntax in my .py file to :
print(namedVariable, "someString", (evaluatedCalculation))
The true error here was not just in the logic I applied in writing my Python code... but in the logic I applied in finding the source of my error.
I learned much more in finding the flaw in my thinking than I did in finding the flaw in this code. But hey.. live and learn right?
Anyway,
happy coding !
Love and Respect !

Embedded Python in C++ cannot import pandas twice

I'm embedding Python 3.8.2 in C++ code (using Visual Studio 2019). Python has pandasn installed (through pip).
I manage to import pandas from a C++ program, however, when I try to import it a second time, it crashs.
#include <Python.h>
#include <iostream>
int main( int argc, char* argv[] )
{
{
Py_SetPythonHome( L"C:\\Python38" );
// Initialize the Python Interpreter
Py_Initialize();
std::cout << "Importing pandas..." << std::endl;
if ( PyRun_SimpleString( "import pandas" ) == 0 )
std::cout << "SUCCESS" << std::endl;
else
std::cout << "FAIL" << std::endl;
Py_Finalize();
}
{
Py_SetPythonHome( L"C:\\Python38" );
// Initialize the Python Interpreter
Py_Initialize();
std::cout << "Importing pandas..." << std::endl;
if ( PyRun_SimpleString( "import pandas" ) == 0 )
std::cout << "SUCCESS" << std::endl;
else
std::cout << "FAIL" << std::endl;
Py_Finalize();
}
return 0;
}
This crashs with an exception:
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b8ca69() Inconnu
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b8ffd6() Inconnu
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b9d34d() Inconnu
python38.dll!00007ffbd22f6131() Inconnu
python38.dll!00007ffbd22f6092() Inconnu
Output is:
Importing pandas...
SUCCESS
Importing pandas...
Traceback (most recent call last):
File "<string>", line 1, in <module>
Is there any init/uninit step I missed that could make this fail while it shaould work?
Note that I cannot Debug as pandas cannot be loaded in Debug build.
Upon request from OP, I made a small demo for how we wrap user Python scripts in our application to prevent that global variables of user scripts become unintended persistent:
#include <iostream>
#include <string>
#include <Python.h>
const char *PyScript = R"(try:
print(a)
except:
print("a not (yet) defined")
a = 123
print(a)
)";
std::string wrapPyScript(const char* script)
{
std::string source = std::string("def __mainPythonFunction():\n") + script;
{ const char *const indent = "\n ";
for (size_t i = source.size(); i--;) {
size_t n = 1;
switch (source[i]) {
case '\n': if (i && source[i - 1] == '\r') n = 2, --i;
case '\r': source.replace(i, n, indent); break;
}
}
}
source += "\n"
"pass\n"
"\n"
"try:\n"
" __mainPythonFunction()\n"
"except:\n"
" rf.form.appContext.notifyAbort()\n"
" raise\n";
return source;
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Py_Initialize());
std::cout << "\nWithout wrapper:\n\n";
DEBUG(for (int i = 0; i < 2; ++i) {
DEBUG(PyRun_SimpleString(PyScript));
});
std::cout << "\nWith wrapper:\n\n";
DEBUG(for (int i = 0; i < 2; ++i) {
DEBUG(PyRun_SimpleString(wrapPyScript(PyScript).c_str()));
});
std::cout << '\n';
DEBUG(Py_Finalize());
}
Output:
Py_Initialize();
Without wrapper:
for (int i = 0; i < 2; ++i) { DEBUG(PyRun_SimpleString(PyScript)); };
PyRun_SimpleString(PyScript);
a not (yet) defined
123
PyRun_SimpleString(PyScript);
123
123
With wrapper:
for (int i = 0; i < 2; ++i) { DEBUG(PyRun_SimpleString(wrapPyScript(PyScript).c_str())); };
PyRun_SimpleString(wrapPyScript(PyScript).c_str());
a not (yet) defined
123
PyRun_SimpleString(wrapPyScript(PyScript).c_str());
a not (yet) defined
123
Py_Finalize();
However, I'm not quite sure whether this is enough to fix OPs issue with the imported Pandas library.
In our application (where we used the above trick), we import selected libraries once after the Py_Initialize().
(I remember roughly that this was our last desperate resort to fix similar issues like OP observed.)

How to setup a Pub/Sub in nanomsg between a C and Python sides?

I'm trying to learn the nanomsg library.
I'm using the code examples of both versions C and Python. I'm trying to subscribe to the C service with a Python script, but nothing is happening.
Here's both of my code :
Python subscriber
from __future__ import print_function
from nanomsg import Socket, PAIR, PUB
s2 = Socket(PAIR)
while(True):
s2.connect('tcp://127.0.0.1:5555')
s2.send(b'hello nanomsg #1')
s2.send(b'hello nanomsg #2')
s2.close()
C code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netinet/in.h> /* For htonl and ntohl */
#include <unistd.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
/* The server runs forever. */
int server(const char *url)
{
int fd;
/* Create the socket. */
fd = nn_socket (AF_SP, NN_PUB);
if (fd < 0) {
fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
return (-1);
}
/* Bind to the URL. This will bind to the address and listen
synchronously; new clients will be accepted asynchronously
without further action from the calling program. */
if (nn_bind (fd, url) < 0) {
fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ()));
nn_close (fd);
return (-1);
}
/* Now we can just publish results. Note that there is no explicit
accept required. We just start writing the information. */
for (;;) {
uint8_t msg[2 * sizeof (uint32_t)];
uint32_t secs, subs;
int rc;
secs = (uint32_t) time (NULL);
subs = (uint32_t) nn_get_statistic (fd, NN_STAT_CURRENT_CONNECTIONS);
secs = htonl (secs);
subs = htonl (subs);
memcpy (msg, &secs, sizeof (secs));
memcpy (msg + sizeof (secs), &subs, sizeof (subs));
rc = nn_send (fd, msg, sizeof (msg), 0);
if (rc < 0) {
/* There are several legitimate reasons this can fail.
We note them for debugging purposes, but then ignore
otherwise. */
fprintf (stderr, "nn_send: %s (ignoring)\n",
nn_strerror (nn_errno ()));
}
sleep(10);
}
/* NOTREACHED */
nn_close (fd);
return (-1);
}
/* The client runs in a loop, displaying the content. */
int client (const char *url)
{
int fd;
int rc;
fd = nn_socket (AF_SP, NN_SUB);
if (fd < 0) {
fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
return (-1);
}
if (nn_connect (fd, url) < 0) {
fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
nn_close (fd);
return (-1);
}
/* We want all messages, so just subscribe to the empty value. */
if (nn_setsockopt (fd, NN_SUB, NN_SUB_SUBSCRIBE, "", 0) < 0) {
fprintf (stderr, "nn_setsockopt: %s\n", nn_strerror (nn_errno ()));
nn_close (fd);
return (-1);
}
for (;;) {
uint8_t msg[2 * sizeof (uint32_t)];
char hhmmss[9]; /* HH:MM:SS\0 */
uint32_t subs, secs;
time_t t;
rc = nn_recv (fd, msg, sizeof (msg), 0);
if (rc < 0) {
fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ()));
break;
}
if (rc != sizeof (msg)) {
fprintf (stderr, "nn_recv: got %d bytes, wanted %d\n",
rc, (int)sizeof (msg));
break;
}
memcpy (&secs, msg, sizeof (secs));
memcpy (&subs, msg + sizeof (secs), sizeof (subs));
t = (time_t) ntohl(secs);
strftime (hhmmss, sizeof (hhmmss), "%T", localtime (&t));
printf ("%s <pid %u> There are %u clients connected.\n", hhmmss,
(unsigned) getpid(), (unsigned) ntohl(subs));
}
nn_close (fd);
return (-1);
}
int main (int argc, char **argv)
{
int rc;
if ((argc == 3) && (strcmp (argv[2], "-s") == 0)) {
rc = server (argv[1]);
} else if (argc == 2) {
rc = client (argv[1]);
} else {
fprintf (stderr, "Usage: %s <url> [-s]\n", argv[0]);
exit (EXIT_FAILURE);
}
exit (rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
I run the C code by doing
./pubsub_demo tcp://127.0.0.1:5555 -s
Thanks for your help
The C code looks good. It comes from here.
A simpler version of C NN_PUB server and NN_SUB client also exists.
There are a few problems with presented the Python code.
1) In nanomsg we have to match behavioural-"protocols". In order to receive a NN_PUB broadcast from the C server, we have to have a matching SUB, not a PAIR, socket on the Python side.
2) Connect to the same endpoint-transport-class://address:port as NN_PUB socket nn_bind()-s to. There is no need to do it in the loop.
3) The socket has to have SUB_SUBSCRIBE option set.
4) SUB socket is for listening, it is not designed to .send() anything.
An untested Python program may look in-principle as follows:
# import appropriate modules for the nanomsg socket
from nanomsg import Socket, PUB, SUB, SUB_SUBSCRIBE
# open Python's SUB socket matching the NN_PUB socket on the C side
s2 = Socket(SUB)
# s2 should be >= 0
# connect the socket to the same endpoint as NN_PUB server
ret1 = s2.connect('tcp://127.0.0.1:5555')
# ret1 should be 0
# subscribe to everything:
ret2 = s2.set_string_option(SUB, SUB_SUBSCRIBE, '')
# ret1 should be 0
# receive messages:
while(True):
message = s2.recv()
You can also look at Python test PUB/SUB example
I hope it helps.

C++ program crashing on Python script call

I am attempting to send a command that runs a specific python script: however, whenever the program reaches the execution line, this occurs:
Unhandled exception at 0x69bd1f16 in GameServer.exe: 0xC0000005: Access violation reading location 0x46f520ca.
The program stops resonding and crashes. Here is the method in question:
void ScriptManager::runScript(std::string scriptName, std::string args[])
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(int i = 0; i < args->length(); i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
This calls the above function:
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
std::string data[] = {username, password};
script.runScript("Python.py", data);
}
The script does not run, as far as I know. I can also post the script if it would help.
This is the problem:
for (int i = 0; i < args->length(); i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
args->length() is equivalent to args[0].length(); i.e. you're taking the length of the first string in the array and using that as an index. After two iterations pass, you're going to access past the end of the array. The best solutions are(all examples are UNTESTED):
Use an std::array(C++11 only):
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
script.runScript("Python.py", {username, password});
}
void ScriptManager::runScript(std::string scriptName, std::array<std::string, 2> args)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for (std::string s : args)
{
py += " " + s;
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
Use an std::vector(the example uses C++03):
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
int tmp[2] = {username, password};
script.runScript("Python.py", std::vector<std::string>(&tmp[0], &tmp[0]+2));
}
void ScriptManager::runScript(std::string scriptName, std::vector<std::string> args)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(std::vector<std::string>::iterator it = args.begin(); it != args.end(); it++)
{
py += " " + *it;
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
Pass the array size as a parameter:
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
script.runScript("Python.py", {username, password}, 2);
}
void ScriptManager::runScript(std::string scriptName, std::string args[], int size)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(int i=0; i<size; i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
I personally prefer example 1 and would avoid example 3 like the plague. Example 2 works well but probably isn't as fast as example 1.

Rate-limiting in python/arduino client/server communication

I'm trying to make a python client communicate with an arduino server. The python client asks the server to take a measurement from the sonar, and then server just sends a confirmation message and then takes the message.
The client:
client.py
import socket
import time
while True:
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("192.168.0.250", 10220))
data = "GET\nSONAR\n\n"
print 'send to server: ' + data
client_socket.send(data)
receive = client_socket.recv(2048)
print receive
client_socket.close()
time.sleep(0.1)
except Exception as msg:
print msg
and the server:
server.ino
#include <avr/wdt.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
//localClient parameters, for sending data to the server.
byte mac[] = {0x90, 0xA2, 0xDA, 0x0F, 0x03, 0x58};
byte ip[] = {192,168,0,250};
byte server[] = {192, 168, 0, 100};
int serverPort = 8220;
//Server parameters, for acting like a server.
int pollPort = serverPort + 2000;
EthernetServer pollServer = EthernetServer(pollPort);
//char inString[32]; // string for incoming serial data
//sonar stuff
String content_string;
int NUM_SONARS = 1;
int sonarPin[] = {2, 3, 4, 5};
int triggerPin = 6;
int sonarThreshold = 12.0;
int sonarState[] = {0, 0, 0, 0};
long pulse;
int numPulses = 3;
int pulseArray[] = {0,0,0,0,0};
int filteredMode = 0;
float time;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
wdt_enable(WDTO_8S);
pollServer.begin();
for(int i = 0; i < NUM_SONARS; i++) {
pinMode(sonarPin[i], INPUT);
}
pinMode(triggerPin, OUTPUT);
digitalWrite(triggerPin, LOW);
time = 0;
}
void loop() {
wdt_reset();
time = millis();
EthernetClient pollClient = pollServer.available();
if (pollClient) {
boolean currentLineIsBlank = true;
String receivingString = "";
while (pollClient.connected()) {
//while the socket is open
if(pollClient.available()) {
//and there is something to read on the port, then read the available characters
char c = pollClient.read();
receivingString += c;
if (c == '\n' && currentLineIsBlank) {
Serial.print("String received -- ");
Serial.print(receivingString);
Serial.print("at ");
Serial.println(time);
pollClient.println("Received message.");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// parse the incoming data
String command = split(receivingString,'\n',0);
String payload = split(receivingString,'\n',1);
String key = split(payload,'=',0);
String value = split(payload,'=',1);
//PARSE THE KEY AND VALUE NOW
if(command == "GET") {
//if I received a GET command, send a response to the client.
if(key == "SONAR") {
pingSonars();
}
}
}
String split(String data, char delimiter, int index) {
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==delimiter || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void isort(int *a, int n) {
for (int i = 1; i < n; ++i) {
int j = a[i];
int k;
for (k = i - 1; (k >= 0) && (j < a[k]); k--) {
a[k + 1] = a[k];
}
a[k + 1] = j;
}
}
int mode(int *x,int n){
int i = 0;
int count = 0;
int maxCount = 0;
int mode = 0;
int bimodal;
int prevCount = 0;
while(i<(n-1)){
prevCount=count;
count=0;
while(x[i]==x[i+1]){
count++;
i++;
}
if(count>prevCount&count>maxCount){
mode=x[i];
maxCount=count;
bimodal=0;
}
if(count==0){
i++;
}
if(count==maxCount){//If the dataset has 2 or more modes.
bimodal=1;
}
if(mode==0||bimodal==1){//Return the median if there is no mode.
mode=x[(n/2)];
}
return mode;
}
}
void printArray(int *a, int n) {
for (int i = 0; i < n; i++)
{
Serial.print(a[i], DEC);
Serial.print(' ');
}
Serial.println();
}
void pingSonars() {
digitalWrite(6, HIGH);
for(int i = 0; i < NUM_SONARS; i++) {
for(int j = 0; j < numPulses; j++) {
pulse = pulseIn(sonarPin[i], HIGH);
pulseArray[j] = pulse/147; //convert to inches -- 147 uS per inches
delay(5);
}
isort(pulseArray, numPulses);
filteredMode = mode(pulseArray,numPulses);
//printArray(pulseArray,numPulses);
Serial.print("Filtered distance for Sonar ");
Serial.print(i);
Serial.print(": ");
Serial.println(filteredMode);
if((filteredMode < sonarThreshold) && !sonarState[i]) {
//if we are closer than the threshold and previously were not, this is a rising edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" triggered!");
sonarState[i] = 1;
}
else if (filteredMode > sonarThreshold && sonarState[i]) {
//if we are greater than the threshold and previously were, this is a falling edge:
Serial.print("Sonar ");
Serial.print(i);
Serial.println(" falling!");
sonarState[i] = 0;
}
}
}
The client sends requests at about a 100 millisecond interval, but the server seems to be able to respond much slower than that -- maybe at 2-3 times per second. What's limiting the rate of communication? Is it possible that the serial printouts are actually limiting it? Or does it have to do with how I'm opening/closing/listening to the port in the server code?
thanks for your help!

Categories