blob: a6fe50489f6c0b4bb9fa77c93f30b38c525e74eb [file] [log] [blame]
Will Drewryd4ae5282017-01-03 22:06:26 -06001/*
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
Will Drewryd4ae5282017-01-03 22:06:26 -060019#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
Will Drewryde2cad72017-03-10 15:53:34 -060023#include "../libese-teq1/include/ese/teq1.h"
24#include "../libese/include/ese/ese.h"
25#include "../libese/include/ese/log.h"
Will Drewryd4ae5282017-01-03 22:06:26 -060026
27struct EchoState {
28 struct Teq1Frame frame;
29 uint8_t *rx_fill;
30 uint8_t *tx_sent;
31 int recvd;
32};
33
Will Drewryde2cad72017-03-10 15:53:34 -060034#define ECHO_STATE(ese) (*(struct EchoState **)(&ese->pad[1]))
Will Drewryd4ae5282017-01-03 22:06:26 -060035
36static int echo_open(struct EseInterface *ese, void *hw_opts) {
37 struct EchoState *es = hw_opts; /* shorter than __attribute */
38 struct EchoState **es_ptr;
Will Drewryd4ae5282017-01-03 22:06:26 -060039 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 }
Will Drewryde2cad72017-03-10 15:53:34 -060045 es_ptr = &ECHO_STATE(ese);
Will Drewryd4ae5282017-01-03 22:06:26 -060046 *es_ptr = malloc(sizeof(struct EchoState));
Will Drewryde2cad72017-03-10 15:53:34 -060047 if (!*es_ptr) {
Will Drewryd4ae5282017-01-03 22:06:26 -060048 return -1;
Will Drewryde2cad72017-03-10 15:53:34 -060049 }
Will Drewryd4ae5282017-01-03 22:06:26 -060050 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
Will Drewryde2cad72017-03-10 15:53:34 -060057static void echo_close(struct EseInterface *ese) {
Will Drewryd4ae5282017-01-03 22:06:26 -060058 struct EchoState *es;
Will Drewryd4ae5282017-01-03 22:06:26 -060059 es = ECHO_STATE(ese);
Will Drewryde2cad72017-03-10 15:53:34 -060060 if (!es) {
61 return;
62 }
Will Drewryd4ae5282017-01-03 22:06:26 -060063 free(es);
Will Drewryde2cad72017-03-10 15:53:34 -060064 es = NULL;
Will Drewryd4ae5282017-01-03 22:06:26 -060065}
66
Will Drewryde2cad72017-03-10 15:53:34 -060067static uint32_t echo_receive(struct EseInterface *ese, uint8_t *buf,
68 uint32_t len, int complete) {
Will Drewryd4ae5282017-01-03 22:06:26 -060069 struct EchoState *es = ECHO_STATE(ese);
70 ALOGV("interface attempting to read data");
Will Drewryde2cad72017-03-10 15:53:34 -060071 if (!es->recvd) {
Will Drewryd4ae5282017-01-03 22:06:26 -060072 return 0;
Will Drewryde2cad72017-03-10 15:53:34 -060073 }
Will Drewryd4ae5282017-01-03 22:06:26 -060074
Will Drewryde2cad72017-03-10 15:53:34 -060075 if (len > sizeof(es->frame) - (es->tx_sent - &es->frame.header.NAD)) {
Will Drewryd4ae5282017-01-03 22:06:26 -060076 return 0;
Will Drewryde2cad72017-03-10 15:53:34 -060077 }
Will Drewryd4ae5282017-01-03 22:06:26 -060078
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
Will Drewryde2cad72017-03-10 15:53:34 -060090static uint32_t echo_transmit(struct EseInterface *ese, const uint8_t *buf,
91 uint32_t len, int complete) {
Will Drewryd4ae5282017-01-03 22:06:26 -060092 struct EchoState *es = ECHO_STATE(ese);
93 ALOGV("interface transmitting data");
Will Drewryde2cad72017-03-10 15:53:34 -060094 if (len > sizeof(es->frame) - (es->rx_fill - &es->frame.header.NAD)) {
Will Drewryd4ae5282017-01-03 22:06:26 -060095 return 0;
Will Drewryde2cad72017-03-10 15:53:34 -060096 }
Will Drewryd4ae5282017-01-03 22:06:26 -060097 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
112static 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. */
Will Drewryde2cad72017-03-10 15:53:34 -0600118 if (timeout > 0.0) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600119 usleep(timeout * 1000);
Will Drewryde2cad72017-03-10 15:53:34 -0600120 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600121 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
131int 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
Will Drewryde2cad72017-03-10 15:53:34 -0600147static const struct Teq1ProtocolOptions kTeq1Options = {
Will Drewryd4ae5282017-01-03 22:06:26 -0600148 .host_address = 0xAA,
149 .node_address = 0xBB,
150 .bwt = 3.14152f,
151 .etu = 1.0f,
152 .preprocess = &echo_preprocess,
153};
154
Will Drewry8f367fc2017-03-30 22:07:48 -0500155uint32_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) {
Will Drewryde2cad72017-03-10 15:53:34 -0600158 return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
159}
Will Drewryd4ae5282017-01-03 22:06:26 -0600160
161static 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};
Will Drewryde2cad72017-03-10 15:53:34 -0600166
167static 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};
179ESE_DEFINE_HW_OPS(ESE_HW_ECHO, ops);