Read arduino Serial.Write with C# - c#

I have an Arduino that send on serial port some information revealed by analogical pin. Anyway, in the Arduino code (that I can not modify) is used Serial.write() instead of Serial.print() in order to print a buffer of char. As a consequence, if in my C# software I read the information with a "simple" ReadLine(), the data are incomprehensible. How can I read these type of data with C#?
It is the Arduino code:
#include <compat/deprecated.h>
#include <FlexiTimer2.h>
#define TIMER2VAL (1024/256) // 256Hz - frequency
volatile unsigned char myBuff[8];
volatile unsigned char c=0;
volatile unsigned int myRead=0;
volatile unsigned char mych=0;
volatile unsigned char i;
void setup() {
pinMode(9, OUTPUT);
noInterrupts();
myBuff[0] = 0xa5; //START 0
myBuff[1] = 0x5a; //START 1
myBuff[2] = 2; //myInformation
myBuff[3] = 0; //COUNTER
myBuff[4] = 0x02; //CH1 HB
myBuff[5] = 0x00; //CH1 LB
myBuff[6] = 0x02; //CH2 HB
myBuff[7] = 0x00; //CH2 LB
myBuff[8] = 0x01; //END
FlexiTimer2::set(TIMER2VAL, Timer2);
FlexiTimer2::start();
Serial.begin(57600);
interrupts();
}
void Timer2()
{
for(mych=0;mych<2;mych++){
myRead= analogRead(mych);
myBuff[4+mych] = ((unsigned char)((myRead & 0xFF00) >> 8)); // Write HB
myBuff[5+mych] = ((unsigned char)(myRead & 0x00FF)); // Write LB
}
// SEND
for(i=0;i<8;i++){
Serial.write(myBuff[i]);
}
myBuff[3]++;
}
void loop() {
__asm__ __volatile__ ("sleep");
}
And this is the C# method that read from serial port
public void StartRead()
{
msp.Open(); //Open the serial port
while (!t_suspend)
{
i++;
String r = msp.ReadLine();
Console.WriteLine(i + ": " + r);
}
}
EDIT: I would as output an array of string that correspond to the data of Arduino output. If I record everything as an array of byte, I have not the information about start and the end of the array.
I can edit the code as:
public void StartRead()
{
msp.Open(); //Open the serial port
ASCIIEncoding ascii = new ASCIIEncoding();
while (!t_suspend)
{
i++;
int r = msp.ReadByte();
String s = ascii.getString((byte)r); // here there is an error, it require an array byte[] and not a single byte
Console.WriteLine(i + ": " + r);
}
}
How I can have the same Arduino array value (but as a String) in my C# software, considering that the starting value is every time 0xa5 and the end is 0x01.

Arduino sends a telegram of several bytes. You can read it into a byte array:
byte[] telegram = byte[msp.BytesToRead];
msp.Read(telegram, 0, msp.BytesToRead);
To get the data from the byte array you have to interpret the bytes (See example below).
Of course you could create a string from the properties of the Telegram class:
class Telegram {
public Telegram(byte[] tel) {
// Check start bytes ( 0xa5, 0x5a );
Info = tel[2];
Counter = tel[3];
Channel1 = BitConverter.ToInt16(new byte[] { tel[5], tel[4] }, 0); // Switch lo/hi byte
Channel2 = BitConverter.ToInt16(new byte[] { tel[7], tel[6] }, 0);// Switch lo/hi byte
// check tel[8] == 1 for end of telegram
}
public int Info { get; private set; }
public int Counter { get; private set; }
public int Channel1 { get; private set; }
public int Channel2 { get; private set; }
}

Related

How to stream back audio using External Media Channel using ARI in asterisk

