Skip to content

Conversation

@nickzoic
Copy link

@nickzoic nickzoic commented Oct 4, 2018

This is an implementation of #703 ... porting WizNet 5200/5500 support across from MicroPython.
Tested on Metro M0 Express and Metro M4 Express with WizNet 5500 FeatherWing.

There's no particular reason this shouldn't be adaptable for other architectures which support SPI.

This particular version doesn't use LWIP as that used up too much memory for use with M0. Instead it uses the WizNet native mode which imposes some limitations but reduces demand on the main CPU.

Example code (updated for dhcp and connected property):

import board
import busio
import wiznet

spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)
eth = wiznet.WIZNET5K(spi, board.D10, board.D11)
eth.connected

host = 'example.com'
import socket
fam, typ, pro, nam, sockaddr = socket.getaddrinfo(host, 80)[0]
ss = socket.socket(fam, typ, pro)
ss.connect(sockaddr)
ss.send("GET / HTTP/1.0\nHost: %s\n\n" % host)
print(ss.recv(1024))
ss.close()

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! I'm excited to see the progress.

Looks like a docs pass is need in addition to a bit of refactoring. You can test the docs locally with:

pip install 'Sphinx<1.8.0' sphinx-rtd-theme recommonmark
sphinx-build -E -W -b html . _build/html

You don't need a new PR to push new changes. Any changes to the PRs branch will be reflect on the PR.

Thanks!

}

/******************************************************************************/
// MicroPython bindings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the argument parsing done below should be in this file. The above should go in shared-module. Please also document everything below with the //| rst style so it appears in sphinx.

//| :synopsis: TCP, UDP and RAW sockets
//| :platform: SAMD21, SAMD51
//|
//| XXX TODO Write Docs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now is the time. :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed :-)

} u_param;
mp_uint_t u_state;
};
} mod_network_socket_obj_t;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These structs should go into shared-module as well. This header should only extern it. It should also declare any functions called.

This is done to mirror the common-hal structure where each port actually implements the struct and methods.

}

void network_module_deinit(void) {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These go in shared-module as well because they are C API.


STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
{ MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this useful for? Can we omit the network module for now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The network module maintains a registry of nics, and when you configure a nic (eg: construct it with wiznet.WIZNET5K()) it calls network_module_register_nic to add that nic to the list. When you call socket.socket() it calls network_module_find_nic to find an appropriate nic for this socket.

This functionality could be merged into the socket module I suppose.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... in MicroPython, the network module also collects all the network device classes in one place (they're not all compiled in, you can control that with various MICROPY_PY_WHATEVER flags)

I've split WIZNET5K out into its own 'wiznet' module, but I'm not sure that once we have a few of these we wouldn't be better collecting them into 'network' after all ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think network is the way to go. I don't want extra stuff in socket.

Is it useful from Python though? Maybe it should be an internal only concept for now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in MicroPython it exposes the nic classes. In CircuitPython all it has left is 'network.route' which lets you enumerate all the configured nics, eg:

>>> network.route()[0].ifconfig()
('10.107.1.123', '255.255.255.0', '10.107.1.1', '0.0.0.0')

not necessarily very useful

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making it internal only for now?

uint8_t sn_size[16] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 2k buffer for each socket
ctlwizchip(CW_INIT_WIZCHIP, sn_size);

// set some sensible default values; they are configurable using ifconfig method
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we default to DHCP instead? My guess is that will be much more common. Maybe take ip, netmask, gateway and dns as kwargs instead in case static allocation is wanted instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if you'd rather.

}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs);

STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets have a .connected property instead since its state.

{ MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) },
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) },
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class related functions should go into a separate file (WIZNET5K.c in this case) to make it easier to find.


/// \method ifconfig([(ip, subnet, gateway, dns)])
/// Get/set IP address, subnet mask, gateway and DNS.
STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding properties for each of these four attributes? Do they all need to be set at the once? If not, they can be read/write. Otherwise they can be read-only.

If they all need to be set at once, can we switch to a method that takes kwargs so each ip is labeled with what it is?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, they're all set together. It'd make sense for these to be kwargs I agree, it does make the code more readable.

@tannewt tannewt added this to the Long term milestone Oct 4, 2018
@nickzoic
Copy link
Author

nickzoic commented Oct 9, 2018

