Índice
ToggleThis guide helps developers quickly get up and running on the EC700 — covering serial port communication, digital I/O control, REST API integration, pre-installed software management, and boot logo customization.
The EC700 is an AI edge computing industrial PC powered by the Rockchip RK3588J with a built-in 6 TOPS NPU, designed for on-device AI inference. It’s commonly deployed in smart manufacturing, industrial vision inspection, and other AI scenarios. See the full spec sheet on the EC700 product page.
Prerequisites and Tools
This guide applies to the EC700 gateway. Before diving in, make sure you have the following tools ready. Please download the following tools via the download page.
SSH Client
MobaXterm is recommended, or you may use any SSH client you’re familiar with.
Serial Debug Tool
XCOM is recommended, or you may use any serial terminal you prefer.
Hardware Accessories
Common auxiliary debugging tools include USB-to-RS485 adapters, Ethernet cables, etc. Please prepare these yourself.
Cadena de herramientas de compilación cruzada
If you’re compiling native C/C++ applications on a host PC and deploying to the EC700.
Entorno informático
The EC700 ships with a full embedded Linux environment. Here’s what’s running under the hood:
| Software | Versión |
|---|---|
| OS | Linux integrado |
| Kernel | Linux 6.1.118 |
| Node.js | v22.17.0 |
| Python | Python 3.10.12 |
| Concha | bash |
| Docker | V27.4.1 |
| Qt | V5.15.3 |
| Desktop Environment | Xfce4 |
Device Resources
| Categoría | Details | Observaciones |
|---|---|---|
| Almacenamiento | 128 GB total | ~108 GB free out of the box; expandable via SD card or M.2 NVMe SSD |
| Memoria | 8 GB | ~6 GB free out of the box |
| CPU | RK3588 | ~98% idle out of the box |
| NPU | 6 TOPS | ~100% idle out of the box |
Interfaces periféricos
1. Debug Port
The EC700 exposes the system debug serial port via a Tipo-C interface. Use these settings in your serial terminal:
- Baud rate: 115200
- Data bits: 8
- Stop bits: 1
- Parity: None
- Flow control: None
- Default username: root
- Default password: See the open system permissions documentation.
2. Serial Ports (RS485 / RS232)
The EC700 provides two RS485 channels and one RS232 channel:
| Interfaz de hardware | Archivo de dispositivo |
|---|---|
| RS485-1 | /dev/ttyS3 (corresponds to A1 / B1) |
| RS485-2 | /dev/ttyS4 (corresponds to A2 / B2) |
| RS232 | /dev/ttyS1 (corresponds to TXD / RTD) |
Nota: The RS485 ports use automatic direction control. You do not need to switch between transmit and receive modes manually — the hardware handles it automatically.
2.1 Quick Test
Use the minicom utility for testing. Refer to online resources or consult GPT/ Google for usage details.
2.2 C Code Example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/select.h>
#define BUFFER_SIZE 256
typedef struct {
int baud_rate; // Baud rate
int data_bits; // Data bits (5,6,7,8)
int stop_bits; // Stop bits (1,2)
char parity; // Parity bit (N: None, O: Odd, E: Even)
} SerialConfig;
int set_serial_attr(int fd, SerialConfig *config)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
perror("tcgetattr");
return -1;
}
// Set Baud rate
speed_t speed;
switch (config->baud_rate) {
case 9600: speed = B9600; break;
case 19200: speed = B19200; break;
case 38400: speed = B38400; break;
case 57600: speed = B57600; break;
case 115200: speed = B115200; break;
default:
fprintf(stderr, "Unsupported baud rate, using 115200\n");
speed = B115200;
}
cfsetispeed(&tty, speed);
cfsetospeed(&tty, speed);
// Set Data bits
tty.c_cflag &= ~CSIZE;
switch (config->data_bits) {
case 5: tty.c_cflag |= CS5; break;
case 6: tty.c_cflag |= CS6; break;
case 7: tty.c_cflag |= CS7; break;
case 8: tty.c_cflag |= CS8; break;
default:
fprintf(stderr, "Unsupported data bits, using 8\n");
tty.c_cflag |= CS8;
}
// Set Stop bits
if (config->stop_bits == 2) {
tty.c_cflag |= CSTOPB;
} else {
tty.c_cflag &= ~CSTOPB;
}
// Set Parity bit
switch (config->parity) {
case 'N': case 'n':
tty.c_cflag &= ~PARENB; // None
break;
case 'O': case 'o':
tty.c_cflag |= PARENB; // Odd
tty.c_cflag |= PARODD;
break;
case 'E': case 'e':
tty.c_cflag |= PARENB; // Even
tty.c_cflag &= ~PARODD;
break;
default:
fprintf(stderr, "Unsupported parity, using N\n");
tty.c_cflag &= ~PARENB;
}
// Other settings
tty.c_cflag |= (CLOCAL | CREAD); // Enable receiver and local mode
tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Raw input mode
tty.c_oflag &= ~OPOST; // Raw output mode
tty.c_cc[VMIN] = 1; // Minimum number of characters to read
tty.c_cc[VTIME] = 0; // Read timeout (unit: 0.1 seconds)
if (tcsetattr(fd, TCSANOW, &tty) < 0) {
perror("tcsetattr");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int fd;
char *portname;
if (argc < 2) {
fprintf(stderr, "Usage: %s <serial_port>\n", argv[0]);
exit(EXIT_FAILURE);
}
portname = argv[1];
// Configure serial port parameters
SerialConfig config = {
.baud_rate = 115200, // Baud rate
.data_bits = 8, // Data bits
.stop_bits = 1, // Stop bits
.parity = 'N' // Parity (N: None, O: Odd, E: Even)
};
fd = open(portname, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
if (set_serial_attr(fd, &config)) {
close(fd);
exit(EXIT_FAILURE);
}
printf("Serial port echo test running on %s\n", portname);
printf("Configuration: %d baud, %d data bits, %d stop bit, %c parity\n",
config.baud_rate, config.data_bits, config.stop_bits, config.parity);
printf("Press Ctrl+C to exit.\n");
fd_set readfds;
char buffer[BUFFER_SIZE];
int n;
while (1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
// Wait indefinitely for data to arrive (timeout setting removed)
if (select(fd + 1, &readfds, NULL, NULL, NULL) < 0) {
perror("select");
break;
}
if (FD_ISSET(fd, &readfds)) {
n = read(fd, buffer, BUFFER_SIZE - 1);
if (n > 0) {
buffer[n] = '\0';
printf("Received %d bytes: %s\n", n, buffer);
// Echo data
write(fd, buffer, n);
} else if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("read");
break;
}
}
}
}
close(fd);
return 0;
}
Compilar: gcc rs485_ejemplo.c -o rs485_ejemplo
Test RS485-1: ./rs485_example /dev/ttyS3
2.3 Python Code Example
import serial
import select
import sys
import tty
class SerialConfig:
def __init__(self):
self.baud_rate = 115200 # Baud rate
self.data_bits = 8 # Data bits
self.stop_bits = 1 # Stop bits
self.parity = 'N' # Parity (N: None, O: Odd, E: Even)
def set_serial_config(ser, config):
"""Configure serial port parameters"""
# Set baud rate
ser.baudrate = config.baud_rate
# Set data bits
if config.data_bits == 5:
ser.bytesize = serial.FIVEBITS
elif config.data_bits == 6:
ser.bytesize = serial.SIXBITS
elif config.data_bits == 7:
ser.bytesize = serial.SEVENBITS
else: # Default to 8 bits
ser.bytesize = serial.EIGHTBITS
# Set stop bits
if config.stop_bits == 2:
ser.stopbits = serial.STOPBITS_TWO
else: # Default to 1 bit
ser.stopbits = serial.STOPBITS_ONE
# Set parity
if config.parity.upper() == 'O':
ser.parity = serial.PARITY_ODD
elif config.parity.upper() == 'E':
ser.parity = serial.PARITY_EVEN
else: # Default to none
ser.parity = serial.PARITY_NONE
# Disable hardware flow control
ser.rtscts = False
# Disable software flow control
ser.xonxoff = False
# Set timeout
ser.timeout = 0.1 # 100ms timeout
return ser
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <serial_device>")
print(f"Example: {sys.argv[0]} /dev/ttyS7")
sys.exit(1)
portname = sys.argv[1]
buff_size = 256
# Initialize serial configuration
config = SerialConfig()
try:
# Open serial port
ser = serial.Serial()
ser.port = portname
# Apply configuration and open serial port
ser = set_serial_config(ser, config)
ser.open()
if not ser.is_open:
print("Failed to open serial port")
sys.exit(1)
print(f"Serial port {portname} opened successfully")
print(f"Config: Baud rate {config.baud_rate}, Data bits {config.data_bits}, "
f"Stop bits {config.stop_bits}, Parity {config.parity}")
print("Press Ctrl+C to exit")
# Use select to monitor serial port data
while True:
# Wait for data to arrive on serial port
readable, _, _ = select.select([ser.fileno()], [], [], None)
if readable:
# Read data
data = ser.read(buff_size - 1)
if data:
# Try decoding as string, show hex if failed
try:
text = data.decode('utf-8')
except UnicodeDecodeError:
text = f"[Binary data] {data.hex()}"
print(f"Received {len(data)} bytes: {text}")
# Echo data
ser.write(data)
except serial.SerialException as e:
print(f"Serial error: {e}")
sys.exit(1)
except KeyboardInterrupt:
print("\nUser interrupted, exiting")
finally:
if 'ser' in locals() and ser.is_open:
ser.close()
print("Serial port closed")
if __name__ == "__main__":
main()
Install the dependency first: pip install pyserial
Test RS485-1: python uart_example.py /dev/ttyS3
3. DI
The EC700 provides one digital input channel for detecting dry-contact signals, corresponding to the DIN+ and DIN- terminals.
| Hardware interface | IO index |
|---|---|
| DI-1 | 130 |
3.1 Quick Test
#!/bin/bash
# EC700 DI (Digital Input) Test
# Usage: bash di_example.sh <GPIO_NUM>
# Example: bash di_example.sh 130
if [ $# -lt 1 ]; then
echo "Usage: bash $0 <GPIO_NUM>"
echo "Example: bash $0 130"
exit 1
fi
GPIO=$1
GPIO_PATH=/sys/class/gpio/gpio${GPIO}
echo "EC700 DI Test - GPIO $GPIO"
echo "--------------------------"
# Export GPIO
if [ ! -d "$GPIO_PATH" ]; then
echo "$GPIO" > /sys/class/gpio/export 2>/dev/null
sleep 0.1
fi
if [ ! -d "$GPIO_PATH" ]; then
echo "ERROR: Cannot export GPIO $GPIO"
exit 1
fi
# Set direction to input
echo "in" > ${GPIO_PATH}/direction
echo ""
echo "Reading DI value..."
echo "Short DIN+ to 3.3V -> value=1"
echo "Short DIN+ to GND -> value=0"
echo "Press Ctrl+C to stop"
echo ""
# Read loop
while true; do
VAL=$(cat ${GPIO_PATH}/value 2>/dev/null)
if [ "$VAL" != "$LAST" ]; then
echo "[$(date +%H:%M:%S)] DI = $VAL"
LAST=$VAL
fi
sleep 0.2
done
Run: bash di_example.sh 130
After running the script, repeatedly short or open DIN+ and DIN- to observe the digital input state changes.
3.2 C Code Example
/*
* EC700 DI (Digital Input) Test
* Usage: ./di_example <GPIO_NUM>
* Example: ./di_example 130
*
* Connect DIN+ to 3.3V -> reads 1
* Connect DIN+ to GND -> reads 0
* Ctrl+C to stop
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
static int keep_running = 1;
static void sig_handler(int sig)
{
(void)sig;
keep_running = 0;
}
/* return 0 on success, -1 on error */
static int gpio_write_file(const char *path, const char *value)
{
int fd = open(path, O_WRONLY);
if (fd < 0) {
perror("open");
return -1;
}
if (write(fd, value, strlen(value)) < 0) {
perror("write");
close(fd);
return -1;
}
close(fd);
return 0;
}
/* return value char on success, -1 on error */
static int gpio_read_value(const char *path)
{
char buf[4] = {0};
int fd = open(path, O_RDONLY);
if (fd < 0) {
perror("open");
return -1;
}
if (read(fd, buf, sizeof(buf) - 1) < 0) {
perror("read");
close(fd);
return -1;
}
close(fd);
return buf[0];
}
int main(int argc, char *argv[])
{
int gpio;
char path[128];
char export_str[16];
int last_val = -1;
if (argc < 2) {
fprintf(stderr, "Usage: %s <GPIO_NUM>\n", argv[0]);
fprintf(stderr, "Example: %s 130\n", argv[0]);
return 1;
}
gpio = atoi(argv[1]);
if (gpio < 0 || gpio > 512) {
fprintf(stderr, "Invalid GPIO number: %d\n", gpio);
return 1;
}
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
printf("EC700 DI Test - GPIO %d\n", gpio);
printf("--------------------------\n");
/* Export GPIO */
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", gpio);
if (access(path, F_OK) != 0) {
snprintf(export_str, sizeof(export_str), "%d", gpio);
if (gpio_write_file("/sys/class/gpio/export", export_str) < 0) {
fprintf(stderr, "ERROR: Cannot export GPIO %d\n", gpio);
return 1;
}
usleep(100000); /* 100ms settle time */
}
/* Set direction to input */
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio);
if (gpio_write_file(path, "in") < 0) {
fprintf(stderr, "ERROR: Cannot set GPIO %d to input\n", gpio);
return 1;
}
printf("\nReading DI value...\n");
printf("Short DIN+ to 3.3V -> value=1\n");
printf("Short DIN+ to GND -> value=0\n");
printf("Press Ctrl+C to stop\n\n");
/* Read loop */
while (keep_running) {
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio);
int val = gpio_read_value(path);
if (val < 0) {
fprintf(stderr, "ERROR: Cannot read GPIO %d value\n", gpio);
break;
}
if (val != last_val) {
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
printf("[%02d:%02d:%02d] DI = %c\n",
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec,
val);
fflush(stdout);
last_val = val;
}
usleep(10000); /* 10ms */
}
/* Unexport */
printf("\nCleaning up...\n");
snprintf(export_str, sizeof(export_str), "%d", gpio);
gpio_write_file("/sys/class/gpio/unexport", export_str);
printf("Done.\n");
return 0;
}
Compilar: gcc di_example.c -o di_example
Run: ./di_example 130
3.3 Python Code Example
#!/usr/bin/env python3
"""
EC700 DI (Digital Input) Test
Usage: python3 di_example.py <GPIO_NUM>
Example: python3 di_example.py 130
Connect DIN+ to 3.3V -> reads 1
Connect DIN+ to GND -> reads 0
Ctrl+C to stop
"""
import sys
import os
import time
GPIO_BASE = "/sys/class/gpio"
def gpio_export(num):
path = os.path.join(GPIO_BASE, "export")
with open(path, "w") as f:
f.write(str(num))
def gpio_unexport(num):
path = os.path.join(GPIO_BASE, "unexport")
with open(path, "w") as f:
f.write(str(num))
def gpio_set_direction(num, direction):
path = os.path.join(GPIO_BASE, f"gpio{num}", "direction")
with open(path, "w") as f:
f.write(direction)
def gpio_read_value(num):
path = os.path.join(GPIO_BASE, f"gpio{num}", "value")
with open(path, "r") as f:
return f.read().strip()
def main():
if len(sys.argv) < 2:
print(f"Usage: python3 {sys.argv[0]} <GPIO_NUM>")
print(f"Example: python3 {sys.argv[0]} 130")
sys.exit(1)
gpio = int(sys.argv[1])
gpio_path = os.path.join(GPIO_BASE, f"gpio{gpio}")
print(f"EC700 DI Test - GPIO {gpio}")
print("-" * 26)
# Export GPIO
if not os.path.exists(gpio_path):
try:
gpio_export(gpio)
time.sleep(0.1)
except Exception as e:
print(f"ERROR: Cannot export GPIO {gpio}: {e}")
sys.exit(1)
if not os.path.exists(gpio_path):
print(f"ERROR: GPIO {gpio} export failed")
sys.exit(1)
# Set direction
try:
gpio_set_direction(gpio, "in")
except Exception as e:
print(f"ERROR: Cannot set GPIO {gpio} to input: {e}")
gpio_unexport(gpio)
sys.exit(1)
print()
print("Reading DI value...")
print("Short DIN+ to 3.3V -> value=1")
print("Short DIN+ to GND -> value=0")
print("Press Ctrl+C to stop")
print()
last_val = None
try:
while True:
val = gpio_read_value(gpio)
if val != last_val:
now = time.strftime("%H:%M:%S", time.localtime())
print(f"[{now}] DI = {val}")
last_val = val
time.sleep(0.01)
except KeyboardInterrupt:
pass
except Exception as e:
print(f"ERROR: {e}")
finally:
print("\nCleaning up...")
try:
gpio_unexport(gpio)
except Exception:
pass
print("Done.")
if __name__ == "__main__":
main()
Run: python di_example.py 130
4. DO
The EC700 provides two relay output channels supporting normally-open dry-contact output for industrial relays, used to control external circuit on/off states. Hardware Interface:
| IO | Índice IO | Número IO | Grupo Chip |
|---|---|---|---|
| DO-1 | 129 | GPIO4_A | gpiochip1 |
| DO-2 | 128 | GPIO4_A | gpiochip0 |
4.1 Quick Test
#!/bin/bash
# EC700 DO (Digital Output) Test
# Usage: bash do_example.sh <GPIO_NUM> <on|off>
# DOUT1: bash do_example.sh 129 on
# DOUT2: bash do_example.sh 128 off
if [ $# -lt 1 ]; then
echo "Usage: bash $0 <GPIO_NUM> [on|off]"
echo " GPIO: 129=DOUT1 128=DOUT2"
echo " If on/off omitted: toggle"
exit 1
fi
GPIO=$1
GPIO_PATH=/sys/class/gpio/gpio${GPIO}
# Export
if [ ! -d "$GPIO_PATH" ]; then
echo "$GPIO" > /sys/class/gpio/export 2>/dev/null
sleep 0.1
fi
# Set direction
echo "out" > ${GPIO_PATH}/direction 2>/dev/null
# Read current value
CUR=$(cat ${GPIO_PATH}/value 2>/dev/null)
if [ $# -ge 2 ]; then
case "$2" in
on|1) VAL=1 ;;
off|0) VAL=0 ;;
*) echo "Invalid: $2 (use on/off or 1/0)"; exit 1 ;;
esac
else
# Toggle
if [ "$CUR" = "1" ]; then VAL=0; else VAL=1; fi
fi
echo "$VAL" > ${GPIO_PATH}/value
CUR=$(cat ${GPIO_PATH}/value)
[ "$CUR" = "1" ] && STATE="ON (Relay Closed)" || STATE="OFF (Relay Open)"
echo "DOUT GPIO=$1 -> $STATE"
# Cleanup
echo "$GPIO" > /sys/class/gpio/unexport 2>/dev/null
Compilar: gcc do_example.c -o do_example
Run: ./do_example 129 on
4.2 C Code Example
/*
* EC700 DO (Digital Output) Test
* Usage: ./do_example <GPIO_NUM> [on|off]
* GPIO 129 = DOUT1 128 = DOUT2
* Without on/off: toggle
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
static int gpio_write_file(const char *path, const char *value)
{
int fd = open(path, O_WRONLY);
if (fd < 0) { perror("open"); return -1; }
if (write(fd, value, strlen(value)) < 0) { perror("write"); close(fd); return -1; }
close(fd);
return 0;
}
static int gpio_read_value(const char *path)
{
char buf[4] = {0};
int fd = open(path, O_RDONLY);
if (fd < 0) { perror("open"); return -1; }
if (read(fd, buf, sizeof(buf) - 1) < 0) { perror("read"); close(fd); return -1; }
close(fd);
return buf[0];
}
int main(int argc, char *argv[])
{
int gpio, val;
char path[128], export_str[16], val_str[2];
if (argc < 2) {
fprintf(stderr, "Usage: %s <GPIO_NUM> [on|off]\n", argv[0]);
fprintf(stderr, " GPIO 129=DOUT1 128=DOUT2\n");
fprintf(stderr, " Without on/off: toggle\n");
return 1;
}
gpio = atoi(argv[1]);
snprintf(export_str, sizeof(export_str), "%d", gpio);
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", gpio);
/* Export */
if (access(path, F_OK) != 0) {
gpio_write_file("/sys/class/gpio/export", export_str);
usleep(100000);
}
/* Set direction */
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio);
gpio_write_file(path, "out");
/* Read current */
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio);
int cur = gpio_read_value(path);
if (argc >= 3) {
if (strcmp(argv[2], "on") == 0 || strcmp(argv[2], "1") == 0)
val = 1;
else if (strcmp(argv[2], "off") == 0 || strcmp(argv[2], "0") == 0)
val = 0;
else {
fprintf(stderr, "Invalid value: %s (use on/off or 1/0)\n", argv[2]);
gpio_write_file("/sys/class/gpio/unexport", export_str);
return 1;
}
} else {
val = (cur == '1') ? 0 : 1; /* toggle */
}
snprintf(val_str, sizeof(val_str), "%d", val);
gpio_write_file(path, val_str);
cur = gpio_read_value(path);
printf("DOUT GPIO=%d -> %s (%s)\n", gpio,
(cur == '1') ? "ON (Relay Closed)" : "OFF (Relay Open)",
(cur == '1') ? "COM-NO Closed" : "COM-NO Open");
/* Unexport */
gpio_write_file("/sys/class/gpio/unexport", export_str);
return 0;
}
4.3 Python Code Example
#!/usr/bin/env python3
"""
EC700 DO (Digital Output) Test
Usage: python3 do_example.py <GPIO_NUM> [on|off]
GPIO 129 = DOUT1 128 = DOUT2
Without on/off: toggle
"""
import sys
import os
import time
GPIO_BASE = "/sys/class/gpio"
def gpio_export(num):
with open(os.path.join(GPIO_BASE, "export"), "w") as f:
f.write(str(num))
def gpio_unexport(num):
with open(os.path.join(GPIO_BASE, "unexport"), "w") as f:
f.write(str(num))
def gpio_set_direction(num, direction):
path = os.path.join(GPIO_BASE, f"gpio{num}", "direction")
with open(path, "w") as f:
f.write(direction)
def gpio_write_value(num, value):
path = os.path.join(GPIO_BASE, f"gpio{num}", "value")
with open(path, "w") as f:
f.write(str(value))
def gpio_read_value(num):
path = os.path.join(GPIO_BASE, f"gpio{num}", "value")
with open(path, "r") as f:
return f.read().strip()
def main():
if len(sys.argv) < 2:
print(f"Usage: python3 {sys.argv[0]} <GPIO_NUM> [on|off]")
print(" GPIO 129=DOUT1 128=DOUT2")
print(" Without on/off: toggle")
sys.exit(1)
gpio = int(sys.argv[1])
gpio_path = os.path.join(GPIO_BASE, f"gpio{gpio}")
# Export
if not os.path.exists(gpio_path):
try:
gpio_export(gpio)
time.sleep(0.1)
except Exception as e:
print(f"ERROR: export GPIO {gpio}: {e}")
sys.exit(1)
# Set direction
gpio_set_direction(gpio, "out")
# Read current
cur = gpio_read_value(gpio)
if len(sys.argv) >= 3:
arg = sys.argv[2].lower()
if arg in ("on", "1"):
val = 1
elif arg in ("off", "0"):
val = 0
else:
print(f"Invalid value: {arg} (use on/off or 1/0)")
gpio_unexport(gpio)
sys.exit(1)
else:
val = 0 if cur == "1" else 1 # toggle
gpio_write_value(gpio, val)
cur = gpio_read_value(gpio)
if cur == "1":
state = "ON (Relay Closed) COM-NO Closed"
else:
state = "OFF (Relay Open) COM-NO Open"
print(f"DOUT GPIO={gpio} -> {state}")
gpio_unexport(gpio)
if __name__ == "__main__":
main()
Run: python do_example.py 129 on
5. Ethernet Ports
The Ethernet ports are divided into WAN y LAN, managed by the internal network service. Configuration is done via the web. See: [EC Series ARM Industrial Computer Quick Start / Preparation].
6. Cellular Wireless (Optional)
The EC700 product supports 4G/5G communication (please contact customer service to purchase 4G/5G communication modules). Module identification and dialing are managed internally, requiring no user intervention. For more details, please refer to: [EC Series ARM Industrial Computer Quick Start / Preparation]
Note: The SIM card does not support hot-swapping. Power off the device before inserting or removing the SIM card.
7. WiFi (Optional)
The EC700 supports both WiFi hotspot and WiFi client modes (consult customer service for WiFi module purchases). It supports 2,4 GHz y 5 GHz bands. WiFi is managed by the internal program — no user intervention required. Please refer to: [EC Series ARM Industrial Computer Quick Start / Preparation]
8. Bluetooth (Optional)
The EC300 product series supports Bluetooth functionality.
8.1 Quick Test
# 1. View local Bluetooth hardware status hciconfig -a # 2. Enter Bluetooth interactive console bluetoothctl # Bluetooth initialization, essential for pairing # Power on the Bluetooth controller power on # Turn on the pairing agent to handle pairing pop-ups/verification codes agent on # Set as default agent default-agent # Turn on scanning, wait for [NEW] Device AA:BB:CC:DD:EE:FF target device to be printed before pairing scan on # Clear old device pairing cache (optional, resolves cache abnormalities) remove AA:BB:CC:DD:EE:FF # Initiate pairing, confirm by typing yes in the pop-up, PIN code is usually 0000/1234 pair AA:BB:CC:DD:EE:FF # Trust the device to support automatic reconnection trust AA:BB:CC:DD:EE:FF # Establish Bluetooth connection connect AA:BB:CC:DD:EE:FF # Turn off scanning to stop log flooding scan off # Debug query commands # View all scanned devices devices # View all paired devices paired-devices # View currently connected devices connections # View target device complete protocols and connection status info AA:BB:CC:DD:EE:FF # Disconnect device connection disconnect AA:BB:CC:DD:EE:FF # Turn off Bluetooth power (execute as needed) power off # Exit Bluetooth console exit
9. Audio
The EC700 supports a 3.5mm headset jack for microphone recording and speaker playback.
9.1 Quick Test
#Recording # Record 10 seconds of audio arecord -D hw:1,0 -f cd -t wav test.wav -d 10 #Playback: #Enter the command to open the sound debugging console alsamixer #Press F6 to select default:1 rockchip-es8388 #Press Enter to enter #Ensure <Headphon><OUT1> is set to [00], press the M key to toggle the state #Use the following command to play the audio in the current folder aplay -D hw:1,0 test.wav
10. Display
10.1 HDMI Output
The EC700 supports up to 4K @ 60 fps video output.
Video output: Connect a monitor to the HDMI port. The device auto-adjusts the resolution on boot. If display issues occur, try switching the monitor resolution to 1080P.
Audio output: Connect an audio-capable monitor to the HDMI port and use the desktop media player to test:
/userdata/piano2-CoolEdit.mp3
10.2 HDMI Input
Supports 1080P60 video input.
Video Input:
# Connect the PC to the device via HDMI, and use the following command to check if the connection is successful v4l2-ctl -d /dev/video0 -D # Start capturing images v4l2-ctl --verbose -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat='BGR3' --stream-mmap=4 --stream-skip=0 --stream-to=~/Desktop/1080P60.bgr --stream-count=50 --stream-poll # Captures 50 frames by default. After capture is complete, it is saved as 1080P60.bgr at the path ~/Desktop/1080P60.bgr # You can use an image viewer that supports BGR to open it and verify whether the output color and resolution are normal. # It is recommended to use the 7YUV program for viewing.
Audio Input:
# Ensure the HDMI RX cable is connected between the PC and the device, ensure audio is playing on the PC, and specify the output sound card as RK xxx in Win10. # Execute the following command on the board to capture HDMI RX audio input (the default HDMIRX input sound card is hw:0,0): arecord -D hw:0,0 -f dat hdmi_rx.wav # Stop capturing after a period of time by pressing Ctrl+C. The file will be saved in the current directory. # Copy the audio file hdmi_rx.wav to the Win10 PC for playback. The sound should match.
System REST API
The EC700 exposes a REST API for querying device and network status programmatically. Both endpoints accept GET requests with no parameters.
1. Get Device Basic Information
-
- URL:
GET http://{device_IP}/rpc-api/data/devinfo
- URL:
-
- Method: GET
-
- Request parameters: Ninguno
Response fields:
| Campo | Descripción | Type | Observaciones |
|---|---|---|---|
| code | Response status code | int | Always 200 on success |
| data.model | Device model | string | Device model |
| data.sn | Device Serial number | string | Device Serial number |
| data.version | Device Version | string | Software version number |
Response example:
{
"code": 200,
"data": {
"model": "EC700",
"sn": "xxxxxxxxxxxx",
"version": "x.x.x"
}
}
2. Get Device WWAN (Cellular) Network Information
- URL:
GET http://{device_IP}/rpc-api/data/wwaninfo - Method: GET
- Request parameters: Ninguno
Response fields:
| Campo | Descripción | Type | Observaciones |
|---|---|---|---|
| code | Response status code | int | Always 200 on success |
| data.enable | Cellular enabled | boolean | true = enabled, false = disabled |
| data.status | Dial-up status | number | 0 = powered on, 1 = initializing, 2 = SIM detection, 3 = PDP activated, 4 = dialing, 5 = ready |
| data.ip | WWAN IP address | string | IP assigned by cellular network |
| data.mask | Subnet mask | string | Subnet mask |
| data.gateway | Gateway address | string | Default gateway |
| data.metric | Route metric | number | Lower value = higher priority |
| data.dns | DNS server | string | DNS resolver address |
| data.version | Module firmware version | string | 5G/4G module firmware version |
| data.imei | IMEI | string | Module IMEI number |
| data.signal | Signal strength | number | 0–100, higher = stronger signal |
| data.ccid | SIM card ID | string | SIM ICCID |
| data.operator | Carrier | string | Currently registered carrier name |
| data.sim.maxcall | Max redial attempts | number | Retry limit on dial failure |
| data.sim.sim0.auth | APN auth method | number | 0 = None, 1 = PAP, 2 = CHAP, 3 = PAP/CHAP |
| data.sim.sim0.addr | APN address | string | Access point name |
| data.sim.sim0.name | APN username | string | APN auth username |
| data.sim.sim0.passwd | APN password | string | APN auth password |
| data.sim.sim0.pinCode | PIN code | string | SIM card PIN code |
| data.ping.enable | Network probe | boolean | true = enabled, false = disabled |
| data.ping.addr0 | Probe host 0 | string | Network probe target address 1 |
| data.ping.addr1 | Probe host 1 | string | Network probe target address 2 |
| data.ping.cyc | Probe interval | number | Interval in seconds |
| data.ping.num | Probe count | number | Failure threshold count |
| data.ping.state | Probe status | number | 255 = not probed, 0 = failed, 1 = success |
Response example:
{
"code": 200,
"data": {
"enable": true,
"status": 0,
"ip": "",
"mask": "",
"gateway": "",
"metric": 3,
"dns": "223.5.5.5 8.8.8.8",
"version": "",
"imei": "",
"signal": -1,
"ccid": "",
"operator": "",
"sim": {
"maxcall": 5,
"sim0": {
"auth": 3,
"addr": "",
"name": "",
"passwd": "",
"pinCode": ""
},
},
"ping": {
"enable": true,
"addr0": "223.5.5.5",
"addr1": "8.8.8.8",
"cyc": 10,
"num": 3,
"state": 255
}
}
}
Pre-Installed Software
The EC700 comes with several industrial software packages pre-installed and configured for auto-start. Here’s how to manage each one.
1. Internal Management Program (iotrouter)
To simplify user experience, the EC700 series ships with the built-in iotrouter management program that starts on boot. The management program covers:
- Device initialization
- Network management
- Cellular management
- WiFi management
- Cortafuegos
- Device configuration service (default port 80, configurable; file:
/usr/local/src/iotrouter/web/user-config.js) - File browser (default path:
/run/media/; configurable; file:/usr/local/src/iotrouter/web/user-config.js)
Note: It is recommended to keep the internal program running. If you must disable it, you will need to take over the above management services yourself.
2. NeuronEX
The EC700 comes with NeuronEX-Lite pre-installed. The service starts automatically on boot and listens on port 8085.
For an introduction, see: [Ruta de aprendizaje del ordenador industrial ARM serie EC]
View service status: systemctl status neuronex
Reinicia el servicio: systemctl restart neuronex
Parar servicio: systemctl stop neuronex
Disable auto-start: systemctl disable neuronex
3. Nodo-RED
The EC700 comes with Node-RED pre-installed. The service starts automatically on boot and listens on port 1880. For an introduction, see: [Ruta de aprendizaje del ordenador industrial ARM serie EC]
View service status: systemctl status nodo-rojo
Reinicia el servicio: systemctl restart nodo-red
Parar servicio: systemctl stop nodo-rojo
Disable auto-start: systemctl disable node-red
4. FUXA
All EC700 series products come with FUXA pre-installed. The service starts automatically on boot and listens on port 1881. For an introduction, see: [Guía de desarrollo avanzado para los ordenadores industriales ARM de la serie EC]
View service status: systemctl status fuxa
Reinicia el servicio: systemctl restart fuxa
Parar servicio: systemctl stop fuxa
Disable auto-start: systemctl disable fuxa
5. Xfce4 Desktop
The default desktop environment is Xfce4. This is provided as a demonstration only. If you need to display other content, such as a Qt-based UI, you can develop it yourself.
The display manager is: lightdm
View service status: systemctl status lightdm
Reinicia el servicio: systemctl restart lightdm
Parar servicio: systemctl stop lightdm
Disable auto-start: systemctl disable lightdm
6. Custom User Programs
User applications are developed independently by users and run as separate processes. However, careful attention must be paid to memory and storage management to prevent system exceptions. Software can be added to start automatically via the system using the following methods:
/etc/rc.local- servicio systemd
/etc/init.dsystem
We also offer custom software development services. For inquiries, please contact our sales team.
7. Boot Logo Customization
Users can replace the system boot logo themselves.
| Logo File | Display Stage |
|---|---|
| logo.bmp | Displayed during the U-Boot phase |
| logo_kernel.bmp | Displayed during the kernel boot phase |
7.1 Format Requirements
The logo image must be a 24-bit BMP bitmap. The image resolution should not exceed the resolution of the connected HDMI display.
7.2 Logo Replacement
- Power on the device.
- Copy your custom
logo.bmpylogo_kernel.bmpfiles to theSDK_PATH/kernel-6.1directory, replacing the existing files of the same name.

Note: The logo filenames must not be changed.
Wrapping Up
The EC700 is built to get you from concept to deployed prototype fast. Between the open Linux environment, pre-installed industrial software stack (Node-RED, NeuronEX, FUXA), and straightforward hardware interfaces, most of the plumbing is already done — you just need to write your application logic and wire up your sensors and actuators.
A few things worth keeping in mind as you start developing:
- Start with the debug serial port. Even if you plan to work over SSH, the Type-C debug port is your fallback when the network isn’t cooperating.
- Leverage the REST API. En
/rpc-api/data/endpoints make it trivial to pull device info and cellular status into your own dashboards or monitoring scripts — no need to parse AT commands yourself. - Respect the iotrouter service. It handles network, WiFi, and cellular management behind the scenes. If you disable it, plan to reimplement those functions yourself.
- Mind your storage budget. With 128 GB on board and NVMe expansion available, you have room to breathe — but Docker images and AI model weights add up quickly.
If you’re looking for the full hardware specifications, protocol support matrix, or OEM/ODM customization options, check out the EC700 product page. For questions about SDK access, custom development, or bulk ordering, the IOTRouter team is ready to help — just reach out through the contact form on the site.