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. */ 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 */ 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 */ 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 */ 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 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 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 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