CC3000 wifi shield in a class/library

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: CC3000 wifi shield in a class/library

Post by tdicola »

Interesting idea, thanks for sharing the library you're working on. Hrm, it's a very good question how to write code that works across multiple network/wifi boards. The CC3000 client and server objects do inherit from the Arduino Client and Server base classes, so in theory you could hold a pointer to those classes and assign it either a CC3000 client / server or Arduino ethernet client / server. For example change your class to this (notice the mb_server and mb_client members are now pointers to the base class types):

Code: Select all

class ModbusTCP {
public:
  ModbusTCP(void);
  void begin(void);
  void run(void);
  int setFloat(uint16_t iAddress, float fValue);
  float getFloat(uint16_t iAddress);
  int setU32(uint16_t iAddress, uint32_t iValue);
  uint32_t getU32(uint16_t iAddress);
  int setU16(uint16_t iAddress, uint16_t iValue);
  uint16_t getU16(uint16_t iAddress);
private:
  uint16_t mb_reg[MB_REGISTERS_MAX];
  uint8_t mb_adu[260];
  Server* mb_server;
  Client* mb_client;
  #ifdef SOME_SPECIAL_DEFINE_TO_ENABLE_CC3000
    // Members that are included only with CC3000 support.  This is just to give a place to create
    // and store these variables so they don't have to be created dynamically with new/malloc.
    // Only the setup function should touch these variables, all the other functions should interact
    // with mb_server and mb_client so they can work with either CC3000 or ethernet library 
    // client / server code.
    Adafruit_CC3000 cc3000;
    Adafruit_CC3000_Server cc3000server;
  #elif SOME_SPECIAL_DEFINET_TO_ENABLE_ETHERNET_LIBRARY
    // Members to hold ethernet library objects.  Again, only setup() should touch these.
    EthernetClient ethernetClient;
    EthernetServer ethernetServer;
  #endif
};
You'll also probably need to add the main CC3000 class and a server instance, but hide them behind an #ifdef to conditionally add those variables only if CC3000 support is enabled. This will give a place to store these values without the user having to put them in their sketch's global variables. Also note the comment about only the setup function touching these variables. This will help all your functions be generic--they interact just with the Client/Server pointers and the setup function initializes those pointers with the right instance of a client/server class depending on the selected board.

Then in your begin() function you'd want to probably put a couple ifdef blocks to setup the server and client classes depending on what board the user has specified. For example the CC3000 server setup might look something like:

Code: Select all

void ModbusTCP::begin(void) {
  #ifdef SOME_SPECIAL_DEFINE_TO_ENABLE_CC3000
    // Insert standard CC3000 setup code to connect to network, get IP, etc...
    // i.e. call stuff like:
    // cc3000.begin();
    // cc3000.connectToAP(...);
    // cc3000.checkDHCP();
    // .. etc.

    // Create server and save reference to it.
    // Insert CC3000 server setup code like:
    // cc3000server.begin();

    // Finally update Server pointer to use cc3000 server reference.
    Server = &cc3000server;
  #elif SOME_SPECIAL_DEFINET_TO_ENABLE_ETHERNET_LIBRARY
    // .. ethernet library setup code goes here ..
    // Update Server pointer to use ethernet library server reference at the end:
    Server = &ethernetServer; 
  #endif
}
This simplifies it a lot but you can see the basic idea. Use the mb_server & mb_client classes to store a reference to the appropriate CC3000 or ethernet library class, and have the setup() function conditionally include the right setup code.

You'll also need to change all the functions that use mb_server and mb_client to deal with those objects as pointers (use -> instead of . to call a function for example). However the functions should 'just work' with any underlying implementation this way, since both the ethernet library and CC3000 library have implemented the same client & server interface. In practice I haven't seen a ton of examples of people doing this kind of cross-board support, so you might run into some bugs or quirks with the CC3000 library. Let me know if so an I can help give some advice or try to integrate fixes so the library works better side by side with the ethernet library. Good luck!

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: CC3000 wifi shield in a class/library

Post by tdicola »

Ouch that's annoying that Arduino doesn't support conditional includes. That doesn't look like a bad way to work around it though by just defining the class in the sketch.

User avatar
philou
 
Posts: 27
Joined: Wed Jan 28, 2015 2:24 pm

Re: CC3000 wifi shield in a class/library

Post by philou »