(note that while the docs build, they're not actually filled in yet. Also, we need to exclude the smallest M0 boards from using this option ... not sure how you want to handle that.

@tannewt
Copy link
Member

tannewt commented Oct 9, 2018

I think we'll need to enable MICROPY_PY_NETWORK and MICROPY_PY_WIZNET5K on a board-by-board basis in mpconfigboard.mk since the express builds with lots frozen in are failing. Any idea how much extra space it takes? Maybe we can get them to fit too.

@nickzoic
Copy link
Author

nickzoic commented Oct 11, 2018

I think we'll need to enable MICROPY_PY_NETWORK and MICROPY_PY_WIZNET5K on a board-by-board basis in mpconfigboard.mk since the express builds with lots frozen in are failing. Any idea how much extra space it takes? Maybe we can get them to fit too.

metro_m4_express build without:

276436 bytes free in flash out of 499712 bytes ( 488.0 kb ).
180088 bytes free in ram for stack out of 196608 bytes ( 192.0 kb ).

metro_m4_express build with:

265492 bytes free in flash out of 499712 bytes ( 488.0 kb ).
179892 bytes free in ram for stack out of 196608 bytes ( 192.0 kb ).

hallowing_m0_express build without:

3724 bytes free in flash out of 253696 bytes ( 247.75 kb ).
24216 bytes free in ram for stack out of 32768 bytes ( 32.0 kb ).

hallowing_m0_express build with network:

region `FLASH' overflowed by 5772 bytes

... in general, I suspect this module will be useful to only a few people ... and if we also add support for, say, the ATWINC1500 and similar then that's even more ... I think it'd be worth considering how we could have a more flexible build system so that these modules are more easily optional.

@nickzoic
Copy link
Author

nickzoic commented Oct 11, 2018 via email

@tannewt
Copy link
Member

tannewt commented Oct 12, 2018

My worry with having all of them under one module is that we won't be able to pick and choose which to have in particular builds. We've already set a guideline that feature availability is done at the module level instead of the class level. If we have it under network then we'd need to have them all there.

I think we'll add more under network in the future so we could also just leave it.

1 similar comment
@tannewt
Copy link
Member

tannewt commented Oct 12, 2018

My worry with having all of them under one module is that we won't be able to pick and choose which to have in particular builds. We've already set a guideline that feature availability is done at the module level instead of the class level. If we have it under network then we'd need to have them all there.

I think we'll add more under network in the future so we could also just leave it.

@nickzoic
Copy link
Author

nickzoic commented Oct 12, 2018 via email

DHCP_time_handler();
int dhcp_state = DHCP_run();
if (dhcp_state == DHCP_IP_LEASED || dhcp_state == DHCP_IP_CHANGED) break;
mp_hal_delay_ms(1000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the construction of the object really slow when not plugged in. Can we do one try in the constructor and one each time the other APIs are called?

@nickzoic
Copy link
Author

nickzoic commented Oct 16, 2018 via email

@tannewt
Copy link
Member

tannewt commented Oct 16, 2018

Do you mind doing it now?

If not, can the loop at least check for a CTRL-C? I noticed it when trying to ctrl-c and it not responding.

@nickzoic
Copy link
Author

nickzoic commented Oct 17, 2018 via email

@tannewt
Copy link
Member

tannewt commented Oct 17, 2018

Yup! Using the background tasks to drive dhcp makes sense to me. Please merge it in.

@nickzoic
Copy link
Author

(this has been held up by my day job, for reasons which are incomprehensible to anyone not following Australian politics. I'll get on with it soon.)

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!!

@tannewt tannewt merged commit fd89cdd into adafruit:master Oct 25, 2018
@gvcp
Copy link

gvcp commented Mar 19, 2019

tried to use the W5500 feather wing with a Feather M4 Express (great combination, pin compatible and allow piggypacking) with CP4 beta 5 but only with partial success:
connected, ifconfig(), socket.socket, connect seems to work, get a connection to a server socket, but when I try to send something it results in I/O errors, close doesn´t result in an error but socket isn´t really closed.

@notro
Copy link

notro commented Mar 19, 2019

I had a similar problem (which I gave up on): #1500 (comment)

@nickzoic
Copy link
Author

nickzoic commented Mar 20, 2019 via email

@gvcp
Copy link

gvcp commented Apr 15, 2019

is there any chance that the wiznet ethernet wing will work with the feather M4 express in the final CP4 release ? the last time I tried it was with CP4 beta6 which still gave an IO error on send when done from REPL. when executing the sequence from a file it hanged and couldn´t be aborted via ctrl C.

@dhalbert
Copy link
Collaborator

@gvcp Please open an issue if something about Ethernet isn't working. Include your program and other details. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants