Guida allo sviluppo dell'EC700: Introduzione al PC industriale per l'AI Edge Computing

Questa guida aiuta gli sviluppatori a familiarizzare rapidamente con l'EC700, trattando argomenti quali la comunicazione tramite porta seriale, il controllo degli I/O digitali, l'integrazione delle API REST, la gestione del software preinstallato e la personalizzazione del logo di avvio.

L'EC700 è un PC industriale per l'edge computing basato sull'intelligenza artificiale, alimentato dal processore Rockchip RK3588J con NPU integrata da 6 TOPS, progettato per l'inferenza AI direttamente sul dispositivo. Viene comunemente impiegato nella produzione intelligente, nell'ispezione visiva industriale e in altri scenari di intelligenza artificiale. Consulta la scheda tecnica completa su Pagina del prodotto EC700.

Prerequisiti e strumenti per lo sviluppo di EC700

La presente guida si riferisce al gateway EC700. Prima di iniziare, assicurati di avere a disposizione i seguenti strumenti. Scarica i seguenti strumenti dal sito pagina di download.

Client SSH

Si consiglia di utilizzare MobaXterm, oppure è possibile utilizzare qualsiasi client SSH con cui si ha familiarità.

Strumento di debug seriale

Si consiglia di utilizzare XCOM, oppure è possibile utilizzare qualsiasi terminale seriale si preferisca.

Accessori hardware

Tra gli strumenti ausiliari più comuni per il debug figurano gli adattatori da USB a RS485, i cavi Ethernet, ecc. Ti preghiamo di prepararli tu stesso.

Toolchain per la compilazione incrociata

Se si stanno compilando applicazioni native in C/C++ su un PC host e si sta effettuando la distribuzione sull'EC700.

Ambiente software

L'EC700 viene fornito con un ambiente Linux completamente integrato. Ecco cosa c'è sotto il cofano:

Software Versione
OS Linux integrato
Kernel Linux 6.1.118
Node.js v22.17.0
Python Python 3.10.12
Conchiglia bash
Docker V27.4.1
Qt V5.15.3
Ambiente desktop Xfce4

Risorse del dispositivo

Categoria Dettagli Osservazioni
Immagazzinamento 128 GB in totale ~108 GB di spazio libero di serie; espandibile tramite scheda SD o SSD M.2 NVMe
Memoria 8 GB ~6 GB di spazio libero già pronto all'uso
CPU RK3588 ~98% inattivo appena tolto dalla confezione
NPU 6 TOP ~100% inattivo appena tolto dalla confezione

Interfacce periferiche

1. Porta di debug

L'EC700 rende accessibile la porta seriale di debug del sistema tramite un Tipo-C interfaccia. Utilizza queste impostazioni nel tuo terminale seriale:

2. Porte seriali (RS485 / RS232)

L'EC700 dispone di due canali RS485 e un canale RS232:

Interfaccia hardware File del dispositivo
RS485-1 /dev/ttyS3 (corrisponde a A1 / B1)
RS485-2 /dev/ttyS4 (corrisponde a A2 / B2)
RS232 /dev/ttyS1 (corrisponde a TXD / RTD)

Nota: Le porte RS485 utilizzano il controllo automatico della direzione. Non è necessario passare manualmente dalla modalità di trasmissione a quella di ricezione: l'hardware lo gestisce automaticamente.

2.1 Test rapido

Utilizza il minicom strumento di prova. Per ulteriori dettagli sull'utilizzo, consultare le risorse online o cercare su GPT/Google.

2.2 Esempio di codice in C

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFFER_SIZE 256

typedef struct {
  int baud_rate; // Velocità di trasmissione
  int data_bits; // Bit di dati (5, 6, 7, 8)
  int stop_bits; // Bit di stop (1,2)
  char parity; // Bit di parità (N: Nessuna, O: Dispari, E: Pari)
} SerialConfig;

