USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
address.h
Go to the documentation of this file.
1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2 
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
8 the GPL2 ("Copyleft").
9 
10 Contact information
11 -------------------
12 
13 Circuits At Home, LTD
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
16 */
17 #if !defined(__ADDRESS_H__)
18 #define __ADDRESS_H__
19 
20 #include <inttypes.h>
21 #include <stddef.h>
22 #include "max3421e.h"
23 
24 
25 /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
26 /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
27 #define USB_NAK_MAX_POWER 16 //NAK binary order maximum value
28 #define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up
29 #define USB_NAK_NOWAIT 1 //Single NAK stops transfer
30 #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
31 
32 struct EpInfo
33 {
34  uint8_t epAddr; // Endpoint address
35  uint8_t maxPktSize; // Maximum packet size
36 
37  union
38  {
39  uint8_t epAttribs;
40 
41  struct
42  {
43  uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
44  uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
45  uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
46  };
47  };
48 };
49 
50 // 7 6 5 4 3 2 1 0
51 // ---------------------------------
52 // | | H | P | P | P | A | A | A |
53 // ---------------------------------
54 //
55 // H - if 1 the address is a hub address
56 // P - parent hub address
57 // A - device address / port number in case of hub
58 //
60 {
61  union
62  {
63  struct
64  {
65  uint8_t bmAddress : 3; // device address/port number
66  uint8_t bmParent : 3; // parent hub address
67  uint8_t bmHub : 1; // hub flag
68  uint8_t bmReserved : 1; // reserved, must be zerro
69  };
70  uint8_t devAddress;
71  };
72 };
73 
74 #define bmUSB_DEV_ADDR_ADDRESS 0x07
75 #define bmUSB_DEV_ADDR_PARENT 0x38
76 #define bmUSB_DEV_ADDR_HUB 0x40
77 
78 struct UsbDevice
79 {
80  EpInfo *epinfo; // endpoint info pointer
81  uint8_t address; // address
82  uint8_t epcount; // number of endpoints
83  bool lowspeed; // indicates if a device is the low speed one
84 // uint8_t devclass; // device class
85 };
86 
88 {
89 public:
90  virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
91  virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
92  virtual void FreeAddress(uint8_t addr) = 0;
93 };
94 
95 typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
96 
97 #define ADDR_ERROR_INVALID_INDEX 0xFF
98 #define ADDR_ERROR_INVALID_ADDRESS 0xFF
99 
100 template <const uint8_t MAX_DEVICES_ALLOWED>
102 {
103  EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
104 
105  uint8_t hubCounter; // hub counter is kept
106  // in order to avoid hub address duplication
107 
108  UsbDevice thePool[MAX_DEVICES_ALLOWED];
109 
110  // Initializes address pool entry
111  void InitEntry(uint8_t index)
112  {
113  thePool[index].address = 0;
114  thePool[index].epcount = 1;
115  thePool[index].lowspeed = 0;
116  thePool[index].epinfo = &dev0ep;
117  };
118  // Returns thePool index for a given address
119  uint8_t FindAddressIndex(uint8_t address = 0)
120  {
121  for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
122  {
123  if (thePool[i].address == address)
124  return i;
125  }
126  return 0;
127  };
128  // Returns thePool child index for a given parent
129  uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
130  {
131  for (uint8_t i=(start<1 || start>=MAX_DEVICES_ALLOWED) ? 1 : start; i<MAX_DEVICES_ALLOWED; i++)
132  {
133  if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
134  return i;
135  }
136  return 0;
137  };
138  // Frees address entry specified by index parameter
139  void FreeAddressByIndex(uint8_t index)
140  {
141  // Zerro field is reserved and should not be affected
142  if (index == 0)
143  return;
144 
145  // If a hub was switched off all port addresses should be freed
146  if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1)
147  {
148  for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); )
149  FreeAddressByIndex(i);
150 
151  // If the hub had the last allocated address, hubCounter should be decremented
152  if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
153  hubCounter --;
154  }
155  InitEntry(index);
156  }
157  // Initializes the whole address pool at once
158  void InitAllAddresses()
159  {
160  for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
161  InitEntry(i);
162 
163  hubCounter = 0;
164  };
165 
166 public:
167  AddressPoolImpl() : hubCounter(0)
168  {
169  // Zero address is reserved
170  InitEntry(0);
171 
172  thePool[0].address = 0;
173  thePool[0].epinfo = &dev0ep;
174  dev0ep.epAddr = 0;
175  dev0ep.maxPktSize = 8;
176  dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
177  dev0ep.bmNakPower = USB_NAK_MAX_POWER;
178 
179  InitAllAddresses();
180  };
181  // Returns a pointer to a specified address entry
182  virtual UsbDevice* GetUsbDevicePtr(uint8_t addr)
183  {
184  if (!addr)
185  return thePool;
186 
187  uint8_t index = FindAddressIndex(addr);
188 
189  return (!index) ? NULL : thePool + index;
190  };
191 
192  // Performs an operation specified by pfunc for each addressed device
194  {
195  if (!pfunc)
196  return;
197 
198  for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
199  if (thePool[i].address)
200  pfunc(thePool + i);
201  };
202  // Allocates new address
203  virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
204  {
205  /* if (parent != 0 && port == 0)
206  Serial.println("PRT:0"); */
207 
208  if (parent > 127 || port > 7)
209  return 0;
210 
211  if (is_hub && hubCounter == 7)
212  return 0;
213 
214  // finds first empty address entry starting from one
215  uint8_t index = FindAddressIndex(0);
216 
217  if (!index) // if empty entry is not found
218  return 0;
219 
220  if (parent == 0)
221  {
222  if (is_hub)
223  {
224  thePool[index].address = 0x41;
225  hubCounter ++;
226  }
227  else
228  thePool[index].address = 1;
229 
230  return thePool[index].address;
231  }
232 
233  UsbDeviceAddress addr;
234 
235  addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
236 
237  if (is_hub)
238  {
239  addr.bmHub = 1;
240  addr.bmAddress = ++hubCounter;
241  }
242  else
243  {
244  addr.bmHub = 0;
245  addr.bmAddress = port;
246  }
247  thePool[index].address = *((uint8_t*)&addr);
248 /*
249  Serial.print("Addr:");
250  Serial.print(addr.bmHub, HEX);
251  Serial.print(".");
252  Serial.print(addr.bmParent, HEX);
253  Serial.print(".");
254  Serial.println(addr.bmAddress, HEX);
255 */
256  return thePool[index].address;
257  };
258  // Empties pool entry
259  virtual void FreeAddress(uint8_t addr)
260  {
261  // if the root hub is disconnected all the addresses should be initialized
262  if (addr == 0x41)
263  {
264  InitAllAddresses();
265  return;
266  }
267  uint8_t index = FindAddressIndex(addr);
268  FreeAddressByIndex(index);
269  };
270  // Returns number of hubs attached
271  // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
272  //uint8_t GetNumHubs()
273  //{
274  // return hubCounter;
275  //};
276  //uint8_t GetNumDevices()
277  //{
278  // uint8_t counter = 0;
279 
280  // for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
281  // if (thePool[i].address != 0);
282  // counter ++;
283 
284  // return counter;
285  //};
286 };
287 
288 #endif // __ADDRESS_H__