Working with AsterNET.ARI I am able to expose audio stream from asterisk, using ExternalMedia.
Scenario:
Call is started and Stasis App is invoked
Create ExternalMediaChannel that sends stream to a RTP server I created listening from all IPs in Port: 7777.
Create bridge type mixing and add both channels in it
The goal is to send back this stream to this channel that normally should be heared in the originator channel since both channels are in the same bridge.
It looks like the RTP is sent back and received by asterisk but however I'm not able to hear it.
ARI ExternMediaChannel:
{"UNICASTRTP_LOCAL_PORT":"15672","UNICASTRTP_LOCAL_ADDRESS":"172.18.33.220"}
Asterisk
Got RTP packet from 10.114.0.234:55874 (type 111, seq 031742, ts 3934092822, len 000069)
Sent RTP packet to 172.18.33.220:7777 (type 118, seq 029097, ts 1090576, len 000640)
Got RTP packet from 10.114.0.234:55874 (type 111, seq 031743, ts 3934093782, len 000071)
Sent RTP packet to 172.18.33.220:7777 (type 118, seq 029098, ts 1090896, len 000640)
RTP Server
Sending To: 172.18.33.220:15672
Received From: 172.18.33.220:15672
Sending To: 172.18.33.220:15672
Received From: 172.18.33.220:15672
I can actually print the byte codes received and I know it's the audio because I have saved the byte codes to file and played the file successfully.
How I am receiving and trying to send the stream back (RTP Server):
public class UDPListener
{
private const int ListenPort = 7777;
public static void StartListener()
{
UdpClient server = new UdpClient(ListenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, ListenPort);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
Console.WriteLine("Listening to: " + ListenPort);
while (true)
{
byte[] bytes = server.Receive(ref groupEP);
// PRINTS THE BYTE CODES
// Console.WriteLine($" {Encoding.ASCII.GetString(bytes, 0, bytes.Length)}");
RtpPacket rcvpacket;
bool parsedRCV = RtpPacket.TryParse(bytes, out rcvpacket);
if(parsedRCV){
Console.WriteLine($"Received From: {groupEP.Address}:{groupEP.Port}");
}
RtpPacket packet;
bool parsed = RtpPacket.TryParse(bytes, out packet);
if(parsed){
Console.WriteLine($"Sending To: {groupEP.Address}:{groupEP.Port}");
client.SendTo(packet.PayloadSegment, groupEP);
}
}
}
}
}
RtpPacket is a C# class that represents the definition of a RTP packet.
struct RtpPacket
{
public const int RtpHeaderSize = 12;
public const int RtpProtocolVersion = 2;
public int ProtocolVersion { get; private set; }
public bool PaddingFlag { get; private set; }
public bool ExtensionFlag { get; private set; }
public int CsrcCount { get; private set; }
public bool MarkerBit { get; private set; }
public int PayloadType { get; private set; }
public ushort SeqNumber { get; private set; }
public uint Timestamp { get; private set; }
public uint SyncSourceId { get; private set; }
public int ExtensionHeaderId { get; private set; }
public ArraySegment<byte> PayloadSegment { get; set; }
internal RtpPacket(ushort seqNumber, ArraySegment<byte> payloadSegment)
{
ProtocolVersion = 1;
PaddingFlag = false;
ExtensionFlag = false;
CsrcCount = 0;
MarkerBit = false;
PayloadType = 0;
SeqNumber = 0;
Timestamp = 0;
SyncSourceId = 0;
ExtensionHeaderId = 0;
SeqNumber = seqNumber;
PayloadSegment = payloadSegment;
}
public static bool TryParse(ArraySegment<byte> byteSegment, out RtpPacket rtpPacket)
{
rtpPacket = new RtpPacket();
Debug.Assert(byteSegment.Array != null, "byteSegment.Array != null");
if (byteSegment.Count < RtpHeaderSize)
return false;
int offset = byteSegment.Offset;
rtpPacket.ProtocolVersion = byteSegment.Array[offset] >> 6;
if (rtpPacket.ProtocolVersion != RtpProtocolVersion)
return false;
rtpPacket.PaddingFlag = (byteSegment.Array[offset] >> 5 & 1) != 0;
rtpPacket.ExtensionFlag = (byteSegment.Array[offset] >> 4 & 1) != 0;
rtpPacket.CsrcCount = byteSegment.Array[offset++] & 0xF;
rtpPacket.MarkerBit = byteSegment.Array[offset] >> 7 != 0;
rtpPacket.PayloadType = byteSegment.Array[offset++] & 0x7F;
rtpPacket.SeqNumber = (ushort)BigEndianConverter.ReadUInt16(byteSegment.Array, offset);
offset += 2;
rtpPacket.Timestamp = BigEndianConverter.ReadUInt32(byteSegment.Array, offset);
offset += 4;
rtpPacket.SyncSourceId = BigEndianConverter.ReadUInt32(byteSegment.Array, offset);
offset += 4 + 4 * rtpPacket.CsrcCount;
if (rtpPacket.ExtensionFlag)
{
rtpPacket.ExtensionHeaderId = BigEndianConverter.ReadUInt16(byteSegment.Array, offset);
offset += 2;
int extensionHeaderLength = BigEndianConverter.ReadUInt16(byteSegment.Array, offset) * 4;
offset += 2 + extensionHeaderLength;
}
int payloadSize = byteSegment.Offset + byteSegment.Count - offset;
if (rtpPacket.PaddingFlag)
{
int paddingBytes = byteSegment.Array[byteSegment.Offset + byteSegment.Count - 1];
payloadSize -= paddingBytes;
}
rtpPacket.PayloadSegment = new ArraySegment<byte>(byteSegment.Array, offset, payloadSize);
return true;
}
}
public static class BigEndianConverter
{
public static uint ReadUInt32(byte[] buffer, int offset)
{
return (uint)(buffer[offset] << 24 |
buffer[offset + 1] << 16 |
buffer[offset + 2] << 8 |
buffer[offset + 3]);
}
public static int ReadUInt24(byte[] buffer, int offset)
{
return buffer[offset] << 16 |
buffer[offset + 1] << 8 |
buffer[offset + 2];
}
public static int ReadUInt16(byte[] buffer, int offset)
{
return (buffer[offset] << 8) | buffer[offset + 1];
}
}
Any idea why I am not able to hear the stream back ?

