enc28j60-coap.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //! ENC28J60 demo: a RESTful LED using CoAP
  2. //!
  3. //! The server will expose the LED as a resource under the `/led` path. You can use the CoAP client
  4. //! in the [`jnet`] crate to interact with the server.
  5. //!
  6. //! - `coap GET coap://192.168.1.33/led` will return the state of the LED: either "on" or "off".
  7. //! - `coap PUT coap://192.168.1.33/led on` will change the state of the LED; the payload must be
  8. //! either "on" or "off".
  9. //!
  10. //! [`jnet`]: https://github.com/japaric/jnet
  11. #![deny(unsafe_code)]
  12. #![deny(warnings)]
  13. #![feature(nll)]
  14. #![feature(try_from)]
  15. #![no_main]
  16. #![no_std]
  17. #[macro_use]
  18. extern crate cortex_m;
  19. extern crate cortex_m_rt as rt;
  20. extern crate enc28j60;
  21. extern crate heapless;
  22. extern crate jnet;
  23. extern crate panic_itm;
  24. #[macro_use]
  25. extern crate serde_derive;
  26. extern crate serde_json_core as json;
  27. extern crate stm32f1xx_hal as hal;
  28. use core::convert::TryInto;
  29. use enc28j60::Enc28j60;
  30. use hal::delay::Delay;
  31. use hal::prelude::*;
  32. use hal::spi::Spi;
  33. use hal::stm32f103xx;
  34. use heapless::consts::*;
  35. use heapless::FnvIndexMap;
  36. use jnet::{arp, coap, ether, icmp, ipv4, mac, udp, Buffer};
  37. use rt::{entry, exception, ExceptionFrame};
  38. /* Constants */
  39. const KB: u16 = 1024;
  40. /* Network configuration */
  41. const MAC: mac::Addr = mac::Addr([0x20, 0x18, 0x03, 0x01, 0x00, 0x00]);
  42. const IP: ipv4::Addr = ipv4::Addr([192, 168, 1, 33]);
  43. // disable tracing
  44. // macro_rules! iprintln {
  45. // ($($tt: tt)*) => {};
  46. // }
  47. // LED resource
  48. #[derive(Deserialize, Serialize)]
  49. struct Led {
  50. led: bool,
  51. }
  52. #[entry]
  53. fn main() -> ! {
  54. let mut cp = cortex_m::Peripherals::take().unwrap();
  55. let dp = stm32f103xx::Peripherals::take().unwrap();
  56. let mut rcc = dp.RCC.constrain();
  57. let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
  58. let mut flash = dp.FLASH.constrain();
  59. let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
  60. let _stim = &mut cp.ITM.stim[0];
  61. let clocks = rcc.cfgr.freeze(&mut flash.acr);
  62. // LED
  63. let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
  64. let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
  65. // turn the LED off during initialization
  66. led.set_high();
  67. // SPI
  68. let mut rst = gpioa.pa3.into_push_pull_output(&mut gpioa.crl);
  69. rst.set_high();
  70. let mut ncs = gpioa.pa4.into_push_pull_output(&mut gpioa.crl);
  71. ncs.set_high();
  72. let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl);
  73. let miso = gpioa.pa6;
  74. let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl);
  75. let spi = Spi::spi1(
  76. dp.SPI1,
  77. (sck, miso, mosi),
  78. &mut afio.mapr,
  79. enc28j60::MODE,
  80. 1.mhz(),
  81. clocks,
  82. &mut rcc.apb2,
  83. );
  84. // ENC28J60
  85. let mut delay = Delay::new(cp.SYST, clocks);
  86. let mut enc28j60 = Enc28j60::new(
  87. spi,
  88. ncs,
  89. enc28j60::Unconnected,
  90. rst,
  91. &mut delay,
  92. 7 * KB,
  93. MAC.0,
  94. )
  95. .ok()
  96. .unwrap();
  97. // LED on after initialization
  98. led.set_low();
  99. // FIXME some frames are lost when sending right after initialization
  100. delay.delay_ms(100_u8);
  101. let mut cache = FnvIndexMap::<_, _, U8>::new();
  102. let mut buf = [0; 128];
  103. loop {
  104. let mut buf = Buffer::new(&mut buf);
  105. let len = enc28j60.receive(buf.as_mut()).ok().unwrap();
  106. buf.truncate(len);
  107. if let Ok(mut eth) = ether::Frame::parse(buf) {
  108. iprintln!(_stim, "\nRx({})", eth.as_bytes().len());
  109. iprintln!(_stim, "* {:?}", eth);
  110. let mac_src = eth.get_source();
  111. match eth.get_type() {
  112. ether::Type::Arp => {
  113. if let Ok(arp) = arp::Packet::parse(eth.payload_mut()) {
  114. match arp.downcast() {
  115. Ok(mut arp) => {
  116. iprintln!(_stim, "** {:?}", arp);
  117. if !arp.is_a_probe() {
  118. cache.insert(arp.get_spa(), arp.get_sha()).ok();
  119. }
  120. // are they asking for us?
  121. if arp.get_oper() == arp::Operation::Request && arp.get_tpa() == IP
  122. {
  123. // reply the ARP request
  124. let tha = arp.get_sha();
  125. let tpa = arp.get_spa();
  126. arp.set_oper(arp::Operation::Reply);
  127. arp.set_sha(MAC);
  128. arp.set_spa(IP);
  129. arp.set_tha(tha);
  130. arp.set_tpa(tpa);
  131. iprintln!(_stim, "\n** {:?}", arp);
  132. // update the Ethernet header
  133. eth.set_destination(tha);
  134. eth.set_source(MAC);
  135. iprintln!(_stim, "* {:?}", eth);
  136. iprintln!(_stim, "Tx({})", eth.as_bytes().len());
  137. enc28j60.transmit(eth.as_bytes()).ok().unwrap();
  138. }
  139. }
  140. Err(_arp) => {
  141. iprintln!(_stim, "** {:?}", _arp);
  142. }
  143. }
  144. } else {
  145. iprintln!(_stim, "Err(B)");
  146. }
  147. }
  148. ether::Type::Ipv4 => {
  149. if let Ok(mut ip) = ipv4::Packet::parse(eth.payload_mut()) {
  150. iprintln!(_stim, "** {:?}", ip);
  151. let ip_src = ip.get_source();
  152. if !mac_src.is_broadcast() {
  153. cache.insert(ip_src, mac_src).ok();
  154. }
  155. match ip.get_protocol() {
  156. ipv4::Protocol::Icmp => {
  157. if let Ok(icmp) = icmp::Packet::parse(ip.payload_mut()) {
  158. iprintln!(_stim, "*** {:?}", icmp);
  159. if icmp.get_type() == icmp::Type::EchoRequest
  160. && icmp.get_code() == 0
  161. {
  162. let _icmp =
  163. icmp.set_type(icmp::Type::EchoReply).update_checksum();
  164. iprintln!(_stim, "\n*** {:?}", _icmp);
  165. // update the IP header
  166. let mut ip = ip.set_source(IP);
  167. ip.set_destination(ip_src);
  168. let _ip = ip.update_checksum();
  169. iprintln!(_stim, "** {:?}", _ip);
  170. // update the Ethernet header
  171. eth.set_destination(*cache.get(&ip_src).unwrap());
  172. eth.set_source(MAC);
  173. iprintln!(_stim, "* {:?}", eth);
  174. iprintln!(_stim, "Tx({})", eth.as_bytes().len());
  175. enc28j60.transmit(eth.as_bytes()).ok().unwrap();
  176. }
  177. } else {
  178. iprintln!(_stim, "Err(C)");
  179. }
  180. }
  181. ipv4::Protocol::Udp => {
  182. if let Ok(udp) = udp::Packet::parse(ip.payload()) {
  183. iprintln!(_stim, "*** {:?}", udp);
  184. let udp_src = udp.get_source();
  185. if udp.get_destination() == coap::PORT {
  186. if let Ok(coap) = coap::Message::parse(udp.payload()) {
  187. iprintln!(_stim, "**** {:?}", coap);
  188. let path_is_led = coap
  189. .options()
  190. .filter_map(|opt| {
  191. if opt.number() == coap::OptionNumber::UriPath {
  192. Some(opt.value())
  193. } else {
  194. None
  195. }
  196. })
  197. .eq([b"led"].iter().cloned());
  198. let mut resp = coap::Response::BadRequest;
  199. match coap.get_code().try_into() {
  200. Ok(coap::Method::Get) => {
  201. if path_is_led {
  202. resp = coap::Response::Content;
  203. }
  204. }
  205. Ok(coap::Method::Put) => {
  206. if path_is_led {
  207. if let Ok(json) = json::de::from_slice::<Led>(
  208. coap.payload(),
  209. ) {
  210. if json.led {
  211. led.set_low();
  212. } else {
  213. led.set_high();
  214. }
  215. resp = coap::Response::Changed;
  216. }
  217. }
  218. }
  219. _ => {}
  220. }
  221. let mut buf = eth.free();
  222. buf.reset();
  223. let mut eth = ether::Frame::new(buf);
  224. eth.set_destination(*cache.get(&ip_src).unwrap());
  225. eth.set_source(MAC);
  226. eth.ipv4(|ip| {
  227. ip.set_source(IP);
  228. ip.set_destination(ip_src);
  229. ip.udp(|udp| {
  230. udp.set_destination(udp_src);
  231. udp.set_source(coap::PORT);
  232. udp.coap(0, |coap| {
  233. coap.set_type(coap::Type::Acknowledgement);
  234. coap.set_code(resp);
  235. if resp == coap::Response::Content {
  236. coap.set_payload(
  237. &json::ser::to_vec::<[u8; 16], _>(
  238. &Led {
  239. led: led.is_set_low(),
  240. },
  241. )
  242. .unwrap(),
  243. );
  244. } else {
  245. coap.set_payload(&[]);
  246. }
  247. iprintln!(_stim, "\n**** {:?}", coap);
  248. });
  249. iprintln!(_stim, "*** {:?}", udp);
  250. });
  251. iprintln!(_stim, "** {:?}", ip);
  252. });
  253. iprintln!(_stim, "* {:?}", eth);
  254. let bytes = eth.as_bytes();
  255. iprintln!(_stim, "Tx({})", bytes.len());
  256. enc28j60.transmit(bytes).ok().unwrap();
  257. }
  258. }
  259. }
  260. }
  261. _ => {}
  262. }
  263. } else {
  264. iprintln!(_stim, "Err(D)");
  265. }
  266. }
  267. _ => {}
  268. }
  269. } else {
  270. iprintln!(_stim, "Err(E)");
  271. }
  272. }
  273. }
  274. #[exception]
  275. fn HardFault(ef: &ExceptionFrame) -> ! {
  276. panic!("{:#?}", ef);
  277. }
  278. #[exception]
  279. fn DefaultHandler(irqn: i16) {
  280. panic!("Unhandled exception (IRQn = {})", irqn);
  281. }