Интернет шилд ENC28J60

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Час повозился с ENC28J60, только поднял сервер по готовым примерам (и то, 90% не работают)... До клиента так и не допер, может, у кого есть готовенькое?

Хотелось бы создать клиента, сделать запрос/отправить данные, принять ответ сервера, удалить клиента.

Еще, может, ктонить разжует мне вкратце список функций или методов...? Это будет полезно многим.

Спасибо!

 

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Итак, продолжаем ковырять. Нашел более-мение адекватную библиотеку с примером, похожим на мой. В примере клиент подключается к серверу почты, проверяет/забирает её.

Путь к библиотеке: https://www.heise.de/ct/projekte/machmit/processing/attachment/wiki/Lese...

И код под спойлером, который буду рассматривать:

/*
 * Arduino ENC28J60 Ethernet shield POP3 mail checker
 */

#include "etherShield.h"

// A pin to use as output to signal mails
#define MAIL_PIN 7
#define ENABLE_PIN 2

// #define PJDEBUG

// 
// The name of the virtual host which you want to contact at websrvip (hostname of the first portion of the URL):
#define POPSERVER_VHOST "pop3.provider.de" // Name of POP3-Mailserver
#define MAILACCOUNT "my.mailaccount" // Name of Mail Account
#define MAILPASSWORD "secret" // Mail password

// listen port for tcp/www:
#define POP3PORT 110
#define MAILINTERVALL 300000
#define POP3TIMEOUT 6000

#define BUFFER_SIZE 512

// popstatus
#define W4PACKET       0
#define W4PREPARE      1
#define W4CONNECT      2
#define W4USER         3
#define W4PASS         4
#define W4STAT         5
#define W4QUIT         99

// mainstatus
#define W4IDLE         0
#define W4REQUEST      1
#define W4SETFLAG      2
#define W4RESETFLAG    3


static volatile uint8_t popstatus=W4PACKET;
static volatile uint8_t mainstatus=W4IDLE;
static volatile uint8_t answer_ok=0;
unsigned long ulTimerCount = 0; 
unsigned long ulPopCount = 0;
int16_t iMailCount = 0;

static uint8_t buf[BUFFER_SIZE+1];

// global string buffer for message:
static char statusstr[150];

// Please modify the following lines. mac and ip have to be unique
// in your local area network. You can not have the same numbers in
// two devices:
// how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX
static uint8_t mymac[6] = {0x54,0x55,0x58,0x00,0x00,0x07}; // my MAC-Address
static uint8_t myip[4]  = {192,168,100,99}; // my IP-Address, adapt to your own network!!!

// Default gateway. The ip address of your DSL router. It can be set to the same as
// mailsrvip the case where there is no default GW to access the 
// pop server (=pop server is on the same lan as this host) 
static uint8_t gwip[4] = {192,168,100,1};  // my Default-Gateway, adapt to your own network!!!

// IP address of the POP3 server to contact. Adapt to your mail provider/mail account. 
// E.g. get mail address by pinging the pop3 mail server name.
// DNS look-up is a feature which we still need to add.
//static uint8_t popsrvip[4] = {62,153,158,211}; // T-Online Germany
static uint8_t popsrvip[4] = {151,189,21,113}; // Vodafone(Arcor) Germany

EtherShield es=EtherShield();



//--------------------------------------------------------------------------------------
void setup()
{
  uint8_t  ui8LinkUp;

  //  Prepare Output for LED
  pinMode( MAIL_PIN, OUTPUT );
  digitalWrite( MAIL_PIN, LOW );
  pinMode( ENABLE_PIN, INPUT );
  digitalWrite( ENABLE_PIN, HIGH );

  Serial.begin(9600);	// opens serial port, sets data rate to 9600 bps
  
  /*initialize enc28j60*/
  es.ES_enc28j60Init(mymac);

  //init the ethernet/ip layer:
  es.ES_init_ip_arp_udp_tcp(mymac,myip, POP3PORT);

  // init the web client:
  es.ES_client_set_gwip(gwip);  // e.g internal IP of dsl router
  es.ES_client_tcp_set_serverip(popsrvip);

  ui8LinkUp = es.ES_enc28j60linkup();
  Serial.print("Link Up: ");
  Serial.println(ui8LinkUp,HEX);

  popstatus=W4PACKET;
  mainstatus=W4IDLE;
  iMailCount = 0;
  ulTimerCount = millis() + MAILINTERVALL;
  ulPopCount   = 0;
  
  Serial.println("etherShield Mailchecker ready.");
}