Why is the endian reversed after sending over TCP

I have a client written in C#, and a server written in python. The messages that I send over the socket are 8 bytes followed by the data, the 8 bytes are the data length.
In C# before sending, I convert the 8-byte data length too big endian as shown:
public void Send(SSLMsg m)
{
string json = m.Serialize();
byte[] data = Encoding.ASCII.GetBytes(json);
ulong dataLen = (ulong)data.Length;
byte[] dataLenPacked = packIt(dataLen);
Log("Sending " + dataLen + " " + json);
sslStream.Write(dataLenPacked);
sslStream.Write(data);
sslStream.Flush();
}
private byte[] packIt(ulong n)
{
byte[] bArr = BitConverter.GetBytes(n);
if (BitConverter.IsLittleEndian)
Array.Reverse(bArr, 0, 8);
return bArr;
}
The message is sent successfully and I am getting tied up in the python server code since the unpack format should be correct here shouldn't it?
(length,) = unpack('>Q', data)
# len(data) is 8 here
# length is 1658170187863248538
Isn't the big-endian character '>'? Why is my length so long?
UPDATE:
There was a bug where I was unpacking the wrong 8 bytes, that has been fixed, now that I am unpacking the correct data I still have the same question.
(length,) = unpack('>Q', data)
# len(data) is 8 here
# length is 13330654897016668160L
The correct length is given only if I unpack using little endian even though I sent the bytes to the server using big-endian... so I am expecting >Q to work, but instead
(length,) = unpack('<Q', data)
# len(data) is 8 here
# length is 185
Here is how I am receiving the bytes in python:
while (True):
r,w,e = select.select(...)
for c in r:
if (c == socket):
connection_accept(c)
else
# c is SSL wrapped at this point
read = 0
data = []
while (read != 8):
bytes = c.recv(min(8-read, 8))
read += len(bytes)
data.append(bytes)
joinedData = ''.join(data)
# the below length is 13330654897016668160L
# I am expecting it to be 185
(length,) = unpack('>Q', joinedData)
# the below length is 185, it should not be however
# since the bytes were sent in big-endian
(length,) = unpack('<Q', joinedData)
Something is wrong with your code:
length is 1658170187863248538
This is in hex 1703010020BB4E9A. This has nothing to do with a length of 8, no matter which endianess is involved. Instead it looks suspiciously like a TLS record:
17 - record type application data (decimal 23)
03 01 - protocol version TLS 1.0 (aka SSL 3.1)
00 20 - length of the following encrypted data (32 byte)
..
Since according to your code your are doing SSL there is probably something wrong in your receiver. My guess is that you read from the plain socket instead of the SSL socket and thus read the encrypted data instead of the decrypted ones.
On client side, when you write data to stream, you're doing two Write calls:
sslStream.Write(dataLenPacked);
sslStream.Write(data);
sslStream.Flush();
MSDN says about NetworkStream.Write: The Write method blocks until the requested number of bytes are sent or a SocketException is thrown. On the server side, there is no guarantee that you will receive all bytes in one receive call - it depends on OS, eth driver/config and etc. So, you have to handle this scenario. As I can see in you're handling it by reading 8 or less bytes, but socket.recv says, it's better to receive by bigger portions. Here is my implementation of the server on Python. It creates binary file in the current folder with received bytes - might be helpful to analyze what's wrong. To set listening port need to use -p/--port argument:
#!/usr/bin/env python
import sys, socket, io
import argparse
import struct
CHUNK_SIZE = 4096
def read_payload(connection, payload_len):
recv_bytes = 0
total_data = ""
while (recv_bytes < payload_len):
data = connection.recv(CHUNK_SIZE)
if not data:
break
total_data += data
recv_bytes += len(data)
if len(total_data) != payload_len:
print >> sys.stderr, "-ERROR. Expected to read {0} bytes, but have read {0} bytes\n".format(payload_len, len(total_data))
return total_data
def handle_connection(connection, addr):
total_received = 0
addrAsStr = "{0}:{1}".format(addr[0], addr[1])
# write receved bytes to file for analyzis
filename = "{0}_{1}.bin".format(addr[0], addr[1])
file = io.FileIO(filename, "w")
print "Connection from {0}".format(addrAsStr)
try:
# loop for handling data transfering for particular connection
while True:
header = connection.recv(CHUNK_SIZE)
header_len = len(header)
total_received += header_len
if header_len == 0:
break
if header_len < 8:
print >> sys.stderr, "-ERROR. Received header with len {0} less than 8 bytes!\n".format(header_len)
break
print("Header len is {0} bytes".format(len(header)))
# extract payload length - it's first 8 bytes
real_header = header[0:8]
file.write(real_header)
# more about unpack - https://docs.python.org/3/library/struct.html#module-struct
# Byte order - network (= big-endian), type - unsigned long long (8 bytes)
payload_len = struct.unpack("!Q", real_header)[0]
print("Payload len is {0} bytes".format(payload_len))
# extract payload from header
payload_in_header = header[8:] if header_len > 8 else ""
if len(payload_in_header) > 0:
print "Payload len in header is {0} bytes".format(len(payload_in_header))
file.write(payload_in_header)
# calculate remains
remains_payload_len = payload_len - len(payload_in_header)
remains_payload = read_payload(connection, remains_payload_len)
payload = payload_in_header + remains_payload
print("Payload is '{0}'".format(payload))
if remains_payload:
file.write(remains_payload)
else:
break
total_received += len(remains_payload)
finally:
file.close()
return total_received
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--port', required=True)
args = parser.parse_args()
# listen tcp socket on all interfaces
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", int(args.port)))
s.listen(1)
# loop for handling incoming connection
while True:
print "Waiting for a connection..."
(connection, addr) = s.accept()
addrAsStr = "{0}:{1}".format(addr[0], addr[1])
try:
total_received = handle_connection(connection, addr)
print "Handled connection from {0}. Received: {1} bytes\n".format(addrAsStr, total_received)
finally:
# Clean up the connection
connection.close()
if __name__ == "__main__":
main()
To make this example full, here is C# client. It uses one external library - Newtonsoft.Json for serialization:
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SimpleTcpClient
{
class SimpleTcpClient : IDisposable
{
readonly TcpClient _client;
public SimpleTcpClient(string host, int port)
{
_client = new TcpClient(host, port);
}
public void Send(byte[] payload)
{
// Get network order of array length
ulong length = (ulong)IPAddress.HostToNetworkOrder(payload.LongLength);
var stream = _client.GetStream();
// Write length
stream.Write(BitConverter.GetBytes(length), 0, sizeof(long));
// Write payload
stream.Write(payload, 0, payload.Length);
stream.Flush();
Console.WriteLine("Have sent {0} bytes", sizeof(long) + payload.Length);
}
public void Dispose()
{
try { _client.Close(); }
catch { }
}
}
class Program
{
class DTO
{
public string Name { get; set; }
public int Age { get; set; }
public double Weight { get; set; }
public double Height { get; set; }
public string RawBase64 { get; set; }
}
static void Main(string[] args)
{
// Set server name/ip-address
string server = "192.168.1.101";
// Set server port
int port = 8080;
string[] someNames = new string[]
{
"James", "David", "Christopher", "George", "Ronald",
"John", "Richard", "Daniel", "Kennet", "Anthony",
"Robert","Charles", "Paul", "Steven", "Kevin",
"Michae", "Joseph", "Mark", "Edward", "Jason",
"Willia", "Thomas", "Donald", "Brian", "Jeff"
};
// Init random generator
Random rnd = new Random(Environment.TickCount);
int i = 1;
while (true) {
try {
using (var c = new SimpleTcpClient(server, port)) {
byte[] rawData = new byte[rnd.Next(16, 129)];
rnd.NextBytes(rawData);
// Create random data transfer object
var d = new DTO() {
Name = someNames[rnd.Next(0, someNames.Length)],
Age = rnd.Next(10, 101),
Weight = rnd.Next(70, 101),
Height = rnd.Next(165, 200),
RawBase64 = Convert.ToBase64String(rawData)
};
// UTF-8 doesn't have endianness - so we can convert it to byte array and send it
// More about it - https://stackoverflow.com/questions/3833693/isn-t-on-big-endian-machines-utf-8s-byte-order-different-than-on-little-endian
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(d));
c.Send(bytes);
}
}
catch (Exception ex) {
Console.WriteLine("Get exception when send: {0}\n", ex);
}
Thread.Sleep(200);
i++;
}
}
}
}
According to https://msdn.microsoft.com/en-us/library/z78xtwts(v=vs.110).aspx you are reversing 9 bytes when you invoke:
if (BitConverter.IsLittleEndian)
Array.Reverse(bArr, 0, 8);
and according to https://www.displayfusion.com/Discussions/View/converting-c-data-types-to-c/?ID=38db6001-45e5-41a3-ab39-8004450204b3 a ulong in C# is only 8 bytes.
I don't think that this is necessarily an answer, but maybe it's a clue?

