service experiments
Change-Id: I4affed8a4b6e2bc61c67f1b6cd408e6c662fa7e3
diff --git a/bin/sysmgr/config/services.config b/bin/sysmgr/config/services.config
index 423f8a0..eb55ae3 100644
--- a/bin/sysmgr/config/services.config
+++ b/bin/sysmgr/config/services.config
@@ -32,6 +32,7 @@
"fuchsia.scpi.SystemController": "scpi",
"fuchsia.simplecamera.SimpleCamera" : "simple_camera_server_cpp",
"fuchsia.stash.Store": "stash",
+ "fuchsia.telephony.ModemManagement": "modem-mgr",
"fuchsia.timezone.Timezone": "timezone",
"fuchsia.timezone.TimeService": "network_time_service",
"fuchsia.tracelink.Registry": "trace_manager",
diff --git a/bin/telephony/modem-mgr/BUILD.gn b/bin/telephony/modem-mgr/BUILD.gn
index ddecff0..4425390 100644
--- a/bin/telephony/modem-mgr/BUILD.gn
+++ b/bin/telephony/modem-mgr/BUILD.gn
@@ -11,7 +11,7 @@
deps = [
# "//garnet/bin/telephony/qmi-protocol",
-# "//garnet/public/fidl/fuchsia.telephony.qmi:fuchsia.telephony.qmi-rustc",
+ "//garnet/public/fidl/fuchsia.telephony.qmi:fuchsia.telephony.qmi-rustc",
"//garnet/public/lib/fidl/rust/fidl",
"//garnet/public/rust/crates/fdio",
"//garnet/public/rust/crates/fuchsia-app",
diff --git a/bin/telephony/modem-mgr/src/main.rs b/bin/telephony/modem-mgr/src/main.rs
index c213471..21b8b6b 100644
--- a/bin/telephony/modem-mgr/src/main.rs
+++ b/bin/telephony/modem-mgr/src/main.rs
@@ -10,6 +10,8 @@
//
//
+use fuchsia_app::{server::ServicesServer, client::Launcher};
+use fidl_fuchsia_telephony_qmi::{QmiModemMarker, QmiModemProxy};
use fdio::{fdio_sys, ioctl_raw, make_ioctl};
use std::os::unix::io::AsRawFd;
use std::os::raw;
@@ -59,14 +61,25 @@
Ok(fasync::Channel::from_channel(chan)?)
}
+pub async fn start_qmi_modem(chan: fasync::Channel) -> Result<QmiModemProxy, Error> {
+ let launcher = Launcher::new()
+ .context("Failed to open launcher service")?;
+ let qmi = launcher
+ .launch(String::from("qmi-modem"), None)
+ .context("Failed to launch qmi-modem service")?;
+ let app = qmi.connect_to_service(QmiModemMarker)?;
+ let success = await!(app.connect_transport(chan.into()))?;
+ Ok(app)
+}
+
pub struct Manager {
- channel: Option<fasync::Channel>,
+ proxies: Vec<QmiModemProxy>
}
impl Manager {
pub fn new() -> Self {
Manager {
- channel: None
+ proxies: vec![],
}
}
@@ -75,32 +88,34 @@
let path: &Path = Path::new(QMI_TRANSPORT);
let dir = File::open(QMI_TRANSPORT).unwrap();
let mut watcher = Watcher::new(&dir).unwrap();
-// let mut channel = None;
while let Some(msg) = await!(watcher.try_next())? {
match msg.event {
WatchEvent::EXISTING | WatchEvent::ADD_FILE => {
let qmi_path = path.join(msg.filename);
fx_log_info!("Found QMI device at {:?}", qmi_path);
let channel = connect_qmi_transport(qmi_path)?;
- fx_log_info!("Connected a channel to the device");
- channel.write(&[0x01,
- 0x0F, 0x00, // length
- 0x00, // control flag
- 0x00, // service type
- 0x00, // client id
- // SDU below
- 0x00, // control flag
- 0x00, // tx id
- 0x20, 0x00, // message id
- 0x04, 0x00, // Length
- 0x01, // type
- 0x01, 0x00, // length
- 0x48, // value
- ], &mut Vec::new()); // TODO Remove
- let mut buffer = zx::MessageBuf::new();
- await!(channel.repeat_server(|_chan, buf| {
- println!("{:X?}", buf.bytes());
- }));
+ let svc = await!(start_qmi_modem(channel))?;
+ self.proxies.push(svc);
+
+ //fx_log_info!("Connected a channel to the device");
+ //channel.write(&[0x01,
+ // 0x0F, 0x00, // length
+ // 0x00, // control flag
+ // 0x00, // service type
+ // 0x00, // client id
+ // // SDU below
+ // 0x00, // control flag
+ // 0x00, // tx id
+ // 0x20, 0x00, // message id
+ // 0x04, 0x00, // Length
+ // 0x01, // type
+ // 0x01, 0x00, // length
+ // 0x48, // value
+ //], &mut Vec::new()); // TODO Remove
+ //let mut buffer = zx::MessageBuf::new();
+ //await!(channel.repeat_server(|_chan, buf| {
+ // println!("{:X?}", buf.bytes());
+ //}));
//}
//self.channel = Some(channel);
}
diff --git a/bin/telephony/qmi-modem/src/main.rs b/bin/telephony/qmi-modem/src/main.rs
index b49e842..94fe7e5 100644
--- a/bin/telephony/qmi-modem/src/main.rs
+++ b/bin/telephony/qmi-modem/src/main.rs
@@ -3,73 +3,183 @@
// found in the LICENSE file.
//#![deny(warnings)]
-#![feature(async_await, await_macro, futures_api, pin, arbitrary_self_types)]
+#![feature(
+ async_await,
+ await_macro,
+ futures_api,
+ pin,
+ arbitrary_self_types
+)]
#![feature(try_from)]
-use fuchsia_syslog::{self as syslog, macros::*};
-use failure::{ResultExt, Error};
-use fuchsia_app::server::ServicesServer;
-use fidl_fuchsia_telephony_qmi::{QmiModemMarker, QmiModemRequest, QmiModemRequestStream};
+use failure::{Error, ResultExt};
use fidl::endpoints2::RequestStream;
-use futures::{future, TryStreamExt, TryFutureExt};
-use fuchsia_async as fasync;
+use fidl::endpoints2::ServerEnd;
use fidl::endpoints2::ServiceMarker;
-use std::pin::PinMut;
+use fidl_fuchsia_telephony_qmi::{DeviceManagementRequest, DeviceManagementRequestStream};
+use fidl_fuchsia_telephony_qmi::{QmiClientMarker, QmiClientRequest, QmiClientRequestStream};
+use fidl_fuchsia_telephony_qmi::{QmiModemMarker, QmiModemRequest, QmiModemRequestStream};
+use fuchsia_app::server::ServicesServer;
+use fuchsia_async as fasync;
+use fuchsia_syslog::{self as syslog, macros::*};
+use fuchsia_zircon as zx;
+use futures::{future, TryFutureExt, TryStreamExt};
use std::convert::TryInto;
+use std::pin::PinMut;
-// mod service;
+use parking_lot::{Mutex, RwLock};
+use std::sync::Arc;
-//#[derive(QmiMsg)]
-//SetInstanceId {
-// msg_id: 0x0020,
-// req: tlv!(0x01, u8, instance),
-// resp: tlv!(0x01, u16, id),
-//}
-//
-//let msg = SetInstanceId::msg(3u8);
-//let id = SetInstanceId::parse([0x01, 9u16])
-//
-//use qmi_protocol::QmiClient;
-use qmi_protocol::DeviceManagement::*;
-use qmi_protocol::{ToQmiMsg, QmiMsg};
+type QmiModemPtr = Arc<Mutex<QmiModem>>;
+type QmiClientPtr = Arc<RwLock<QmiClient>>;
-pub struct QmiClient {
+// Many Qualcomm modems have an limit of 5 outstanding requests by default
+pub const MAX_CONCURRENT: usize = 4;
-}
-
+pub struct QmiClient;
impl QmiClient {
pub fn new() -> Self {
- QmiClient { }
- }
-
- pub async fn send_msg<T: ToQmiMsg>(&mut self, event: T) -> Result<QmiMsg, Error> {
- //let res = DeviceManagement::EventReportResponse::new();
- Ok(QmiMsg::new())
+ QmiClient {
+ }
}
}
-
-struct QmiModem;
+pub struct QmiModem {
+ transport_channel: Option<fasync::Channel>,
+}
impl QmiModem {
- fn spawn(chan: fasync::Channel) {
- // allocate client ID here and whatnot
- fasync::spawn(
- QmiModemRequestStream::from_channel(chan)
- .try_for_each(Self::handle_request)
- .unwrap_or_else(|e| fx_log_err!("Error running {:?}", e)))
+ pub fn new() -> Self {
+ QmiModem {
+ transport_channel: None,
+ }
}
- async fn handle_request(request: QmiModemRequest) -> Result<(), fidl::Error> {
+ pub fn connected(&self) -> bool {
+ self.transport_channel.is_some()
+ }
+
+ pub fn set_transport(&mut self, chan: zx::Channel) -> bool {
+ if self.transport_channel.is_none() {
+ return false;
+ }
+ match fasync::Channel::from_channel(chan) {
+ Ok(chan) => {
+ self.transport_channel = Some(chan);
+ true
+ }
+ Err(_) => {
+ fx_log_err!("Failed to convert a zircon channel to a fasync one");
+ false
+ }
+ }
+ }
+
+ pub async fn create_client(&self) -> Result<QmiClientPtr, Error> {
+ // do all the client work
let client = QmiClient::new();
+ //let resp = await!(client.send_raw_msg(&[0x01,
+ // 0x0F, 0x00, // length
+ // 0x00, // control flag
+ // 0x00, // service type
+ // 0x00, // client id
+ // // SDU below
+ // 0x00, // control flag
+ // 0x00, // tx id
+ // 0x20, 0x00, // message id
+ // 0x04, 0x00, // Length
+ // 0x01, // type
+ // 0x01, 0x00, // length
+ // 0x48 // value
+ //]));
+ Ok(Arc::new(RwLock::new(client)))
+ }
+}
+
+// TODO create_service!(DataManagementService,
+
+use fidl_fuchsia_telephony_qmi::DeviceManagementMarker;
+struct DataManagementService;
+impl DataManagementService {
+ pub fn spawn(server_end: ServerEnd<DeviceManagementMarker>, client: QmiClientPtr) {
+ if let Ok(request_stream) = server_end.into_stream() {
+ fasync::spawn(
+ request_stream
+ .try_for_each(move |req| Self::handle_request(client.clone(), req))
+ .unwrap_or_else(|e| fx_log_err!("Error running {:?}", e)),
+ );
+ }
+ }
+
+ async fn handle_request(
+ client: QmiClientPtr, request: DeviceManagementRequest,
+ ) -> Result<(), fidl::Error> {
match request {
- QmiModemRequest::RequestDataManagementService { service, responder } => {
- let client_id: u32 = 0; // TODO set this via modem
- fx_log_info!("request for Data Management Service from client: {}", client_id);
- // TODO start the service
- //)())); //qmi_msg!(0x0020)));
+ DeviceManagementRequest::SetEventReport {
+ power_state,
+ battery_lvl_lower_limit,
+ battery_lvl_upper_limit,
+ pin_state,
+ activation_state,
+ operator_mode_state,
+ uim_state,
+ responder,
+ } => {
Ok(())
- //responder.send(&mut resp)
+ }
+ }
+ }
+}
+
+struct QmiClientService;
+impl QmiClientService {
+ pub fn spawn(server_end: ServerEnd<QmiClientMarker>, client: QmiClientPtr) {
+ if let Ok(request_stream) = server_end.into_stream() {
+ fasync::spawn(
+ request_stream
+ .try_for_each(move |req| Self::handle_request(client.clone(), req))
+ .unwrap_or_else(|e| fx_log_err!("Error running {:?}", e)),
+ );
+ }
+ }
+
+ async fn handle_request(
+ client: QmiClientPtr, request: QmiClientRequest,
+ ) -> Result<(), fidl::Error> {
+ match request {
+ QmiClientRequest::RequestDataManagementService { service, responder } => {
+ DataManagementService::spawn(service, client.clone());
+ responder.send(true)
+ }
+ }
+ }
+}
+
+struct QmiModemService;
+impl QmiModemService {
+ pub fn spawn(modem: QmiModemPtr, chan: fasync::Channel) {
+ let server = QmiModemRequestStream::from_channel(chan)
+ .try_for_each_concurrent(MAX_CONCURRENT, move |req| {
+ Self::handle_request(modem.clone(), req)
+ }).unwrap_or_else(|e| fx_log_err!("Error running {:?}", e));
+ fasync::spawn(server);
+ }
+
+ async fn handle_request(
+ modem: QmiModemPtr, request: QmiModemRequest,
+ ) -> Result<(), fidl::Error> {
+ match request {
+ QmiModemRequest::ConnectTransport { channel, responder } => {
+ responder.send(modem.lock().set_transport(channel))
+ }
+ QmiModemRequest::ConnectClient { channel, responder } => {
+ if !modem.lock().connected() {
+ return responder.send(false);
+ }
+ let m = modem.lock();
+ let client = await!(m.create_client()).unwrap();
+ QmiClientService::spawn(channel, client);
+ responder.send(true)
}
}
}
@@ -81,21 +191,14 @@
let mut executor = fasync::Executor::new().context("Error creating executor")?;
+ let modem = Arc::new(Mutex::new(QmiModem::new()));
+
let server = ServicesServer::new()
.add_service((QmiModemMarker::NAME, move |chan: fasync::Channel| {
fx_log_info!("client connecting to QMI modem");
- QmiModem::spawn(chan)
- })).start()?;
+ QmiModemService::spawn(modem.clone(), chan)
+ })).start()
+ .context("Error starting QMI modem service")?;
- let client = QmiClient::new();
-
- let test_fut = async {
- let qmi_resp: EventReportResponse = await!(client.send_msg(EventReport::new()))?.try_into()?;
- //.unwrap().try_into().unwrap());//Some(true), Some(3))));
-// let response = await!(DeviceManagement::set_event_report(&mut client, Some(false), Some(0))); //&client, 0, 0, 0));
- Ok::<(), Error>(())
- };
-
- let x = executor.run_singlethreaded(test_fut);
- Ok(())
+ executor.run_singlethreaded(server)
}
diff --git a/packages/prod/telephony b/packages/prod/telephony
index 46ffd60..58c784f 100644
--- a/packages/prod/telephony
+++ b/packages/prod/telephony
@@ -1,6 +1,7 @@
{
"packages": [
"//garnet/bin/telephony/modem-mgr",
+ "//garnet/bin/telephony/qmi-modem",
"//garnet/drivers/telephony/qmi-transport"
]
}
diff --git a/public/fidl/fuchsia.telephony.qmi/qmi.fidl b/public/fidl/fuchsia.telephony.qmi/qmi.fidl
index 87f600b..9854612 100644
--- a/public/fidl/fuchsia.telephony.qmi/qmi.fidl
+++ b/public/fidl/fuchsia.telephony.qmi/qmi.fidl
@@ -22,18 +22,36 @@
ErrorCode error;
};
-/// Interface to request QMI Standard services from.
-interface QmiModem {
- // No interface to CTL service is exposed
-
-// /// Fulfill a request for the Wireless Data |service| interface
-// 1001: RequestWirelessDataService(request<WirelessData> service);
-
+interface QmiClient {
/// Fulfill a request for the Device Management |service| interface
- 1002: RequestDataManagementService(request<DeviceManagement> service) -> (QmiResult res);
+ //1002: RequestDataManagementService(request<DeviceManagement> service) -> (QmiResult res);
+ 1002: RequestDataManagementService(request<DeviceManagement> service) -> (bool res);
-// /// Fulfill a request for the Loctaion |service| interface
-// 1003: RequestLocationService(request<Location> location);
-
- // A bunch more services. Messaging, User Identity, Phonebook, etc...
};
+
+/// Interface to request QMI Standard services from. Manages modem client ID
+/// allocation automatically after a transport mechanism has been connected.
+interface QmiModem {
+ /// Connect to the underlying transport |channel|. Start watching for QMI
+ /// messages to demultiplex/translate to their respective FIDL interface for
+ /// each connected client. Called per-modem, not per client connection.
+ 100: ConnectTransport(handle<channel> channel) -> (bool success);
+
+ // No methods to the global CTL service is exposed, in the future we may want to expose a subset
+
+ /// Connect to the modem, allocating the client ID and exposing a set of QMI services over
+ /// the new |QmiClient| interface
+ 200: ConnectClient(request<QmiClient> channel) -> (bool success);
+};
+
+
+//
+// /// Fulfill a request for the Wireless Data |service| interface
+// // 1001: RequestWirelessDataService(request<WirelessData> service);
+//
+//
+// /// Fulfill a request for the Loctaion |service| interface
+// // 1003: RequestLocationService(request<Location> location);
+//
+// // A bunch more services. Messaging, User Identity, Phonebook, etc...
+//};