int set_serial_attr(int fd, SerialConfig *config)
{
  struct termios tty;

  if (tcgetattr(fd, &tty) 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, "Velocità di trasmissione non supportata, si utilizza 115200\n");
 velocità = B115200;
  }
  cfsetispeed(&tty, velocità);
  cfsetospeed(&tty, velocità);

  // Imposta i bit di dati
  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, "Bit di dati non supportati, si utilizzano 8\n");
    tty.c_cflag |= CS8;
  }

  // Imposta i bit di stop
  if (config->stop_bits == 2) {
  tty.c_cflag |= CSTOPB;
  } else {
  tty.c_cflag &= ~CSTOPB;
  }

  // Imposta il bit di parità
  switch (config->parity) {
    case 'N': case 'n':
 tty.c_cflag &= ~PARENB; // Nessuna
 break;
    case 'O': case 'o':
      tty.c_cflag |= PARENB; // Dispari
 tty.c_cflag |= PARODD;
 break;
    case 'E': case 'e':
 tty.c_cflag |= PARENB; // Pari
      tty.c_cflag &= ~PARODD;
 break;
    default:
 fprintf(stderr, "Parità non supportata, si utilizza N\n");
 tty.c_cflag &= ~PARENB;
  }

  // Altre impostazioni
  tty.c_cflag |= (CLOCAL | CREAD); // Abilita la modalità ricevitore e locale
  tty.c_cflag &= ~CRTSCTS; // Disabilita il controllo di flusso hardware

  tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Modalità di input grezza
  tty.c_oflag &= ~OPOST; // Modalità di output grezza

  tty.c_cc[VMIN] = 1; // Numero minimo di caratteri da leggere
  tty.c_cc[VTIME] = 0; // Timeout di lettura (unità: 0,1 secondi)

  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, "Uso: %s \n", argv[0]);
    exit(EXIT_FAILURE);
  }

  portname = argv[1];

  // Configura i parametri della porta seriale
  SerialConfig config = {
    .baud_rate = 115200, // Velocità di trasmissione
    .data_bits = 8, // Bit di dati
    .stop_bits = 1, // Bit di stop
    .parity = 'N' // Parità (N: Nessuna, O: Dispari, E: Pari)
  };

  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("Test di eco della porta seriale in esecuzione su %s\n", portname);
  printf("Configurazione: baud %d, bit di dati %d, bit di stop %d, parità %c\n",
  config.baud_rate, config.data_bits, config.stop_bits, config.parity);
  printf("Premere Ctrl+C per uscire.\n");

  fd_set readfds;
  char buffer[BUFFER_SIZE];
  int n;

  while (1) {
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);

    // Attesa indefinita per l'arrivo dei dati (impostazione del timeout rimossa)
    if (select(fd + 1, &readfds, NULL, NULL, NULL)  0) {
 buffer[n] = '\0';
 printf("Byte ricevuti: %d\n", n, buffer);

        // Ripetizione dei dati
 write(fd, buffer, n);
    } else if (n < 0) {
 if (errno != EAGAIN && errno != EWOULDBLOCK) {
 perror("read");
        break;
 }
 }
    }
  }

  close(fd);
  return 0;
}

Compilazione: gcc rs485_example.c -o rs485_example

Test RS485-1: ./rs485_example /dev/ttyS3

2.3 Esempio di codice Python

import serial
import select
import sys
import tty

class SerialConfig:
  def __init__(self):
    self.baud_rate = 115200 # Velocità di trasmissione
    self.data_bits = 8 # Bit di dati
    self.stop_bits = 1 # Bit di stop
    self.parity = 'N' # Parità (N: Nessuna, O: Dispari, E: Pari)

def set_serial_config(ser, config):
  """Configura i parametri della porta seriale"""
  # Imposta la velocità di trasmissione
  ser.baudrate = config.baud_rate
  
  # Imposta i bit di dati
  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: # Impostazione predefinita a 8 bit
    ser.bytesize = serial.EIGHTBITS

  # Imposta i bit di stop
  if config.stop_bits == 2:
    ser.stopbits = serial.STOPBITS_TWO
  else: # Impostazione predefinita: 1 bit
    ser.stopbits = serial.STOPBITS_ONE

  # Imposta la parità
  if config.parity.upper() == 'O':
    ser.parity = serial.PARITY_ODD
  elif config.parity.upper() == 'E':
    ser.parity = serial.PARITY_EVEN
  altrimenti: # Impostazione predefinita: nessuna
    ser.parity = serial.PARITY_NONE
 
 # Disabilita il controllo di flusso hardware
  ser.rtscts = False
  # Disabilita il controllo di flusso software
  ser.xonxoff = False
  # Imposta il timeout
  ser.timeout = 0.1 # Timeout di 100 ms

  return ser