Converting String from SerialPort, converring to byte array, then being able to identify each byte individually

I have a byte array coming in through the SerialPort of gto 8 bytes. Each byte within the array means something different so I am looking for a wy to be able to label each byte to be interrogated later on in the program. I know the code below is not right, but I need to be able to interrogate each byte from byte0 up to byte7.
For example:
rxString = mySerialPort.ReadExisting();
byte[] bytes = Encoding.ASCII.GetBytes(rxString);
if (bytes.SequenceEqual(new byte[] { (byte0) = 0x95 }))
{
tb_Status.AppendText("Correct Sequence");
}
else
{
tb_Status.AppendText("Incorrect Sequence!!!");
}
Thanks
You should simply read the bytes into an array and access them by an index (0 to 7 as you said). If you interpret a special meaning on specific bytes, you should encapsulate the whole thing in a class and provide a named access to the array by properties like:
public short MyFancyData {
get {
return bytes[2] + (bytes[3] << 8);
}
}
public byte MyLessFancyData {
get {
return bytes[7];
}
}
public bool IsCorrect {
get {
return bytes[0] == 0x95;
}
}
// etc.
Is this getting close?
rxString = SerialPort.ReadExisting();
byte[] bytes = Encoding.ASCII.GetBytes(rxString);
var a = bytes[0];
var b = bytes[1];
if (a == 0x74)
{
tb_Status.AppendText("This is Good");
}

