Inviare dei Byte ad Patchube(Cosm) tramite sim908

Salve a tutti,

come brevemente descritto nel titolo il mio problema consiste nell'inviare dei byte per chiedere la connessione ad un server tramite il protocollo MQTT, in pratica dopo aver stabilito la connessione TCP con il server di cosm, attraverso il metodo connectTCP della libreria InetGSM, dovrei inviare una richiesta di connect per questo protocollo, in pratica dovrei inviare questo:

byte[] connectMessage = {0x10 //Connect
, 0x0C + 0x04 //Remaining Length
, 0x00 //0
, 0x06 //6
, 0x4d //M
, 0x51 //Q
, 0x49 //I
, 0x73 //S
, 0x64 //D
, 0x70 //P
, 0x03 //Protocol version = 3
, 0x02 //Clean session only
, 0x00 //Keepalive MSB
, 0x3c //Keepaliave LSB = 60
, 0x00 //String length MSB
, 0x02 //String length LSB = 2
, 0x4d //M
, 0x70 //P .. Let's say client ID = MP
};

byte[] publishMessage = { 0x30 //Publish with QOS 0
, 0x05 + 0x05 //Remaining length
, 0x00 //MSB
, 0x03 //3 bytes of topic
, 0x61 //a
, 0x2F ///
, 0x62 //b (a/b) is the topic
, 0x48, 0x45 , 0x4c , 0x4c, 0x4f //HELLO is the message
};

sono dei codici esadecimali che indicano al server che voglio instaurare una connessione con protocollo MQTT, esso mi dovrà rispondere con un'accettazione, che dovrò leggere, e poi effettuare il publisch, quindi inviare il secondo set di byte.
Utilizzo i byte perchè ho preso i valori direttamente dalla spiegazione di questo nuovo protocollo, ma se qualcuno mi può consigliare qualche altro metodo è sempre ben accetto.
In tutti i casi il problema principale è spedire questi dati al server.
Qualcuno può aiutarmi?

ciao, la libreria InetGSM è una astrazione della SIM900 che permette di creare facilmente richieste GET e POST col protocollo HTTP (che sta al di sopra del TCP)
Tu, che vuoi creare una libreria per il protocollo MQTT, quindi, dovrai usare i metodi forniti dalla libreria SIM900; la connect mi pare sia identica, ma essa ti mette a disposizione anche i metodi simpleWrite, WaitResp e read, che tra l'altro funzionano anche con array di byte come piace a te (di solito il problema non è con gli array di byte, ma con tutti gli altri tipi di dato in particolare numerici a virgola mobile e stringhe).

Ti voglio inanzi tutto ringraziare per la risposta, poi, dato che sono alle prime armi con l'uso dei protocolli volevo delle chiarificazioni, in pratica io dovrei prima instaurare una connessione TCP con il server (cosm), dopo di che mandare la richiesta di connect per specificare il tipo di protocollo che devo usare, quindi il fatto che io utilizzo la connectTCP della inetGsm dici che non va bene? poi come posso leggere se c'è una risposta da parte del server dopo aver fatto la connessione tcp?
Penso ci sia qualche cosa che mi sfugge...

no, tu instauri una comunicazione TCP con la connect, dopo di che parli direttamente con il protocollo.
In pratica ogni porta di un server fornisce un diverso "servizio", ed ogni servizio parla con il suo protocollo. Quindi la scelta di cosa e con che protocollo lo fai scegliendo la porta.

Il numero delle porte è standard (fino alla 1024), ma può essere facilmente cambiato dagli amministratori in base alle esigenze. Per esempio la porta 21 viene usata dai server FTP, ma anche dalle shell. La porta 80, la 8080 e la 8000 sono normalmente usate per fare l'HTTP (web), la 25 invio delle emalil (SMTP) e la 23 per la ricezione della posta (POP3), la 993 sia per l'invio che la ricezione delle mail ma con protocollo IMAP

da mqtt.org:
"Are there standard ports for MQTT to use?
Yes. TCP/IP port 1883 is reserved with IANA for use with MQTT. TCP/IP port 8883 is also registered, for using MQTT over SSL."

Quindi, visto che arduino non regge l'SSL, probabilmente dovrai usare la porta 1883

ora che sei connesso, invii la tua stringa di byte, attendi (se necessario) che si completi l'invio, e attendi (se necessario) la risposta.

nel tuo caso prima invii la connectMessage, attendi una risposta positiva (se no è inutile andare avanti), poi invii publishMessage per completare l'operazione