def main():
  if len(sys.argv) < 2:
    print(f"Uso: {sys.argv[0]} ")
    print(f"Esempio: {sys.argv[0]} /dev/ttyS7")
    sys.exit(1)

  portname = sys.argv[1]
  buff_size = 256
 
 # Inizializza la configurazione seriale
  config = SerialConfig()
  
  try:
    # Apri la porta seriale
    ser = serial.Serial()
    ser.port = portname
    # Applica la configurazione e apri la porta seriale
    ser = set_serial_config(ser, config)
    ser.open()

    if not ser.is_open:
 print("Impossibile aprire la porta seriale")
 sys.exit(1)

 print(f"Porta seriale {portname} aperta con successo")
    print(f"Configurazione: Velocità di trasmissione {config.baud_rate}, Bit di dati {config.data_bits}, "
f"Bit di stop {config.stop_bits}, Parità {config.parity}")
    print("Premere Ctrl+C per uscire")
    
    # Utilizza `select` per monitorare i dati della porta seriale
    while True:
 # Attendi l'arrivo dei dati sulla porta seriale
 readable, _, _ = select.select([ser.fileno()], [], [], None)

      if readable:
 # Leggi i dati
 data = ser.read(buff_size - 1)
 if data:
 # Prova a decodificare come stringa, mostra il valore esadecimale in caso di errore
 try:
 text = data.decode('utf-8')
         except UnicodeDecodeError:
 text = f"[Dati binari] {data.hex()}"

 print(f"Ricevuti {len(data)} byte: {text}")

        # Invia i dati in eco
 ser.write(data)

  except serial.SerialException as e:
    print(f"Errore seriale: {e}")
    sys.exit(1)
  except KeyboardInterrupt:
    print("\nInterruzione da parte dell'utente, uscita")
  finally:
    if 'ser' in locals() and ser.is_open:
    ser.close()
    print("Porta seriale chiusa")
if __name__ == "__main__":
  main()

Per prima cosa, installa la dipendenza: pip install pyserial

Test RS485-1: python uart_example.py /dev/ttyS3

3. DI

L'EC700 dispone di un canale di ingresso digitale per il rilevamento di segnali a contatto pulito, corrispondente ai terminali DIN+ e DIN-.

Interfaccia hardware Indice IO
DI-1 130

3.1 Test rapido

#!/bin/bash
Test # EC700 DI (ingresso digitale)
Utilizzo di #: bash di_example.sh 
Esempio di #: bash di_example.sh 130