real time server/client application in C++ and C#

I have a working chat -server application in C++ on a raspberry pi that listens for clients and sends messages from one client to the others and vice versa using pthreads in for loops. I am using C# as the clients.
The C# clients are sending and receiving data (single byte) to the RPi server continuously, and logging the times when they send and receive data.
Looking at the logged times, I can see that there is a delay of 100 ms or so between when one client sends and the second one receives the data. This kind of delay is unacceptable for my application. I need to get it under 15 ms consistently.
In my C++ program, the time delay between receiving and sending the byte back to the client is 1-2 ms.
I am not sure if there is a problem in how I have coded the C# clients or the C++ server. I upgraded my kernel with the RT PREEMPT patch but this has not affected the delay times.
If I put in a random delay on the order of seconds before sending a byte to the server in the C# program, then the delay times improve significantly - down to 1-2 ms.
Is there a way to optimize it so even when sending continuously, the delay times are very small? I can post the codes if needed.
**EDIT: Here is the server side code on the RPi.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string.h> // memset
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <vector>
#include <string>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <sys/time.h>
#include <sched.h>
#include <time.h>
#include <sys/mman.h>
using namespace std;
int BACKLOG;
#define IP_ADDR "192.168.137.99"
#define PORT "8888"
#define MAXLEN 1
#define MY_PRIORITY (49) /* we use 49 as the PRREMPT_RT use 50
as the priority of kernel tasklets
and interrupt handler by default */
#define MAX_SAFE_STACK (8*1024) /* The maximum stack size which is
guaranteed safe to access without
faulting */
#define NSEC_PER_SEC (1000000000) /* The number of nsecs per sec. */
static unsigned int cli_count = 0;
vector<int> cliarray;
vector<vector<unsigned long long> > data;
pthread_attr_t custom_sched_attr;
int fifo_max_prio, fifo_min_prio;
struct sched_param fifo_param;
void stack_prefault(void) {
unsigned char dummy[MAX_SAFE_STACK];
memset(dummy, 0, MAX_SAFE_STACK);
return;
}
void send_message(char *s, int sock){
int i;
for(i=0;i<BACKLOG;i++){
if(cliarray[i]){
if(cliarray[i] != sock){
send(cliarray[i], s, 1,0);
}
}
}
}
/* Send message to all clients */
void send_message_all(char *s){
int k;
for(k=0;k<BACKLOG;k++){
if(cliarray[k]){
send(cliarray[k], s, 1,0);
}
}
}
void *handle_conn(void *pnewsock)
{
int sock = *(int*)pnewsock;
char client_msg[MAXLEN];
int read_size;
struct timeval tv;
bool looprun = true;
int clientint;
vector<unsigned long long> row(4);
while(looprun ){
read_size = recv(sock, client_msg, 1, 0);
gettimeofday(&tv, NULL);
unsigned long long milliseconds_recv =(unsigned long long)(tv.tv_sec) * 1000 +(unsigned long long)(tv.tv_usec) / 1000;
clientint = int(*client_msg);
client_msg[read_size] = '\0';
/* cout << "length of client message: " << strlen(client_msg) << endl;
cout << "# bytes is : " << read_size << endl;
cout << clientint << " received" << endl;*/
send_message(client_msg,sock);
gettimeofday(&tv, NULL);
unsigned long long milliseconds_sent =(unsigned long long)(tv.tv_sec) * 1000 +(unsigned long long)(tv.tv_usec) / 1000;
row = {clientint, milliseconds_recv, milliseconds_sent, strlen(client_msg)};
data.push_back(row);
if (clientint == 100)
{
looprun = false;
break;
}
}
cout << "exit handle -conn " << endl;
pthread_exit(NULL);
}
int main (int argc, char **argv)
{
struct timespec t;
struct sched_param param;
int interval = 50000; /* 50us*/
/* Declare ourself as a real time task */
param.sched_priority = MY_PRIORITY;
if(sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
perror("sched_setscheduler failed");
exit(-1);
}
/* Lock memory */
if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
perror("mlockall failed");
exit(-2);
}
/* Pre-fault our stack */
stack_prefault();
int connfd =0, n = 0;
int *new_sock, sock;
struct addrinfo hints, *res;
int reuseaddr = 1; // True
// Get the address info
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(IP_ADDR, PORT, &hints, &res) != 0) {
perror("getaddrinfo");
exit (EXIT_FAILURE);
//return 1;
}
// Create the socket
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
perror("socket");
exit (EXIT_FAILURE);
// return 1;
}
// Enable the socket to reuse the address
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) {
perror("setsockopt");
::close(sock);
exit (EXIT_FAILURE);
//shutdown(sock,2);
// return 1;
}
// Bind to the address
if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
perror("bind");
::close(sock);
exit (EXIT_FAILURE);
//shutdown(sock,2);
//return 0;
}
freeaddrinfo(res);
// Listen
if (listen(sock, BACKLOG) == -1) {
perror("listen");
exit (EXIT_FAILURE);
// return 0;
}
cout << "Enter # clients: " ;
cin >> BACKLOG;
cout << "Enter name of text file (num clients - trial #).txt:" << endl;
string filename;
cin >> filename;
cout << "listening for connections" << endl;
// Main loop
// Main loop
bool running = true;
// Initialize clients
while (running)
{
size_t size = sizeof(struct sockaddr_in);
struct sockaddr_in their_addr;
int clilen = sizeof(their_addr);
int newsock = accept(sock, (struct sockaddr*)&their_addr, &size);
if (newsock == -1)
{
perror("accept");
exit (EXIT_FAILURE);
// return -1;
}
cli_count++;
printf("Got a connection from %s on port %d\n", inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
cliarray.push_back(newsock);
if (cli_count == BACKLOG)
{
cout << "Max clients reached" << endl;
running = false;
break;
}
}
ofstream frout("/home/pi/cplus/"+filename,ios::app);
frout << "recv \t" << "time recv (ms) \t" << "time sent (ms) \t" << "length of msg" << endl;
/* Send message to all clients that server is ready to accept data */
char r = char(cli_count);
char *mesg = &r;
send_message_all(mesg);
cout << "length of mesg: " << strlen(mesg) << endl;
//pthread_t from_ard_t, *ptr;
pthread_attr_init(&custom_sched_attr);
pthread_attr_setinheritsched(&custom_sched_attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&custom_sched_attr, SCHED_FIFO);
fifo_max_prio = sched_get_priority_max(SCHED_FIFO);
fifo_param.sched_priority = fifo_max_prio;
pthread_attr_setschedparam(&custom_sched_attr, &fifo_param);
pthread_t *ptr;
ptr =static_cast<pthread_t*>(malloc(sizeof(pthread_t)*cli_count));
int i;
for (i=0;i<BACKLOG;i++)
{
if (pthread_create(&ptr[i], &custom_sched_attr, handle_conn, (void *)&cliarray[i]) != 0)//was newsock
{
fprintf(stderr, "Failed to create thread\n");
exit (EXIT_FAILURE);
}
}
/*if (pthread_create(&from_ard_t, NULL, from_ard, NULL)!=0)
{
fprintf(stderr, "Failed to create thread\n");
}*/
//pthread_join(from_ard_t, NULL);
cout << "Created threads" << endl;
for(i = 0; i < BACKLOG; i++)
{
pthread_join(ptr[i], NULL);
}
cout << "joined send/recv threads" << endl;
close(sock);
/* array for timestamp data */
int numrows = data.size();
for (int k = 0; k < numrows; k++)
{
for (int j = 0; j < 4; j++)
{
frout << data[k][j] << "\t";
}
frout << endl;
}
}
C# client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.IO;
//make command line possible to save time info in file
namespace sockclient_cs
{
public class Program
{
private System.Object lockThis = new System.Object();
const int MAXLEN = 1;
public bool recvrun = true;
StringBuilder sb = new StringBuilder();
public NetworkStream stream;
string fnrecv;
string fnsend;
public int clicount;
DateTime centuryBegin = new DateTime(1970, 1, 1);
Random rndseed;
public Program(NetworkStream streamer, int clinum, string pathsend, string pathrecv, Random rand)
{
stream = streamer;
clicount = clinum;
fnrecv = pathrecv;
fnsend = pathsend;
rndseed = rand;
}
public void SendData()
{
int[] numarray = new int[] { 70, 80, 90, 100, 60, 50, 40, 30}; // coressponds to %, A, P, _, d
bool looprun = true;
while (looprun)
{
int rnd1 = rndseed.Next(0, numarray.Length);
byte[] writebyte = new byte[] { BitConverter.GetBytes(numarray[rnd1])[0] };
int delay = rndseed.Next(2000,6000);
Thread.Sleep(delay);
Array.Reverse(writebyte);
stream.Write(writebyte, 0, writebyte.Length);
DateTime currentDate = DateTime.Now;
long elapsedTicks = currentDate.Ticks - centuryBegin.Ticks;
Decimal milliseconds = elapsedTicks / (Decimal)TimeSpan.TicksPerMillisecond;
using (StreamWriter sw = File.AppendText(fnsend))
{
sw.WriteLine(numarray[rnd1] + "\t" + milliseconds + "\n");
}
Console.Write("sent: " + numarray[rnd1] + "\n");
if (numarray[rnd1] == 100)
{
looprun = false;
break;
}
}
}
public void ReceiveData()
{
bool recvrun = true;
int numenders = 0;
while (recvrun)
{
String responseData = String.Empty;
byte[] bb = new byte[1]; //1 byte of data coming in
ASCIIEncoding ascii = new ASCIIEncoding();
int bytes;
bytes = stream.Read(bb, 0, bb.Length);
DateTime currentDate = DateTime.Now;
long elapsedTicks = currentDate.Ticks - centuryBegin.Ticks;
Decimal milliseconds = elapsedTicks / (Decimal)TimeSpan.TicksPerMillisecond;
int numback = BitConverter.ToInt16(new byte[] { bb[0], 0x00 }, 0);
using (StreamWriter sw = File.AppendText(fnrecv))
{
sw.WriteLine(numback + "\t" + milliseconds + "\n");
}
//responseData = ascii.GetString(bb, 0, bytes);
Console.WriteLine("Received: " + bb[0] + "\n");
if (numback == 100)
{
numenders++;
if (numenders == clicount-1)
{
recvrun = false;
break;
}
}
}
Console.Write("Exiting receive");
}
}
public class Simple
{
public static void Main()
{
Console.Write("Enter name of recv data file (ex. cli1recv_1.txt):\n");
string recvfile = Console.ReadLine();
string pathrecv = #"C:\Users\Neha\Documents\Ayaz Research\" + recvfile;
Console.Write("Enter name of send data file (ex. cli4send_1.txt):\n");
string sendfile = Console.ReadLine();
string pathsend = #"C:\Users\Neha\Documents\Ayaz Research\" + sendfile;
using (StreamWriter sw = File.CreateText(pathrecv))
{
sw.WriteLine("Received \t Recv time (ms) \n");
}
using (StreamWriter sw = File.CreateText(pathsend))
{
sw.WriteLine("Sent \t Sent time (ms) \n");
}
//SerialPort Serial1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
Random seed = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
try
{
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting...");
tcpclnt.Connect("192.168.137.99", 8888); //address of RPi on arbitrary non privileged port
Console.WriteLine("Connected");
NetworkStream stream = tcpclnt.GetStream();
/*Receive the welcome from server */
String responseData = String.Empty;
Byte[] bb = new byte[2]; //1 byte of data coming in
ASCIIEncoding ascii = new ASCIIEncoding();
int bytes = stream.Read(bb, 0, bb.Length);
int numback = BitConverter.ToInt16(new byte[] { bb[0], 0x00 }, 0);
Console.Write("Received initial message from server: " + bb[0] + "\n");
/*byte[] writebyte = new byte[] { BitConverter.GetBytes(82)[0] };
Console.Write("writebyte length is " + writebyte.Length + "\n");
Array.Reverse(writebyte);
stream.Write(writebyte, 0, writebyte.Length);
bytes = stream.Read(bb, 0,bb.Length);
// convert to string info
Console.Write("reading byte length is " + bb.Length + "\n");
responseData = ascii.GetString(bb, 0, bytes);
Console.WriteLine("bb[0] is: " + bb[0] + "and bb[1] is: " + bb[1] + "\n");
int numback = BitConverter.ToInt16(new byte[] { bb[0], 0x00 }, 0);
Console.WriteLine("Received: " + responseData + "\n");
Console.WriteLine("Received: " + numback + "\n");*/
Program clientObject = new Program(stream,numback,pathsend, pathrecv, seed);
//non loop format - for cppserv
ThreadStart sending = new ThreadStart(clientObject.SendData);
Thread sendThread = new Thread(sending);
sendThread.Start();
ThreadStart receiving = new ThreadStart(clientObject.ReceiveData);
Thread recvThread = new Thread(receiving);
recvThread.Start();
sendThread.Join();
recvThread.Join();
tcpclnt.Close();
}
catch (Exception e)
{
Console.WriteLine("Error...." + e.StackTrace);
}
}
}
}
Here is what Client 2 is sending to Client 1 and the timestamp.
Sent Sent time (ms)
70 1467720189893.1576
80 1467720189912.1587
60 1467720189926.1595
60 1467720189937.1602
50 1467720189949.1608
60 1467720189959.1614
40 1467720189969.162
100 1467720190006.1641
Here is what Client 1 is receiving from Client 2 and the timestamp.
Received Recv time (ms)
70 1467720190016.1647
80 1467720190063.1674
60 1467720190079.1683
60 1467720190109.17
50 1467720190126.171
60 1467720190137.1716
40 1467720190149.1723
100 1467720190161.173
Turn off the Nagle algorithm at the sender
Socket.NoDelay = true

