yprog.c
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * $Id: yprog.c 28495 2017-09-13 13:36:02Z seb $
4  *
5  * Implementation of firmware upgrade functions
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__ "yprog"
41 #include "ydef.h"
42 #ifdef YAPI_IN_YDEVICE
43 #include "Yocto/yocto.h"
44 #endif
45 #ifdef MICROCHIP_API
46 #include <Yocto/yapi_ext.h>
47 #else
48 #include "yproto.h"
49 #ifndef WINDOWS_API
50 #include <dirent.h>
51 #include <sys/stat.h>
52 #endif
53 #endif
54 #include "yhash.h"
55 #include "yjson.h"
56 #include "yprog.h"
57 #include <stdio.h>
58 //#define DEBUG_FIRMWARE
59 
60 #ifndef YAPI_IN_YDEVICE
61 // Public implementation of uProgXXX function (used only in public API).
62 // Init and Free are automatically called from yapiInit and yapiFree
63 
65 // these two variable have been extracted from FIRMWARE_CONTEXT
66 // to prevent some compiler to misalign them (GCC on raspberry PI)
69 
70 #ifdef __BORLANDC__
71 #pragma warn - 8066
72 #pragma warn - 8008
73 #pragma warn - 8065
74 #endif
75 
76 void yProgInit(void)
77 {
78  // BYN header must have an even number of bytes
79  YASSERT((sizeof(byn_head_multi)& 1) == 0);
80 
81  memset(&fctx, 0, sizeof(fctx));
82  fctx.stepA = FLASH_DONE;
83  memset(&firm_dev, 0, sizeof(firm_dev));
86 }
87 
88 void yProgFree(void)
89 {
90  int fuPending;
91  do {
92 
95  fuPending = 0;
96  } else{
97  fuPending = 1;
98  }
100  if (fuPending){
102  }
103  } while (fuPending);
104 
105  if (yContext->fuCtx.serial)
109  if (yContext->fuCtx.settings)
111  yDeleteCriticalSection(&fctx.cs);
112  memset(&fctx, 0, sizeof(fctx));
113 }
114 
115 #endif
116 
117 #ifdef MICROCHIP_API
118 static
119 #endif
120 const char* prog_GetCPUName(BootloaderSt *dev)
121 {
122  const char * res="";
123  switch(dev->devid_family){
125  switch(dev->devid_model){
126 #ifndef MICROCHIP_API
127  case PIC24FJ128DA206 :
128  return "PIC24FJ128DA206";
129  case PIC24FJ128DA106 :
130  return "PIC24FJ128DA106";
131  case PIC24FJ128DA210 :
132  return "PIC24FJ128DA210";
133  case PIC24FJ128DA110 :
134  return "PIC24FJ128DA110";
135  case PIC24FJ256DA206 :
136  return "PIC24FJ256DA206";
137  case PIC24FJ256DA106 :
138  return "PIC24FJ256DA106";
139  case PIC24FJ256DA210 :
140  return "PIC24FJ256DA210";
141  case PIC24FJ256DA110 :
142  return "PIC24FJ256DA110";
143  default:
144  res = "Unknown CPU model(family PIC24FJ256DA210)";
145  break;
146 #else
147  case PIC24FJ256DA206 :
148  return "PIC24FJ256DA206";
149  default: ;
150 #endif
151  }
152  break;
154  switch(dev->devid_model){
155 #ifndef MICROCHIP_API
156  case PIC24FJ32GB002 :
157  return "PIC24FJ32GB002";
158  case PIC24FJ64GB002 :
159  return "PIC24FJ64GB002";
160  case PIC24FJ32GB004 :
161  return "PIC24FJ32GB004";
162  case PIC24FJ64GB004 :
163  return "PIC24FJ64GB004";
164  default:
165  res= "Unknown CPU model(family PIC24FJ64GB004)";
166  break;
167 #else
168  case PIC24FJ64GB002 :
169  return "PIC24FJ64GB002";
170  default:
171  break;
172 #endif
173  }
174  break;
175  }
176  return res;
177 }
178 
179 
180 //used by yprogrammer
181 static int checkHardwareCompat(BootloaderSt *dev,const char *pictype)
182 {
183  const char *cpuname=prog_GetCPUName(dev);
184  if(YSTRICMP(cpuname,pictype)!=0){
185  return 0;
186  }
187  return 1;
188 }
189 
190 
191 
192 #ifdef MICROCHIP_API
193 
194 int IsValidBynHead(const byn_head_multi *head, u32 size, u16 flags, char *errmsg)
195 {
196  if(head->h.sign != BYN_SIGN){
197  return YERRMSG(YAPI_INVALID_ARGUMENT, "Not a firmware file");
198  }
199  if(YSTRLEN(head->h.serial) >= YOCTO_SERIAL_LEN){
200  return YERRMSG(YAPI_INVALID_ARGUMENT, "Bad serial");
201  }
202  if(YSTRLEN(head->h.product) >= YOCTO_PRODUCTNAME_LEN){
203  return YERRMSG(YAPI_INVALID_ARGUMENT, "Bad product name");
204  }
205  if(YSTRLEN(head->h.firmware) >= YOCTO_FIRMWARE_LEN){
206  return YERRMSG(YAPI_INVALID_ARGUMENT, "Bad firmware revision");
207  }
208  switch(head->h.rev) {
209  case BYN_REV_V4:
210  if( head->v4.nbzones > MAX_ROM_ZONES_PER_FILES){
211  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many zones");
212  }
213  if(head->v4.datasize != size -(sizeof(byn_head_sign)+sizeof(byn_head_v4))){
214  return YERRMSG(YAPI_INVALID_ARGUMENT, "Incorrect file size");
215  }
216  return YAPI_SUCCESS;
217  case BYN_REV_V5:
218  //we do not check prog_version on YoctoHubs on purpose
219  if( head->v5.nbzones > MAX_ROM_ZONES_PER_FILES){
220  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many zones");
221  }
222  if(head->v5.datasize != size -(sizeof(byn_head_sign)+sizeof(byn_head_v5))){
223  return YERRMSG(YAPI_INVALID_ARGUMENT, "Incorrect file size");
224  }
225  return YAPI_SUCCESS;
226  case BYN_REV_V6:
227  //we do not check prog_version on YoctoHubs on purpose
229  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many ROM zones");
230  }
232  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many FLASH zones");
233  }
234  return YAPI_SUCCESS;
235  default:
236  break;
237  }
238  return YERRMSG(YAPI_INVALID_ARGUMENT, "Please upgrade the hub device first");
239 }
240 
241 #else
242 
243 int IsValidBynHead(const byn_head_multi *head, u32 size, u16 flags, char *errmsg)
244 {
245  if(head->h.sign != BYN_SIGN){
246  return YERRMSG(YAPI_INVALID_ARGUMENT, "Not a valid .byn file");
247  }
248  if(YSTRLEN(head->h.serial) >= YOCTO_SERIAL_LEN){
249  return YERRMSG(YAPI_INVALID_ARGUMENT, "Invalid serial");
250  }
251  if(YSTRLEN(head->h.product) >= YOCTO_PRODUCTNAME_LEN){
252  return YERRMSG(YAPI_INVALID_ARGUMENT, "Invalid product name");
253  }
254  if(YSTRLEN(head->h.firmware) >= YOCTO_FIRMWARE_LEN){
255  return YERRMSG(YAPI_INVALID_ARGUMENT, "Invalid firmware revision");
256  }
257 
258  switch(head->h.rev) {
259  case BYN_REV_V4:
260  if( head->v4.nbzones > MAX_ROM_ZONES_PER_FILES){
261  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many zones in .byn file");
262  }
263  if(head->v4.datasize != size -(sizeof(byn_head_sign)+sizeof(byn_head_v4))){
264  return YERRMSG(YAPI_INVALID_ARGUMENT, "Incorrect file size or corrupt file");
265  }
266  return YAPI_SUCCESS;
267  case BYN_REV_V5:
268  if(YSTRLEN(head->v5.prog_version) >= YOCTO_SERIAL_LEN){
269  return YERRMSG(YAPI_INVALID_ARGUMENT, "Invalid programming tools revision or corrupt file");
270  }
271 #ifndef YBUILD_PATCH_WITH_BUILD
272  if((flags & YPROG_FORCE_FW_UPDATE) == 0 && head->v5.prog_version[0]){
273  int byn = atoi(head->v5.prog_version);
274  int tools=atoi(YOCTO_API_BUILD_NO);
275  if(byn>tools){
276  return YERRMSG(YAPI_VERSION_MISMATCH, "This firmware is too recent, please upgrade your VirtualHub or Yoctopuce library");
277  }
278  }
279 #endif
280  if( head->v5.nbzones > MAX_ROM_ZONES_PER_FILES){
281  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many zones in .byn file");
282  }
283  if(head->v5.datasize != size -(sizeof(byn_head_sign)+sizeof(byn_head_v5))){
284  return YERRMSG(YAPI_INVALID_ARGUMENT, "Incorrect file size or corrupt file");
285  }
286  return YAPI_SUCCESS;
287  case BYN_REV_V6:
288  if(YSTRLEN(head->v6.prog_version) >= YOCTO_SERIAL_LEN){
289  return YERRMSG(YAPI_INVALID_ARGUMENT, "Invalid programming tools revision or corrupt file");
290  }
291 #ifndef YBUILD_PATCH_WITH_BUILD
292  if ((flags & YPROG_FORCE_FW_UPDATE) == 0 && head->v6.prog_version[0]){
293  int byn = atoi(head->v6.prog_version);
294  int tools=atoi(YOCTO_API_BUILD_NO);
295  if(byn>tools){
296  return YERRMSG(YAPI_VERSION_MISMATCH, "This firmware is too recent, please upgrade your VirtualHub or Yoctopuce library");
297  }
298  }
299 #endif
301  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many ROM zones in .byn file");
302  }
304  return YERRMSG(YAPI_INVALID_ARGUMENT,"Too many FLASH zones in .byn file");
305  }
306  return YAPI_SUCCESS;
307  default:
308  break;
309  }
310  return YERRMSG(YAPI_INVALID_ARGUMENT, "Unsupported file format, please upgrade your VirtualHub or Yoctopuce library");
311 }
312 #endif
313 
314 int ValidateBynCompat(const byn_head_multi *head, u32 size, const char *serial, u16 flags, BootloaderSt *dev, char *errmsg)
315 {
316  YPROPERR(IsValidBynHead(head, size, flags, errmsg));
317  if(serial && YSTRNCMP(head->h.serial,serial,YOCTO_BASE_SERIAL_LEN)!=0){
318  return YERRMSG(YAPI_INVALID_ARGUMENT, "This BYN file is not designed for your device");
319  }
320  if(dev && !checkHardwareCompat(dev,head->h.pictype)){
321  return YERRMSG(YAPI_INVALID_ARGUMENT, "This BYN file is not designed for your device");
322  }
323  return 0;
324 }
325 
326 #ifndef MICROCHIP_API
327 // user by yprogrammer
328 int IsValidBynFile(const byn_head_multi *head, u32 size, const char *serial, u16 flags, char *errmsg)
329 {
330  HASH_SUM ctx;
331  u8 md5res[16];
332  int res;
333 
334  res = ValidateBynCompat(head, size, serial, flags, NULL, errmsg);
335  if(res == YAPI_SUCCESS && head->h.rev == BYN_REV_V6) {
336  // compute MD5
337  MD5Initialize(&ctx);
338  MD5AddData(&ctx, ((u8*)head)+BYN_MD5_OFS_V6, size-BYN_MD5_OFS_V6);
339  MD5Calculate(&ctx, md5res);
340  if(memcmp(md5res, head->v6.md5chk, 16)) {
341  return YERRMSG(YAPI_INVALID_ARGUMENT,"Invalid checksum");
342  }
343  }
344  return res;
345 }
346 #endif
347 
348 #ifdef CPU_BIG_ENDIAN
349 
350 #define BSWAP_U16(NUM) (((NUM )>> 8) | ((NUM) << 8))
351 #define BSWAP_U32(NUM) ((((NUM) >> 24) & 0xff) | (((NUM) << 8) & 0xff0000) | (((NUM) >> 8) & 0xff00) | (((NUM) << 24) & 0xff000000 ))
352 
354 {
355  head->h.sign = BSWAP_U32(head->h.sign);
356  head->h.rev = BSWAP_U16(head->h.rev);
357  switch (head->h.rev) {
358  case BYN_REV_V4:
359  head->v4.nbzones = BSWAP_U32(head->v4.nbzones);
360  head->v4.datasize = BSWAP_U32(head->v4.datasize);
361  break;
362  case BYN_REV_V5:
363  head->v5.pad = BSWAP_U16(head->v5.pad);
364  head->v5.nbzones = BSWAP_U32(head->v5.nbzones);
365  head->v5.datasize = BSWAP_U32(head->v5.datasize);
366  break;
367  case BYN_REV_V6:
368  head->v6.ROM_total_size = BSWAP_U32(head->v6.ROM_total_size);
369  head->v6.FLA_total_size = BSWAP_U32(head->v6.FLA_total_size);
370  break;
371  default:
372  break;
373  }
374 }
375 
376 void decode_byn_zone(byn_zone *zone)
377 {
378  zone->addr_page = BSWAP_U32(zone->addr_page);
379  zone->len = BSWAP_U32(zone->len);
380 }
381 
382 #endif
383 
384 
385 #if !defined(MICROCHIP_API)
386 // Return 1 if the communication channel to the device is busy
387 // Return 0 if there is no ongoing transaction with the device
389 {
390  return 0;
391 }
392 
393 
394 // Return 0 if there command was successfully queued for sending
395 // Return -1 if the output channel is busy and the command could not be sent
396 int ypSendBootloaderCmd(BootloaderSt *dev, const USB_Packet *pkt,char *errmsg)
397 {
398  return yyySendPacket(&dev->iface,pkt,errmsg);
399 }
400 
401 // Return 0 if a reply packet was available and returned
402 // Return -1 if there was no reply available or on error
403 int ypGetBootloaderReply(BootloaderSt *dev, USB_Packet *pkt,char *errmsg)
404 {
405  pktItem *ptr;
406  // clear the dest buffer to avoid any misinterpretation
407  memset(pkt->prog.raw, 0, sizeof(USB_Packet));
408  YPROPERR(yPktQueueWaitAndPopD2H(&dev->iface,&ptr,10,errmsg));
409  if(ptr){
410  yTracePtr(ptr);
411  memcpy(pkt,&ptr->pkt,sizeof(USB_Packet));
412  yFree(ptr);
413  return 0;
414  }
415  return YAPI_TIMEOUT; // not a fatal error, handled by caller
416 }
417 #endif
418 
419 
420 
421 #if !defined(MICROCHIP_API)
422 //pool a packet form usb for a specific device
423 int BlockingRead(BootloaderSt *dev,USB_Packet *pkt, int maxwait, char *errmsg)
424 {
425  pktItem *ptr;
426  YPROPERR(yPktQueueWaitAndPopD2H(&dev->iface,&ptr,maxwait,errmsg));
427  if (ptr) {
428  yTracePtr(ptr);
429  memcpy(pkt,&ptr->pkt,sizeof(USB_Packet));
430  yFree(ptr);
431  return YAPI_SUCCESS;
432  }
433  return YERR(YAPI_TIMEOUT);
434 }
435 
436 int SendDataPacket( BootloaderSt *dev,int program, u32 address, u8 *data,int nbinstr,char *errmsg)
437 {
438 
439  USB_Packet pkt;
440  //USB_Prog_Packet *pkt = &dev->iface.txqueue->pkt.prog;
441  memset(&pkt.prog,0,sizeof(USB_Prog_Packet));
442  if(program){
443  pkt.prog.pkt.type = PROG_PROG;
444  }else{
445  pkt.prog.pkt.type = PROG_VERIF;
446  }
447  pkt.prog.pkt.adress_low = address &0xffff;
448  pkt.prog.pkt.addres_high = (address>>16)&0xff;
449  if(nbinstr > MAX_INSTR_IN_PACKET){
450  nbinstr = MAX_INSTR_IN_PACKET;
451  }
452  if(nbinstr){
453  memcpy(pkt.prog.pkt.data,data,nbinstr*3);
454  pkt.prog.pkt.size= nbinstr;
455  }
456 
457  YPROPERR(ypSendBootloaderCmd(dev,&pkt,errmsg));
458  return nbinstr;
459 }
460 
461 
462 
463 int yUSBGetBooloader(const char *serial, const char * name, yInterfaceSt *iface,char *errmsg)
464 {
465 
466  int nbifaces=0;
467  yInterfaceSt *curif;
468  yInterfaceSt *runifaces=NULL;
469  int i;
470 
471  YPROPERR(yyyUSBGetInterfaces(&runifaces,&nbifaces,errmsg));
472  //inspect all interfaces
473  for(i=0, curif = runifaces ; i < nbifaces ; i++, curif++){
474  // skip real devices
475  if(curif->deviceid >YOCTO_DEVID_BOOTLOADER)
476  continue;
477 #ifdef WINDOWS_API
478  if(name !=NULL && YSTRICMP(curif->devicePath,name)==0){
479  if (iface)
480  memcpy(iface,curif,sizeof(yInterfaceSt));
481  yFree(runifaces);
482  return YAPI_SUCCESS;
483  }else
484 #endif
485  if(serial!=NULL && YSTRCMP(curif->serial,serial)==0){
486  if (iface)
487  memcpy(iface,curif,sizeof(yInterfaceSt));
488  yFree(runifaces);
489  return YAPI_SUCCESS;
490  }
491  }
492  // free all tmp ifaces
493  if(runifaces){
494  yFree(runifaces);
495  }
496  return YERR(YAPI_DEVICE_NOT_FOUND);
497 }
498 
499 #endif
500 
501 #ifndef YAPI_IN_YDEVICE
502 static int yLoadFirmwareFile(const char * filename, u8 **buffer, char *errmsg)
503 {
504  FILE *f = NULL;
505  int size;
506  int readed;
507  u8 *ptr;
508 
509  *buffer = NULL;
510  if (YFOPEN(&f, filename, "rb") != 0) {
511  return YERRMSG(YAPI_IO_ERROR, "unable to access file");
512  }
513  fseek(f, 0, SEEK_END);
514  size = (int)ftell(f);
515  if (size > 0x100000 || size <= 0){
516  fclose(f);
517  return YERR(YAPI_IO_ERROR);
518  }
519  ptr = yMalloc(size);
520  if (ptr == NULL) {
521  fclose(f);
522  return YERR(YAPI_IO_ERROR);
523  }
524  fseek(f, 0, SEEK_SET);
525  readed = (int)fread(ptr, 1, size, f);
526  fclose(f);
527  if (readed != size) {
528  yFree(ptr);
529  return YERRMSG(YAPI_IO_ERROR, "short read");
530  }
531  *buffer = ptr;
532  return size;
533 }
534 
535 
536 static void yGetFirmware(u32 ofs, u8 *dst, u16 size)
537 {
538  YASSERT(fctx.firmware);
539  YASSERT(ofs + size <= fctx.len);
540  memcpy(dst, fctx.firmware + ofs, size);
541 }
542 
543 
544 #endif
545 
546 
547 
548 #ifdef YAPI_IN_YDEVICE
549  #define ulog ylog
550  #define ulogU16 ylogU16
551  #define ulogChar ylogChar
552  #define uLogProgress(msg) yProgLogProgress(msg)
553 
554 
555  // report progress for devices and vhub
556  static void yProgLogProgress(const char *msg)
557  {
558  yEnterCriticalSection(&fctx.cs);
559  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN, msg);
560  hProgLog(msg);
561  yLeaveCriticalSection(&fctx.cs);
562  }
563 #else
564  #define ytime() ((u32) yapiGetTickCount())
565  #define Flash_ready() 1
566  #define ulog(str) dbglog("%s",str)
567  #define ulogU16(val) dbglog("%x",val)
568  #define ulogChar(val) dbglog("%c",val)
569 
570  // report progress for Yoctolib
571  #define setOsGlobalProgress(prog, msg) osProgLogProgressEx(__FILE_ID__,__LINE__, prog, msg)
572  #define uLogProgress(msg) yProgLogProgress(msg)
573 
574 
575  // report progress for devices and vhub
576  static void yProgLogProgress(const char *msg)
577  {
578  yEnterCriticalSection(&fctx.cs);
579  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN, msg);
580  yLeaveCriticalSection(&fctx.cs);
581  }
582 
583 
584  static void osProgLogProgressEx(const char *fileid, int line, int prog, const char *msg)
585  {
586  yEnterCriticalSection(&fctx.cs);
587  if (prog != 0){
589  }
590  if (msg != NULL && *msg != 0){
591 #ifdef DEBUG_FIRMWARE
592  dbglog("%s:%d:(%d%%) %s\n", fileid, line, prog, msg);
593  YSPRINTF(yContext->fuCtx.global_message, YOCTO_ERRMSG_LEN, "%s:%d:%s", fileid, line, msg);
594 #else
596 #endif
597  }
598  yLeaveCriticalSection(&fctx.cs);
599  }
600 
601 #endif
602 
603 #ifdef MICROCHIP_API
604 #define uGetBootloader(serial,ifaceptr) yGetBootloaderPort(serial,ifaceptr)
605 #else
606 #define uGetBootloader(serial,ifaceptr) yUSBGetBooloader(serial, NULL, ifaceptr,NULL)
607 #endif
608 
609 
610 
611 
612 //-1 = error 0= retry 1= ok (the global fctx.stepA is allready updated)
613 static int uGetDeviceInfo(void)
614 {
615  switch(fctx.stepB){
616  case 0:
617  fctx.stepB++;
619  // no break on purpose;
620  case 1:
621  memset(&firm_pkt,0,sizeof(USB_Prog_Packet));
622  firm_pkt.prog.pkt.type = PROG_INFO;
623  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
624  if((s32)(fctx.timeout - ytime()) < 0) {
625 #ifdef DEBUG_FIRMWARE
626  ulog("Cannot send GetInfo pkt\n");
627 #endif
628  YSTRCPY(fctx.errmsg, FLASH_ERRMSG_LEN, "Cannot send GetInfo");
629  return -1;
630  }
631  return 0;
632  }
633  fctx.stepB++;
635  // no break on purpose;
636  case 2:
637  if(ypGetBootloaderReply(&firm_dev, &firm_pkt,NULL)<0){
638  if((s32)(fctx.timeout - ytime()) < 0) {
639 #ifdef DEBUG_FIRMWARE
640  ulog("Bootloader did not respond to GetInfo pkt\n");
641 #endif
642  YSTRCPY(fctx.errmsg, FLASH_ERRMSG_LEN, "Cannot recv GetInfo");
643  return -1;
644  }
645  return 0;
646  }
647  fctx.stepB++;
648  // no break on purpose;
649  case 3:
650  if(firm_pkt.prog.pkt.type == PROG_INFO) {
651 #ifdef DEBUG_FIRMWARE
652  ulog("PROG_INFO received\n");
653 #endif
654  firm_dev.er_blk_size = DECODE_U16(firm_pkt.prog.pktinfo.er_blk_size);
655  firm_dev.pr_blk_size = DECODE_U16(firm_pkt.prog.pktinfo.pr_blk_size);
656  firm_dev.last_addr = DECODE_U32(firm_pkt.prog.pktinfo.last_addr);
657  firm_dev.settings_addr = DECODE_U32(firm_pkt.prog.pktinfo.settings_addr);
658  firm_dev.devid_family = DECODE_U16(firm_pkt.prog.pktinfo.devidl)>>8;
659  firm_dev.devid_model = DECODE_U16(firm_pkt.prog.pktinfo.devidl) & 0xff;
660  firm_dev.devid_rev = DECODE_U16(firm_pkt.prog.pktinfo.devidh);
661  firm_dev.startconfig = DECODE_U32(firm_pkt.prog.pktinfo.config_start);
662  firm_dev.endofconfig = DECODE_U32(firm_pkt.prog.pktinfo.config_stop);
663 #ifndef MICROCHIP_API
664  firm_dev.ext_jedec_id = 0xffff;
665  firm_dev.ext_page_size = 0xffff;
666  firm_dev.ext_total_pages = 0;
667  firm_dev.first_code_page = 0xffff;
668  firm_dev.first_yfs3_page = 0xffff;
669 #endif
670  uLogProgress("Device info retrieved");
671  fctx.stepB = 0;
672  fctx.stepA = FLASH_VALIDATE_BYN;
673 #ifndef MICROCHIP_API
674  } else if(firm_pkt.prog.pkt.type == PROG_INFO_EXT) {
675 #ifdef DEBUG_FIRMWARE
676  ulog("PROG_INFO_EXT received\n");
677 #endif
678  firm_dev.er_blk_size = DECODE_U16(firm_pkt.prog.pktinfo_ext.er_blk_size);
679  firm_dev.pr_blk_size = DECODE_U16(firm_pkt.prog.pktinfo_ext.pr_blk_size);
680  firm_dev.last_addr = DECODE_U32(firm_pkt.prog.pktinfo_ext.last_addr);
682  firm_dev.devid_family = DECODE_U16(firm_pkt.prog.pktinfo_ext.devidl) >> 8;
683  firm_dev.devid_model = DECODE_U16(firm_pkt.prog.pktinfo_ext.devidl) & 0xff;
684  firm_dev.devid_rev = DECODE_U16(firm_pkt.prog.pktinfo_ext.devidh);
685  firm_dev.startconfig = DECODE_U32(firm_pkt.prog.pktinfo_ext.config_start);
686  firm_dev.endofconfig = DECODE_U32(firm_pkt.prog.pktinfo_ext.config_stop);
687  firm_dev.ext_jedec_id = DECODE_U16(firm_pkt.prog.pktinfo_ext.ext_jedec_id);
692  uLogProgress("Device info retrieved");
693  fctx.stepB = 0;
694  fctx.stepA = FLASH_VALIDATE_BYN;
695 #endif
696  } else {
697 #ifdef DEBUG_FIRMWARE
698  ulog("Not a PROG_INFO pkt\n");
699 #endif
700  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Invalid prog pkt");
701  return -1;
702  }
703  return 1;
704 #ifdef DEBUG_FIRMWARE
705  default:
706  ulog("invalid step in uGetDeviceInfo\n");
707  break;
708 #endif
709  }
710  return 0;
711 }
712 
713 
714 
715 
716 static int uSendCmd(u8 cmd,FLASH_DEVICE_STATE nextState)
717 {
718  if(ypIsSendBootloaderBusy(&firm_dev)) {
719  return 0;
720  }
721  memset(&firm_pkt,0,sizeof(USB_Packet));
722  firm_pkt.prog.pkt.type = cmd;
723  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
724  return -1;
725  }
726  fctx.stepA = nextState;
727  return 1;
728 }
729 
730 static int uFlashZone()
731 {
732  u16 datasize;
733  char msg[FLASH_ERRMSG_LEN];
734 
735  switch(fctx.zst){
736  case FLASH_ZONE_START:
737  if(fctx.currzone == fctx.bynHead.v6.ROM_nb_zone + fctx.bynHead.v6.FLA_nb_zone){
739  fctx.stepB = 0;
741  return 0;
742  }
743  uGetFirmwareBynZone(fctx.zOfs, &fctx.bz);
744  YSTRCPY(msg, FLASH_ERRMSG_LEN, "Flash zone");
745 #if defined(DEBUG_FIRMWARE)
746 #ifdef MICROCHIP_API
747  {
748  char *p = msg + 10;
749  *p++ = ' ';
750  u16toa(fctx.currzone, p);
751  p += ystrlen(p);
752  *p++ = ':';
753  u32toa(fctx.zOfs, p);
754  p += ystrlen(p);
755  }
756 #else
757  YSPRINTF(msg, FLASH_ERRMSG_LEN, "Flash zone %d:%d : %x(%x)", fctx.currzone, fctx.zOfs, fctx.bz.addr_page, fctx.bz.len);
758  dbglog("Flash zone %d:%x : %x(%x)\n",fctx.currzone,fctx.zOfs,fctx.bz.addr_page,fctx.bz.len);
759 #endif
760 #endif
761  uLogProgress(msg);
762  if((fctx.bz.addr_page % (firm_dev.pr_blk_size*2)) !=0 ) {
763  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"ProgAlign");
764  return -1;
765  }
766  fctx.zOfs += sizeof(byn_zone);
767  fctx.zNbInstr = fctx.bz.len/3;
768  fctx.stepB = 0;
769  if(fctx.zNbInstr < (u32)firm_dev.pr_blk_size){
770  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"ProgSmall");
771  return -1;
772  }
773  fctx.zst = FLASH_ZONE_PROG;
774  //no break on purpose
775  case FLASH_ZONE_PROG:
776  if(ypIsSendBootloaderBusy(&firm_dev)) {
777  return 0;
778  }
779  memset(&firm_pkt,0,sizeof(USB_Packet));
780  firm_pkt.prog.pkt.type = PROG_PROG;
781  firm_pkt.prog.pkt.adress_low = DECODE_U16(fctx.bz.addr_page & 0xffff);
782  firm_pkt.prog.pkt.addres_high = (fctx.bz.addr_page>>16) & 0xff;
783  firm_pkt.prog.pkt.size = (u8) (fctx.zNbInstr < MAX_INSTR_IN_PACKET? fctx.zNbInstr : MAX_INSTR_IN_PACKET) ;
784 
785  datasize = firm_pkt.prog.pkt.size*3;
786  uGetFirmware(fctx.zOfs, firm_pkt.prog.pkt.data, datasize);
787  //dbglog("Flash zone %d:0x%x 0x%x(%d /%d)\n", fctx.currzone, fctx.zOfs, fctx.bz.addr_page, fctx.stepB, firm_dev.pr_blk_size);
788  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
789  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"ProgPkt");
790  return -1;
791  }
792 
793  fctx.zOfs += datasize;
794  fctx.zNbInstr -= firm_pkt.prog.pkt.size;
795  fctx.stepB += firm_pkt.prog.pkt.size;
796  fctx.progress = (u16)(4 + 92*fctx.zOfs / fctx.len);
797 
798  if( fctx.stepB >= firm_dev.pr_blk_size){
799  //look for confirmation
801  fctx.zst = FLASH_ZONE_RECV_OK;
802  }
803  break;
804  case FLASH_ZONE_RECV_OK:
805  if(ypGetBootloaderReply(&firm_dev, &firm_pkt,NULL)<0){
806  if((s32)(fctx.timeout - ytime()) < 0) {
807 #if defined(DEBUG_FIRMWARE) && !defined(MICROCHIP_API)
808  dbglog("Bootlaoder did not send confirmation for Zone %x Block %x\n",fctx.currzone,fctx.bz.addr_page);
809 #endif
810  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"ProgDead");
811  return -1;
812  }
813  return 0;
814  }
815  if(firm_pkt.prog.pkt.type != PROG_PROG){
816  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"ProgReply");
817  return -1;
818  }else{
819  u32 newblock = ((u32)firm_pkt.prog.pkt.addres_high <<16) | DECODE_U16(firm_pkt.prog.pkt.adress_low);
820  //uLogProgress("Block %x to %x is done",fctx.zStartAddr,newblock);
821  fctx.bz.addr_page = newblock;
822  }
823  fctx.stepB = fctx.stepB - firm_dev.pr_blk_size;
824  if(fctx.zNbInstr==0){
825  fctx.zst = FLASH_ZONE_START;
826  fctx.currzone++;
827  }else{
828  fctx.zst = FLASH_ZONE_PROG;
829  }
830  break;
831  default:
832  YASSERT(0);
833  }
834 
835  return 0;
836 }
837 
838 
839 
840 #ifndef MICROCHIP_API
841 
842 static void uSendReboot(u16 signature, FLASH_DEVICE_STATE nextState)
843 {
844  if(ypIsSendBootloaderBusy(&firm_dev))
845  return;
846  memset(&firm_pkt,0,sizeof(USB_Packet));
847  firm_pkt.prog.pkt_ext.type = PROG_REBOOT;
848  firm_pkt.prog.pkt_ext.opt.btsign = DECODE_U16(signature);
849  // do not check reboot packet on purpose (most of the time
850  // the os generate an error because the device rebooted too quickly)
851  ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL);
852  fctx.stepA = nextState;
853  return;
854 }
855 
856 static int uSendErase(u16 firstPage, u16 nPages, FLASH_DEVICE_STATE nextState)
857 {
858  if(ypIsSendBootloaderBusy(&firm_dev))
859  return 0;
860  memset(&firm_pkt,0,sizeof(USB_Packet));
861  firm_pkt.prog.pkt_ext.type = PROG_ERASE;
862  SET_PROG_POS_PAGENO(firm_pkt.prog.pkt_ext, firstPage, 0);
863  firm_pkt.prog.pkt_ext.opt.npages = DECODE_U16(nPages);
864  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
865  return -1;
866  }
867  fctx.stepA = nextState;
868  return 0;
869 }
870 
871 static int uFlashFlash()
872 {
873  u32 addr, datasize;
874  u8 buff[MAX_BYTE_IN_PACKET];
875  char msg[FLASH_ERRMSG_LEN];
876  u32 pos, pageno;
877 
878  switch(fctx.zst){
879  case FLASH_ZONE_START:
880  if(fctx.currzone == fctx.bynHead.v6.ROM_nb_zone + fctx.bynHead.v6.FLA_nb_zone){
881  fctx.stepA = FLASH_AUTOFLASH;
882  return 0;
883  }
884  uGetFirmwareBynZone(fctx.zOfs, &fctx.bz);
885  if(fctx.currzone < fctx.bynHead.v6.ROM_nb_zone) {
886  fctx.bz.addr_page = (u32)firm_dev.first_code_page * firm_dev.ext_page_size + 3*fctx.bz.addr_page/2;
887  } else {
888  fctx.bz.addr_page = (u32)firm_dev.first_yfs3_page * firm_dev.ext_page_size + fctx.bz.addr_page;
889  }
890 #ifdef DEBUG_FIRMWARE
891  dbglog("Flash zone %d:%x : %x(%x)\n",fctx.currzone,fctx.zOfs,fctx.bz.addr_page,fctx.bz.len);
892 #endif
893  YSPRINTF(msg, FLASH_ERRMSG_LEN, "Flash zone %d:%x : %x(%x)",fctx.currzone,fctx.zOfs,fctx.bz.addr_page,fctx.bz.len);
894  uLogProgress(msg);
895 
896  if((fctx.bz.addr_page & 1) != 0 || (fctx.bz.len & 1) != 0) {
897  dbglog("Prog block not on a word boundary (%d+%d)\n", fctx.bz.addr_page, fctx.bz.len);
898  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Prog block not on a word boundary");
899  return -1;
900  }
901  fctx.zOfs += sizeof(byn_zone);
902  fctx.stepB = 0;
903  fctx.zst = FLASH_ZONE_PROG;
904  //no break on purpose
905  case FLASH_ZONE_PROG:
906  if(fctx.bz.len > 0 && fctx.currzone < fctx.bynHead.v6.ROM_nb_zone &&
907  fctx.bz.addr_page >= (u32)firm_dev.first_yfs3_page * firm_dev.ext_page_size) {
908  // skip end of ROM image past reserved flash zone
909 #ifdef DEBUG_FIRMWARE
910  dbglog("Drop ROM data past firmware boundary (zone %d at offset %x)\n", fctx.currzone, fctx.zOfs);
911 #endif
912  fctx.zOfs += fctx.bz.len;
913  fctx.bz.len = 0;
914  fctx.zst = FLASH_ZONE_START;
915  fctx.currzone++;
916  return 0;
917  }
918  addr = fctx.bz.addr_page + fctx.stepB;
919  memset(&firm_pkt,0,sizeof(USB_Packet));
920 
921  SET_PROG_POS_PAGENO(firm_pkt.prog.pkt_ext, addr / firm_dev.ext_page_size, addr >> 2);
922  datasize = firm_dev.ext_page_size - (addr & (firm_dev.ext_page_size-1));
923  if(datasize > MAX_BYTE_IN_PACKET) {
924  datasize = MAX_BYTE_IN_PACKET;
925  }
926  if(fctx.stepB + datasize > fctx.bz.len) {
927  datasize = fctx.bz.len - fctx.stepB;
928  }
929  YASSERT((datasize & 1) == 0);
930  firm_pkt.prog.pkt_ext.size = (u8)(datasize / 2);
931  firm_pkt.prog.pkt_ext.type = PROG_PROG;
932 #ifdef DEBUG_FIRMWARE
933  {
934  u32 page, pos;
935  GET_PROG_POS_PAGENO(firm_pkt.prog.pkt_ext, page, pos);
936  pos *=4;
937  dbglog("Flash at 0x%x:0x%x (0x%x bytes) found at 0x%x (0x%x more in zone)\n",page, pos,
938  2*firm_pkt.prog.pkt_ext.size, fctx.zOfs, fctx.bz.len);
939  }
940 #endif
941  uGetFirmware(fctx.zOfs, firm_pkt.prog.pkt_ext.opt.data, 2*firm_pkt.prog.pkt_ext.size);
942  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
943  dbglog("Unable to send prog pkt\n");
944  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Unable to send prog pkt");
945  return -1;
946  }
947  fctx.zOfs += datasize;
948  fctx.stepB += datasize;
949 
950  // verify each time we finish a page or a zone
951  if ((u16)((addr & (firm_dev.ext_page_size-1)) + datasize) >= firm_dev.ext_page_size || fctx.stepB >= fctx.bz.len) {
952  fctx.zOfs -= fctx.stepB; // rewind to check
953  fctx.zst = FLASH_ZONE_READ;
954  }
955  break;
956  case FLASH_ZONE_READ:
957  // pageno is already set properly
958  addr = fctx.bz.addr_page;
959  SET_PROG_POS_PAGENO(firm_pkt.prog.pkt_ext, addr / firm_dev.ext_page_size, addr >> 2);
960  firm_pkt.prog.pkt.type = PROG_VERIF;
961  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
962  dbglog("Unable to send verif pkt\n");
963  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Unable to send verif pkt");
964  return -1;
965  }
966  fctx.zst = FLASH_ZONE_RECV_OK;
968  //no break on purpose
969  case FLASH_ZONE_RECV_OK:
970  if(ypGetBootloaderReply(&firm_dev, &firm_pkt,NULL)<0){
971  if((s32)(fctx.timeout - ytime()) < 0) {
972 #ifdef DEBUG_FIRMWARE
973  dbglog("Bootlaoder did not send confirmation for Zone %x Block %x\n",fctx.currzone,fctx.bz.addr_page);
974 #endif
975  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Device did not respond to verif pkt");
976  return -1;
977  }
978  return 0;
979  }
980  if(firm_pkt.prog.pkt.type != PROG_VERIF) {
981  dbglog("Invalid verif pkt\n");
982  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Invalid verif pkt");
983  return -1;
984  }
985  GET_PROG_POS_PAGENO(firm_pkt.prog.pkt_ext, pageno, pos);
986 #ifdef DEBUG_FIRMWARE
987  dbglog("Verif at 0x%x:0x%x (up to 0x%x bytes)\n",pageno,
988  pos <<2,
989  2*firm_pkt.prog.pkt_ext.size);
990 #endif
991  addr = pageno * firm_dev.ext_page_size + (pos << 2) ;
992  YASSERT(addr >= fctx.bz.addr_page);
993  if(addr < fctx.bz.addr_page + fctx.stepB) {
994  // packet is in verification range
995  datasize = 2 * firm_pkt.prog.pkt_ext.size;
996  if(addr + datasize >= fctx.bz.addr_page + fctx.stepB) {
997  datasize = fctx.bz.addr_page + fctx.stepB - addr;
998  }
999  uGetFirmware(fctx.zOfs + (addr-fctx.bz.addr_page), buff, (u16)datasize);
1000  if(memcmp(buff, firm_pkt.prog.pkt_ext.opt.data, datasize) != 0) {
1001  dbglog("Flash verification failed at %x (%x:%x)\n", addr, pageno, addr);
1002  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Flash verification failed");
1003  return -1;
1004  }
1005 #ifdef DEBUG_FIRMWARE
1006  } else {
1007  dbglog("Skip verification for block at addr 0x%x (block ends at %x)\n", addr, fctx.bz.addr_page + fctx.stepB);
1008 #endif
1009  }
1010  if((addr & (firm_dev.ext_page_size-1)) + 2 * (u32)firm_pkt.prog.pkt_ext.size < (u32)firm_dev.ext_page_size) {
1011  // more packets expected (device will dump a whole flash page)
1012  return 0;
1013  }
1014  fctx.zOfs += fctx.stepB;
1015  fctx.progress = (u16)(20 + 76*fctx.zOfs / (BYN_HEAD_SIZE_V6 + fctx.bynHead.v6.ROM_total_size + fctx.bynHead.v6.FLA_total_size));
1016  fctx.bz.addr_page += fctx.stepB;
1017  fctx.bz.len -= fctx.stepB;
1018  if(fctx.bz.len > 0 && fctx.currzone < fctx.bynHead.v6.ROM_nb_zone &&
1019  fctx.bz.addr_page >= (u32)firm_dev.first_yfs3_page * firm_dev.ext_page_size) {
1020  // skip end of ROM image past reserved flash zone
1021 #ifdef DEBUG_FIRMWARE
1022  dbglog("Drop ROM data past firmware boundary (zone %d at offset %x)\n", fctx.currzone, fctx.zOfs);
1023 #endif
1024  fctx.zOfs += fctx.bz.len;
1025  fctx.bz.len = 0;
1026  }
1027  if(fctx.bz.len == 0){
1028  fctx.zst = FLASH_ZONE_START;
1029  fctx.currzone++;
1030 #ifdef DEBUG_FIRMWARE
1031  dbglog("Switch to next zone (zone %d at offset %x)\n", fctx.currzone, fctx.zOfs);
1032 #endif
1033  } else {
1034  fctx.zst = FLASH_ZONE_PROG;
1035  fctx.stepB = 0;
1036 #ifdef DEBUG_FIRMWARE
1037  dbglog("Continue zone %d at offset %x for %x more bytes\n", fctx.currzone, fctx.zOfs, fctx.bz.len);
1038 #endif
1039  }
1040  }
1041 
1042  return 0;
1043 }
1044 #endif
1045 
1046 
1048 {
1049  byn_head_multi head;
1050  int res;
1051 
1052  if(fctx.stepA != FLASH_FIND_DEV && fctx.stepA != FLASH_DONE) {
1053  if(ypIsSendBootloaderBusy(&firm_dev)) {
1054  return YPROG_WAITING;
1055  }
1056  // ReSharper disable once CppUnreachableCode
1057  if(!Flash_ready()) {
1058  return YPROG_WAITING;
1059  }
1060  }
1061 
1062  switch(fctx.stepA){
1063  case FLASH_FIND_DEV:
1064  uLogProgress("Wait for device");
1065  if (uGetBootloader(fctx.bynHead.h.serial, &firm_dev.iface)<0){
1066 #ifndef MICROCHIP_API
1067  if((s32)(fctx.timeout - ytime()) >= 0) {
1068  return YPROG_WAITING;
1069  }
1070  #endif
1071  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"device not present");
1072 #ifdef DEBUG_FIRMWARE
1073  ulog("device not present\n");
1074 #endif
1075  return YPROG_DONE;
1076  }
1077  fctx.progress = 2;
1078  uLogProgress("Device detected");
1079 
1080 #if defined(DEBUG_FIRMWARE) && defined(MICROCHIP_API)
1081  ulog("Bootloader ");
1082  ulog(fctx.bynHead.h.serial);
1083  ulog(" on port ");
1084 #ifdef MICROCHIP_API
1085  ulogU16(firm_dev.iface);
1086 #else
1087  ulogU16(firm_dev.iface.deviceid);
1088 #endif
1089  ulog("\n");
1090 #endif
1091 #ifndef MICROCHIP_API
1092  fctx.stepA = FLASH_CONNECT;
1093  // no break on purpose
1094  case FLASH_CONNECT:
1095  if(YISERR(yyySetup(&firm_dev.iface,NULL))){
1096  YSTRCPY(fctx.errmsg,FLASH_ERRMSG_LEN,"Unable to open connection to the device");
1097  return YPROG_DONE;
1098  }
1099  uLogProgress("Device connected");
1100 #endif
1101  fctx.stepA = FLASH_GET_INFO;
1102  fctx.stepB = 0;
1103  break;
1104  case FLASH_GET_INFO:
1105  if(uGetDeviceInfo()<0){
1106 #ifdef DEBUG_FIRMWARE
1107  ulog("uGetDeviceInfo failed\n");
1108 #endif
1109  fctx.stepA = FLASH_DISCONNECT;
1110  }
1111  fctx.progress = 2;
1112  break;
1113  case FLASH_VALIDATE_BYN:
1114 #ifdef DEBUG_FIRMWARE
1115  ulog("PICDev ");
1116  ulogU16(firm_dev.devid_model);
1117  ulog(" detected\n");
1118 #endif
1119  uGetFirmwareBynHead(&head);
1120  if (ValidateBynCompat(&head, fctx.len, fctx.bynHead.h.serial, fctx.flags, &firm_dev, fctx.errmsg) < 0) {
1121 #ifdef DEBUG_FIRMWARE
1122  ulog("ValidateBynCompat failed:");
1123  ulog(fctx.errmsg);
1124  ulog("\n");
1125 #endif
1126  fctx.stepA = FLASH_DISCONNECT;
1127  break;
1128  }
1129 
1130  switch(head.h.rev) {
1131  case BYN_REV_V4:
1132  fctx.bynHead.v6.ROM_nb_zone = (u8)head.v4.nbzones;
1133  fctx.bynHead.v6.FLA_nb_zone = 0;
1134  fctx.currzone = 0;
1135  fctx.zOfs = BYN_HEAD_SIZE_V4;
1136  break;
1137  case BYN_REV_V5:
1138  fctx.bynHead.v6.ROM_nb_zone = (u8)head.v5.nbzones;
1139  fctx.bynHead.v6.FLA_nb_zone = 0;
1140  fctx.currzone = 0;
1141  fctx.zOfs = BYN_HEAD_SIZE_V5;
1142  break;
1143  case BYN_REV_V6:
1144  fctx.bynHead.v6.ROM_nb_zone = (u8)head.v6.ROM_nb_zone;
1145  fctx.bynHead.v6.FLA_nb_zone = (u8)head.v6.FLA_nb_zone;
1146  fctx.currzone = 0;
1147  fctx.zOfs = BYN_HEAD_SIZE_V6;
1148  break;
1149  default:
1150 #ifdef DEBUG_FIRMWARE
1151  ulog("Unsupported file format (upgrade our VirtualHub)\n");
1152 #endif
1153  fctx.stepA = FLASH_DISCONNECT;
1154  break;
1155  }
1156  fctx.progress = 3;
1157  fctx.stepA = FLASH_ERASE;
1158 #ifndef MICROCHIP_API
1159  if(firm_dev.ext_total_pages) {
1160  fctx.flashPage = firm_dev.first_code_page;
1161  }
1162 #endif
1163 #ifdef DEBUG_FIRMWARE
1164  ulogU16(fctx.bynHead.v6.ROM_nb_zone);
1165  ulog(" ROM zones to flash\n");
1166 #endif
1167  break;
1168  case FLASH_ERASE:
1169  fctx.zst = FLASH_ZONE_START;
1170  fctx.stepB = 0;
1171 #ifdef MICROCHIP_API
1173 #else
1174  if(firm_dev.ext_total_pages) {
1175  int npages = firm_dev.ext_total_pages - fctx.flashPage;
1176  int maxpages = (firm_dev.ext_jedec_id == JEDEC_SPANSION_4MB || firm_dev.ext_jedec_id == JEDEC_SPANSION_8MB ? 16 : 128);
1177 #ifdef DEBUG_FIRMWARE
1178  ulogU16(npages);
1179  ulog(" pages still to flash\n");
1180 #endif
1181  if(npages > maxpages) npages = maxpages;
1182  res = uSendErase(fctx.flashPage, npages, FLASH_WAIT_ERASE);
1183  fctx.flashPage += npages;
1184  } else {
1186  }
1187 #endif
1188  if(res<0){
1189 #ifdef DEBUG_FIRMWARE
1190  ulog("FlashErase failed\n");
1191 #endif
1192  YSTRCPY(fctx.errmsg,sizeof(fctx.errmsg),"Unable to blank flash");
1193  fctx.stepA = FLASH_DISCONNECT;
1194  }
1195  break;
1196  case FLASH_WAIT_ERASE:
1197  if(fctx.stepB == 0) {
1198 #ifndef MICROCHIP_API
1199  if(firm_dev.ext_total_pages) {
1200  if(ypIsSendBootloaderBusy(&firm_dev)) {
1201  return YPROG_WAITING;
1202  }
1203  memset(&firm_pkt,0,sizeof(USB_Prog_Packet));
1204  firm_pkt.prog.pkt.type = PROG_INFO;
1205  if(ypSendBootloaderCmd(&firm_dev,&firm_pkt,NULL)<0){
1206  return YPROG_WAITING;
1207  }
1208  }
1209 #endif
1210  fctx.stepB = ytime();
1211  } else {
1212 #ifndef MICROCHIP_API
1213  if(firm_dev.ext_total_pages) {
1214  if(ypGetBootloaderReply(&firm_dev, &firm_pkt,NULL)<0) {
1215  if((u32)(ytime() - fctx.stepB) < 2000u) {
1216  return YPROG_WAITING;
1217  }
1218 #ifdef DEBUG_FIRMWARE
1219  ulog("FlashErase failed\n");
1220 #endif
1221  YSTRCPY(fctx.errmsg,sizeof(fctx.errmsg),"Timeout blanking flash");
1222  fctx.stepA = FLASH_DISCONNECT;
1223  } else {
1224 #ifdef DEBUG_FIRMWARE
1225  ulog("clear time: ");
1226  ulogU16((u16)(ytime() - fctx.stepB));
1227  ulog("\n");
1228 #endif
1229  fctx.progress = 3+(18*fctx.flashPage/firm_dev.ext_total_pages);
1230  uLogProgress("Erasing flash");
1231  if(fctx.flashPage < firm_dev.ext_total_pages) {
1232  fctx.stepA = FLASH_ERASE;
1233  break;
1234  }
1235  }
1236  } else
1237 #endif
1238  {
1239  u32 delay = 1000 + (firm_dev.last_addr>>5);
1240  if((u32)(ytime() - fctx.stepB) < delay) {
1241  return YPROG_WAITING;
1242  }
1243  }
1244  fctx.stepA = FLASH_DOFLASH;
1245  fctx.stepB = 0;
1246  }
1247  break;
1248  case FLASH_DOFLASH:
1249 #ifdef MICROCHIP_API
1250  res = uFlashZone();
1251 #else
1252  if(firm_dev.ext_total_pages) {
1253  res = uFlashFlash();
1254  } else {
1255  res = uFlashZone();
1256  }
1257 #endif
1258  if(res<0){
1259 #ifdef DEBUG_FIRMWARE
1260  ulog("Flash failed\n");
1261  ulog("errmsg=");
1262  ulog(fctx.errmsg);
1263  ulogChar('\n');
1264 #endif
1265  fctx.stepA = FLASH_DISCONNECT;
1266  }
1267  break;
1268 
1270  res =uGetDeviceInfo();
1271  if(res <0){
1272 #ifdef DEBUG_FIRMWARE
1273  ulog("uGetDeviceInfo failed\n");
1274 #endif
1275  YSTRCPY(fctx.errmsg, FLASH_ERRMSG_LEN, "Last communication before reboot failed");
1276  fctx.stepA = FLASH_DISCONNECT;
1277  } else if(res == 1) {
1278  fctx.stepA = FLASH_REBOOT;
1279  }
1280  break;
1281 
1282  case FLASH_REBOOT:
1283  fctx.progress = 95;
1284 #ifdef DEBUG_FIRMWARE
1285  ulog("Send reboot\n");
1286 #endif
1287 
1288 #ifdef MICROCHIP_API
1289  res = ypBootloaderShutdown(&firm_dev);
1290  if (res < 0) {
1291 #ifdef DEBUG_FIRMWARE
1292  ulog("reboot failed\n");
1293 #endif
1294  YSTRCPY(fctx.errmsg,sizeof(fctx.errmsg),"Unable to reboot bootloader");
1295  fctx.stepA = FLASH_DISCONNECT;
1296  }
1297 #else
1299  // do not check reboot packet on purpose (most of the time
1300  // the os generate an error because the device rebooted too quickly)
1301 #endif
1304  break;
1305  case FLASH_REBOOT_VALIDATE:
1306  if(uGetBootloader(fctx.bynHead.h.serial,NULL)<0){
1307  fctx.progress = 98;
1308 #ifdef DEBUG_FIRMWARE
1309  ulog("device not present\n");
1310 #endif
1311  fctx.stepA = FLASH_SUCCEEDED;
1312  break;
1313  } else {
1314  if((s32)(fctx.timeout - ytime()) >= 0) {
1315  return YPROG_WAITING;
1316  }
1317 #if defined(DEBUG_FIRMWARE) && defined(MICROCHIP_API)
1318  ulog("Bootloader ");
1319  ulog(fctx.bynHead.h.serial);
1320  ulog(" on port ");
1321 #ifdef MICROCHIP_API
1322  ulogU16(firm_dev.iface);
1323 #else
1324  ulogU16(firm_dev.iface.deviceid);
1325 #endif
1326  ulog("\n");
1327 #endif
1328  if (fctx.zOfs == 0){
1329  uLogProgress("reboot failed try again...");
1331  break;
1332  }
1333  uLogProgress("Device still in bootloader");
1334  fctx.zOfs--;
1335  uLogProgress("Device still in bootloader");
1336  // FIXME: could try to add a retry
1337  fctx.stepA = FLASH_DISCONNECT;
1338  }
1339  break;
1340 #ifndef MICROCHIP_API
1341  case FLASH_AUTOFLASH:
1342  fctx.progress = 98;
1344  fctx.stepA = FLASH_SUCCEEDED;
1345  break;
1346 #endif
1347  case FLASH_SUCCEEDED:
1348 #ifdef DEBUG_FIRMWARE
1349  ulog("Flash succeeded\n");
1350 #endif
1351  YSTRCPY(fctx.errmsg,sizeof(fctx.errmsg),"Flash succeeded");
1352  fctx.progress = 100;
1353  fctx.stepA = FLASH_DISCONNECT;
1354  // intentionally no break
1355  case FLASH_DISCONNECT:
1356 #ifdef DEBUG_FIRMWARE
1357  ulog("Flash disconnect\n");
1358 #endif
1359 #ifndef MICROCHIP_API
1360  yyyPacketShutdown(&firm_dev.iface);
1361 #endif
1362  fctx.stepA = FLASH_DONE;
1363  // intentionally no break
1364  case FLASH_DONE:
1365  return YPROG_DONE;
1366  }
1367  return YPROG_WAITING;
1368 }
1369 
1370 
1371 #ifndef MICROCHIP_API
1372 
1373 typedef int(*yprogTcpReqCb)(void *ctx, const char* buffer, u32 len, char *errmsg);
1374 
1375 static int getTCPBootloaders(void *ctx, const char* buffer, u32 len, char *errmsg)
1376 {
1377  int res = 0;
1379  char *p = ctx;
1380  memset(p, 0, YOCTO_SERIAL_LEN * 4);
1381 
1382  // Parse HTTP header
1383  j.src = buffer;
1384  j.end = j.src + len;
1385  j.st = YJSON_HTTP_START;
1386  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_CODE) {
1387  return YERRMSG(YAPI_IO_ERROR,"Failed to parse HTTP header");
1388  }
1389  if (YSTRCMP(j.token, "200")) {
1390  return YERRMSG(YAPI_IO_ERROR,"Unexpected HTTP return code");
1391  }
1392  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_MSG) {
1393  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1394  }
1395  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_PARSE_STRUCT) {
1396  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1397  }
1398  while (yJsonParse(&j) == YJSON_PARSE_AVAIL && j.st == YJSON_PARSE_MEMBNAME) {
1399  if (!strcmp(j.token, "list")) {
1400  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_PARSE_ARRAY) {
1401  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1402  }
1403 
1404  while (yJsonParse(&j) == YJSON_PARSE_AVAIL && j.st != YJSON_PARSE_ARRAY) {
1405  if (res < 4) {
1406  YSTRCPY(p + res * YOCTO_SERIAL_LEN, YOCTO_SERIAL_LEN, j.token);
1407  }
1408  res++;
1409  }
1410  }
1411  yJsonSkip(&j, 1);
1412  }
1413  return res;
1414 }
1415 
1416 
1417 // return the list of bootladers in a specific hub
1418 // buffer must be an pointer to a buffer of min 4 * YOCTO_SERIAL_LEN
1419 // return the number of booloader copyed to buffer
1420 int yNetHubGetBootloaders(const char *hubserial, char *buffer, char *errmsg)
1421 {
1422  const char * req = "GET /flash.json?a=list \r\n\r\n";
1423  YIOHDL iohdl;
1424  YRETCODE res, subres;
1425  int replysize;
1426  char *reply;
1427 
1428  res = yapiHTTPRequestSyncStartEx_internal(&iohdl, 0, hubserial, req, YSTRLEN(req), &reply, &replysize, NULL, NULL, errmsg);
1429  if (YISERR(res)) {
1430  return res;
1431  }
1432  res = getTCPBootloaders(buffer, reply, replysize, errmsg);
1433  subres = yapiHTTPRequestSyncDone_internal(&iohdl, NULL);
1434  YASSERT(!YISERR(subres));
1435  return res;
1436 }
1437 
1438 
1439 #endif
1440 
1441 
1442 #ifndef YAPI_IN_YDEVICE
1443 
1444 static int getBootloaderInfos(const char *devserial, char *out_hubserial, char *errmsg)
1445 {
1446  int i, res;
1447 
1448 
1449  if (yContext->detecttype & Y_DETECT_USB) {
1450  int nbifaces = 0;
1451  yInterfaceSt *iface;
1452  yInterfaceSt *runifaces = NULL;
1453 
1454  if (YISERR(res = (YRETCODE)yyyUSBGetInterfaces(&runifaces, &nbifaces, errmsg))){
1455  return res;
1456  }
1457 
1458  for (i = 0, iface = runifaces; i < nbifaces; i++, iface++){
1459  if (iface->deviceid == YOCTO_DEVID_BOOTLOADER && YSTRCMP(devserial, iface->serial) == 0) {
1460  YSTRCPY(out_hubserial, YOCTO_SERIAL_LEN, "usb");
1461  return 1;
1462  }
1463  }
1464  }
1465 
1466 
1467  for (i = 0; i < NBMAX_NET_HUB; i++){
1468  if (yContext->nethub[i]){
1469  char bootloaders[4 * YOCTO_SERIAL_LEN];
1470  char hubserial[YOCTO_SERIAL_LEN];
1471  int j;
1472  char *serial;
1474  res = yNetHubGetBootloaders(hubserial, bootloaders, errmsg);
1475  if (YISERR(res)) {
1476  return res;
1477  }
1478  for (j = 0, serial = bootloaders; j < res; j++, serial += YOCTO_SERIAL_LEN){
1479  if (YSTRCMP(devserial,serial) == 0) {
1480  YSTRCPY(out_hubserial, YOCTO_SERIAL_LEN, hubserial);
1481  return 1;
1482  }
1483  }
1484  }
1485  }
1486  return 0;
1487 }
1488 
1489 typedef enum
1490 {
1494  FLASH_HUB_NOT_BUSY, // CHECK there is on pending fwupdate (cmd=state-> !uploading && !flashing)
1496 } FLASH_HUB_CMD;
1497 
1498 
1499 typedef struct {
1501  const char *devserial;
1502 }ckReqHeadCtx;
1503 
1504 static int checkRequestHeader(void *ctx_ptr, const char* buffer, u32 len, char *errmsg) {
1505  ckReqHeadCtx *ctx = ctx_ptr;
1507  char lastmsg[YOCTO_ERRMSG_LEN] = "invalid";
1508  int count = 0, return_code = 0;;
1509 
1510  // Parse HTTP header
1511  j.src = buffer;
1512  j.end = j.src + len;
1513  j.st = YJSON_HTTP_START;
1514  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_CODE) {
1515  return YERRMSG(YAPI_IO_ERROR,"Failed to parse HTTP header");
1516  }
1517  if (YSTRCMP(j.token, "200")) {
1518  return YERRMSG(YAPI_IO_ERROR,"Unexpected HTTP return code");
1519  }
1520  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_MSG) {
1521  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1522  }
1523  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_PARSE_STRUCT) {
1524  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1525  }
1526  while (yJsonParse(&j) == YJSON_PARSE_AVAIL && j.st == YJSON_PARSE_MEMBNAME) {
1527  switch (ctx->cmd){
1528  case FLASH_HUB_STATE:
1529  if (!strcmp(j.token, "state")) {
1530  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
1531  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1532  }
1533  if (YSTRCMP(j.token, "valid")) {
1534  YSTRCPY(lastmsg, YOCTO_ERRMSG_LEN, "Invalid firmware");
1535  return_code = YAPI_IO_ERROR;
1536  } else {
1537  count++;
1538  }
1539  } else if (!strcmp(j.token, "firmware")) {
1540  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
1541  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1542  }
1544  YSTRCPY(lastmsg, YOCTO_ERRMSG_LEN, "Firmware not designed for this module");
1545  return_code = YAPI_IO_ERROR;
1546  } else {
1547  count++;
1548  }
1549  } else if (!strcmp(j.token, "message")) {
1550  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
1551  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1552  }
1553  YSTRCPY(lastmsg, YOCTO_ERRMSG_LEN, j.token);
1554  } else {
1555  yJsonSkip(&j, 1);
1556  }
1557  break;
1558  case FLASH_HUB_NOT_BUSY:
1559  if (!strcmp(j.token, "state")) {
1560  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
1561  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1562  }
1563  if (YSTRCMP(j.token, "uploading") == 0 || YSTRCMP(j.token, "flashing")==0) {
1564  YSTRCPY(lastmsg, YOCTO_ERRMSG_LEN, "Cannot start firmware update: busy (");
1565  YSTRCAT(lastmsg, YOCTO_ERRMSG_LEN, j.token);
1566  YSTRCAT(lastmsg, YOCTO_ERRMSG_LEN, ")");
1567  return_code = YAPI_IO_ERROR;
1568  } else {
1569  count++;
1570  }
1571  } else {
1572  yJsonSkip(&j, 1);
1573  }
1574  break;
1575  case FLASH_HUB_AVAIL:
1576  yJsonSkip(&j, 1);
1577  break;
1578  case FLASH_HUB_FLASH:
1579  if (!strcmp(j.token, "logs")) {
1580  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_PARSE_ARRAY) {
1581  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1582  }
1583  while (yJsonParse(&j) == YJSON_PARSE_AVAIL && j.st != YJSON_PARSE_ARRAY) {
1584  setOsGlobalProgress(0, j.token);
1585  YSTRCPY(lastmsg, YOCTO_ERRMSG_LEN, j.token);
1586  }
1587  } else if (!strcmp(j.token, "progress")) {
1588  int progress;
1589  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
1590  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
1591  }
1592  progress = atoi(j.token);
1593  if (progress < 100) {
1594  return_code = YAPI_IO_ERROR;
1595  }
1596  } else {
1597  yJsonSkip(&j, 1);
1598  }
1599  break;
1600  default:
1601  yJsonSkip(&j, 1);
1602  break;
1603  }
1604  }
1605 
1606  if (return_code < 0) {
1607  YSTRCPY(errmsg,YOCTO_ERRMSG_LEN, lastmsg);
1608  return return_code;
1609  }
1610  return count;
1611 }
1612 
1613 static int checkHTTPHeader(void *ctx, const char* buffer, u32 len, char *errmsg) {
1615  // Parse HTTP header
1616  j.src = buffer;
1617  j.end = j.src + len;
1618  j.st = YJSON_HTTP_START;
1619  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_CODE) {
1620  return YERRMSG(YAPI_IO_ERROR, "Failed to parse HTTP header");
1621  }
1622  if (YSTRCMP(j.token, "200")) {
1623  return YERRMSG(YAPI_IO_ERROR, "Unexpected HTTP return code");
1624  }
1625 
1626  return 0;
1627 }
1628 
1629 
1630 // Method used to upload a file to the device
1631 static int upload(const char *hubserial, const char *subpath, const char *filename, u8 *data, u32 data_len, char *errmsg)
1632 {
1633 
1634  char *p;
1635  int buffer_size = 1024 + data_len;
1636  char *buffer = yMalloc(buffer_size);
1637  char boundary[32];
1638  int res;
1639  YIOHDL iohdl;
1640  char *reply = NULL;
1641  int replysize = 0;
1642 
1643  do {
1644  YSPRINTF(boundary, 32, "Zz%06xzZ", rand() & 0xffffff);
1645  } while (ymemfind(data, data_len, (u8*)boundary, YSTRLEN(boundary)) >= 0);
1646 
1647  YSTRCPY(buffer, buffer_size, "POST ");
1648  YSTRCAT(buffer, buffer_size, subpath);
1649  YSTRCAT(buffer, buffer_size, "upload.html HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=");
1650  YSTRCAT(buffer, buffer_size, boundary);
1651  YSTRCAT(buffer, buffer_size,
1652  "\r\n\r\n"
1653  "--");
1654  YSTRCAT(buffer, buffer_size, boundary);
1655  YSTRCAT(buffer, buffer_size, "\r\nContent-Disposition: form-data; name=\"");
1656  YSTRCAT(buffer, buffer_size, filename);
1657  YSTRCAT(buffer, buffer_size, "\"; filename=\"api\"\r\n"
1658  "Content-Type: application/octet-stream\r\n"
1659  "Content-Transfer-Encoding: binary\r\n\r\n");
1660  p = buffer + YSTRLEN(buffer);
1661  memcpy(p, data, data_len);
1662  p += data_len;
1663  YASSERT(p - buffer < buffer_size);
1664  buffer_size -= (int)(p - buffer);
1665  YSTRCPY(p, buffer_size, "\r\n--");
1666  YSTRCAT(p, buffer_size, boundary);
1667  YSTRCAT(p, buffer_size, "--\r\n");
1668  buffer_size = (int)(p - buffer) + YSTRLEN(p);
1669  //todo: chose wisely callback and tpchan
1670  res = yapiHTTPRequestSyncStartEx_internal(&iohdl, 0, hubserial, buffer, buffer_size, &reply, &replysize, NULL, NULL,errmsg);
1671  if (res >= 0) {
1672  res = checkHTTPHeader(NULL, reply, replysize, errmsg);
1673  yapiHTTPRequestSyncDone_internal(&iohdl, errmsg);
1674  }
1675  yFree(buffer);
1676  return res;
1677 }
1678 
1679 
1680 typedef enum
1681 {
1685 } FLASH_TYPE;
1686 
1687 
1688 static int sendHubFlashCmd(const char *hubserial, const char *subpath, const char *devserial, FLASH_HUB_CMD cmd, const char *args, char *errmsg)
1689 {
1690  char buffer[512];
1691  const char *cmd_str;
1692  ckReqHeadCtx ctx;
1693  int res;
1694  YIOHDL iohdl;
1695  YRETCODE subres;
1696  int replysize;
1697  char *reply;
1698 
1699  switch (cmd){
1700  case FLASH_HUB_AVAIL:
1701  case FLASH_HUB_STATE:
1702  case FLASH_HUB_NOT_BUSY:
1703  cmd_str = "state";
1704  break;
1705  case FLASH_HUB_FLASH:
1706  cmd_str = "flash";
1707  break;
1708  default:
1709  return YERR(YAPI_INVALID_ARGUMENT);
1710  }
1711  YSPRINTF(buffer, 512, "GET %sflash.json?a=%s%s \r\n\r\n", subpath, cmd_str, args);
1712  ctx.cmd = cmd;
1713  ctx.devserial = devserial;
1714  res = yapiHTTPRequestSyncStartEx_internal(&iohdl, 0, hubserial, buffer, YSTRLEN(buffer), &reply, &replysize, NULL, NULL, errmsg);
1715  if (YISERR(res)) {
1716  return res;
1717  }
1718  res = checkRequestHeader(&ctx, reply, replysize, errmsg);
1719  subres = yapiHTTPRequestSyncDone_internal(&iohdl, NULL);
1720  YASSERT(!YISERR(subres));
1721  return res;
1722 }
1723 
1724 static int isWebPath(const char *path)
1725 {
1726  if (YSTRNCMP(path, "http://", 7) == 0){
1727  return 7;
1728  } else if (YSTRNCMP(path, "www.yoctopuce.com",17) == 0){
1729  return 0;
1730  }
1731  return -1;
1732 }
1733 
1734 static int yDownloadFirmware(const char * url, u8 **out_buffer, char *errmsg)
1735 {
1736  char host[256];
1737  u8 *buffer;
1738  int res, len, ofs, i;
1739  const char * http_ok = "HTTP/1.1 200 OK";
1740 
1741 
1742  for (i = 0; i < 255 && i < YSTRLEN(url) && url[i] != '/'; i++){
1743  host[i] = url[i];
1744  }
1745 
1746  if (url[i] != '/'){
1747  return YERRMSG(YAPI_INVALID_ARGUMENT, "invalid url");
1748  }
1749  host[i] = 0;
1750 
1751  //yFifoInit(&(hub->fifo), hub->buffer,sizeof(hub->buffer));
1752  res = yTcpDownload(host, url+i, &buffer, 10000, errmsg);
1753  if (res < 0){
1754  return res;
1755  }
1756  if (YSTRNCMP((char*)buffer, http_ok, YSTRLEN(http_ok))) {
1757  yFree(buffer);
1758  return YERRMSG(YAPI_IO_ERROR, "Unexpected HTTP return code");
1759  }
1760 
1761  ofs = ymemfind(buffer, res, (u8*)"\r\n\r\n", 4);
1762  if (ofs <0) {
1763  yFree(buffer);
1764  return YERRMSG(YAPI_IO_ERROR, "Invalid HTTP header");
1765 
1766  }
1767  ofs += 4;
1768  len = res - ofs;
1769  *out_buffer = yMalloc(len);
1770  memcpy(*out_buffer, buffer + ofs, len);
1771  yFree(buffer);
1772  return len;
1773 
1774 }
1775 
1776 
1777 static void* yFirmwareUpdate_thread(void* ctx)
1778 {
1779  yThread *thread = (yThread*)ctx;
1780  YAPI_DEVICE dev;
1781  int res;
1782  char errmsg[YOCTO_ERRMSG_LEN];
1783  char buffer[256];
1784  char subpath[256];
1785  char bootloaders[YOCTO_SERIAL_LEN * 4];
1786  char *p;
1787  char replybuf[512];
1788  const char* reboot_req = "GET %sapi/module/rebootCountdown?rebootCountdown=-3 \r\n\r\n";
1789  const char* reboot_hub = "GET %sapi/module/rebootCountdown?rebootCountdown=-1003 \r\n\r\n";
1790  const char* get_api_fmt = "GET %sapi.json \r\n\r\n";
1791  char hubserial[YOCTO_SERIAL_LEN];
1792  char *reply = NULL;
1793  int replysize = 0;
1794  int ofs,i;
1795  u64 timeout;
1796  FLASH_TYPE type = FLASH_USB;
1797  int online, found;
1798  YPROG_RESULT u_flash_res;
1799 
1800 
1801  yThreadSignalStart(thread);
1802 
1803  //1% -> 5%
1804  setOsGlobalProgress(1, "Loading firmware");
1806  if (ofs < 0){
1807  res = yLoadFirmwareFile(yContext->fuCtx.firmwarePath, &fctx.firmware, errmsg);
1808  } else {
1809  res = yDownloadFirmware(yContext->fuCtx.firmwarePath + ofs, &fctx.firmware, errmsg);
1810  }
1811  if (YISERR(res)) {
1812  setOsGlobalProgress(res, errmsg);
1813  goto exitthread;
1814  }
1815  fctx.len = res;
1816  //copy firmware header into context variable (to have same behaviour as a device)
1817  memcpy(&fctx.bynHead, fctx.firmware, sizeof(fctx.bynHead));
1819 
1820 
1821  res = IsValidBynFile((const byn_head_multi *)fctx.firmware, fctx.len, yContext->fuCtx.serial, fctx.flags, errmsg);
1822  if (YISERR(res)) {
1823  setOsGlobalProgress(res, errmsg);
1824  goto exit_and_free;
1825  }
1826 
1827  //5% -> 10%
1828  setOsGlobalProgress(5, "Enter firmware update mode");
1829  dev = wpSearch(yContext->fuCtx.serial);
1830  if (dev != -1) {
1831  yUrlRef url;
1832  int urlres = wpGetDeviceUrl(dev, hubserial, subpath, 256, NULL);
1833  if (urlres < 0) {
1835  goto exit_and_free;
1836  }
1837  url = wpGetDeviceUrlRef(dev);
1838  if (yHashGetUrlPort(url, NULL, NULL, NULL, NULL, NULL) == USB_URL) {
1839  // USB connected device -> reboot it in bootloader
1840  type = FLASH_USB;
1841  YSPRINTF(buffer, sizeof(buffer), reboot_req, subpath);
1842  res = yapiHTTPRequest(hubserial, buffer, replybuf, sizeof(replybuf), NULL, errmsg);
1843  if (res < 0) {
1844  setOsGlobalProgress(res, errmsg);
1845  goto exit_and_free;
1846  }
1847  } else {
1848  res = sendHubFlashCmd(hubserial, subpath, yContext->fuCtx.serial, FLASH_HUB_AVAIL, "", NULL);
1849  if (res < 0 || YSTRNCMP(hubserial, "VIRTHUB", 7) == 0) {
1850  int is_shield = YSTRNCMP(yContext->fuCtx.serial, "YHUBSHL1", YOCTO_BASE_SERIAL_LEN)==0;
1851  res = yNetHubGetBootloaders(hubserial, bootloaders, errmsg);
1852  if (res < 0) {
1853  setOsGlobalProgress(res, errmsg);
1854  goto exit_and_free;
1855  }
1856  for (i = 0; i < res; i++) {
1857  p = bootloaders + YOCTO_SERIAL_LEN * i;
1858  if (YSTRCMP(yContext->fuCtx.serial, p) == 0) {
1859  break;
1860  }
1861  }
1862  if (i == res) {
1863  // not in bootloader list...
1864  //...check if list is allready full..
1865  if (res == 4) {
1866  setOsGlobalProgress(YAPI_IO_ERROR, "Too many devices in update mode");
1867  goto exit_and_free;
1868  }
1869  if (is_shield) {
1870  //...and that we do not already have a shield in bootlader..
1871  for (i = 0; i < res; i++) {
1872  p = bootloaders + YOCTO_SERIAL_LEN * i;
1873  if (YSTRNCMP(p, "YHUBSHL1", YOCTO_BASE_SERIAL_LEN)==0) {
1874  setOsGlobalProgress(YAPI_IO_ERROR, "Only one YoctoHub-Shield is allowed in update mode");
1875  goto exit_and_free;
1876  }
1877  }
1878  }
1879 
1880  // ...must reboot in programtion
1881  setOsGlobalProgress(8, "Reboot to firmware update mode");
1882  YSPRINTF(buffer, sizeof(buffer), reboot_req, subpath);
1883  res = yapiHTTPRequest(hubserial, buffer, replybuf, sizeof(replybuf), NULL, errmsg);
1884  if (res < 0) {
1885  setOsGlobalProgress(res, errmsg);
1886  goto exit_and_free;
1887  }
1888  if (replybuf[0] != 'O' || replybuf[1] != 'K') {
1889  dbglog("Reboot to firmware update mode:\n%s\n", replybuf);
1890  }
1891  }
1892  type = FLASH_NET_SUBDEV;
1893  } else {
1894  type = FLASH_NET_SELF;
1895  }
1896  }
1897  } else {
1898  //no known device -> check if device is in bootloader
1899  res = getBootloaderInfos(yContext->fuCtx.serial, hubserial, errmsg);
1900  if (res < 0) {
1901  setOsGlobalProgress(res, errmsg);
1902  goto exit_and_free;
1903  }
1904  if (res == 0) {
1905  setOsGlobalProgress(YAPI_DEVICE_NOT_FOUND, "Bootloader not found");
1906  goto exit_and_free;
1907  }
1908  if (YSTRCMP(hubserial, "usb") == 0) {
1909  type = FLASH_USB;
1910  } else {
1911  type = FLASH_NET_SUBDEV;
1912  }
1913  }
1914 
1915  //10% -> 40%
1916  setOsGlobalProgress(10, "Send new firmware");
1917  if (type != FLASH_USB){
1918  // ensure flash engine is not busy
1919  res = sendHubFlashCmd(hubserial, type == FLASH_NET_SELF ? subpath : "/", yContext->fuCtx.serial, FLASH_HUB_NOT_BUSY, "", errmsg);
1920  if (res < 1) {
1921  setOsGlobalProgress(res, errmsg);
1922  goto exit_and_free;
1923  }
1924  // start firmware upload
1925  // IP connected device -> upload the firmware to the Hub
1926  res = upload(hubserial, type == FLASH_NET_SELF ? subpath : "/", "firmware", fctx.firmware, fctx.len, errmsg);
1927  if (res < 0) {
1928  setOsGlobalProgress(res, errmsg);
1929  goto exit_and_free;
1930  }
1931  // verify that firmware is correctly uploaded
1932  res = sendHubFlashCmd(hubserial, type == FLASH_NET_SELF ? subpath : "/", yContext->fuCtx.serial, FLASH_HUB_STATE, "", errmsg);
1933  if (res < 2) {
1934  setOsGlobalProgress(res, errmsg);
1935  goto exit_and_free;
1936  }
1937 
1938  if (type == FLASH_NET_SELF) {
1939  const char *settingsOnly, *services;
1940  u8 *startupconf_data;
1941  int settings_len = yapiJsonGetPath_internal("api", (char*)yContext->fuCtx.settings, yContext->fuCtx.settings_len, 0, &settingsOnly, errmsg);
1942  int service_len = yapiJsonGetPath_internal("services", settingsOnly, settings_len, 0, &services, errmsg);
1943  int startupconf_data_len;
1944  if (service_len > 0) {
1945  int first_len = (services - settingsOnly) & 0xffffffff;
1946  int sec_len = ((settingsOnly + settings_len) - (services + service_len)) & 0xffffffff;
1947  startupconf_data = yMalloc(settings_len - service_len + 2);
1948  memcpy(startupconf_data, settingsOnly, first_len);
1949  startupconf_data[first_len] = '{';
1950  startupconf_data[first_len + 1] = '}';
1951  memcpy(startupconf_data + first_len + 2, services + service_len, sec_len);
1952  startupconf_data_len = first_len + sec_len;
1953  } else {
1954  startupconf_data_len = settings_len;
1955  startupconf_data = yMalloc(settings_len);
1956  memcpy(startupconf_data, settingsOnly, settings_len);
1957  }
1958  setOsGlobalProgress(20,"Save startupConf.json");
1959  // save settings
1960  res = upload(hubserial, subpath, "startupConf.json", startupconf_data, startupconf_data_len, errmsg);
1961  if (res < 0) {
1962  yFree(startupconf_data);
1963  setOsGlobalProgress(res, errmsg);
1964  goto exit_and_free;
1965  }
1966  setOsGlobalProgress(30,"Save firmwareConf");
1967  res = upload(hubserial, subpath, "firmwareConf", startupconf_data, startupconf_data_len, errmsg);
1968  yFree(startupconf_data);
1969  if (res < 0) {
1970  setOsGlobalProgress(res, errmsg);
1971  goto exit_and_free;
1972  }
1973  }
1974  }
1975 
1976  //40%-> 80%
1977  fctx.progress = 0 ;
1978  switch (type){
1979  case FLASH_USB:
1980  setOsGlobalProgress(40, "Flash firmware");
1982  do {
1983  u_flash_res = uFlashDevice();
1984  if (u_flash_res != YPROG_DONE){
1985  setOsGlobalProgress(40 + fctx.progress/2, fctx.errmsg);
1986  yApproximateSleep(1);
1987  }
1988  } while (u_flash_res != YPROG_DONE);
1989  if (fctx.progress < 100) {
1991  goto exit_and_free;
1992  }
1993  break;
1994  case FLASH_NET_SELF:
1995  setOsGlobalProgress(40, "Flash firmware");
1996  // the hub itself -> reboot in autoflash mode
1997  YSPRINTF(buffer, sizeof(buffer), reboot_hub, subpath);
1998  res = yapiHTTPRequest(hubserial, buffer, replybuf, sizeof(replybuf), NULL, errmsg);
1999  if (res < 0) {
2000  setOsGlobalProgress(res, errmsg);
2001  goto exit_and_free;
2002  }
2003  for (i = 0; i < 8; i++){
2004  setOsGlobalProgress(50 + i*5, "Flash firmware");
2005  yApproximateSleep(1000);
2006  }
2007  break;
2008  case FLASH_NET_SUBDEV:
2009  // verify that the device is in bootloader
2010  setOsGlobalProgress(40, "Verify that the device is in update mode");
2012  found = 0;
2013  while (!found && yapiGetTickCount()< timeout) {
2014  res = yNetHubGetBootloaders(hubserial, bootloaders, errmsg);
2015  if (res < 0) {
2016  setOsGlobalProgress(res, errmsg);
2017  goto exit_and_free;
2018  } else if (res > 0) {
2019  for (i = 0; i < res; i++) {
2020  p = bootloaders + YOCTO_SERIAL_LEN * i;
2021  if (YSTRCMP(yContext->fuCtx.serial, p) == 0) {
2022  found = 1;
2023  break;
2024  }
2025  }
2026  }
2027  // device still rebooting
2028  yApproximateSleep(100);
2029  }
2030  if (!found) {
2031  setOsGlobalProgress(YAPI_IO_ERROR, "Hub did not detect bootloader");
2032  goto exit_and_free;
2033  }
2034  //start flash
2035  setOsGlobalProgress(50, "Flash firmware");
2036  YSPRINTF(buffer, sizeof(buffer), "&s=%s", yContext->fuCtx.serial);
2037  res = sendHubFlashCmd(hubserial, "/", yContext->fuCtx.serial, FLASH_HUB_FLASH, buffer, errmsg);
2038  if (res < 0) {
2039  setOsGlobalProgress(res, errmsg);
2040  goto exit_and_free;
2041  }
2042  break;
2043  }
2044 
2045  //90%-> 98%
2046  setOsGlobalProgress(90, "Wait for the device to restart");
2047  online = 0;
2048  timeout = yapiGetTickCount() + 60000;
2049  do {
2050  YIOHDL iohdl;
2051  char tmp_errmsg[YOCTO_ERRMSG_LEN];
2052  res = yapiUpdateDeviceList(1, errmsg);
2053  if (res < 0 && type != FLASH_NET_SELF) {
2054  setOsGlobalProgress(res, errmsg);
2055  goto exit_and_free;
2056  }
2057  dev = wpSearch(yContext->fuCtx.serial);
2058  if (dev != -1) {
2059  wpGetDeviceUrl(dev, hubserial, subpath, 256, NULL);
2060  YSPRINTF(buffer, sizeof(buffer), get_api_fmt, subpath);
2061  res = yapiHTTPRequestSyncStartEx_internal(&iohdl, 0, hubserial, buffer, YSTRLEN(buffer), &reply, &replysize, NULL, NULL, tmp_errmsg);
2062  if (res >= 0) {
2063  if (checkHTTPHeader(NULL, reply, replysize, tmp_errmsg) >= 0) {
2064  const char * real_fw;
2065  int fw_len;
2066  fw_len = yapiJsonGetPath_internal("module|firmwareRelease", (char*)reply, replysize, 1, &real_fw, errmsg);
2067  online = 1;
2068  if (fw_len > 2) {
2069  const char *p = ((const byn_head_multi *)fctx.firmware)->h.firmware;
2070  //remove quote
2071  real_fw++;
2072  fw_len -= 2;
2073  if (YSTRNCMP(real_fw,p, fw_len)==0) {
2074  online = 2;
2075  }
2076  }
2077  yapiHTTPRequestSyncDone_internal(&iohdl, tmp_errmsg);
2078  break;
2079  }
2080  yapiHTTPRequestSyncDone_internal(&iohdl, tmp_errmsg);
2081  }
2082  }
2083  // idle a bit
2084  yApproximateSleep(100);
2085  } while (!online && yapiGetTickCount()< timeout);
2086 
2087  if (online){
2088  if (online == 2) {
2089  setOsGlobalProgress(100, "Firmware updated");
2090  }else {
2091  setOsGlobalProgress(YAPI_VERSION_MISMATCH, "Unable to update firmware");
2092  }
2093  } else {
2094  setOsGlobalProgress(YAPI_DEVICE_NOT_FOUND, "Device did not reboot correctly");
2095  }
2096 
2097 exit_and_free:
2098 
2099  if (fctx.firmware) {
2100  yFree(fctx.firmware);
2101  fctx.firmware = NULL;
2102  }
2103 
2104 exitthread:
2105  yThreadSignalEnd(thread);
2106  return NULL;
2107 }
2108 
2109 
2110 static int yStartFirmwareUpdate(const char *serial, const char *firmwarePath, const char *settings, u16 flags, char *msg)
2111 {
2112 
2113  if (yContext->fuCtx.serial)
2115  yContext->fuCtx.serial = YSTRDUP(serial);
2118  if (yContext->fuCtx.settings)
2120  yContext->fuCtx.firmwarePath = YSTRDUP(firmwarePath);
2121  yContext->fuCtx.settings = (u8*) YSTRDUP(settings);
2122  yContext->fuCtx.settings_len = YSTRLEN(settings);
2123  fctx.firmware = NULL;
2124  fctx.len = 0;
2125  fctx.flags = flags;
2126  fctx.stepA = FLASH_FIND_DEV;
2129  YSTRCPY(msg, FLASH_ERRMSG_LEN, "Firmware update started");
2130  memset(&yContext->fuCtx.thread, 0, sizeof(yThread));
2131  //yThreadCreate will not create a new thread if there is already one running
2133  yContext->fuCtx.serial = NULL;
2134  YSTRCPY(msg, FLASH_ERRMSG_LEN, "Unable to start helper thread");
2135  return YAPI_IO_ERROR;
2136  }
2137  return 0;
2138 
2139 }
2140 
2141 
2142 
2143 static YRETCODE yapiCheckFirmwareFile(const char *serial, int current_rev, u16 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
2144 {
2145  byn_head_multi *head;
2146  int size, res, file_rev;
2147  u8 *p;
2148 
2149  size = yLoadFirmwareFile(path, &p, errmsg);
2150  if (YISERR(size) || p == NULL){
2151  return YAPI_IO_ERROR;
2152  }
2153  head = (byn_head_multi*) p;
2154  res = IsValidBynFile(head, size, serial, flags, errmsg);
2155  if (YISERR(res)) {
2156  yFree(p);
2157  return res;
2158  }
2159 
2160 
2161  file_rev = atoi(head->h.firmware);
2162  if (file_rev > current_rev) {
2163  int pathsize = YSTRLEN(path) + 1;
2164  if (fullsize)
2165  *fullsize = YSTRLEN(path);
2166  if (pathsize <= buffersize) {
2167  YSTRCPY(buffer, buffersize, path);
2168  }
2169  } else{
2170  file_rev = 0;
2171  }
2172  yFree(p);
2173  return file_rev;
2174 }
2175 
2176 
2177 /***************************************************************************
2178  * new firmware upgrade API
2179  **************************************************************************/
2180 
2181 static YRETCODE yapiCheckFirmware_r(const char *serial, int current_rev, u16 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
2182 {
2183  int best_rev = current_rev;
2184  int pathlen = YSTRLEN(path);
2185  char abspath[1024];
2186 #ifdef WINDOWS_API
2187  WIN32_FIND_DATAA ffd;
2188  HANDLE hFind;
2189 #else
2190  struct dirent *pDirent;
2191  DIR *pDir;
2192 #endif
2193 
2194 #ifdef WINDOWS_API
2195 #else
2196 
2197  pDir = opendir(path);
2198  if (pDir == NULL) {
2199  return yapiCheckFirmwareFile(serial, current_rev, flags, path, buffer, buffersize, fullsize, errmsg);
2200  }
2201 #endif
2202 
2203  if (pathlen == 0 || pathlen >= 1024 - 32) {
2204  return YERRMSG(YAPI_INVALID_ARGUMENT, "path too long");
2205  }
2206 
2207  YSTRCPY(abspath, 1024, path);
2208  if (abspath[pathlen - 1] != '/' && abspath[pathlen - 1] != '\\') {
2209 #ifdef WINDOWS_API
2210  abspath[pathlen] = '\\';
2211 #else
2212  abspath[pathlen] = '/';
2213 #endif
2214  abspath[++pathlen] = 0;
2215  }
2216 
2217 
2218 #ifdef WINDOWS_API
2219  // Find the first file in the directory.
2220  YSTRCAT(abspath, 1024, "*");
2221  hFind = FindFirstFileA(abspath, &ffd);
2222  if (INVALID_HANDLE_VALUE == hFind) {
2223  return yapiCheckFirmwareFile(serial, current_rev, flags, path, buffer, buffersize, fullsize, errmsg);
2224  }
2225  do {
2226  char *name = ffd.cFileName;
2227 #else
2228  while ((pDirent = readdir(pDir)) != NULL) {
2229  char *name = pDirent->d_name;
2230  struct stat buf;
2231 #endif
2232  int isdir;
2233  int frev = 0;
2234 
2235  if (*name == '.')
2236  continue;
2237  abspath[pathlen] = 0;
2238  YSTRCAT(abspath, 1024, name);
2239 #ifdef WINDOWS_API
2240  isdir = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
2241 #else
2242  stat(abspath, &buf);
2243  isdir = S_ISDIR(buf.st_mode);
2244 #endif
2245  if (isdir)
2246  {
2247  frev = yapiCheckFirmware_r(serial, best_rev, flags, abspath, buffer, buffersize, fullsize, errmsg);
2248  } else {
2249  int len = YSTRLEN(name);
2250  if (len < 32 && 'b' == name[len - 3] && 'y' == name[len - 2] && 'n' == name[len - 1]) {
2251  frev = yapiCheckFirmwareFile(serial, best_rev, flags, abspath, buffer, buffersize, fullsize, errmsg);
2252  }
2253  }
2254  if (frev > 0){
2255  best_rev = frev;
2256  }
2257 
2258 #ifdef WINDOWS_API
2259  } while (FindNextFileA(hFind, &ffd) != 0);
2260 #else
2261  }
2262  closedir(pDir);
2263 #endif
2264  return best_rev;
2265 }
2266 
2267 
2268 static int checkFirmwareFromWeb(const char * serial, char * out_url, int url_max_len, int *fullsize, char * errmsg)
2269 {
2270  char request[256];
2271  u8 *buffer;
2272  int res, len;
2274 
2275  YSPRINTF(request, 256,"/FR/common/getLastFirmwareLink.php?serial=%s" , serial);
2276  res = yTcpDownload("www.yoctopuce.com", request, &buffer, 10000, errmsg);
2277  if (res<0){
2278  return res;
2279  }
2280  // Parse HTTP header
2281  j.src = (char*)buffer;
2282  j.end = j.src + res;
2283  j.st = YJSON_HTTP_START;
2284  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_CODE) {
2285  yFree(buffer);
2286  return YERRMSG(YAPI_IO_ERROR,"Unexpected HTTP return code");
2287  }
2288  if (YSTRCMP(j.token, "200")) {
2289  yFree(buffer);
2290  return YERRMSG(YAPI_IO_ERROR,"Unexpected HTTP return code");
2291  }
2292  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_HTTP_READ_MSG) {
2293  yFree(buffer);
2294  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
2295  }
2296  if (yJsonParse(&j) != YJSON_PARSE_AVAIL || j.st != YJSON_PARSE_STRUCT) {
2297  yFree(buffer);
2298  return YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
2299  }
2300  res = 0;
2301  while (yJsonParse(&j) == YJSON_PARSE_AVAIL && j.st == YJSON_PARSE_MEMBNAME) {
2302  if (!strcmp(j.token, "link")) {
2303  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
2304  res = YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
2305  break;
2306  }
2307  len = YSTRLEN(j.token);
2308  if (fullsize){
2309  *fullsize = len;
2310  }
2311  if (url_max_len < len + 1){
2312  res = YERRMSG(YAPI_INVALID_ARGUMENT, "buffer too small");
2313  break;
2314  }
2315  if (out_url) {
2316  YSTRCPY(out_url,url_max_len,j.token);
2317  }
2318  } else if (!strcmp(j.token, "version")) {
2319  if (yJsonParse(&j) != YJSON_PARSE_AVAIL) {
2320  res = YERRMSG(YAPI_IO_ERROR, "Unexpected JSON reply format");
2321  break;
2322  }
2323  res = atoi(j.token);
2324  } else {
2325  yJsonSkip(&j, 1);
2326  }
2327  }
2328 
2329  yFree(buffer);
2330  return res;
2331 }
2332 
2333 YRETCODE yapiCheckFirmware_internal(const char *serial, const char *rev, u32 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
2334 {
2335  int current_rev = 0;
2336  int best_rev;
2337 
2338  *buffer = 0;
2339  if (fullsize)
2340  *fullsize = 0;
2341  if (*rev!=0)
2342  current_rev = atoi(rev);
2343 
2344  if (isWebPath(path)>=0) {
2345  best_rev = checkFirmwareFromWeb(serial, buffer, buffersize, fullsize, errmsg);
2346  } else{
2347  best_rev = yapiCheckFirmware_r(serial, current_rev, (u16)flags, path, buffer, buffersize, fullsize, errmsg);
2348  }
2349  if (best_rev < 0){
2350  return best_rev;
2351  }
2352  if (best_rev <= current_rev) {
2353  buffer[0] = 0;
2354  if (fullsize){
2355  *fullsize = 0;
2356  }
2357  return 0;
2358  }
2359  return best_rev;
2360 }
2361 
2362 YRETCODE yapiUpdateFirmware_internal(const char *serial, const char *firmwarePath, const char *settings, int force, int startUpdate, char *msg)
2363 {
2364  YRETCODE res;
2365  yEnterCriticalSection(&fctx.cs);
2366  if (startUpdate) {
2367  if (yContext->fuCtx.serial == NULL || yContext->fuCtx.firmwarePath == NULL) {
2368  res = yStartFirmwareUpdate(serial, firmwarePath, settings, force ? YPROG_FORCE_FW_UPDATE : 0, msg);
2369  }else if (yContext->fuCtx.global_progress < 0 || yContext->fuCtx.global_progress >= 100) {
2370  res = yStartFirmwareUpdate(serial, firmwarePath, settings, force ? YPROG_FORCE_FW_UPDATE : 0, msg);
2371  } else {
2372  YSTRCPY(msg, FLASH_ERRMSG_LEN, "Last firmware update is not finished");
2373  res = 0;
2374  }
2375  } else {
2376  if (yContext->fuCtx.serial == NULL || yContext->fuCtx.firmwarePath == NULL) {
2377  YSTRCPY(msg, FLASH_ERRMSG_LEN, "No firmware update pending");
2378  res = YAPI_INVALID_ARGUMENT;
2379  } else if (YSTRCMP(serial, yContext->fuCtx.serial) || YSTRCMP(firmwarePath, yContext->fuCtx.firmwarePath)){
2380  YSTRCPY(msg, FLASH_ERRMSG_LEN, "Last firmware update is not finished");
2381  res = YAPI_INVALID_ARGUMENT;
2382  } else {
2385  }
2386  }
2387  yLeaveCriticalSection(&fctx.cs);
2388  return res;
2389 }
2390 
2391 #endif
u16 pad
Definition: yprog.h:95
FLASH_ZONE_STATE zst
Definition: yprog.h:284
#define NBMAX_NET_HUB
Definition: yproto.h:553
HubSt * nethub[NBMAX_NET_HUB]
Definition: yproto.h:941
#define BYN_REV_V5
Definition: yprog.h:60
u16 rev
Definition: yprog.h:81
#define BLOCK_FLASH_TIMEOUT
Definition: yprog.h:255
#define BYN_MD5_OFS_V6
Definition: yprog.h:123
static int sendHubFlashCmd(const char *hubserial, const char *subpath, const char *devserial, FLASH_HUB_CMD cmd, const char *args, char *errmsg)
Definition: yprog.c:1688
#define YERRMSG(code, message)
Definition: yproto.h:458
static int getTCPBootloaders(void *ctx, const char *buffer, u32 len, char *errmsg)
Definition: yprog.c:1375
#define PIC24FJ32GB002
Definition: ydef.h:1032
#define YSTRICMP(A, B)
Definition: yproto.h:228
byn_head_multi bynHead
Definition: yprog.h:277
static int uSendCmd(u8 cmd, FLASH_DEVICE_STATE nextState)
Definition: yprog.c:716
Definition: ykey.h:74
#define PIC24FJ256DA106
Definition: ydef.h:1026
#define ulog(str)
Definition: yprog.c:566
static int yLoadFirmwareFile(const char *filename, u8 **buffer, char *errmsg)
Definition: yprog.c:502
void * YIOHDL
Definition: ydef.h:260
void yInitializeCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:629
#define uGetFirmware(ofs, dst, size)
Definition: yprog.h:309
u16 first_yfs3_page
Definition: yprog.h:179
u32 ROM_total_size
Definition: yprog.h:105
u16 first_code_page
Definition: ydef.h:967
YRETCODE yPktQueueWaitAndPopD2H(yInterfaceSt *iface, pktItem **pkt, int ms, char *errmsg)
Definition: ystream.c:1128
f
#define YOCTO_DEVID_BOOTLOADER
Definition: ydef.h:404
#define YOCTO_PRODUCTNAME_LEN
Definition: ydef.h:422
yHash yUrlRef
Definition: ydef.h:215
yStrRef serial
Definition: yproto.h:805
USB_Packet pkt
Definition: yproto.h:508
USB_Packet firm_pkt
Definition: yprog.c:68
#define PIC24FJ32GB004
Definition: ydef.h:1034
#define FAMILY_PIC24FJ256DA210
Definition: ydef.h:1020
void yHashGetStr(yHash yhash, char *destbuf, u16 bufsize)
Definition: yhash.c:365
#define PROG_INFO
Definition: ydef.h:879
u16 first_yfs3_page
Definition: ydef.h:968
#define PIC24FJ128DA210
Definition: ydef.h:1023
#define FLASH_ERRMSG_LEN
Definition: yprog.h:265
#define MAX_ROM_ZONES_PER_FILES
Definition: yprog.h:55
#define ytime()
Definition: yprog.c:564
#define MAX_INSTR_IN_PACKET
Definition: ydef.h:883
int ValidateBynCompat(const byn_head_multi *head, u32 size, const char *serial, u16 flags, BootloaderSt *dev, char *errmsg)
Definition: yprog.c:314
#define YOCTO_BASE_SERIAL_LEN
Definition: ydef.h:421
#define YSTRCAT(dst, dstsize, src)
Definition: yproto.h:235
char token[62]
Definition: yjson.h:88
yContextSt * yContext
Definition: ystream.c:59
#define YPROG_FORCE_FW_UPDATE
Definition: yprog.h:260
int ypGetBootloaderReply(BootloaderSt *dev, USB_Packet *pkt, char *errmsg)
Definition: yprog.c:403
u16 devidl
Definition: ydef.h:917
int yThreadCreate(yThread *yth, void *(*fun)(void *), void *arg)
Definition: ythread.c:293
const int Y_DETECT_USB
Definition: yocto_api.h:204
FLASH_TYPE
Definition: yprog.c:1680
#define PIC24FJ256DA206
Definition: ydef.h:1025
struct USB_Prog_Packet::@38 pkt_ext
#define FLASH_NB_REBOOT_RETRY
Definition: yprog.h:224
int yNetHubGetBootloaders(const char *hubserial, char *buffer, char *errmsg)
Definition: yprog.c:1420
u8 data[MAX_BYTE_IN_PACKET]
Definition: ydef.h:905
u32 settings_addr
Definition: ydef.h:919
#define YOCTO_FIRMWARE_LEN
Definition: ydef.h:423
#define YERR(code)
Definition: yproto.h:456
#define dbglog(args...)
Definition: yproto.h:413
u32 last_addr
Definition: yprog.h:167
static YRETCODE yapiCheckFirmware_r(const char *serial, int current_rev, u16 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
Definition: yprog.c:2181
#define YPROPERR(call)
Definition: yproto.h:455
FLASH_HUB_CMD cmd
Definition: yprog.c:1500
int IsValidBynFile(const byn_head_multi *head, u32 size, const char *serial, u16 flags, char *errmsg)
Definition: yprog.c:328
u8 FLA_nb_zone
Definition: yprog.h:104
int yyySetup(yInterfaceSt *iface, char *errmsg)
FLASH_DEVICE_STATE stepA
Definition: yprog.h:283
yJsonRetCode yJsonParse(yJsonStateMachine *j)
Definition: yjson.c:83
#define decode_byn_zone(dummy)
Definition: yprog.h:137
_FAR const char * src
Definition: yjson.h:82
byn_head_v5 v5
Definition: yprog.h:113
int yyyUSBGetInterfaces(yInterfaceSt **ifaces, int *nbifaceDetect, char *errmsg)
yAsbUrlType yHashGetUrlPort(yUrlRef urlref, char *url, u16 *port, yAsbUrlProto *proto, yStrRef *user, yStrRef *password)
Definition: yhash.c:579
#define uGetFirmwareBynZone(offset, zone_ptr)
Definition: yprog.h:319
u32 addr_page
Definition: yprog.h:126
#define YOCTO_SERIAL_LEN
Definition: ydef.h:420
#define YPROG_BOOTLOADER_TIMEOUT
Definition: yprog.h:259
FLASH_HUB_CMD
Definition: yprog.c:1489
void yLeaveCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:672
void yProgInit(void)
Definition: yprog.c:76
u32 nbzones
Definition: yprog.h:96
#define MAX_BYTE_IN_PACKET
Definition: ydef.h:882
#define PIC24FJ256DA210
Definition: ydef.h:1027
#define YOCTO_ERRMSG_LEN
Definition: ydef.h:418
static int yDownloadFirmware(const char *url, u8 **out_buffer, char *errmsg)
Definition: yprog.c:1734
u32 pr_blk_size
Definition: yprog.h:165
byn_head_v6 v6
Definition: yprog.h:112
char errmsg[FLASH_ERRMSG_LEN]
Definition: yprog.h:296
yCRITICAL_SECTION cs
Definition: yprog.h:273
u16 pr_blk_size
Definition: ydef.h:916
#define PROG_PROG
Definition: ydef.h:877
int yTcpDownload(const char *host, const char *url, u8 **out_buffer, u32 mstimeout, char *errmsg)
Definition: ytcp.c:702
#define DECODE_U16(NUM)
Definition: yprog.h:138
#define BYN_REV_V4
Definition: yprog.h:59
void yJsonSkip(yJsonStateMachine *j, int nitems)
Definition: yjson.c:367
#define BYN_REV_V6
Definition: yprog.h:61
void yProgFree(void)
Definition: yprog.c:88
byn_head_sign h
Definition: yprog.h:110
static int getBootloaderInfos(const char *devserial, char *out_hubserial, char *errmsg)
Definition: yprog.c:1444
static void uSendReboot(u16 signature, FLASH_DEVICE_STATE nextState)
Definition: yprog.c:842
struct USB_Prog_Packet::@39 pktinfo_ext
#define BYN_HEAD_SIZE_V6
Definition: yprog.h:122
u16 devid_rev
Definition: yprog.h:171
YRETCODE
Definition: ydef.h:376
FLASH_DEVICE_STATE
Definition: yprog.h:226
const char * devserial
Definition: yprog.c:1501
void MD5Calculate(HASH_SUM *ctx, u8 digest[16])
Definition: ykey.c:671
BootloaderSt firm_dev
Definition: yprog.c:67
int wpGetDeviceUrl(YAPI_DEVICE devdesc, char *roothubserial, char *request, int requestsize, int *neededsize)
Definition: yhash.c:1124
FUpdateContext fuCtx
Definition: yproto.h:960
_FAR const char * end
Definition: yjson.h:83
u16 ext_page_size
Definition: yprog.h:176
u8 * settings
Definition: yproto.h:896
#define yTracePtr(ptr)
Definition: yproto.h:200
#define yApproximateSleep(ms)
Definition: yproto.h:433
#define JEDEC_SPANSION_4MB
Definition: ydef.h:1038
#define YSTRCPY(dst, dstsize, src)
Definition: yproto.h:234
#define PROG_VERIF
Definition: ydef.h:878
#define PIC24FJ256DA110
Definition: ydef.h:1028
#define uGetFirmwareBynHead(head_ptr)
Definition: yprog.h:318
u16 ext_jedec_id
Definition: ydef.h:964
#define BYN_HEAD_SIZE_V5
Definition: yprog.h:121
static int checkHardwareCompat(BootloaderSt *dev, const char *pictype)
Definition: yprog.c:181
u16 ext_total_pages
Definition: yprog.h:177
char * serial
Definition: yproto.h:894
char product[YOCTO_PRODUCTNAME_LEN]
Definition: yprog.h:84
u32 sign
Definition: yprog.h:73
int ypBootloaderShutdown(BootloaderSt *dev)
u32 last_addr
Definition: ydef.h:920
#define START_AUTOFLASHER_SIGN
Definition: ydef.h:1000
u16 first_code_page
Definition: yprog.h:178
static int yStartFirmwareUpdate(const char *serial, const char *firmwarePath, const char *settings, u16 flags, char *msg)
Definition: yprog.c:2110
#define ulogU16(val)
Definition: yprog.c:567
int settings_len
Definition: yproto.h:897
#define YASSERT(x)
Definition: yproto.h:454
u32 config_start
Definition: ydef.h:921
#define Flash_ready()
Definition: yprog.c:565
#define YSPRINTF
Definition: yproto.h:238
yJsonState st
Definition: yjson.h:84
u8 ROM_nb_zone
Definition: yprog.h:103
int yapiJsonGetPath_internal(const char *path, const char *json_data, int json_size, int withHTTPheader, const char **output, char *errmsg)
Definition: yapi.c:3912
#define ZONE_VERIF_TIMEOUT
Definition: yprog.h:257
static int uFlashZone()
Definition: yprog.c:730
u32 nbzones
Definition: yprog.h:89
byn_zone bz
Definition: yprog.h:286
u32 FLA_total_size
Definition: yprog.h:106
void yEnterCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:647
static int uGetDeviceInfo(void)
Definition: yprog.c:613
#define yFree(ptr)
Definition: yproto.h:199
u32 settings_addr
Definition: yprog.h:168
char serial[YOCTO_SERIAL_LEN *2]
Definition: yproto.h:567
u16 deviceid
Definition: yproto.h:564
#define SET_PROG_POS_PAGENO(PKT_EXT, PAGENO, POS)
Definition: ydef.h:973
byn_head_v4 v4
Definition: yprog.h:114
static int upload(const char *hubserial, const char *subpath, const char *filename, u8 *data, u32 data_len, char *errmsg)
Definition: yprog.c:1631
static int isWebPath(const char *path)
Definition: yprog.c:1724
yThread thread
Definition: yproto.h:898
FIRMWARE_CONTEXT fctx
Definition: yprog.c:64
Definition: yhash.h:174
#define yMalloc(size)
Definition: yproto.h:198
u8 * firmware
Definition: yprog.h:272
static void yProgLogProgress(const char *msg)
Definition: yprog.c:576
u32 datasize
Definition: yprog.h:90
char prog_version[YOCTO_FIRMWARE_LEN]
Definition: yprog.h:94
#define YSTRLEN(str)
Definition: yproto.h:230
static void * yFirmwareUpdate_thread(void *ctx)
Definition: yprog.c:1777
struct USB_Prog_Packet::@37 pktinfo
#define BYN_SIGN
Definition: yprog.h:58
int detecttype
Definition: yproto.h:932
int(* yprogTcpReqCb)(void *ctx, const char *buffer, u32 len, char *errmsg)
Definition: yprog.c:1373
void yDeleteCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:682
void MD5Initialize(HASH_SUM *ctx)
Definition: ykey.c:540
#define MAX_FLASH_ZONES_PER_FILES
Definition: yprog.h:56
u16 devidh
Definition: ydef.h:918
int SendDataPacket(BootloaderSt *dev, int program, u32 address, u8 *data, int nbinstr, char *errmsg)
Definition: yprog.c:436
#define PROG_ERASE
Definition: ydef.h:876
int ypIsSendBootloaderBusy(BootloaderSt *dev)
Definition: yprog.c:388
static int checkHTTPHeader(void *ctx, const char *buffer, u32 len, char *errmsg)
Definition: yprog.c:1613
u8 raw[64]
Definition: ydef.h:893
#define BYN_HEAD_SIZE_V4
Definition: yprog.h:120
union USB_Prog_Packet::@38::@40 opt
int IsValidBynHead(const byn_head_multi *head, u32 size, u16 flags, char *errmsg)
Definition: yprog.c:243
YRETCODE yapiCheckFirmware_internal(const char *serial, const char *rev, u32 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
Definition: yprog.c:2333
YPROG_RESULT
Definition: yprog.h:215
u32 endofconfig
Definition: yprog.h:173
yTime timeout
Definition: yprog.h:289
YPROG_RESULT uFlashDevice(void)
Definition: yprog.c:1047
u16 ext_total_pages
Definition: ydef.h:966
#define JEDEC_SPANSION_8MB
Definition: ydef.h:1039
u8 md5chk[16]
Definition: yprog.h:101
static void yGetFirmware(u32 ofs, u8 *dst, u16 size)
Definition: yprog.c:536
int global_progress
Definition: yproto.h:899
u64 YAPI_FUNCTION_EXPORT yapiGetTickCount(void)
Definition: yapi.c:2713
u16 ext_jedec_id
Definition: yprog.h:175
void yyyPacketShutdown(yInterfaceSt *iface)
#define uLogProgress(msg)
Definition: yprog.c:572
#define PROG_GET_INFO_TIMEOUT
Definition: yprog.h:256
void yThreadSignalEnd(yThread *yth)
Definition: ythread.c:326
u8 devid_model
Definition: yprog.h:170
int ymemfind(const u8 *haystack, u32 haystack_len, const u8 *needle, u32 needle_len)
Definition: ymemory.c:373
#define PROG_INFO_EXT
Definition: ydef.h:880
#define YSTRDUP(src)
Definition: yproto.h:233
USB_Prog_Packet prog
Definition: ydef.h:1008
static YRETCODE yapiCheckFirmwareFile(const char *serial, int current_rev, u16 flags, const char *path, char *buffer, int buffersize, int *fullsize, char *errmsg)
Definition: yprog.c:2143
static void osProgLogProgressEx(const char *fileid, int line, int prog, const char *msg)
Definition: yprog.c:584
char * firmwarePath
Definition: yproto.h:895
u16 adress_low
Definition: ydef.h:904
#define PIC24FJ128DA106
Definition: ydef.h:1022
const char * prog_GetCPUName(BootloaderSt *dev)
Definition: yprog.c:120
u32 er_blk_size
Definition: yprog.h:166
u8 devid_family
Definition: yprog.h:169
YRETCODE yapiHTTPRequestSyncStartEx_internal(YIOHDL *iohdl, int tcpchan, const char *device, const char *request, int requestsize, char **reply, int *replysize, yapiRequestProgressCallback progress_cb, void *progress_ctx, char *errmsg)
Definition: yapi.c:3348
#define PIC24FJ128DA110
Definition: ydef.h:1024
#define ulogChar(val)
Definition: yprog.c:568
YAPI_DEVICE wpSearch(const char *device_str)
Definition: yhash.c:1014
static int checkFirmwareFromWeb(const char *serial, char *out_url, int url_max_len, int *fullsize, char *errmsg)
Definition: yprog.c:2268
#define FAMILY_PIC24FJ64GB004
Definition: ydef.h:1031
char prog_version[YOCTO_FIRMWARE_LEN]
Definition: yprog.h:102
#define YISERR(retcode)
Definition: ydef.h:394
YRETCODE yyySendPacket(yInterfaceSt *iface, const USB_Packet *pkt, char *errmsg)
Definition: ystream.c:1199
s32 YAPI_DEVICE
Definition: ydef.h:216
char global_message[YOCTO_ERRMSG_LEN]
Definition: yproto.h:900
#define PIC24FJ128DA206
Definition: ydef.h:1021
u32 datasize
Definition: yprog.h:97
u8 addres_high
Definition: ydef.h:903
#define YSTRNCMP(A, B, len)
Definition: yproto.h:227
YRETCODE yapiHTTPRequestSyncDone_internal(YIOHDL *iohdl, char *errmsg)
Definition: yapi.c:3398
ProgIface iface
Definition: yprog.h:164
int ypSendBootloaderCmd(BootloaderSt *dev, const USB_Packet *pkt, char *errmsg)
Definition: yprog.c:396
void yThreadSignalStart(yThread *yth)
Definition: ythread.c:318
struct USB_Prog_Packet::@36 pkt
u16 ext_page_size
Definition: ydef.h:965
u16 er_blk_size
Definition: ydef.h:923
#define decode_byn_head_multi(dummy)
Definition: yprog.h:136
YRETCODE yapiUpdateFirmware_internal(const char *serial, const char *firmwarePath, const char *settings, int force, int startUpdate, char *msg)
Definition: yprog.c:2362
#define YSTRCMP(A, B)
Definition: yproto.h:226
u32 len
Definition: yprog.h:127
#define setOsGlobalProgress(prog, msg)
Definition: yprog.c:571
static int uSendErase(u16 firstPage, u16 nPages, FLASH_DEVICE_STATE nextState)
Definition: yprog.c:856
char firmware[YOCTO_FIRMWARE_LEN]
Definition: yprog.h:85
#define YSTRNCPY(dst, dstsize, src, len)
Definition: yproto.h:237
#define uGetBootloader(serial, ifaceptr)
Definition: yprog.c:606
#define PIC24FJ64GB002
Definition: ydef.h:1033
static int checkRequestHeader(void *ctx_ptr, const char *buffer, u32 len, char *errmsg)
Definition: yprog.c:1504
u32 config_stop
Definition: ydef.h:922
YRETCODE YAPI_FUNCTION_EXPORT yapiUpdateDeviceList(u32 forceupdate, char *errmsg)
Definition: yapi.c:4437
int BlockingRead(BootloaderSt *dev, USB_Packet *pkt, int maxwait, char *errmsg)
Definition: yprog.c:423
int YFOPEN(FILE **f, const char *filename, const char *mode)
Definition: ystream.c:130
#define GET_PROG_POS_PAGENO(PKT_EXT, PAGENO, POS)
Definition: ydef.h:977
u32 startconfig
Definition: yprog.h:172
#define PIC24FJ64GB004
Definition: ydef.h:1035
static int uFlashFlash()
Definition: yprog.c:871
char serial[YOCTO_SERIAL_LEN]
Definition: yprog.h:82
void MD5AddData(HASH_SUM *ctx, const u8 *buf, u32 len)
Definition: ykey.c:634
char pictype[20]
Definition: yprog.h:83
#define YOCTO_API_BUILD_NO
Definition: yversion.h:2
#define PROG_REBOOT
Definition: ydef.h:875
#define DECODE_U32(NUM)
Definition: yprog.h:139
int yUSBGetBooloader(const char *serial, const char *name, yInterfaceSt *iface, char *errmsg)
Definition: yprog.c:463
int YAPI_FUNCTION_EXPORT yapiHTTPRequest(const char *device, const char *request, char *buffer, int buffsize, int *fullsize, char *errmsg)
Definition: yapi.c:4648
yUrlRef wpGetDeviceUrlRef(YAPI_DEVICE devdesc)
Definition: yhash.c:1102


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