blob: 1c44e59ba537d67fb3186110714ac5aa8a1df78c [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//#![deny(warnings)]
#![feature(
async_await,
await_macro,
futures_api,
pin,
arbitrary_self_types
)]
use failure::{Error, ResultExt};
use fidl::endpoints::{RequestStream, ServerEnd, ServiceMarker};
use fidl_fuchsia_telephony_ril::{RadioInterfaceLayerMarker, RadioInterfaceLayerRequest, RadioInterfaceLayerRequestStream};
use fidl_fuchsia_telephony_ril::RadioPowerState;
use fuchsia_app::server::ServicesServer;
use fuchsia_async as fasync;
use fuchsia_syslog::{self as syslog, macros::*};
use fuchsia_zircon as zx;
use futures::{TryFutureExt, TryStreamExt};
use qmi_protocol::QmiResult;
use parking_lot::{Mutex, RwLock};
use std::sync::Arc;
use crate::client::QmiClient;
use crate::transport::QmiTransport;
use crate::errors::QmuxError;
use qmi_protocol::CTL::*;
use qmi_protocol::*;
mod client;
mod errors;
mod service;
mod transport;
type QmiModemPtr = Arc<Mutex<QmiModem>>;
type QmiClientPtr = Arc<RwLock<QmiClient>>;
pub struct QmiModem {
inner: Option<Arc<QmiTransport>>,
}
impl QmiModem {
pub fn new() -> Self {
QmiModem { inner: None }
}
pub fn connected(&self) -> bool {
// TODO add aditional logic for checking transport_channel open
self.inner.is_some()
}
pub fn connect_transport(&mut self, chan: zx::Channel) -> bool {
fx_log_info!("Connecting the transport");
if self.connected() {
fx_log_err!("Attempted to connect more than one transport");
return false;
}
match fasync::Channel::from_channel(chan) {
Ok(chan) => {
if chan.is_closed() {
fx_log_err!("The transport channel is not open");
return false;
}
self.inner = Some(Arc::new(QmiTransport::new(chan)));
true
}
Err(_) => {
fx_log_err!("Failed to convert a zircon channel to a fasync one");
false
}
}
}
pub async fn create_client(&self) -> Result<QmiClient, Error> {
fx_log_info!("Client connecting...");
if let Some(ref inner) = self.inner {
let transport_inner = inner.clone();
let client = QmiClient::new(transport_inner);
Ok(client)
} else {
Err(QmuxError::NoClient.into())
}
}
}
type ClientPtr = Arc<Mutex<Option<QmiClient>>>;
struct FrilService;
impl FrilService {
pub fn spawn(modem: QmiModemPtr, chan: fasync::Channel) {
let client = Arc::new(Mutex::new(None));
let server = RadioInterfaceLayerRequestStream::from_channel(chan)
.try_for_each(move |req| Self::handle_request(modem.clone(), client.clone(), req))
.unwrap_or_else(|e| fx_log_err!("Error running {:?}", e));
fasync::spawn(server);
}
async fn handle_request(
modem: QmiModemPtr, mut client: ClientPtr, request: RadioInterfaceLayerRequest,
) -> Result<(), fidl::Error> {
match request {
RadioInterfaceLayerRequest::ConnectTransport { channel, responder } => {
let mut lock = modem.lock();
let status = lock.connect_transport(channel);
fx_log_info!("Connecting the service to the transport driver: {}", status);
responder.send(status)
}
RadioInterfaceLayerRequest::GetDeviceIdentity { responder } => {
let mut client_lock = client.lock();
if client_lock.is_none() {
fx_log_info!("Requested client connect.");
// TODO RIL Error type
let modem_lock = modem.lock();
let alloced_client = await!(modem_lock.create_client()).unwrap();
*client_lock = Some(alloced_client);
}
if let Some(ref client) = *client_lock {
let resp: QmiResult<DMS::GetDeviceSerialNumbersResp> =
await!(client.send_msg(DMS::GetDeviceSerialNumbersReq::new())).unwrap();
return responder.send(&resp.unwrap().imei);
}
responder.send("none")
}
RadioInterfaceLayerRequest::RadioPowerStatus { responder } => {
let mut client_lock = client.lock();
if client_lock.is_none() {
fx_log_info!("Requested client connect.");
// TODO RIL Error type
let modem_lock = modem.lock();
let alloced_client = await!(modem_lock.create_client()).unwrap();
*client_lock = Some(alloced_client);
}
if let Some(ref client) = *client_lock {
fx_log_info!("send serial request!");
let resp: DMS::GetOperatingModeResp =
await!(client.send_msg(DMS::GetOperatingModeReq::new())).unwrap().unwrap();
if (resp.operating_mode == 0x00) {
return responder.send(RadioPowerState::On);
} else {
return responder.send(RadioPowerState::Off);
}
}
responder.send(RadioPowerState::Off)
}
}
}
}
fn main() -> Result<(), Error> {
syslog::init_with_tags(&["ril-qmi"]).expect("Can't init logger");
fx_log_info!("Starting ril-qmi...");
let mut executor = fasync::Executor::new().context("Error creating executor")?;
let modem = Arc::new(Mutex::new(QmiModem::new()));
let server = ServicesServer::new()
.add_service((RadioInterfaceLayerMarker::NAME, move |chan: fasync::Channel| {
fx_log_info!("New client connecting to the Fuchsia RIL");
FrilService::spawn(modem.clone(), chan)
})).start()
.context("Error starting QMI modem service")?;
executor.run_singlethreaded(server)
}