if [ $# -lt 1 ]; then
  echo "Utilizzo: bash $0 "
  echo "Esempio: bash $0 130"
  exit 1
fi

GPIO=$1
GPIO_PATH=/sys/class/gpio/gpio${GPIO}

echo "Test EC700 DI - GPIO $GPIO"
echo "--------------------------"

Esportazione 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 "ERRORE: Impossibile esportare il GPIO $GPIO"
  exit 1
fi

# Imposta la direzione su ingresso
echo "in" > ${GPIO_PATH}/direction

echo ""
echo "Lettura del valore DI..."
echo "Cortocircuito DIN+ a 3,3 V -> valore=1"
echo "Cortocircuito DIN+ a GND -> valore=0"
echo "Premere Ctrl+C per interrompere"
echo ""

# Ciclo di lettura
while true; do
  VAL=$(cat ${GPIO_PATH}/value 2>/dev/null)
  if [ "$VAL" != "$LAST" ]; then
    echo "[$(data +%H:%M:%S)] DI = $VAL"
    LAST=$VAL
  fi
  sleep 0.2
done

Esegui: bash di_example.sh 130

Dopo aver eseguito lo script, cortocircuitare o aprire ripetutamente DIN+ e DIN- per osservare le variazioni dello stato degli ingressi digitali.

3.2 Esempio di codice in C

/*
* 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;
}

Compilazione: gcc di_example.c -o di_example

Esegui: ./di_example 130

3.3 Esempio di codice Python

#!/usr/bin/env python3
"""
Test EC700 DI (ingresso digitale)
Utilizzo: python3 di_example.py 
Esempio: python3 di_example.py 130

Collegare DIN+ a 3,3 V -> viene letto 1
Collegare DIN+ a GND -> viene letto 0
Premere Ctrl+C per interrompere
"""

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"Uso: python3 {sys.argv[0]} ")
    print(f"Esempio: 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"Test EC700 DI - GPIO {gpio}")
print("-" * 26)

# Esportazione GPIO
if not os.path.exists(gpio_path):
  try:
    gpio_export(gpio)
    time.sleep(0.1)
  except Exception as e:
    print(f"ERRORE: Impossibile esportare il GPIO {gpio}: {e}")
    sys.exit(1)

if not os.path.exists(gpio_path):
  print(f"ERRORE: esportazione del GPIO {gpio} non riuscita")
  sys.exit(1)

# Imposta direzione
try:
  gpio_set_direction(gpio, "in")
except Exception as e:
  print(f"ERRORE: Impossibile impostare il GPIO {gpio} come ingresso: {e}")
  gpio_unexport(gpio)
  sys.exit(1)

print()
print("Lettura del valore DI...")
print("Cortocircuito tra DIN+ e 3,3 V -> valore=1")
print("Cortocircuito tra DIN+ e GND -> valore=0")
print("Premere Ctrl+C per interrompere")
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"ERRORE: {e}")
finally:
  print("\nPulizia in corso...")
  try:
    gpio_unexport(gpio)
  except Exception:
    pass
  print("Fatto.")

if __name__ == "__main__":
  main()

Esegui: python di_example.py 130

4. DA FARE

L'EC700 offre due canali di uscita a relè che supportano un'uscita a contatto pulito normalmente aperto per relè industriali, utilizzata per controllare gli stati di accensione e spegnimento dei circuiti esterni. Interfaccia hardware:

IO Indice IO Numero IO Chip Group
DO-1 129 GPIO4_A gpiochip1
DO-2 128 GPIO4_A  gpiochip0

4.1 Test rapido

#!/bin/bash
# Test DO (uscita digitale) EC700
# Modalità d'uso: bash do_example.sh  
# DOUT1: bash do_example.sh 129 on
# DOUT2: bash do_example.sh 128 off

if [ $# -lt 1 ]; then
  echo "Uso: bash $0  [on|off]"
  echo " GPIO: 129=DOUT1 128=DOUT2"
  echo " Se on/off viene omesso: commuta"
  exit 1
fi

GPIO=$1
GPIO_PATH=/sys/class/gpio/gpio${GPIO}

# Esportazione
if [ ! -d "$GPIO_PATH" ]; then
  echo "$GPIO" > /sys/class/gpio/export 2>/dev/null
  sleep 0.1
fi

# Imposta direzione
echo "out" > ${GPIO_PATH}/direction 2>/dev/null

# Leggi valore corrente
CUR=$(cat ${GPIO_PATH}/value 2>/dev/null)

if [ $# -ge 2 ]; then
  case "$2" in
    on|1) VAL=1 ;;
    off|0) VAL=0 ;;
    *) echo "Non valido: $2 (utilizzare on/off o 1/0)"; exit 1 ;;
  esac
else
  # Inverti
  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 (relè chiuso)" || STATE="OFF (relè aperto)"
echo "DOUT GPIO=$1 -> $STATE"

# Pulizia
echo "$GPIO" > /sys/class/gpio/unexport 2>/dev/null

Compilazione: gcc do_example.c -o do_example

Esegui: ./do_example 129 on

4.2 Esempio di codice in C

/*
* Test EC700 DO (uscita digitale)
* Modalità d'uso: ./do_example  [on|off]
* GPIO 129 = DOUT1 128 = DOUT2
* Senza on/off: commuta
*/

#include 
#include 
#include 
#include 
#include 

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, "Uso: %s  [on|off]\n", argv[0]);
    fprintf(stderr, " GPIO 129=DOUT1 128=DOUT2\n");
    fprintf(stderr, " Senza on/off: commuta\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);

/* Esportazione */
if (access(path, F_OK) != 0) {
  gpio_write_file("/sys/class/gpio/export", export_str);
  usleep(100000);
}

/* Imposta direzione */
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio);
gpio_write_file(path, "out");

/* Leggi il valore attuale */
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, "Valore non valido: %s (utilizzare on/off o 1/0)\n", argv[2]);
    gpio_write_file("/sys/class/gpio/unexport", export_str);
    return 1;
  }
} else {
    val = (cur == '1') ? 0 : 1; /* inverti */
}

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 (relè chiuso)" : "OFF (relè aperto)",
(cur == '1') ? "COM-NO chiuso" : "COM-NO aperto");

/* Rimuovi dall'esportazione */
gpio_write_file("/sys/class/gpio/unexport", export_str);

return 0;
}

4.3 Esempio di codice Python

 #!/usr/bin/env python3
