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