La tua risposta è e stata perfetta e chiara :), ho fatto tutto quello che mi hai detto, ho instaurato un collegamento TCP con cosm sulla porta 1883, il problema nasce quando cerco di inviare il connectMessage, io faccio:

gsm.SimpleWriteln(connectMessage);

ed ottengo un errore in compilazione e cioè:

call of overloadded SimpleWriteln(byte[18]) is ambiguous.

Prova_Protocollo_MQTT.cpp: In function 'void setup()':
Prova_Protocollo_MQTT:66: error: call of overloaded 'SimpleWriteln(byte [18])' is ambiguous
C:\Users\Gianni\Documents\arduino-1.0.1\libraries\GSMSHIELD/SIM900.h:34: note: candidates are: void SIMCOM900::SimpleWriteln(char*)
C:\Users\Gianni\Documents\arduino-1.0.1\libraries\GSMSHIELD/SIM900.h:36: note: void SIMCOM900::SimpleWriteln(const char*)
C:\Users\Gianni\Documents\arduino-1.0.1\libraries\GSMSHIELD/SIM900.h:38: note: void SIMCOM900::SimpleWriteln(int)

ti posto anche il codice del mio programma.

#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"
//#include "sms.h"
//#include "call.h"

//To change pins for Software Serial, use the two lines in GSM.cpp.

//GSM Shield for Arduino
//www.open-electronics.org
//this code is based on the example of Arduino Labs.

//Simple sketch to start a connection as client.

byte connectMessage[] = {0x10 //Connect
, 0x0C + 0x04 //Remaining Length
, 0x00 //0
, 0x06 //6
, 0x4d //M
, 0x51 //Q
, 0x49 //I
, 0x73 //S
, 0x64 //D
, 0x70 //P
, 0x03 //Protocol version = 3
, 0x02 //Clean session only
, 0x00 //Keepalive MSB
, 0x3c //Keepaliave LSB = 60
, 0x00 //String length MSB
, 0x02 //String length LSB = 2
, 0x4d //M
, 0x70 //P .. Let's say client ID = MP
};

InetGSM inet;

boolean started=false;

void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(2400)){
Serial.println("\nstatus=READY");
started=true;
}
else Serial.println("\nstatus=IDLE");

if(started){
//GPRS attach, put in order APN, username and password.
//If no needed auth let them blank.
if (inet.attachGPRS("internet.wind", "", ""))
Serial.println("status=ATTACHED");
else Serial.println("status=ERROR");
delay(1000);

//Read IP address.
gsm.SimpleWriteln("AT+CIFSR");
delay(5000);
//Read until serial buffer is empty.
gsm.WhileSimpleRead();
if(inet.connectTCP("api.cosm.com",1883)){
Serial.println("Connesso a Cosm");
gsm.SimpleWriteln(connectMessage);
}
else Serial.println("Non Connesso");

}
};

void loop()
{

};

Ti ringrazio nuovamente per il supporto, ne approfitto perchè si vede che sei una persona competente e in grado di spiegare le cose in maniera semplice, che è proprio quello che serve a me che mi sono appena avvicinato al mondo dei protocolli internet ed arduino.

sì, mi sono sbgliato, non vuole un array di byte ma un array di char. Dovrebbe bastare semplicemente cambiare il tipo di dato dell'array, da byte a char, senza alcun altro problema
comuque il compilatore ti suggerisce qualcosa:
SimpleWriteln(char*) array di char dinamico
SimpleWriteln(const char*) array di char
SimpleWriteln(int) un int

noon penso basti fare il casting..vedi,se gli passi una stringa,lui si ferma al primo 0 che vede(significa terminatore di stringa)..ma un array di bytes può contenere diversi zero(e quindi si fermerebba al primo 0) o non contenerne affatto..

hai ragione, vedendo che ai byte c'era affianco una lettera pensavo seguissero la tabella ascii.

Allora la soluzione "stupida" è raggrupare 2 a 2 i byte ed inviarli usando la SimpleWriteln(int) ma funziona solo se il numero di byte è pari (mi pare di sì nel caso dei tuoi messaggi)

per esempio

int i, mess;
for (i=0;i<lunghezzaArray;i+=2){
    mess = ((int)connectMessage[i])<<8+connectMessage[i+1];
    gsm.SimpleWriteln(mess);
}

la soluzione "difficile" è modificare la libreria per "magiarsi" anche gli array di byte (oppure sempre di char ma specificando la lunghezza, bypassando così il tappo delle stringhe)