"""
Test DO (uscita digitale) EC700
Utilizzo: python3 do_example.py  [on|off]
GPIO 129 = DOUT1 128 = DOUT2
Senza on/off: commutazione
"""

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"Uso: python3 {sys.argv[0]}  [on|off]")
    print(" GPIO 129=DOUT1 128=DOUT2")
    print(" Senza on/off: toggle")
    sys.exit(1)

  gpio = int(sys.argv[1])
  gpio_path = os.path.join(GPIO_BASE, f"gpio{gpio}")

  Esportazione #
  if not os.path.exists(gpio_path):
    try:
      gpio_export(gpio)
 time.sleep(0.1)
    except Exception as e:
 print(f"ERRORE: esportazione GPIO {gpio}: {e}")
 sys.exit(1)

  # Imposta direzione
  gpio_set_direction(gpio, "out")

  # Leggi valore attuale
  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"Valore non valido: {arg} (utilizzare on/off o 1/0)")
 gpio_unexport(gpio)
 sys.exit(1)
  else:
    val = 0 se cur == "1" altrimenti 1 # toggle

  gpio_write_value(gpio, val)
  cur = gpio_read_value(gpio)

  if cur == "1":
    state = "ON (relè chiuso) COM-NO chiuso"
  else:
    state = "OFF (relè aperto) COM-NO aperto"

  print(f"DOUT GPIO={gpio} -> {state}")

  gpio_unexport(gpio)

if __name__ == "__main__":
main()

Esegui: python do_example.py 129 in esecuzione

5. Porte Ethernet

Le porte Ethernet sono suddivise in WAN e LAN, gestito dal servizio di rete interna. La configurazione avviene tramite il web. Vedi: [Guida rapida / Preparazione del computer industriale ARM serie EC].

6. Rete cellulare wireless (opzionale)

Il prodotto EC700 supporta la comunicazione 4G/5G (si prega di contattare servizio clienti per l'acquisto di moduli di comunicazione 4G/5G). L'identificazione del modulo e la composizione del numero vengono gestite internamente, senza richiedere alcun intervento da parte dell'utente. Per ulteriori dettagli, consultare: [Guida rapida / Preparazione del computer industriale ARM serie EC]

Nota: la scheda SIM non supporta la sostituzione a caldo. Spegnere il dispositivo prima di inserire o rimuovere la scheda SIM.

7. Wi-Fi (opzionale)

L'EC700 supporta sia la modalità hotspot Wi-Fi che quella client Wi-Fi (consultare servizio clienti (per l'acquisto di moduli WiFi). Supporta 2,4 GHz e 5 GHz bande. Il WiFi è gestito dal programma interno — non è richiesto alcun intervento da parte dell'utente. Si prega di fare riferimento a: [Guida rapida / Preparazione del computer industriale ARM serie EC]

8. Bluetooth (opzionale)

La serie di prodotti EC300 supporta la funzionalità Bluetooth.

8.1 Test rapido

# 1. Visualizza lo stato dell'hardware Bluetooth locale
hciconfig -a

# 2. Accedi alla console interattiva Bluetooth
bluetoothctl

# Inizializzazione del Bluetooth, essenziale per l’accoppiamento
# Accensione del controller Bluetooth
power on
# Attivazione dell’agente di accoppiamento per gestire le finestre di dialogo di accoppiamento e i codici di verifica
agent on
# Impostazione come agente predefinito
default-agent

# Attivare la scansione, attendere che venga visualizzato il messaggio [NEW] Device AA:BB:CC:DD:EE:FF (dispositivo di destinazione) prima di procedere all’accoppiamento
scan on

# Cancellare la cache dei dispositivi accoppiati in precedenza (opzionale, risolve anomalie della cache)
rimuovi AA:BB:CC:DD:EE:FF
# Avvia l’accoppiamento, conferma digitando «yes» nella finestra pop-up; il codice PIN è solitamente 0000/1234
accoppia AA:BB:CC:DD:EE:FF
# Considera attendibile il dispositivo per supportare la riconnessione automatica
considera attendibile AA:BB:CC:DD:EE:FF
# Stabilisci la connessione Bluetooth
connetti AA:BB:CC:DD:EE:FF

# Disattiva la scansione per impedire il sovraccarico del log
disattiva scansione

# Eseguire il debug dei comandi di interrogazione
# Visualizzare tutti i dispositivi rilevati
devices
# Visualizzare tutti i dispositivi accoppiati
paired-devices
# Visualizzare i dispositivi attualmente connessi
connections
# Visualizzare i protocolli completi e lo stato di connessione del dispositivo di destinazione
info AA:BB:CC:DD:EE:FF

# Disconnetti il dispositivo
disconnect AA:BB:CC:DD:EE:FF
# Spegni il Bluetooth (esegui all’occorrenza)
power off
# Esci dalla console Bluetooth
exit

9. Audio

