• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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  * Implement a simple T=1 echo endpoint.
17  */
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include "../libese-teq1/include/ese/teq1.h"
24 #include "../libese/include/ese/ese.h"
25 #include "../libese/include/ese/log.h"
26 
27 struct EchoState {
28   struct Teq1Frame frame;
29   uint8_t *rx_fill;
30   uint8_t *tx_sent;
31   int recvd;
32 };
33 
34 #define ECHO_STATE(ese) (*(struct EchoState **)(&ese->pad[1]))
35 
echo_open(struct EseInterface * ese,void * hw_opts)36 static int echo_open(struct EseInterface *ese, void *hw_opts) {
37   struct EchoState *es = hw_opts; /* shorter than __attribute */
38   struct EchoState **es_ptr;
39   if (sizeof(ese->pad) < sizeof(struct EchoState *)) {
40     /* This is a compile-time correctable error only. */
41     ALOGE("Pad size too small to use Echo HW (%zu < %zu)", sizeof(ese->pad),
42           sizeof(struct EchoState *));
43     return -1;
44   }
45   es_ptr = &ECHO_STATE(ese);
46   *es_ptr = malloc(sizeof(struct EchoState));
47   if (!*es_ptr) {
48     return -1;
49   }
50   es = ECHO_STATE(ese);
51   es->rx_fill = &es->frame.header.NAD;
52   es->tx_sent = es->rx_fill;
53   es->recvd = 0;
54   return 0;
55 }
56 
echo_close(struct EseInterface * ese)57 static void echo_close(struct EseInterface *ese) {
58   struct EchoState *es;
59   es = ECHO_STATE(ese);
60   if (!es) {
61     return;
62   }
63   free(es);
64   es = NULL;
65 }
66 
echo_receive(struct EseInterface * ese,uint8_t * buf,uint32_t len,int complete)67 static uint32_t echo_receive(struct EseInterface *ese, uint8_t *buf,
68                              uint32_t len, int complete) {
69   struct EchoState *es = ECHO_STATE(ese);
70   ALOGV("interface attempting to read data");
71   if (!es->recvd) {
72     return 0;
73   }
74 
75   if (len > sizeof(es->frame) - (es->tx_sent - &es->frame.header.NAD)) {
76     return 0;
77   }
78 
79   /* NAD was polled for so skip it. */
80   memcpy(buf, es->tx_sent, len);
81   es->tx_sent += len;
82   if (complete) {
83     es->tx_sent = &es->frame.header.NAD;
84     es->recvd = 0;
85     ALOGV("card sent a frame");
86   }
87   return sizeof(es->frame.header) + es->frame.header.LEN;
88 }
89 
echo_transmit(struct EseInterface * ese,const uint8_t * buf,uint32_t len,int complete)90 static uint32_t echo_transmit(struct EseInterface *ese, const uint8_t *buf,
91                               uint32_t len, int complete) {
92   struct EchoState *es = ECHO_STATE(ese);
93   ALOGV("interface transmitting data");
94   if (len > sizeof(es->frame) - (es->rx_fill - &es->frame.header.NAD)) {
95     return 0;
96   }
97   memcpy(es->rx_fill, buf, len);
98   es->rx_fill += len;
99   es->recvd = complete;
100   if (complete) {
101     es->frame.header.NAD = 0x00;
102     if (teq1_compute_LRC(&es->frame) != es->frame.INF[es->frame.header.LEN]) {
103       ALOGV("card received frame with bad LRC");
104       return 0;
105     }
106     ALOGV("card received valid frame");
107     es->rx_fill = &es->frame.header.NAD;
108   }
109   return len;
110 }
111 
echo_poll(struct EseInterface * ese,uint8_t poll_for,float timeout,int complete)112 static int echo_poll(struct EseInterface *ese, uint8_t poll_for, float timeout,
113                      int complete) {
114   struct EchoState *es = ECHO_STATE(ese);
115   const struct Teq1ProtocolOptions *opts = ese->ops->opts;
116   ALOGV("interface polling for start of frame/host node address: %x", poll_for);
117   /* In reality, we should be polling at intervals up to the timeout. */
118   if (timeout > 0.0) {
119     usleep(timeout * 1000);
120   }
121   if (poll_for == opts->host_address) {
122     ALOGV("interface received NAD");
123     if (!complete) {
124       es->tx_sent++; /* Consume the polled byte: NAD */
125     }
126     return 1;
127   }
128   return -1;
129 }
130 
echo_preprocess(const struct Teq1ProtocolOptions * const opts,struct Teq1Frame * frame,int tx)131 int echo_preprocess(const struct Teq1ProtocolOptions *const opts,
132                     struct Teq1Frame *frame, int tx) {
133   if (tx) {
134     /* Recompute the LRC with the NAD of 0x00 */
135     frame->header.NAD = 0x00;
136     frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
137     frame->header.NAD = opts->node_address;
138     ALOGV("interface is preprocessing outbound frame");
139   } else {
140     /* Replace the NAD with 0x00 so the LRC check passes. */
141     frame->header.NAD = 0x00;
142     ALOGV("interface is preprocessing inbound frame");
143   }
144   return 0;
145 }
146 
147 static const struct Teq1ProtocolOptions kTeq1Options = {
148     .host_address = 0xAA,
149     .node_address = 0xBB,
150     .bwt = 3.14152f,
151     .etu = 1.0f,
152     .preprocess = &echo_preprocess,
153 };
154 
echo_transceive(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)155 uint32_t echo_transceive(struct EseInterface *ese,
156                          const struct EseSgBuffer *tx_buf, uint32_t tx_len,
157                          struct EseSgBuffer *rx_buf, uint32_t rx_len) {
158   return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
159 }
160 
161 static const char *kErrorMessages[] = {
162     "T=1 hard failure.",        /* TEQ1_ERROR_HARD_FAIL */
163     "T=1 abort.",               /* TEQ1_ERROR_ABORT */
164     "T=1 device reset failed.", /* TEQ1_ERROR_DEVICE_ABORT */
165 };
166 
167 static const struct EseOperations ops = {
168     .name = "eSE Echo Hardware (fake)",
169     .open = &echo_open,
170     .hw_receive = &echo_receive,
171     .hw_transmit = &echo_transmit,
172     .transceive = &echo_transceive,
173     .poll = &echo_poll,
174     .close = &echo_close,
175     .opts = &kTeq1Options,
176     .errors = kErrorMessages,
177     .errors_count = sizeof(kErrorMessages),
178 };
179 ESE_DEFINE_HW_OPS(ESE_HW_ECHO, ops);
180