/* 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> /* --------- 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)); } /* ----------------------- */ /* -- NetworkInterface -- */ class NetworkInterface { public: NetworkInterface(Wiz810MjDevice& networkDevice); 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. */ }; // NetworkInterface Network = NetworkInterface(...); // TODO: Make this a global /* ----------------------- */ // #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..."); SPI.begin(); Wiz810MjDevice WIZ810MJ = Wiz810MjDevice(PIN_RESET); Serial.println("Test W5100 configuration..."); WIZ810MJ.setMac(0x02,0xDE,0xAD,0xBE,0xEF,0x00); // WIZ810MJ.setIp(192,168,2,105); WIZ810MJ.setMask(255,255,255,0); WIZ810MJ.setGateway(192,168,2,101); NetworkInterface Network = NetworkInterface(WIZ810MJ); Network.device.setIp(192,168,2,105); 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..."); }