なんとなく興味があったのでついでにフラッシュ・プログラマーも作って見た。Windows版を作るにはVisual-Studioで開発したほうが簡単なんだけど使うと後々面倒なことになるだけなのでEclipse-CDT+MinGW64で開発している。リンカー(ld.exe)の不具合?なのかDLLの一部のシンボルがリンクエラーになってしまうので動的ロードするための余計なコードを書くハメになってしまったが、それはともかくEclipseとの連携を考慮してコマンドライン・ツールとして作成。って、いうとなんだか聞こえはいいがGUIが大の苦手なだけである。(-_-;)
プログラムはFTDIチップのCBUSピンを制御しデバイスのブートローダーを起動し通信を行う仕組みでファームウェアの読み書きに対応している。基本機能的にはモノワイヤレス社のTWE-Programmerと同じものだがブートローダーにはコードをRAMに転送し実行する機能もあるようだ。試してないけど。
ちなみにftd2.h/ftd2.cppは汎用的に使えるFTDIライブラリだ。CBUSピンはArduinoのようにpinMode/digitalWrite/digitalReadで制御できるので使いやすいかも。4ピンしかないけどね。(-_-;)
【コマンドライン(-h)】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Flash Programmer Utility for NXP JN516X, Version 1.1 Copyright(c) 2022-2024 Sasapea's Lab. All right reserved. Usage: JN516X-PROG [options] options: -s ... FTD2XX Port Scan -p portname ... FTD2XX Serial Number for Open -b ... baudrate (38400,115200,500K,*1M) -d ... device information -w filename ... write device (.bin) -r filename ... read device (.bin) -f sector ... start sector (*0 - n) -h ... this help |
【ポートスキャン(-s)】
1 2 3 4 5 6 7 8 |
Flash Programmer Utility for NXP JN516X, Version 1.1 Copyright(c) 2022-2024 Sasapea's Lab. All right reserved. Device Count: 4 Device-0: -- Open failure -- Device-1: Port: Com8, Serial: MW2Z8X7S, Description: TWE-Lite-R Device-2: Port: Com7, Serial: MW1DKWWS, Description: TWE-Lite-R Device-3: Port: Com12, Serial: MW67J6YY, Description: MONOSTICK |
【デバイス情報(-d)】
1 2 3 4 5 6 7 |
Flash Programmer Utility for NXP JN516X, Version 1.1 Copyright(c) 2022-2024 Sasapea's Lab. All right reserved. Program mode: 1M bps BootLoader Version: 0x02000B00 Flash ID: 0xCCEE, Type: 8 Chip ID: 0x0100B686, Name: JN5169, Flash: 512 Kb, Ram: 32 Kb, Type: 11 |
【デバイス読み込み(-r)】
1 2 3 4 5 6 7 |
Flash Programmer Utility for NXP JN516X, Version 1.1 Copyright(c) 2022-2024 Sasapea's Lab. All right reserved. Program mode: 1M bps Read Device [JN5169] -> "firmware.bin" Progress: 524288/524288 Success. |
【デバイス書き込み(-w)】
1 2 3 4 5 6 7 |
Flash Programmer Utility for NXP JN516X, Version 1.1 Copyright(c) 2022-2024 Sasapea's Lab. All right reserved. Program mode: 1M bps Write Device [JN5169] <- "firmware.bin" Progress: 99968/ 99968 Success. |
【修正履歴】
2024-01-29
ChipIDをJN516X-PROG.chipidファイルに記録&参照するように改良。chipidファイルによりChipIDの誤判定を修正することが可能となる。
2024-01-28
チップ・レビジョンによりデバイスの誤判定が起こるため改良。
2023-11-19
JN5168のChipIDの誤りとJN5164のChipIDが複数あるためにJN5164をJN5168と誤判定してしまうことがあったためJN5168はJN5164として判定するように対策。
2022-11-07
デバイス情報(-d)としてMAC Address表示を追加。
2022-06-01
JN5164で作成したプログラムが書き込みできなくて調べてみたらチップがJN5168だった。JN5161/JN5164/JN5168は同一パイナリーで動作するのでJN5161/JN5164/JN5168については同一チップと見なすように変更した。
2022-05-15
あちこち大幅改修。まずポート指定はシリアル番号指定が必要であったが面倒だったので-sコマンドでの何番目かを数字指定できるように変更した。-wコマンドはセクター単位の消去に変更したので全体を消去する-eコマンドを新たに追加。それと-rコマンドは有効なセクターを検索するようにしたので-fオプションが検索を開始するセクター指定となり複数のプログラムが書き込まれているときでもそれぞれを読み込むことが可能となるようにしてみた。あと物がないから試せないけどJN5179にも対応してみたつもり。
【プロジェクト一式(Eclipse)】
JN516X-PROG
【プログラム】
ftd2xx.hのためにコンパイルには次のシンボル定義が必要となる。
#define _WIN32
#define FTD2XX_STATIC
※モノワイヤレス社のTWELITE-R(2)/MONOSTICKのHW仕様でのみ動作することに注意。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
/* main.cpp - Flash Programmer Utility for NXP JN516x Series Copyright (c) 2022-2024 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <limits.h> #include "jn516x_prog.h" class Device : public JN516x_PROG { public: Device(void) {} virtual ~Device(void) {} protected: void programStart(const char *chipname, const char *filename, bool program) override { if (program) printf("Write Device [%s] <- \"%s\"\n", chipname, filename); else printf("Read Device [%s] -> \"%s\"\n", chipname, filename); } void programProgress(size_t size, size_t processed) override { printf("Progress: %6llu/%6llu\r", processed, size); } void programEnd(STATUS status) override { printf("\n"); if (status != STATUS_OK) printf("Error: [0x%02X] ", status); printf("%s\n", errstr(status)); } }; static Device device; void printMAC(const char *message, bool customer) { uint8_t buf[8]; device.macAddress(buf, customer); printf("%s", message); for (int i = 0; i < 8; ++i) { if (i) printf(":"); printf("%02X", buf[i]); } printf("\n"); } void chipInfo(void) { Device::CHIPID chipid; Device::VERSION chipver; Device::FLASHID flashid; uint32_t bootver; device.chipID(chipid); chipver = device.chipVersion(chipid); device.flashID(flashid); device.bootVersion(bootver); printf("BootLoader Version: 0x%08X\n", bootver); printf("Flash ID: 0x%04X, Type: %u\n", flashid, device.flashType(flashid)); printf("Chip ID: 0x%08X, Name: %s", chipid, device.chipName(chipver)); printf(", Flash: %u Kb, Ram: %u Kb, Type: %u\n", device.chipFlashSize(chipver) / 1024, device.chipRamSize(chipver) / 1024, device.chipType(chipver)); printMAC("Default MAC Address: ", false); printMAC("Customer MAC Address: ", true ); } void portScan(void) { int count = device.getDeviceCount(); printf("Device Count: %d\n", count); for (int i = 0; i < count; ++i) { char buf[128]; printf("Device-%d: ", i); if (device.begin(i)) { printf("Port: Com%u", device.getComPortNumber()); device.end(); device.getDeviceSerial(i, buf); printf(", Serial: %s", buf); device.getDeviceDescription(i, buf); printf(", Description: %s", buf); } else printf("-- Open failure --"); printf("\n"); } } void usage(bool help) { printf("Flash Programmer Utility for NXP JN516X, Version 1.1\n"); printf("Copyright(c) 2022-2024 Sasapea's Lab. All right reserved.\n"); printf("\n"); if (help) { printf("Usage: JN516X-PROG [options]\n"); printf("\n"); printf(" options:\n"); printf(" -s ... FTD2XX Port Scan\n"); printf(" -p portname ... FTD2XX Serial Number for Open\n"); printf(" -b ... baudrate (38400,115200,500K,*1M)\n"); printf(" -d ... device information\n"); printf(" -e ... erase device\n"); printf(" -w filename ... write device (.bin)\n"); printf(" -r filename ... read device (.bin)\n"); printf(" -f sector ... start sector (*0 - n)\n"); printf(" -h ... this help\n"); printf("\n"); } } int main(int argc, char **argv) { bool help = false; bool scan = false; bool info = false; bool erase = false; const char *portname = ""; const char *firmware = ""; const char *savefile = ""; Device::SPEED speed = Device::SPEED_1M; uint8_t sector = 0; for (int i = 1; i < argc; ) { char *p = argv[i++]; if (*p == '-') { switch (*++p) { case 'h': help = true; break; case 's': scan = true; break; case 'p': if (i < argc) portname = argv[i++]; break; case 'w': if (i < argc) firmware = argv[i++]; break; case 'r': if (i < argc) savefile = argv[i++]; break; case 'b': if (i < argc) { switch (strtoul(argv[i++], &p, 10)) { case 38400: speed = Device::SPEED_38400; break; case 115200: speed = Device::SPEED_115200; break; case 500: if (toupper(*p) != 'K') break; /* Fall Through */ case 500000: speed = Device::SPEED_500K; break; case 1: if (toupper(*p) != 'M') break; /* Fall Through */ case 1000000: speed = Device::SPEED_1M; break; } } break; case 'f': if (i < argc) sector = atoi(argv[i++]); break; case 'd': info = true; break; case 'e': erase = true; break; default: help = true; break; } } else help = true; } if (help) usage(true); else if (device.status() != FT_OK) { usage(false); printf("FTD2XX Library Not Found."); } else if (scan) { usage(false); portScan(); } else if (device.begin(portname)) { static char path[PATH_MAX]; snprintf(path, sizeof(path), "%s", argv[0]); char *p = strrchr(path, '.'); if (!p) p = path + strlen(path); snprintf(p, sizeof(path) - strlen(path), "%s", ".chipid"); device.setChipIDPath(path); Device::STATUS rv = device.program(speed); if (rv == Device::STATUS_OK) { usage(false); switch (speed) { case Device::SPEED_1M: printf("Program Mode: 1M bps\n"); break; case Device::SPEED_500K: printf("Program Mode: 500K bps\n"); break; default: printf("Program Mode: %d bps\n", speed); break; } if (info) chipInfo(); if (*savefile) device.readDevice(savefile, sector); if (erase) device.eraseDevice(); if (*firmware) device.writeDevice(firmware, sector); device.restart(); } else printf("Program Mode Failed = 0x%02X\n", rv); device.end(); } else { usage(false); printf("Port Open Failed: \"%s\"\n", portname); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
/* jn516x_prog.h - Flash Programmer Library for NXP JN516x Series Copyright (c) 2022-2024 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include "ftd2.h" #include "jn516x.h" #define JN516X_MAX_DATA_SIZE 128 #define OTA_BOOT_FIRMWARE "-OTA-BOOT.bin" class JN516x_PROG : public JN516x, public FTD2 { public: typedef enum { /* boot loader */ STATUS_OK = 0, STATUS_NOT_SUPPORTED = 0xFF, STATUS_WRITE_FAIL = 0xFE, STATUS_INVALID_RESPONSE = 0xFD, STATUS_CRC_ERROR = 0xFC, STATUS_ASSERT_FAIL = 0xFB, STATUS_USER_INTERRUPT = 0xFA, STATUS_READ_FAIL = 0xF9, STATUS_TST_ERROR = 0xF8, STATUS_AUTH_ERROR = 0xF7, STATUS_NO_RESPONSE = 0xF6, /* orignal */ STATUS_FILE_WRITE_FAIL = 0xE3, STATUS_FILE_READ_FAIL = 0xE2, STATUS_FILE_NOT_FOUND = 0xE1, STATUS_INVALID_VERSION = 0xE0, } STATUS; typedef struct __attribute__((packed)) { uint8_t magicNumber[12]; uint8_t configuration; uint8_t status; uint16_t applicationID; } tsBIR; typedef struct __attribute__((packed)) { tsBIR sBIR; // 16-byte Boot Image Record uint8_t encryption[14]; // Encryption Initialisation Vector (ignored if unencrypted) uint16_t configuration; // 16-bit Software Configuration Options uint32_t imageSize; // 32-bit Length of Binary Image in bytes uint32_t dataStart; // 32-bit .data section Flash start address uint16_t dataAddress; // 16-bit .data section load address in RAM (word aligned) uint16_t dataLength; // 16-bit .data section length in 32-bit words uint16_t bssStart; // 16 bit .bss section start address in RAM (word aligned) uint16_t bssLength; // 16-bit .bss section length in 32-bit words uint32_t warmStart; // 32-bit wake-up entry point (word aligned) – warm start uint32_t coldStart; // 32-bit reset entry point (word aligned) – cold start } tsFlashHeader; typedef struct __attribute__((packed)) { uint32_t version; // version tsBIR sBIR; // 16-byte Boot Image Record uint8_t encryption[14]; // Encryption Initialisation Vector (ignored if unencrypted) uint16_t configuration; // 16-bit Software Configuration Options uint32_t imageSize; // 32-bit Length of Binary Image in bytes uint32_t dataStart; // 32-bit .data section Flash start address uint16_t dataAddress; // 16-bit .data section load address in RAM (word aligned) uint16_t dataLength; // 16-bit .data section length in 32-bit words uint16_t bssStart; // 16 bit .bss section start address in RAM (word aligned) uint16_t bssLength; // 16-bit .bss section length in 32-bit words uint32_t warmStart; // 32-bit wake-up entry point (word aligned) – warm start uint32_t coldStart; // 32-bit reset entry point (word aligned) – cold start } tsFlashHeader_JN5179; JN516x_PROG(void) : _debug(false) { } virtual ~JN516x_PROG(void) { } static const char *errstr(STATUS status) { switch (status) { case STATUS_OK: return "Success"; /* boot loader */ case STATUS_NOT_SUPPORTED: return "not supported"; case STATUS_WRITE_FAIL: return "write failed"; case STATUS_INVALID_RESPONSE: return "invalid responce"; case STATUS_CRC_ERROR: return "CRC error"; case STATUS_ASSERT_FAIL: return "assert failed"; case STATUS_USER_INTERRUPT: return "user interrupt"; case STATUS_READ_FAIL: return "read failed"; case STATUS_TST_ERROR: return "test error"; case STATUS_AUTH_ERROR: return "auth error"; case STATUS_NO_RESPONSE: return "no responce"; /* orignal */ case STATUS_FILE_WRITE_FAIL: return "file write failed"; case STATUS_FILE_READ_FAIL: return "file read failed"; case STATUS_FILE_NOT_FOUND: return "file not found"; case STATUS_INVALID_VERSION: return "invalid version"; } return "unknown error"; } void setChipIDPath(const char *path) { _chipidpath = path; } VERSION chipVersion(CHIPID id) { char keyname[16], chipver[16]; if (_chipidpath.length()) { snprintf(keyname, sizeof(keyname), "%08X", id); if (GetPrivateProfileString("chipid", keyname, "", chipver, sizeof(chipver), _chipidpath.c_str())) return (VERSION)strtoul(chipver, nullptr, 16); } VERSION version = JN516x::chipVersion(id); unsigned char b; switch (version) { case VERSION_JN517x: _debug = false; if (readFlash(160 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = (VERSION)0; else if (readFlash(256 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = VERSION_JN5174; else if (readFlash(512 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = VERSION_JN5178; else { version = VERSION_JN5179; break; } /* restart boot mode */ program(_speed, _timeout); break; case VERSION_JN516x: _debug = false; if (readFlash( 64 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = (VERSION)0; else if (readFlash(160 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = VERSION_JN5161; else if (readFlash(256 * 1024 - 1, &b, sizeof(b)) != STATUS_OK) version = VERSION_JN5164; else { version = VERSION_JN5168; break; } /* restart boot mode */ program(_speed, _timeout); break; default: break; } if (_chipidpath.length() && version) { snprintf(chipver, sizeof(chipver), "%08X", version); WritePrivateProfileString("chipid", keyname, chipver, _chipidpath.c_str()); } return version; } STATUS eraseDevice(void) { CHIPID chipid; STATUS rv = chipID(chipid); if (rv == STATUS_OK) { FLASHID flashid; if ((rv = flashID(flashid)) == STATUS_OK) { if ((rv = selectFlash(flashType(flashid))) == STATUS_OK) { if ((rv = writeSR(0)) == STATUS_OK) rv = eraseFlash(); } } } return rv; } STATUS writeDevice(const char *filename, uint8_t u8Sector = 0) { CHIPID chipid; VERSION chipver; STATUS rv = chipID(chipid); chipver = chipVersion(chipid); programStart(chipName(chipver), filename, true); if (rv == STATUS_OK) { rv = STATUS_FILE_NOT_FOUND; FILE *fp = fopen(filename, "rb"); if (fp) { VERSION filever; if ((rv = fileVersion(filever, fp)) == STATUS_OK) { if (chipType(filever) != chipType(chipver)) rv = STATUS_INVALID_VERSION; else { FLASHID flashid; if ((rv = flashID(flashid)) == STATUS_OK) { if ((rv = selectFlash(flashType(flashid))) == STATUS_OK) { if ((rv = writeSR(0)) == STATUS_OK) { uint8_t data[JN516X_MAX_DATA_SIZE]; size_t fpos = (chipver == VERSION_JN5179 ? 0 : ftell(fp)); fseek(fp, 0, SEEK_END); size_t size = ftell(fp) - fpos; if (strstr(filename, OTA_BOOT_FIRMWARE)) u8Sector = chipFlashSectors(chipver) - 1; size_t offs = FLASH_SECTOR_OFFSET(u8Sector); size_t addr = 0; size_t prog = 0; uint8_t erase = 0xFF; fseek(fp, fpos, SEEK_SET); while (1) { ssize_t n = fread(data, 1, sizeof(data), fp); if (n <= 0) break; u8Sector = (addr + offs) >> 15; if (erase != u8Sector) { erase = u8Sector; if ((rv = eraseFlash(u8Sector))) break; } if ((rv = programFlash(addr + offs, data, n)) != STATUS_OK) break; addr += n; if (prog != (addr >> 10)) { prog = (addr >> 10); programProgress(size, addr); } } programProgress(size, addr); } } } } } fclose(fp); } } programEnd(rv); return rv; } STATUS readDevice(const char *filename, uint8_t u8Sector = 0) { CHIPID chipid; VERSION chipver; STATUS rv = chipID(chipid); chipver = chipVersion(chipid); programStart(chipName(chipver), filename, false); if (rv == STATUS_OK) { rv = STATUS_FILE_NOT_FOUND; FILE *fp = fopen(filename, "wb"); if (fp) { FLASHID flashid; if ((rv = flashID(flashid)) == STATUS_OK) { if ((rv = selectFlash(flashType(flashid))) == STATUS_OK) { if ((rv = writeSR(0)) == STATUS_OK) { /* Search Flash Header */ size_t offs = FLASH_SECTOR_OFFSET(u8Sector); size_t size = chipFlashSize(chipver); bool boot; while (offs < size) { boot = false; if (chipver == VERSION_JN5179) { tsFlashHeader_JN5179 sFlashHeader; if ((rv = readFlash(offs, (uint8_t *)&sFlashHeader, sizeof(sFlashHeader))) != STATUS_OK) break; boot |= memcmp(sFlashHeader.sBIR.magicNumber, JN516x::MAGICNUMBER, sizeof(JN516x::MAGICNUMBER)) == 0; boot |= memcmp(sFlashHeader.sBIR.magicNumber, JN516x::MAGICNUMBER_JN5179, sizeof(JN516x::MAGICNUMBER)) == 0; boot &= sFlashHeader.sBIR.status == 0x01; boot &= sFlashHeader.sBIR.applicationID == 0x0000; if (boot) { size = read32((uint8_t *)&sFlashHeader.imageSize); break; } } else { tsFlashHeader sFlashHeader; if ((rv = readFlash(offs, (uint8_t *)&sFlashHeader, sizeof(sFlashHeader))) != STATUS_OK) break; boot |= memcmp(sFlashHeader.sBIR.magicNumber, JN516x::MAGICNUMBER, sizeof(JN516x::MAGICNUMBER)) == 0; boot &= sFlashHeader.sBIR.status == 0x01; boot &= sFlashHeader.sBIR.applicationID == 0x0000; if (boot) { size = read32((uint8_t *)&sFlashHeader.imageSize); break; } } offs += 0x8000U; } if (boot) { uint8_t data[JN516X_MAX_DATA_SIZE]; if (chipver != VERSION_JN5179) { write32(data, chipver, false); if (fwrite(data, 1, 4, fp) != 4) rv = STATUS_FILE_WRITE_FAIL; } if (rv == STATUS_OK) { size_t addr = 0; size_t prog = 0; while (addr < size) { size_t n = __min(size - addr, sizeof(data)); if ((rv = readFlash(addr + offs, data, n)) != STATUS_OK) break; if (fwrite(data, 1, n, fp) != n) { rv = STATUS_FILE_WRITE_FAIL; break; // write error } addr += n; if (prog != (addr >> 10)) { prog = (addr >> 10); programProgress(size, addr); } } programProgress(size, addr); } } } } } fclose(fp); } } programEnd(rv); return rv; } STATUS program(SPEED speed = SPEED_1M, uint32_t timeout = 1000) { // setup uart init(SPEED_38400, MODE_8N1, FLOW_RTS_CTS, timeout); // setup cbus digitalWrite(PIN_PROG , HIGH); digitalWrite(PIN_RESET, HIGH); pinMode(PIN_PROG , GPIO_OUTPUT); pinMode(PIN_RESET, GPIO_OUTPUT); // start program mode digitalWrite(PIN_PROG, LOW); restart(true); Sleep::sleep(300); digitalWrite(PIN_PROG, HIGH); // change baudrate STATUS status = changeBaudrate(speed); if (status == STATUS_OK) { _debug = true; _speed = speed; _timeout = timeout; } return status; } STATUS restart(bool hardware = true) { if (hardware) { digitalWrite(PIN_RESET, LOW); digitalWrite(PIN_RESET, HIGH); return STATUS_OK; } return protocol(MSGTYPE_SET_RESET_REQUEST); } STATUS changeBaudrate(SPEED speed) { uint8_t arg; switch (speed) { case SPEED_1M : arg = 1; break; case SPEED_500K : arg = 2; break; case SPEED_115200: arg = 9; break; case SPEED_38400 : arg = 26; break; default: return STATUS_NOT_SUPPORTED; } STATUS rv = protocol(MSGTYPE_CHANGE_BAUDRATE_REQUEST, &arg, sizeof(arg)); if (rv == STATUS_OK) baudrate(speed); return rv; } STATUS eraseFlash(void) { return protocol(MSGTYPE_FLASH_ERASE_REQUEST); } STATUS eraseFlash(uint8_t sector) { return protocol(MSGTYPE_SECTOR_ERASE_REQUEST, §or, sizeof(sector)); } STATUS programFlash(uint32_t addr, uint8_t *buf, uint16_t len) { uint8_t data[JN516X_MAX_DATA_SIZE + 4]; if (len > JN516X_MAX_DATA_SIZE) len = JN516X_MAX_DATA_SIZE; write32(data + 0, addr); memcpy(data + 4, buf, len); return protocol(MSGTYPE_FLASH_PROGRAM_REQUEST, data, len + 4); } STATUS readFlash(uint32_t addr, uint8_t *buf, uint16_t len) { if (len > JN516X_MAX_DATA_SIZE) len = JN516X_MAX_DATA_SIZE; uint8_t data[6]; write32(data + 0, addr); write16(data + 4, len); STATUS rv = protocol(MSGTYPE_FLASH_READ_REQUEST, data, sizeof(data)); if (rv == STATUS_OK) memcpy(buf, _packet + 3, len); return rv; } STATUS selectFlash(FLASH type, uint32_t jump = 0) { uint8_t data[5]; data[0] = (uint8_t)type; write32(data + 1, jump); return protocol(MSGTYPE_SELECT_FLASH_TYPE_REQUEST, data, sizeof(data)); } STATUS writeSR(uint8_t data) { return protocol(MSGTYPE_WRITE_SR_REQUEST, &data, sizeof(data)); } STATUS writeRAM(uint32_t addr, uint8_t *buf, uint16_t len) { uint8_t data[JN516X_MAX_DATA_SIZE + 4]; if (len > JN516X_MAX_DATA_SIZE) len = JN516X_MAX_DATA_SIZE; write32(data + 0, addr); memcpy(data + 4, buf, len); return protocol(MSGTYPE_RAM_WRITE_REQUEST, data, len + 4); } STATUS readRAM(uint32_t addr, uint8_t *buf, uint16_t len) { if (len > JN516X_MAX_DATA_SIZE) len = JN516X_MAX_DATA_SIZE; uint8_t data[6]; write32(data + 0, addr); write16(data + 4, len); STATUS rv = protocol(MSGTYPE_RAM_READ_REQUEST, data, sizeof(data)); if (rv == STATUS_OK) memcpy(buf, _packet + 3, len); return rv; } STATUS run(uint32_t jump) { uint8_t data[4]; write32(data, jump); return protocol(MSGTYPE_RUN_REQUEST, data, sizeof(data)); } STATUS chipID(CHIPID& id) { STATUS rv = protocol(MSGTYPE_GET_CHIP_ID_REQUEST); id = (CHIPID)(rv == STATUS_OK ? read32(_packet + 3) : 0); return rv; } STATUS flashID(FLASHID& id) { STATUS rv = protocol(MSGTYPE_READ_FLASH_ID_REQUEST); id = (FLASHID)(rv == STATUS_OK ? read16(_packet + 3) : 0); return rv; } FLASH flashType(FLASHID id) { switch (id) { case FLASHID_ST_M25P05_A: return FLASH_ST_M25P05_A; case FLASHID_ST_M25P10_A: return FLASH_ST_M25P10_A; case FLASHID_ST_M25P20_A: return FLASH_ST_M25P20_A; case FLASHID_ST_M25P40: return FLASH_ST_M25P40; case FLASHID_SST_25VF010A: return FLASH_SST_25VF010A; case FLASHID_ATMEL_25F512: return FLASH_ATMEL_25F512; case FLASHID_INTERNAL_FLASH: return FLASH_INTERNAL_FLASH; default: break; } return (FLASH)0; } STATUS bootVersion(uint32_t& version) { uint8_t buf[sizeof(version)]; STATUS rv = readRAM(0x0004, buf, sizeof(buf)); version = (rv == STATUS_OK ? read32(buf) : 0); return rv; } STATUS macAddress(uint8_t *buf, bool customer = true) { return readRAM(customer ? 0x01001570 : 0x01001580, buf, 8); } protected: virtual void programStart(const char *chipname, const char *filename, bool program) {} virtual void programProgress(size_t size, size_t processed) {} virtual void programEnd(STATUS status) {} private: // // for MONOWIRELESS TWELITE-R(2) / MONOSTICK // static const CBUS PIN_PROG = CBUS_3; static const CBUS PIN_RESET = CBUS_2; typedef enum : uint8_t { MSGTYPE_FLASH_ERASE_REQUEST = 0x07, MSGTYPE_FLASH_ERASE_RESPONSE = 0x08, MSGTYPE_FLASH_PROGRAM_REQUEST = 0x09, MSGTYPE_FLASH_PROGRAM_RESPONSE = 0x0A, MSGTYPE_FLASH_READ_REQUEST = 0x0B, MSGTYPE_FLASH_READ_RESPONSE = 0x0C, MSGTYPE_SECTOR_ERASE_REQUEST = 0x0D, MSGTYPE_SECTOR_ERASE_RESPONSE = 0x0E, MSGTYPE_WRITE_SR_REQUEST = 0x0F, MSGTYPE_WRITE_SR_RESPONSE = 0x10, MSGTYPE_SET_RESET_REQUEST = 0x14, MSGTYPE_SET_RESET_RESPONSE = 0x15, MSGTYPE_RAM_WRITE_REQUEST = 0x1D, MSGTYPE_RAM_WRITE_RESPONSE = 0x1E, MSGTYPE_RAM_READ_REQUEST = 0x1F, MSGTYPE_RAM_READ_RESPONSE = 0x20, MSGTYPE_RUN_REQUEST = 0x21, MSGTYPE_RUN_RESPONSE = 0x22, MSGTYPE_READ_FLASH_ID_REQUEST = 0x25, MSGTYPE_READ_FLASH_ID_RESPONSE = 0x26, MSGTYPE_CHANGE_BAUDRATE_REQUEST = 0x27, MSGTYPE_CHANGE_BAUDRATE_RESPONSE = 0x28, MSGTYPE_SELECT_FLASH_TYPE_REQUEST = 0x2C, MSGTYPE_SELECT_FLASH_TYPE_RESPONSE = 0x2D, MSGTYPE_GET_CHIP_ID_REQUEST = 0x32, MSGTYPE_GET_CHIP_ID_RESPONSE = 0x33, } MSGTYPE; void write32(uint8_t *buf, uint32_t data, bool littleEndian = true) { if (littleEndian) { buf[0] = (uint8_t)data; buf[1] = (uint8_t)(data >> 8); buf[2] = (uint8_t)(data >> 16); buf[3] = (uint8_t)(data >> 24); } else { buf[3] = (uint8_t)data; buf[2] = (uint8_t)(data >> 8); buf[1] = (uint8_t)(data >> 16); buf[0] = (uint8_t)(data >> 24); } } void write16(uint8_t *buf, uint16_t data, bool littleEndian = true) { if (littleEndian) { buf[0] = (uint8_t)data; buf[1] = (uint8_t)(data >> 8); } else { buf[1] = (uint8_t)data; buf[0] = (uint8_t)(data >> 8); } } uint32_t read32(const uint8_t *buf, bool littleEndian = false) { return littleEndian ? ((uint32_t)buf[3] << 24) | ((uint32_t)buf[2] << 16) | ((uint16_t)buf[1] << 8) | buf[0] : ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint16_t)buf[2] << 8) | buf[3]; } uint16_t read16(const uint8_t *buf, bool littleEndian = false) { return littleEndian ? ((uint16_t)buf[1] << 8) | buf[0] : ((uint16_t)buf[0] << 8) | buf[1]; } STATUS fileVersion(VERSION& version, FILE *fp) { uint8_t data[4]; fseek(fp, 0, SEEK_SET); if (fread(data, 1, sizeof(data), fp) != sizeof(data)) { version = (VERSION)0; return STATUS_FILE_READ_FAIL; } version = (VERSION)read32(data); return STATUS_OK; } uint8_t csum(void *buf, size_t len) { uint8_t *p = (uint8_t *)buf; uint8_t c = 0; while (len--) c ^= *p++; return c; } STATUS protocol(MSGTYPE msg, uint8_t *buf = nullptr, uint8_t len = 0) { memcpy(_packet + 2, buf, len); len += 2; _packet[0] = len; _packet[1] = msg; _packet[len] = csum(_packet, len); len += 1; if (write(_packet, len) != len) return STATUS_WRITE_FAIL; for (len = _packet[0] = 0; len <= _packet[0]; ) { uint8_t n = read(_packet + len, _packet[0] - len + 1); if (n == 0) { if (_debug) printf("Error: Message Type [%02X]\n", msg); return STATUS_NO_RESPONSE; } len += n; } return csum(_packet, len) ? STATUS_CRC_ERROR : (STATUS)_packet[2]; } bool _debug; SPEED _speed; uint32_t _timeout; std::string _chipidpath; uint8_t _packet[256]; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
/* jn516x.h - JN516x Chip Library for NXP JN516x Series Copyright (c) 2022-2024 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include <stdint.h> #define FLASH_START_ADDRESS 0x80000U #define FLASH_SECTOR_OFFSET(sec) (0x8000U * (sec)) #if defined(JN5161) #define CHIP_VERSION JN516x::VERSION_JN5161 #elif defined(JN5164) #define CHIP_VERSION JN516x::VERSION_JN5164 #elif defined(JN5168) #define CHIP_VERSION JN516x::VERSION_JN5168 #elif defined(JN5169) #define CHIP_VERSION JN516x::VERSION_JN5169 #elif defined(JN5179) #define CHIP_VERSION JN516x::VERSION_JN5179 #else #define CHIP_VERSION 0 #endif class JN516x { public: static const uint8_t MAGICNUMBER[12]; static const uint8_t MAGICNUMBER_JN5179[12]; typedef struct __attribute__((packed)) { uint8_t magicNumber[12]; uint8_t configuration; uint8_t status; uint16_t applicationID; } tsBIR; typedef struct __attribute__((packed)) { tsBIR sBIR; // 16-byte Boot Image Record uint8_t encryption[14]; // Encryption Initialisation Vector (ignored if unencrypted) uint16_t configuration; // 16-bit Software Configuration Options uint32_t imageSize; // 32-bit Length of Binary Image in bytes uint32_t dataStart; // 32-bit .data section Flash start address uint16_t dataAddress; // 16-bit .data section load address in RAM (word aligned) uint16_t dataLength; // 16-bit .data section length in 32-bit words uint16_t bssStart; // 16 bit .bss section start address in RAM (word aligned) uint16_t bssLength; // 16-bit .bss section length in 32-bit words uint32_t warmStart; // 32-bit wake-up entry point (word aligned) – warm start uint32_t coldStart; // 32-bit reset entry point (word aligned) – cold start } tsFlashHeader; typedef struct __attribute__((packed)) { uint32_t version; // version tsBIR sBIR; // 16-byte Boot Image Record uint8_t encryption[14]; // Encryption Initialisation Vector (ignored if unencrypted) uint16_t configuration; // 16-bit Software Configuration Options uint32_t imageSize; // 32-bit Length of Binary Image in bytes uint32_t dataStart; // 32-bit .data section Flash start address uint16_t dataAddress; // 16-bit .data section load address in RAM (word aligned) uint16_t dataLength; // 16-bit .data section length in 32-bit words uint16_t bssStart; // 16 bit .bss section start address in RAM (word aligned) uint16_t bssLength; // 16-bit .bss section length in 32-bit words uint32_t warmStart; // 32-bit wake-up entry point (word aligned) – warm start uint32_t coldStart; // 32-bit reset entry point (word aligned) – cold start } tsFlashHeader_JN5179; typedef enum { CHIPID_JN517x = 0xA686U, CHIPID_JN5169 = 0xB686U, CHIPID_JN516x = 0x8686U, CHIPID_JN5148 = 0x4686U, CHIPID_JN5142 = 0x5686U, CHIPID_JN5139 = 0x2000U, } CHIPID; typedef enum { VERSION_JN517x = 0x0000000AU, VERSION_JN5179 = 0x0F03000AU, VERSION_JN5178 = 0x0703000AU, VERSION_JN5174 = 0x0403000AU, VERSION_JN5169 = 0x0F03000BU, VERSION_JN516x = 0x00000008U, VERSION_JN5168 = 0x07030008U, VERSION_JN5164 = 0x04030008U, VERSION_JN5161 = 0x01000008U, } VERSION; typedef enum { FLASHID_ST_M25P05_A = 0x0505U, FLASHID_ST_M25P10_A = 0x1010U, FLASHID_ST_M25P20_A = 0x1101U, FLASHID_ST_M25P40 = 0x1212U, FLASHID_SST_25VF010A = 0xBF49U, FLASHID_ATMEL_25F512 = 0x1F60U, FLASHID_INTERNAL_FLASH = 0xCCEEU, // JN516x/7x only } FLASHID; typedef enum { FLASH_ST_M25P05_A = 4U, FLASH_ST_M25P10_A = 0U, FLASH_ST_M25P20_A = 5U, FLASH_ST_M25P40 = 3U, FLASH_SST_25VF010A = 1U, FLASH_ATMEL_25F512 = 2U, FLASH_INTERNAL_FLASH = 8U, // JN516x/7x only } FLASH; typedef struct __attribute__((packed)) { uint8_t command; union { uint8_t mode; uint8_t data[96]; uint32_t crc32; } args; } ota_request_t; typedef struct __attribute__((packed)) { uint8_t command; uint8_t status; union { struct __attribute__((packed)) { uint32_t version; uint8_t otaboot; } device; uint32_t crc32; } args; } ota_response_t; typedef enum { ADDR_BROADCAST = 0xFFFFU, ADDR_OTA_BOOT = ADDR_BROADCAST - 1, ADDR_OTA_BRIDGE = ADDR_BROADCAST - 2, ADDR_OTA_BRIDGE2 = ADDR_BROADCAST - 3, } ADDR; typedef enum { OTA_UPDATE_CHIPVER = 0xC0U, OTA_UPDATE_BLDMODE = 0xC1U, OTA_UPDATE_START = 0xC2U, OTA_UPDATE_PROGRAM = 0xC3U, OTA_UPDATE_END = 0xC4U, } OTA_UPDATE; typedef enum { OTA_STATUS_OK = 0x00U, OTA_STATUS_ARG_ERROR = 0xFAU, OTA_STATUS_BLD_ERROR = 0xFBU, OTA_STATUS_CRC_ERROR = 0xFCU, OTA_STATUS_SDK_ERROR = 0xFDU, } OTA_STATUS; static VERSION chipVersion(CHIPID id) { switch (id & 0xFFFF) { case CHIPID_JN517x : return VERSION_JN517x; case CHIPID_JN5169 : return VERSION_JN5169; case CHIPID_JN516x : return VERSION_JN516x; default: break; } return (VERSION)0; } static const char *chipName(VERSION version) { switch (version) { case VERSION_JN5179: return "JN5179"; case VERSION_JN5178: return "JN5178"; case VERSION_JN5174: return "JN5174"; case VERSION_JN5169: return "JN5169"; case VERSION_JN5168: return "JN5168"; case VERSION_JN5164: return "JN5164"; case VERSION_JN5161: return "JN5161"; default: break; } return "(unknown)"; } static uint32_t chipFlashSectors(VERSION version) { return (uint8_t)(version >> 24) + 1; } static uint32_t chipFlashSize(VERSION version) { return 32768U * chipFlashSectors(version); } static uint32_t chipRamSize(VERSION version) { return 8192U * ((uint8_t)(version >> 16) + 1); } static uint16_t chipType(VERSION version) { return (uint16_t)version; } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* jn516x.cpp - JN516x Chip Library for NXP JN516x Series Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "jn516x.h" const uint8_t JN516x::MAGICNUMBER[] = { 0x12, 0x34, 0x56, 0x78, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; const uint8_t JN516x::MAGICNUMBER_JN5179[] = { 0x12, 0x34, 0x56, 0x78, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
/* ftd2.h - Serial Library for FTDI USB Chip FT2XX Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include "ftd2xx.h" #include "sleep.h" #ifndef LOW #define LOW 0 #endif #ifndef HIGH #define HIGH 1 #endif extern FT_STATUS FT_GetLastError(void); class FTD2 { public: // // FT_OpenEx Flags // typedef enum { OPENBY_SERIAL_NUMBER = FT_OPEN_BY_SERIAL_NUMBER, OPENBY_DESCRIPTION = FT_OPEN_BY_DESCRIPTION, OPENBY_LOCATION = FT_OPEN_BY_LOCATION, } OPENBY; // // Baud Rates // typedef enum { SPEED_300 = FT_BAUD_300, SPEED_600 = FT_BAUD_600, SPEED_1200 = FT_BAUD_1200, SPEED_2400 = FT_BAUD_2400, SPEED_4800 = FT_BAUD_4800, SPEED_9600 = FT_BAUD_9600, SPEED_14400 = FT_BAUD_14400, SPEED_19200 = FT_BAUD_19200, SPEED_38400 = FT_BAUD_38400, SPEED_57600 = FT_BAUD_57600, SPEED_115200 = FT_BAUD_115200, SPEED_230400 = FT_BAUD_230400, SPEED_460800 = FT_BAUD_460800, SPEED_500K = 500000, SPEED_921600 = FT_BAUD_921600, SPEED_1M = 1000000, SPEED_2M = 2000000, SPEED_3M = 3000000, } SPEED; // // mode // typedef enum { MODE_7N1 = 0, MODE_8N1 = 1, MODE_7N2 = 2, MODE_8N2 = 3, MODE_7E1 = 4, MODE_8E1 = 5, MODE_7E2 = 6, MODE_8E2 = 7, MODE_7O1 = 8, MODE_8O1 = 9, MODE_7O2 = 10, MODE_8O2 = 11, } MODE; // // Flow Control // typedef enum { FLOW_NONE = FT_FLOW_NONE, FLOW_RTS_CTS = FT_FLOW_RTS_CTS, FLOW_DTR_DSR = FT_FLOW_DTR_DSR, FLOW_XON_XOFF = FT_FLOW_XON_XOFF, } FLOW; // // Bit Modes // typedef enum { BITMODE_RESET = FT_BITMODE_RESET, BITMODE_ASYNC_BITBANG = FT_BITMODE_ASYNC_BITBANG, BITMODE_MPSSE = FT_BITMODE_MPSSE, BITMODE_SYNC_BITBANG = FT_BITMODE_SYNC_BITBANG, BITMODE_MCU_HOST = FT_BITMODE_MCU_HOST, BITMODE_FAST_SERIAL = FT_BITMODE_FAST_SERIAL, BITMODE_CBUS_BITBANG = FT_BITMODE_CBUS_BITBANG, BITMODE_SYNC_FIFO = FT_BITMODE_SYNC_FIFO, } BITMODE; typedef enum { GPIO_INPUT = 0, GPIO_OUTPUT = 1, } GPIO; typedef enum { CBUS_0 = 0, CBUS_1 = 1, CBUS_2 = 2, CBUS_3 = 3, } CBUS; FTD2(BITMODE mode = BITMODE_CBUS_BITBANG) : _handle(0) , _mode(mode) , _cbus(0) { FT_Initialise(); } virtual ~FTD2(void) { end(); FT_Finalise(); } FT_STATUS status(void) { return FT_GetLastError(); } size_t getDeviceCount(void) { DWORD count = 0; FT_ListDevices(&count, NULL, FT_LIST_NUMBER_ONLY); return count; } bool getDeviceSerial(size_t index, char *buf) { strcpy(buf, "(null)"); return FT_SUCCESS(FT_ListDevices((void *)index, buf, FT_LIST_BY_INDEX | FT_OPEN_BY_SERIAL_NUMBER)); } bool getDeviceDescription(size_t index, char *buf) { strcpy(buf, "(null)"); return FT_SUCCESS(FT_ListDevices((void *)index, buf, FT_LIST_BY_INDEX | FT_OPEN_BY_DESCRIPTION)); } bool getDeviceLocation(size_t index, char *buf) { strcpy(buf, "(null)"); return FT_SUCCESS(FT_ListDevices((void *)index, buf, FT_LIST_BY_INDEX | FT_OPEN_BY_LOCATION)); } bool begin(int index, SPEED speed = SPEED_115200, MODE mode = MODE_8N1, FLOW flow = FLOW_NONE) { if (!FT_SUCCESS(FT_Open(index, &_handle))) return false; init(speed, mode, flow); return true; } bool begin(const char *name, SPEED speed = SPEED_115200, MODE mode = MODE_8N1, FLOW flow = FLOW_NONE) { char *eos; int index = strtoul(name, &eos, 10); if (*eos) { if (!FT_SUCCESS(FT_OpenEx((void *)name, OPENBY_SERIAL_NUMBER, &_handle))) return false; } else { if (!FT_SUCCESS(FT_Open(index, &_handle))) return false; } init(speed, mode, flow); return true; } bool end(void) { if (_handle) { FT_HANDLE h = _handle; _handle = nullptr; return FT_SUCCESS(FT_Close(h)); } return true; } int getComPortNumber(void) { LONG com = -1; FT_GetComPortNumber(_handle, &com); return com; } bool baudrate(SPEED speed) { switch (speed) { case SPEED_500K: return FT_SUCCESS(FT_SetDivisor(_handle, 6)); case SPEED_1M: return FT_SUCCESS(FT_SetDivisor(_handle, 3)); case SPEED_2M: return FT_SUCCESS(FT_SetDivisor(_handle, 1)); case SPEED_3M: return FT_SUCCESS(FT_SetDivisor(_handle, 0)); default: break; } return FT_SUCCESS(FT_SetBaudRate(_handle, speed)); } bool frame(MODE mode = MODE_8N1) { return FT_SUCCESS(FT_SetDataCharacteristics(_handle, mode & 1 ? DATA_8 : DATA_7, mode & 2 ? STOP_2 : STOP_1, mode & 4 ? PAR_EVEN : (mode & 8 ? PAR_NONE : PAR_NONE) )); } bool flowCtrl(FLOW mode, uint8_t xon = 0x11, uint8_t xoff = 0x13) { return FT_SUCCESS(FT_SetFlowControl(_handle, mode, xon, xoff)); } bool dtr(bool on) { return FT_SUCCESS(on ? FT_SetDtr(_handle) : FT_ClrDtr(_handle)); } bool rts(bool on) { return FT_SUCCESS(on ? FT_SetRts(_handle) : FT_ClrRts(_handle)); } bool timeout(uint32_t readTimeout, uint32_t writeTimeout) { return FT_SUCCESS(FT_SetTimeouts(_handle, readTimeout, writeTimeout)); } bool purge(void) { return FT_SUCCESS(FT_Purge(_handle, FT_PURGE_RX | FT_PURGE_TX)); } size_t read(void *buf, size_t len) { DWORD bytesReceived = 0; FT_Read(_handle, buf, len, &bytesReceived); return bytesReceived; } size_t write(const void *buf, size_t len) { DWORD bytesWritten = 0; FT_Write(_handle, (void *)buf, len, &bytesWritten); return bytesWritten; } void pinMode(CBUS pin, GPIO mode) { pin = (CBUS)((pin & 3) + 4); if (mode == GPIO_OUTPUT) _cbus |= (1 << pin); else _cbus &= ~(1 << pin); FT_SetBitMode(_handle, _cbus, _mode); } void digitalWrite(CBUS pin, uint8_t value) { pin = (CBUS)(pin & 3); if (value) _cbus |= (1 << pin); else _cbus &= ~(1 << pin); FT_SetBitMode(_handle, _cbus, _mode); } uint8_t digitalRead(CBUS pin) { pin = (CBUS)(pin & 3); uint8_t mask = _cbus >> 4; uint8_t data = 0; FT_GetBitMode(_handle, &data); return (((data & ~mask) | (_cbus & mask)) >> pin) & 1; } protected: void init(SPEED speed, MODE mode, FLOW flow) { baudrate(speed); frame(mode); flowCtrl(flow); rts(true); dtr(true); timeout(1000, 1000); purge(); FT_SetBitMode(_handle, _cbus, BITMODE_RESET); } private: // // Word Lengths // typedef enum { DATA_8 = FT_BITS_8, DATA_7 = FT_BITS_7, } DATA; // // Stop Bits // typedef enum { STOP_1 = FT_STOP_BITS_1, STOP_2 = FT_STOP_BITS_2, } STOP; // // Parity // typedef enum { PAR_NONE = FT_PARITY_NONE, PAR_ODD = FT_PARITY_ODD, PAR_EVEN = FT_PARITY_EVEN, PAR_MARK = FT_PARITY_MARK, PAR_SPACE = FT_PARITY_SPACE, } PAR; FT_HANDLE _handle; uint8_t _mode; uint8_t _cbus; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
/* ftd2.cpp - Serial Library for FTDI USB Chip FT2XX Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ftd2.h" typedef FT_STATUS (WINAPI *LPFN_FT_ListDevices)(PVOID pvArg1, PVOID pvArg2, DWORD dwFlags); typedef FT_STATUS (WINAPI *LPFN_FT_Open)(int iDevice, FT_HANDLE *ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_OpenEx)(PVOID pArg1, DWORD Flags, FT_HANDLE *pHandle); typedef FT_STATUS (WINAPI *LPFN_FT_Close)(FT_HANDLE ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_SetTimeouts)(FT_HANDLE ftHandle, DWORD dwReadTimeout, DWORD dwWriteTimeout); typedef FT_STATUS (WINAPI *LPFN_FT_Read)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned); typedef FT_STATUS (WINAPI *LPFN_FT_Write)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten); typedef FT_STATUS (WINAPI *LPFN_FT_SetBaudRate)(FT_HANDLE ftHandle, ULONG BaudRate); typedef FT_STATUS (WINAPI *LPFN_FT_SetDivisor)(FT_HANDLE ftHandle, USHORT usDivisor); typedef FT_STATUS (WINAPI *LPFN_FT_SetDataCharacteristics)(FT_HANDLE ftHandle, UCHAR WordLength, UCHAR StopBits, UCHAR Parity); typedef FT_STATUS (WINAPI *LPFN_FT_SetFlowControl)(FT_HANDLE ftHandle, USHORT FlowControl, UCHAR XonChar, UCHAR XoffChar); typedef FT_STATUS (WINAPI *LPFN_FT_SetDtr)(FT_HANDLE ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_ClrDtr)(FT_HANDLE ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_SetRts)(FT_HANDLE ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_ClrRts)(FT_HANDLE ftHandle); typedef FT_STATUS (WINAPI *LPFN_FT_SetBitMode)(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable); typedef FT_STATUS (WINAPI *LPFN_FT_GetBitMode)(FT_HANDLE ftHandle, PUCHAR pucMode); typedef FT_STATUS (WINAPI *LPFN_FT_GetComPortNumber)(FT_HANDLE ftHandle, LPLONG lplComPortNumber); typedef FT_STATUS (WINAPI *LPFN_FT_Purge)(FT_HANDLE ftHandle, ULONG Mask); static HMODULE hFTD2XX; static LPFN_FT_ListDevices lpfn_FT_ListDevices; static LPFN_FT_Open lpfn_FT_Open; static LPFN_FT_OpenEx lpfn_FT_OpenEx; static LPFN_FT_Close lpfn_FT_Close; static LPFN_FT_SetTimeouts lpfn_FT_SetTimeouts; static LPFN_FT_Read lpfn_FT_Read; static LPFN_FT_Write lpfn_FT_Write; static LPFN_FT_SetBaudRate lpfn_FT_SetBaudRate; static LPFN_FT_SetDivisor lpfn_FT_SetDivisor; static LPFN_FT_SetDataCharacteristics lpfn_FT_SetDataCharacteristics; static LPFN_FT_SetFlowControl lpfn_FT_SetFlowControl; static LPFN_FT_SetDtr lpfn_FT_SetDtr; static LPFN_FT_ClrDtr lpfn_FT_ClrDtr; static LPFN_FT_SetRts lpfn_FT_SetRts; static LPFN_FT_ClrRts lpfn_FT_ClrRts; static LPFN_FT_SetBitMode lpfn_FT_SetBitMode; static LPFN_FT_GetBitMode lpfn_FT_GetBitMode; static LPFN_FT_GetComPortNumber lpfn_FT_GetComPortNumber; static LPFN_FT_Purge lpfn_FT_Purge; static FT_STATUS status = FT_OK; FT_STATUS FT_GetLastError(void) { return status; } FT_STATUS WINAPI FT_Initialise(void) { if (!hFTD2XX) { if (!(hFTD2XX = LoadLibrary("ftd2xx.dll"))) return status = FT_NOT_SUPPORTED; lpfn_FT_ListDevices = (LPFN_FT_ListDevices) GetProcAddress(hFTD2XX, "FT_ListDevices"); lpfn_FT_Open = (LPFN_FT_Open) GetProcAddress(hFTD2XX, "FT_Open"); lpfn_FT_OpenEx = (LPFN_FT_OpenEx) GetProcAddress(hFTD2XX, "FT_OpenEx"); lpfn_FT_Close = (LPFN_FT_Close) GetProcAddress(hFTD2XX, "FT_Close"); lpfn_FT_SetTimeouts = (LPFN_FT_SetTimeouts) GetProcAddress(hFTD2XX, "FT_SetTimeouts"); lpfn_FT_Read = (LPFN_FT_Read) GetProcAddress(hFTD2XX, "FT_Read"); lpfn_FT_Write = (LPFN_FT_Write) GetProcAddress(hFTD2XX, "FT_Write"); lpfn_FT_SetBaudRate = (LPFN_FT_SetBaudRate) GetProcAddress(hFTD2XX, "FT_SetBaudRate"); lpfn_FT_SetDivisor = (LPFN_FT_SetDivisor) GetProcAddress(hFTD2XX, "FT_SetDivisor"); lpfn_FT_SetDataCharacteristics = (LPFN_FT_SetDataCharacteristics)GetProcAddress(hFTD2XX, "FT_SetDataCharacteristics"); lpfn_FT_SetFlowControl = (LPFN_FT_SetFlowControl) GetProcAddress(hFTD2XX, "FT_SetFlowControl"); lpfn_FT_SetDtr = (LPFN_FT_SetDtr) GetProcAddress(hFTD2XX, "FT_SetDtr"); lpfn_FT_ClrDtr = (LPFN_FT_ClrDtr) GetProcAddress(hFTD2XX, "FT_ClrDtr"); lpfn_FT_SetRts = (LPFN_FT_SetRts) GetProcAddress(hFTD2XX, "FT_SetRts"); lpfn_FT_ClrRts = (LPFN_FT_ClrRts) GetProcAddress(hFTD2XX, "FT_ClrRts"); lpfn_FT_SetBitMode = (LPFN_FT_SetBitMode) GetProcAddress(hFTD2XX, "FT_SetBitMode"); lpfn_FT_GetBitMode = (LPFN_FT_GetBitMode) GetProcAddress(hFTD2XX, "FT_GetBitMode"); lpfn_FT_GetComPortNumber = (LPFN_FT_GetComPortNumber) GetProcAddress(hFTD2XX, "FT_GetComPortNumber"); lpfn_FT_Purge = (LPFN_FT_Purge) GetProcAddress(hFTD2XX, "FN_FT_Purge"); } return status = FT_OK; } void WINAPI FT_Finalise(void) { if (hFTD2XX) { FreeLibrary(hFTD2XX); hFTD2XX = NULL; } } FTD2XX_API FT_STATUS FT_ListDevices(PVOID pvArg1, PVOID pvArg2, DWORD dwFlags) { return status = (lpfn_FT_ListDevices ? lpfn_FT_ListDevices(pvArg1, pvArg2, dwFlags) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_Open(int iDevice, FT_HANDLE *ftHandle) { return status = (lpfn_FT_Open ? lpfn_FT_Open(iDevice, ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_OpenEx(PVOID pArg1, DWORD Flags, FT_HANDLE *pHandle) { return status = (lpfn_FT_OpenEx ? lpfn_FT_OpenEx(pArg1, Flags, pHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_Close(FT_HANDLE ftHandle) { return status = (lpfn_FT_Close ? lpfn_FT_Close(ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetTimeouts(FT_HANDLE ftHandle, DWORD dwReadTimeout, DWORD dwWriteTimeout) { return status = (lpfn_FT_SetTimeouts ? lpfn_FT_SetTimeouts(ftHandle, dwReadTimeout, dwWriteTimeout) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_Read(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned) { return status = (lpfn_FT_Read ? lpfn_FT_Read(ftHandle, lpBuffer, dwBytesToRead, lpBytesReturned) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_Write(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten) { return status = (lpfn_FT_Write ? lpfn_FT_Write(ftHandle, lpBuffer, dwBytesToWrite, lpBytesWritten) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetBaudRate(FT_HANDLE ftHandle, ULONG BaudRate) { return status = (lpfn_FT_SetBaudRate ? lpfn_FT_SetBaudRate(ftHandle, BaudRate) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetDivisor(FT_HANDLE ftHandle, USHORT usDivisor) { return status = (lpfn_FT_SetDivisor ? lpfn_FT_SetDivisor(ftHandle, usDivisor) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetDataCharacteristics(FT_HANDLE ftHandle, UCHAR WordLength, UCHAR StopBits, UCHAR Parity) { return status = (lpfn_FT_SetDataCharacteristics ? lpfn_FT_SetDataCharacteristics(ftHandle, WordLength, StopBits, Parity) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetFlowControl(FT_HANDLE ftHandle, USHORT FlowControl, UCHAR XonChar, UCHAR XoffChar) { return status = (lpfn_FT_SetFlowControl ? lpfn_FT_SetFlowControl(ftHandle, FlowControl, XonChar, XoffChar) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetDtr(FT_HANDLE ftHandle) { return status = (lpfn_FT_SetDtr ? lpfn_FT_SetDtr(ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_ClrDtr(FT_HANDLE ftHandle) { return status = (lpfn_FT_ClrDtr ? lpfn_FT_ClrDtr(ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetRts(FT_HANDLE ftHandle) { return status = (lpfn_FT_SetRts ? lpfn_FT_SetRts(ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_ClrRts(FT_HANDLE ftHandle) { return status = (lpfn_FT_ClrRts ? lpfn_FT_ClrRts(ftHandle) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_SetBitMode(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable) { return status = (lpfn_FT_SetBitMode ? lpfn_FT_SetBitMode(ftHandle, ucMask, ucEnable) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_GetBitMode(FT_HANDLE ftHandle, PUCHAR pucMode) { return status = (lpfn_FT_GetBitMode ? lpfn_FT_GetBitMode(ftHandle, pucMode) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_GetComPortNumber(FT_HANDLE ftHandle, LPLONG lplComPortNumber) { return status = (lpfn_FT_GetComPortNumber ? lpfn_FT_GetComPortNumber(ftHandle, lplComPortNumber) : FT_NOT_SUPPORTED); } FTD2XX_API FT_STATUS FT_Purge(FT_HANDLE ftHandle, ULONG Mask) { return status = (lpfn_FT_Purge ? lpfn_FT_Purge(ftHandle, Mask) : FT_NOT_SUPPORTED); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/* sleep.h - Sleep Library Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #ifdef __linux__ #include <time.h> #else #include <windows.h> #endif class Sleep { public: static void sleep(unsigned long ms) { #ifdef __linux__ struct timespec req; req.tv_sec = (ms / 1000); req.tv_nsec = (ms % 1000) * 1000000; nanosleep(&req, NULL); #else ::Sleep(ms); #endif } }; |