#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "zmq.h"
#include "zmq_utils.h"
//#define __DEBUG__
const ssize_t data_size = 1024;
char buffer[data_size];
char unlock = 17;
char starter = 29;
char terminator = 30;
class Arduino
{
struct termios tio;
struct termios stdio;
struct termios old_stdio;
int tty_fd;
ssize_t read;
public:
Arduino()
{
tcgetattr(STDOUT_FILENO, &old_stdio);
memset(&stdio, 0, sizeof(stdio));
stdio.c_iflag = 0;
stdio.c_oflag = 0;
stdio.c_cflag = 0;
stdio.c_lflag = 0;
stdio.c_cc[VMIN] = 1;
stdio.c_cc[VTIME] = 0;
tcsetattr(STDOUT_FILENO, TCSANOW, &stdio);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio, 0, sizeof(tio));
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 5;
}
~Arduino()
{
close(tty_fd);
tcsetattr(STDOUT_FILENO, TCSANOW, &old_stdio);
}
void Connect(std::string device = "/dev/ttyACM0")
{
tty_fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
cfsetospeed(&tio, B115200); // 115200 baud
cfsetispeed(&tio, B115200); // 115200 baud
tcsetattr(tty_fd, TCSANOW, &tio);
}
ssize_t Recv(bool old = false)
{
if (old)
{
ssize_t c = ::read(tty_fd, &buffer[0], data_size);
if (c > 0)
{
return c;
}
return 0;
}
else
{
ssize_t c = ::read(tty_fd, &buffer[0], 1);
if (c == 1 && buffer[0] == starter)
{
ssize_t c = ::read(tty_fd, &buffer[1], data_size - 1);
if (c > 0)
{
return c + 1;
}
return 0;
}
return 0;
}
}
ssize_t Send(ssize_t write_size)
{
return ::write(tty_fd, &buffer[0], write_size);
}
};
class Server
{
void *context;
void *responder;
int rc;
ssize_t count;
public:
Server()
{
}
bool Start(std::string port = "5000")
{
context = zmq_ctx_new();
responder = zmq_socket(context, ZMQ_DEALER);
rc = zmq_bind(responder, (std::string("tcp://*:") + port).c_str());
return rc == 0;
}
ssize_t Recv()
{
std::cout << "Trying ZMQ_RECV...\r\n" << std::flush;
if (zmq_recv(responder, &buffer[0], 1, ZMQ_DONTWAIT) != -1)
{
std::cout << "checking buffer[0] == starter\r\n" << std::flush;
if (buffer[0] == starter)
{
std::cout << "yes, receiving other data...\r\n" << std::flush;
count = zmq_recv(responder, &buffer[0], data_size, ZMQ_DONTWAIT);
if (count == -1)
{
std::cout << "ZMQ RECV error: ";
int err =
zmq_errno();
switch (err)
{
case EAGAIN:
std::cout << "EAGAIN";
break;
case ENOTSUP:
std::cout << "ENOTSUP";
break;
case EFSM:
std::cout << "EFSM";
break;
case ETERM:
std::cout << "ETERM";
break;
case ENOTSOCK:
std::cout << "ENOTSOCK";
break;
case EINTR:
std::cout << "EINTR";
break;
case EFAULT:
std::cout << "EFAULT";
break;
}
std::cout << "\r\n" << std::flush;
return 0;
}else
if (count > 0)
{
std::cout << "...OK\r\n" << std::flush;
return count + 1;
}
else
{
std::cout << "FAIL 1\r\n" << std::flush;
return 0;
}
}
std::cout << "FAIL 2\r\n" << std::flush;
return 0;
}
return 0;
}
bool Send(ssize_t size)
{
if (zmq_send(responder, &buffer[0], size, ZMQ_DONTWAIT) == -1)
{
//std::cout << "ZMQ SEND error: ";
//int err =
//zmq_errno();
/*switch (err)
{
case EAGAIN:
std::cout << "EAGAIN";
break;
case ENOTSUP:
std::cout << "ENOTSUP";
break;
case EFSM:
std::cout << "EFSM";
break;
case ETERM:
std::cout << "ETERM";
break;
case ENOTSOCK:
std::cout << "ENOTSOCK";
break;
case EINTR:
std::cout << "EINTR";
break;
case EFAULT:
std::cout << "EFAULT";
break;
}
std::cout << "\r\n" << std::flush;*/
return false;
}
return true;
}
};
void SleepMs(int ms)
{
usleep(ms * 1000); //convert to microseconds
}
void UnlockArduino(Arduino& ACM0)
{
buffer[0] = starter;
buffer[1] = 0;
buffer[2] = unlock;
buffer[3] = unlock;
buffer[4] = unlock;
buffer[5] = unlock;
buffer[6] = terminator;
ACM0.Send(7);
}
int main()
{
memset(&buffer[0], 0, sizeof(buffer));
ssize_t count = 0;
//setup arduino and server
Arduino ACM0;
Server Svr;
//connect to arduino and start server
ACM0.Connect();
//send startup code
UnlockArduino(ACM0);
SleepMs(35);
bool status = true;
char CODE_OK[16] = { 'U', 'N', 'L', 'O', 'C', 'K', 'O', 'K', '-', '5', 'A', 'E', '3', 'C', '2' };
while (status)
{
//std::cout << "Trying Recv...\r\n" << std::flush;
count = ACM0.Recv(true);
if (count >= 15)
{
//std::cout << "Received...\r\n" << std::flush;
status = false;
if (std::string(buffer,15).compare(std::string(CODE_OK,15)) == 0)
{
}
else
{
status = true;
}
std::cout << buffer << std::flush;
//std::cout << "\r\nStatus:" << status << "\r\n" << std::flush;
}
SleepMs(75);
if (status)
{
UnlockArduino(ACM0);
}
SleepMs(75);
}
//std::cout << "Received UNLOCK == OK Signal\r\n" << std::flush;
if (Svr.Start("5000"))
{
//infinite loop
while (true)
{
//check if arduino has data to send
count = ACM0.Recv();
if (count > 0)
{
std::cout << "SENDING: [" << std::hex << (int)buffer[0] << "|"
<< std::hex << (int)buffer[1] << "|"
<< std::hex << (int)buffer[2] << "|"
<< std::hex << (int)buffer[3] << "|"
<< std::hex << (int)buffer[4] << "|"
<< std::hex << (int)buffer[5] << "|"
<< std::hex << (int)buffer[6] << "]" << "\r\n" << std::flush;
//if yes send to laptop
Svr.Send(count);
}
//check if laptop has data to send to arduino
count = Svr.Recv();
if (count > 0)
{
std::cout << "RECEIVED: [" << std::hex << (int)buffer[0] << "|"
<< std::hex << (int)buffer[1] << "|"
<< std::hex << (int)buffer[2] << "|"
<< std::hex << (int)buffer[3] << "|"
<< std::hex << (int)buffer[4] << "|"
<< std::hex << (int)buffer[5] << "|"
<< std::hex << (int)buffer[6] << "]" << "\r\n" << std::flush;
//if yes do it
ACM0.Send(count);
}
SleepMs(250);
}
}
return EXIT_SUCCESS;
}