DMX USB Pro(FTDI) works very sporadically

I've been trying to write a C# application that send data to a stage light using the Enttec DMX USB Pro box. There are provided C# wrappers that I'm using and I've gotten the light to respond as expected but it very rarely works. I seem to have to switch between using from off the shelf application to "reset" the connection a few times before I can get it to start responding to my writes.
My DMX Code is
class DmxDriver
{
const int DMX_PACKET_SIZE = 513;
private bool connected;
private FTDI device;
private int startAddr;
private byte[] packet;
public DmxDriver(int baseDmxAddr)
{
startAddr = baseDmxAddr;
device = new FTDI();
FTDI.FT_STATUS result = device.OpenByIndex(0);
if (result == FTDI.FT_STATUS.FT_OK)
{
connected = true;
Console.WriteLine("DMX connected");
}
else
{
connected = false;
Console.WriteLine("DMX CONNECTION FAILED");
}
packet = new byte[DMX_PACKET_SIZE];
for (int i = 0; i < DMX_PACKET_SIZE; i++)
{
packet[i] = 0;
}
}
~DmxDriver()
{
device.Close();
}
public bool deviceConnected()
{
return connected;
}
public void sendData()
{
if (packet.Length != 513)
{
return;
}
uint written = 0;
FTDI.FT_STATUS result;
byte[] header = new byte[4];
header[0] = 0x7E; //start code
header[1] = 6; //DMX TX
header[2] = 255 & 0xFF; //pack length logical and with max packet size
header[3] = 255 >> 8; //packet length shifted by byte length? DMX standard idk
result = device.Write(header, 4, ref written);//send dmx header
Console.WriteLine(result);
Console.WriteLine(written);
result = device.Write(packet, 513, ref written);//send data array
Console.WriteLine(result);
Console.WriteLine(written);
byte[] endcode = new byte[1];
endcode[0] = 0xE7;
device.Write(endcode, 1, ref written);//send dmx end code
}

Categories