Copy current echo server demo to serve as base for client demo.

git-svn-id: svn+ssh://oldsvn/home/mlalondesvn/svn/cral@126 3ee9b42a-b53c-0410-a25e-f0b6218d5d5b
master
follower 17 years ago
parent 2b9fcedc53
commit 4813578111

@ -0,0 +1,328 @@
/*
Code to test wiznet WIZ810MJ module
See:
<http://code.rancidbacon.com/LearningAboutArduinoWIZ810MJ>
Current features:
* Initial W5100 driver port:
+ new-style network configuration
+ socket creation/listening/closing
+ Sending/Receiving okay
+ example "echo" server (no longer)
+ example "web server" with LED flash.
* Terrible hacked-together code
Author:
follower@rancidbacon.com
License:
LGPL
Version:
20071106-0005+
*/
#include <WIZ810MJ.h>
// Define SPI-related pins
#define PIN_DATA_OUT 11 // MOSI (Master Out / Slave In)
#define PIN_DATA_IN 12 // MISO (Master In / Slave Out)
#define PIN_SPI_CLOCK 13 // SCK (Serial Clock)
#define PIN_SLAVE_SELECT 10 // SS (Slave Select)
// #define PIN_RESET 9 // WIZnet module /RESET
#define PIN_RESET 8 // WIZnet module /RESET
SOCKET testSocket;
byte ip[6];
void configureSPI() {
/*
Configure pins and registers required for SPI communication.
*/
// Configure I/O pins
pinMode(PIN_DATA_OUT, OUTPUT);
pinMode(PIN_DATA_IN, INPUT);
pinMode(PIN_SPI_CLOCK, OUTPUT);
pinMode(PIN_SLAVE_SELECT, OUTPUT);
digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
/*
Configure SPI Control Register (SPCR) (All values initially 0)
Bit Description
7 SPI Interrupt Enable -- disable (SPIE --> 0)
6 SPI Enable -- enable (SPE --> 1)
5 Data Order -- MSB 1st (DORD --> 0) (Slave specific)
4 Master/Slave Select -- master (MSTR --> 1)
3 Clock Polarity -- (CPOL --> 0) (Slave specific) ("Mode")
2 Clock Phase -- (CPHA --> 0) (Slave specific)
1 SPI Clock Rate Select 1 -- } (SPR1 --> 0)
0 SPI Clock Rate Select 0 -- } fOSC/4 (SPR0 --> 0) ("Fastest" but see SPI2X in SPSR)
*/
SPCR = (1<<SPE)| (1<<MSTR);
// Clear previous data and status (TODO: Determine if necessary/better way.)
// (Based on Playground SPI example.)
byte dummy;
dummy = SPSR;
dummy = SPDR;
delay(10);
}
void initModule() {
/*
Initialise the WIZ810MJ module and driver.
*/
/*
Initialise the W5100 chip
(Originally I thought it was possible for the chip
to function without a hardware reset but it
seems not to be the case.)
*/
pinMode(PIN_RESET, OUTPUT);
// We rely on the time between function calls to
// be long enough for the chip to recognise the
// reset.
digitalWrite(PIN_RESET, HIGH);
digitalWrite(PIN_RESET, LOW); // reset
digitalWrite(PIN_RESET, HIGH);
// Chip initialisation by driver
// Might be redundant following the above reset,
// as this performs a software reset.
iinchip_init();
// Initialise driver
// (This is required to configure some variables used
// internally by the driver--even if the default chip
// configuration is used.)
sysinit(0x55, 0x55);
}
#define PIN_LED 2
void setup () {
Serial.begin(9600);
Serial.println("Setup enter...");
configureSPI();
initModule();
Serial.println("Test W5100 configuration...");
byte config_gateway[] = {192,168,2,101};
byte config_subnet_mask[] = {255,255,255,0};
byte config_mac_address[] = {0x02,0xDE,0xAD,0xBE,0xEF,0x00};
byte config_ip_address[] = {192,168,2,105};
setGAR(config_gateway);
setSUBR(config_subnet_mask);
setSHAR(config_mac_address);
setSIPR(config_ip_address);
Serial.println("End test W5100 configuration...");
Serial.println("Test W5100 driver code...");
getGAR(ip);
Serial.print("Gateway IP read (first digit): ");
Serial.println(ip[0], DEC);
Serial.println("End test W5100 driver code...");
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, HIGH);
Serial.println("Setup exit...");
}
void sendPrompt(uint8_t *buffer) { // {Socket targetSocket, ) {
strcpy((char *) buffer, "w00t!> ");
Serial.print("send result: ");
//Serial.println(send(testSocket, buffer, 6), DEC);
Serial.println(send(testSocket, buffer, strlen((char *)buffer)), DEC);
}
void sendBanner(uint8_t *buffer, int ledState) { // {Socket targetSocket, ) {
//strcpy((char *) buffer, "Content-Type: text/plain\n\nfoo!\n");
strcpy((char *) buffer, "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body bgcolor='#000000'>foo!</body></html>\n");
if (ledState) {
buffer[63] = 'F';
} else {
buffer[65] = 'F';
}
Serial.print("send result: ");
Serial.println(send(testSocket, buffer, strlen((char *)buffer)), DEC);
}
void loop() {
Serial.println("Test W5100 socket...");
Serial.print("Create socket result: ");
Serial.println(socket(testSocket, Sn_MR_TCP, 80, 0), DEC);
Serial.print("Socket status: ");
Serial.println(IINCHIP_READ(Sn_SR(testSocket)), HEX);
if (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
Serial.println("Socket still closed, waiting...");
while (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
//pass
}
}
Serial.print("Listen on socket result: ");
Serial.println(listen(testSocket), DEC);
Serial.println("Waiting for connection...");
while (getSn_SR(testSocket) == SOCK_LISTEN) {
delay(500);
}
Serial.println(getSn_SR(testSocket),HEX);
getSn_DIPR(testSocket, ip);
Serial.print("Destination IP read (last digit): ");
Serial.println(ip[3], DEC);
// TODO: Avoid buffer overflows in both cases...
#define MAX_RX_BUFFER_SIZE 5
#define MAX_TX_BUFFER_SIZE 200
uint8_t bytesReceived[MAX_RX_BUFFER_SIZE]; // NOTE: Actual buffer should be larger.
uint8_t bytesToSend[MAX_TX_BUFFER_SIZE];
//sendBanner(bytesReceived);
//sendPrompt(bytesReceived);
int dataLength = 0;
#define STATE_G 0
#define STATE_E 1
#define STATE_T 2
#define STATE_SPACE 3
#define STATE_SLASH 4
#define STATE_READ 5
#define STATE_END -2
#define STATE_ERR -1
int state = STATE_G;
int ledState = 1;
unsigned char theByte;
while (getSn_SR(testSocket) == SOCK_ESTABLISHED) {
while (getSn_RX_RSR(testSocket) > 0) {
recv(testSocket, bytesReceived, 1);
theByte = bytesReceived[0];
//Serial.print(bytesReceived[0], BYTE);
Serial.print(theByte, BYTE);
if ((state == STATE_G) && (theByte == 'G')) {
state = STATE_E;
} else if ((state == STATE_E) && (theByte == 'E')) {
state = STATE_T;
} else if ((state == STATE_T) && (theByte == 'T')) {
state = STATE_SPACE;
} else if ((state == STATE_SPACE) && (theByte == ' ')) {
state = STATE_SLASH;
} else if ((state == STATE_SLASH) && (theByte == '/')) {
state = STATE_READ;
} else if ((state == STATE_READ) && (theByte == '0')) {
digitalWrite(PIN_LED, LOW);
ledState = 0;
//state = STATE_END;
delay(100);
} else if ((state == STATE_READ) && (theByte == '1')) {
digitalWrite(PIN_LED, HIGH);
ledState = 1;
//state = STATE_END;
delay(100);
} else if (state == STATE_READ) {
// It's not a valid byte.
state = STATE_END;
} else {
state = STATE_ERR;
}
if ((state == STATE_ERR) || (state == STATE_END)) {
Serial.println("");
break;
}
/*
dataLength = getSn_RX_RSR(testSocket);
if (dataLength >= MAX_RX_BUFFER_SIZE) { // TODO: blah, blah...
dataLength = MAX_RX_BUFFER_SIZE-1;
}
// Serial.print("dataLength: "); Serial.println(dataLength, HEX);
//Serial.print("recv result: ");
//Serial.println(recv(testSocket, bytesReceived, dataLength), DEC); // NOTE: Throws away unread portion? No?
recv(testSocket, bytesReceived, dataLength); // TODO: Return length?
bytesReceived[dataLength]=0x00;
Serial.print((char *)bytesReceived);
//Serial.print("send result: ");
//Serial.println(send(testSocket, bytesReceived, dataLength), DEC);
//sendPrompt(bytesReceived);
*/
}
sendBanner(bytesToSend, ledState);
//sendPrompt(bytesReceived);
break;
}
close(testSocket);
disconnect(testSocket);
Serial.println("End test W5100 socket...");
}

