• 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 <fcntl.h>
18 #include <chrono>
19 #include <cstdint>
20 
21 #include "host/commands/casimir_control_server/crc.h"
22 
23 #include "casimir_control.grpc.pb.h"
24 #include "casimir_controller.h"
25 
26 namespace cuttlefish {
27 
28 using namespace casimir::rf;
29 using namespace std::literals::chrono_literals;
30 using pdl::packet::slice;
31 
Mute()32 Result<void> CasimirController::Mute() {
33   if (!sock_->IsOpen()) {
34     return {};
35   }
36   FieldInfoBuilder rf_off;
37   rf_off.field_status_ = FieldStatus::FieldOff;
38   rf_off.power_level_ = power_level;
39   CF_EXPECT(Write(rf_off));
40   return {};
41 }
42 
CasimirController(SharedFD sock)43 CasimirController::CasimirController(SharedFD sock)
44     : sock_(sock), power_level(10) {}
45 
46 /* static */
ConnectToTcpPort(int rf_port)47 Result<CasimirController> CasimirController::ConnectToTcpPort(int rf_port) {
48   SharedFD sock = SharedFD::SocketLocalClient(rf_port, SOCK_STREAM);
49   CF_EXPECT(sock->IsOpen(),
50             "Failed to connect to casimir with RF port" << rf_port);
51 
52   int flags = sock->Fcntl(F_GETFL, 0);
53   CF_EXPECT_GE(flags, 0, "Failed to get FD flags of casimir socket");
54   CF_EXPECT_EQ(sock->Fcntl(F_SETFL, flags | O_NONBLOCK), 0,
55                "Failed to set casimir socket nonblocking");
56 
57   return CasimirController(sock);
58 }
59 
60 /* static */
ConnectToUnixSocket(const std::string & rf_path)61 Result<CasimirController> CasimirController::ConnectToUnixSocket(
62     const std::string& rf_path) {
63   SharedFD sock = SharedFD::SocketLocalClient(rf_path, false, SOCK_STREAM);
64   CF_EXPECT(sock->IsOpen(),
65             "Failed to connect to casimir with RF path" << rf_path);
66 
67   int flags = sock->Fcntl(F_GETFL, 0);
68   CF_EXPECT_GE(flags, 0, "Failed to get FD flags of casimir socket");
69   CF_EXPECT_EQ(sock->Fcntl(F_SETFL, flags | O_NONBLOCK), 0,
70                "Failed to set casimir socket nonblocking");
71   return CasimirController(sock);
72 }
73 
Unmute()74 Result<void> CasimirController::Unmute() {
75   if (!sock_->IsOpen()) {
76     return {};
77   }
78   FieldInfoBuilder rf_on;
79   rf_on.field_status_ = FieldStatus::FieldOn;
80   rf_on.power_level_ = power_level;
81   CF_EXPECT(Write(rf_on));
82   return {};
83 }
84 
SetPowerLevel(uint32_t power_level)85 Result<void> CasimirController::SetPowerLevel(uint32_t power_level) {
86   this->power_level = power_level;
87   return {};
88 }
89 
SelectNfcA()90 Result<uint16_t> CasimirController::SelectNfcA() {
91   PollCommandBuilder poll_command;
92   poll_command.technology_ = Technology::NFC_A;
93   poll_command.format_ = PollingFrameFormat::SHORT;
94   poll_command.bitrate_ = BitRate::BIT_RATE_106_KBIT_S;
95   poll_command.power_level_ = power_level;
96   // WUPA
97   poll_command.payload_ = std::vector<uint8_t>{0x52};
98   CF_EXPECT(Write(poll_command), "Failed to send NFC-A poll command");
99 
100   auto res = CF_EXPECT(ReadRfPacket(10s), "Failed to get NFC-A poll response");
101 
102   auto rf_packet = RfPacketView::Create(slice(res));
103   if (rf_packet.IsValid()) {
104     auto poll_response = NfcAPollResponseView::Create(rf_packet);
105     if (poll_response.IsValid() && poll_response.GetIntProtocol() == 0b01) {
106       return poll_response.GetSender();
107     }
108   }
109   return CF_ERR("Invalid Poll-A response");
110 }
111 
SelectT4AT(uint16_t sender_id)112 Result<void> CasimirController::SelectT4AT(uint16_t sender_id) {
113   T4ATSelectCommandBuilder t4at_select_command;
114   t4at_select_command.sender_ = sender_id;
115   t4at_select_command.param_ = 0;
116   t4at_select_command.bitrate_ = BitRate::BIT_RATE_106_KBIT_S;
117   CF_EXPECT(Write(t4at_select_command), "Failed to send T4AT select command");
118 
119   auto res = CF_EXPECT(ReadRfPacket(1s), "Failed to get T4AT response");
120 
121   // Note: T4AT select response implies NFC_A and ISO_DEP
122   auto rf_packet = RfPacketView::Create(slice(res));
123   if (rf_packet.IsValid()) {
124     auto select_response = T4ATSelectResponseView::Create(rf_packet);
125     if (select_response.IsValid() && select_response.GetSender() == sender_id) {
126       return {};
127     }
128   }
129   return CF_ERR("Invalid T4AT response");
130 }
131 
Poll()132 Result<uint16_t> CasimirController::Poll() {
133   CF_EXPECT(sock_->IsOpen());
134 
135   uint16_t sender_id = CF_EXPECT(SelectNfcA(), "Failed to select NFC-A");
136   CF_EXPECT(SelectT4AT(sender_id), "Failed to select T4AT");
137   return sender_id;
138 }
139 
SendApdu(uint16_t receiver_id,std::vector<uint8_t> apdu)140 Result<std::vector<uint8_t>> CasimirController::SendApdu(
141     uint16_t receiver_id, std::vector<uint8_t> apdu) {
142   CF_EXPECT(sock_->IsOpen());
143 
144   DataBuilder data_builder;
145   data_builder.data_ = std::move(apdu);
146   data_builder.receiver_ = receiver_id;
147   data_builder.technology_ = Technology::NFC_A;
148   data_builder.protocol_ = Protocol::ISO_DEP;
149   data_builder.bitrate_ = BitRate::BIT_RATE_106_KBIT_S;
150 
151   CF_EXPECT(Write(data_builder), "Failed to send APDU bytes");
152 
153   auto res = CF_EXPECT(ReadRfPacket(3s), "Failed to get APDU response");
154   auto rf_packet = RfPacketView::Create(slice(res));
155   if (rf_packet.IsValid()) {
156     auto data = DataView::Create(rf_packet);
157     if (data.IsValid() && rf_packet.GetSender() == receiver_id) {
158       return data.GetData();
159     }
160   }
161   return CF_ERR("Invalid APDU response");
162 }
163 
164 Result<std::tuple<std::vector<uint8_t>, std::string, bool, uint32_t, uint32_t,
165                   uint32_t, double>>
SendBroadcast(std::vector<uint8_t> data,std::string type,bool crc,uint8_t bits,uint32_t bitrate,uint32_t timeout,double power)166 CasimirController::SendBroadcast(std::vector<uint8_t> data, std::string type,
167                                  bool crc, uint8_t bits, uint32_t bitrate,
168                                  uint32_t timeout, double power) {
169   PollCommandBuilder poll_command;
170 
171   if (type == "A") {
172     poll_command.technology_ = Technology::NFC_A;
173     if (crc) {
174       data = CF_EXPECT(WithCrc16A(data), "Could not append CRC16A");
175     }
176   } else if (type == "B") {
177     poll_command.technology_ = Technology::NFC_B;
178     if (crc) {
179       data = CF_EXPECT(WithCrc16B(data), "Could not append CRC16B");
180     }
181     if (bits != 8) {
182       return CF_ERR(
183           "Sending NFC-B data with != 8 bits in the last byte is unsupported");
184     }
185   } else if (type == "F") {
186     poll_command.technology_ = Technology::NFC_F;
187     if (!crc) {
188       // For NFC-F, CRC also assumes preamble
189       return CF_ERR("Sending NFC-F data without CRC is unsupported");
190     }
191     if (bits != 8) {
192       return CF_ERR(
193           "Sending NFC-F data with != 8 bits in the last byte is unsupported");
194     }
195   } else if (type == "V") {
196     poll_command.technology_ = Technology::NFC_V;
197   } else {
198     poll_command.technology_ = Technology::RAW;
199   }
200 
201   if (bitrate == 106) {
202     poll_command.bitrate_ = BitRate::BIT_RATE_106_KBIT_S;
203   } else if (bitrate == 212) {
204     poll_command.bitrate_ = BitRate::BIT_RATE_212_KBIT_S;
205   } else if (bitrate == 424) {
206     poll_command.bitrate_ = BitRate::BIT_RATE_424_KBIT_S;
207   } else if (bitrate == 848) {
208     poll_command.bitrate_ = BitRate::BIT_RATE_848_KBIT_S;
209   } else if (bitrate == 1695) {
210     poll_command.bitrate_ = BitRate::BIT_RATE_1695_KBIT_S;
211   } else if (bitrate == 3390) {
212     poll_command.bitrate_ = BitRate::BIT_RATE_3390_KBIT_S;
213   } else if (bitrate == 6780) {
214     poll_command.bitrate_ = BitRate::BIT_RATE_6780_KBIT_S;
215   } else if (bitrate == 26) {
216     poll_command.bitrate_ = BitRate::BIT_RATE_26_KBIT_S;
217   } else {
218     return CF_ERR("Proper bitrate was not provided: " << bitrate);
219   }
220 
221   poll_command.payload_ = std::move(data);
222 
223   if (bits > 8) {
224     return CF_ERR("There can not be more than 8 bits in last byte: " << bits);
225   }
226   poll_command.format_ =
227       bits != 8 ? PollingFrameFormat::SHORT : PollingFrameFormat::LONG;
228 
229   // Adjust range of values from 0-100 to 0-12
230   poll_command.power_level_ = static_cast<int>(std::round(power * 12 / 100));
231 
232   CF_EXPECT(Write(poll_command), "Failed to send broadcast frame");
233 
234   if (timeout != 0) {
235     CF_EXPECT(ReadRfPacket(std::chrono::microseconds(timeout)));
236   }
237 
238   return std::make_tuple(data, type, crc, bits, bitrate, timeout, power);
239 }
240 
Write(const RfPacketBuilder & rf_packet)241 Result<void> CasimirController::Write(const RfPacketBuilder& rf_packet) {
242   std::vector<uint8_t> raw_bytes = rf_packet.SerializeToBytes();
243   uint16_t header_bytes_le = htole16(raw_bytes.size());
244   ssize_t written = WriteAll(sock_, reinterpret_cast<char*>(&header_bytes_le),
245                              sizeof(header_bytes_le));
246   CF_EXPECT_EQ(written, sizeof(header_bytes_le),
247                "Failed to write packet header to casimir socket, errno="
248                    << sock_->GetErrno());
249 
250   written = WriteAll(sock_, reinterpret_cast<char*>(raw_bytes.data()),
251                      raw_bytes.size());
252   CF_EXPECT_EQ(written, raw_bytes.size(),
253                "Failed to write packet payload to casimir socket, errno="
254                    << sock_->GetErrno());
255 
256   return {};
257 }
258 
ReadExact(size_t size,std::chrono::microseconds timeout)259 Result<std::shared_ptr<std::vector<uint8_t>>> CasimirController::ReadExact(
260     size_t size, std::chrono::microseconds timeout) {
261   size_t total_read = 0;
262   auto out = std::make_shared<std::vector<uint8_t>>(size);
263   auto prev_time = std::chrono::steady_clock::now();
264   while (
265       std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count() >
266       0) {
267     PollSharedFd poll_fd = {
268         .fd = sock_,
269         .events = EPOLLIN,
270         .revents = 0,
271     };
272     int res = sock_.Poll(
273         &poll_fd, 1,
274         std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count());
275     CF_EXPECT_GE(res, 0, "Failed to poll on the casimir socket");
276     CF_EXPECT_EQ(poll_fd.revents, EPOLLIN,
277                  "Unexpected poll result for reading");
278 
279     // Nonblocking read, so don't need to care about timeout.
280     ssize_t read =
281         sock_->Read((void*)&(out->data()[total_read]), size - total_read);
282     CF_EXPECT_GT(
283         read, 0,
284         "Failed to read from casimir socket, errno=" << sock_->GetErrno());
285 
286     total_read += read;
287     if (total_read >= size) {
288       return out;
289     }
290 
291     auto current_time = std::chrono::steady_clock::now();
292     timeout -= std::chrono::duration_cast<std::chrono::microseconds>(
293         current_time - prev_time);
294   }
295 
296   return CF_ERR("Failed to read from casimir socket; timed out");
297 }
298 
299 // Note: Although rf_packets.h doesn't document nor include packet header,
300 // the header is necessary to know total packet size.
ReadRfPacket(std::chrono::microseconds timeout)301 Result<std::shared_ptr<std::vector<uint8_t>>> CasimirController::ReadRfPacket(
302     std::chrono::microseconds timeout) {
303   auto start_time = std::chrono::steady_clock::now();
304 
305   auto res = CF_EXPECT(ReadExact(sizeof(uint16_t), timeout),
306                        "Failed to read RF packet header");
307   slice packet_size_slice(res);
308   int16_t packet_size = packet_size_slice.read_le<uint16_t>();
309 
310   auto current_time = std::chrono::steady_clock::now();
311   timeout -= std::chrono::duration_cast<std::chrono::microseconds>(
312       current_time - start_time);
313   return CF_EXPECT(ReadExact(packet_size, timeout),
314                    "Failed to read RF packet payload");
315 }
316 
317 }  // namespace cuttlefish
318