//--------------------------------------------------------------------------------------
void loop()
{
switch(mainstatus)
  {
  case W4IDLE: // IDLE state, wait for timer event
    if(ulTimerCount < millis() && (digitalRead(ENABLE_PIN)))
      {
      ulTimerCount = millis() + MAILINTERVALL;
      mainstatus = W4REQUEST;
#ifdef PJDEBUG
      Serial.println("mainstatus = W4REQUEST");
#endif
      }
    break;
  case W4REQUEST: // REQUEST state, get mail count
    if(popstatus == W4PACKET)
      {// Mailcount received
      if(iMailCount > 0)
        {
        mainstatus = W4SETFLAG;
#ifdef PJDEBUG
        Serial.println("mainstatus = W4SETFLAG");
#endif
        }
        else
        {
        mainstatus = W4RESETFLAG;        
#ifdef PJDEBUG
        Serial.println("mainstatus = W4RESETFLAG");
#endif
        }
      }
    break;
  case W4SETFLAG: // SETFLAG state, set mail flag to active position
    mainstatus = W4IDLE;
#ifdef PJDEBUG
    Serial.println("mainstatus = W4IDLE");
#endif
    Serial.println("Mailsignal eingeschaltet.");
    digitalWrite(MAIL_PIN, HIGH);
    break;
  case W4RESETFLAG: // RESETFLAG state, return mail flag back to idle position
    mainstatus=W4IDLE;
#ifdef PJDEBUG
    Serial.println("mainstatus = W4IDLE");
#endif
    Serial.println("Mailsignal AUSgeschaltet.");
    digitalWrite(MAIL_PIN, LOW);
    break;
  default:
    mainstatus=W4IDLE;
#ifdef PJDEBUG
    Serial.println("DEFAULT! mainstatus = W4IDLE");
#endif
    break;
  }

// state machine for Mail request
getMailCount();
}


//--------------------------------------------------------------------------------------
void getMailCount()
{
static uint16_t dat_p;
static uint16_t uiLen;
static uint8_t  ui8Fd;

dat_p=es.ES_packetloop_icmp_tcp(buf, es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));

