ofer 0 Posted March 11, 2014 Share Posted March 11, 2014 I used the code you sent me and some code from "w5200-0716.zip" and i was able to create a server but i couldn't understand how to run it as a client and handle the responses. my goal is to have a client that communicate with a server via TCP. any help would be great. thanks a lot, Ofer. Quote Link to post Share on other sites
RobG 1,892 Posted March 11, 2014 Author Share Posted March 11, 2014 You should be able to use client code from W5200 code. void runAsClient() { while (1) { // the event in this case is whatever triggers client request waitForEvent(); // startClient(0, (u_char *) destinationIP, (u_char) destinationPort); // send request - build query string and send request sendRequest(); // wait for response waitForData(0); // we've got data, process it // if needed, parse response in a similar way as server's requests are parsed, verify status is 200, discard all unused information, // and extract any value that you need from content //processClientResponse(); - must implement // disconnect & close stopClient(0); } } Quote Link to post Share on other sites
ofer 0 Posted March 11, 2014 Share Posted March 11, 2014 thanks Rob, i tried to do this but my program gets stuck on: while (readFromRegister(Sn_CR)); in the functuon: void connect(u_char s, u_char * addr, u_int port) i think its because when i tried to mix both W5500 and W5200 files i get Sn_XX duplicates.. i tried to override some and change some but i guess im not doing it right. can you give me a direction? thanks, Ofer. Quote Link to post Share on other sites
RobG 1,892 Posted March 11, 2014 Author Share Posted March 11, 2014 OK, let me take a look. Quote Link to post Share on other sites
RobG 1,892 Posted March 12, 2014 Author Share Posted March 12, 2014 @@ofer, added all missing client functions and uploaded file to post #29. As is, the code will send request every 2 seconds to 192.168.168.5:80 192.168.168.43 - - [12/Mar/2014:16:38:54 -0400] "GET /mypage?button=OFF HTTP/1.1" 400 226 192.168.168.43 - - [12/Mar/2014:16:38:56 -0400] "GET /mypage?button=OFF HTTP/1.1" 400 226 192.168.168.43 - - [12/Mar/2014:16:38:58 -0400] "GET /mypage?button=OFF HTTP/1.1" 400 226 192.168.168.43 - - [12/Mar/2014:16:39:00 -0400] "GET /mypage?button=OFF HTTP/1.1" 400 226 ofer 1 Quote Link to post Share on other sites
ofer 0 Posted March 13, 2014 Share Posted March 13, 2014 Works like a charm.. thanks a lot Rob. Quote Link to post Share on other sites
ofer 0 Posted April 3, 2014 Share Posted April 3, 2014 Hi @@RobG Is their a way to add DHCP to the project? I read in one of your posts that the MSP430G2553 does't have enough memory, is their a way around it? Thanks for all your help, Ofer. Quote Link to post Share on other sites
RobG 1,892 Posted April 3, 2014 Author Share Posted April 3, 2014 Yes there is. You can use W5500's memory as extra RAM. @@spirilis was working on DHCP but I am not sure what the status is. BTW, EBP v2 has space for SRAM memory, so DHCP is also a possibility. 4jochen 1 Quote Link to post Share on other sites
spirilis 1,265 Posted April 3, 2014 Share Posted April 3, 2014 I have working DHCP on the w5200, was in the middle of documenting that library (I'm not using any of RobG's code with that one so it's a whole 'nother foundation API) but haven't ported it to the w5500 yet. It should fit just fine on the G2553, as it basically reads & writes packets "piecemeal" leaning on the socket buffer for space. There's really nothing special about any of these protocols, they can all be done with limited SRAM so long as you can write packet data "piecemeal" a header/subcomponent of the packet at a time and only commit (Sn_CR=SEND) the whole packet when you're done. I have DNS A-record lookups working the same way. Quote Link to post Share on other sites
spirilis 1,265 Posted April 3, 2014 Share Posted April 3, 2014 @@RobG Reading your code and then the datasheet, am I right in saying that WizNet finally did away with the user-exposed ring-buffer math? Looks like it does the ring-buffer math for you now by having you issue a 16-bit offset and then using the "control" byte to select which buffer... If that's the case then !@#!$@!$#@#@!HALLELUJAH!!! I can't tell you how much code I have written to maintain that ring-buffer math in the W5200 :-) My library is notably FAT compared to yours, as it tries to manage everything plus the kitchen sink for the user, so I might just play with yours a bit and see if I can port my dhcplib and dnslib over. If there's anything else I need to add to make my "way of working" operate, I'll add it to w5500.c/.h. (unfortunately not working on this today as I don't have my W5500 with me...) Quote Link to post Share on other sites
spirilis 1,265 Posted April 4, 2014 Share Posted April 4, 2014 Awfully close to hitting the mark with this dhcp library... but I keep bumping into what I think is stack overrunning BSS, so stuff gets messed up. Will have to hack on it some more and see if there's a way I can consolidate a lot of memory usage. Plus I have a hacked up sprintf in use for debugging, so I can probably consolidate that down into a printf function that just bangs the UART one byte at a time so I don't need an 80-byte buffer hanging around... RobG 1 Quote Link to post Share on other sites
spirilis 1,265 Posted April 7, 2014 Share Posted April 7, 2014 It only took me most of a day to figure out that ... Yes, DHCP packets are to be sent to 255.255.255.255, not 0.0.0.0. Whoops. Anyway, RobG's code sufficiently doctored up and running DHCP on an MSP430G2553: Beginning: Waiting for PHY: PHY up dhcp_loop_configure(): Sending DHCPDISCOVER dhcp_send_dhcpdiscover(): Our MAC = 00:08:DC:04:03:00 dhcp_loop_configure(): Waiting for DHCPOFFER dhcp_loop_configure(): Packet received dhcp_loop_configure(): SrcPort = 67, PktLen = 300, RXrecv = 308 dhcp_read_header(): Initial header: OP=2, HTYPE=1, HLEN=6, HOPS=0 dhcp_read_header(): Read XID: 3903F326 dhcp_read_header(): SECS=0000, FLAGS=0000 dhcp_read_option(): optcode=53, optlen=1, maxlen=8 dhcp_loop_configure(): Packet is DHCPOFFER dhcp_loop_configure(): DHCP server gave us IP address 10.104.115.41 dhcp_read_option(): optcode=1, optlen=4, maxlen=8 dhcp_loop_configure(): subnetmask: 255.255.255.0 dhcp_read_option(): optcode=58, optlen=4, maxlen=8 dhcp_read_option(): optcode=59, optlen=4, maxlen=8 dhcp_read_option(): optcode=51, optlen=4, maxlen=8 dhcp_read_option(): optcode=54, optlen=4, maxlen=8 dhcp_loop_configure(): DHCP server: 10.104.8.201 dhcp_read_option(): optcode=3, optlen=4, maxlen=8 dhcp_loop_configure(): gateway: 10.104.115.1 dhcp_read_option(): optcode=6, optlen=8, maxlen=8 dhcp_loop_configure(): DNS server: 10.104.8.201 (2 in total) dhcp_read_option(): optcode=255, optlen=0, maxlen=8 dhcp_loop_configure(): Sending DHCPREQUEST to 10.104.8.201 requesting IP=10.104.115.41 dhcp_send_dhcprequest(): Our MAC = 00:08:DC:04:03:00 dhcp_loop_configure(): Waiting for DHCPACK dhcp_loop_configure(): Packet received dhcp_loop_configure(): SrcPort = 67, PktLen = 300, RXrecv = 308 dhcp_read_header(): Initial header: OP=2, HTYPE=1, HLEN=6, HOPS=0 dhcp_read_header(): Read XID: 3903F326 dhcp_read_header(): SECS=0000, FLAGS=0000 dhcp_read_option(): optcode=53, optlen=1, maxlen=8 dhcp_loop_configure(): Packet is DHCPACK dhcp_read_option(): optcode=58, optlen=4, maxlen=8 dhcp_read_option(): optcode=59, optlen=4, maxlen=8 dhcp_read_option(): optcode=51, optlen=4, maxlen=8 dhcp_read_option(): optcode=54, optlen=4, maxlen=8 dhcp_loop_configure(): DHCP server: 10.104.8.201 dhcp_read_option(): optcode=1, optlen=4, maxlen=8 dhcp_read_option(): optcode=255, optlen=0, maxlen=8 dhcp_loop_configure(): DHCPACK contents processed; validating dhcp_loop_configure(): Configuring WizNet IP settings ... [ebrundic@spock ~]$ ping 10.104.115.41 PING 10.104.115.41 (10.104.115.41) 56(84) bytes of data. 64 bytes from 10.104.115.41: icmp_seq=1 ttl=128 time=0.444 ms 64 bytes from 10.104.115.41: icmp_seq=2 ttl=128 time=0.275 ms 64 bytes from 10.104.115.41: icmp_seq=3 ttl=128 time=0.227 ms ^C --- 10.104.115.41 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.227/0.315/0.444/0.094 ms Code needs some touchups & cleanup, and then it can be compacted down a bit more to save on flash..... I'm using a rather bastardized variable setup here, as the main function allocates a 34-byte uint8_t array and passes it around to the various subfunctions so they can use & reuse some of the space; I've mentally kept track of the code logic so I know which parts can be reused at the different phases, and I believe it to be stable ;-) It will gracefully handle incoming messages that are not destined for it, too, and precisely skip past just those packets in case another (valid or not) UDP packet is waiting in the buffer for us to process (i.e. the code doesn't haphazardly just clear the whole RX buffer when it finds any mismatches in the data). TODO: Report back the DHCP lease time, and provide a comparable function that can perform a simple lease update at the user's discretion. dubnet and RobG 2 Quote Link to post Share on other sites
spirilis 1,265 Posted April 7, 2014 Share Posted April 7, 2014 Ok, my totally reworked version of RobG's G2553 example. A number of changes have occurred here to Rob's core code: 1. Some minor bugs in the Sn_IMR macros in w5500.h were fixed (although I don't use them) 2. A "piecemeal I/O" infrastructure has been added- BSS bloated by 32 bytes as we now track a local copy of the RX_RD and TX_WR variables, since these variables can be written to but not read back; reading back their values actually gives us the original values, until Sn_CR_RECV or Sn_CR_SEND respectively are submitted; the whole idea behind this "piecemeal I/O" is that we're not doing this, we don't want the buffers to change yet. u_int _tx_wr_cache[8], _rx_rd_cache[8]; /* Used for "piecemeal" writes & reads when * we update TX_WR or RX_RD but the WizNet still * gives us the old value until we perform a CR * command action on the socket. */ A pair of functions update this value for a specified socket: void refreshTXBufferCache(u_char s); void refreshRXBufferCache(u_char s); For the most part you don't have to worry about it, as I've peppered those calls inside the existing stuff like socket() et al. But do know that if you submit an Sn_CR_SEND or Sn_CR_RECV yourself, you may want to update the internal "state" of those cached variables if you happen to be using the Piecemeal I/O functions. The piecemeal I/O functions consist of: void writeToTXBufferPiecemeal(u_char s, u_char* array, u_int length); void fillTXBufferPiecemeal(u_char s, u_char value, u_int length); void readFromRXBufferPiecemeal(u_char s, u_char* array, u_int length); void flushRXBufferPiecemeal(u_char s, u_int length); // u_int getTXVirtualFreeSize(u_char s); u_int getVirtualRXReceived(u_char s); writeToTXBufferPiecemeal writes the specified array of length bytes to the buffer, updates TX_WR both on the chip and in the local cache, but does not send the data just yet. It always starts writing from the current value of the "local cached copy" of TX_WR, so that you can continuously append to the buffer without committing the packet. fillTXBufferPiecemeal is similar, but it writes a single byte length # of times. I added a fillMemoryArray() call likewise to support that. readFromRXBufferPiecemeal is as you'd expect... it reads those bytes, updates Sn_RX_RD and a local cached copy of it. Further reads from that use the local cached copy of RX_RD as the address to start from. flushRXBufferPiecemeal merely advances RX_RD without reading; advancing the "local cached copy" likewise. getTXVirtualFreeSize computes the "amount of free space available" using the chip's copy of TX_RD and our local cached copy of TX_WR. getVirtualRXReceived computes the "amount of unread data" using the chip's copy of RX_WR and our local cached copy of RX_RD. Also to make it feel more unix-y, I've added these: u_int ntohs(u_char *array); void htons(u_int val, u_char *array); which are used extensively within the DHCP code. There is a printf-style debugging infrastructure used extensively throughout the dhcplib code, and you can use it in your own software as well. See wizdebug.c and wizdebug.h. It has a hierarchical "debug level" of aliases called wiznet_debugN_printf() where N goes from 1 to 6, and if the WIZNET_DEBUG #define is less than N, that function is #define'd away as a simple ";", with WIZNET_DEBUG 0 removing it entirely. From wizdebug.h: /* Debug levels: * 1 - Basic information from libraries * 2 - Error reporting from libraries * 3 - Gratuitous information from libraries * 4 - Pedantic information from libraries * 5 - Extraneous detail from base socket library * 6 - Low-level I/O dump from SPI transfer functions * * Each debug level includes information from all levels below. */ #define WIZNET_DEBUG 4 void wiznet_debug_init(); void wiznet_debug_printf(char *format, ...); void wiznet_debug_putc(unsigned int); void wiznet_debug_puts(const char *); #if WIZNET_DEBUG > 0 #define wiznet_debug1_printf(...) wiznet_debug_printf(__VA_ARGS__) #else #define wiznet_debug1_printf(...) ; #endif #if WIZNET_DEBUG > 1 #define wiznet_debug2_printf(...) wiznet_debug_printf(__VA_ARGS__) #else #define wiznet_debug2_printf(...) ; #endif #if WIZNET_DEBUG > 2 #define wiznet_debug3_printf(...) wiznet_debug_printf(__VA_ARGS__) #else #define wiznet_debug3_printf(...) ; #endif (etc and so forth) You may want to inspect wiznet_debug_init() in wizdebug.c to make sure it supports your UART or other peripheral correctly. Likewise, the source is all there, you can change it to spit the data out over SPI or I2C or whatever if you'd like. The printf function is based on @@oPossum 's code... minor addition is a "%h" type exists to print 8-bit hex only, whereas "%x" does 16-bit hex. The '\n' char is expanded to '\r\n' for UART use; see the bottom of wiznet_debug_printf() for that code, which can be changed. Also note that none of this has been tested on CCS yet, so I'll be looking for folks to try it out. Ok... DHCP library. dhcplib.h has a tunable: /* User-tunable options. */ #define DHCP_LOOP_COUNT_TIMEOUT 500 The main while() loop in dhcp_loop_configure() does a _delay_cycles(250000) if nothing else is happening, and it will time out after DHCP_LOOP_COUNT_TIMEOUT iterations. The dhcp library has one simple function for the user to call: int dhcp_loop_configure(uint8_t *); // Perform DHCP configuration, optionally reporting back DNS server The uint8_t * pointer argument is a user-supplied buffer where 4 bytes will be written containing the first DNS server entry reported by the DHCP server; if this argument is NULL ( (uint8_t *)0x0000 ), the DNS server info will be ignored. If this function returns -1 (0 = success, -1 = error), an extern global called "dhcplib_errno" may be analyzed to discover the cause; a function: char *dhcp_strerror(int); // Return descriptive string of dhcplib_errno value has been provided to interpret this, passing a "char *" casted pointer to a const char string declared inside dhcplib.c. If dhcp_loop_configure returns successful (return value = 0), then your IP, subnetmask and gateway will be automatically configured in the WizNet's system registers. Also, the code currently has socket #7 hardcoded as a #define in dhcplib.h Code: robg-w5500-with-dhcplib.zip RobG, bluehash, 4jochen and 3 others 6 Quote Link to post Share on other sites
RobG 1,892 Posted April 7, 2014 Author Share Posted April 7, 2014 One word, awesome! spirilis 1 Quote Link to post Share on other sites
bluehash 1,581 Posted April 8, 2014 Share Posted April 8, 2014 One word, awesome! No kidding!. Thanks @@spirilis! Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.