L'EC700 è dotato di un jack da 3,5 mm per cuffie, che consente la registrazione tramite microfono e la riproduzione tramite altoparlanti.

9.1 Test rapido

#Registrazione
# Registra 10 secondi di audio
arecord -D hw:1,0 -f cd -t wav test.wav -d 10

#Riproduzione:
#Inserisci il comando per aprire la console di debug audio
alsamixer

#Premi F6 per selezionare default:1 rockchip-es8388
#Premi Invio per confermare
#Assicurarsi che  sia impostato su [00], premere il tasto M per cambiare lo stato
#Utilizzare il seguente comando per riprodurre l'audio nella cartella corrente
aplay -D hw:1,0 test.wav

10. Display

10.1 Uscita HDMI

L'EC700 supporta un'uscita video fino a 4K a 60 fps.

Uscita video: Collegare un monitor alla porta HDMI. Il dispositivo regola automaticamente la risoluzione all'avvio. Se si verificano problemi di visualizzazione, provare a impostare la risoluzione del monitor su 1080P.

Uscita audio: Collegare un monitor dotato di uscita audio alla porta HDMI e utilizzare il lettore multimediale del desktop per effettuare il test:

/userdata/piano2-CoolEdit.mp3

10.2 Ingresso HDMI

Supporta l'ingresso video 1080P60.

Ingresso video:

# Collegare il PC al dispositivo tramite HDMI e utilizzare il seguente comando per verificare che la connessione sia stata stabilita correttamente
v4l2-ctl -d /dev/video0 -D
# Avviare l'acquisizione delle immagini
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
# Per impostazione predefinita vengono acquisiti 50 fotogrammi. Al termine dell’acquisizione, il file viene salvato come 1080P60.bgr nel percorso ~/Desktop/1080P60.bgr
# È possibile utilizzare un visualizzatore di immagini che supporti il formato BGR per aprirlo e verificare se il colore e la risoluzione dell'output sono normali.
# Si consiglia di utilizzare il programma 7YUV per la visualizzazione.

Ingresso audio:

# Assicurarsi che il cavo HDMI RX sia collegato tra il PC e il dispositivo, verificare che l'audio sia in riproduzione sul PC e impostare la scheda audio di uscita su RK xxx in Windows 10.
# Eseguire il seguente comando sulla scheda per acquisire l’audio in ingresso HDMI RX (la scheda audio predefinita per l’ingresso HDMI RX è hw:0,0):
arecord -D hw:0,0 -f dat hdmi_rx.wav
# Interrompere l’acquisizione dopo un certo periodo di tempo premendo Ctrl+C. Il file verrà salvato nella directory corrente.
# Copiare il file audio hdmi_rx.wav sul PC con Windows 10 per la riproduzione. L’audio dovrebbe corrispondere.

API REST del sistema

L'EC700 mette a disposizione un'API REST per interrogare a livello di programmazione lo stato del dispositivo e della rete. Entrambi gli endpoint accettano OTTIENI richieste senza parametri.

1. Ottenere le informazioni di base sul dispositivo

    • URL: GET http://{device_IP}/rpc-api/data/devinfo
    • Metodo: OTTIENI
    • Parametri della richiesta: Nessuno

Campi di risposta:

Campo Descrizione Tipo Osservazioni
codice Codice di stato della risposta int Sempre 200 in caso di successo
data.model Modello del dispositivo stringa Modello del dispositivo
data.sn Numero di serie del dispositivo stringa Numero di serie del dispositivo
versione dei dati Versione del dispositivo stringa Numero di versione del software

Esempio di risposta:

{
  "codice": 200,
  "dati": {
    "modello": "EC700",
    "sn": "xxxxxxxxxxxx",
    "versione": "x.x.x"
  }
}

 

2. Ottenere le informazioni sulla rete WWAN (cellulare) del dispositivo

  • URL: GET http://{device_IP}/rpc-api/data/wwaninfo
  • Metodo: OTTIENI
  • Parametri della richiesta: Nessuno

Campi di risposta:

Campo Descrizione Tipo Osservazioni
codice Codice di stato della risposta int Sempre 200 in caso di successo
data.enable Con connessione cellulare booleano true = abilitato, false = disabilitato
data.status Stato della connessione dial-up numero 0 = acceso, 1 = in fase di inizializzazione, 2 = rilevamento SIM, 3 = PDP attivato, 4 = composizione del numero, 5 = pronto
data.ip Indirizzo IP WWAN stringa Indirizzo IP assegnato dalla rete cellulare
data.mask Maschera di sottorete stringa Maschera di sottorete
data.gateway Indirizzo del gateway stringa Gateway predefinito
data.metric Metrica del percorso numero Valore più basso = priorità più alta
data.dns Server DNS stringa Indirizzo del resolver DNS
versione dei dati Versione del firmware del modulo stringa Versione del firmware del modulo 5G/4G
data.imei IMEI stringa Numero IMEI del modulo
dati.segnale Potenza del segnale numero 0–100, più alto = segnale più forte
data.ccid ID della scheda SIM stringa ICCID della SIM
data.operator Vettore stringa Nome del vettore attualmente registrato
data.sim.maxcall Numero massimo di tentativi di ricomposizione numero Limite di tentativi in caso di errore di composizione del numero
data.sim.sim0.auth Metodo di autenticazione APN numero 0 = Nessuno, 1 = PAP, 2 = CHAP, 3 = PAP/CHAP
data.sim.sim0.addr Indirizzo APN stringa Nome del punto di accesso
data.sim.sim0.nome Nome utente APN stringa Nome utente per l'autenticazione APN
data.sim.sim0.passwd Password APN stringa Password di autenticazione APN
data.sim.sim0.pinCode Codice PIN stringa Codice PIN della scheda SIM
data.ping.enable Sonda di rete booleano true = abilitato, false = disabilitato
data.ping.addr0 Host della sonda 0 stringa Indirizzo di destinazione della sonda di rete 1
data.ping.addr1 Host della sonda 1 stringa Indirizzo di destinazione della sonda di rete 2
data.ping.cyc Intervallo di sondaggio numero Intervallo in secondi
data.ping.num Numero di sonde numero Numero di soglie di errore
data.ping.stato Stato della sonda numero 255 = non verificato, 0 = fallito, 1 = riuscito

Esempio di risposta:

{
  "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
    }
  }
}

 

Software preinstallato

L'EC700 viene fornito con diversi pacchetti software industriali preinstallati e configurati per l'avvio automatico. Ecco come gestirli.

1. Programma di gestione interna (iotrouter)

Per semplificare l'esperienza utente, la serie EC700 viene fornita con la funzione integrata iotrouter programma di gestione che si avvia all'avvio del sistema. Il programma di gestione comprende:

  • Inizializzazione del dispositivo
  • Gestione della rete
  • Gestione cellulare
  • Gestione del WiFi
  • Firewall
  • Servizio di configurazione dei dispositivi (porta predefinita 80, configurabile; file: /usr/local/src/iotrouter/web/user-config.js)
  • Esploratore di file (percorso predefinito: /run/media/; configurabile; file: /usr/local/src/iotrouter/web/user-config.js)

Nota: si consiglia di lasciare in esecuzione il programma interno. Se è necessario disattivarlo, dovrai occuparti personalmente dei servizi di gestione sopra indicati.

2. NeuronEX

L'EC700 viene fornito con NeuronEX-Lite preinstallato. Il servizio si avvia automaticamente all'avvio del sistema e ascolta sulla porta 8085.

Per un'introduzione, si veda: [Percorso di apprendimento dei computer industriali ARM della serie EC]

Visualizza lo stato del servizio: systemctl status neuronex

Riavvia il servizio: systemctl restart neuronex

Sospensione del servizio: systemctl stop neuronex

Disattiva l'avvio automatico: systemctl disable neuronex

3. Node-RED

L'EC700 viene fornito con Node-RED preinstallato. Il servizio si avvia automaticamente all'avvio del sistema e rimane in ascolto sulla porta 1880. Per un'introduzione, si veda: [Percorso di apprendimento dei computer industriali ARM della serie EC]

Visualizza lo stato del servizio: systemctl status node-red

Riavvia il servizio: systemctl restart node-red

Sospensione del servizio: systemctl stop node-red

Disattiva l'avvio automatico: systemctl disable node-red

 

4. FUXA

Tutti i prodotti della serie EC700 sono dotati di FUXA preinstallato. Il servizio si avvia automaticamente all'avvio del sistema e ascolta sulla porta 1881. Per un'introduzione, si veda: [Guida allo sviluppo avanzato per i computer industriali ARM della serie EC]

Visualizza lo stato del servizio: systemctl status fuxa

Riavvia il servizio: systemctl restart fuxa

Sospensione del servizio: systemctl stop fuxa

Disattiva l'avvio automatico: systemctl disable fuxa

5. Desktop Xfce4