// state machine
switch(popstatus)
  {
  case W4PACKET: // IDLE state
    if((mainstatus ==W4REQUEST))
      {
      answer_ok = 0;
      Serial.println("Open Connection to Server");
      ui8Fd = es.ES_client_tcp_req(mail_client_tcp_result_callback,mail_client_tcp_datafill_callback,POP3PORT);
      ulPopCount = millis() + POP3TIMEOUT;
      popstatus = W4PREPARE;
#ifdef PJDEBUG
      Serial.println("W4Pk: popstatus = W4PREPARE");
#endif
      }
    break;
  case W4PREPARE: // Open connection to pop server
    if(ulPopCount < millis())
      {// Timeout erreicht
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    if(answer_ok)
      {
      answer_ok = 0;
      Serial.println("W4Pr: Should not come up!");
      break;
      }
  case W4CONNECT: // Wait until server answered, then send USER command
    if(ulPopCount < millis())
      {// Timeout erreicht
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    if(answer_ok)
      {
      answer_ok = 0;
#ifdef PJDEBUG
      Serial.println("W4Co: Send USER to server");
#endif
      es.ES_client_tcp_add(buf, mail_client_tcp_result_callback, mail_client_tcp_datafill_callback);
      break;
      }
  case W4USER: // Wait for answer from server after USER command then send PASS
    if(ulPopCount < millis())
      {// Timeout erreicht
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    if(answer_ok)
      {
      answer_ok = 0;
#ifdef PJDEBUG
      Serial.println("W4Us: Send PASS to server");
#endif
      es.ES_client_tcp_add(buf, mail_client_tcp_result_callback, mail_client_tcp_datafill_callback);
      break;
      }
  case W4PASS: // Wait for answer after PASS, then send STAT
    if(ulPopCount < millis())
      {// Timeout erreicht
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    if(answer_ok)
      {
      answer_ok = 0;
#ifdef PJDEBUG
      Serial.println("W4Pw: Send STAT to server");
#endif
      es.ES_client_tcp_add(buf, mail_client_tcp_result_callback, mail_client_tcp_datafill_callback);
      break;
      }
  case W4STAT: // Wait for answer after STAT, then send QUIT
    if(ulPopCount < millis())
      {// Timeout erreicht
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    if(answer_ok)
      {
      answer_ok = 0;
#ifdef PJDEBUG
      Serial.println("W4St: Send QUIT to server");
#endif
      es.ES_client_tcp_add(buf, mail_client_tcp_result_callback, mail_client_tcp_datafill_callback);
      break;
      }
  case W4QUIT: // Wait for answer after QUIT, then return to W4PACKET state
    if(ulPopCount < millis() || answer_ok)
      {// Timeout erreicht
      answer_ok = 0;
      popstatus = W4PACKET;
#ifdef PJDEBUG
      Serial.println("popstatus = W4PACKET");
#endif
      break;
      }
    break;
  default:
    answer_ok = 0;
    popstatus = W4PACKET;
    break;
  }
}

//--------------------------------------------------------------------------------------
// This is how to use the tcp client:
//
// Declare a callback function to get the result (tcp data from the server):
//
// uint8_t your_client_tcp_result_callback(uint8_t fd, uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data){...your code;return(close_tcp_session);}
//
// statuscode=0 means the buffer has valid data, otherwise len and pos_in_buf
// are invalid. That is: do not use data_start_pos_in_buf and len_of_data
// if statuscode!=0.
//
// This callback gives you access to the TCP data of the first
// packet returned from the server. You should aim to minimize the server
// output such that this will be the only packet.
//
// close_tcp_session=1 means close the session now. close_tcp_session=0
// read all data and leave it to the other side to close it. 
// If you connect to a web server then you want close_tcp_session=0.
// If you connect to a modbus/tcp equipment then you want close_tcp_session=1
//
// Declare a callback function to be called in order to fill in the request (tcp data sent to the server):
// uint16_t your_client_tcp_datafill_callback(uint8_t fd){...your code;return(len_of_data_filled_in);}
//
// Now call: 
// fd=client_tcp_req(&your_client_tcp_result_callback,&your_client_tcp_datafill_callback,portnumber);
//
// fd is a file descriptor like number that you get back in the fill and result
// function so you know to which call of client_tcp_req this callback belongs.
//
// You can not start different clients (e.g modbus and web) at the
// same time but you can start them one after each other. That is
// when the request has timed out or when the result_callback was
// executed then you can start a new one. The fd makes it still possible to
// distinguish in the callback code the different types you started.
//
// Note that you might never get called back if the other side does
// not answer. A timer would be needed to recongnize such a condition.
//
// We use callback functions because that saves memory and a uC is very
// limited in memory
//
// PJ2010-11-11a:
// After the initial exchange, continue the conversation by using the function
//   es.ES_client_tcp_add(buf, mail_client_tcp_result_callback, mail_client_tcp_datafill_callback);
// which is similar to the client_tcp_req() function but will keep the port and tcp data from the initial conversation.
// I use the same callback and data fill functions and decide what to do by checking the current state, which is a global
// variable. Observe the usage of client_tcp_add() within the function void getMailCount() above.
//
//--------------------------------------------------------------------------------------
uint8_t mail_client_tcp_result_callback(uint8_t fd, uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data)
{
uint8_t close_tcp_session=0;
uint16_t i;
char  *cpOK;

switch(statuscode)
  {
  case 0: // Valid data received
#ifdef PJDEBUG
    Serial.print("RC: Data received: >");
#endif
    for(i=data_start_pos_in_buf; i<data_start_pos_in_buf+len_of_data; i++)
      {
#ifdef PJDEBUG
      Serial.print(buf[i], BYTE);
#endif
      }
    buf[i]=0;
#ifdef PJDEBUG
    Serial.println("<");
#endif
    //
    switch(popstatus)
      { // Initial connection: No data, Server answers first
      case W4PREPARE:
#ifdef PJDEBUG
        Serial.print("RC:W4PREPARE");
#endif
        if(strstr((const char *)&(buf[data_start_pos_in_buf]), "+OK")!=NULL)
          {// Server answered with OK
#ifdef PJDEBUG
          Serial.println(" +OK found");
#endif
          answer_ok = 1;
          close_tcp_session = 0;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4CONNECT");
#endif
          popstatus = W4CONNECT;
          }
          else
          {
          Serial.println(" Error found");
          close_tcp_session = 1;
          answer_ok = 0;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PACKET");
#endif
          popstatus = W4PACKET;
          }
        break;
      case W4CONNECT: // waiting for OK on user
#ifdef PJDEBUG
        Serial.print("RC:W4CONNECT");
#endif
        if(strstr((const char *)&(buf[data_start_pos_in_buf]), "+OK")!=NULL)
          {// positive answer received
#ifdef PJDEBUG
          Serial.println(" +OK found");
#endif
          answer_ok = 1;
          close_tcp_session = 0;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4USER");
#endif
          popstatus = W4USER;
          }
          else
          {
          Serial.println(" Error found");
          answer_ok = 0;
          close_tcp_session = 1;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PACKET");
#endif
          popstatus = W4PACKET;
          }
        break;
      case W4USER:
#ifdef PJDEBUG
        Serial.print("RC:W4USER");
#endif
        if(strstr((const char *)&(buf[data_start_pos_in_buf]), "+OK")!=NULL)
          {// positive answer received
#ifdef PJDEBUG
          Serial.println(" +OK found");
#endif
          answer_ok = 1;
          close_tcp_session = 0;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PASS");
#endif
          popstatus = W4PASS;
          }
          else
          {
          Serial.println(" Error found");
          answer_ok = 0;
          close_tcp_session = 1;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PACKET");
#endif
          popstatus = W4PACKET;
          }
        break;
      case W4PASS:
#ifdef PJDEBUG
        Serial.print("RC:W4PASS");
#endif
        if((cpOK=strstr((const char *)&(buf[data_start_pos_in_buf]), "+OK"))!=NULL)
          {// positive answer received
#ifdef PJDEBUG
          Serial.println(" +OK found");
#endif
          answer_ok = 1;
          close_tcp_session = 0;
          // evaluate Status
          i = strcspn (cpOK,"1234567890");
          iMailCount = atoi (cpOK+i);
          //
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4STAT");
#endif
          popstatus = W4STAT;
          }
          else
          {
          Serial.println(" Error found");
          answer_ok = 0;
          close_tcp_session = 1;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PACKET");
#endif
          popstatus = W4PACKET;
          }
        break;
      case W4STAT:
#ifdef PJDEBUG
        Serial.print("RC:W4STAT");
#endif
        if(strstr((const char *)&(buf[data_start_pos_in_buf]), "+OK")!=NULL)
          {// positive answer received
#ifdef PJDEBUG
          Serial.println(" +OK found");
#endif
          answer_ok = 1;
          close_tcp_session = 0;
          // 
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4QUIT");
#endif
          popstatus = W4QUIT;
          }
          else
          {
          Serial.println(" Error found");
          answer_ok = 0;
          close_tcp_session = 1;
#ifdef PJDEBUG
          Serial.println("RC: Change popstatus to W4PACKET");
#endif
          popstatus = W4PACKET;
          }
        break;
      case W4QUIT:
#ifdef PJDEBUG
        Serial.print("RC:W4QUIT");
        Serial.println("RC: Change popstatus to W4PACKET");
#endif
        answer_ok = 1;
        popstatus = W4PACKET;
        close_tcp_session = 1;
        break;
      default:
        Serial.println("RC:Default");
#ifdef PJDEBUG
        Serial.println("RC: Change popstatus to W4PACKET");
#endif
        popstatus = W4PACKET;
        answer_ok = 0;
        close_tcp_session = 1;
        break;
      }
    break;
  case 3: // RST received
#ifdef PJDEBUG
    Serial.println("RC: RST received");
    Serial.println("RC: Change popstatus to W4PACKET");
#endif
    popstatus = W4PACKET;
    close_tcp_session = 1;
    break;
  default: // All other errors
    Serial.print("RC: Error ");
    Serial.print(statuscode, DEC);
    Serial.print(" received in pop state ");
    Serial.print(popstatus, DEC);
    Serial.println(" !");
    Serial.println("RC: Change popstatus to W4PACKET");
    popstatus = W4PACKET;
    close_tcp_session = 1;
    break;
  }

return(close_tcp_session);
}

//--------------------------------------------------------------------------------------
//
// Datafill-Callback 
// 
uint16_t mail_client_tcp_datafill_callback(uint8_t fd)
{
uint16_t len_of_data_filled_in = 0;

switch(popstatus)
  { // Initial connection: No data, Server answers first
  case W4PREPARE:
#ifdef PJDEBUG
    Serial.println("DC: No data in W4P");
#endif
    break;
  case W4CONNECT:
#ifdef PJDEBUG
    Serial.println("DC: W4CONNECT");
#endif
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("USER "));
    len_of_data_filled_in=fill_tcp_data(buf,len_of_data_filled_in, MAILACCOUNT);
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("\r\n"));
    break;
  case W4USER:
#ifdef PJDEBUG
    Serial.println("DC: W4USER");
#endif
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("PASS "));
    len_of_data_filled_in=fill_tcp_data(buf,len_of_data_filled_in, MAILPASSWORD);
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("\r\n"));
    break;
  case W4PASS:
#ifdef PJDEBUG
    Serial.println("DC: W4PASS");
#endif
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("STAT\r\n"));
    break;
  case W4STAT:
#ifdef PJDEBUG
    Serial.println("DC: W4STAT");
#endif
    len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("QUIT\r\n"));
    break;
  case W4QUIT:
#ifdef PJDEBUG
    Serial.println("DC: W4QUIT");
#endif
    break;
  default:
#ifdef PJDEBUG
    Serial.print("DC: Unhandled state ");
    Serial.print(popstatus, DEC);
    Serial.println(" !");
#endif
    break;
  }

//...your code;
// len_of_data_filled_in=fill_tcp_data_p(buf,len_of_data_filled_in,PSTR("\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"));
// len_of_data_filled_in=fill_tcp_data(buf,len_of_data_filled_in,client_postval);

return(len_of_data_filled_in);
}
// end of file

 

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Небольшое отступление. Базовые вещи:

#include "etherShield.h"

//ip, mac, getaway, ...
static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
static uint8_t myip[4] = {192,168,2,25};
static uint8_t gwip[4] = {192,168,2,1};

 

//Создаём обьект нашего шилда
EtherShield es=EtherShield();

 

//Инициализация, "биндим" ip и getaway
void setup(){
  // initialize enc28j60
  es.ES_enc28j60Init(mymac);
  //init the ethernet/ip layer:
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
  // init the web client:
  es.ES_client_set_gwip(gwip);  // e.g internal IP of dsl router
}

 

//Примерный вариант генерации страницы со стороны ардуина-сервера

uint16_t print_webpage(uint8_t *buf){
  uint16_t plen;
  char vstr[5];

  plen = es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h1>Title</h1><pre>\n"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("text: "));

  ....

  return(plen);
}

 