I am not sur I have all understood from this discussion but here is my pb :
I try to adapt my previous code base on Arduino ethernet library for the CC3000 using a Web server (like your example) but with multi pages display : for that,
previously (with the std Ethernet library), I was declaring at beginning a global variable named client_loc as :"EthernetClient client_loc;" then, I was used to declare functions using local variables like this :

Code: Select all

#include <Ethernet.h>


EthernetServer server(85);   // necessaire pour serveur WEB arduino
EthernetClient client;       // necessaire pour connexion pages free
EthernetClient client_loc;   // necessaire pour connexion serveur arduino


void setup() ----------------------------

// Initialisation carte TcpIp ------------


void loop() ------------------------------                    


// Traitement affichage vers site WEB //
//************************************//


// Create a client connection
//  EthernetClient client = server.available();
  client_loc = server.available();
  if (client_loc) {
    while (client_loc.connected()) {
      if (client_loc.available())    {
// recupere les carac requete HTML maxi taille buffer 50 min à ajuster
        char c = client_loc.read();
        buffer_lect[k]=c;   // Sauvegarde du caractere C dans le buffer
        buffer_lect[k+1]=0;  // on efface le caractère d'après (fin de chaine)
        k++;   
//if HTTP request has ended
      if (c == '\n') {
// trait requete HTTP

(then some treatment which define choix=0,1 or2 to display correct page)

  // affichage page WEB choisie **************************
      switch (choix) {
        case 1:
          Config();
          break;
        //case 2:
          //Digital();
          //break;
        case 0:
        default :
          showAcceuil(info);
      }
  client_loc.println(F("</body></html>"));      
  
  client_loc.stop();
            }   // if HTTP request end        
        }  // if client available        
      } // while client
       memset (buffer_lect,0,sizeof(buffer_lect));  //clearing string for next read
       k=0;
    }  // if (client)

// ******* fin affichage WEB *******************************

fin main loop ------------------------------------------------

// here is the functions now ................................

