-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathethernet.rs
168 lines (138 loc) · 5.11 KB
/
ethernet.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_parens)]
#![allow(unused_variables)]
#![no_main]
#![no_std]
use cortex_m;
use cortex_m_rt::entry;
use nucleo::loggit;
use nucleo_h7xx as nucleo;
use hal::gpio::Speed::*;
use hal::hal::digital::v2::OutputPin;
use hal::hal::digital::v2::ToggleableOutputPin;
use hal::prelude::*;
use hal::rcc::CoreClocks;
use hal::{ethernet, ethernet::PHY};
use nucleo::hal;
use hal::pac;
use pac::interrupt;
use smoltcp;
use smoltcp::iface::{Interface, InterfaceBuilder, Neighbor, NeighborCache, Route, Routes};
use smoltcp::socket::{UdpPacketMetadata, UdpSocket, UdpSocketBuffer};
use smoltcp::storage::PacketMetadata;
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address, Ipv6Cidr};
use log::{debug, error, info};
/// Simple ethernet example that will respond to icmp pings on
/// `IP_LOCAL` and periodically send a udp packet to
/// `IP_REMOTE:IP_REMOTE_PORT`
///
/// You can start a simple listening server with netcat:
///
/// nc -u -l 34254
const MAC_LOCAL: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
const IP_LOCAL: [u8; 4] = [192, 168, 20, 99];
const IP_REMOTE: [u8; 4] = [192, 168, 20, 207];
const IP_REMOTE_PORT: u16 = 34254;
mod utilities;
#[entry]
fn main() -> ! {
// - endpoints ------------------------------------------------------------
let local_endpoint = IpEndpoint::new(Ipv4Address::from_bytes(&IP_LOCAL).into(), 1234);
let remote_endpoint =
IpEndpoint::new(Ipv4Address::from_bytes(&IP_REMOTE).into(), IP_REMOTE_PORT);
// - board setup ----------------------------------------------------------
info!("Setting up board");
let board = nucleo::Board::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let ccdr = board.freeze_clocks(dp.PWR.constrain(), dp.RCC.constrain(), &dp.SYSCFG);
let pins = board.split_gpios(
dp.GPIOA.split(ccdr.peripheral.GPIOA),
dp.GPIOB.split(ccdr.peripheral.GPIOB),
dp.GPIOC.split(ccdr.peripheral.GPIOC),
dp.GPIOD.split(ccdr.peripheral.GPIOD),
dp.GPIOE.split(ccdr.peripheral.GPIOE),
dp.GPIOF.split(ccdr.peripheral.GPIOF),
dp.GPIOG.split(ccdr.peripheral.GPIOG),
);
utilities::logger::init();
// - ethernet interface ---------------------------------------------------
info!("Bringing up ethernet interface");
let timeout_timer = dp
.TIM17
.timer(100.Hz(), ccdr.peripheral.TIM17, &ccdr.clocks);
let timeout_timer = nucleo::timer::CountDownTimer::new(timeout_timer);
let timeout_timer = match nucleo::ethernet::EthernetInterface::start(
pins.ethernet,
&MAC_LOCAL,
&IP_LOCAL,
ccdr.peripheral.ETH1MAC,
&ccdr.clocks,
timeout_timer,
) {
Ok(tim17) => tim17,
Err(e) => {
error!("Failed to start ethernet interface: {:?}", e);
loop {}
}
};
// wait for link to come up
info!("Waiting for link to come up");
nucleo::ethernet::EthernetInterface::interrupt_free(
|ethernet_interface| {
while !ethernet_interface.poll_link() {}
},
);
// create and bind socket
let socket_handle = nucleo::ethernet::EthernetInterface::interrupt_free(|ethernet_interface| {
let socket_handle = ethernet_interface.new_udp_socket();
let socket = ethernet_interface
.interface
.as_mut()
.unwrap()
.get_socket::<UdpSocket>(socket_handle);
match socket.bind(local_endpoint) {
Ok(()) => return socket_handle,
Err(e) => {
error!("Failed to bind socket to endpoint: {:?}", local_endpoint);
loop {}
}
}
});
// - main loop ------------------------------------------------------------
info!("Entering main loop");
let mut last = 0;
loop {
cortex_m::asm::wfi();
// poll ethernet interface
let now = nucleo::ethernet::EthernetInterface::interrupt_free(|ethernet_interface| {
match ethernet_interface.poll() {
Ok(result) => {} // packets were processed or emitted
Err(smoltcp::Error::Exhausted) => (),
Err(smoltcp::Error::Unrecognized) => (),
Err(e) => debug!("ethernet::EthernetInterface.poll() -> {:?}", e),
}
ethernet_interface.now()
});
// check if it has been 5 seconds since we last sent something
if (now - last) < 5000 {
continue;
} else {
last = now;
}
// send something
nucleo::ethernet::EthernetInterface::interrupt_free(|ethernet_interface| {
let socket = ethernet_interface
.interface
.as_mut()
.unwrap()
.get_socket::<UdpSocket>(socket_handle);
match socket.send_slice("nucleo says hello!\n".as_bytes(), remote_endpoint) {
Ok(()) => (),
Err(smoltcp::Error::Exhausted) => (),
Err(e) => error!("UdpSocket::send error: {:?}", e),
};
});
}
}