• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 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 #include <iostream>
18 #include <memory>
19 #include <string>
20 
21 #include <android-base/hex.h>
22 #include <gflags/gflags.h>
23 #include <grpcpp/ext/proto_server_reflection_plugin.h>
24 #include <grpcpp/grpcpp.h>
25 #include <grpcpp/health_check_service_interface.h>
26 
27 #include "casimir_control.grpc.pb.h"
28 
29 #include "common/libs/utils/result.h"
30 #include "host/commands/casimir_control_server/casimir_controller.h"
31 #include "host/commands/casimir_control_server/hex.h"
32 
33 using casimircontrolserver::CasimirControlService;
34 using casimircontrolserver::PowerLevel;
35 using casimircontrolserver::RadioState;
36 using casimircontrolserver::SendApduReply;
37 using casimircontrolserver::SendApduRequest;
38 using casimircontrolserver::SendBroadcastRequest;
39 using casimircontrolserver::SendBroadcastResponse;
40 using casimircontrolserver::SenderId;
41 using casimircontrolserver::TransceiveConfiguration;
42 using casimircontrolserver::Void;
43 
44 using cuttlefish::CasimirController;
45 
46 using google::protobuf::Empty;
47 using grpc::Server;
48 using grpc::ServerBuilder;
49 using grpc::ServerContext;
50 using grpc::Status;
51 using grpc::StatusCode;
52 using std::string;
53 using std::vector;
54 
55 DEFINE_string(grpc_uds_path, "", "grpc_uds_path");
56 DEFINE_int32(casimir_rf_port, -1, "RF port to control Casimir");
57 DEFINE_string(casimir_rf_path, "", "RF unix server path to control Casimir");
58 
59 namespace cuttlefish {
60 namespace {
61 
ConnectToCasimir()62 Result<CasimirController> ConnectToCasimir() {
63   if (FLAGS_casimir_rf_port >= 0) {
64     return CF_EXPECT(
65         CasimirController::ConnectToTcpPort(FLAGS_casimir_rf_port));
66   } else if (!FLAGS_casimir_rf_path.empty()) {
67     return CF_EXPECT(
68         CasimirController::ConnectToUnixSocket(FLAGS_casimir_rf_path));
69   } else {
70     return CF_ERR("`--casimir_rf_port` or `--casimir_rf_path` must be set");
71   }
72 }
73 
ResultToStatus(Result<void> res)74 Status ResultToStatus(Result<void> res) {
75   if (res.ok()) {
76     return Status::OK;
77   } else {
78     LOG(ERROR) << "RPC failed: " << res.error().FormatForEnv();
79     return Status(StatusCode::INTERNAL,
80                   res.error().FormatForEnv(/* color = */ false));
81   }
82 }
83 
84 class CasimirControlServiceImpl final : public CasimirControlService::Service {
85  private:
SetPowerLevel(ServerContext * context,const PowerLevel * power_level,Void *)86   Status SetPowerLevel(ServerContext* context, const PowerLevel* power_level,
87                        Void*) override {
88     return ResultToStatus(SetPowerLevelResult(power_level));
89   }
90 
SetPowerLevelResult(const PowerLevel * power_level)91   Result<void> SetPowerLevelResult(const PowerLevel* power_level) {
92     if (!device_) {
93       return {};
94     }
95     CF_EXPECT(device_->SetPowerLevel(power_level->power_level()),
96               "Failed to set power level");
97     return {};
98   }
99 
Close(ServerContext * context,const Void *,Void * senderId)100   Status Close(ServerContext* context, const Void*, Void* senderId) override {
101     device_ = std::nullopt;
102     return Status::OK;
103   }
104 
Init(ServerContext *,const Void *,Void *)105   Status Init(ServerContext*, const Void*, Void*) override {
106     return ResultToStatus(Init());
107   }
108 
Init()109   Result<void> Init() {
110     if (device_.has_value()) {
111       return {};
112     }
113     // Step 1: Initialize connection with casimir
114     device_ = CF_EXPECT(ConnectToCasimir());
115     return {};
116   }
117 
Mute()118   Result<void> Mute() {
119     if (!device_.has_value()) {
120       return {};
121     }
122 
123     if (is_radio_on_) {
124       CF_EXPECT(device_->Mute(), "Failed to mute radio");
125       is_radio_on_ = false;
126     }
127     return {};
128   }
129 
Unmute()130   Result<void> Unmute() {
131     if (!is_radio_on_) {
132       CF_EXPECT(device_->Unmute(), "Failed to unmute radio");
133       is_radio_on_ = true;
134     }
135     return {};
136   }
137 
SetRadioState(ServerContext * context,const RadioState * radio_state,Void *)138   Status SetRadioState(ServerContext* context, const RadioState* radio_state,
139                        Void*) override {
140     return ResultToStatus(SetRadioStateResult(radio_state));
141   }
142 
SetRadioStateResult(const RadioState * radio_state)143   Result<void> SetRadioStateResult(const RadioState* radio_state) {
144     if (radio_state->radio_on()) {
145       CF_EXPECT(Init());
146       CF_EXPECT(Unmute());
147       return {};
148     } else {
149       if (!device_.has_value()) {
150         return {};
151       }
152       CF_EXPECT(Mute());
153       return {};
154     }
155   }
156 
PollAResult(SenderId * sender_id)157   Result<void> PollAResult(SenderId* sender_id) {
158     // Step 1: Initialize connection with casimir
159     if (!device_.has_value()) {
160       device_ = CF_EXPECT(ConnectToCasimir(), "Failed to connect with casimir");
161       CF_EXPECT(Unmute(), "failed to unmute the device");
162     }
163     // Step 2: Poll
164     /* Casimir control server seems to be dropping integer values of zero.
165       This works around that issue by translating the 0-based sender IDs to
166       be 1-based.*/
167     sender_id->set_sender_id(
168 
169         CF_EXPECT(device_->Poll(),
170                   "Failed to poll and select NFC-A and ISO-DEP") +
171         1);
172     return {};
173   }
174 
PollA(ServerContext *,const Void *,SenderId * sender_id)175   Status PollA(ServerContext*, const Void*, SenderId* sender_id) override {
176     return ResultToStatus(PollAResult(sender_id));
177   }
178 
SendApduResult(const SendApduRequest * request,SendApduReply * response)179   Result<void> SendApduResult(const SendApduRequest* request,
180                               SendApduReply* response) {
181     // Step 0: Parse input
182     std::vector<std::vector<uint8_t>> apdu_bytes;
183     for (const std::string& apdu_hex_string : request->apdu_hex_strings()) {
184       apdu_bytes.emplace_back(
185           CF_EXPECT(HexToBytes(apdu_hex_string),
186                     "Failed to parse input. Must only contain [0-9a-fA-F]"));
187     }
188     // Step 1: Initialize connection with casimir
189     CF_EXPECT(Init());
190 
191     int16_t id;
192     if (request->has_sender_id()) {
193       /* Casimir control server seems to be dropping integer values of zero.
194         This works around that issue by translating the 0-based sender IDs to
195         be 1-based.*/
196       id = request->sender_id() - 1;
197     } else {
198       // Step 2: Poll
199       SenderId sender_id;
200       CF_EXPECT(PollAResult(&sender_id));
201       id = sender_id.sender_id() - 1;
202     }
203 
204     // Step 3: Send APDU bytes
205     response->clear_response_hex_strings();
206     for (int i = 0; i < apdu_bytes.size(); i++) {
207       std::vector<uint8_t> bytes =
208           CF_EXPECT(device_->SendApdu(id, std::move(apdu_bytes[i])),
209                     "Failed to send APDU bytes");
210       std::string resp = android::base::HexString(
211           reinterpret_cast<void*>(bytes.data()), bytes.size());
212       response->add_response_hex_strings(std::move(resp));
213     }
214 
215     // Returns OK although returned bytes is valids if ends with [0x90, 0x00].
216     return {};
217   }
218 
SendApdu(ServerContext *,const SendApduRequest * request,SendApduReply * response)219   Status SendApdu(ServerContext*, const SendApduRequest* request,
220                   SendApduReply* response) override {
221     return ResultToStatus(SendApduResult(request, response));
222   }
223 
SendBroadcastResult(const SendBroadcastRequest * request,SendBroadcastResponse * response)224   Result<void> SendBroadcastResult(const SendBroadcastRequest* request,
225                                    SendBroadcastResponse* response) {
226     // Default configuration values
227     TransceiveConfiguration requestConfig;
228     // Type A
229     requestConfig.set_type("A");
230     // CRC present
231     requestConfig.set_crc(true);
232     // 8 bits in last byte
233     requestConfig.set_bits(8);
234     // 106kbps
235     requestConfig.set_bitrate(106);
236     // No timeout, timeout immediately
237     requestConfig.clear_timeout();
238     // 100% output power
239     requestConfig.set_power(100);
240 
241     // Overwrite defaults with provided configuration, if present
242     if (request->has_configuration()) {
243       auto config = request->configuration();
244       if (config.has_type()) {
245         requestConfig.set_type(config.type());
246       }
247       if (config.has_crc()) {
248         requestConfig.set_crc(config.crc());
249       }
250       if (config.has_bits()) {
251         requestConfig.set_bits(config.bits());
252       }
253       if (config.has_bitrate()) {
254         requestConfig.set_bitrate(config.bitrate());
255       }
256       if (config.has_timeout()) {
257         requestConfig.set_timeout(config.timeout());
258       }
259       if (config.has_power()) {
260         requestConfig.set_power(config.power());
261       }
262     }
263 
264     if (!device_.has_value()) {
265       device_ = CF_EXPECT(ConnectToCasimir(), "Failed to connect with casimir");
266       CF_EXPECT(Unmute(), "failed to unmute the device");
267     }
268 
269     std::vector<uint8_t> requestData =
270         CF_EXPECT(HexToBytes(request->data()),
271                   "Failed to parse input. Must only contain [0-9a-fA-F]");
272 
273     CF_EXPECT(device_->SendBroadcast(
274                   requestData, requestConfig.type(), requestConfig.crc(),
275                   requestConfig.bits(), requestConfig.bitrate(),
276                   requestConfig.timeout(), requestConfig.power()),
277               "Failed to send broadcast data");
278 
279     return {};  // Success
280   }
281 
SendBroadcast(ServerContext *,const SendBroadcastRequest * request,SendBroadcastResponse * response)282   Status SendBroadcast(ServerContext*, const SendBroadcastRequest* request,
283                        SendBroadcastResponse* response) override {
284     return ResultToStatus(SendBroadcastResult(request, response));
285   }
286 
287   std::optional<CasimirController> device_;
288   bool is_radio_on_ = false;
289 };
290 
RunServer(int argc,char ** argv)291 void RunServer(int argc, char** argv) {
292   ::gflags::ParseCommandLineFlags(&argc, &argv, true);
293   std::string server_address("unix:" + FLAGS_grpc_uds_path);
294   CasimirControlServiceImpl service;
295 
296   grpc::EnableDefaultHealthCheckService(true);
297   grpc::reflection::InitProtoReflectionServerBuilderPlugin();
298   ServerBuilder builder;
299   // Listen on the given address without any authentication mechanism.
300   builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
301   // Register "service" as the instance through which we'll communicate with
302   // clients. In this case it corresponds to an *synchronous* service.
303   builder.RegisterService(&service);
304   // Finally assemble the server.
305   std::unique_ptr<Server> server(builder.BuildAndStart());
306   std::cout << "Server listening on " << server_address << std::endl;
307 
308   // Wait for the server to shutdown. Note that some other thread must be
309   // responsible for shutting down the server for this call to ever return.
310   server->Wait();
311 }
312 
313 }  // namespace
314 }  // namespace cuttlefish
315 
main(int argc,char ** argv)316 int main(int argc, char** argv) {
317   cuttlefish::RunServer(argc, argv);
318 
319   return 0;
320 }
321