-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
358 lines (318 loc) · 11.9 KB
/
main.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//! Blinks the LED on a Pico board
//!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED.
#![no_std]
#![no_main]
use defmt_rtt as _;
use bsp::entry;
use core::fmt::Debug;
use defmt::*;
use embedded_hal::digital::OutputPin;
use panic_probe as _;
use sim7020::at_command::http::HttpMethod::GET;
use sim7020::at_command::AtResponse;
use sim7020::AtError;
use sim7020::Modem;
use sim7020::Write;
use sim7020::{at_command, Read};
use fugit::RateExtU32;
// Provide an alias for our BSP so we can switch targets quickly.
// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change.
use rp_pico as bsp;
// use sparkfun_pro_micro_rp2040 as bsp;
use bsp::hal::{
clocks::init_clocks_and_plls,
gpio::{FunctionUart, Pins},
pac,
sio::Sio,
uart::{self, DataBits, StopBits, UartConfig, UartPeripheral},
watchdog::Watchdog,
Clock,
};
use cortex_m::asm::delay;
use cortex_m::prelude::_embedded_hal_blocking_delay_DelayMs;
use cortex_m::prelude::_embedded_hal_blocking_i2c_Read;
use rp_pico::hal::gpio::bank0::{Gpio0, Gpio1};
use rp_pico::hal::gpio::{Pin, PullDown};
// use rp_pico::hal::uart::{ReadErrorType, Reader, Writer};
use rp_pico::pac::UART0;
use sim7020::at_command::mqtt::{
MQTTConnectionSettings, MQTTError, MQTTSessionSettings, MQTTVersion, Mqtt,
};
use sim7020::at_command::network_information::NetworkMode;
const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; // Typically found in BSP crates
#[entry]
fn main() -> ! {
info!("Program start");
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);
// External high-speed crystal on the pico board is 12Mhz
let clocks = init_clocks_and_plls(
XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
let pins = bsp::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
info!("resetting modem");
let mut power_pin = pins.gpio14.into_push_pull_output();
let mut wake_pin = pins.gpio17.into_push_pull_output();
let mut led_pin = pins.led.into_push_pull_output();
power_pin.set_low().unwrap();
led_pin.set_low().unwrap();
delay.delay_ms(500);
led_pin.set_high().unwrap();
power_pin.set_high().unwrap();
delay.delay_ms(3000);
info!("resetting modem... done");
// Set up UART on GP0 and GP1 (Pico pins 1 and 2)
let pins_uart = (
pins.gpio0.into_function::<FunctionUart>(),
pins.gpio1.into_function::<FunctionUart>(),
);
// Need to perform clock init before using UART or it will freeze.
let uart = UartPeripheral::new(pac.UART0, pins_uart, &mut pac.RESETS)
.enable(
UartConfig::new(9600.Hz(), DataBits::Seven, None, StopBits::One),
clocks.peripheral_clock.freq(),
)
.unwrap();
let (mut reader, mut writer) = uart.split();
let mut modem = Modem::new(&mut writer, &mut reader).unwrap();
modem.set_flow_control().unwrap();
modem.enable_numeric_errors().unwrap();
'outer: loop {
info!("waiting for operator...........................................");
let power_saving_mode = modem
.send_and_wait_reply(&at_command::power_saving_mode::GetPowerSavingMode {})
.unwrap();
info!("power_saving_mode: {}", power_saving_mode);
let battery_charge = modem
.send_and_wait_reply(&at_command::battery::BatteryCharge {})
.unwrap();
info!("battery_charge: {}", battery_charge);
let gprs_status = modem
.send_and_wait_reply(&at_command::at_cgatt::GPRSServiceStatus {})
.unwrap();
info!("gprs status: {}", gprs_status);
let sleep_indication = modem
.send_and_wait_reply(&at_command::sleep_indication::SleepIndicationStatus {})
.unwrap();
info!("sleep_indication status: {}", sleep_indication);
let signal_quality = modem
.send_and_wait_reply(&at_command::at_csq::SignalQualityReport {})
.unwrap();
info!("signal quality: {}", signal_quality);
let registration = modem
.send_and_wait_reply(&at_command::at_creg::NetworkRegistration {})
.unwrap();
info!("network registration: {:?}", registration);
let registration = modem
.send_and_wait_reply(&at_command::network_registration_status::NetworkRegistration {})
.unwrap();
info!("network registration status: {:?}", registration);
let pdp_context = modem
.send_and_wait_reply(&at_command::pdp_context::PDPContext {})
.unwrap();
info!("pdp context: {:?}", pdp_context);
let response = modem
.send_and_wait_reply(&at_command::cgcontrdp::PDPContextReadDynamicsParameters {})
.unwrap();
info!("pdp context dynamics parameters: {}", response);
let network_information = modem
.send_and_wait_reply(&at_command::network_information::NetworkInformation {})
.unwrap();
match network_information {
AtResponse::NetworkInformationState(_, _, operator) => {
if let Some(operator) = operator {
info!("operator available: {:?}", operator);
break 'outer;
}
}
_ => continue,
}
delay.delay_ms(1000);
}
delay.delay_ms(2000);
modem
.send_and_wait_reply(&at_command::at_cpin::PINRequired {})
.expect("TODO: panic message");
let response = modem
.send_and_wait_reply(&at_command::model_identification::ModelIdentification {})
.unwrap();
info!("model id: {}", response);
modem
.send_and_wait_reply(&at_command::at_creg::NetworkRegistration {})
.unwrap();
let time = modem
.send_and_wait_reply(&at_command::clock::Clock {})
.unwrap();
info!("network time: {}", time);
//
// delay.delay_ms(4000);
// let _ = modem
// .send_and_wait_reply(&at_command::ntp::StartQueryNTP {
// url: "pool.ntp.org",
// tzinfo: Some("+32"),
// })
// .or_else(|e| {
// warn!("failed starting ntp connection. Connection already established?");
// return Err(e);
// });
//
// delay.delay_ms(10000);
// let _ = modem
// .send_and_wait_reply(&at_command::ntp::StopQueryNTP {})
// .or_else(|e| {
// warn!("failed stopping ntp connection. Connection already established?");
// return Err(e);
// });
// // here we should expect an unsolicited ntp response
// if let Err(e) = test_http_connection(&mut modem) {
// error!("http test failed");
// }
test_mqtt_connection(&mut modem, &mut delay).unwrap();
delay.delay_ms(2000);
// Setting the APN fails:
// match modem.send_and_wait_reply(at_command::at_cstt::SetAPNUserPassword::new().with_apn("iot.1nce.net")){
// Ok(result) => info!("set apn"),
// Err(e) => error!("failed setting apn"),
// }
//
// modem.send_and_wait_reply(at_command::at_cstt::GetAPNUserPassword{})
// .unwrap();
// // at_command::at::At::send(&writer);
// // at_command::at_creg::AtCreg::send(&writer);
//
// // writer.write_full_blocking(b"ATE0\r\n");
info!("receive loop");
loop {
let gprs_status = modem
.send_and_wait_reply(&at_command::at_cgatt::GPRSServiceStatus {})
.unwrap();
info!("gprs status: {}", gprs_status);
let signal_quality = modem
.send_and_wait_reply(&at_command::at_csq::SignalQualityReport {})
.unwrap();
info!("signal quality: {}", signal_quality);
delay.delay_ms(5000);
}
}
fn test_mqtt_connection<T, U>(
mut modem: &mut Modem<T, U>,
delay: &mut cortex_m::delay::Delay,
) -> Result<(), AtError>
where
T: Write,
U: Read,
{
let mqtt_session = modem
.send_and_wait_reply(&at_command::mqtt::GetMQTTSession {})
.unwrap();
info!("mqtt_session: {:?}", mqtt_session);
let connection = MQTTSessionSettings::new("88.198.226.54", 1883);
loop {
let mqtt_session = modem
.send_and_wait_reply(&at_command::mqtt::GetMQTTSession {})
.unwrap();
info!("mqtt_session: {:?}", mqtt_session);
modem
.send_and_wait_reply(&at_command::at_creg::NetworkRegistration {})
.unwrap();
delay.delay_ms(1000);
info!("creating mqtt session.");
let mqtt = Mqtt::new(&connection);
let mqtt_session = mqtt
.create_session(&mut modem)
.map_err(|_| AtError::MqttFailure);
if let Err(e) = mqtt_session {
info!("mqtt session creation failed: {:?}. Retry", e);
continue;
}
let mqtt_session = mqtt_session.unwrap();
delay.delay_ms(1000);
let mqtt_connection = mqtt_session
.connect(
MQTTConnectionSettings {
version: MQTTVersion::MQTT31,
client_id: "nbiot",
keepalive_interval: 0,
clean_session: false,
will_flag: false,
username: env!("EXAMPLE_MQTT_USER"),
password: env!("EXAMPLE_MQTT_PASSWORD"),
},
&mut modem,
)
.unwrap();
let mqtt_session = modem
.send_and_wait_reply(&at_command::mqtt::GetMQTTSession {})
.unwrap();
info!("mqtt_session: {:?}", mqtt_session);
delay.delay_ms(1000);
match mqtt_connection.publish(
&at_command::mqtt::MQTTMessage {
topic: "test", // length max 128b
qos: 1, // 0 | 1 | 2
retained: false, // 0 | 1
dup: false, // 0 | 1
message: b"hello world via mqtt", // as hex
},
&mut modem,
) {
Ok(..) => {
info!("sent message")
}
Err(e) => {
warn!("failed to sent message: {:?}", e);
continue;
}
};
delay.delay_ms(1000);
let mqtt = mqtt_connection.disconnect(&mut modem).unwrap();
delay.delay_ms(10000);
}
}
fn test_http_connection<T, U>(modem: &mut Modem<T, U>) -> Result<(), AtError>
where
T: Write,
U: Read,
{
// To test this you can start a server e.g. using python with `python3 -m http.server 8000`
// if this errors, most likely the session count is exhausted (max 4)
let _ = modem.send_and_wait_reply(&at_command::http::GetHttpSessions {})?;
let result = modem.send_and_wait_reply(&at_command::http::CreateHttpSession {
host: "http://88.198.226.54:8000",
user: None,
password: None,
})?;
info!("created http session: {}", result);
if let AtResponse::HTTPSessionCreated(client_id) = result {
// if this errors, most likely the server did not respond
info!("connecting:");
modem.send_and_wait_reply(&at_command::http::HttpConnect { client_id })?;
info!("sending:");
modem.send_and_wait_reply(&at_command::http::HttpSend {
client_id,
method: GET,
path: "/hello/world",
})?;
let _ = modem.send_and_wait_reply(&at_command::http::GetHttpSessions {})?;
modem.send_and_wait_reply(&at_command::http::HttpDisconnect { client_id })?;
modem.send_and_wait_reply(&at_command::http::HttpDestroy { client_id })?;
}
Ok(())
}