void sendHeader(EthernetClient client, char *title)
{   // send a standard http response header }

void sendHeaderFix(EthernetClient client, char *title)
{ }

void showAcceuil(char* info_loc)
{
 sendHeader(client_loc,Nommage_client);
 // corps page HTML
}

void Config()
{
  sendHeaderFix(client_loc,"Configuration");
}
------------------------------------------------------------------> and with CC3000 based on your example code : I have declared:

Code: Select all

#include <Adafruit_CC3000.h>
#include <SPI.h>
#include "utility/debug.h"
#include "utility/socket.h"


Adafruit_CC3000_Server httpServer(LISTEN_PORT);


void setup() ----------------------------

// Initialisation carte TcpIp ------------

// Start listening for connections
  httpServer.begin();

void loop() ------------------------------                    


// Traitement affichage vers site WEB //
//************************************//


// Try to get a client which is connected.
  Adafruit_CC3000_ClientRef client_loc = httpServer.available();
  if (client_loc) {
    while (client_loc.connected()) {
      if (client_loc.available())    {
// recupere les carac requete HTML maxi taille buffer 50 min à ajuster
        char c = client_loc.read();
        buffer_lect[k]=c;   // Sauvegarde du caractere C dans le buffer
        buffer_lect[k+1]=0;  // on efface le caractère d'après (fin de chaine)
        k++;   
//if HTTP request has ended
      if (c == '\n') {
// trait requete HTTP

(then some treatment which define choix=0,1 or2 to display correct page)

  // affichage page WEB choisie **************************
      switch (choix) {
        case 1:
          Config();
          break;
        //case 2:
          //Digital();
          //break;
        case 0:
        default :
          showAcceuil(info);
      }
  client_loc.fastrprintln(F("</body></html>"));
  client_loc.fastrprintln(F(""));      
  
  client_loc.close();
            }   // if HTTP request end        
        }  // if client available        
      } // while client
       memset (buffer_lect,0,sizeof(buffer_lect));  //clearing string for next read
       k=0;
    }  // if (client)

// ******* fin affichage WEB *******************************

fin main loop ------------------------------------------------

// here is the functions now ................................

 void sendHeader(Adafruit_CC3000_ClientRef client, char *title)
{   // send a standard http response header }

void sendHeaderFix(Adafruit_CC3000_ClientRef client, char *title)
{ }

void showAcceuil(char* info_loc)
{
 sendHeader(client_loc,Nommage_client);
 // corps page HTML
}

void Config()
{
  sendHeaderFix(client_loc,"Configuration");
}


it doesn't compile : client_loc is not known in functions Config or showAcceuil
is there any way to declare a global variable for such client ??
thanks to help me...

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: CC3000 wifi shield in a class/library

Post by tdicola »

Try adding client_loc as a parameter to each of those functions. You'll want to pass it around by reference since it's a somewhat complex type (just a funky C++ issue to prevent the parameter from being copied). Here's an example of how the functions might be defined:

Code: Select all

void showAcceuil(Adafruit_CC3000_ClientRef& client_loc, char* info_loc)
{
 sendHeader(client_loc,Nommage_client);
 // corps page HTML
}

void Config(Adafruit_CC3000_ClientRef& client_loc)
{
  sendHeaderFix(client_loc,"Configuration");
}
Then when you call those functions in your main code you can pass client_loc as the first parameter:

Code: Select all

switch (choix) {
        case 1:
          Config(client_loc);
          break;
        //case 2:
          //Digital();
          //break;
        case 0:
        default :
          showAcceuil(client_loc, info);
      }
That should help you pass around the client to functions so they can use it too. Good luck!

User avatar
philou
 
Posts: 27
Joined: Wed Jan 28, 2015 2:24 pm

Re: CC3000 wifi shield in a class/library

Post by philou »

great !! it works too, so I can use now client as a variable ....
I have 1 other questions about printing html requests, found yesterday :

what is the diff between client.print and client.fastrprint (the 2 are compiling...) but sometimes it works, and some other, no !

it seems that fastrprint works only for static strings ("....") or define (#) , not for variables...except for char array so in fact it works only with string pointers....is it right ?
for all other variables except char array, you have to use client.print or client.println ... am i right ?

so fastprint is a quick way to treat a string or a char array only, but it works also with print... ?

User avatar
philou
 
Posts: 27
Joined: Wed Jan 28, 2015 2:24 pm

Re: CC3000 wifi shield in a class/library

Post by philou »

Hello : I have found the way to do conditionnal include with ARDUINO !!! not completely checked but it compiles..

here is the way applied for Ethernet and CC"k librairies :

Code: Select all

#include <EEPROM.h>
#include <SPI.h>
#define wifi

#ifdef wifi
#include <Adafruit_CC3000.h>
#include <utility/debug.h>
#include <utility/socket.h>
#else
#include <SPI.h>
#include <Ethernet.h>
#include <MemoryFree.h>
#endif
of course, you can add #define specific variables inside the ifdef else endif declaration for each application, if needed...

a second remarks about difference between ETH and CC3k shield cards: as the WEB or CLIENT requests takes more time with the CC3k, I get some delay in my interrupt time management so a slight difference of tasks timing between the 2 cards which lead to some differences.... take care of that...

User avatar
peterd0404
 
Posts: 4
Joined: Thu May 19, 2016 10:33 am

Re: CC3000 wifi shield in a class/library

Post by peterd0404 »

I do not know if this subject is still being monitored. I am trying to use the CC3000 with DuctSoup MB/tcp library and his sample code. I am testing this with a HMI simulator software. I am getting an error message "invalid data length" on my simulator. The CC3000 receive the request but does not respond properly. I took a wireshark trace of the comms. The packet is requesting for read holding registers (FC3) with a length of 6 words. The reply is:
Transaction Identifier:0
Protocol Identifier: 0
Length: 3
Unit Identifier: 255
Function Code: Reading Hold Registers (3)
Request Frame:352
Byte Count: 2
Data: <MISSING>

I am requesting for 6 words and it is only responding back with 3 words.

Attached is my program. Any help is greatly appreciated.

Thanks,
Peter
Attachments
modbus_tcp_test.zip
(6.42 KiB) Downloaded 19 times

User avatar
philou
 
Posts: 27
Joined: Wed Jan 28, 2015 2:24 pm

Re: CC3000 wifi shield in a class/library

Post by philou »

sorry ! I don't know what ModBus library is used for... could you give more explanations about your application, so maybe some people will be interested in to have a deeper look inside and be able to help you !

User avatar
peterd0404
 
Posts: 4
Joined: Thu May 19, 2016 10:33 am

Re: CC3000 wifi shield in a class/library

Post by peterd0404 »

I have tested it with ModPoll and I am getting the error: Invalid Reply Error. The wireshark trace still gave me the same message. I used your "simpletest" project.

I included the header for the MB_CC3000 and removed the MB_Ethernet.

My assumption is that the message received is not sync with the arduino clock through SPI. I'm not that familiar with the CC3000 library.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”