Интернет шилд ENC28J60
- Войдите на сайт для отправки комментариев
Втр, 17/07/2012 - 00:24
Час повозился с ENC28J60, только поднял сервер по готовым примерам (и то, 90% не работают)... До клиента так и не допер, может, у кого есть готовенькое?
Хотелось бы создать клиента, сделать запрос/отправить данные, принять ответ сервера, удалить клиента.
Еще, может, ктонить разжует мне вкратце список функций или методов...? Это будет полезно многим.
Спасибо!
Итак, продолжаем ковырять. Нашел более-мение адекватную библиотеку с примером, похожим на мой. В примере клиент подключается к серверу почты, проверяет/забирает её.
Путь к библиотеке: 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Небольшое отступление. Базовые вещи:
#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};//Инициализация, "биндим" 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() - наверное это оно самое?
Вот тут: http://arduino.shopium.ua/pages/etherShield-simple-wrapper/
врапер, облегчает жизнь при работе с шилдом, если использовать как сервер. Заработало сразу.
Но, нет подсети (гетэвея) и нет клиента.
А вот тут решение проблеммы: http://arduino.ru/forum/apparatnye-voprosy/problema-s-enc28j60arduino-0
Используем библиотечку от сюда: http://jeelabs.net/projects/cafe/wiki/EtherCard
и слушаем советы от leshak, по первой ссылке.
Как же хорошо, когда разберешся...
по второй ссылке страница не существует, не могли бы вы перезалить куда-нибудь библиотеку? заранее спасибо
https://github.com/jcw/ethercard