non ho quella libreria sottomano,ma direi che c'è un metodo simpleWrite che accetta due parametri,il vettore dy bytes,e la sua lunghezza...

non mi pare ci fosse, ma quella libreria a sua volta si poggiava su un'altra libreria(quindi alla fine erano 3 librerie una sopra l'altra), che essendo più "basso livello" dovrebbe avere il metodo, ora controllo

edit: come non detto, anche la libreria più a basso livello lavora con le stringhe, per via del fatto che sono comandi AT. però giaà nella libreria SIM900 si può notare un oggetto _cell, che poi sarebbe la seriale che è collegata con il modulo GSM (SoftwareSerial)...

quindi in SIM900.h aggiungi:

void SimpleWrite(byte *comm, int len);

e in SIM900.cpp

void SIMCOM900::SimpleWrite(byte *comm, int len)
{
        _cell.write(comm, len);
}

dopo di che potrei usare tranquillamente gli array byte così
gsm.SimpleWriteln(connectMessage, 18); //18 è il numero di byte da scrivere

Ciao, allora ho provato a fare il tutto, risolto problema in compilazione, ma invio il messaggio di connect al server ma questo non mi risponde, allora ho fatto delle prove su un server di un mio amico e ho verificato che dopo aver avviato la connessione TCP, regolarmente accettata dal server, qualunque cosa invio al server questi non riceve nulla; Viceversa se il server manda qualcosa a me io la ricevo.
Ho provato anche a mandare una semplice stringa di caratteri tramite il comando SimpleWrietln ma nulla.
Ho fatto una prova con il metodo get della libreria inetGsm e in quel caso il server riceve le stringhe che si trovano nel metodo.
Non mi capacito quale sia la differenza e del perchè questo avvenga.
Potete illuminarmi!!!??? =(

l'unica divverenza che noto è il carattere di "a capo" che viene aggiunto attraverso la println. Quindi dovresti modificare

void SIMCOM900::SimpleWrite(byte *comm, int len)
{
        _cell.write(comm, len);
}

in

void SIMCOM900::SimpleWrite(byte *comm, int len)
{
        _cell.write(comm, len);
        _cell.write('\n', 1); //aggiunge il carattere "a capo"
}

però a questo punto ho paura a cosa possa succedere se in mezzo al comando ci sia un valore che corrisponda all'a-capo.. tutto dipende da come interpreta i dati il chip GSM, bisognerebbe vedere che succede a basso livello (libreria gsm.h) però ora sono a lavoro.

@lesto: sicuro di poter usare _cell.write('\n', 1) ?non so com'è fatta la libreria,ma ho paura che facendo così usi 13 o 10(valore asci dell'acapo) come indirizzo per cercarsi il vettore di array..

uff hai ragione ancora una volta, dovrebbe essere
char acapo = '\n';
_cell.write(&acapo, 1)

con le doppie virgolette, in questo modo lo forzi a a passare l'indirizzo

edit: chissà se si può fare
_cell.write(&'\n', 1)

o meglio
_cell.write("\n", 1)

si,con il & dovrebbe andare..

Allora ho provato ha cambiare il metodo come mi avete consigliato, ma purtroppo non funziona mi dà errore in compilazione, quindi ho pensato di inserire nel codice del programma /n direttamente con il SimpleWrite, ho provato a inviare questo connectMessage a cosm, ma questi dopo aver accettato la connessione TCP non risponde nulla, invece secondo il protocollo MQTT dovrebbe rispondere con dei connectACK sia nel caso in cui accetti la richiesta sia nel caso in cui il connectMessage sia sbagliato, quindi mi sorge il dubbio che al server ancora non arriva nulla.
Come posso verificare se il server riceve i byte che gli mando?

Ragazzi veramente grazie per la pazienza e il supporto che mi state dando :P!!!

uhmm un analizzatore di rete lato server tipo wireshark o snuff

Ho scaricato il programma che mi hai detto hai idea di come posso fare l'analisi della connessione con il gsm di arduino?
Scusa se ti rompo, ma ho visto che sembra abbastanza complicato, quindi magari se tu avevi già esperienza potevi velocizzarmi un pò la cosa.

Cmq ottimo programma, stò analizzando il traffico del mio cpu ed è veramente perfetto per quello che serve a me, il problema è far analizzare il traffico sul gsm...

il traffico del tuo cpu?

non puoi analizzare il traffico sulla rete GSM, ma puoi analizzarlo una volta che sul cavo/wifi una volta che arriva al server