1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*=============================================================================
18   @file sns_qmi_client.c
19 
20   ===========================================================================*/
21 
22 /*=============================================================================
23   Include Files
24   ===========================================================================*/
25 #include <inttypes.h>
26 #include "pb_encode.h"
27 #include "qmi_client.h"
28 #include "sns_client.h"
29 #include "sns_client.pb.h"
30 #include "sns_client_api_v01.h"
31 #include "sns_osa.h"
32 
33 /*=============================================================================
34   Type Definitions
35   ===========================================================================*/
36 
37 /* An outgoing request which is awaiting the corresponding response message. */
38 typedef struct sns_request {
39   struct sns_client *client;
40   /* Client registered callback */
41   sns_client_resp resp_cb;
42   void *resp_cb_data;
43 } sns_request;
44 
45 /* A client connection; a client process may open multiple QMI connections. */
46 typedef struct sns_client {
47   /* Client registered callbacks */
48   sns_client_ind ind_cb;
49   void *ind_cb_data;
50   sns_client_error error_cb;
51   void *error_cb_data;
52 
53   /* QMI Client Handle */
54   qmi_client_type qmi_handle;
55 } sns_client;
56 
57 /*=============================================================================
58   Static Function Definitions
59   ===========================================================================*/
60 
61 /* QMI indication callback.  See qmi_client_ind_cb. */
client_ind_cb(qmi_client_type user_handle,unsigned int msg_id,void * ind_buf,unsigned int ind_buf_len,void * ind_cb_data)62 static void client_ind_cb(qmi_client_type user_handle, unsigned int msg_id,
63                           void *ind_buf, unsigned int ind_buf_len,
64                           void *ind_cb_data) {
65   UNUSED_VAR(user_handle);
66   sns_client *client = ind_cb_data;
67   size_t ind_len = sizeof(sns_client_report_ind_msg_v01);
68   sns_client_report_ind_msg_v01 *ind = sns_malloc(ind_len);
69   int32_t qmi_err;
70 
71   SNS_ASSERT(NULL != ind);
72 
73   // Extract the Protocol Buffer encoded message from the outer QMI/IDL  message
74   qmi_err = qmi_idl_message_decode(SNS_CLIENT_SVC_get_service_object_v01(),
75                                    QMI_IDL_INDICATION, msg_id, ind_buf,
76                                    ind_buf_len, ind, ind_len);
77   if (QMI_IDL_LIB_NO_ERR != qmi_err) {
78     SNS_LOG(ERROR, "QMI decode error %i", qmi_err);
79   } else {
80     SNS_LOG(VERBOSE, "Indication from client ID %" PRIu64, ind->client_id);
81 
82     client->ind_cb(client, ind->payload, ind->payload_len, client->ind_cb_data);
83   }
84 
85   sns_free(ind);
86 }
87 
88 /**
89  * Allocate and initialize the response callback handler state for a request.
90  *
91  * @param[i] client
92  * @param[i] resp_cb Callback to be called upon response receipt
93  * @param[i] resp_cb_data Optional callback to be delivered
94  *
95  * @return Newly create request objct
96  */
create_request(sns_client * client,sns_client_resp resp_cb,void * resp_cb_data)97 static sns_request *create_request(sns_client *client, sns_client_resp resp_cb,
98                                    void *resp_cb_data) {
99   sns_request *request;
100 
101   request = sns_malloc(sizeof(*request));
102   SNS_ASSERT(NULL != request);
103 
104   request->resp_cb = resp_cb;
105   request->resp_cb_data = resp_cb_data;
106   request->client = client;
107 
108   return request;
109 }
110 
111 /**
112  * Handle an incoming QMI response message from the Sensors Service.
113  */
client_resp_cb(qmi_client_type user_handle,unsigned int msg_id,void * resp_c_struct,unsigned int resp_c_struct_len,void * resp_cb_data,qmi_client_error_type transp_err)114 static void client_resp_cb(qmi_client_type user_handle, unsigned int msg_id,
115                            void *resp_c_struct, unsigned int resp_c_struct_len,
116                            void *resp_cb_data,
117                            qmi_client_error_type transp_err) {
118   UNUSED_VAR(user_handle);
119   UNUSED_VAR(msg_id);
120   UNUSED_VAR(resp_c_struct_len);
121   sns_request *request = resp_cb_data;
122   sns_client_resp_msg_v01 *resp = resp_c_struct;
123   sns_std_error err = SNS_STD_ERROR_NO_ERROR;
124 
125   if (NULL != resp && resp->result_valid) {
126     err = resp->result;
127     SNS_LOG(VERBOSE, "Response from client %" PRIu64, resp->client_id);
128   } else if (QMI_NO_ERR != transp_err) {
129     err = SNS_STD_ERROR_FAILED;
130   }
131 
132   if (NULL != request->resp_cb)
133     request->resp_cb(request->client, err, request->resp_cb_data);
134 
135   sns_free(request);
136   sns_free(resp_c_struct);
137 }
138 
139 /**
140  * An error occurred; typically means the SLPI has restarted, and the client
141  * should attempt to reconnect.
142  */
client_error_cb(qmi_client_type user_handle,qmi_client_error_type error,void * err_cb_data)143 static void client_error_cb(qmi_client_type user_handle,
144                             qmi_client_error_type error, void *err_cb_data) {
145   UNUSED_VAR(user_handle);
146   UNUSED_VAR(error);
147   sns_client *client = err_cb_data;
148 
149   SNS_LOG(VERBOSE, "Error from client");
150 
151   // PEND: Convert QMI transport error
152   client->error_cb(client, SNS_STD_ERROR_INVALID_STATE, client->error_cb_data);
153 }
154 
155 /*=============================================================================
156   Public Function Definitions
157   ===========================================================================*/
158 
sns_client_init(sns_client ** client_out,uint32_t timeout,sns_client_ind ind_cb,void * ind_cb_data,sns_client_error error_cb,void * error_cb_data)159 int sns_client_init(sns_client **client_out, uint32_t timeout,
160                     sns_client_ind ind_cb, void *ind_cb_data,
161                     sns_client_error error_cb, void *error_cb_data) {
162   qmi_idl_service_object_type service_obj =
163       SNS_CLIENT_SVC_get_service_object_v01();
164   qmi_service_instance instance_id = 0;
165   qmi_client_error_type qmi_err;
166   qmi_cci_os_signal_type os_params;
167   int rv = -1;
168   sns_client *client;
169 
170   client = sns_malloc(sizeof(*client));
171   SNS_ASSERT(NULL != client);
172   client->ind_cb = ind_cb;
173   client->ind_cb_data = ind_cb_data;
174   client->error_cb = error_cb;
175   client->error_cb_data = error_cb_data;
176 
177   qmi_err =
178       qmi_client_init_instance(service_obj, instance_id, client_ind_cb, client,
179                                &os_params, timeout, &client->qmi_handle);
180   if (QMI_NO_ERR != qmi_err) {
181     SNS_LOG(ERROR, "qmi_client_init_instance error %i", qmi_err);
182   } else {
183     qmi_err =
184         qmi_client_register_error_cb(client->qmi_handle, client_error_cb, NULL);
185 
186     if (QMI_NO_ERR != qmi_err)
187       SNS_LOG(ERROR, "qmi_client_register_error_cb error %i", qmi_err);
188     else
189       rv = 0;
190   }
191 
192   if (0 != rv) {
193     if (NULL != client->qmi_handle) qmi_client_release(client->qmi_handle);
194 
195     sns_free(client);
196     client = NULL;
197   }
198 
199   SNS_LOG(VERBOSE, "sns_client_init %p", client);
200 
201   *client_out = client;
202   return rv;
203 }
204 
sns_client_deinit(sns_client * client)205 int sns_client_deinit(sns_client *client) {
206   qmi_client_release(client->qmi_handle);
207   sns_free(client);
208 
209   SNS_LOG(VERBOSE, "sns_client_deinit complete %p", client);
210   return 0;
211 }
212 
sns_client_send(sns_client * client,sns_client_request_msg * msg,sns_client_resp resp_cb,void * resp_cb_data)213 int sns_client_send(sns_client *client, sns_client_request_msg *msg,
214                     sns_client_resp resp_cb, void *resp_cb_data) {
215   int rv = 0;
216   pb_ostream_t stream;
217   sns_client_req_msg_v01 *req_msg;
218 
219   req_msg = sns_malloc(sizeof(*req_msg));
220   SNS_ASSERT(NULL != req_msg);
221 
222   stream = pb_ostream_from_buffer(req_msg->payload, sizeof(req_msg->payload));
223   if (!pb_encode(&stream, sns_client_request_msg_fields, msg)) {
224     SNS_LOG(ERROR, "pb_encode error: %s", PB_GET_ERROR(&stream));
225     rv = -1;
226   } else {
227     qmi_txn_handle txn_handle;
228     qmi_client_error_type qmi_err;
229     sns_request *request;
230     size_t resp_len = sizeof(sns_client_resp_msg_v01);
231     void *resp;
232 
233     resp = sns_malloc(resp_len);
234     SNS_ASSERT(NULL != resp);
235     request = create_request(client, resp_cb, resp_cb_data);
236 
237     req_msg->payload_len = stream.bytes_written;
238     qmi_err = qmi_client_send_msg_async(
239         client->qmi_handle, SNS_CLIENT_REQ_V01, req_msg, sizeof(*req_msg), resp,
240         resp_len, client_resp_cb, request, &txn_handle);
241 
242     if (QMI_NO_ERR != qmi_err) {
243       SNS_LOG(ERROR, "qmi_client_send_msg_async error %i", qmi_err);
244       sns_free(resp);
245       sns_free(request);
246       rv = -2;
247     }
248   }
249 
250   sns_free(req_msg);
251   return rv;
252 }
253