yhash.c
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * $Id: yhash.c 29054 2017-11-01 10:09:54Z seb $
4  *
5  * Simple hash tables and device/function information store
6  *
7  * - - - - - - - - - License information: - - - - - - - - -
8  *
9  * Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
10  *
11  * Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
12  * non-exclusive license to use, modify, copy and integrate this
13  * file into your software for the sole purpose of interfacing
14  * with Yoctopuce products.
15  *
16  * You may reproduce and distribute copies of this file in
17  * source or object form, as long as the sole purpose of this
18  * code is to interface with Yoctopuce products. You must retain
19  * this notice in the distributed source file.
20  *
21  * You should refer to Yoctopuce General Terms and Conditions
22  * for additional information regarding your rights and
23  * obligations.
24  *
25  * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
26  * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
27  * WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
28  * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
29  * EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
30  * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
31  * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
32  * SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
33  * LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
34  * CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
35  * BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
36  * WARRANTY, OR OTHERWISE.
37  *
38  *********************************************************************/
39 
40 #define __FILE_ID__ "yhash"
41 #include "yhash.h"
42 #include <string.h>
43 
44 #ifdef MICROCHIP_API
45 __eds__ __attribute__((far, __section__(".yfar1"))) YHashSlot yHashTable[NB_MAX_HASH_ENTRIES];
46 #include <Yocto/yapi_ext.h>
47 #else
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include "yproto.h"
51 #ifdef WINDOWS_API
52 #include <Windows.h>
53 #endif
54 #define __eds__
60 #endif
61 
62 //#define DEBUG_YHASH
63 #ifdef DEBUG_YHASH
64 #define HLOGF(x) dbglog x;
65 #else
66 #define HLOGF(x)
67 #endif
68 
69 #ifndef MICROCHIP_API
70 static u16 usedDevYdx[NB_MAX_DEVICES/16];
71 static u16 nextDevYdx = 0;
72 #endif
73 static u8 nextCatYdx = 1;
74 static u16 nextHashEntry = 256;
75 
78 
79 #ifndef MICROCHIP_API
81 #endif
83 
86 
87 // =======================================================================
88 // Small block (16 bytes) allocator, for white pages and yellow pages
89 // =======================================================================
90 
91 #define BLK(hdl) (yHashTable[(hdl)>>1].blk[(hdl)&1])
92 #define WP(hdl) (BLK(hdl).wpEntry)
93 #define YC(hdl) (BLK(hdl).ypCateg)
94 #define YP(hdl) (BLK(hdl).ypEntry)
95 #define YA(hdl) (BLK(hdl).ypArray)
96 
98 
99 static yBlkHdl yBlkAlloc(void)
100 {
101  yBlkHdl res;
102 
103  yEnterCriticalSection(&yFreeMutex);
104  if(freeBlks != INVALID_BLK_HDL) {
105  res = freeBlks;
106  freeBlks = BLK(freeBlks).nextPtr;
107  } else {
108  yEnterCriticalSection(&yHashMutex);
109  YASSERT(nextHashEntry < NB_MAX_HASH_ENTRIES);
110  res = ((nextHashEntry++) << 1) + 1;
111  yLeaveCriticalSection(&yHashMutex);
112  BLK(res).blkId = 0;
113  BLK(res).nextPtr = INVALID_BLK_HDL;
114  freeBlks = res--;
115  HLOGF(("yBlkAlloc() uses bucket 0x%x\n",nextHashEntry));
116  }
117  HLOGF(("yBlkAlloc() returns blkHdl 0x%x\n",res));
118  BLK(res).blkId = 0;
119  BLK(res).nextPtr = INVALID_BLK_HDL;
120  yLeaveCriticalSection(&yFreeMutex);
121 
122  return res;
123 }
124 
125 static void yBlkFree(yBlkHdl hdl)
126 {
127  HLOGF(("Free blkHdl 0x%x\n",hdl));
128  yEnterCriticalSection(&yFreeMutex);
129  BLK(hdl).ydx = 0;
130  BLK(hdl).blkId = 0;
131  BLK(hdl).nextPtr = freeBlks;
132  freeBlks = hdl;
133  yLeaveCriticalSection(&yFreeMutex);
134 }
135 
137 {
138  u16 res = 0;
139 
140  while(hdl != INVALID_BLK_HDL) {
141  res++;
142  hdl = BLK(hdl).nextPtr;
143  }
144  return res;
145 }
146 
148 {
149  while(hdl != INVALID_BLK_HDL && pos > 0) {
150  hdl = BLK(hdl).nextPtr;
151  pos--;
152  }
153  return hdl;
154 }
155 
156 // =======================================================================
157 // Tiny Hash table support
158 // =======================================================================
159 
160 static u16 fletcher16(const u8 *data, u16 len, u16 virtlen)
161 {
162  u16 sum1 = 0xff, sum2 = 0xff - len, plen = 0;
163 
164  // process data
165  while (len > 0) {
166  u16 tlen = len > 21 ? 21 : len;
167  len -= tlen;
168  plen += tlen;
169  do {
170  sum1 += *data++;
171  sum2 += sum1;
172  } while (--tlen);
173  sum1 = (sum1 & 0xff) + (sum1 >> 8);
174  sum2 = (sum2 & 0xff) + (sum2 >> 8);
175  }
176  // process zero-padding
177  plen = virtlen - plen;
178  while(plen > 0) {
179  u16 tlen = plen > 21 ? 21 : plen;
180  plen -= tlen;
181  sum2 += sum1 * tlen;
182  sum2 = (sum2 & 0xff) + (sum2 >> 8);
183  }
184  sum1 = (sum1 & 0xff) + (sum1 >> 8);
185  sum2 = (sum2 & 0xff) + (sum2 >> 8);
186  return ((sum1 & 0xff) << 8) | (sum2 & 0xff);
187 }
188 
189 void yHashInit(void)
190 {
191  yStrRef empty, Module, module, HubPort,Sensor;
192  u16 i;
193 
194  HLOGF(("yHashInit\n"));
195  for(i = 0; i < 256; i++)
196  yHashTable[i].next = 0;
197  for(i = 0; i < NB_MAX_DEVICES; i++)
198  devYdxPtr[i] = INVALID_BLK_HDL;
199  for(i = 0; i < NB_MAX_DEVICES; i++)
200  funYdxPtr[i] = INVALID_BLK_HDL;
201 #ifndef MICROCHIP_API
202  memset((u8 *)usedDevYdx, 0, sizeof(usedDevYdx));
203  yInitializeCriticalSection(&yHashMutex);
204  yInitializeCriticalSection(&yFreeMutex);
205  yInitializeCriticalSection(&yWpMutex);
206  yInitializeCriticalSection(&yYpMutex);
207 #endif
208 
209  // Always init hast table with empty string and Module string
210  // This ensures they always get the same magic hash value
211  empty = yHashPutStr("");
212  Module = yHashPutStr("Module");
213  module = yHashPutStr("module");
214  HubPort = yHashPutStr("HubPort");
215  Sensor = yHashPutStr("Sensor");
216  if(empty != YSTRREF_EMPTY_STRING ||
217  Module != YSTRREF_MODULE_STRING ||
218  module != YSTRREF_mODULE_STRING ||
219  HubPort != YSTRREF_HUBPORT_STRING ||
220  Sensor != YSTRREF_SENSOR_STRING) {
221  // This should never ever happen, something is really weird
222  // No log is possible here (called within yapiInitAPI), so
223  // the best we can do to help debugging is a tight loop.
224 #ifdef MICROCHIP_API
225  while(1);
226 #else
227  YPANIC;
228 #endif
229  }
230  SerialRef = yHashPutStr(SerialNumberStr);
231 
232  yYpListHead = yBlkAlloc();
233  YC(yYpListHead).catYdx = 0;
234  YC(yYpListHead).blkId = YBLKID_YPCATEG;
235  YC(yYpListHead).name = YSTRREF_MODULE_STRING;
236  YC(yYpListHead).entries = INVALID_BLK_HDL;
237 }
238 
239 #ifndef MICROCHIP_API
240 void yHashFree(void)
241 {
242  HLOGF(("yHashFree\n"));
243  yDeleteCriticalSection(&yHashMutex);
244  yDeleteCriticalSection(&yFreeMutex);
245  yDeleteCriticalSection(&yWpMutex);
246  yDeleteCriticalSection(&yYpMutex);
247 }
248 #endif
249 
250 static yHash yHashPut(const u8 *buf, u16 len, u8 testonly)
251 {
252  u16 hash,i;
253  yHash yhash, prevhash = INVALID_HASH_IDX;
254  __eds__ u8 *p;
255 
256  hash = fletcher16(buf, len, HASH_BUF_SIZE);
257  yhash = hash & 0xff;
258 
259  yEnterCriticalSection(&yHashMutex);
260 
261  if(yHashTable[yhash].next != 0) {
262  // first entry is allocated, search chain
263  do {
264  if(yHashTable[yhash].hash == hash) {
265  // hash match, perform exact comparison
266  p = yHashTable[yhash].buff;
267  for(i = 0; i < len; i++) if(p[i] != buf[i]) break;
268  if(i == len) {
269  // data match, verify padding zeroes for a full match
270  while(i < HASH_BUF_SIZE) if(p[i++] != 0) break;
271  if(i == HASH_BUF_SIZE) {
272  // full match
273  HLOGF(("yHash found at 0x%x\n", yhash));
274  goto exit_ok;
275  }
276  }
277  }
278  // not a match, try next entry in chain
279  prevhash = yhash;
280  yhash = yHashTable[yhash].next;
281  } while(yhash != -1);
282  // not found in chain
283  if(testonly) goto exit_error;
284  YASSERT(nextHashEntry < NB_MAX_HASH_ENTRIES);
285  yhash = nextHashEntry++;
286  } else {
287  // first entry not allocated
288  if(testonly) {
289  exit_error:
290  HLOGF(("yHash entry not found\n", yhash));
291  yLeaveCriticalSection(&yHashMutex);
292  return -1;
293  }
294  }
295 
296  // create new entry
297  yHashTable[yhash].hash = hash;
298  yHashTable[yhash].next = -1;
299  p = yHashTable[yhash].buff;
300  for(i = 0; i < len; i++) p[i] = buf[i];
301  while(i < HASH_BUF_SIZE) p[i++] = 0;
302  if(prevhash != INVALID_HASH_IDX) {
303  yHashTable[prevhash].next = yhash;
304  }
305  HLOGF(("yHash added at 0x%x\n", yhash));
306 
307 exit_ok:
308  yLeaveCriticalSection(&yHashMutex);
309  return yhash;
310 }
311 
312 yHash yHashPutBuf(const u8 *buf, u16 len)
313 {
314  if(len > HASH_BUF_SIZE) len = HASH_BUF_SIZE;
315  return yHashPut(buf, len, 0);
316 }
317 
318 yHash yHashPutStr(const char *str)
319 {
320  u16 len = (u16) YSTRLEN(str);
321 
322  if(len > HASH_BUF_SIZE) len = HASH_BUF_SIZE;
323  HLOGF(("yHashPutStr('%s'):\n",str));
324  return yHashPut((const u8 *)str, len, 0);
325 }
326 
327 yHash yHashTestBuf(const u8 *buf, u16 len)
328 {
329  if(len > HASH_BUF_SIZE) len = HASH_BUF_SIZE;
330  return yHashPut(buf, len, 1);
331 }
332 
333 yHash yHashTestStr(const char *str)
334 {
335  u16 len = (u16) YSTRLEN(str);
336 
337  if(len > HASH_BUF_SIZE) len = HASH_BUF_SIZE;
338  HLOGF(("yHashTestStr('%s'):\n",str));
339  return yHashPut((const u8 *)str, len, 1);
340 }
341 
342 void yHashGetBuf(yHash yhash, u8 *destbuf, u16 bufsize)
343 {
344  __eds__ u8 *p;
345 
346  HLOGF(("yHashGetBuf(0x%x)\n",yhash));
347  YASSERT(yhash >= 0);
348 #ifdef MICROCHIP_API
349  if(yhash >= nextHashEntry || yHashTable[yhash].next == 0) {
350  // should never happen !
351  memset(destbuf, 0, bufsize);
352  return;
353  }
354 #else
355  YASSERT(yhash < nextHashEntry);
356  YASSERT(yHashTable[yhash].next != 0); // 0 means unallocated, -1 means end of chain
357 #endif
358  if(bufsize > HASH_BUF_SIZE) bufsize = HASH_BUF_SIZE;
359  p = yHashTable[yhash].buff;
360  while(bufsize-- > 0) {
361  *destbuf++ = *p++;
362  }
363 }
364 
365 void yHashGetStr(yHash yhash, char *destbuf, u16 bufsize)
366 {
367  HLOGF(("yHashGetStr(0x%x):\n",yhash));
368  yHashGetBuf(yhash, (u8 *)destbuf, bufsize);
369  destbuf[bufsize-1] = 0;
370 }
371 
372 #ifdef MICROCHIP_API
373 // safe since this is a single-thread environment
374 static char shared_hashbuf[HASH_BUF_SIZE+1];
375 #endif
376 
378 {
379 #ifdef MICROCHIP_API
380  u16 i;
381 #endif
382 
383  HLOGF(("yHashGetStrLen(0x%x)\n",yhash));
384  YASSERT(yhash >= 0);
385 #ifdef MICROCHIP_API
386  if(yhash >= nextHashEntry || yHashTable[yhash].next == 0) {
387  // should never happen
388  return 0;
389  }
390  for(i = 0; i < HASH_BUF_SIZE; i++) {
391  if(!yHashTable[yhash].buff[i]) break;
392  }
393  return i;
394 #else
395  YASSERT(yhash < nextHashEntry);
396  YASSERT(yHashTable[yhash].next != 0); // 0 means unallocated
397  return (u16) YSTRLEN((char *)yHashTable[yhash].buff);
398 #endif
399 }
400 
401 char *yHashGetStrPtr(yHash yhash)
402 {
403 #ifdef MICROCHIP_API
404  u16 i;
405 #endif
406 
407  HLOGF(("yHashGetStrPtr(0x%x)\n",yhash));
408  YASSERT(yhash >= 0);
409  YASSERT(yhash < nextHashEntry);
410  YASSERT(yHashTable[yhash].next != 0); // 0 means unallocated
411 #ifdef MICROCHIP_API
412  for(i = 0; i < HASH_BUF_SIZE; i++) {
413  char c = yHashTable[yhash].buff[i];
414  if(!c) break;
415  shared_hashbuf[i] = c;
416  }
417  shared_hashbuf[i] = 0;
418  return shared_hashbuf;
419 #else
420  return (char *)yHashTable[yhash].buff;
421 #endif
422 }
423 
424 #ifndef MICROCHIP_API
425 
430 static int yComputeRelPath(yAbsUrl* absurl, const char* rootUrl, u8 testonly)
431 {
432  int i, len;
433  while (*rootUrl == '/') rootUrl++;
434  for (i = 0; i < YMAX_HUB_URL_DEEP && *rootUrl;) {
435  for (len = 0; rootUrl[len] && rootUrl[len] != '/'; len++);
436  if ((len != 8 || memcmp(rootUrl, "bySerial", 8) != 0) &&
437  (len != 3 || memcmp(rootUrl, "api", 3) != 0)) {
438  absurl->path[i] = yHashPut((const u8 *)rootUrl, len, testonly);
439  if (absurl->path[i] == INVALID_HASH_IDX) return -1;
440  i++;
441  }
442  rootUrl += len;
443  while (*rootUrl == '/') rootUrl++;
444  }
445  if (*rootUrl && testonly) return -1;
446  return 0;
447 }
448 
454 yUrlRef yHashUrlFromRef(yUrlRef urlref, const char* rootUrl)
455 {
456  yAbsUrl huburl;
457 
458  // set all path as invalid
459  HLOGF(("yHashUrlFromRef('%s')\n", rootUrl));
460  yHashGetBuf(urlref, (u8 *)&huburl, sizeof(huburl));
461  memset(huburl.path, 0xff, sizeof(huburl.path));
462 
463  if (yComputeRelPath(&huburl, rootUrl, 0) < 0) {
464  return INVALID_HASH_IDX;
465  }
466  return yHashPut((const u8 *)&huburl, sizeof(huburl), 0);
467 }
468 
469 
474 yUrlRef yHashUrl(const char *url, const char *rootUrl, u8 testonly, char *errmsg)
475 {
476  yAbsUrl huburl;
477  int len,hostlen, domlen,iptest=0;
478  const char *end, *p;
479  const char *pos,*posplus;
480  const char *host=NULL;
481  char buffer[8];
482 
483  // set all hash as invalid
484  HLOGF(("yHashUrl('%s','%s')\n",url,rootUrl));
485  memset(&huburl, 0xff, sizeof(huburl));
486  huburl.proto = PROTO_AUTO;
487  if(*url) {
488  if (YSTRNCMP(url, "http://", 7) == 0) {
489  url += 7;
490  huburl.proto = PROTO_HTTP;
491  } else if (YSTRNCMP(url, "ws://", 5) == 0) {
492  url += 5;
493  huburl.proto = PROTO_WEBSOCKET;
494  }
495  // search for any authentication info
496  for (p = url; *p && *p != '@' && *p != '/'; p++);
497  if (*p == '@') {
498  for (p = url; *p != ':' && *p != '@'; p++);
499  if (*p != ':') {
500  if (errmsg) YSTRCPY(errmsg, YOCTO_ERRMSG_LEN, "missing authentication parameter");
501  return INVALID_HASH_IDX;
502  }
503  len = (int)(p - url);
504  if (len > HASH_BUF_SIZE) {
505  if (errmsg) YSTRCPY(errmsg, YOCTO_ERRMSG_LEN, "username too long");
506  return INVALID_HASH_IDX;
507  }
508  huburl.user = yHashPutBuf((const u8*)url, len);
509  url = ++p;
510  while (*p != '@') p++;
511  len = (int)(p - url);
512  if (len > HASH_BUF_SIZE) {
513  if (errmsg) YSTRCPY(errmsg, YOCTO_ERRMSG_LEN, "password too long");
514  return INVALID_HASH_IDX;
515  }
516  huburl.password = yHashPutBuf((const u8*)url, len);
517  url = ++p;
518  }
519  end =strchr(url,'/');
520  if(!end)
521  end = url + strlen(url);
522  pos = strchr(url,':');
523  posplus=pos+1;
524  if(pos && pos < end ){
525  len= (int)(end-posplus);
526  if(len>7){
527  if(errmsg) YSTRCPY(errmsg,YOCTO_ERRMSG_LEN,"invalid port");
528  return INVALID_HASH_IDX;
529  }
530  memcpy(buffer,posplus,len);
531  buffer[len] = '\0';
532  huburl.byip.port = atoi(buffer);
533  end =pos;
534  }else{
535  huburl.byip.port = YOCTO_DEFAULT_PORT;
536  }
537  pos = strchr(url,'.');
538  posplus=pos+1;
539  if(pos && pos < end ){
540  hostlen = (int)(pos-url);
541  if(hostlen>HASH_BUF_SIZE){
542  if(errmsg) YSTRCPY(errmsg,YOCTO_ERRMSG_LEN,"hostname too long");
543  return INVALID_HASH_IDX;
544  }
545  host = url;
546  url=posplus;
547  }else{
548  hostlen=0;
549  }
550  if(hostlen && hostlen <= 3){
551  memcpy(buffer,host,hostlen);
552  buffer[hostlen]=0;
553  iptest=atoi(buffer);
554  }
555  if(iptest && iptest< 256 && end-host < 16){
556  // this is probably an ip
557  huburl.byip.ip = yHashPutBuf((const u8*)host,(u16)(end-host));
558  }else{
559  domlen= (int)(end - url);
560  if(domlen >HASH_BUF_SIZE){
561  if(errmsg) YSTRCPY(errmsg,YOCTO_ERRMSG_LEN,"domain name too long");
562  return INVALID_HASH_IDX;
563  }
564  if (hostlen) {
565  huburl.byname.host = yHashPutBuf((const u8*)host, hostlen);
566  } else {
567  huburl.byname.host = INVALID_HASH_IDX;
568  }
569  huburl.byname.domaine = yHashPutBuf((const u8*)url,domlen);
570  }
571  }
572  if(yComputeRelPath(&huburl, rootUrl, testonly)<0){
573  return INVALID_HASH_IDX;
574  }
575  return yHashPut((const u8 *)&huburl, sizeof(huburl), testonly);
576 }
577 
578 // return port , get hash of the url an a pointer to a buffer of YOCTO_HOSTNAME_NAME len
579 yAsbUrlType yHashGetUrlPort(yUrlRef urlref, char *url, u16 *port, yAsbUrlProto *proto, yStrRef *user, yStrRef *password)
580 {
581  yAbsUrl absurl;
582 
583  // set all path as invalid
584  yHashGetBuf(urlref, (u8 *)&absurl, sizeof(absurl));
585  if (proto) *proto = absurl.proto;
586  if (user) *user = absurl.user;
587  if (password) *password = absurl.password;
588 
589  if(absurl.byusb.invalid1 ==INVALID_HASH_IDX && absurl.byusb.invalid2 == INVALID_HASH_IDX){
590  // we have an USB address
591  if (url) {
592  *url='\0';
593  }
594  if(port) *port = 0;
595  return USB_URL;
596  }else if(absurl.byip.invalid == INVALID_HASH_IDX){
597  // we have an ip address
598  if (url) {
599  yHashGetStr(absurl.byip.ip,url,16);
600  }
601  if (port) *port = absurl.byip.port;
602  return IP_URL;
603  }else{
604  char *p = url;
605  if(url) {
606  // we have an hostname
607  if(absurl.byname.host!= INVALID_HASH_IDX){
608  yHashGetStr(absurl.byname.host,p,YOCTO_HOSTNAME_NAME);
609  p = url + YSTRLEN(url);
610  *p++ = '.';
611  }
612  yHashGetStr(absurl.byname.domaine,p,(u16)(YOCTO_HOSTNAME_NAME - (p-url)));
613  }
614  if(port) *port = absurl.byname.port;
615  return NAME_URL;
616  }
617 }
618 
619 int yHashSameHub(yUrlRef url_a, yUrlRef url_b)
620 {
621  yAbsUrl absurl_a;
622  yAbsUrl absurl_b;
623 
624  // set all path as invalid
625  yHashGetBuf(url_a, (u8 *)&absurl_a, sizeof(absurl_a));
626  yHashGetBuf(url_b, (u8 *)&absurl_b, sizeof(absurl_b));
627  if (absurl_a.byname.domaine == absurl_b.byname.domaine &&
628  absurl_a.byname.host == absurl_b.byname.host &&
629  absurl_a.byname.port == absurl_b.byname.port)
630  return 1;
631  return 0;
632 }
633 
634 #endif
635 
636 // Return a hash-encoded URL for a local USB/YSB device
638 {
639  yAbsUrl huburl;
640  // set all hash as invalid
641  memset(&huburl, 0xff, sizeof(huburl));
642  huburl.proto = PROTO_AUTO;
643  // for USB we store only the serial number since
644  // we access all devices directly
645  huburl.byusb.serial = serial;
646  return yHashPut((const u8 *)&huburl, sizeof(huburl), 0);
647 }
648 
649 // Return a hash-encoded URL for our local /api
651 {
652  yAbsUrl huburl;
653  // set all hash as invalid
654  memset(&huburl, 0xff, sizeof(huburl));
655  huburl.proto = PROTO_AUTO;
656  return yHashPut((const u8 *)&huburl, sizeof(huburl), 0);
657 }
658 
659 // =======================================================================
660 // White pages support
661 // =======================================================================
662 
663 static void ypUnregister(yStrRef serial);//forward declaration
664 
665 static int wpLockCount = 0;
666 static int wpSomethingUnregistered = 0;
667 
668 static void wpExecuteUnregisterUnsec(void)
669 {
670  yBlkHdl prev = INVALID_BLK_HDL, next;
671  yBlkHdl hdl, funHdl, nextHdl;
672  // Note: do not use u16 below, because of GCC optimization bug
673  // which does not properly handle u16->u64 extension on OSX
674  unsigned devYdx;
675 
676  hdl = yWpListHead;
677  while(hdl != INVALID_BLK_HDL) {
678  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
679  next = WP(hdl).nextPtr;
680  if(WP(hdl).flags & YWP_MARK_FOR_UNREGISTER) {
681 #ifdef DEBUG_WP
682  {
683  char host[YOCTO_HOSTNAME_NAME];
684  u16 port;
685  yAsbUrlType type = yHashGetUrlPort( WP(hdl).url,host,&port);
686  switch(type){
687  case USB_URL:
688  dbglog("WP: unregister %s(0x%X) form USB\n",yHashGetStrPtr(WP(hdl).serial),WP(hdl).serial);
689  break;
690  default:
691  dbglog("WP: unregister %s(0x%X) from %s:%u\n",yHashGetStrPtr(WP(hdl).serial),WP(hdl).serial,host,port);
692  }
693  }
694 #endif
695 
696 
697  // first remove YP entry
698  ypUnregister(WP(hdl).serial);
699  // entry mark as to remove
700  if(prev == INVALID_BLK_HDL) {
701  yWpListHead = next;
702  } else {
703  WP(prev).nextPtr = next;
704  }
705  devYdx = WP(hdl).devYdx;
706  funHdl = funYdxPtr[devYdx];
707  while(funHdl != INVALID_BLK_HDL) {
708  YASSERT(YA(funHdl).blkId == YBLKID_YPARRAY);
709  nextHdl = YA(funHdl).nextPtr;
710  yBlkFree(funHdl);
711  funHdl = nextHdl;
712  }
713  funYdxPtr[devYdx] = INVALID_BLK_HDL;
714  devYdxPtr[devYdx] = INVALID_BLK_HDL;
715 #ifndef MICROCHIP_API
716  if((unsigned) nextDevYdx > devYdx) {
717  nextDevYdx = devYdx;
718  }
719  usedDevYdx[devYdx>>4] &= ~ (u16)(1 << (devYdx&15));
720  //dbglog("wpUnregister serial=%X devYdx=%d (next=%d)\n", WP(hdl).serial, devYdx, nextDevYdx);
721  freeDevYdxInfos(devYdx);
722 #endif
723  yBlkFree(hdl);
724  } else {
725  prev = hdl;
726  }
727  hdl = next;
728  }
729 }
730 
731 #ifndef DEBUG_WP_LOCK
732 
734 {
735  yEnterCriticalSection(&yWpMutex);
736  YASSERT(wpLockCount < 128);
737  wpLockCount++;
738  yLeaveCriticalSection(&yWpMutex);
739 }
740 
742 {
743  yEnterCriticalSection(&yWpMutex);
744  YASSERT(wpLockCount > 0);
745  wpLockCount--;
746  if(wpSomethingUnregistered && !wpLockCount) {
748  wpSomethingUnregistered = 0;
749  }
750  yLeaveCriticalSection(&yWpMutex);
751 }
752 
753 #else
754 
755 void wpPreventUnregisterDbg(const char *file, u32 line)
756 {
757  yEnterCriticalSection(&yWpMutex);
758  dbglog("wpPreventUnregisterDbg: %s:%d\n",file,line);
759  YASSERT(wpLockCount < 128);
760  wpLockCount++;
761  yLeaveCriticalSection(&yWpMutex);
762 }
763 
764 void wpAllowUnregisterDbg(const char *file, u32 line)
765 {
766  yEnterCriticalSection(&yWpMutex);
767  dbglog("wpAllowUnregisterDbg: %s:%d\n",file,line);
768  YASSERT(wpLockCount > 0);
769  wpLockCount--;
770  if(wpSomethingUnregistered && !wpLockCount) {
772  }
773  yLeaveCriticalSection(&yWpMutex);
774 }
775 
776 #endif
777 
778 // return :
779 // 0 -> no change
780 // 1 -> update
781 // 2 -> first register
782 
783 int wpRegister(int devYdx, yStrRef serial, yStrRef logicalName, yStrRef productName, u16 productId, yUrlRef devUrl, s8 beacon)
784 {
785  yBlkHdl prev = INVALID_BLK_HDL;
786  yBlkHdl hdl;
787  int changed=0;
788 
789  yEnterCriticalSection(&yWpMutex);
790 
791  YASSERT(devUrl != INVALID_HASH_IDX);
792  hdl = yWpListHead;
793  while(hdl != INVALID_BLK_HDL) {
794  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
795  if(WP(hdl).serial == serial) break;
796  prev = hdl;
797  hdl = WP(prev).nextPtr;
798  }
799  if(hdl == INVALID_BLK_HDL) {
800  hdl = yBlkAlloc();
801  changed = 2;
802 #ifndef MICROCHIP_API
803  if(devYdx == -1) devYdx = nextDevYdx;
804  YASSERT(!(usedDevYdx[devYdx>>4] & (1 << (devYdx&15))));
805  usedDevYdx[devYdx>>4] |= 1 << (devYdx&15);
806  if(nextDevYdx == devYdx) {
807  nextDevYdx++;
808  while(usedDevYdx[nextDevYdx>>4] & (1 << (nextDevYdx&15))) {
809  if(nextDevYdx >= NB_MAX_DEVICES) break;
810  nextDevYdx++;
811  }
812  }
813  //dbglog("wpRegister serial=%X devYdx=%d\n", serial, devYdx);
814  initDevYdxInfos(devYdx,serial);
815 #endif
816  YASSERT(devYdx < NB_MAX_DEVICES);
817  devYdxPtr[devYdx] = hdl;
818  WP(hdl).devYdx = (u8)devYdx;
819  WP(hdl).blkId = YBLKID_WPENTRY;
820  WP(hdl).serial = serial;
821  WP(hdl).name = YSTRREF_EMPTY_STRING;
822  WP(hdl).product = YSTRREF_EMPTY_STRING;
823  WP(hdl).url = devUrl;
824  WP(hdl).devid = 0;
825  WP(hdl).flags = 0;
826  if(prev == INVALID_BLK_HDL) {
827  yWpListHead = hdl;
828  } else {
829  WP(prev).nextPtr = hdl;
830  }
831 #ifdef MICROCHIP_API
832  } else if(devYdx != -1 && WP(hdl).devYdx != devYdx) {
833  // allow change of devYdx based on hub role
834  u16 oldDevYdx = WP(hdl).devYdx;
835  if(oldDevYdx < NB_MAX_DEVICES) {
836  funYdxPtr[devYdx] = funYdxPtr[oldDevYdx];
837  funYdxPtr[oldDevYdx] = INVALID_BLK_HDL;
838  devYdxPtr[devYdx] = hdl;
839  }
840  devYdxPtr[oldDevYdx] = INVALID_BLK_HDL;
841  WP(hdl).devYdx = (u8)devYdx;
842 #endif
843  }
844  if(logicalName != INVALID_HASH_IDX) {
845  if(WP(hdl).name != logicalName){
846  if(changed==0) changed=1;
847  WP(hdl).name = logicalName;
848  }
849  }
850  if(productName != INVALID_HASH_IDX) WP(hdl).product = productName;
851  if(productId != 0) WP(hdl).devid = productId;
852  WP(hdl).url = devUrl;
853  if(beacon >= 0) {
854  WP(hdl).flags = (beacon > 0 ? YWP_BEACON_ON : 0);
855  } else {
856  WP(hdl).flags &= ~YWP_MARK_FOR_UNREGISTER;
857  }
858 
859 #ifdef DEBUG_WP
860  {
861  char host[YOCTO_HOSTNAME_NAME];
862  u16 port;
863  yAsbUrlType type = yHashGetUrlPort(devUrl,host,&port);
864  switch(type){
865  case USB_URL:
866  dbglog("WP: regiser %s(0x%X) form USB (res=%d)\n",yHashGetStrPtr(serial),serial,changed);
867  break;
868  default:
869  dbglog("WP: regiser %s(0x%X) from %s:%u (res=%d)\n",yHashGetStrPtr(serial),serial,host,port,changed);
870  }
871  }
872 #endif
873 
874  yLeaveCriticalSection(&yWpMutex);
875  return changed;
876 }
877 
878 
879 
881 {
883 
884  yEnterCriticalSection(&yWpMutex);
885  if(WP(hdl).blkId == YBLKID_WPENTRY) {
886  switch(attridx) {
887  case Y_WP_SERIALNUMBER: res = WP(hdl).serial; break;
888  case Y_WP_LOGICALNAME: res = WP(hdl).name; break;
889  case Y_WP_PRODUCTNAME: res = WP(hdl).product; break;
890  case Y_WP_PRODUCTID: res = WP(hdl).devid; break;
891  case Y_WP_NETWORKURL: res = WP(hdl).url; break;
892  case Y_WP_BEACON: res = (WP(hdl).flags & YWP_BEACON_ON ? 1 : 0); break;
893  case Y_WP_INDEX: res = WP(hdl).devYdx; break;
894  }
895  }
896  yLeaveCriticalSection(&yWpMutex);
897 
898  return res;
899 }
900 
901 void wpGetSerial(yBlkHdl hdl, char *serial)
902 {
903  yEnterCriticalSection(&yWpMutex);
904  if(WP(hdl).blkId == YBLKID_WPENTRY) {
905  yHashGetStr(WP(hdl).serial, serial, YOCTO_SERIAL_LEN);
906  }
907  yLeaveCriticalSection(&yWpMutex);
908 }
909 
910 void wpGetLogicalName(yBlkHdl hdl, char *logicalName)
911 {
912  yEnterCriticalSection(&yWpMutex);
913  if(WP(hdl).blkId == YBLKID_WPENTRY) {
914  yHashGetStr(WP(hdl).name, logicalName, YOCTO_LOGICAL_LEN);
915  }
916  yLeaveCriticalSection(&yWpMutex);
917 }
918 
920 {
921  yBlkHdl next;
922  yBlkHdl hdl;
923  int retval=0;
924  yEnterCriticalSection(&yWpMutex);
925 
926  hdl = yWpListHead;
927  while(hdl != INVALID_BLK_HDL) {
928  next = WP(hdl).nextPtr;
929  if(WP(hdl).serial == serial) {
930  if( (WP(hdl).flags & YWP_MARK_FOR_UNREGISTER)==0 ) {
931  WP(hdl).flags |= YWP_MARK_FOR_UNREGISTER;
932  wpSomethingUnregistered = 1;
933  retval = 1;
934  }
935  break;
936  }
937  hdl = next;
938  }
939 
940 #ifdef DEBUG_WP
941  {
942  char host[YOCTO_HOSTNAME_NAME];
943  u16 port;
944  if (retval) {
945  yAsbUrlType type = yHashGetUrlPort( WP(hdl).url,host,&port);
946  switch(type){
947  case USB_URL:
948  dbglog("WP: mark for unregister %s(0x%X) form USB\n",yHashGetStrPtr(serial),serial);
949  break;
950  default:
951  dbglog("WP: mark for unregister %s(0x%X) from %s:%u\n",yHashGetStrPtr(serial),serial,host,port);
952  }
953  }else{
954  dbglog("WP: mark for unregister %s(0x%X) witch is unregistred!\n",yHashGetStrPtr(serial),serial);
955  }
956  }
957 #endif
958 
959  yLeaveCriticalSection(&yWpMutex);
960  return retval;
961 }
962 
963 u16 wpEntryCount(void)
964 {
965  return yBlkListLength(yWpListHead);
966 }
967 
968 int wpGetDevYdx(yStrRef serial)
969 {
970  yBlkHdl hdl;
971  int res = -1;
972 
973  yEnterCriticalSection(&yWpMutex);
974  hdl = yWpListHead;
975  while(hdl != INVALID_BLK_HDL) {
976  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
977  if(WP(hdl).serial == serial) {
978  res = WP(hdl).devYdx;
979  break;
980  }
981  hdl = WP(hdl).nextPtr;
982  }
983  yLeaveCriticalSection(&yWpMutex);
984 
985  return res;
986 }
987 
989 {
990  yBlkHdl hdl,byname;
991  YAPI_DEVICE res = -1;
992 
993  byname = INVALID_BLK_HDL;
994 
995  yEnterCriticalSection(&yWpMutex);
996  hdl = yWpListHead;
997  while(hdl != INVALID_BLK_HDL) {
998  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
999  if(WP(hdl).serial == strref) {
1000  res = strref;
1001  break;
1002  }
1003  if(WP(hdl).name == strref) byname = hdl;
1004  hdl = WP(hdl).nextPtr;
1005  }
1006  if(hdl == INVALID_BLK_HDL && byname != INVALID_BLK_HDL) {
1007  res = WP(byname).serial;
1008  }
1009  yLeaveCriticalSection(&yWpMutex);
1010 
1011  return res;
1012 }
1013 
1014 YAPI_DEVICE wpSearch(const char *device_str)
1015 {
1016  yStrRef strref = yHashTestStr(device_str);
1017  if (strref == INVALID_HASH_IDX)
1018  return -1;
1019  return wpSearchEx(strref);
1020 }
1021 
1022 
1024 {
1025  yBlkHdl hdl;
1026  YAPI_DEVICE res = -1;
1027 
1028  if(strref == INVALID_HASH_IDX)
1029  return -1;
1030 
1031  yEnterCriticalSection(&yWpMutex);
1032  hdl = yWpListHead;
1033  while(hdl != INVALID_BLK_HDL) {
1034  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1035  if(WP(hdl).name == strref) {
1036  res = WP(hdl).serial;
1037  break;
1038  }
1039  hdl = WP(hdl).nextPtr;
1040  }
1041  yLeaveCriticalSection(&yWpMutex);
1042 
1043  return res;
1044 }
1045 
1046 #ifndef MICROCHIP_API
1047 
1048 YAPI_DEVICE wpSearchByUrl(const char *host, const char *rootUrl)
1049 {
1050  yStrRef apiref;
1051  yBlkHdl hdl;
1052  YAPI_DEVICE res = -1;
1053 
1054  apiref = yHashUrl(host, rootUrl, 1,NULL);
1055  if(apiref == INVALID_HASH_IDX) return -1;
1056 
1057  yEnterCriticalSection(&yWpMutex);
1058  hdl = yWpListHead;
1059  while(hdl != INVALID_BLK_HDL) {
1060  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1061  if(WP(hdl).url == apiref) {
1062  res = WP(hdl).serial;
1063  break;
1064  }
1065  hdl = WP(hdl).nextPtr;
1066  }
1067  yLeaveCriticalSection(&yWpMutex);
1068 
1069  return res;
1070 }
1071 
1072 int wpGetAllDevUsingHubUrl( yUrlRef hubUrl, yStrRef *buffer,int sizeInStrRef)
1073 {
1074  yBlkHdl hdl;
1075  int count=0;
1076  yAbsUrl hubAbsUrl;
1077  yHashGetBuf(hubUrl, (u8 *)&hubAbsUrl, sizeof(hubAbsUrl));
1078 
1079  yEnterCriticalSection(&yWpMutex);
1080  hdl = yWpListHead;
1081  while(hdl != INVALID_BLK_HDL) {
1082  yAbsUrl absurl;
1083  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1084  yHashGetBuf(WP(hdl).url, (u8 *)&absurl, sizeof(absurl));
1085  if( absurl.byname.domaine == hubAbsUrl.byname.domaine &&
1086  absurl.byname.host == hubAbsUrl.byname.host &&
1087  absurl.byname.port == hubAbsUrl.byname.port ) {
1088  if(sizeInStrRef){
1089  *buffer++ = WP(hdl).serial;
1090  sizeInStrRef--;
1091  }
1092  count++;
1093  }
1094  hdl = WP(hdl).nextPtr;
1095  }
1096  yLeaveCriticalSection(&yWpMutex);
1097 
1098  return count;
1099 }
1100 
1101 
1103 {
1104  yBlkHdl hdl;
1105  yUrlRef urlref = INVALID_HASH_IDX;
1106 
1107  yEnterCriticalSection(&yWpMutex);
1108 
1109  hdl = yWpListHead;
1110  while(hdl != INVALID_BLK_HDL) {
1111  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1112  if(WP(hdl).serial == (u16)devdesc) {
1113  urlref=WP(hdl).url;
1114  break;
1115  }
1116  hdl = WP(hdl).nextPtr;
1117  }
1118 
1119  yLeaveCriticalSection(&yWpMutex);
1120 
1121  return urlref;
1122 }
1123 
1124 int wpGetDeviceUrl(YAPI_DEVICE devdesc, char *roothubserial, char *request, int requestsize, int *neededsize)
1125 {
1126  yBlkHdl hdl;
1127  yUrlRef hubref = INVALID_HASH_IDX;
1128  yStrRef strref = INVALID_HASH_IDX;
1129  yAbsUrl absurl,huburl;
1130  char serial[YOCTO_SERIAL_LEN];
1131  int fullsize, len,idx;
1132 
1133  yEnterCriticalSection(&yWpMutex);
1134  hdl = yWpListHead;
1135  while(hdl != INVALID_BLK_HDL) {
1136  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1137  if(WP(hdl).serial == (u16)devdesc) {
1138  hubref = WP(hdl).url;
1139  // store device serial;
1140  strref = WP(hdl).serial;
1141  break;
1142  }
1143  hdl = WP(hdl).nextPtr;
1144  }
1145  yLeaveCriticalSection(&yWpMutex);
1146  if(hubref == INVALID_HASH_IDX)
1147  return -1;
1148 
1149  yHashGetBuf(hubref, (u8 *)&absurl, sizeof(absurl));
1150  if(absurl.byusb.invalid1 == INVALID_HASH_IDX && absurl.byusb.invalid2 == INVALID_HASH_IDX) {
1151  // local device
1152  strref = absurl.byusb.serial;
1153  if(strref == 0) strref = devdesc & 0xffff; // ourself
1154  }else if( absurl.path[0] != INVALID_HASH_IDX){
1155  // sub device, need to find serial of its root hub
1156  memcpy(&huburl,&absurl,sizeof(absurl));
1157 
1158  for(idx = 0 ; idx < YMAX_HUB_URL_DEEP && huburl.path[idx] != INVALID_HASH_IDX ; idx++)
1159  huburl.path[idx] = INVALID_HASH_IDX;
1160  // search white pages by url
1161  hubref = yHashTestBuf((u8 *)&huburl, sizeof(huburl));
1162  strref = INVALID_HASH_IDX;
1163  yEnterCriticalSection(&yWpMutex);
1164  hdl = yWpListHead;
1165  while(hdl != INVALID_BLK_HDL) {
1166  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1167  if(WP(hdl).url == hubref) {
1168  strref = WP(hdl).serial;
1169  break;
1170  }
1171  hdl = WP(hdl).nextPtr;
1172  }
1173  yLeaveCriticalSection(&yWpMutex);
1174  if(strref == INVALID_HASH_IDX) return -1;
1175  }
1176 
1177  // extract root device serial
1178  if(roothubserial) {
1179  yHashGetStr(strref, roothubserial, YOCTO_SERIAL_LEN);
1180  }
1181  if(!request) requestsize = 0;
1182 
1183  if(absurl.path[0] != INVALID_HASH_IDX){
1184  if(requestsize > 10) {
1185  memcpy(request,"/bySerial/",10);
1186  request+=10;
1187  requestsize-=10;
1188  }
1189  fullsize = 11; // null-terminated slash
1190  }else{
1191  if(requestsize > 1) {
1192  *request++ = '/';
1193  requestsize--;
1194  }
1195  fullsize = 2; // null-terminated slash
1196  }
1197  // build relative url
1198  idx=0;
1199  while((strref = absurl.path[idx]) != INVALID_HASH_IDX) {
1200  yHashGetStr(strref, serial, YOCTO_SERIAL_LEN);
1201  len = (int)strlen(serial)+1;
1202  fullsize += len;
1203  if(requestsize>0 && requestsize > len) {
1204  memcpy(request, serial, len-1);
1205  request[len-1] = '/';
1206  request += len;
1207  requestsize -= len;
1208  }
1209  idx++;
1210  }
1211  if(neededsize != NULL) *neededsize = fullsize;
1212  // null-terminate request
1213  if(requestsize > 0) *request = 0;
1214 
1215  return 0;
1216 }
1217 
1218 #endif
1219 
1220 int wpGetDeviceInfo(YAPI_DEVICE devdesc, u16 *deviceid, char *productname, char *serial, char *logicalname, u8 *beacon)
1221 {
1222  yBlkHdl hdl;
1223 
1224  yEnterCriticalSection(&yWpMutex);
1225 
1226  hdl = yWpListHead;
1227  while(hdl != INVALID_BLK_HDL) {
1228  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1229  if(WP(hdl).serial == (u16)devdesc) {
1230  // entry found
1231  if(deviceid) *deviceid = WP(hdl).devid;
1232  if(productname) yHashGetStr(WP(hdl).product, productname, YOCTO_PRODUCTNAME_LEN);
1233  if(serial) yHashGetStr(WP(hdl).serial, serial, YOCTO_SERIAL_LEN);
1234  if(logicalname) yHashGetStr(WP(hdl).name, logicalname, YOCTO_LOGICAL_LEN);
1235  if(beacon) *beacon = (WP(hdl).flags & YWP_BEACON_ON ? 1 : 0);
1236  break;
1237  }
1238  hdl = WP(hdl).nextPtr;
1239  }
1240 
1241  yLeaveCriticalSection(&yWpMutex);
1242 
1243  return (hdl != INVALID_BLK_HDL ? 0 : -1);
1244 }
1245 
1246 
1247 
1248 // =======================================================================
1249 // Yellow pages support
1250 // =======================================================================
1251 
1252 // return 1 on change 0 if value are the same as the cache
1253 int ypRegister(yStrRef categ, yStrRef serial, yStrRef funcId, yStrRef funcName, int funClass, int funYdx, const char *funcVal)
1254 {
1255  yBlkHdl prev = INVALID_BLK_HDL;
1256  yBlkHdl hdl;
1257  yBlkHdl cat_hdl;
1258  yBlkHdl yahdl;
1259  u16 i, cnt;
1260  int devYdx, changed=0;
1261  const u16 *funcValWords = (const u16 *)funcVal;
1262 
1263  yEnterCriticalSection(&yYpMutex);
1264 
1265  // locate category node
1266  hdl = yYpListHead;
1267  while(hdl != INVALID_BLK_HDL) {
1268  YASSERT(YC(hdl).blkId == YBLKID_YPCATEG);
1269  if(YC(hdl).name == categ) break;
1270  prev = hdl;
1271  hdl = YC(prev).nextPtr;
1272  }
1273  if(hdl == INVALID_BLK_HDL) {
1274  hdl = yBlkAlloc();
1275  YC(hdl).catYdx = nextCatYdx++;
1276  YC(hdl).blkId = YBLKID_YPCATEG;
1277  YC(hdl).name = categ;
1278  YC(hdl).entries = INVALID_BLK_HDL;
1279  if(prev == INVALID_BLK_HDL) {
1280  yYpListHead = hdl;
1281  } else {
1282  YC(prev).nextPtr = hdl;
1283  }
1284  }
1285  cat_hdl = hdl;
1286 
1287  // locate entry node
1288  prev = INVALID_BLK_HDL;
1289  hdl = YC(cat_hdl).entries;
1290  while(hdl != INVALID_BLK_HDL) {
1291  YASSERT(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND);
1292  if(YP(hdl).serialNum == serial && YP(hdl).funcId == funcId) break;
1293  prev = hdl;
1294  hdl = YP(prev).nextPtr;
1295  }
1296  if(hdl == INVALID_BLK_HDL) {
1297  changed = 1; // new entry-> changed
1298  hdl = yBlkAlloc();
1299  if(funClass < 0 || funClass >= YOCTO_N_BASECLASSES) {
1300  funClass = 0;
1301  }
1302  YP(hdl).blkId = YBLKID_YPENTRY+funClass;
1303  YP(hdl).serialNum = serial;
1304  YP(hdl).funcId = funcId;
1305  YP(hdl).funcName = YSTRREF_EMPTY_STRING;
1306  YP(hdl).funInfo.raw = 15;
1307  for(i = 0; i < YOCTO_PUBVAL_SIZE/2; i++) {
1308  YP(hdl).funcValWords[i] = 0;
1309  }
1310  if(prev == INVALID_BLK_HDL) {
1311  YC(cat_hdl).entries = hdl;
1312  } else {
1313  YP(prev).nextPtr = hdl;
1314  }
1315  }
1316  if(funcName != INVALID_HASH_IDX) {
1317  if(YP(hdl).funcName != funcName){
1318  changed=1;
1319  YP(hdl).funcName = funcName;
1320  }
1321  }
1322  if(categ != YSTRREF_MODULE_STRING) {
1323  if(funYdx >= 0 && funYdx < 15) {
1324  YP(hdl).funInfo.raw = funYdx;
1325  } else {
1326  funYdx = YP(hdl).funInfo.v2.funydx;
1327  }
1328  devYdx = wpGetDevYdx(serial);
1329  if(devYdx >= 0) {
1330  cnt = funYdx;
1331  if(cnt == 255) { // unknown funYdx, prepare to allocate new one
1332  funYdx = 0;
1333  }
1334  prev = INVALID_BLK_HDL;
1335  yahdl = funYdxPtr[devYdx];
1336  while(yahdl != INVALID_BLK_HDL) {
1337  YASSERT(YA(yahdl).blkId == YBLKID_YPARRAY);
1338  if(cnt < 6) break;
1339  if(cnt < 255) { // known funYdx
1340  cnt -= 6;
1341  } else { // unknown funYdx
1342  funYdx += 6;
1343  }
1344  prev = yahdl;
1345  yahdl = YA(prev).nextPtr;
1346  }
1347  if(cnt == 255) {
1348  // unknown funYdx, allocate a free bucket
1349  cnt = 0;
1350  if(prev != INVALID_BLK_HDL) {
1351  for(i = 0; i < 6; i++) {
1352  if(YA(prev).entries[i] == INVALID_BLK_HDL) {
1353  yahdl = prev;
1354  cnt = i;
1355  funYdx = funYdx - 6 + i;
1356  break;
1357  }
1358  }
1359  }
1360  if (funYdx < 15){
1361  YP(hdl).funInfo.raw = funYdx;
1362  }
1363  }
1364  while(yahdl == INVALID_BLK_HDL) {
1365  yahdl = yBlkAlloc();
1366  YA(yahdl).blkId = YBLKID_YPARRAY;
1367  for(i = 0; i < 6; i++) YA(yahdl).entries[i] = INVALID_BLK_HDL;
1368  if(prev == INVALID_BLK_HDL) {
1369  funYdxPtr[devYdx] = yahdl;
1370  } else {
1371  YA(prev).nextPtr = yahdl;
1372  }
1373  if(cnt < 6) break;
1374  cnt -= 6;
1375  prev = yahdl;
1376  yahdl = YA(prev).nextPtr;
1377  }
1378  YA(yahdl).entries[cnt] = hdl;
1379  }
1380  if(funcVal != NULL) {
1381  for(i = 0; i < YOCTO_PUBVAL_SIZE/2; i++) {
1382  if(YP(hdl).funcValWords[i] != funcValWords[i]){
1383  changed = 1;
1384  YP(hdl).funcValWords[i] = funcValWords[i];
1385  }
1386  }
1387  }
1388  }
1389  yLeaveCriticalSection(&yYpMutex);
1390  return changed;
1391 }
1392 
1393 // return 1 on change 0 if value are the same as the cache
1394 // WARNING: funcVal MUST BE WORD-ALIGNED
1395 int ypRegisterByYdx(u8 devYdx, Notification_funydx funInfo, const char *funcVal, YAPI_FUNCTION *fundesc)
1396 {
1397  yBlkHdl hdl;
1398  u16 i;
1399  int funYdx = funInfo.v2.funydx;
1400  int changed=0;
1401  const u16 *funcValWords = (const u16 *)funcVal;
1402 
1403  yEnterCriticalSection(&yYpMutex);
1404 
1405  // Ignore unknown devYdx
1406  if(devYdxPtr[devYdx] != INVALID_BLK_HDL) {
1407  hdl = funYdxPtr[devYdx];
1408  while(hdl != INVALID_BLK_HDL && funYdx >= 6) {
1409 // YASSERT(YA(hdl).blkId == YBLKID_YPARRAY);
1410  if(YA(hdl).blkId != YBLKID_YPARRAY) {
1411  yLeaveCriticalSection(&yYpMutex);
1412  return 0; // discard invalid block silently
1413  }
1414  hdl = YA(hdl).nextPtr;
1415  funYdx -= 6;
1416  }
1417  // Ignore unknown funYdx
1418  if(hdl != INVALID_BLK_HDL) {
1419  YASSERT(YA(hdl).blkId == YBLKID_YPARRAY);
1420  hdl = YA(hdl).entries[funYdx];
1421  if(hdl != INVALID_BLK_HDL) {
1422  YASSERT(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND);
1423  if(funcVal) {
1424  // apply value change
1425  for(i = 0; i < YOCTO_PUBVAL_SIZE/2; i++) {
1426  if(YP(hdl).funcValWords[i] != funcValWords[i]) {
1427  YP(hdl).funcValWords[i] = funcValWords[i];
1428  changed = 1;
1429  }
1430  }
1431  if(YP(hdl).funInfo.raw != funInfo.raw) {
1432  YP(hdl).funInfo.raw = funInfo.raw;
1433  changed = 1;
1434  }
1435  }
1436  if(fundesc) {
1437  *fundesc = YP(hdl).hwId;
1438  }
1439  }
1440  }
1441  }
1442 
1443  yLeaveCriticalSection(&yYpMutex);
1444 
1445  return changed;
1446 }
1447 
1448 // return -1 on error
1449 // WARNING: funcVal MUST BE WORD-ALIGNED
1450 int ypGetAttributesByYdx(u8 devYdx, u8 funYdx, yStrRef *serial, yStrRef *logicalName, yStrRef *funcId, yStrRef *funcName, Notification_funydx *funcInfo, char *funcVal)
1451 {
1452  yBlkHdl hdl;
1453  u16 i;
1454  int res = -1;
1455  u16 *funcValWords = (u16 *)funcVal;
1456 
1457  yEnterCriticalSection(&yYpMutex);
1458 
1459  // Ignore unknown devYdx
1460  if (devYdxPtr[devYdx] != INVALID_BLK_HDL) {
1461  if (logicalName) {
1462  hdl = devYdxPtr[devYdx];
1463  *logicalName = WP(hdl).name;
1464  }
1465  hdl = funYdxPtr[devYdx];
1466  while (hdl != INVALID_BLK_HDL && funYdx >= 6) {
1467  // YASSERT(YA(hdl).blkId == YBLKID_YPARRAY);
1468  if (YA(hdl).blkId != YBLKID_YPARRAY) {
1469  yLeaveCriticalSection(&yYpMutex);
1470  return -1; // discard invalid block silently
1471  }
1472  hdl = YA(hdl).nextPtr;
1473  funYdx -= 6;
1474  }
1475  // Ignore unknown funYdx
1476  if (hdl != INVALID_BLK_HDL) {
1477  YASSERT(YA(hdl).blkId == YBLKID_YPARRAY);
1478  hdl = YA(hdl).entries[funYdx];
1479  if (hdl != INVALID_BLK_HDL) {
1480  YASSERT(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND);
1481  if (serial) {
1482  *serial = YP(hdl).serialNum;
1483  }
1484  if (funcId) {
1485  *funcId = YP(hdl).funcId;
1486  }
1487  if (funcName) {
1488  *funcName = YP(hdl).funcName;
1489  }
1490  if (funcInfo) {
1491  funcInfo->raw = YP(hdl).funInfo.raw;
1492  }
1493  if (funcVal) {
1494  // apply value change
1495  for (i = 0; i < YOCTO_PUBVAL_SIZE / 2; i++) {
1496  funcValWords[i] = YP(hdl).funcValWords[i];
1497  }
1498  }
1499  res = 0;
1500  }
1501  }
1502  }
1503  yLeaveCriticalSection(&yYpMutex);
1504  return res;
1505 }
1506 
1507 
1508 void ypGetCategory(yBlkHdl hdl, char *name, yBlkHdl *entries)
1509 {
1510  // category records are never freed
1511  if(name) yHashGetStr(YC(hdl).name, name, YOCTO_FUNCTION_LEN);
1512  if(entries) *entries = YC(hdl).entries;
1513 }
1514 
1515 int ypGetAttributes(yBlkHdl hdl, yStrRef *serial, yStrRef *funcId, yStrRef *funcName, Notification_funydx *funcInfo, char *funcVal)
1516 {
1517  yStrRef serialref = YSTRREF_EMPTY_STRING;
1518  yStrRef funcidref = YSTRREF_EMPTY_STRING;
1519  yStrRef funcnameref = YSTRREF_EMPTY_STRING;
1520  u16 i;
1521  int res = -1;
1522  u16 *funcValWords = (u16 *)funcVal;
1523 
1524  yEnterCriticalSection(&yYpMutex);
1525  if(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND) {
1526  serialref = YP(hdl).serialNum;
1527  funcidref = YP(hdl).funcId;
1528  funcnameref = YP(hdl).funcName;
1529  if(funcVal != NULL) { // intentionally not null terminated !
1530  for(i = 0; i < YOCTO_PUBVAL_SIZE/2; i++) {
1531  funcValWords[i] = YP(hdl).funcValWords[i];
1532  }
1533  }
1534  if (funcInfo)
1535  *funcInfo = YP(hdl).funInfo;
1536  res = YP(hdl).funInfo.v2.funydx;
1537  } else {
1538  if (funcInfo)
1539  funcInfo->raw = 0;
1540  if (funcVal) *funcVal = 0;
1541  }
1542  yLeaveCriticalSection(&yYpMutex);
1543 
1544  if(serial != NULL) *serial = serialref;
1545  if(funcId != NULL) *funcId = funcidref;
1546  if(funcName != NULL) *funcName = funcnameref;
1547 
1548  return res;
1549 }
1550 
1552 {
1553  int res = -1;
1554 
1555  yEnterCriticalSection(&yYpMutex);
1556  if(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND) {
1557  res =YP(hdl).blkId - YBLKID_YPENTRY;
1558  }
1559  yLeaveCriticalSection(&yYpMutex);
1560 
1561  return res;
1562 }
1563 
1564 static void ypUnregister(yStrRef serial)
1565 {
1566  yBlkHdl prev, next;
1567  yBlkHdl cat_hdl, hdl;
1568 
1569  yEnterCriticalSection(&yYpMutex);
1570 
1571  // scan all category nodes
1572  cat_hdl = yYpListHead;
1573  while(cat_hdl != INVALID_BLK_HDL) {
1574  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1575  hdl = YC(cat_hdl).entries;
1576  prev = INVALID_BLK_HDL;
1577  // scan all yp entries
1578  while(hdl != INVALID_BLK_HDL) {
1579  YASSERT(YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND);
1580  next = YP(hdl).nextPtr;
1581  if(YP(hdl).serialNum == serial) {
1582  // entry found, remove it
1583  if(prev == INVALID_BLK_HDL) {
1584  YC(cat_hdl).entries = next;
1585  } else {
1586  YP(prev).nextPtr = next;
1587  }
1588  yBlkFree(hdl);
1589  // continue search on next entries
1590  } else {
1591  prev = hdl;
1592  }
1593  hdl = next;
1594  }
1595  cat_hdl = YC(cat_hdl).nextPtr;
1596  }
1597 
1598  yLeaveCriticalSection(&yYpMutex);
1599 }
1600 
1601 #ifndef MICROCHIP_API
1602 
1603 YAPI_FUNCTION ypSearch(const char *class_str, const char *func_or_name)
1604 {
1605  yStrRef categref = INVALID_HASH_IDX;
1606  yStrRef devref, funcref;
1607  yBlkHdl cat_hdl, hdl, byname;
1608  int abstract = 0;
1609  const char *dotpos = func_or_name;
1610  char categname[HASH_BUF_SIZE];
1611  YAPI_FUNCTION res = -1;
1612  YAPI_FUNCTION best_name = -1;
1613  int i;
1614 
1615  // first search for the category node
1616  if (!strcmp(class_str, "Function")) {
1617  cat_hdl = INVALID_BLK_HDL;
1618  }else if (!strcmp(class_str, "Sensor")) {
1619  abstract = YOCTO_AKA_YSENSOR;
1620  cat_hdl = INVALID_BLK_HDL;
1621  } else {
1622  categref = yHashTestStr(class_str);
1623  if(categref == INVALID_HASH_IDX)
1624  return -2; // no device of this type so far
1625  yEnterCriticalSection(&yYpMutex);
1626  cat_hdl = yYpListHead;
1627  while(cat_hdl != INVALID_BLK_HDL) {
1628  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1629  if(YC(cat_hdl).name == categref) break;
1630  cat_hdl = YC(cat_hdl).nextPtr;
1631  }
1632  yLeaveCriticalSection(&yYpMutex);
1633  if(cat_hdl == INVALID_BLK_HDL)
1634  return -2; // no device of this type so far
1635  }
1636 
1637  // analyse function string
1638  while(*dotpos && *dotpos != '.') dotpos++;
1639  if(!*dotpos) {
1640  // search for a function by pure logical name
1641  funcref = yHashTestStr(func_or_name);
1642  if(funcref == INVALID_HASH_IDX)
1643  return -1;
1644  yEnterCriticalSection(&yYpMutex);
1645  if(categref != INVALID_HASH_IDX) {
1646  // search within defined function category
1647  hdl = YC(cat_hdl).entries;
1648  while(hdl != INVALID_BLK_HDL) {
1649  if(YP(hdl).funcName == funcref) {
1650  res = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1651  break;
1652  }
1653  hdl = YP(hdl).nextPtr;
1654  }
1655  } else {
1656  // search by pure logical name within abstract basetype
1657  hdl = INVALID_BLK_HDL;
1658  for(cat_hdl = yYpListHead; cat_hdl != INVALID_BLK_HDL; cat_hdl = YC(cat_hdl).nextPtr) {
1659  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1660  hdl = YC(cat_hdl).entries;
1661  while (hdl != INVALID_BLK_HDL) {
1662  // check functions matching abstract baseclass, skip others
1663  if ((abstract == YOCTO_AKA_YFUNCTION || YP(hdl).blkId == YBLKID_YPENTRY + abstract) && YP(hdl).funcName == funcref) {
1664  res = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1665  break;
1666  }
1667  hdl = YP(hdl).nextPtr;
1668  }
1669  if(hdl != INVALID_BLK_HDL) break;
1670  }
1671  }
1672  yLeaveCriticalSection(&yYpMutex);
1673  if(hdl != INVALID_BLK_HDL) return res;
1674  // not found, fallback to assuming that str_func is a logical name or serial number
1675  // of a module with an implicit function name (like serial.module for instance)
1676  devref = funcref;
1677  categname[0] = class_str[0] | 0x20; // lowercase first letter
1678  for(i = 1; (categname[i] = class_str[i]) != 0; i++);
1679  funcref = yHashTestStr(categname);
1680  if(funcref == INVALID_HASH_IDX)
1681  return -1;
1682  } else {
1683  if(dotpos==func_or_name){
1684  // format is ".funcid"
1685  devref = INVALID_HASH_IDX;
1686  }else{
1687  // format is "device.funcid"
1688  devref = yHashTestBuf((u8 *)func_or_name, (u16)( dotpos-func_or_name));
1689  if(devref == INVALID_HASH_IDX)
1690  return -1;
1691  }
1692  funcref = yHashTestStr(dotpos+1);
1693  if(funcref == INVALID_HASH_IDX)
1694  return -1;
1695  }
1696 
1697  if(devref!= INVALID_HASH_IDX){
1698  // locate function identified by devref.funcref by first resolving devref
1699  byname = INVALID_BLK_HDL;
1700  yEnterCriticalSection(&yWpMutex);
1701  hdl = yWpListHead;
1702  while(hdl != INVALID_BLK_HDL) {
1703  YASSERT(WP(hdl).blkId == YBLKID_WPENTRY);
1704  if(WP(hdl).serial == devref) break;
1705  if(WP(hdl).name == devref) byname = hdl;
1706  hdl = WP(hdl).nextPtr;
1707  }
1708  yLeaveCriticalSection(&yWpMutex);
1709  if(hdl == INVALID_BLK_HDL) {
1710  if(byname == INVALID_BLK_HDL)
1711  return -1;
1712  // device found by logicalname
1713  devref = WP(byname).serial;
1714  }
1715  }
1716  // device found, now we can search for function by serial.funcref
1717  yEnterCriticalSection(&yYpMutex);
1718  if(categref != INVALID_HASH_IDX) {
1719  // search within defined function category
1720  hdl = YC(cat_hdl).entries;
1721  while(hdl != INVALID_BLK_HDL) {
1722  if(devref==INVALID_HASH_IDX || YP(hdl).serialNum == devref) {
1723  if(YP(hdl).funcId == funcref) {
1724  res = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1725  break;
1726  }
1727  if (best_name != -1 && YP(hdl).funcName == funcref) {
1728  best_name = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1729  }
1730  }
1731  hdl = YP(hdl).nextPtr;
1732  }
1733  } else {
1734  // search by pure logical name within abstract basetype
1735  for(cat_hdl = yYpListHead; cat_hdl != INVALID_BLK_HDL; cat_hdl = YC(cat_hdl).nextPtr) {
1736  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1737  hdl = YC(cat_hdl).entries;
1738  while(hdl != INVALID_BLK_HDL) {
1739  // check functions matching abstract baseclass, skip others
1740  if ((abstract == YOCTO_AKA_YFUNCTION || YP(hdl).blkId == YBLKID_YPENTRY + abstract) && (devref == INVALID_HASH_IDX || YP(hdl).serialNum == devref)) {
1741  if (YP(hdl).funcId == funcref) {
1742  res = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1743  break;
1744  }
1745  if (best_name != -1 && YP(hdl).funcName == funcref) {
1746  best_name = YP(hdl).serialNum + ((u32)(YP(hdl).funcId) << 16);
1747  }
1748  }
1749  hdl = YP(hdl).nextPtr;
1750  }
1751  if(hdl != INVALID_BLK_HDL) break;
1752  }
1753  }
1754  if (res == -1 && best_name != -1) {
1755  res = best_name;
1756  }
1757  yLeaveCriticalSection(&yYpMutex);
1758 
1759  return res;
1760 }
1761 
1762 
1763 int ypGetFunctions(const char *class_str, YAPI_DEVICE devdesc, YAPI_FUNCTION prevfundesc,
1764  YAPI_FUNCTION *buffer,int maxsize,int *neededsize)
1765 {
1766  yStrRef categref = INVALID_HASH_IDX;
1767  yBlkHdl cat_hdl, hdl;
1768  int abstract = 0;
1769  int maxfun = 0, nbreturned = 0;
1770  YAPI_FUNCTION fundescr=0;
1771  int use = (prevfundesc==0);// if prefuncdesc == 0 use any functions
1772 
1773  if(class_str) {
1774  if (!strcmp(class_str, "Function")) {
1775  abstract = YOCTO_AKA_YFUNCTION;
1776  } else if (!strcmp(class_str, "Sensor")) {
1777  abstract = YOCTO_AKA_YSENSOR;
1778  } else {
1779  categref = yHashTestStr(class_str);
1780  if(categref == INVALID_HASH_IDX) {
1781  if(*neededsize) *neededsize = 0;
1782  return 0;
1783  }
1784  }
1785  }
1786  yEnterCriticalSection(&yYpMutex);
1787  for(cat_hdl = yYpListHead; cat_hdl != INVALID_BLK_HDL; cat_hdl = YC(cat_hdl).nextPtr) {
1788  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1789  if(categref == INVALID_HASH_IDX) {
1790  // search any type of function, but skip Module
1791  if(YC(cat_hdl).name == YSTRREF_MODULE_STRING) continue;
1792  } else {
1793  // search for a specific function type
1794  if(YC(cat_hdl).name != categref) continue;
1795  }
1796  hdl = YC(cat_hdl).entries;
1797  while(hdl != INVALID_BLK_HDL) {
1798  // if an abstract baseclass is specified, skip others
1799  if(abstract && YP(hdl).blkId != YBLKID_YPENTRY+abstract) {
1800  hdl = YP(hdl).nextPtr;
1801  continue;
1802  }
1803  if(devdesc == -1 || YP(hdl).serialNum == (u16)devdesc) {
1804  if(!use && prevfundesc == fundescr){
1805  use = 1;
1806  }
1807  fundescr = YP(hdl).hwId;
1808  if(use) {
1809  maxfun++;
1810  if(maxsize >= (int)sizeof(YAPI_FUNCTION)) {
1811  maxsize -= sizeof(YAPI_FUNCTION);
1812  if (buffer){
1813  *buffer++ = fundescr;
1814  nbreturned++;
1815  }
1816  }
1817  }
1818  }
1819  hdl = YP(hdl).nextPtr;
1820  }
1821  // if we were looking for a specific category, we found it
1822  if(categref != INVALID_HASH_IDX) break;
1823  }
1824  yLeaveCriticalSection(&yYpMutex);
1825 
1826  if(neededsize) *neededsize = sizeof(YAPI_FUNCTION) * maxfun;
1827  return nbreturned;
1828 }
1829 
1830 
1831 // This function should only be called after seizing ypMutex
1833 {
1834  yBlkHdl cat_hdl, hdl;
1835  yStrRef funcref, categref;
1836  char funcname[YOCTO_FUNCTION_LEN], *p;
1837 
1838  funcref = (u16)(fundesc >> 16);
1839  yHashGetStr(funcref, funcname, YOCTO_FUNCTION_LEN);
1840  funcname[0] &= ~0x20; // uppercase first letter
1841  for(p = funcname+1; *p > '9'; p++);
1842  *p = 0;
1843  categref = yHashTestStr(funcname);
1844  if(categref == INVALID_HASH_IDX)
1845  return INVALID_BLK_HDL; // no device of this type so far, should never happen
1846 
1847  cat_hdl = yYpListHead;
1848  while(cat_hdl != INVALID_BLK_HDL) {
1849  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1850  if(YC(cat_hdl).name == categref) break;
1851  cat_hdl = YC(cat_hdl).nextPtr;
1852  }
1853  if(cat_hdl == INVALID_BLK_HDL)
1854  return INVALID_BLK_HDL; // no device of this type so far, should never happen
1855 
1856  hdl = YC(cat_hdl).entries;
1857  while(hdl != INVALID_BLK_HDL) {
1858  if(YP(hdl).hwId == fundesc) {
1859  return hdl;
1860  }
1861  hdl = YP(hdl).nextPtr;
1862  }
1863  return INVALID_BLK_HDL; // device not found, most probably unplugged
1864 }
1865 
1866 int ypGetFunctionInfo(YAPI_FUNCTION fundesc, char *serial, char *funcId, char *baseType, char *funcName, char *funcVal)
1867 {
1868  yBlkHdl hdl;
1869  u16 i;
1870  u16 *funcValWords = (u16 *)funcVal;
1871 
1872  yEnterCriticalSection(&yYpMutex);
1873  hdl = functionSearch(fundesc);
1874  if(hdl != INVALID_BLK_HDL) {
1875  if(serial) yHashGetStr(YP(hdl).serialNum, serial, YOCTO_SERIAL_LEN);
1876  if(funcId) yHashGetStr(YP(hdl).funcId, funcId, YOCTO_FUNCTION_LEN);
1877  if (baseType) {
1878  int type = YOCTO_AKA_YFUNCTION;
1879  if (YP(hdl).blkId >= YBLKID_YPENTRY && YP(hdl).blkId <= YBLKID_YPENTRYEND) {
1880  type = YP(hdl).blkId - YBLKID_YPENTRY;
1881  }
1882  if (type == YOCTO_AKA_YSENSOR) {
1883  YSTRCPY(baseType, YOCTO_FUNCTION_LEN, "Sensor");
1884  } else {
1885  YSTRCPY(baseType, YOCTO_FUNCTION_LEN, "Function");
1886  }
1887  }
1888  if(funcName) yHashGetStr(YP(hdl).funcName, funcName, YOCTO_LOGICAL_LEN);
1889  if(funcVal != NULL) { // null-terminate
1890  for(i = 0; i < YOCTO_PUBVAL_SIZE/2; i++) {
1891  funcValWords[i] = YP(hdl).funcValWords[i];
1892  }
1893  funcVal[6] = 0;
1894  }
1895  } else {
1896  if(funcVal != NULL) funcVal[0] = 0;
1897  }
1898  yLeaveCriticalSection(&yYpMutex);
1899 
1900  return (hdl == INVALID_BLK_HDL ? -1 : 0);
1901 }
1902 
1903 #endif
1904 
1905 
1906 int ypGetFunctionsEx(yStrRef categref, YAPI_DEVICE devdesc, YAPI_FUNCTION prevfundesc,
1907  YAPI_FUNCTION *buffer, int maxsize, int *neededsize)
1908 {
1909  yBlkHdl cat_hdl, hdl;
1910  int abstract = 0;
1911  int maxfun = 0, nbreturned = 0;
1912  YAPI_FUNCTION fundescr = 0;
1913  int use = (prevfundesc == 0);// if prefuncdesc == 0 use any functions
1914 
1915  if (categref == YSTRREF_SENSOR_STRING) {
1916  abstract = YOCTO_AKA_YSENSOR;
1917  }
1918  yEnterCriticalSection(&yYpMutex);
1919  for (cat_hdl = yYpListHead; cat_hdl != INVALID_BLK_HDL; cat_hdl = YC(cat_hdl).nextPtr) {
1920  YASSERT(YC(cat_hdl).blkId == YBLKID_YPCATEG);
1921  if (categref == INVALID_HASH_IDX) {
1922  // search any type of function, but skip Module
1923  if (YC(cat_hdl).name == YSTRREF_MODULE_STRING) continue;
1924  } else {
1925  // search for a specific function type
1926  if (YC(cat_hdl).name != categref) continue;
1927  }
1928  hdl = YC(cat_hdl).entries;
1929  while (hdl != INVALID_BLK_HDL) {
1930  // if an abstract baseclass is specified, skip others
1931  if (abstract && YP(hdl).blkId != YBLKID_YPENTRY + abstract) {
1932  hdl = YP(hdl).nextPtr;
1933  continue;
1934  }
1935  if (devdesc == -1 || YP(hdl).serialNum == (u16)devdesc) {
1936  if (!use && prevfundesc == fundescr) {
1937  use = 1;
1938  }
1939  fundescr = YP(hdl).hwId;
1940  if (use) {
1941  maxfun++;
1942  if (maxsize >= (int)sizeof(YAPI_FUNCTION)) {
1943  maxsize -= sizeof(YAPI_FUNCTION);
1944  if (buffer) {
1945  *buffer++ = fundescr;
1946  nbreturned++;
1947  }
1948  }
1949  }
1950  }
1951  hdl = YP(hdl).nextPtr;
1952  }
1953  // if we were looking for a specific category, we found it
1954  if (categref != INVALID_HASH_IDX) break;
1955  }
1956  yLeaveCriticalSection(&yYpMutex);
1957 
1958  if (neededsize) *neededsize = sizeof(YAPI_FUNCTION) * maxfun;
1959  return nbreturned;
1960 }
1961 
1962 
1963 
1964 s16 ypFindBootloaders(yStrRef *serials, u16 maxSerials)
1965 {
1966  yBlkHdl cat_hdl, hdl;
1967  s16 res = 0;
1968 
1969  // first search for the category node
1970  yEnterCriticalSection(&yYpMutex);
1971  cat_hdl = yYpListHead;
1972  while(cat_hdl != INVALID_BLK_HDL) {
1973  if(YC(cat_hdl).name == YSTRREF_HUBPORT_STRING) break;
1974  cat_hdl = YC(cat_hdl).nextPtr;
1975  }
1976  yLeaveCriticalSection(&yYpMutex);
1977  if(cat_hdl == INVALID_BLK_HDL)
1978  return -2; // no hubPort registered so far
1979 
1980  yEnterCriticalSection(&yYpMutex);
1981  hdl = YC(cat_hdl).entries;
1982  while(hdl != INVALID_BLK_HDL) {
1983  if(YP(hdl).funcValWords[0]==WORD_TEXT_PR && YP(hdl).funcValWords[1]==WORD_TEXT_OG) {
1984  if(res++ < maxSerials) {
1985  *serials++ = YP(hdl).funcName;
1986  }
1987  }
1988  hdl = YP(hdl).nextPtr;
1989  }
1990  yLeaveCriticalSection(&yYpMutex);
1991 
1992  return res;
1993 }
1994 
1995 #ifdef MICROCHIP_API
1996 int ypGetBootDevHdl(const char *serial)
1997 {
1998  yBlkHdl cat_hdl, hdl;
1999  yStrRef serialRef;
2000  char funcid[9];
2001  s16 devYdx;
2002 
2003  serialRef = yHashTestStr(serial);
2004  if(serialRef == INVALID_HASH_IDX)
2005  return -1; // unknown serial
2006 
2007  // search for the category node
2008  yEnterCriticalSection(&yYpMutex);
2009  cat_hdl = yYpListHead;
2010  while(cat_hdl != INVALID_BLK_HDL) {
2011  if(YC(cat_hdl).name == YSTRREF_HUBPORT_STRING) break;
2012  cat_hdl = YC(cat_hdl).nextPtr;
2013  }
2014  yLeaveCriticalSection(&yYpMutex);
2015  if(cat_hdl == INVALID_BLK_HDL)
2016  return -2; // no hubPort registered so far
2017 
2018  yEnterCriticalSection(&yYpMutex);
2019  hdl = YC(cat_hdl).entries;
2020  while(hdl != INVALID_BLK_HDL) {
2021  if(YP(hdl).funcName == serialRef &&
2022  YP(hdl).funcValWords[0] == WORD_TEXT_PR &&
2023  YP(hdl).funcValWords[1] == WORD_TEXT_OG) {
2024  break;
2025  }
2026  hdl = YP(hdl).nextPtr;
2027  }
2028  yLeaveCriticalSection(&yYpMutex);
2029  if(hdl == INVALID_BLK_HDL)
2030  return -3; // serial not connected in PROG mode
2031 
2032  yHashGetStr(YP(hdl).funcId, funcid, sizeof(funcid));
2033  if(funcid[7] <'1' || funcid[7] > '4')
2034  return -3; // invalid function id
2035  devYdx = wpGetDevYdx(YP(hdl).serialNum);
2036  if(devYdx == hubDevYdx) {
2037  // The 3 root ports use devhdl 0-2
2038  return funcid[7] - '1';
2039  }
2040 
2041  // ports on shield use hub devYdx+(1..4)
2042  return devYdx + funcid[7] - '0';
2043 }
2044 #endif
2045 
2046 
2047 // Network notification format: 7x7bit (mapped to 7 chars in range 32..159)
2048 // used to represent 1 flag (RAW6BYTES) + 6 bytes
2049 // INPUT: [R765432][1076543][2107654][3210765][4321076][5432107][6543210]
2050 // OUTPUT: [R][-byte 0][-byte 1-][-byte 2-][-byte 3-][-byte 4-][-byte 5-]
2051 //
2052 // return the effective number of bytes produced; if < 6 remaining are padded with 0
2053 // input and output buffer may be the same one
2054 // encoding function is defined in yhub.c
2055 //
2056 int decodeNetFuncValV2(const u8 *p, Notification_funydx *funInfo, char *funcVal)
2057 {
2058  u16 ch = *p;
2059  int len = 0;
2060 
2061  if(ch < 32 || ch > 32+127) {
2062  return -1;
2063  }
2064  // get the 7 first bits
2065  ch -= 32;
2066  funInfo->v2.typeV2 = (ch & 0x40 ? NOTIFY_V2_6RAWBYTES : NOTIFY_V2_TYPEDDATA);
2067  // clear flag
2068  ch &= 0x3f;
2069  while(len < YOCTO_PUBVAL_SIZE) {
2070  u8 newCh = *++p;
2071  if(newCh == 0 || newCh == NOTIFY_NETPKT_STOP) {
2072  memset(funcVal+len, 0, YOCTO_PUBVAL_SIZE-len);
2073  break;
2074  }
2075  if(newCh < 32 || newCh > 32+127) {
2076  return -1;
2077  }
2078  newCh -= 32;
2079  ch = (ch << 7) + newCh;
2080  funcVal[len] = (ch >> (5-len));
2081  len++;
2082  }
2083  return len;
2084 }
2085 
YAPI_DEVICE wpSearchByNameHash(yStrRef strref)
Definition: yhash.c:1023
#define YSTRREF_SENSOR_STRING
Definition: yhash.h:66
yStrRef wpGetAttribute(yBlkHdl hdl, yWPAttribute attridx)
Definition: yhash.c:880
yCRITICAL_SECTION yYpMutex
Definition: yhash.c:59
static void wpExecuteUnregisterUnsec(void)
Definition: yhash.c:668
Definition: yhash.h:175
int decodeNetFuncValV2(const u8 *p, Notification_funydx *funInfo, char *funcVal)
Definition: yhash.c:2056
struct yAbsUrl::@53::@55 byname
#define WP(hdl)
Definition: yhash.c:92
#define YSTRREF_EMPTY_STRING
Definition: yhash.h:62
int ypGetFunctions(const char *class_str, YAPI_DEVICE devdesc, YAPI_FUNCTION prevfundesc, YAPI_FUNCTION *buffer, int maxsize, int *neededsize)
Definition: yhash.c:1763
int yHashSameHub(yUrlRef url_a, yUrlRef url_b)
Definition: yhash.c:619
void * yCRITICAL_SECTION
Definition: ydef.h:366
s16 yHash
Definition: ydef.h:212
static yBlkHdl funYdxPtr[NB_MAX_DEVICES]
Definition: yhash.c:77
static yBlkHdl functionSearch(YAPI_FUNCTION fundesc)
Definition: yhash.c:1832
void yInitializeCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:629
s32 YAPI_FUNCTION
Definition: ydef.h:217
yHash yStrRef
Definition: ydef.h:214
#define YOCTO_PRODUCTNAME_LEN
Definition: ydef.h:422
yHash yUrlRef
Definition: ydef.h:215
yCRITICAL_SECTION yFreeMutex
Definition: yhash.c:57
#define NOTIFY_V2_TYPEDDATA
Definition: ydef.h:552
yBlkHdl freeBlks
Definition: yhash.c:97
yUrlRef yHashUrlAPI(void)
Definition: yhash.c:650
#define HLOGF(x)
Definition: yhash.c:66
void yHashGetStr(yHash yhash, char *destbuf, u16 bufsize)
Definition: yhash.c:365
#define YBLKID_YPENTRY
Definition: yhash.h:89
yAsbUrlType
Definition: yhash.h:173
u16 wpEntryCount(void)
Definition: yhash.c:963
int ypRegisterByYdx(u8 devYdx, Notification_funydx funInfo, const char *funcVal, YAPI_FUNCTION *fundesc)
Definition: yhash.c:1395
static yBlkHdl devYdxPtr[NB_MAX_DEVICES]
Definition: yhash.c:76
u16 hash
Definition: yhash.h:148
static u16 nextDevYdx
Definition: yhash.c:71
void wpGetSerial(yBlkHdl hdl, char *serial)
Definition: yhash.c:901
#define HASH_BUF_SIZE
Definition: yhash.h:52
#define YSTRREF_mODULE_STRING
Definition: yhash.h:64
static u8 nextCatYdx
Definition: yhash.c:73
#define dbglog(args...)
Definition: yproto.h:413
#define YA(hdl)
Definition: yhash.c:95
static int wpLockCount
Definition: yhash.c:665
void yHashInit(void)
Definition: yhash.c:189
yAsbUrlType yHashGetUrlPort(yUrlRef urlref, char *url, u16 *port, yAsbUrlProto *proto, yStrRef *user, yStrRef *password)
Definition: yhash.c:579
int wpGetDevYdx(yStrRef serial)
Definition: yhash.c:968
#define YOCTO_SERIAL_LEN
Definition: ydef.h:420
void yLeaveCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:672
static yBlkHdl yBlkAlloc(void)
Definition: yhash.c:99
struct yAbsUrl::@53::@56 byip
#define NOTIFY_NETPKT_STOP
Definition: ydef.h:694
#define YOCTO_ERRMSG_LEN
Definition: ydef.h:418
char * yHashGetStrPtr(yHash yhash)
Definition: yhash.c:401
void yHashFree(void)
Definition: yhash.c:240
static void yBlkFree(yBlkHdl hdl)
Definition: yhash.c:125
yHash yHashTestStr(const char *str)
Definition: yhash.c:333
yCRITICAL_SECTION yWpMutex
Definition: yhash.c:58
#define YPANIC
Definition: yproto.h:453
yCRITICAL_SECTION yHashMutex
Definition: yhash.c:56
int ypGetBootDevHdl(const char *serial)
#define YP(hdl)
Definition: yhash.c:94
int wpGetDeviceUrl(YAPI_DEVICE devdesc, char *roothubserial, char *request, int requestsize, int *neededsize)
Definition: yhash.c:1124
yUrlRef yHashUrlUSB(yHash serial)
Definition: yhash.c:637
static int yComputeRelPath(yAbsUrl *absurl, const char *rootUrl, u8 testonly)
Definition: yhash.c:430
int wpGetAllDevUsingHubUrl(yUrlRef hubUrl, yStrRef *buffer, int sizeInStrRef)
Definition: yhash.c:1072
yStrRef user
Definition: yhash.h:206
void freeDevYdxInfos(int devYdx)
Definition: yapi.c:388
struct Notification_funydx::@10 v2
#define INVALID_BLK_HDL
Definition: ydef.h:220
#define YSTRCPY(dst, dstsize, src)
Definition: yproto.h:234
#define YOCTO_PUBVAL_SIZE
Definition: ydef.h:427
void ypGetCategory(yBlkHdl hdl, char *name, yBlkHdl *entries)
Definition: yhash.c:1508
#define YMAX_HUB_URL_DEEP
Definition: yhash.h:170
u16 yBlkHdl
Definition: ydef.h:213
yHash yHashPutBuf(const u8 *buf, u16 len)
Definition: yhash.c:312
#define YOCTO_FUNCTION_LEN
Definition: ydef.h:425
#define NOTIFY_V2_6RAWBYTES
Definition: ydef.h:551
static u16 usedDevYdx[NB_MAX_DEVICES/16]
Definition: yhash.c:70
YAPI_DEVICE wpSearchByUrl(const char *host, const char *rootUrl)
Definition: yhash.c:1048
#define YASSERT(x)
Definition: yproto.h:454
#define NB_MAX_HASH_ENTRIES
Definition: yhash.h:58
static yHash yHashPut(const u8 *buf, u16 len, u8 testonly)
Definition: yhash.c:250
u8 buff[HASH_BUF_SIZE]
Definition: yhash.h:150
Definition: yhash.h:187
#define BLK(hdl)
Definition: yhash.c:91
yHash yHashPutStr(const char *str)
Definition: yhash.c:318
void initDevYdxInfos(int devYdx, yStrRef serial)
Definition: yapi.c:379
yStrRef SerialRef
Definition: yhash.c:82
int ypGetFunctionInfo(YAPI_FUNCTION fundesc, char *serial, char *funcId, char *baseType, char *funcName, char *funcVal)
Definition: yhash.c:1866
#define WORD_TEXT_OG
Definition: yhash.h:70
YAPI_FUNCTION ypSearch(const char *class_str, const char *func_or_name)
Definition: yhash.c:1603
yBlkHdl yWpListHead
Definition: yhash.c:84
void wpAllowUnregisterEx(void)
Definition: yhash.c:741
int ypGetAttributes(yBlkHdl hdl, yStrRef *serial, yStrRef *funcId, yStrRef *funcName, Notification_funydx *funcInfo, char *funcVal)
Definition: yhash.c:1515
int wpMarkForUnregister(yStrRef serial)
Definition: yhash.c:919
void yEnterCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:647
yHash next
Definition: yhash.h:149
s16 ypFindBootloaders(yStrRef *serials, u16 maxSerials)
Definition: yhash.c:1964
int ypGetType(yBlkHdl hdl)
Definition: yhash.c:1551
void yHashGetBuf(yHash yhash, u8 *destbuf, u16 bufsize)
Definition: yhash.c:342
#define YSTRREF_MODULE_STRING
Definition: yhash.h:63
void wpPreventUnregisterEx(void)
Definition: yhash.c:733
yAsbUrlProto
Definition: yhash.h:179
#define YOCTO_DEFAULT_PORT
Definition: ydef.h:400
#define YOCTO_AKA_YSENSOR
Definition: ydef.h:414
yBlkHdl yBlkListSeek(yBlkHdl hdl, u16 pos)
Definition: yhash.c:147
Definition: yhash.h:174
yWPAttribute
Definition: yhash.h:76
u16 yHashGetStrLen(yHash yhash)
Definition: yhash.c:377
int ypGetAttributesByYdx(u8 devYdx, u8 funYdx, yStrRef *serial, yStrRef *logicalName, yStrRef *funcId, yStrRef *funcName, Notification_funydx *funcInfo, char *funcVal)
Definition: yhash.c:1450
#define YBLKID_WPENTRY
Definition: yhash.h:86
u16 proto
Definition: yhash.h:205
static u16 nextHashEntry
Definition: yhash.c:74
yStrRef password
Definition: yhash.h:207
#define YSTRLEN(str)
Definition: yproto.h:230
void wpGetLogicalName(yBlkHdl hdl, char *logicalName)
Definition: yhash.c:910
void yDeleteCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:682
#define YC(hdl)
Definition: yhash.c:93
u16 yBlkListLength(yBlkHdl hdl)
Definition: yhash.c:136
#define WORD_TEXT_PR
Definition: yhash.h:69
yHash yHashTestBuf(const u8 *buf, u16 len)
Definition: yhash.c:327
struct yAbsUrl::@53::@57 byusb
YAPI_DEVICE wpSearchEx(yStrRef strref)
Definition: yhash.c:988
#define INVALID_HASH_IDX
Definition: ydef.h:219
#define YBLKID_YPCATEG
Definition: yhash.h:87
char SerialNumberStr[YOCTO_SERIAL_LEN]
Definition: yhash.c:80
int wpGetDeviceInfo(YAPI_DEVICE devdesc, u16 *deviceid, char *productname, char *serial, char *logicalname, u8 *beacon)
Definition: yhash.c:1220
#define YBLKID_YPARRAY
Definition: yhash.h:88
#define YOCTO_HOSTNAME_NAME
Definition: yhash.h:171
yUrlRef yHashUrlFromRef(yUrlRef urlref, const char *rootUrl)
Definition: yhash.c:454
#define YWP_MARK_FOR_UNREGISTER
Definition: yhash.h:105
#define __eds__
Definition: yhash.c:54
static YHashSlot yHashTable[NB_MAX_HASH_ENTRIES]
Definition: yhash.c:55
yUrlRef yHashUrl(const char *url, const char *rootUrl, u8 testonly, char *errmsg)
Definition: yhash.c:474
int ypRegister(yStrRef categ, yStrRef serial, yStrRef funcId, yStrRef funcName, int funClass, int funYdx, const char *funcVal)
Definition: yhash.c:1253
YAPI_DEVICE wpSearch(const char *device_str)
Definition: yhash.c:1014
static int wpSomethingUnregistered
Definition: yhash.c:666
s32 YAPI_DEVICE
Definition: ydef.h:216
#define YSTRREF_HUBPORT_STRING
Definition: yhash.h:65
int ypGetFunctionsEx(yStrRef categref, YAPI_DEVICE devdesc, YAPI_FUNCTION prevfundesc, YAPI_FUNCTION *buffer, int maxsize, int *neededsize)
Definition: yhash.c:1906
#define YSTRNCMP(A, B, len)
Definition: yproto.h:227
yStrRef path[YMAX_HUB_URL_DEEP]
Definition: yhash.h:208
#define NB_MAX_DEVICES
Definition: yhash.h:59
#define YOCTO_AKA_YFUNCTION
Definition: ydef.h:413
yBlkHdl yYpListHead
Definition: yhash.c:85
static u16 fletcher16(const u8 *data, u16 len, u16 virtlen)
Definition: yhash.c:160
static void ypUnregister(yStrRef serial)
Definition: yhash.c:1564
#define YOCTO_N_BASECLASSES
Definition: ydef.h:415
int wpRegister(int devYdx, yStrRef serial, yStrRef logicalName, yStrRef productName, u16 productId, yUrlRef devUrl, s8 beacon)
Definition: yhash.c:783
#define YWP_BEACON_ON
Definition: yhash.h:106
#define YOCTO_LOGICAL_LEN
Definition: ydef.h:424
#define YBLKID_YPENTRYEND
Definition: yhash.h:90
yUrlRef wpGetDeviceUrlRef(YAPI_DEVICE devdesc)
Definition: yhash.c:1102


yoctopuce_altimeter
Author(s): Anja Sheppard
autogenerated on Mon Jun 10 2019 15:49:10