[risolto]Problemi nel monitor seriale

Salve a tutti. Sto cercando di leggere dei dati da un'applicazione. Il problema è che quando digito il seguente comando

echo 188#02000000 > /dev/ttyACM0

nel monitor seriale riesco a vedere ciò che invio. Il problema è che quando digito

candump vcan0 > /dev/ttyACM0

nel serial monitor non visualizzo nulla ma il led Rx di arduino rimane acceso. Il candump legge i dati da un'applicazione. L'output è :

(1571913127.393927) vcan0 166#D0320018
 158#0000000000000019
161#000005500108001C
 191#010010A141000B
164#0000C01AA8000004
 133#00000000A7
 136#000200000000002A
 13A#0000000000000028
 17C#0000000010000021
 18E#00006B
 1CF#80050000003C
 1DC#02000039
 183#0000000A0000102F e cosi via...

Si tratta di una lettura continua. Mica arduino è lento nel leggere e scrivere quasi contemporaneamente ?

Conversione hex to dec : [risolto]Conversione hex a dec - Software - Arduino Forum

Non sono sicuro che il mio intervento possa aiutare nello specifico, posto principalmente perché non ho chiaro il codice che stati usando su arduino.

Con il codice che ho visto in precedenza su arduino quelle stringhe non vanno bene, a meno che tu abbia scritto una routine di decodifica da ASCII > byte.

Per dire, ho provato a spedire da PC > Arduino la tua stringa che viene letta così:

ASCII                                  byte
188#02000000            31 38 38 23 30 32 30 30 30 30 30 30

Infatti se osservi qui la tabella ASCII vedi che:
1 31
8 38
8 38

23

0 30
ecc.

Ok ho ripescato il link alla lib che usi.
Si vede come è composta la struct can_frame

struct can_frame {
    uint32_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
    uint8_t  can_dlc;
    uint8_t  data[8];
};

32 bit vanno in can_id
8 bit vanno in can_dlc
e data è il buffer di 8 byte.

Con la tua stringa can_frame verrebbe riempita così:
can_id = 31 38 38 23
can_dlc = 30 !! 30 byte di data len??
data[0] = 32
data[1] = 30
data[2] = 30
data[3] = 30
data[4] = 30
data[5] = 30
data[6] = 30
data[7] = ????

Ciao.

Ciao, ma non ho capito la tua risposta. Ti faccio un esempio con la singola stringa:

leggo dal pc 188#02000000 e l'invio ad arduino che effettuerà la conversione e spedisce il tutto. Il messaggio attraverserà due shield per poi arrivare ad un altro arduino che effettuerà la riconversione in hex . Sia l'invio che la ricezione sono due comandi fatti con la shell di bash. Con la singola stringa tutto funziona ma con il candump no. L'arrivo del messaggio è semplicemente visualizzato con un Serial.println(canMsg.data[i],HEX)

perchè se effettuo la lettura di una singola stringa funziona mentre se invio tante stringhe non funziona ? Arduino è letto nel processare tutte queste informazioni ?

perchè se effettuo la lettura di una singola stringa funziona mentre se invio tante stringhe non funziona ? Arduino è letto nel processare tutte queste informazioni ?

Prova a chiudere il serial monitor e poi usa candump, però credo che lo fai già diversamente non funzionerebbe neanche echo 188#02000000 > /dev/ttyACM0.

Arduino è letto nel processare tutte queste informazioni ?

Quando converti stringhe in numeri certamente un po di tempo se lo prende, però penso che se si trattasse di velocità al meno un paio di messaggio li vedresti. Dovresti vedere anche lampeggiare il led RX sulla board ricevente.

Io farei delle prove banali scrivendo codice sui due arduino, esempio:
Supponiamo che il controller (A0) principale vuole sapere se tutti i nodi di cui ha una lista sono presenti e svegli. Diciamo che hai in lista due nodi quindi uno non ti risponde lo devi disabilitare e appuntarti l'errore. Con l'unico nodo (A1) puoi dialogare, con dei pulsanti su A0 premendone uno invia il messaggio a A1 che ad esempio è la centralina fari, A1 dovrà quindi accendere un led ecc.

