Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
A
Arduino4D_Robot
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CLEAR
Arduino4D_Robot
Merge requests
!1
Arduino networking code
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Arduino networking code
arduinoServer
into
master
Overview
5
Commits
26
Pipelines
0
Changes
2
Merged
Kyrre Ness Sjobaek
requested to merge
arduinoServer
into
master
4 years ago
Overview
2
Commits
26
Pipelines
0
Changes
2
Expand
0
0
Merge request reports
Compare
master
version 24
984fb343
4 years ago
version 23
740275b9
4 years ago
version 22
8db061d2
4 years ago
version 21
072eb009
4 years ago
version 20
5203822d
4 years ago
version 19
f754157a
4 years ago
version 18
3d6115a9
4 years ago
version 17
0da250aa
4 years ago
version 16
117b4e58
4 years ago
version 15
f5f81541
4 years ago
version 14
0039bb16
4 years ago
version 13
36ba83a0
4 years ago
version 12
91ed13bc
4 years ago
version 11
34f799d7
4 years ago
version 10
69f78505
4 years ago
version 9
a35a4c54
4 years ago
version 8
93ca3ee9
4 years ago
version 7
da45d9da
4 years ago
version 6
13508201
4 years ago
version 5
98e572df
4 years ago
version 4
d2efe175
4 years ago
version 3
f3141861
4 years ago
version 2
b2be484a
4 years ago
version 1
f72441a7
4 years ago
master (base)
and
version 5
latest version
c91fb939
26 commits,
4 years ago
version 24
984fb343
25 commits,
4 years ago
version 23
740275b9
24 commits,
4 years ago
version 22
8db061d2
23 commits,
4 years ago
version 21
072eb009
22 commits,
4 years ago
version 20
5203822d
21 commits,
4 years ago
version 19
f754157a
20 commits,
4 years ago
version 18
3d6115a9
19 commits,
4 years ago
version 17
0da250aa
18 commits,
4 years ago
version 16
117b4e58
17 commits,
4 years ago
version 15
f5f81541
16 commits,
4 years ago
version 14
0039bb16
15 commits,
4 years ago
version 13
36ba83a0
14 commits,
4 years ago
version 12
91ed13bc
13 commits,
4 years ago
version 11
34f799d7
12 commits,
4 years ago
version 10
69f78505
11 commits,
4 years ago
version 9
a35a4c54
10 commits,
4 years ago
version 8
93ca3ee9
9 commits,
4 years ago
version 7
da45d9da
8 commits,
4 years ago
version 6
13508201
7 commits,
4 years ago
version 5
98e572df
6 commits,
4 years ago
version 4
d2efe175
4 commits,
4 years ago
version 3
f3141861
3 commits,
4 years ago
version 2
b2be484a
2 commits,
4 years ago
version 1
f72441a7
1 commit,
4 years ago
2 files
+
529
−
0
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
2
Search (e.g. *.vue) (Ctrl+P)
4DrobotServer/4DrobotServer.ino
0 → 100644
+
442
−
0
Options
/*
* Server for controling 4D robot for moving samples in/out of the beam at CLEAR.
* Access via telnet-like interface at port 23.
*
* Note: Expects UNIX line-endings, '\n', not '\r\n' ala Windows.
* Best client: Netcat (nc) -- this is a clean TCP client, no attempts to negotiate anything.
* Example:
* nc 192.168.1.31 23
*
* Kyrre Ness Sjobak, 24 April 2021
* University of Oslo / CERN
*
* Inspired by PositionGaugeServer,
* also in use at CLEAR
*/
#include
<Arduino.h>
#include
<SPI.h>
#include
<Ethernet.h>
// ***** NETWORK CONFIG ************************
// *** MAC ADDRESS FOR THE ARDUINO ON THE PLASMA-LENS ***
//byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xED};
// *** MAC ADDRESS FOR THE ARDUINO ON THE CLIC STRUCTURE ***
//byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x84, 0xEE};
// *** MAC ADDRESS FOR KYRRE'S TEST BOARD ***
byte
mac
[]
=
{
0xA8
,
0x61
,
0x0A
,
0xAE
,
0x72
,
0xF7
};
//To use DHCP or not to use DHCP, that's the question.
// Comment out this line to NOT use DHCP.
#define USE_DHCP
#ifndef USE_DHCP
IPAddress
ip
(
192
,
168
,
1
,
177
);
IPAddress
myDns
(
192
,
168
,
1
,
1
);
IPAddress
gateway
(
192
,
168
,
1
,
1
);
IPAddress
subnet
(
255
,
255
,
0
,
0
);
#endif
const
size_t
telnet_numConnections
=
MAX_SOCK_NUM
;
const
size_t
telnet_bufflen
=
256
;
//This quickly takes a LOT of memory! Total for MEGA is 8k!
const
int
telnet_port
=
23
;
const
size_t
output_bufflen
=
2048
;
// Output buffer
//Robot arm configuration
// ***** GLOBAL VARIABLES - DO NOT TOUCH ********
EthernetServer
telnet_socket
(
telnet_port
);
EthernetClient
telnet_connection
[
telnet_numConnections
];
bool
telnet_connectionInUse
[
telnet_numConnections
];
//Buffers & buffCount (number of elements = idx of first free element)
char
telnet_buff
[
telnet_numConnections
][
telnet_bufflen
];
size_t
telnet_buffCount
[
telnet_numConnections
];
char
serial_buff
[
telnet_bufflen
];
size_t
serial_buffCount
;
char
output_buff
[
output_bufflen
];
size_t
output_buffCount
;
void
setup
()
{
//Serial setup, for debugging
Serial
.
begin
(
9600
);
// wait for serial port to connect. Needed for native USB port only
int
serialCounter
=
0
;
while
(
!
Serial
)
{
//However only wait for 1 second before giving up,
// so that it can work also when not connected to USB
delay
(
100
);
serialCounter
++
;
if
(
serialCounter
>
10
)
break
;
}
Serial
.
println
();
Serial
.
println
(
"4DrobotServer initializing..."
);
//Network setup
Serial
.
println
(
"Starting networking..."
);
#ifdef USE_DHCP
Ethernet
.
begin
(
mac
);
#else
Ethernet
.
begin
(
mac
,
ip
,
myDns
,
gateway
,
subnet
);
#endif
// Check for Ethernet hardware present
if
(
Ethernet
.
hardwareStatus
()
==
EthernetNoHardware
)
{
Serial
.
println
(
"Ethernet shield was not found. Sorry, can't run without hardware. :("
);
while
(
true
)
{
delay
(
1
);
// do nothing, no point running without Ethernet hardware
}
}
while
(
true
)
if
(
Ethernet
.
linkStatus
()
==
LinkOFF
)
{
Serial
.
println
(
"Ethernet cable is not connected"
);
}
else
{
Serial
.
println
(
"Ethernet cable connected / status unknown"
);
break
;
}
byte
buffMAC
[
6
];
Serial
.
print
(
"MAC address: "
);
Ethernet
.
MACAddress
(
buffMAC
);
for
(
byte
octet
=
0
;
octet
<
6
;
octet
++
)
{
Serial
.
print
(
buffMAC
[
octet
],
HEX
);
if
(
octet
<
5
)
{
Serial
.
print
(
":"
);
}
}
Serial
.
println
();
Serial
.
print
(
"IP address: "
);
Serial
.
println
(
Ethernet
.
localIP
());
Serial
.
print
(
"DNS address: "
);
Serial
.
println
(
Ethernet
.
dnsServerIP
());
Serial
.
print
(
"Gateway address: "
);
Serial
.
println
(
Ethernet
.
gatewayIP
());
Serial
.
print
(
"Subnet: "
);
Serial
.
println
(
Ethernet
.
subnetMask
());
//Server setup
telnet_socket
.
begin
();
for
(
uint8_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
memset
(
telnet_buff
[
i
],
'\0'
,
sizeof
(
telnet_buff
[
i
]));
telnet_buffCount
[
i
]
=
0
;
telnet_connectionInUse
[
i
]
=
false
;
}
memset
(
serial_buff
,
'\0'
,
sizeof
(
serial_buff
));
serial_buffCount
=
0
;
memset
(
output_buff
,
'\0'
,
sizeof
(
output_buff
));
output_buffCount
=
0
;
//Serial is ready for input!
Serial
.
println
(
"$"
);
}
void
loop
()
{
//Run all the "programs" in order
//delay(1000);
telnet_server
();
// ** Housekeeping **
#ifdef USE_DHCP
DHCPhousekeeping
();
#endif
}
void
telnet_server
()
{
// Program for running the telnet- and serial communication
//1. Check for new connections
while
(
true
)
{
//Loop in case there are multiple new connections
EthernetClient
newConnection
=
telnet_socket
.
accept
();
if
(
newConnection
)
{
//Find a new connection slot
for
(
size_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
if
(
!
telnet_connectionInUse
[
i
])
{
telnet_connection
[
i
]
=
newConnection
;
telnet_connectionInUse
[
i
]
=
true
;
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
"< INFO CONN MAKE: "
);
IPAddress
IP
=
telnet_connection
[
i
].
remoteIP
();
char
IP_buff
[
16
];
snprintf
(
IP_buff
,
sizeof
(
IP_buff
),
"%d.%d.%d.%d"
,
IP
[
0
],
IP
[
1
],
IP
[
2
],
IP
[
3
]);
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
IP_buff
);
snprintf
(
IP_buff
,
sizeof
(
IP_buff
),
" ON #%-2d
\n
"
,
i
);
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
IP_buff
);
telnet_connection
[
i
].
println
(
"$"
);
break
;
}
}
}
else
{
break
;
}
}
//2. Check for incoming data (telnet & serial) and buffer it
for
(
size_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
while
(
telnet_connectionInUse
[
i
]
&&
telnet_connection
[
i
].
connected
()
&&
telnet_connection
[
i
].
available
()
>
0
)
{
bufferWriteChar
(
telnet_buff
[
i
],
sizeof
(
telnet_buff
[
i
]),
telnet_buffCount
[
i
],
telnet_connection
[
i
].
read
());
}
}
while
(
Serial
.
available
()
>
0
)
{
bufferWriteChar
(
serial_buff
,
sizeof
(
serial_buff
),
serial_buffCount
,
Serial
.
read
());
}
//3. Feed the clients & serial with the content of the output buffer
if
(
output_buffCount
)
{
for
(
size_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
if
(
telnet_connectionInUse
[
i
]
&&
telnet_connection
[
i
].
connected
()
)
{
telnet_connection
[
i
].
print
(
output_buff
);
}
}
Serial
.
print
(
output_buff
);
memset
(
output_buff
,
'\0'
,
sizeof
(
output_buff
));
output_buffCount
=
0
;
}
//4. Check for telnet disconnects & handle
for
(
size_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
if
(
telnet_connectionInUse
[
i
]
&&
!
telnet_connection
[
i
].
connected
()
)
{
telnet_connectionInUse
[
i
]
=
false
;
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
"< INFO CONN BREAK: "
);
IPAddress
IP
=
telnet_connection
[
i
].
remoteIP
();
char
IP_buff
[
16
];
snprintf
(
IP_buff
,
sizeof
(
IP_buff
),
"%d.%d.%d.%d"
,
IP
[
0
],
IP
[
1
],
IP
[
2
],
IP
[
3
]);
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
IP_buff
);
snprintf
(
IP_buff
,
sizeof
(
IP_buff
),
" ON #%-2d
\n
"
,
i
);
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
IP_buff
);
telnet_connection
[
i
].
stop
();
memset
(
telnet_buff
[
i
],
'\0'
,
sizeof
(
telnet_buff
[
i
]));
telnet_buffCount
[
i
]
=
0
;
}
}
//5. Parse input buffers & notify that we are ready for more
for
(
size_t
i
=
0
;
i
<
telnet_numConnections
;
i
++
)
{
input_parser
(
telnet_buff
[
i
],
sizeof
(
telnet_buff
[
i
]),
telnet_buffCount
[
i
],
&
(
telnet_connection
[
i
]));
}
input_parser
(
serial_buff
,
sizeof
(
serial_buff
),
serial_buffCount
,
&
(
Serial
));
}
void
input_parser
(
char
*
in
,
const
size_t
buffSize
,
size_t
&
buffCount
,
Stream
*
originatingStream
)
{
// Attempt to parse the commands in the buffer.
// It will only attempt to parse commands that end with a '\n', '\r', or a combination thereof
//1. Sanity-check the buffer size
// (Note: Last entry is always a \0, buffSize cannot point to it)
if
(
buffCount
==
buffSize
-
1
)
{
originatingStream
->
println
(
"@ INFO BUFFER FULL"
);
originatingStream
->
println
(
"@ INFO BUFFER RESET"
);
memset
(
in
,
'\0'
,
buffSize
);
buffCount
=
0
;
// Ready for more
originatingStream
->
println
(
"$"
);
return
;
}
//2. Look for whole lines & parse each of them in order
char
line_buff
[
buffSize
];
memset
(
line_buff
,
'\0'
,
sizeof
(
line_buff
));
size_t
line_next
=
0
;
//Index of the first valid character
bool
lastchar_was_newline
=
true
;
bool
gotCommand
=
false
;
//Print a `$` when done, after having run commands
for
(
size_t
i
=
0
;
i
<
buffCount
;
i
++
)
{
if
(
in
[
i
]
==
'\0'
)
{
//Sanity check: There should be no NULL before the end of the buffer `in`
originatingStream
->
println
(
"@ INFO BUFFER NULL"
);
originatingStream
->
println
(
"@ INFO BUFFER RESET"
);
memset
(
line_buff
,
'\0'
,
sizeof
(
line_buff
));
memset
(
in
,
'\0'
,
buffSize
);
line_next
=
0
;
buffCount
=
0
;
// Ready for more
originatingStream
->
println
(
"$"
);
return
;
}
else
if
(
lastchar_was_newline
)
{
//Skip repeated newlines, and place line_next correctly
line_next
=
i
;
if
(
in
[
i
]
!=
'\n'
and
in
[
i
]
!=
'\r'
)
{
//Double newline or newline at start
lastchar_was_newline
=
false
;
}
}
else
if
(
in
[
i
]
==
'\n'
or
in
[
i
]
==
'\r'
)
{
//Newline not following start or another newline
memcpy
(
line_buff
,
in
+
line_next
,
i
-
line_next
);
line_buff
[
i
-
line_next
]
=
'\0'
;
parse_line
(
line_buff
);
lastchar_was_newline
=
true
;
//Note: line_next is valid before lastchar_was_newline is false
line_next
=
i
;
memset
(
line_buff
,
'\0'
,
sizeof
(
line_buff
));
gotCommand
=
true
;
}
//Else: Just keep counting chars
}
//3. Prepare buffers for next round
if
(
lastchar_was_newline
&&
buffCount
>
0
)
{
// All data was parsed; reset buffer and continue
if
(
not
in
[
line_next
+
1
]
==
'\0'
)
{
//Internal error!
originatingStream
->
println
(
"@ INFO BUFFER UNTERMINATED"
);
originatingStream
->
println
(
"@ INFO BUFFER RESET"
);
//TODO:
// This may indicate a serious bug (array overrun)
// consider resetting the CPU!
}
//All treated, let's reset
memset
(
line_buff
,
'\0'
,
sizeof
(
line_buff
));
memset
(
in
,
'\0'
,
buffSize
);
buffCount
=
0
;
line_next
=
0
;
// Ready for more
originatingStream
->
println
(
"$"
);
}
else
if
(
not
lastchar_was_newline
&&
line_next
>
0
)
{
// Shift remaining content of `in` to start of `in`
size_t
j
=
0
;
for
(
size_t
i
=
line_next
;
i
<
buffCount
;
i
++
)
{
in
[
j
]
=
in
[
i
];
j
+=
1
;
}
memset
(
in
+
j
,
'\0'
,
buffSize
-
j
);
buffCount
=
j
;
}
}
void
parse_line
(
char
*
line_buff
)
{
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
"> "
);
bufferWrite
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
line_buff
);
bufferWriteChar
(
output_buff
,
sizeof
(
output_buff
),
output_buffCount
,
'\n'
);
}
int
bufferWrite
(
char
*
buff
,
const
size_t
buffSize
,
size_t
&
buffCount
,
const
char
*
in
)
{
/* Add a zero-terminated string to a buffer,
* checking for buffer overruns and
* (SIDE EFFECT!) incrementing the buffCount.
* If the buffer will overrun, truncate the input string.
* Return number of chars written, or return <0 on error.
* If buffer overrun, chars may still be written -> positive return.
*/
size_t
len
=
strlen
(
in
);
int
ret
=
snprintf
(
buff
+
buffCount
,
buffSize
-
buffCount
,
in
);
buffCount
+=
ret
;
return
ret
;
}
int
bufferWriteChar
(
char
*
buff
,
const
size_t
buffSize
,
size_t
&
buffCount
,
const
char
in
)
{
/* Add a single char to a buffer,
* checking that there is space for it and
* (SIDE EFFECT!) incrementing the buffCount.
* Returns the number of chars written (0 or 1).
*/
if
(
buffCount
==
buffSize
-
1
)
{
//Pointing at terminating \0,
// no more space!
return
0
;
}
else
{
buff
[
buffCount
]
=
in
;
buffCount
++
;
return
1
;
}
}
#ifdef USE_DHCP
void
DHCPhousekeeping
()
{
switch
(
Ethernet
.
maintain
())
{
case
1
:
//renewed fail
Serial
.
println
(
"Error: renewed fail"
);
break
;
case
2
:
//renewed success
Serial
.
println
(
"Renewed success"
);
//print your local IP address:
Serial
.
print
(
"My IP address: "
);
Serial
.
println
(
Ethernet
.
localIP
());
break
;
case
3
:
//rebind fail
Serial
.
println
(
"Error: rebind fail"
);
break
;
case
4
:
//rebind success
Serial
.
println
(
"Rebind success"
);
//print your local IP address:
Serial
.
print
(
"My IP address: "
);
Serial
.
println
(
Ethernet
.
localIP
());
break
;
default:
//nothing happened
break
;
}
}
#endif
Loading