//Ну и loop()

void loop(){


  void nul(){
    //Пока не ясно что и почему:
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));

    //Привязываем клиента к ip в переменной twitterip
    es.ES_client_set_wwwip(twitterip);
    посылаем http запрос, тут синтаксис тоже до конца не ясен
    es.ES_client_http_post(PSTR(TWITTERAPIURL),PSTR(TWITTER_VHOST),PSTR(TWITTERACCOUNT), PSTR("POST "),statusstr,&browserresult_callback);
    
    //Тоже самое
    es.ES_client_set_wwwip(pachubeip);
    es.ES_client_http_post(PSTR(PACHUBEAPIURL),PSTR(PACHUBE_VHOST),PSTR(PACHUBEAPIKEY), PSTR("PUT "), statusstr ,&browserresult_callback);

  }

    //Формируем страницу
    dat_p=print_webpage(buf);
    //Делаем "запрос"? Помним, что 
    //dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
    es.ES_www_server_reply(buf,dat_p);
}

 

Вот в loop() и кроются искомые запросы к серверу с передачей параметров. Т.к. весь код выдран из примера, прошу не обращать внимание на переменные.

es.ES_client_http_post() - наверное это оно самое?

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Вот тут: http://arduino.shopium.ua/pages/etherShield-simple-wrapper/
врапер, облегчает жизнь при работе с шилдом, если использовать как сервер. Заработало сразу.

Но, нет подсети (гетэвея) и нет клиента.

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

А вот тут решение проблеммы: http://arduino.ru/forum/apparatnye-voprosy/problema-s-enc28j60arduino-0
Используем библиотечку от сюда: http://jeelabs.net/projects/cafe/wiki/EtherCard
и слушаем советы от leshak, по первой ссылке.

Как же хорошо, когда разберешся...

vankenshtein
Offline
Зарегистрирован: 15.04.2014

по второй ссылке страница не существует, не могли бы вы перезалить куда-нибудь библиотеку? заранее спасибо

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013