Visto che i problemi con can potrebbero continuare ti consiglio di mantenere un tuo thread principale in cui aggiorni ad esempio la prima pagina, inserendo il nuovo codice che stati usando, i link alla libreria ecc.
PS: se il thread lo apri tu lo puoi mantenere modificando i contenuti.

Ciao.

Maurotec:
Prova a chiudere il serial monitor e poi usa candump, però credo che lo fai già diversamente non funzionerebbe neanche echo 188#02000000 > /dev/ttyACM0.

ho già fatto questa prova e non funziona niente. Forse con il candump devo stare attento ai caratteri di fine linea. Proverò con un file.

Maurotec:
Visto che i problemi con can potrebbero continuare ti consiglio di mantenere un tuo thread principale in cui aggiorni ad esempio la prima pagina, inserendo il nuovo codice che stati usando, i link alla libreria ecc.
PS: se il thread lo apri tu lo puoi mantenere modificando i contenuti.

Nel senso che posso usare sempre questo invece di aprirne altri ?

Maurotec:
Prova a chiudere il serial monitor e poi usa candump, però credo che lo fai già diversamente non funzionerebbe neanche echo 188#02000000 > /dev/ttyACM0.
Quando converti stringhe in numeri certamente un po di tempo se lo prende, però penso che se si trattasse di velocità al meno un paio di messaggio li vedresti. Dovresti vedere anche lampeggiare il led RX sulla board ricevente.

Ma il led Rx ha sempre lampeggiato quindi arduino qualcosa riceve

Ho provato ad inviare consecutivamente

echo 188#0200000A > /dev/ttyACM0
                                                                    echo 188#020000B0 > /dev/ttyACM0

come risultato ottengo che il primo echo viene processato e visualizzato nel monitor seriale. Per il secondo echo visualizzo cose strane. Questo è il risultato:

020000010218188243

Ma tu nel monitor seriale esattamente COSA mostri? Ci fai vedere almeno la parte di codice dove scrivi i valori sulla Serial? Puoi mettere un qualche separatore tra un byte e l'altro??

Nel senso che posso usare sempre questo invece di aprirne altri ?

Si, decidi tu cosa fare. L'argomento di base è comunque il can bus. Puoi anche decidere di aprire un altro thread come hai fatto per la conversione da Hex to Int la quale può tornare utile ad altri, ma chi segue questo thread trova comunque comodo avere un link al thread Hex to Int che puoi aggiungere nel primo tuo post di questo thread.

Qualcosa del tipo:

Libreria can bus: link

Moduli can bus: link

ecc...

ho già fatto questa prova e non funziona niente. Forse con il candump devo stare attento ai caratteri di fine linea. Proverò con un file.

Per forza di cose arduino che riceve le stringhe attraverso,
candump vcan0 > /dev/ttyACM0
deve potere distinguere un messaggio dall'altro. Ho dato uno sguardo veloce al sorgente di candump e credo che ogni messaggio termina con '\n' NewLine (o LineFeed come riportato nella tabella ASCII).

Proviamo arduino da seriale riceve l'output di candump. Come riferimento prendo le prime 3 stringhe:

(0) 166#D0320018
(1) 158#0000000000000019
(2) 161#000005500108001C

Il messaggio "0" ha can_id 0x166, il can_data è 0xD0320018, mentre can_dlc deve essere dedotto contando i caratteri del can_data che sono 8 digit quindi 8/2 = 4 byte.

Decodificata questa stringa si deve riempire il frame

struct can_frame {
    uint32_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
    uint8_t  can_dlc;
    uint8_t  data[8];
};

struct can_frame frame;

frame.can_id = 0x166;
frame.can_dlc = 0x04;
frame.data[0] = 0xD0;
frame.data[1] = 0x32;
frame.data[2] = 0x00;
frame.data[3] = 0x18;

Se il can_id del messaggio è composta da 8 digit si tratta di Extended Frame e si dovrà riempire il can_id come riportato qui.

frame.can_id = 0x12345678 | CAN_EFF_FLAG;

Ho scritto codice di test C per essere eseguito sul PC dove dispongo della funzione strtoll che non c'è su arduino e
non ho ancora risolto. Se campo data è composto da 16 digit can_dlc sarà 16/2 = 8 byte, si spezzano in due
per avere 4 byte da dare in pasto a strtol (due volte), quindi 64 bit si dividono in MSBdata di 32bit e LSBdata di 32bit,
con cui riempire frame.data. Tornerebbe utile una union su frame.data in modo che possa accettare direttamente MSB e LSB.

