// Copyright Open Logistics Foundation // // Licensed under the Open Logistics Foundation License 1.3. // For details on the licensing terms, see the LICENSE file. // SPDX-License-Identifier: OLFL-1.3 //! Simple TCP echo example //! //! When running the example, please specify the socket address (ip address + port number) of a TCP //! echo server in the environment variable `BG77_REMOTE`. //! //! This example will print some minimal output over serial uart and RTT. #![no_std] #![no_main] pub use hal::stm32 as pac; pub use stm32l4xx_hal as hal; use core::{str::FromStr, time::Duration}; use hal::prelude::*; use panic_probe as _; mod boards; use boards::common; #[cortex_m_rt::entry] fn main() -> ! { let mut driver = boards::board_setup(); let bg77 = quectel_bg77::Bg77ClientStack::new(&mut driver); // IP address of your TCP echo server: read from environment variable let socket_addr_str = core::env!( "BG77_REMOTE", "Please specify the socket address of your tcp echo server, e.g. '192.168.1.1:12345'" ); let socket_addr = match embedded_nal::SocketAddr::from_str(socket_addr_str) { Ok(s) => s, Err(e) => { log::info!("Could not parse socket address: {:?}", e); #[allow(clippy::empty_loop)] loop {} } }; // TCP echo example if let Err(e) = tcp_client_example(bg77, socket_addr) { log::error!("Example failed: {:?}", e); } else { log::info!("Example successful"); } #[allow(clippy::empty_loop)] loop {} } fn tcp_client_example( mut bg77: BG77, socket_addr: embedded_nal::SocketAddr, ) -> Result<(), E> where E: core::fmt::Debug, BG77: embedded_nal::TcpClientStack, { // This only fails if all sockets are currently in use let mut socket = bg77.socket().unwrap(); log::info!("Connect socket to {}", socket_addr); nb::block!(bg77.connect(&mut socket, socket_addr))?; let tx = b"Hello, BG77!\n"; let mut sent = 0; log::info!("Send message"); while sent < tx.len() { // bg77.send() currently never returns `nb::Error::WouldBlock` so `nb::block!` is not // required here but this would be the correct usage of a generic // `embedded_nal::TcpClientStack` let chunk_len = nb::block!(bg77.send(&mut socket, &tx[sent..tx.len()]))?; sent += chunk_len; log::info!("Bytes sent (total): {}", sent); } loop { log::info!("Receive"); let mut rx_buf = [0u8; 100]; match bg77.receive(&mut socket, &mut rx_buf) { Ok(received) => { log::info!("Received {} bytes: {:?}", received, &rx_buf[..received]); log::info!("Stop"); // The driver implements `Drop` for the sockets so it is closed automatically. In // general, calling `TcpClientStack::close(socket)` would be required. return Ok(()); } Err(nb::Error::WouldBlock) => { log::info!("Nothing received, retrying in a second"); let mut timer = common::Timer::new(); timer.start(Duration::from_secs(1)); nb::block!(timer.wait()).unwrap(); } Err(nb::Error::Other(e)) => { return Err(e); } } } }