123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- //! ENC28J60 demo: pong server + UDP echo server
- //!
- //! This program:
- //!
- //! - Responds to ARP requests
- //! - Responds to ICMP echo requests, thus you can `ping` the device
- //! - Responds to *all* UDP datagrams by sending them back
- //!
- //! You can test this program by running the following commands:
- //!
- //! - `ping 192.168.1.33`. The device should respond and toggle the state of the LED on every `ping`
- //! request.
- //! - `nc -u 192.168.1.33 1337` and sending any string. The device should respond back by sending
- //! back the received string; the LED will toggle each time a UDP datagram is sent.
- #![deny(unsafe_code)]
- #![deny(warnings)]
- #![feature(nll)]
- #![no_std]
- #![no_main]
- extern crate cortex_m_rt as rt;
- #[macro_use]
- extern crate cortex_m;
- extern crate enc28j60;
- extern crate heapless;
- extern crate jnet;
- extern crate panic_itm;
- extern crate stm32f1xx_hal as hal;
- use enc28j60::Enc28j60;
- use hal::delay::Delay;
- use hal::prelude::*;
- use hal::spi::Spi;
- use hal::stm32f103xx;
- use heapless::consts::*;
- use heapless::FnvIndexMap;
- use jnet::{arp, ether, icmp, ipv4, mac, udp, Buffer};
- use rt::{entry, exception, ExceptionFrame};
- // uncomment to disable tracing
- // macro_rules! iprintln {
- // ($($tt: tt)*) => {};
- // }
- /* Configuration */
- const MAC: mac::Addr = mac::Addr([0x20, 0x18, 0x03, 0x01, 0x00, 0x00]);
- const IP: ipv4::Addr = ipv4::Addr([192, 168, 1, 33]);
- /* Constants */
- const KB: u16 = 1024; // bytes
- #[entry]
- fn main() -> ! {
- let mut cp = cortex_m::Peripherals::take().unwrap();
- let dp = stm32f103xx::Peripherals::take().unwrap();
- let mut rcc = dp.RCC.constrain();
- let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
- let mut flash = dp.FLASH.constrain();
- let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
- let _stim = &mut cp.ITM.stim[0];
- let clocks = rcc.cfgr.freeze(&mut flash.acr);
- cp.DWT.enable_cycle_counter();
- // LED
- let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
- let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
- // turn the LED off during initialization
- led.set_high();
- // SPI
- let mut ncs = gpioa.pa4.into_push_pull_output(&mut gpioa.crl);
- ncs.set_high();
- let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl);
- let miso = gpioa.pa6;
- let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl);
- let spi = Spi::spi1(
- dp.SPI1,
- (sck, miso, mosi),
- &mut afio.mapr,
- enc28j60::MODE,
- 1.mhz(),
- clocks,
- &mut rcc.apb2,
- );
- // ENC28J60
- let mut reset = gpioa.pa3.into_push_pull_output(&mut gpioa.crl);
- reset.set_high();
- let mut delay = Delay::new(cp.SYST, clocks);
- let mut enc28j60 = Enc28j60::new(
- spi,
- ncs,
- enc28j60::Unconnected,
- reset,
- &mut delay,
- 7 * KB,
- MAC.0,
- )
- .ok()
- .unwrap();
- // LED on after initialization
- led.set_low();
- // FIXME some frames are lost when sent right after initialization
- delay.delay_ms(100_u8);
- // ARP cache
- let mut cache = FnvIndexMap::<_, _, U8>::new();
- let mut buf = [0; 256];
- loop {
- let mut buf = Buffer::new(&mut buf);
- let len = enc28j60.receive(buf.as_mut()).ok().unwrap();
- buf.truncate(len);
- if let Ok(mut eth) = ether::Frame::parse(buf) {
- iprintln!(_stim, "\nRx({})", eth.as_bytes().len());
- iprintln!(_stim, "* {:?}", eth);
- let src_mac = eth.get_source();
- match eth.get_type() {
- ether::Type::Arp => {
- if let Ok(arp) = arp::Packet::parse(eth.payload_mut()) {
- match arp.downcast() {
- Ok(mut arp) => {
- iprintln!(_stim, "** {:?}", arp);
- if !arp.is_a_probe() {
- cache.insert(arp.get_spa(), arp.get_sha()).ok();
- }
- // are they asking for us?
- if arp.get_oper() == arp::Operation::Request && arp.get_tpa() == IP
- {
- // reply to the ARP request
- let tha = arp.get_sha();
- let tpa = arp.get_spa();
- arp.set_oper(arp::Operation::Reply);
- arp.set_sha(MAC);
- arp.set_spa(IP);
- arp.set_tha(tha);
- arp.set_tpa(tpa);
- iprintln!(_stim, "\n** {:?}", arp);
- let arp_len = arp.len();
- // update the Ethernet header
- eth.set_destination(tha);
- eth.set_source(MAC);
- eth.truncate(arp_len);
- iprintln!(_stim, "* {:?}", eth);
- iprintln!(_stim, "Tx({})", eth.as_bytes().len());
- enc28j60.transmit(eth.as_bytes()).ok().unwrap();
- }
- }
- Err(_arp) => {
- // Not a Ethernet/IPv4 ARP packet
- iprintln!(_stim, "** {:?}", _arp);
- }
- }
- } else {
- // malformed ARP packet
- iprintln!(_stim, "Err(A)");
- }
- }
- ether::Type::Ipv4 => {
- if let Ok(mut ip) = ipv4::Packet::parse(eth.payload_mut()) {
- iprintln!(_stim, "** {:?}", ip);
- let src_ip = ip.get_source();
- if !src_mac.is_broadcast() {
- cache.insert(src_ip, src_mac).ok();
- }
- match ip.get_protocol() {
- ipv4::Protocol::Icmp => {
- if let Ok(icmp) = icmp::Packet::parse(ip.payload_mut()) {
- match icmp.downcast::<icmp::EchoRequest>() {
- Ok(request) => {
- // is an echo request
- iprintln!(_stim, "*** {:?}", request);
- let src_mac = cache
- .get(&src_ip)
- .unwrap_or_else(|| unimplemented!());
- let _reply: icmp::Packet<_, icmp::EchoReply, _> =
- request.into();
- iprintln!(_stim, "\n*** {:?}", _reply);
- // update the IP header
- let mut ip = ip.set_source(IP);
- ip.set_destination(src_ip);
- let _ip = ip.update_checksum();
- iprintln!(_stim, "** {:?}", _ip);
- // update the Ethernet header
- eth.set_destination(*src_mac);
- eth.set_source(MAC);
- iprintln!(_stim, "* {:?}", eth);
- led.toggle();
- iprintln!(_stim, "Tx({})", eth.as_bytes().len());
- enc28j60.transmit(eth.as_bytes()).ok().unwrap();
- }
- Err(_icmp) => {
- iprintln!(_stim, "*** {:?}", _icmp);
- }
- }
- } else {
- // Malformed ICMP packet
- iprintln!(_stim, "Err(B)");
- }
- }
- ipv4::Protocol::Udp => {
- if let Ok(mut udp) = udp::Packet::parse(ip.payload_mut()) {
- iprintln!(_stim, "*** {:?}", udp);
- if let Some(src_mac) = cache.get(&src_ip) {
- let src_port = udp.get_source();
- let dst_port = udp.get_destination();
- // update the UDP header
- udp.set_source(dst_port);
- udp.set_destination(src_port);
- udp.zero_checksum();
- iprintln!(_stim, "\n*** {:?}", udp);
- // update the IP header
- let mut ip = ip.set_source(IP);
- ip.set_destination(src_ip);
- let ip = ip.update_checksum();
- let ip_len = ip.len();
- iprintln!(_stim, "** {:?}", ip);
- // update the Ethernet header
- eth.set_destination(*src_mac);
- eth.set_source(MAC);
- eth.truncate(ip_len);
- iprintln!(_stim, "* {:?}", eth);
- led.toggle();
- iprintln!(_stim, "Tx({})", eth.as_bytes().len());
- enc28j60.transmit(eth.as_bytes()).ok().unwrap();
- }
- } else {
- // malformed UDP packet
- iprintln!(_stim, "Err(C)");
- }
- }
- _ => {}
- }
- } else {
- // malformed IPv4 packet
- iprintln!(_stim, "Err(D)");
- }
- }
- _ => {}
- }
- } else {
- // malformed Ethernet frame
- iprintln!(_stim, "Err(E)");
- }
- }
- }
- #[exception]
- fn HardFault(ef: &ExceptionFrame) -> ! {
- panic!("{:#?}", ef);
- }
- #[exception]
- fn DefaultHandler(irqn: i16) {
- panic!("Unhandled exception (IRQn = {})", irqn);
- }
|