Riepita frame. si può spedire il messaggio, che viene spedito tramite MCP sul BUS fisico all'altro MCP ricevente.
Il MCP ricevente solleva il PIN INT per comunicare alla MCU328 che sono arrivati dati e questo li legge interrogando MCP tramite SPI, letto il messaggio lo stampa via seriale Serial.

Ciao.

docdoc:
Ma tu nel monitor seriale esattamente COSA mostri? Ci fai vedere almeno la parte di codice dove scrivi i valori sulla Serial? Puoi mettere un qualche separatore tra un byte e l'altro??

Nel monitor seriale dovrei vedere quello che invio dalla shell di linux. Il codice è questo:

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg1;
struct can_frame canMsg2;
String incString = "";

MCP2515 mcp2515(10);


void setup() {
  
  while (!Serial);
  Serial.begin(115200);
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  
  Serial.println("Example: Write to CAN");
}

void loop() {
  if (Serial.available() > 0) {
   incString = Serial.readString();
   int lung_stringa = incString.length();       
   incString = incString.substring(0,lung_stringa-1);     
   lung_stringa = incString.length();                    
..........
..........
    
     //canMsg1.data[i] = payload_dec;
        canMsg1.data[i] = val ;
        Serial.print(canMsg1.data[i]);
   }
 
   mcp2515.sendMessage(&canMsg1);
  }
}

Stampo la conversione da hex a dec

Nel monitor seriale dovrei vedere quello che invio dalla shell di linux. Il codice è questo:

Si ma in quale monitor seriale, quello che riceve dal CAN bus o quello che riceve i messaggi inviati da candump?
Penso che mentre impegni la ttyACM0 da sheel il monitor seriale sulla stessa ttyACM0 non può ricevere nulla.

$ echo 188#02000000 > /dev/ttyUSB0
bash: /dev/ttyUSB0: Device or resource busy
[maurilio@localhost ~]$

Questo perché ho script comunicator che impegna la ttyUSB0.

Ciao.

centurione_agrippa:
Stampo la conversione da hex a dec

Si ma qualche consiglio: intanto nella stringa che mostri ti conviene separare i singoli valori, ad esempio con uno spazio, altrimenti non sai se "134" è un byte (134 decimale), due (13 e 4, oppure 1 e 34), o tre (1 3 e 4)...
Secondo, perché usare esadecimale da una parte e decimale dall'altra? Ti conviene sempre "parlare" la stessa lingua, ad esempio mostra sempre i valori in esadecimale così è tutto più facile!
Ossia una cosa del tipo:

        canMsg1.data[i] = val ;
        Serial.print(canMsg1.data[i], HEX);
        Serial.print(" ");

Ovviamente se hai già una variabile stringa con quel singolo byte in esadecimale ti conviene stampare quella (aggiungendo sempre anche il separatore, per maggiore chiarezza) così hai sempre 2 caratteri in output e risulterà tutto più "pulito" e leggibile. E se quella Serial.print() è dentro ad un ciclo for() dei byte del pacchetto, al termine del ciclo metti un Serial.Println() così hai un pacchetto per riga.

Per il resto, concordo con Maurotec.

Maurotec:
Si, decidi tu cosa fare. L'argomento di base è comunque il can bus. Puoi anche decidere di aprire un altro thread come hai fatto per la conversione da Hex to Int la quale può tornare utile ad altri, ma chi segue questo thread trova comunque comodo avere un link al thread Hex to Int che puoi aggiungere nel primo tuo post di questo thread.

Qualcosa del tipo:

Libreria can bus: link

Moduli can bus: link

ecc...

Per forza di cose arduino che riceve le stringhe attraverso,

candump vcan0 > /dev/ttyACM0

deve potere distinguere un messaggio dall'altro. Ho dato uno sguardo veloce al sorgente di candump e credo che ogni messaggio termina con '\n' NewLine (o LineFeed come riportato nella tabella ASCII).

Allora il mio problema sta all'inizio, nel momento in cui lancio il candump. Sempre da shell dovrei fare in modo che passi all'arduino sempre una nuova riga.

Maurotec:
Si ma in quale monitor seriale, quello che riceve dal CAN bus o quello che riceve i messaggi inviati da candump?
Penso che mentre impegni la ttyACM0 da sheel il monitor seriale sulla stessa ttyACM0 non può ricevere nulla.

$ echo 188#02000000 > /dev/ttyUSB0

bash: /dev/ttyUSB0: Device or resource busy
[maurilio@localhost ~]$


Da Pc (shell)--------------------------------------------------------->Arduino (monitor seriale)

echo echo 188#02000000 > /dev/ttyUSB0 id 392 payload 02000000 

Nel mio caso funziona non mi dice che il device è occupato. Io vorrei fare la stessa cosa con candump

docdoc:
Si ma qualche consiglio: intanto nella stringa che mostri ti conviene separare i singoli valori, ad esempio con uno spazio, altrimenti non sai se "134" è un byte (134 decimale), due (13 e 4, oppure 1 e 34), o tre (1 3 e 4)

La stringa originale è con gli spazi poi devo compattarla altrimenti non viene eseguita da chi deve leggerla

Secondo, perché usare esadecimale da una parte e decimale dall'altra? Ti conviene sempre "parlare" la stessa lingua, ad esempio mostra sempre i valori in esadecimale così è tutto più facile!
Ossia una cosa del tipo:

        canMsg1.data[i] = val ;

Serial.print(canMsg1.data[i], HEX);
        Serial.print(" ");



Ovviamente se hai già una variabile stringa con quel singolo byte in esadecimale ti conviene stampare quella (aggiungendo sempre anche il separatore, per maggiore chiarezza) così hai sempre 2 caratteri in output e risulterà tutto più "pulito" e leggibile. E se quella Serial.print() è dentro ad un ciclo for() dei byte del pacchetto, al termine del ciclo metti un Serial.Println() così hai un pacchetto per riga.

Devo prova il secondo suggerimento

Serial.print() non gestisce dati a 64 bit. strtoull su arduino non esiste e quindi l'ho copiata da qui. La ho adattata come di seguito:

#include <ctype.h>
#include <errno.h>
#ifndef ULLONG_MAX
#define ULLONG_MAX (~(uint64_t)0) /* 0xFFFFFFFFFFFFFFFF */
#endif
/*
 * Convert a string to an unsigned long long integer.
 *
 * Ignores `locale' stuff.  Assumes that the upper and lower case
 * alphabets and digits are each contiguous.
 */
uint64_t
strtoull(const char *nptr, char **endptr, register int base)
{
        register const char *s = nptr;
        register uint64_t acc;
        register int c;
        register uint64_t cutoff;
        register int neg = 0, any, cutlim;
        /*
         * See strtol for comments as to the logic used.
         */
        do {
                c = *s++;
        } while (isspace(c));
        if (c == '-') {
                neg = 1;
                c = *s++;
        } else if (c == '+')
                c = *s++;
        if ((base == 0 || base == 16) &&
            c == '0' && (*s == 'x' || *s == 'X')) {
                c = s[1];
                s += 2;
                base = 16;
        }
        if (base == 0)
                base = c == '0' ? 8 : 10;
        cutoff = (uint64_t)ULLONG_MAX / (uint64_t)base;
        cutlim = (uint64_t)ULLONG_MAX % (uint64_t)base;
        for (acc = 0, any = 0;; c = *s++) {
                if (isdigit(c))
                        c -= '0';
                else if (isalpha(c))
                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
                else
                        break;
                if (c >= base)
                        break;
                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
                        any = -1;
                else {
                        any = 1;
                        acc *= base;
                        acc += c;
                }
        }
        if (any < 0) {
                acc = ULLONG_MAX;
                errno = ERANGE;
        } else if (neg)
                acc = -acc;
        if (endptr != 0)
                *endptr = (char *) (any ? s - 1 : nptr);
        return (acc);
}

Per testarla ho spedito i seguenti 3 messaggi:

166#D0320018
158#0000000000000019
161#000005500108001C

Copiati da questo post evidenziando e copiando.
Non si vede sopra ma ogni messaggio termina con '\n'.
I caratteri '\n' sono già presenti nella copia, non li ho dovuti aggiungere

Arduino riceve e mi stampa questo output:

New Message
msgLen = 12
can_dlc = 4
dataLen = 8
can_id = 166
frame.data[0] = 18
frame.data[1] = 0
frame.data[2] = 32
frame.data[3] = D0
New Message
msgLen = 20
can_dlc = 8
dataLen = 16
can_id = 158
frame.data[0] = 19
frame.data[1] = 0
frame.data[2] = 0
frame.data[3] = 0
frame.data[4] = 0
frame.data[5] = 0
frame.data[6] = 0
frame.data[7] = 0
New Message
msgLen = 20
can_dlc = 8
dataLen = 16
can_id = 161
frame.data[0] = 1C
frame.data[1] = 0
frame.data[2] = 8
frame.data[3] = 1
frame.data[4] = 50
frame.data[5] = 5
frame.data[6] = 0
frame.data[7] = 0

Ciao.

Maurotec:
Serial.print() non gestisce dati a 64 bit. strtoull su arduino non esiste e quindi l'ho copiata da qui.

Grazie mille per il supporto. Devo adattare il tuo codice al mio ? Scusa se ritorno sempre sullo stesso discorso perché con il singolo comando funziona e con il cundump non dovrebbe funzionare ?

centurione_agrippa:
La stringa originale è con gli spazi poi devo compattarla altrimenti non viene eseguita da chi deve leggerla

Ma io non parlo mica di cambiare il comando originale, ma solo la visualizzazione sulla seriale. Ed anche "chi deve leggerla" comunque se è un programma può funzionare correttamente solo se i dati sono di lunghezza fissa e nota (o se ha un separatore)...

Grazie mille per il supporto. Devo adattare il tuo codice al mio ? Scusa se ritorno sempre sullo stesso discorso perché con il singolo comando funziona e con il cundump non dovrebbe funzionare ?

mmm...troppe domande a cui non so dare una risposta.

Ieri ho anche io installato le canutils sto usando un altro metodo per fare quello che credo vorresti fare.
Intanto non sono esperto con le canutils. Sto usando slcand su ttyUSB0, poi per generare con cangen non uso vcan0 ma slcan0. Nell'altra shell c'è candump slcan0 in attesa dei dati.

Qui i comandi:

sudo slcand -o -s8 -S 57600 /dev/ttyUSB0

Questo crea il device slcan0, poi:

sudo ip link set up slcan0

poi:

cangen slcan0

Arduino riceve dei dati, ma non conosco il protocollo e allora ho scritto il programma arduino in modo di salvare i dati ricevuto in un buffer di 64 byte. Ricevuti i dati uccido il processo cangen con kill, adesso posso aprire il serial monitor su ttyUSB0. Adesso pigio il pulsante sul pin 2 e arduino mi spedisce i dati presenti nel buffer e li posto:

t4A43CC4BBEt6CB8576D022FB9530672t309841743F58D2B76221t66741A0

Strano 61 byte dovevano essere 64, poi controllo il perché. Controllato rapidamente ci sono '\n'. dove lo vedo dopo mangiato.
Quello a seguire è l'output di candump slcan0

slcan0  4A4   [3]  CC 4B BE
slcan0  6CB   [8]  57 6D 02 2F B9 53 06 72
slcan0  309   [8]  41 74 3F 58 D2 B7 62 21
slcan0  667   [4]  1A 0F B9 50

Io noto solo che ogni messaggio inizia con 't' a cui segue il can_id, quindi il can_dlc e infine il can_data.
Su arduino servirebbe un protocollo che decodifichi il messaggio e riempia la struct frame per poi spedirla via SPI al MCP.

Ora su arduino come faccio a ricavare can_id, can_dlc e can_data? Per lo standard frame so per certo che can_id è sempre di tre digit ma per exented frame è 8 digit.

Non credo che ci sia bisogno di specificarlo che cangen sta spedendo caratteri, infatti compare la t e non byte.

PS:devo provare cosa riceve arduino se nel mezzo di standard frame ci sono exented frame.
PS1: non shield can bus ma solo un arduino 2009, che il pc vede come /dev/ttyUSB0.

Ciao.