Numworks Epsilon  1.4.1
Graphing Calculator Operating System
endpoint0.cpp
Go to the documentation of this file.
1 #include "endpoint0.h"
2 #include "device.h"
3 #include "interface.h"
4 #include "request_recipient.h"
5 #include "../regs/regs.h"
6 #include <string.h>
7 
8 #define MIN(a, b) ((a) < (b) ? (a) : (b))
9 
10 namespace Ion {
11 namespace USB {
12 namespace Device {
13 
15  // Setup the IN direction
16 
17  // Reset the device IN endpoint 0 transfer size register
18  class OTG::DIEPTSIZ0 dieptsiz0(0);
19  /* Transfer size. The core interrupts the application only after it has
20  * exhausted the transfer size amount of data. The transfer size is set to the
21  * maximum packet size, to be interrupted at the end of each packet. */
22  dieptsiz0.setXFRSIZ(k_maxPacketSize);
23  OTG.DIEPTSIZ0()->set(dieptsiz0);
24 
25  // Reset the device IN endpoint 0 control register
26  class OTG::DIEPCTL0 diepctl0(0); // Reset value
27  // Set the maximum packet size
29  // Set the NAK bit: all IN transactions on endpoint 0 receive a NAK answer
30  diepctl0.setSNAK(true);
31  // Enable the endpoint
32  diepctl0.setEPENA(true);
33  OTG.DIEPCTL0()->set(diepctl0);
34 
35  // Setup the OUT direction
36 
37  setupOut();
38  // Set the NAK bit
39  OTG.DOEPCTL0()->setSNAK(true);
40  // Enable the endpoint
41  enableOut();
42 
43  // Setup the Tx FIFO
44 
45  /* Tx FIFO depth
46  * We process each packet as soon as it arrives, so we only need
47  * k_maxPacketSize bytes. TX0FD being in terms of 32-bit words, we divide
48  * k_maxPacketSize by 4. */
49  OTG.DIEPTXF0()->setTX0FD(k_maxPacketSize/4);
50  /* Tx FIFO RAM start address. It starts just after the Rx FIFOso the value is
51  * Rx FIFO start address (0) + Rx FIFO depth. the Rx FIFO depth is set in
52  * usb.cpp, but because the code is linked separately, we cannot get it. */
53  OTG.DIEPTXF0()->setTX0FSA(128);
54 }
55 
57  class OTG::DOEPTSIZ0 doeptsiz0(0);
58  // Number of back-to-back SETUP data packets the endpoint can receive
59  doeptsiz0.setSTUPCNT(1);
60  // Packet count, false if a packet is written into the Rx FIFO
61  doeptsiz0.setPKTCNT(true);
62  /* Transfer size. The core interrupts the application only after it has
63  * exhausted the transfer size amount of data. The transfer size is set to the
64  * maximum packet size, to be interrupted at the end of each packet. */
65  doeptsiz0.setXFRSIZ(64);
66  OTG.DOEPTSIZ0()->set(doeptsiz0);
67 }
68 
69 void Endpoint0::setOutNAK(bool nak) {
70  m_forceNAK = nak;
71  /* We need to keep track of the NAK state of the endpoint to use the value
72  * after a setupOut in poll() of device.cpp. */
73  if (nak) {
74  OTG.DOEPCTL0()->setSNAK(true);
75  } else {
76  OTG.DOEPCTL0()->setCNAK(true);
77  }
78 }
79 
81  OTG.DOEPCTL0()->setEPENA(true);
82 }
83 
85  flushTxFifo();
86  flushRxFifo();
87 }
88 
90  setOutNAK(true);
91 
92  // Read the 8-bytes Setup packet
93  if (readPacket(m_largeBuffer, sizeof(SetupPacket)) != sizeof(SetupPacket)) {
95  return;
96  };
97 
98  m_request = SetupPacket(m_largeBuffer);
99  uint16_t maxBufferLength = MIN(m_request.wLength(), MaxTransferSize);
100 
101  // Forward the request to the request recipient
102  uint8_t type = static_cast<uint8_t>(m_request.recipientType());
103  if (type == 0) {
104  // Device recipient
105  m_requestRecipients[0]->processSetupRequest(&m_request, m_largeBuffer, &m_transferBufferLength, maxBufferLength);
106  } else {
107  // Interface recipient
108  m_requestRecipients[1]->processSetupRequest(&m_request, m_largeBuffer, &m_transferBufferLength, maxBufferLength);
109  }
110 }
111 
113  switch (m_state) {
114  case State::DataIn:
115  sendSomeData();
116  break;
117  case State::LastDataIn:
118  m_state = State::StatusOut;
119  // Prepare to receive the OUT Data[] transaction.
120  setOutNAK(false);
121  break;
122  case State::StatusIn:
123  {
124  m_state = State::Idle;
125  // All the data has been received. Callback the request recipient.
126  uint8_t type = static_cast<uint8_t>(m_request.recipientType());
127  if (type == 0) {
128  // Device recipient
129  m_requestRecipients[0]->wholeDataReceivedCallback(&m_request, m_largeBuffer, &m_transferBufferLength);
130  } else {
131  // Interface recipient
132  m_requestRecipients[1]->wholeDataReceivedCallback(&m_request, m_largeBuffer, &m_transferBufferLength);
133  }
134  }
135  break;
136  default:
138  }
139 }
140 
142  switch (m_state) {
143  case State::DataOut:
144  if (receiveSomeData() < 0) {
145  break;
146  }
147  if ((m_request.wLength() - m_transferBufferLength) <= k_maxPacketSize) {
148  m_state = State::LastDataOut;
149  }
150  break;
151  case State::LastDataOut:
152  if (receiveSomeData() < 0) {
153  break;
154  }
155  // Send the DATA1[] to the host.
156  writePacket(NULL, 0);
157  m_state = State::StatusIn;
158  break;
159  case State::StatusOut:
160  {
161  // Read the DATA1[] sent by the host.
162  readPacket(NULL, 0);
163  m_state = State::Idle;
164  // All the data has been sent. Callback the request recipient.
165  uint8_t type = static_cast<uint8_t>(m_request.recipientType());
166  if (type == 0) {
167  // Device recipient
168  m_requestRecipients[0]->wholeDataSentCallback(&m_request, m_largeBuffer, &m_transferBufferLength);
169  } else {
170  // Interface recipient
171  m_requestRecipients[1]->wholeDataSentCallback(&m_request, m_largeBuffer, &m_transferBufferLength);
172  }
173  }
174  break;
175  default:
177  }
178 }
179 
181  // Set IN endpoint NAK
182  OTG.DIEPCTL0()->setSNAK(true);
183 
184  // Wait for core to respond
185  while (!OTG.DIEPINT(0)->getINEPNE()) {
186  }
187 
188  // Get the Tx FIFO number
189  uint32_t fifo = OTG.DIEPCTL0()->getTXFNUM();
190 
191  // Wait for AHB idle
192  while (!OTG.GRSTCTL()->getAHBIDL()) {
193  }
194 
195  // Flush Tx FIFO
196  OTG.GRSTCTL()->setTXFNUM(fifo);
197  OTG.GRSTCTL()->setTXFFLSH(true);
198 
199  // Reset packet counter
200  OTG.DIEPTSIZ0()->set(0);
201 
202  // Wait for the flush
203  while (OTG.GRSTCTL()->getTXFFLSH()) {
204  }
205 }
206 
208  // Set OUT endpoint NAK
209  OTG.DOEPCTL0()->setSNAK(true);
210 
211  // Wait for AHB idle
212  while (!OTG.GRSTCTL()->getAHBIDL()) {
213  }
214 
215  // Flush Rx FIFO
216  OTG.GRSTCTL()->setRXFFLSH(true);
217 
218  // Reset packet counter
219  OTG.DOEPTSIZ0()->set(0);
220 
221  // Wait for the flush
222  while (OTG.GRSTCTL()->getRXFFLSH()) {
223  }
224 }
225 
227  for (int i = 0; i < m_receivedPacketSize; i += 4) {
228  OTG.DFIFO0()->get();
229  }
230  m_receivedPacketSize = 0;
231 }
232 
234  if (k_maxPacketSize < m_transferBufferLength) {
235  // More than one packet needs to be sent
236  writePacket(m_largeBuffer + m_bufferOffset, k_maxPacketSize);
237  m_state = State::DataIn;
238  m_bufferOffset += k_maxPacketSize;
239  m_transferBufferLength -= k_maxPacketSize;
240  return;
241  }
242  // Last data packet sent
243  writePacket(m_largeBuffer + m_bufferOffset, m_transferBufferLength);
244  if (m_zeroLengthPacketNeeded) {
245  m_state = State::DataIn;
246  } else {
247  m_state = State::LastDataIn;
248  }
249  m_bufferOffset = 0;
250  m_zeroLengthPacketNeeded = false;
251  m_transferBufferLength = 0;
252 }
253 
255  m_transferBufferLength = 0;
256  m_state = (wLength > k_maxPacketSize) ? State::DataOut : State::LastDataOut;
257  setOutNAK(false);
258 }
259 
260 uint16_t Endpoint0::receiveSomeData() {
261  // If it is the first chunk of data to be received, m_transferBufferLength is 0.
262  uint16_t packetSize = MIN(k_maxPacketSize, m_request.wLength() - m_transferBufferLength);
263  uint16_t sizeOfPacketRead = readPacket(m_largeBuffer + m_transferBufferLength, packetSize);
264  if (sizeOfPacketRead != packetSize) {
266  return -1;
267  }
268  m_transferBufferLength += packetSize;
269  return packetSize;
270 }
271 
272 uint16_t Endpoint0::readPacket(void * buffer, uint16_t length) {
273  uint32_t * buffer32 = (uint32_t *) buffer;
274  uint16_t buffer32Length = MIN(length, m_receivedPacketSize);
275 
276  int i;
277  // The RX FIFO is read 4 bytes by 4 bytes
278  for (i = buffer32Length; i >= 4; i -= 4) {
279  *buffer32++ = OTG.DFIFO0()->get();
280  m_receivedPacketSize -= 4;
281  }
282 
283  if (i) {
284  /* If there are remaining bytes that should be read, read the next 4 bytes
285  * and copy only the wanted bytes. */
286  uint32_t extraData = OTG.DFIFO0()->get();
287  memcpy(buffer32, &extraData, i);
288  if (m_receivedPacketSize < 4) {
289  m_receivedPacketSize = 0;
290  } else {
291  m_receivedPacketSize -= 4;
292  }
293  }
294  return buffer32Length;
295 }
296 
297 uint16_t Endpoint0::writePacket(const void * buffer, uint16_t length) {
298  const uint32_t * buffer32 = (uint32_t *) buffer;
299 
300  // Return if there is already a packet waiting to be read in the TX FIFO
301  if (OTG.DIEPTSIZ0()->getPKTCNT()) {
302  return 0;
303  }
304 
305  // Enable transmission
306 
307  class OTG::DIEPTSIZ0 dieptsiz0(0);
308  // Indicate that the Transfer Size is one packet
309  dieptsiz0.setPKTCNT(1);
310  // Indicate the length of the Transfer Size
311  dieptsiz0.setXFRSIZ(length);
312  OTG.DIEPTSIZ0()->set(dieptsiz0);
313  // Enable the endpoint
314  OTG.DIEPCTL0()->setEPENA(true);
315  // Clear the NAK bit
316  OTG.DIEPCTL0()->setCNAK(true);
317 
318  // Copy the buffer to the TX FIFO by writing data 32bits by 32 bits.
319  for (int i = length; i > 0; i -= 4) {
320  OTG.DFIFO0()->set(*buffer32++);
321  }
322 
323  return length;
324 }
325 
327  OTG.DIEPCTL0()->setSTALL(true);
328  m_state = State::Idle;
329 }
330 
332  if (m_transferBufferLength
333  && m_transferBufferLength < m_request.wLength()
334  && m_transferBufferLength % k_maxPacketSize == 0)
335  {
336  m_zeroLengthPacketNeeded = true;
337  return;
338  }
339  m_zeroLengthPacketNeeded = false;
340 }
341 
342 }
343 }
344 }
bool processSetupRequest(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength, uint16_t transferBufferMaxLength)
void clearForOutTransactions(uint16_t wLength)
Definition: endpoint0.cpp:254
static constexpr int k_maxPacketSize
Definition: endpoint0.h:25
unsigned short uint16_t
Definition: stdint.h:5
unsigned char uint8_t
Definition: stdint.h:4
void set(Register< T > value) volatile
Definition: register.h:12
T get() volatile
Definition: register.h:18
virtual void wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength)
constexpr volatile DIEPINT * DIEPINT(int i) const
Definition: otg.h:184
#define MIN(a, b)
Definition: endpoint0.cpp:8
unsigned int uint32_t
Definition: stdint.h:6
#define NULL
Definition: stddef.h:4
void setMPSIZ(MPSIZ s) volatile
Definition: otg.h:119
Definition: app.cpp:5
static constexpr int MaxTransferSize
Definition: endpoint0.h:26
void setOutNAK(bool nak)
Definition: endpoint0.cpp:69
virtual void wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength)
RecipientType recipientType() const
Definition: otg.h:6
Definition: backlight.h:6
void * memcpy(void *dst, const void *src, size_t n)
Definition: memcpy.c:3