L'ambiente desktop predefinito è Xfce4. Viene fornito solo a scopo dimostrativo. Se hai bisogno di visualizzare altri contenuti, come un'interfaccia utente basata su Qt, puoi svilupparla autonomamente.

Il gestore di visualizzazione è: lightdm

Visualizza lo stato del servizio: systemctl status lightdm

Riavvia il servizio: systemctl restart lightdm

Sospensione del servizio: systemctl stop lightdm

Disattiva l'avvio automatico: systemctl disable lightdm

 

6. Programmi utente personalizzati

Le applicazioni utente vengono sviluppate autonomamente dagli utenti e vengono eseguite come processi separati. Tuttavia, è necessario prestare particolare attenzione alla gestione della memoria e dello spazio di archiviazione per evitare eccezioni di sistema. È possibile configurare il software in modo che venga avviato automaticamente dal sistema utilizzando i seguenti metodi:

  • /etc/rc.local
  • servizio systemd
  • /etc/init.d sistema

Offriamo inoltre servizi di sviluppo software su misura. Per richieste di informazioni, ti preghiamo di contattare il nostro team commerciale.

7. Personalizzazione del logo di avvio

Gli utenti possono sostituire autonomamente il logo di avvio del sistema.

File del logo Palcoscenico
logo.bmp Visualizzato durante la fase U-Boot
logo_kernel.bmp Visualizzato durante la fase di avvio del kernel

7.1 Requisiti di formattazione

L'immagine del logo deve essere un Immagine bitmap BMP a 24 bit. La risoluzione dell'immagine non deve superare quella dello schermo HDMI collegato.

7.2 Sostituzione del logo

  1. Accendere il dispositivo.
  2. Copia la tua personalizzazione logo.bmp e logo_kernel.bmp file nel SDK_PATH/kernel-6.1 directory, sostituendo i file esistenti con lo stesso nome.

Guida allo sviluppo dell'EC700: Introduzione al PC industriale per l'AI Edge Computing

Nota: i nomi dei file contenenti i loghi non devono essere modificati.

Conclusione

L'EC700 è progettato per consentirti di passare rapidamente dall'idea iniziale al prototipo funzionante. Grazie all’ambiente Linux aperto, allo stack software industriale preinstallato (Node-RED, NeuronEX, FUXA) e alle interfacce hardware intuitive, la maggior parte del lavoro di base è già stata svolta: basta scrivere la logica dell’applicazione e collegare sensori e attuatori.

Ecco alcuni aspetti da tenere a mente quando inizi a sviluppare:

  • Inizia dalla porta seriale di debug. Anche se prevedi di lavorare tramite SSH, la porta di debug Type-C è la soluzione di riserva da utilizzare quando la rete non funziona correttamente.
  • Sfrutta l'API REST. Il /rpc-api/data/ Gli endpoint rendono semplicissimo importare le informazioni sui dispositivi e lo stato della rete cellulare nelle proprie dashboard o nei propri script di monitoraggio — senza bisogno di analizzare manualmente i comandi AT.
  • Rispettare il servizio iotrouter. Si occupa della gestione della rete, del Wi-Fi e della connessione cellulare in background. Se lo disattivi, dovrai provvedere tu stesso a reimplementare tali funzioni.
  • Tieni d'occhio il budget destinato allo spazio di archiviazione. Con 128 GB di memoria integrata e la possibilità di espansione NVMe, hai spazio a sufficienza — ma le immagini Docker e i pesi dei modelli di IA si accumulano rapidamente.

Se stai cercando le specifiche hardware complete, la tabella di compatibilità dei protocolli o le opzioni di personalizzazione OEM/ODM, consulta la Pagina del prodotto EC700. Per qualsiasi domanda relativa all'accesso all'SDK, allo sviluppo personalizzato o agli ordini all'ingrosso, il team di IOTRouter è a vostra disposizione: basta contattarci tramite il modulo di contatto presente sul sito.

 

Chi sono
db6893fd1d3e314ac461fa240068dc06?s=150&d=mp&r=g
Specialista in soluzioni IoT ~ Web ~  Altri articoli

Agnes Wang è una specialista in soluzioni IoT presso IOTRouter, dove si occupa principalmente di gateway IoT industriali, edge computing e soluzioni di automazione industriale.

È specializzata in tecnologie di comunicazione industriale, tra cui Modbus, IEC 60870-5-104, MQTT, OPC UA, integrazione di PLC e applicazioni di monitoraggio remoto. Collabora alla stesura di articoli tecnici e guide applicative riguardanti soluzioni IoT industriali, conversione di protocolli ed edge computing.

↑