ENC28J60 проблемы с GET
- Войдите на сайт для отправки комментариев
Чт, 15/08/2013 - 09:56
Уперся в непонятную мне проблему:
есть eth модуль на ENC28J60
есть мега к которой еще подключен nrf24 с библиотекой от маньяка
делаю след.
1. добавил пример с web-server в общий код. работает.
2. добавил раздел с вызовом через GET узла, вот тут и возникает проблема
за основу взял https://github.com/jcw/ethercard/blob/master/examples/webClient/webClien...
при вызове не возвращает результат, т.е. не срабатывает callback. причем не срабатывает он только в случае, если вставлен в общий код, если грузить просто пример все работает. 2 дня трахаюсь с этой проблемой. подскажите куда рыть.
Спасибо.
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example of a sensor network
*
* This sketch demonstrates how to use the RF24Network library to
* manage a set of low-power sensor nodes which mostly sleep but
* awake regularly to send readings to the base.
*
* The example uses TWO sensors, a 'temperature' sensor and a 'voltage'
* sensor.
*
* To see the underlying frames being relayed, compile RF24Network with
* #define SERIAL_DEBUG.
*
* The logical node address of each node is set in EEPROM. The nodeconfig
* module handles this by listening for a digit (0-9) on the serial port,
* and writing that number to EEPROM.
*/
#include <avr/pgmspace.h>
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#include <Tictocs.h>
#include <Button.h>
#include <TictocTimer.h>
#include "nodeconfig.h"
#include "sleep.h"
#include "S_message.h"
#include "printf.h"
#include <EtherCard.h>
//-----eth
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,200 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
//-----eth
static BufferFiller bfill; // used as cursor while filling the buffer
struct port_param_t{String name; String value;};
#define MAX_PARAMS 20 // сколько параметров максимально мы умеем парсить
port_param_t params[MAX_PARAMS]; // в этот массив будем сохранять наши парсенные параметры
byte parsedParams=0; // сколько параметров нам удалось напарсить
// This is for git version tracking. Safe to ignore
#ifdef VERSION_H
#include "version.h"
#else
const char program_version[] = "Unknown";
#endif
// Pin definitions
#ifndef PINS_DEFINED
#define __PLATFORM__ "Getting Started board"
// Pins for Eth + Nrf21
const int SS_nrf21 = 14;
const int SS_eth = 1;
// Pins for radio
const int rf_ce = 8;
const int rf_csn = 7;
// Pins for sensors
const int temp_pin = A2;
const int voltage_pin = A3;
// Pins for status LED, or '0' for no LED connected
const int led_red = 22;
const int led_yellow = 23;
const int led_green = 25;
// Button to cont=rol modes
const int button_a = 4;
// What voltage is a reading of 1023?
const unsigned voltage_reference = 5 * 256; // 5.0V
#endif
RF24 radio(rf_ce,rf_csn);
RF24Network network(radio);
// Our node configuration
eeprom_info_t this_node;
// How many measurements to take. 64*1024 = 65536, so 64 is the max we can fit in a uint16_t.
const int num_measurements = 64;
// Sleep constants. In this example, the watchdog timer wakes up
// every 4s, and every single wakeup we power up the radio and send
// a reading. In real use, these numbers which be much higher.
// Try wdt_8s and 7 cycles for one reading per minute.> 1
const wdt_prescalar_e wdt_prescalar = wdt_4s;
const int sleep_cycles_per_transmission = 1;
// Non-sleeping nodes need a timer to regulate their sending interval
Timer send_timer(2000);
// Button controls functionality of the unit
Button ButtonA(button_a);
// Long-press button
Button ButtonLong(button_a,1000);
/**
* Convenience class for handling LEDs. Handles the case where the
* LED may not be populated on the board, so always checks whether
* the pin is valid before setting a value.
*/
class LED
{
private:
int pin;
public:
LED(int _pin): pin(_pin)
{
if (pin > 0)
{
pinMode(pin,OUTPUT);
digitalWrite(pin,LOW);
}
}
void write(bool state) const
{
if (pin > 0)
digitalWrite(pin,state?HIGH:LOW);
}
void operator=(bool state)
{
write(state);
}
};
/**
* Startup LED sequence. Lights up the LEDs in sequence first, then dims
* them in the same sequence.
*/
class StartupLEDs: public Timer
{
private:
const LED** leds;
const LED** current;
const LED** end;
bool state;
protected:
virtual void onFired(void)
{
(*current)->write(state);
++current;
if ( current >= end )
{
if ( state )
{
state = false;
current = leds;
}
else
disable();
}
}
public:
StartupLEDs(const LED** _leds, int _num): Timer(250), leds(_leds), current(_leds), end(_leds+_num), state(true)
{
}
};
/**
* Calibration LED sequence. Flashes all 3 in unison
*/
class CalibrationLEDs: public Timer
{
const LED** leds;
const LED** end;
bool state;
protected:
void write()
{
const LED** current = end;
while (current-- > leds)
(*current)->write(state);
}
virtual void onFired()
{
state = ! state;
write();
}
public:
CalibrationLEDs(const LED** _leds, int _num, unsigned long duration = 500): Timer(duration), leds(_leds), end(_leds+_num), state(false)
{
Timer::disable();
}
void begin()
{
Updatable::begin();
}
void reset()
{
state = true;
write();
Timer::reset();
}
void disable()
{
state = false;
write();
Timer::disable();
}
};
LED Red(led_red), Yellow(led_yellow), Green(led_green);
const LED* leds[] = { &Red, &Yellow, &Green };
const int num_leds = sizeof(leds)/sizeof(leds[0]);
StartupLEDs startup_leds(leds,num_leds);
CalibrationLEDs calibration_leds(leds,num_leds);
// Nodes in test mode do not sleep, but instead constantly try to send
bool test_mode = false;
// Nodes in calibration mode are looking for temperature calibration
bool calibration_mode = false;
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
// --eth--
Serial.println("\n[backSoon]");
if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
Serial.println( "Failed to access Ethernet controller");
#if STATIC
ether.staticSetup(myip, gwip);
#else
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
// --eth--
printf_begin();
printf_P(PSTR("\n\rRF24Network/examples/sensornet/\n\r"));
printf_P(PSTR("PLATFORM: " __PLATFORM__ "\n\r"),program_version);
printf_P(PSTR("VERSION: %s\n\r"),program_version);
//
// Pull node address out of eeprom
//
// Which node are we?
this_node = nodeconfig_read();
//
// Prepare sleep parameters
//
// Only the leaves sleep. Nodes 01-05 are presumed to be relay nodes.
if ( ! this_node.relay )
Sleep.begin(wdt_prescalar,sleep_cycles_per_transmission);
//
// Set up board hardware
//
ButtonA.begin();
ButtonLong.begin();
// Sensors use the stable internal 1.1V voltage
#ifdef INTERNAL1V1
analogReference(INTERNAL1V1);
#else
analogReference(INTERNAL);
#endif
// Prepare the startup sequence
send_timer.begin();
startup_leds.begin();
calibration_leds.begin();
//
// Bring up the RF network
//
SPI.begin();
radio.begin();
network.begin(/*channel*/ 92, /*node address*/ this_node.address);
}
bool Param2Msg(void* port_param_t, void* S_message)
{
return true;
}
void NRF21(void)
{
// Update objects
theUpdater.update();
// Pump the network regularly
network.update();
// If we are the base, is there anything ready for us?
while ( network.available() )
{
// If so, grab it and print it out
RF24NetworkHeader header;
S_message message;
network.read(header,&message,sizeof(message));
printf_P(PSTR("%lu: APP Received #%u %s from 0%o\n\r"),millis(),header.id,message.toString(),header.from_node);
}
// If we are the kind of node that sends readings, AND it's time to send
// a reading AND we're in the mode where we send readings...
if ( this_node.address > 0 && ( ( Sleep && ! test_mode ) || send_timer.wasFired() ) && ! calibration_mode && ! startup_leds )
{
// Transmission beginning, TX LED ON
Yellow = true;
if ( test_mode )
{
Green = false;
Red = false;
}
int i;
S_message message;
// Take the temp reading
i = num_measurements;
uint32_t reading = 0;
while(i--)
reading += analogRead(temp_pin);
// Convert the reading to celcius*256
// This is the formula for MCP9700.
// C = reading * 1.1
// C = ( V - 1/2 ) * 100
message.temp_reading = ( ( ( reading * 0x120 ) - 0x800000 ) * 0x64 ) >> 16;
// Take the voltage reading
i = num_measurements;
reading = 0;
while(i--)
reading += analogRead(voltage_pin);
// Convert the voltage reading to volts*256
message.voltage_reading = ( reading * voltage_reference ) >> 16;
printf_P(PSTR("---------------------------------\n\r"));
printf_P(PSTR("%lu: APP Sending %s to 0%o...\n\r"),millis(),message.toString(),0);
// Send it to the base
RF24NetworkHeader header(/*to node*/ 0, /*type*/ test_mode ? 's' : 'S');
bool ok = network.write(header,&message,sizeof(message));
if (ok)
{
if ( test_mode )
Green = true;
printf_P(PSTR("%lu: APP Send ok\n\r"),millis());
}
else
{
if ( test_mode )
Red = true;
printf_P(PSTR("%lu: APP Send failed\n\r"),millis());
}
// Transmission complete, TX LED OFF
Yellow = false;
if ( Sleep && ! test_mode )
{
// Power down the radio. Note that the radio will get powered back up
// on the next write() call.
radio.powerDown();
// Be sure to flush the serial first before sleeping, so everything
// gets printed properly
Serial.flush();
// Sleep the MCU. The watchdog timer will awaken in a short while, and
// continue execution here.
Sleep.go();
}
}
// Button
unsigned a = ButtonA.wasReleased();
if ( a && a < 500 )
{
// Pressing the button during startup sequences engages test mode.
// Pressing it after turns off test mode.
if ( startup_leds )
test_mode = true;
else if ( test_mode )
{
test_mode = false;
Green = false;
Red = false;
}
else if ( calibration_mode )
{
calibration_mode = false;
test_mode = true;
calibration_leds.disable();
}
}
// Long press
if ( ButtonLong.wasPressed() && test_mode )
{
test_mode = false;
calibration_mode = true;
calibration_leds.reset();
}
// Listen for a new node address
nodeconfig_listen();
}
int strtoint(String str) // Процедура переобразования строки в число
{
int tempInt;
char rez[str.length()+1];
str.toCharArray(rez, sizeof(rez));
tempInt = atoi(rez);
return tempInt;
}
void parseParams(char* inputString)
{
parsedParams=0; // пока ничего не напарсили
char* buffer=strtok(inputString,"?"); // лучше так проверять/пропускать вопросилово
if(buffer!=NULL)
{
for(buffer=strtok(NULL,"&"); buffer!=NULL; buffer=strtok(NULL,"&") )
{
String buffer1= String(buffer);
params[parsedParams].name= buffer1.substring(0,buffer1.indexOf('=')); //достаем имя
params[parsedParams].value=buffer1.substring(buffer1.indexOf('=')+1); //достаем значение в integer
parsedParams++; // отмечаем сколько удалось распарсить
}
if(parsedParams>MAX_PARAMS-1)return; // больше нет места куда сохранять парсенное.
}
}
void printParams(){
Serial.println(parsedParams);
for(byte i=0;i<parsedParams;i++){
// TODO: всю эту кучу принтов можно заменить одним sprintf
Serial.print(params[i].name);
Serial.print(" -> ");
Serial.println(params[i].value);
// Serial.print("=");
// Serial.println(params[i].value,DEC);
}
}
static uint32_t timer;
char website[] PROGMEM = "www.google.com";
static void my_callback (byte status, word off, word len) {
Serial.println(">>>");
Ethernet::buffer[off+300] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println("...");
}
void EthGet(void)
{
ether.packetLoop(ether.packetReceive());
if (millis() > timer)
{
timer = millis() + 5000;
Serial.println();
Serial.print("<<< REQ ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback);
}
}
void Eth(void)
{
word pos = ether.packetLoop(ether.packetReceive()); // получаем запрос или ответ
if (pos)
{
bfill = ether.tcpOffset();
char *data = (char *) Ethernet::buffer + pos;
parseParams(data);
// формируем ответ с переменными
bfill.emit_p(PSTR(
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"<meta http-equiv='refresh' content='5'/>"
"<title>RBBB server</title>"
"<h1>1 - $S<br></h1>"),
"123");
ether.httpServerReply(bfill.position());
}
// wait for an incoming TCP packet, but ignore its contents
/*if (ether.packetLoop(ether.packetReceive()))
{
bfill = ether.tcpOffset();
bfill.emit_p(PSTR(
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"<meta http-equiv='refresh' content='1'/>"
"<title>RBBB server</title>"
"<h1>$D$D:$D$D:$D$D</h1>"),
10, 20, 30, 40, 50, 60);
ether.httpServerReply(bfill.position());
}*/
}
void loop(void)
{
digitalWrite(SS_eth, HIGH);
digitalWrite(SS_nrf21, LOW);
NRF21();
digitalWrite(SS_eth, LOW);
digitalWrite(SS_nrf21, HIGH);
EthGet();
Eth();
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
Возможно, не хватает оперативной памяти. Какой МК?
Объявленная в 495 строке переменная не инициализирована. Не знаю плохо ли это, но я бы присвоил 0.
Задержка в 508 строке чтобы гугл не задосить?
Попробуйте собрать работающий пример с ограниченным функционалом. Только веб сервер и веб клиент, без RF24.
дело не в nrf (пробовал отключать).
Памяти с запасом, там мега2560
задержка чтоб как раз успеть получить ответ после запроса. Оно асинхронно работает.