@ -0,0 +1,346 @@
/*
Code to test wiznet WIZ810MJ module
See:
<http://code.rancidbacon.com/LearningAboutArduinoWIZ810MJ>
Current features:
* Initial W5100 driver port:
+ new-style network configuration
+ socket creation/listening/closing
+ Sending/Receiving okay
+ example "echo" server (no longer)
+ example "web server" with LED flash.
* Terrible hacked-together code
Author:
follower@rancidbacon.com
License:
LGPL
Version:
20071106-0005+
*/
#include <WIZ810MJ.h>
// Define SPI-related pins
#define PIN_DATA_OUT 11 // MOSI (Master Out / Slave In)
#define PIN_DATA_IN 12 // MISO (Master In / Slave Out)
#define PIN_SPI_CLOCK 13 // SCK (Serial Clock)
#define PIN_SLAVE_SELECT 10 // SS (Slave Select)
// #define PIN_RESET 9 // WIZnet module /RESET
#define PIN_RESET 8 // WIZnet module /RESET
SOCKET testSocket;
byte ip[6];
void configureSPI() {
/*
Configure pins and registers required for SPI communication.
*/
// Configure I/O pins
pinMode(PIN_DATA_OUT, OUTPUT);
pinMode(PIN_DATA_IN, INPUT);
pinMode(PIN_SPI_CLOCK, OUTPUT);
pinMode(PIN_SLAVE_SELECT, OUTPUT);
digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
/*
Configure SPI Control Register (SPCR) (All values initially 0)
Bit Description
7 SPI Interrupt Enable -- disable (SPIE --> 0)
6 SPI Enable -- enable (SPE --> 1)
5 Data Order -- MSB 1st (DORD --> 0) (Slave specific)
4 Master/Slave Select -- master (MSTR --> 1)
3 Clock Polarity -- (CPOL --> 0) (Slave specific) ("Mode")
2 Clock Phase -- (CPHA --> 0) (Slave specific)
1 SPI Clock Rate Select 1 -- } (SPR1 --> 0)
0 SPI Clock Rate Select 0 -- } fOSC/4 (SPR0 --> 0) ("Fastest" but see SPI2X in SPSR)
*/
SPCR = (1<<SPE)| (1<<MSTR);
// Clear previous data and status (TODO: Determine if necessary/better way.)
// (Based on Playground SPI example.)
byte dummy;
dummy = SPSR;
dummy = SPDR;
delay(10);
}
void initModule() {
/*
Initialise the WIZ810MJ module and driver.
*/
/*
Initialise the W5100 chip
(Originally I thought it was possible for the chip
to function without a hardware reset but it
seems not to be the case.)
*/
pinMode(PIN_RESET, OUTPUT);
// We rely on the time between function calls to
// be long enough for the chip to recognise the
// reset.
digitalWrite(PIN_RESET, HIGH);
digitalWrite(PIN_RESET, LOW); // reset
digitalWrite(PIN_RESET, HIGH);
// Chip initialisation by driver
// Might be redundant following the above reset,
// as this performs a software reset.
iinchip_init();
// Initialise driver
// (This is required to configure some variables used
// internally by the driver--even if the default chip
// configuration is used.)
sysinit(0x55, 0x55);
}
#define PIN_LED 2
void setup () {
Serial.begin(9600);
Serial.println("Setup enter...");
configureSPI();
initModule();
Serial.println("Test W5100 configuration...");
byte config_gateway[] = {192,168,2,101};
byte config_subnet_mask[] = {255,255,255,0};
byte config_mac_address[] = {0x02,0xDE,0xAD,0xBE,0xEF,0x00};
byte config_ip_address[] = {192,168,2,105};
setGAR(config_gateway);
setSUBR(config_subnet_mask);
setSHAR(config_mac_address);
setSIPR(config_ip_address);
Serial.println("End test W5100 configuration...");
Serial.println("Test W5100 driver code...");
getGAR(ip);
Serial.print("Gateway IP read (first digit): ");
Serial.println(ip[0], DEC);
Serial.println("End test W5100 driver code...");
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, HIGH);
Serial.println("Setup exit...");
}
void sendBanner(uint8_t *buffer, int ledState) { // {Socket targetSocket, ) {
//strcpy((char *) buffer, "Content-Type: text/plain\n\nfoo!\n");
strcpy((char *) buffer, "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body bgcolor='#000000'>foo!</body></html>\n");
if (ledState) {
buffer[63] = 'F';
} else {
buffer[65] = 'F';
}
Serial.print("send result: ");
Serial.println(send(testSocket, buffer, strlen((char *)buffer)), DEC);
}
uint8_t readByte() {
uint8_t theByte;
recv(testSocket, &theByte, 1);
return theByte;
}
int readMatch(char *stringToMatch) {
/*
Routine to read and match bytes received.
(Essentially strcmp replacement without requiring a large receive buffer.)
NOTE: Failed matches drop all bytes read so far. (i.e. you can't check for
a bunch of possible matches from the same starting position).
TODO: Fix this.
Note: This blocks if there isn't enough data in the rx buffer.
*/
while (getSn_RX_RSR(testSocket) < strlen(stringToMatch)) {
// block
// TODO: Return error or wait or "too short"?
}
// TODO: Do fancy string-matching techniques to avoid reading the whole string
// on non-matches. :-)
for (int currCharIdx = 0; currCharIdx < strlen(stringToMatch); currCharIdx++) {
if (readByte() != stringToMatch[currCharIdx]) {
return 0;
}
}
return 1;
}
void loop() {
Serial.println("Test W5100 socket...");
Serial.print("Create socket result: ");
Serial.println(socket(testSocket, Sn_MR_TCP, 80, 0), DEC);
Serial.print("Socket status: ");
Serial.println(IINCHIP_READ(Sn_SR(testSocket)), HEX);
if (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
Serial.println("Socket still closed, waiting...");
while (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
//pass
}
}
Serial.print("Listen on socket result: ");
Serial.println(listen(testSocket), DEC);
Serial.println("Waiting for connection...");
while (getSn_SR(testSocket) == SOCK_LISTEN) {
delay(500);
}
Serial.println(getSn_SR(testSocket),HEX);
getSn_DIPR(testSocket, ip);
Serial.print("Destination IP read (last digit): ");
Serial.println(ip[3], DEC);
// TODO: Avoid buffer overflows...
#define MAX_TX_BUFFER_SIZE 200
uint8_t bytesToSend[MAX_TX_BUFFER_SIZE];
//sendBanner(bytesReceived);
int dataLength = 0;
#define STATE_GET 0
#define STATE_READ 5
#define STATE_END -2
#define STATE_ERR -1
int state = STATE_GET;
int ledState = 1;
unsigned char theByte;
while (getSn_SR(testSocket) == SOCK_ESTABLISHED) {
while (getSn_RX_RSR(testSocket) > 0) {
if (state == STATE_GET) {
if (readMatch("GET /")) {
state = STATE_READ;
} else {
state = STATE_ERR;
}
}
if (state == STATE_READ) {
theByte = readByte();
if (theByte == '0') {
digitalWrite(PIN_LED, LOW);
ledState = 0;
delay(100);
} else if (theByte == '1') {
digitalWrite(PIN_LED, HIGH);
ledState = 1;
delay(100);
} else {
// It's not a valid byte.
state = STATE_END;
}
} else {
state = STATE_ERR;
}
if ((state == STATE_ERR) || (state == STATE_END)) {
Serial.println("");
break;
}
/*
dataLength = getSn_RX_RSR(testSocket);
if (dataLength >= MAX_RX_BUFFER_SIZE) { // TODO: blah, blah...
dataLength = MAX_RX_BUFFER_SIZE-1;
}
// Serial.print("dataLength: "); Serial.println(dataLength, HEX);
//Serial.print("recv result: ");
//Serial.println(recv(testSocket, bytesReceived, dataLength), DEC); // NOTE: Throws away unread portion? No?
recv(testSocket, bytesReceived, dataLength); // TODO: Return length?
bytesReceived[dataLength]=0x00;
Serial.print((char *)bytesReceived);
//Serial.print("send result: ");
//Serial.println(send(testSocket, bytesReceived, dataLength), DEC);
*/
}
sendBanner(bytesToSend, ledState);
break;
}
close(testSocket);
disconnect(testSocket);
Serial.println("End test W5100 socket...");
}

@ -0,0 +1,732 @@
/*
Code to test wiznet WIZ810MJ module
See:
<http://code.rancidbacon.com/LearningAboutArduinoWIZ810MJ>
Current features:
* Initial W5100 driver port:
+ new-style network configuration
+ socket creation/listening/closing
+ Sending/Receiving okay
+ example "echo" server (new version with classes and multiple connections)
+ example "web server" with LED flash. (not currently)
* (slighty less) Terrible hacked-together code
Author:
follower@rancidbacon.com
License:
LGPL
Version:
20071220-0006+
*/
#include <WIZ810MJ.h>
/* --------- SPI --------- */
// Define SPI-related pins
#define PIN_DATA_OUT 11 // MOSI (Master Out / Slave In)
#define PIN_DATA_IN 12 // MISO (Master In / Slave Out)
#define PIN_SPI_CLOCK 13 // SCK (Serial Clock)
#define PIN_SLAVE_SELECT 10 // SS (Slave Select)
class SpiConfiguration {
public:
static void begin(void);
};
void SpiConfiguration::begin(void) {
/*
Configure pins and registers required for SPI communication.
*/
// Configure I/O pins
pinMode(PIN_DATA_OUT, OUTPUT);
pinMode(PIN_DATA_IN, INPUT);
pinMode(PIN_SPI_CLOCK, OUTPUT);
pinMode(PIN_SLAVE_SELECT, OUTPUT);
digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
/*
Configure SPI Control Register (SPCR) (All values initially 0)
Bit Description
7 SPI Interrupt Enable -- disable (SPIE --> 0)
6 SPI Enable -- enable (SPE --> 1)
5 Data Order -- MSB 1st (DORD --> 0) (Slave specific)
4 Master/Slave Select -- master (MSTR --> 1)
3 Clock Polarity -- (CPOL --> 0) (Slave specific) ("Mode")
2 Clock Phase -- (CPHA --> 0) (Slave specific)
1 SPI Clock Rate Select 1 -- } (SPR1 --> 0)
0 SPI Clock Rate Select 0 -- } fOSC/4 (SPR0 --> 0) ("Fastest" but see SPI2X in SPSR)
*/
SPCR = (1<<SPE)| (1<<MSTR);
// Clear previous data and status (TODO: Determine if necessary/better way.)
// (Based on Playground SPI example.)
byte dummy;
dummy = SPSR;
dummy = SPDR;
delay(10);
}
SpiConfiguration SPI = SpiConfiguration();
/* ----------------------- */
/* ------ WIZ810MJ ------ */
class Wiz810MjDevice {
public:
Wiz810MjDevice(int resetPin);
void setIp(byte b0, byte b1, byte b2, byte b3);
void setMask(byte b0, byte b1, byte b2, byte b3);
void setGateway(byte b0, byte b1, byte b2, byte b3);
void setMac(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5);
private:
void _init(void);
byte * _packBuffer(byte b0, byte b1, byte b2, byte b3);
byte * _packBuffer(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5);
int _resetPin;
byte _scratchBuffer[6]; // Can we make this static?
};
Wiz810MjDevice::Wiz810MjDevice(int resetPin) {
// TODO: We should really allow the chip-select pin to be set here?
// Or require that it's defined. (Currently in the library file 'types.h'.)
_resetPin = resetPin;
_init();
}
void Wiz810MjDevice::_init(void) {
/*
Initialise the WIZ810MJ module and driver.
*/
/*
Initialise the W5100 chip
(Originally I thought it was possible for the chip
to function without a hardware reset but it
seems not to be the case.)
*/
pinMode(_resetPin, OUTPUT);
// We rely on the time between function calls to
// be long enough for the chip to recognise the
// reset.
digitalWrite(_resetPin, HIGH);
digitalWrite(_resetPin, LOW); // reset
digitalWrite(_resetPin, HIGH);
// Chip initialisation by driver
// Might be redundant following the above reset,
// as this performs a software reset.
iinchip_init();
// Initialise driver
// (This is required to configure some variables used
// internally by the driver--even if the default chip
// configuration is used.)
sysinit(0x55, 0x55);
}
byte * Wiz810MjDevice::_packBuffer(byte b0, byte b1, byte b2, byte b3) {
/*
*/
return _packBuffer(b0, b1, b2, b3, 0, 0); // Adds two bytes of padding
}
byte * Wiz810MjDevice::_packBuffer(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5) {
/*
*/
_scratchBuffer[0] = b0;
_scratchBuffer[1] = b1;
_scratchBuffer[2] = b2;
_scratchBuffer[3] = b3;
_scratchBuffer[4] = b4;
_scratchBuffer[5] = b5;
return _scratchBuffer;
}
void Wiz810MjDevice::setIp(byte b0, byte b1, byte b2, byte b3) {
/*
*/
setSIPR(_packBuffer(b0, b1, b2, b3));
}
void Wiz810MjDevice::setMask(byte b0, byte b1, byte b2, byte b3) {
/*
*/
setSUBR(_packBuffer(b0, b1, b2, b3));
}
void Wiz810MjDevice::setGateway(byte b0, byte b1, byte b2, byte b3) {
/*
*/
setGAR(_packBuffer(b0, b1, b2, b3));
}
void Wiz810MjDevice::setMac(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5) {
/*
*/
setSHAR(_packBuffer(b0, b1, b2, b3, b4, b5));
}
/* ----------------------- */
/* ---- NetworkConnection ---- */
// TODO: Make this 'NetworkServerConnection'? Or just 'ServerConnection'?
// TODO: Pull one-line methods into class definition to allow inlining?
class NetworkConnection { // Essentially a Socket wrapper
public:
NetworkConnection(uint16_t port); // TODO: Add UDP, TCP choice?
int listen();
int isConnected();
int available();
int read();
void print(uint8_t);
void close();
private:
SOCKET _socket;
static const int _MAX_SOCKETS = MAX_SOCK_NUM; // TODO: Use this.
static int _nextSocket;
};
int NetworkConnection::_nextSocket = 0;
NetworkConnection::NetworkConnection(uint16_t port) {
/*
*/
_socket = _nextSocket; // TODO: Do properly (& max)
_nextSocket++;
socket(_socket, Sn_MR_TCP, port, 0);
}
int NetworkConnection::listen() { // TODO: Make private or protected?
/*
*/
return !!::listen(_socket); // TODO: Use C++ namespaces for the driver functions?
}
int NetworkConnection::available() {
/*
Functionality matches 'Serial.available()'.
Note: If the socket is not connected then this will return 0,
but it is intended that 'isConnected()' would be checked first.
Returns:
"The number of bytes available to read ... or 0 if none are available.
If any data has come in, [...].available() will be greater than 0."
*/
// TODO: Do we want to check for 'isConnected' as well, or not?
// We have to, I guess, for valid behaviour with 'getSn_*'.
if (!isConnected()) {
return 0;
}
return getSn_RX_RSR(_socket);
}
#define NO_READ_DATA_AVAILABLE -1
int NetworkConnection::read() {
/*
Functionality matches 'Serial.read()'.
Returns:
"an int, the first byte of incoming serial data available
(or -1 if no data is available)."
Note: I thought 'recv' blocked until data was available,
but it currently seems not to block after all.
However, because I'm seeking to match the 'Serial.read'
behaviour we don't actually want to block anyway,
so we'll ignore it for the moment and handle things
ourself for now.
*/
uint8_t theByte;
if (!available()) {
return NO_READ_DATA_AVAILABLE;
}
recv(_socket, &theByte, 1);
return theByte;
}
int NetworkConnection::isConnected() {
/*
*/
// TODO: If we want the 'Network*' classes to be generic we
// would need to handle this differently:
return (getSn_SR(_socket) == SOCK_ESTABLISHED);
}
void NetworkConnection::print(uint8_t b) {
/*
*/
if (isConnected()) {
send(_socket, &b, 1);
} else {
// Just drop it if we're not connected.
}
}
void NetworkConnection::close() {
/*
*/
// TODO: Determine if we need/want the disconnect (see pg 26 W5100)
::close(_socket);
disconnect(_socket);
}
/* ----------------------- */
/* -- NetworkInterface -- */
#define HANDLE_BAD_ERROR() while (1) {};
// TODO?: Do we want to have a "default" socket accessible by 'Network.read()' etc?
class NetworkInterface {
public:
NetworkInterface(Wiz810MjDevice& networkDevice);
NetworkConnection listen(uint16_t port);
Wiz810MjDevice& device; // TODO: Make this a generic "network device" interface
};
NetworkInterface::NetworkInterface(Wiz810MjDevice& networkDevice) : device (networkDevice) {
/*
Note: The "weirdness" in this function declaration is a "initalization list",
i.e. this bit:
) : device (networkDevice) {
it is needed to give the 'device' Reference a value supplied to the method
rather than having a new 'Wiz810MjDevice' instance created.
*/
// This may not be the best place to do all this, but it'll do for now:
device.setMac(0x02,0xDE,0xAD,0xBE,0xEF,0x00);
device.setIp(169,254,254,169); // A local-link IP -- NOTE: This is out of spec.
device.setMask(255,255,0,0); // Matches local-link IP /16
device.setGateway(0,0,0,0); // We can't even guess this, so just skip it.
};
NetworkConnection NetworkInterface::listen(uint16_t port) {
/*
NOTE: For reasons I don't understand, this FAILS TO WORK if port >255.
The port that gets opened is ~(port mod 255) but if you limit
port to be uint8_t for example you don't get an error until
the port number is bigger than 'long'.
TODO: Track and fix this for port numbers > 255.
Returns a NetworkConnection listening on the specified TCP port.
*/
NetworkConnection connection = NetworkConnection(port);
// TODO: How to best handle errors?
// There's two major categories I can think of currently:
// 1) A socket wasn't available to listen in the first place
// 2) The listen attempt failed for some reason
// Using 'HANDLE_BAD_ERROR()' (currently an infinite loop) is
// not ideal but should prevent the above errors slipping by unnoticed.
if (!connection.listen()) {
HANDLE_BAD_ERROR();
}
return connection;
}
// NetworkInterface Network = NetworkInterface(...); // TODO: Make this a global
/* ----------------------- */
/* ----- EchoServer ------ */
#define ECHO_CONNECT_WAIT 0
#define ECHO_CONNECTED 1
#define ECHO_CLOSE 2
#define ECHO_HALT 3
class EchoServer {
public:
EchoServer(int port);
void next(); // TODO: Return something useful?
private:
NetworkConnection _connection; // TODO: Make public?
int _state;
};
EchoServer::EchoServer(int port) : _connection (NetworkConnection(port)) {
/*
*/
_state = ECHO_CONNECT_WAIT;
_connection.listen(); // TODO: We should be using Network.listen(...) here and in initialisation list.
}
void EchoServer::next() {
/*
*/
// TODO: Use better state machine implementation?
if (_state == ECHO_CONNECT_WAIT) {
if (_connection.isConnected()) {
_state = ECHO_CONNECTED;
} else {
// Keep waiting
}
} else if (_state == ECHO_CONNECTED) {
if (_connection.available()) {
_connection.print(_connection.read());
} else if (!_connection.isConnected()) {
// Data finished and client disconnected
_state == ECHO_CLOSE;
}
} else if (_state == ECHO_CLOSE) {
_connection.close();
_state = ECHO_HALT;
} else if (_state == ECHO_HALT) {
// Do nothing
} else {
// Unknown state, do nothing.
}
}
/* ----------------------- */
// #define PIN_RESET 9 // WIZnet module /RESET
#define PIN_RESET 8 // WIZnet module /RESET
SOCKET testSocket;
byte ip[6];
#define PIN_LED 2
void setup () {
Serial.begin(9600);
Serial.println("Setup enter...");
Serial.println("Start W5100 configuration...");
SPI.begin();
Wiz810MjDevice WIZ810MJ = Wiz810MjDevice(PIN_RESET);
NetworkInterface Network = NetworkInterface(WIZ810MJ);
Network.device.setIp(192,168,2,105);
Network.device.setMask(255,255,255,0);
Serial.println("End W5100 configuration...");
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, HIGH);
Serial.println("Setup exit...");
/**/
Serial.println("Test sockets...");
#if 0
NetworkConnection conn = Network.listen(7);
Serial.println("Waiting for connection...");
while (!conn.isConnected()) {
//Serial.print(!conn.isConnected());
delay(500);
}
Serial.println("Connected...");
while (conn.isConnected()) {
if (conn.available()) {
// Serial.print(conn.read(), BYTE);
conn.print(conn.read());
}
}
Serial.println("");
conn.close();
#endif
// This uses the 1-argument constructor of EchoServer and supplies it with 7 for each instance.
EchoServer servers[MAX_SOCK_NUM] = {7, 7, 7, 7}; // This will break if MAX_SOCK_NUM changes.
while (1) {
for (int i=0; i<MAX_SOCK_NUM; i++) {
servers[i].next();
}
}
Serial.println("End test and dummy loop");
while (1) {}
/**/
}
#if 0
void sendBanner(uint8_t *buffer, int ledState) { // {Socket targetSocket, ) {
//strcpy((char *) buffer, "Content-Type: text/plain\n\nfoo!\n");
strcpy((char *) buffer, "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body bgcolor='#000000'>foo!</body></html>\n");
if (ledState) {
buffer[63] = 'F';
} else {
buffer[65] = 'F';
}
Serial.print("send result: ");
Serial.println(send(testSocket, buffer, strlen((char *)buffer)), DEC);
}
uint8_t readByte() {
uint8_t theByte;
recv(testSocket, &theByte, 1);
return theByte;
}
int readMatch(char *stringToMatch) {
/*
Routine to read and match bytes received.
(Essentially strcmp replacement without requiring a large receive buffer.)
NOTE: Failed matches drop all bytes read so far. (i.e. you can't check for
a bunch of possible matches from the same starting position).
TODO: Fix this.
Note: This blocks if there isn't enough data in the rx buffer.
*/
while (getSn_RX_RSR(testSocket) < strlen(stringToMatch)) {
// block
// TODO: Return error or wait or "too short"?
}
// TODO: Do fancy string-matching techniques to avoid reading the whole string
// on non-matches. :-)
for (int currCharIdx = 0; currCharIdx < strlen(stringToMatch); currCharIdx++) {
if (readByte() != stringToMatch[currCharIdx]) {
return 0;
}
}
return 1;
}
void loop() {
Serial.println("Test W5100 socket...");
Serial.print("Create socket result: ");
Serial.println(socket(testSocket, Sn_MR_TCP, 80, 0), DEC);
Serial.print("Socket status: ");
Serial.println(IINCHIP_READ(Sn_SR(testSocket)), HEX);
if (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
Serial.println("Socket still closed, waiting...");
while (IINCHIP_READ(Sn_SR(testSocket)) == SOCK_CLOSED) {
//pass
}
}
Serial.print("Listen on socket result: ");
Serial.println(listen(testSocket), DEC);
Serial.println("Waiting for connection...");
while (getSn_SR(testSocket) == SOCK_LISTEN) {
delay(500);
}
Serial.println(getSn_SR(testSocket),HEX);
getSn_DIPR(testSocket, ip);
Serial.print("Destination IP read (last digit): ");
Serial.println(ip[3], DEC);
// TODO: Avoid buffer overflows...
#define MAX_TX_BUFFER_SIZE 200
uint8_t bytesToSend[MAX_TX_BUFFER_SIZE];
//sendBanner(bytesReceived);
int dataLength = 0;
#define STATE_GET 0
#define STATE_READ 5
#define STATE_END -2
#define STATE_ERR -1
int state = STATE_GET;
int ledState = 1;
unsigned char theByte;
while (getSn_SR(testSocket) == SOCK_ESTABLISHED) {
while (getSn_RX_RSR(testSocket) > 0) {
if (state == STATE_GET) {
if (readMatch("GET /")) {
state = STATE_READ;
} else {
state = STATE_ERR;
}
}
if (state == STATE_READ) {
theByte = readByte();
if (theByte == '0') {
digitalWrite(PIN_LED, LOW);
ledState = 0;
delay(100);
} else if (theByte == '1') {
digitalWrite(PIN_LED, HIGH);
ledState = 1;
delay(100);
} else {
// It's not a valid byte.
state = STATE_END;
}
} else {
state = STATE_ERR;
}
if ((state == STATE_ERR) || (state == STATE_END)) {
Serial.println("");
break;
}
/*
dataLength = getSn_RX_RSR(testSocket);
if (dataLength >= MAX_RX_BUFFER_SIZE) { // TODO: blah, blah...
dataLength = MAX_RX_BUFFER_SIZE-1;
}
// Serial.print("dataLength: "); Serial.println(dataLength, HEX);
//Serial.print("recv result: ");
//Serial.println(recv(testSocket, bytesReceived, dataLength), DEC); // NOTE: Throws away unread portion? No?
recv(testSocket, bytesReceived, dataLength); // TODO: Return length?
bytesReceived[dataLength]=0x00;
Serial.print((char *)bytesReceived);
//Serial.print("send result: ");
//Serial.println(send(testSocket, bytesReceived, dataLength), DEC);
*/
}
sendBanner(bytesToSend, ledState);
break;
}
close(testSocket);
disconnect(testSocket);
Serial.println("End test W5100 socket...");
}
#else
void loop() {
}
#endif
Loading…
Cancel
Save