From 761141dab71ef3d772f0ea5be741fa6374573f17 Mon Sep 17 00:00:00 2001 From: Neal Smith Date: Tue, 10 Oct 2017 18:13:06 -0700 Subject: [PATCH] adding the source --- api/LICENSE | 193 +++++++ api/include/mvnc.h | 69 +++ api/include/mvnc_deprecated.h | 39 ++ api/python/mvnc/__init__.py | 0 api/python/mvnc/mvncapi.py | 268 ++++++++++ api/src/97-usbboot.rules | 3 + api/src/Makefile | 79 +++ api/src/Makefile.rpi | 43 ++ api/src/USBLinkDefines.h | 65 +++ api/src/common.h | 34 ++ api/src/mvnc_api.c | 966 ++++++++++++++++++++++++++++++++++ api/src/usb_boot.c | 335 ++++++++++++ api/src/usb_boot.h | 21 + api/src/usb_link.h | 28 + api/src/usb_link_vsc.c | 204 +++++++ 15 files changed, 2347 insertions(+) create mode 100644 api/LICENSE create mode 100644 api/include/mvnc.h create mode 100644 api/include/mvnc_deprecated.h create mode 100644 api/python/mvnc/__init__.py create mode 100644 api/python/mvnc/mvncapi.py create mode 100644 api/src/97-usbboot.rules create mode 100644 api/src/Makefile create mode 100644 api/src/Makefile.rpi create mode 100644 api/src/USBLinkDefines.h create mode 100644 api/src/common.h create mode 100644 api/src/mvnc_api.c create mode 100644 api/src/usb_boot.c create mode 100644 api/src/usb_boot.h create mode 100644 api/src/usb_link.h create mode 100644 api/src/usb_link_vsc.c diff --git a/api/LICENSE b/api/LICENSE new file mode 100644 index 0000000..a444ba1 --- /dev/null +++ b/api/LICENSE @@ -0,0 +1,193 @@ +SOFTWARE TOOLS LICENSE AGREEMENT + +DO NOT DOWNLOAD, INSTALL, ACCESS, COPY, OR USE ANY PORTION OF THE MATERIALS (DEFINED BELOW) UNTIL YOU HAVE READ AND ACCEPTED +THE TERMS AND CONDITIONS OF THIS AGREEMENT. BY INSTALLING, COPYING, ACCESSING, OR USING THE MATERIALS, YOU AGREE TO BE LEGALLY +BOUND BY THE TERMS AND CONDITIONS OF THIS AGREEMENT. If You do not agree to be bound by, or the entity for whose benefit You act has not +authorized You to accept, these terms and conditions, do not install, access, copy, or use the Software and destroy all copies of the Software in Your +possession. + +This DEVELOPMENT TOOLS LICENSE AGREEMENT (this "Agreement") is entered into between Intel Corporation, a Delaware corporation ("Intel") and You. +"You" refers to you or your employer or other entity for whose benefit you act, as applicable. If you are agreeing to the terms and conditions of this +Agreement on behalf of a company or other legal entity, you represent and warrant that you have the legal authority to bind that legal entity to the +Agreement, in which case, "You" or "Your" shall be in reference to such entity. Intel and You are referred to herein individually as a "Party" or, together, as +the "Parties". + +The Parties, in consideration of the mutual covenants contained in this Agreement, and for other good and valuable consideration, the receipt and +sufficiency of which they acknowledge, and intending to be legally bound, agree as follows: + +1. DEFINITIONS. The following definitions are used throughout this Agreement: +"Affiliate" means any entity controlling, controlled by or under common control with a Party hereto, where "control" means the direct or indirect ownership +of more than fifty percent (50%) of such entity"s capital or equivalent voting rights. An entity will be deemed an "Affiliate" only as long as such control exists +during the term of this Agreement. + +"Contractor" means a third party consultant or subcontractor who requires access to or use of the Materials to perform work on Your behalf or at Your +behest. + +"Development Tools" means the development, evaluation, production, or test tool software, and associated documentation or other collateral, identified +in the "development_tools.txt" text files, if any, included in the Materials. + +"Derivatives" means derivative works as defined in 17 U.S.C " 101 et seq. + +"Intel-based Device" means a device designed, manufactured, or configured by You or Your Affiliates to include or operate Intel hardware, software, or +services. + +"Materials" means the software, documentation, the software product serial number and license key codes (if applicable), Development Tools, +Redistributables, and other materials or collateral, including any updates and upgrades thereto, in source code or object code form where applicable, that +are provided or otherwise made available by Intel to You under this Agreement. "Materials" do not include Open Source Software or any computer +programming code that is subject to an agreement, obligation or license (whether or not accompanying the Materials) intended to supersede this +Agreement. + +"Redistributables" means the software, documentation, or other collateral identified in the "redist.txt" text files, if any, included in the Materials. + +2. LIMITED LICENSE. +(A) Subject to the terms and conditions of this Agreement, Intel grants You and Your Affiliates, a limited, nonexclusive, nontransferable, revocable, +worldwide, fully paid-up license during the term of this Agreement, without the right to sublicense, unless expressly stated otherwise, to: +(1) internally reproduce and install a reasonable number of copies of the Materials for Your internal use solely for the purposes of designing, +developing, manufacturing and testing Intel-based Devices; +(2) internally reproduce the source code of the Development Tools, if provided to You by Intel, and to internally create and reproduce Derivatives of +the Development Tools, and to internally reproduce the binary code of the Development Tools, or any Derivatives created by You, in each case solely +for the purpose of designing, developing, manufacturing and testing the Intel-based Device, solely as necessary for the integration of any Intel software +and the output generated by the Development Tools, with and into Intel-based Devices; +(3) create Derivatives of the Redistributables, or any portions thereof, provided to You by Intel in source code form solely for the purposes of designing, +developing, debugging, modifying, distributing and testing software containing significantly more functionality and features than the Redistributables +in the form provided to You by Intel; +(4) distribute (or otherwise make available) on a royalty-free basis, subject to any other terms and conditions which may appear in the Redistributables +text files, the Redistributables, including any Derivatives of the Redistributables pursuant to Section 2(A)(3), or any portions thereof, only as integrated +or embedded in software (and not on a stand-alone basis) solely for use on an Intel-based Device; and +(5) have the tasks set forth in Section 2(A)(1) and (2) above performed by a Contractor on the conditions that You enter into a written confidentiality +agreement with any such Contractor, subject to Section 7 (Confidentiality), and You remain fully liable to Intel for the actions and inactions of Your +Contractors. +(B) You will be liable for Your Affiliate"s breach of these terms. In addition, You acknowledge that Your Affiliates are beneficiaries of the licenses granted by +Intel under Section 2. +(C) Intel hereby grants You the right to sub-license (without rights to further sublicense) the Development Tools, including any accompanying +documentation, to Your manufacturing partners, in the code format provided to You by Intel, solely for designing, developing, manufacturing and testing +the Intel-based Devices solely as necessary for the integration of any Intel software and the output generated by the Development Tools, with and into +Intel-based Devices. The sublicense is subject to a written sublicensing agreement that contains confidentiality obligations and license restrictions that are +no less protective of Intel than those provided in this Agreement. You will be fully responsible and liable towards Intel for Your sub-licensees" compliance +with all such confidentiality obligations and license restrictions. You may grant Your manufacturing partners the right to further distribute Redistributables +solely as integrated or embedded in software for Your Intel-based Devices. + +3. LICENSE RESTRICTIONS. All right, title and interest in and to the Materials and associated documentation are and will remain the exclusive property of +Intel and its suppliers. Unless expressly permitted under the Agreement, You will not, and will not allow any third party to (i) use, copy, distribute, sell or +offer to sell the Materials or associated documentation; (ii) modify, adapt, enhance, disassemble, decompile, reverse engineer, change or create derivative +works from the Materials except and only to the extent as specifically required by mandatory applicable laws or any applicable third party license terms +accompanying the Materials; (iii) use or make the Materials available for the use or benefit of third parties; or (iv) use the Materials on Your products other +than those that include the Intel product(s), platform(s), or software identified in the Materials; or (v) publish or provide any Materials benchmark or +comparison test results. +If You received the Materials solely for evaluation purposes, You have no distribution rights to the Materials or any portion thereof. + +Distribution of the Redistributables is also subject to the following conditions: You shall: (i) be solely responsible to Your customers and end users for any +update or support obligation or other liability which may arise from the distribution, (ii) not make any statement that Your software is "certified", or that its +performance is guaranteed, by Intel, (iii) not use Intel's name or trademarks to promote Your software without prior written permission, (iv) use a license +agreement that contains provisions that are at least as restrictive as this Agreement and which prohibits disassembly and reverse engineering of the +Materials provided in object code form, and (v) indemnify, hold harmless, and defend Intel, Intel"s Affiliates, and its licensors from and against any claims +or lawsuits, including attorney's fees, that arise or result from Your Derivatives or Your distribution of Your software. + +The consideration under this Agreement is only for the licenses Intel expressly grants above. Any other rights including, but not limited to, additional patent +rights, will require an additional license and additional consideration. Nothing in this Agreement requires or will be treated to require Intel to grant any +additional license. You acknowledge that an essential basis of the bargain in this Agreement is that Intel grants You no licenses or other rights including, +but not limited to, patent, copyright, trade secret, trademark, trade name, service mark or other intellectual property licenses or rights with respect to the +Materials and associated documentation, by implication, estoppel or otherwise, except for the licenses expressly granted above. You acknowledge there +are significant uses of the Materials in their original, unmodified and uncombined form. The consideration for the licenses in this Agreement reflects Intel"s +continuing right to assert patent claims against any modifications or derivative works (including, without limitation, error corrections and bug fixes) of, or +combinations with, the Materials that You, Your Affiliates or third parties make that infringe any Intel patent claim. + +4. LICENSE TO FEEDBACK. This Agreement does not obligate You to provide Intel with materials, information, comments, suggestions, Your Derivatives or +other communication regarding the features, functions, performance or use of the Materials ("Feedback"). If any software included in the Materials is +provided or otherwise made available by Intel in source code form, to the extent You provide Intel with Feedback in a tangible form, You grant to Intel and +its affiliates a non-exclusive, perpetual, sublicenseable, irrevocable, worldwide, royalty-free, fully paid-up and transferable license, to and under all of Your +intellectual property rights, whether perfected or not, to publicly perform, publicly display, reproduce, use, make, have made, sell, offer for sale, distribute, +import, create derivative works of and otherwise exploit any comments, suggestions, descriptions, ideas, Your Derivatives or other feedback regarding the +Materials provided by You or on Your behalf. + +5. OPEN SOURCE STATEMENT. The Materials may include Open Source Software (OSS) licensed pursuant to OSS license agreement(s) identified in the +OSS comments in the applicable source code file(s) and/or file header(s) provided with or otherwise associated with the Materials. Neither You nor any +Original Equipment Manufacturer (OEM), Original Device Manufacturer (ODM), customer, or distributor may subject any proprietary portion of the Materials +to any OSS license obligations including, without limitation, combining or distributing the Materials with OSS in a manner that subjects Intel, the Materials +or any portion thereof to any OSS license obligation. Nothing in this Agreement limits any rights under, or grants rights that supersede, the terms of any +applicable OSS license. + +6. THIRD PARTY SOFTWARE. Certain third party software provided with or within the Materials may only be used (a) upon securing a license directly from +the owner of the software or (b) in combination with hardware components purchased from such third party and (c) subject to further license limitations +by the software owner. A listing of any such third party limitations is in one or more text files accompanying the Materials. You acknowledge Intel is not +providing You with a license to such third party software and further that it is Your responsibility to obtain appropriate licenses from such third parties +directly. + +7. CONFIDENTIALITY. The terms and conditions of this Agreement, exchanged confidential information, as well as the Materials are subject to the terms +and conditions of the Non-Disclosure Agreement(s) or Intel Pre-Release Loan Agreement(s) (referred to herein collectively or individually as "NDA") entered +into by and in force between Intel and You, and in any case no less confidentiality protection than You apply to Your information of similar sensitivity. If +You would like to have a Contractor perform work on Your behalf that requires any access to or use of Materials You must obtain a written confidentiality +agreement from the Contractor which contains terms and conditions with respect to access to or use of Materials no less restrictive than those set forth in +this Agreement, excluding any distribution rights and use for any other purpose, and You will remain fully liable to Intel for the actions and inactions of +those Contractors. You may not use Intel's name in any publications, advertisements, or other announcements without Intel's prior written consent. + +8. NO OBLIGATION; NO AGENCY. Intel may make changes to the Software, or items referenced therein, at any time without notice. Intel is not obligated to +support, update, provide training for, or develop any further version of the Software or to grant any license thereto. No agency, franchise, partnership, joint- +venture, or employee-employer relationship is intended or created by this Agreement. + +9. EXCLUSION OF WARRANTIES. THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING +WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. Intel does not warrant or assume responsibility +for the accuracy or completeness of any information, text, graphics, links or other items within the Materials. + +10. LIMITATION OF LIABILITY. IN NO EVENT WILL INTEL OR ITS AFFILIATES, LICENSORS OR SUPPLIERS (INCLUDING THEIR RESPECTIVE DIRECTORS, +OFFICERS, EMPLOYEES, AND AGENTS) BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, LOST PROFITS, BUSINESS +INTERRUPTION, OR LOST DATA) ARISING OUT OF OR IN RELATION TO THIS AGREEMENT, INCLUDING THE USE OF OR INABILITY TO USE THE MATERIALS, +EVEN IF INTEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS PROHIBIT EXCLUSION OR LIMITATION OF LIABILITY +FOR IMPLIED WARRANTIES OR CONSEQUENTIAL OR INCIDENTAL DAMAGES, SO THE ABOVE LIMITATION MAY IN PART NOT APPLY TO YOU. YOU MAY +ALSO HAVE OTHER LEGAL RIGHTS THAT VARY FROM JURISDICTION TO JURISDICTION. THE MATERIALS LICENSED HEREUNDER ARE NOT DESIGNED +OR INTENDED FOR USE IN ANY MEDICAL, LIFE SAVING OR LIFE SUSTAINING SYSTEMS, TRANSPORTATION SYSTEMS, NUCLEAR SYSTEMS, OR FOR ANY +OTHER MISSION CRITICAL APPLICATION IN WHICH THE FAILURE OF THE DEVELOPMENT TOOLS COULD LEAD TO PERSONAL INJURY OR DEATH. YOU +WILL INDEMNIFY AND HOLD INTEL AND ITS AFFILIATES, LICENSORS AND SUPPLIERS (INCLUDING THEIR RESPECTIVE DIRECTORS, OFFICERS, +EMPLOYEES, AND AGENTS) HARMLESS AGAINST ALL CLAIMS, LIABILITIES, LOSSES, COSTS, DAMAGES, AND EXPENSES (INCLUDING REASONABLE +ATTORNEY FEES), ARISING OUT OF, DIRECTLY OR INDIRECTLY, THE DISTRIBUTION OF THE MATERIALS AND ANY CLAIM OF PRODUCT LIABILITY, +PERSONAL INJURY OR DEATH ASSOCIATED WITH ANY UNINTENDED USE, EVEN IF SUCH CLAIM ALLEGES THAT INTEL OR AN INTEL AFFILIATE, LICENSOR +OR SUPPLIER WAS NEGLIGENT REGARDING THE DESIGN OR MANUFACTURE OF THE MATERIALS. THE LIMITED REMEDIES, WARRANTY DISCLAIMER AND +LIMITED LIABILITY ARE FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN INTEL AND YOU AND INTEL WOULD NOT BE ABLE TO +PROVIDE THE MATERIALS WITHOUT SUCH LIMITATIONS. + +11. TERMINATION AND SURVIVAL. Intel may terminate this Agreement for any reason with thirty (30) days" notice and immediately if You or someone +acting on Your behalf or at Your behest violates any of its terms or conditions. Upon termination You will immediately destroy and ensure the destruction +of the Materials (including providing certification of such destruction or return back to Intel). Upon termination of this Agreement, all licenses granted to +You hereunder terminate immediately. All Sections of this Agreement, except Section 2, will survive termination. In the event of termination of this +Agreement, the license grant to any Redistributables, including Your Derivatives of the Redistributables, distributed by You prior to the effective date of +such termination and in accordance with the terms and conditions of this Agreement shall survive any such termination of this Agreement. + +12. GOVERNING LAW AND JURISDICTION. This Agreement and any dispute arising out of or relating to it will be governed by the laws of the U.S.A. and +Delaware, without regard to conflict of laws principles. The Parties exclude the application of the United Nations Convention on Contracts for the +International Sale of Goods (1980). The state and federal courts sitting in Delaware, U.S.A. will have exclusive jurisdiction over any dispute arising out of or +relating to this Agreement. The Parties consent to personal jurisdiction and venue in those courts. A Party that obtains a judgment against the other Party +in the courts identified in this section may enforce that judgment in any court that has jurisdiction over the Parties. + +13. EXPORT REGULATIONS/EXPORT CONTROL. You agree that neither You nor Your subsidiaries or Affiliates will export/re-export the Materials, directly +or indirectly, to any country for which the U.S. Department of Commerce or any other agency or department of the U.S. Government or the foreign +government from where it is shipping requires an export license, or other governmental approval, without first obtaining any such required license or +approval. In the event the Materials are exported from the U.S.A. or re-exported from a foreign destination by You, Your subsidiaries, or Your Affiliates, You +will ensure that the distribution and export/re-export or import of the Materials complies with all laws, regulations, orders, or other restrictions of the U.S. +Export Administration Regulations and the appropriate foreign government. + +14. GOVERNMENT RESTRICTED RIGHTS. The Materials are a commercial item (as defined in 48 C.F.R. 2.101) consisting of commercial computer software +and commercial computer software documentation (as those terms are used in 48 C.F.R. 12.212). Consistent with 48 C.F.R. 12.212 and 48 C.F.R 227.72021 +through 227.7202-4, You will not provide the Materials to the U.S. Government. Contractor or Manufacturer is Intel Corporation, 2200 Mission College +Blvd., Santa Clara, CA 95054. + +15. TRADEMARKS. Third party trademarks, trade names, product names and logos (the "Trademarks") contained in or used by the Materials are the +trademarks or registered trademarks of their respective owners, and the use of such Trademarks shall inure to the benefit of the trademark owner. The +reference to such Trademarks (if any) by Intel in any of the Materials does not constitute: (i) an affiliation by Intel and its licensors with such company, or (ii) +an endorsement or approval of such company of Intel and its licensors and its products or services. + +16. ASSIGNMENT. You may not delegate, assign or transfer this Agreement, the license(s) granted or any of Your rights or duties hereunder, expressly, by +implication, by operation of law, or otherwise and any attempt to do so, without Intel"s express prior written consent, will be null and void. Intel may assign, +delegate and transfer this Agreement, and its rights and obligations hereunder, in its sole discretion. + +17. ENTIRE AGREEMENT; SEVERABILITY. The terms and conditions of this Agreement and any NDA with Intel constitute the entire agreement between the +Parties with respect to the subject matter hereof, and merge and supersede all prior or contemporaneous agreements, understandings, negotiations and +discussions. Neither Party will be bound by any terms, conditions, definitions, warranties, understandings, or representations with respect to the subject +matter hereof other than as expressly provided herein. In the event any provision of this Agreement is unenforceable or invalid under any applicable law +or applicable court decision, such unenforceability or invalidity will not render this Agreement unenforceable or invalid as a whole, instead such provision +will be changed and interpreted so as to best accomplish the objectives of such provision within legal limits. + +18. WAIVER. The failure of a Party to require performance by the other Party of any provision hereof will not affect the full right to require such performance +at any time thereafter; nor will waiver by a Party of a breach of any provision hereof constitute a waiver of the provision itself. + +19. PRIVACY. YOUR PRIVACY RIGHTS ARE SET FORTH IN INTEL'S PRIVACY NOTICE, WHICH FORMS A PART OF THIS AGREEMENT. PLEASE REVIEW THE +PRIVACY NOTICE AT HTTP://WWW.INTEL.COM/PRIVACY TO LEARN HOW INTEL COLLECTS, USES AND SHARES INFORMATION ABOUT YOU. diff --git a/api/include/mvnc.h b/api/include/mvnc.h new file mode 100644 index 0000000..082bd19 --- /dev/null +++ b/api/include/mvnc.h @@ -0,0 +1,69 @@ +#ifndef __MVNC_H_INCLUDED__ +#define __MVNC_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MVNC_MAX_NAME_SIZE 28 + +typedef enum { + MVNC_OK = 0, + MVNC_BUSY = -1, // Device is busy, retry later + MVNC_ERROR = -2, // Error communicating with the device + MVNC_OUT_OF_MEMORY = -3, // Out of memory + MVNC_DEVICE_NOT_FOUND = -4, // No device at the given index or name + MVNC_INVALID_PARAMETERS = -5, // At least one of the given parameters is wrong + MVNC_TIMEOUT = -6, // Timeout in the communication with the device + MVNC_MVCMD_NOT_FOUND = -7, // The file to boot Myriad was not found + MVNC_NO_DATA = -8, // No data to return, call LoadTensor first + MVNC_GONE = -9, // The graph or device has been closed during the operation + MVNC_UNSUPPORTED_GRAPH_FILE = -10, // The graph file version is not supported + MVNC_MYRIAD_ERROR = -11, // An error has been reported by the device, use MVNC_DEBUG_INFO +} mvncStatus; + +typedef enum { + MVNC_LOG_LEVEL = 0, // Log level, int, 0 = nothing, 1 = errors, 2 = verbose +} mvncGlobalOptions; + +typedef enum { + MVNC_ITERATIONS = 0, // Number of iterations per inference, int, normally 1, not for general use + MVNC_NETWORK_THROTTLE = 1, // Measure temperature once per inference instead of once per layer, int, not for general use + MVNC_DONT_BLOCK = 2, // LoadTensor will return BUSY instead of blocking, GetResult will return NO_DATA, int + MVNC_TIME_TAKEN = 1000, // Return time taken for inference (float *) + MVNC_DEBUG_INFO = 1001, // Return debug info, string +} mvncGraphOptions; + +typedef enum { + MVNC_TEMP_LIM_LOWER = 1, // Temperature for short sleep, float, not for general use + MVNC_TEMP_LIM_HIGHER = 2, // Temperature for long sleep, float, not for general use + MVNC_BACKOFF_TIME_NORMAL = 3, // Normal sleep in ms, int, not for general use + MVNC_BACKOFF_TIME_HIGH = 4, // Short sleep in ms, int, not for general use + MVNC_BACKOFF_TIME_CRITICAL = 5, // Long sleep in ms, int, not for general use + MVNC_TEMPERATURE_DEBUG = 6, // Stop on critical temperature, int, not for general use + MVNC_THERMAL_STATS = 1000, // Return temperatures, float *, not for general use + MVNC_OPTIMISATION_LIST = 1001, // Return optimisations list, char *, not for general use + MVNC_THERMAL_THROTTLING_LEVEL = 1002, // 1=TEMP_LIM_LOWER reached, 2=TEMP_LIM_HIGHER reached +} mvncDeviceOptions; + +mvncStatus mvncGetDeviceName(int index, char *name, unsigned int nameSize); +mvncStatus mvncOpenDevice(const char *name, void **deviceHandle); +mvncStatus mvncCloseDevice(void *deviceHandle); +mvncStatus mvncAllocateGraph(void *deviceHandle, void **graphHandle, const void *graphFile, unsigned int graphFileLength); +mvncStatus mvncDeallocateGraph(void *graphHandle); +mvncStatus mvncSetGlobalOption(int option, const void *data, unsigned int dataLength); +mvncStatus mvncGetGlobalOption(int option, void *data, unsigned int *dataLength); +mvncStatus mvncSetGraphOption(void *graphHandle, int option, const void *data, unsigned int dataLength); +mvncStatus mvncGetGraphOption(void *graphHandle, int option, void *data, unsigned int *dataLength); +mvncStatus mvncSetDeviceOption(void *deviceHandle, int option, const void *data, unsigned int dataLength); +mvncStatus mvncGetDeviceOption(void *deviceHandle, int option, void *data, unsigned int *dataLength); +mvncStatus mvncLoadTensor(void *graphHandle, const void *inputTensor, unsigned int inputTensorLength, void *userParam); +mvncStatus mvncGetResult(void *graphHandle, void **outputData, unsigned int *outputDataLength, void **userParam); + +#include "mvnc_deprecated.h" +#ifdef __cplusplus +} +#endif + +#endif diff --git a/api/include/mvnc_deprecated.h b/api/include/mvnc_deprecated.h new file mode 100644 index 0000000..c7fabeb --- /dev/null +++ b/api/include/mvnc_deprecated.h @@ -0,0 +1,39 @@ +#ifndef __MVNC_DEPRECATED_H_INCLUDED__ +#define __MVNC_DEPRECATED_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef mvncGraphOptions GraphOptions __attribute__ \ + ((deprecated("GraphOptions is deprecated. Please use mvncGraphOptions"))); +typedef mvncDeviceOptions DeviceOptions __attribute__ \ + ((deprecated("DeviceOptions is deprecated. Please use mvncDeviceOptions"))); + +// Deprecated Define +#define MVNC_MAXNAMESIZE _Pragma("GCC warning \"'MVNC_MAXNAMESIZE' is deprecated. Please use 'MVNC_MAX_NAME_SIZE'\"") MVNC_MAX_NAME_SIZE + +// Deprecated Global Options +#define MVNC_LOGLEVEL _Pragma("GCC warning \"'MVNC_LOGLEVEL' is deprecated. Please use 'MVNC_LOG_LEVEL'\"") MVNC_LOG_LEVEL + +// Deprecated status values +#define MVNC_MVCMDNOTFOUND _Pragma("GCC warning \"'MVNC_MVCMDNOTFOUND' is deprecated. Please use 'MVNC_MVCMD_NOT_FOUND'\"") MVNC_MVCMD_NOT_FOUND +#define MVNC_NODATA _Pragma("GCC warning \"'MVNC_NO_DATA' is deprecated. Please use 'MVNC_NO_DATA'\"") MVNC_NO_DATA +#define MVNC_UNSUPPORTEDGRAPHFILE _Pragma("GCC warning \"'MVNC_UNSUPPORTEDGRAPHFILE' is deprecated. Please use 'MVNC_UNSUPPORTED_GRAPH_FILE'\"") MVNC_UNSUPPORTED_GRAPH_FILE +#define MVNC_MYRIADERROR _Pragma("GCC warning \"'MVNC_MYRIADERROR' is deprecated. Please use 'MVNC_MYRIAD_ERROR'\"") MVNC_MYRIAD_ERROR + +// Deprecated Graph Options values +#define MVNC_DONTBLOCK _Pragma("GCC warning \"'MVNC_DONTBLOCK' is deprecated. Please use 'MVNC_DONT_BLOCK'\"") MVNC_DONT_BLOCK +#define MVNC_TIMETAKEN _Pragma("GCC warning \"'MVNC_TIMETAKEN' is deprecated. Please use 'MVNC_TIME_TAKEN'\"") MVNC_TIME_TAKEN +#define MVNC_DEBUGINFO _Pragma("GCC warning \"'MVNC_DEBUGINFO' is deprecated. Please use 'MVNC_DEBUG_INFO'\"") MVNC_DEBUG_INFO + +// Deprecated Device Options Values +#define MVNC_THERMALSTATS _Pragma("GCC warning \"'MVNC_THERMALSTATS' is deprecated. Please use 'MVNC_THERMAL_STATS'\"") MVNC_THERMAL_STATS +#define MVNC_OPTIMISATIONLIST _Pragma("GCC warning \"'MVNC_OPTIMISATIONLIST' is deprecated. Please use 'MVNC_OPTIMISATION_LIST'\"") MVNC_OPTIMISATION_LIST + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/api/python/mvnc/__init__.py b/api/python/mvnc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/python/mvnc/mvncapi.py b/api/python/mvnc/mvncapi.py new file mode 100644 index 0000000..523d6fa --- /dev/null +++ b/api/python/mvnc/mvncapi.py @@ -0,0 +1,268 @@ +# Copyright 2017 Intel Corporation. +# The source code, information and material ("Material") contained herein is +# owned by Intel Corporation or its suppliers or licensors, and title to such +# Material remains with Intel Corporation or its suppliers or licensors. +# The Material contains proprietary information of Intel or its suppliers and +# licensors. The Material is protected by worldwide copyright laws and treaty +# provisions. +# No part of the Material may be used, copied, reproduced, modified, published, +# uploaded, posted, transmitted, distributed or disclosed in any way without +# Intel's prior express written permission. No license under any patent, +# copyright or other intellectual property rights in the Material is granted to +# or conferred upon you, either expressly, by implication, inducement, estoppel +# or otherwise. +# Any license under such intellectual property rights must be express and +# approved by Intel in writing. + +import sys +import numpy +import warnings +from enum import Enum +from ctypes import * + +# The toolkit wants its local version +try: + f = CDLL("./libmvnc.so") +except: + f = CDLL("libmvnc.so") + +warnings.simplefilter('default', DeprecationWarning) + + +class EnumDeprecationHelper(object): + def __init__(self, new_target, deprecated_values): + self.new_target = new_target + self.deprecated_values = deprecated_values + + def __call__(self, *args, **kwargs): + return self.new_target(*args, **kwargs) + + def __getattr__(self, attr): + if (attr in self.deprecated_values): + warnings.warn('\033[93m' + "\"" + attr + "\" is deprecated. Please use \"" + + self.deprecated_values[attr] + "\"!" + '\033[0m', + DeprecationWarning, stacklevel=2) + return getattr(self.new_target, self.deprecated_values[attr]) + return getattr(self.new_target, attr) + + +class mvncStatus(Enum): + OK = 0 + BUSY = -1 + ERROR = -2 + OUT_OF_MEMORY = -3 + DEVICE_NOT_FOUND = -4 + INVALID_PARAMETERS = -5 + TIMEOUT = -6 + MVCMD_NOT_FOUND = -7 + NO_DATA = -8 + GONE = -9 + UNSUPPORTED_GRAPH_FILE = -10 + MYRIAD_ERROR = -11 + +Status = EnumDeprecationHelper(mvncStatus, {"MVCMDNOTFOUND": "MVCMD_NOT_FOUND", + "NODATA": "NO_DATA", + "UNSUPPORTEDGRAPHFILE": "UNSUPPORTED_GRAPH_FILE", + "MYRIADERROR": "MYRIAD_ERROR"}) + + +class mvncGlobalOption(Enum): + LOG_LEVEL = 0 + +GlobalOption = EnumDeprecationHelper(mvncGlobalOption, {"LOGLEVEL": "LOG_LEVEL"}) + + +class mvncDeviceOption(Enum): + TEMP_LIM_LOWER = 1 + TEMP_LIM_HIGHER = 2 + BACKOFF_TIME_NORMAL = 3 + BACKOFF_TIME_HIGH = 4 + BACKOFF_TIME_CRITICAL = 5 + TEMPERATURE_DEBUG = 6 + THERMAL_STATS = 1000 + OPTIMISATION_LIST = 1001 + THERMAL_THROTTLING_LEVEL = 1002 + +DeviceOption = EnumDeprecationHelper(mvncDeviceOption, {"THERMALSTATS": "THERMAL_STATS", + "OPTIMISATIONLIST": "OPTIMISATION_LIST"}) + + +class mvncGraphOption(Enum): + ITERATIONS = 0 + NETWORK_THROTTLE = 1 + DONT_BLOCK = 2 + TIME_TAKEN = 1000 + DEBUG_INFO = 1001 + +GraphOption = EnumDeprecationHelper(mvncGraphOption, {"DONTBLOCK": "DONT_BLOCK", + "TIMETAKEN": "TIME_TAKEN", + "DEBUGINFO": "DEBUG_INFO"}) + + +def EnumerateDevices(): + name = create_string_buffer(28) + i = 0 + devices = [] + while True: + if f.mvncGetDeviceName(i, name, 28) != 0: + break + devices.append(name.value.decode("utf-8")) + i = i + 1 + return devices + + +def SetGlobalOption(opt, data): + data = c_int(data) + status = f.mvncSetGlobalOption(opt.value, pointer(data), sizeof(data)) + if status != Status.OK.value: + raise Exception(Status(status)) + + +def GetGlobalOption(opt): + if opt == GlobalOption.LOG_LEVEL: + optsize = c_uint() + optvalue = c_uint() + status = f.mvncGetGlobalOption(opt.value, byref(optvalue), byref(optsize)) + if status != Status.OK.value: + raise Exception(Status(status)) + return optvalue.value + optsize = c_uint() + optdata = POINTER(c_byte)() + status = f.mvncGetDeviceOption(0, opt.value, byref(optdata), byref(optsize)) + if status != Status.OK.value: + raise Exception(Status(status)) + v = create_string_buffer(optsize.value) + memmove(v, optdata, optsize.value) + return v.raw + + +class Device: + def __init__(self, name): + self.handle = c_void_p() + self.name = name + + def OpenDevice(self): + status = f.mvncOpenDevice(bytes(bytearray(self.name, "utf-8")), byref(self.handle)) + if status != Status.OK.value: + raise Exception(Status(status)) + + def CloseDevice(self): + status = f.mvncCloseDevice(self.handle) + self.handle = c_void_p() + if status != Status.OK.value: + raise Exception(Status(status)) + + def SetDeviceOption(self, opt, data): + if opt == DeviceOption.TEMP_LIM_HIGHER or opt == DeviceOption.TEMP_LIM_LOWER: + data = c_float(data) + else: + data = c_int(data) + status = f.mvncSetDeviceOption(self.handle, opt.value, pointer(data), sizeof(data)) + if status != Status.OK.value: + raise Exception(Status(status)) + + def GetDeviceOption(self, opt): + if opt == DeviceOption.TEMP_LIM_HIGHER or opt == DeviceOption.TEMP_LIM_LOWER: + optdata = c_float() + elif (opt == DeviceOption.BACKOFF_TIME_NORMAL or opt == DeviceOption.BACKOFF_TIME_HIGH or + opt == DeviceOption.BACKOFF_TIME_CRITICAL or opt == DeviceOption.TEMPERATURE_DEBUG or + opt == DeviceOption.THERMAL_THROTTLING_LEVEL): + optdata = c_int() + else: + optdata = POINTER(c_byte)() + optsize = c_uint() + status = f.mvncGetDeviceOption(self.handle, opt.value, byref(optdata), byref(optsize)) + if status != Status.OK.value: + raise Exception(Status(status)) + if opt == DeviceOption.TEMP_LIM_HIGHER or opt == DeviceOption.TEMP_LIM_LOWER: + return optdata.value + elif (opt == DeviceOption.BACKOFF_TIME_NORMAL or opt == DeviceOption.BACKOFF_TIME_HIGH or + opt == DeviceOption.BACKOFF_TIME_CRITICAL or opt == DeviceOption.TEMPERATURE_DEBUG or + opt == DeviceOption.THERMAL_THROTTLING_LEVEL): + return optdata.value + v = create_string_buffer(optsize.value) + memmove(v, optdata, optsize.value) + if opt == DeviceOption.OPTIMISATION_LIST: + l = [] + for i in range(40): + if v.raw[i * 50] != 0: + ss = v.raw[i * 50:] + end = ss.find(0) + l.append(ss[0:end].decode()) + return l + if opt == DeviceOption.THERMAL_STATS: + return numpy.frombuffer(v.raw, dtype=numpy.float32) + return int.from_bytes(v.raw, byteorder='little') + + def AllocateGraph(self, graphfile): + hgraph = c_void_p() + status = f.mvncAllocateGraph(self.handle, byref(hgraph), graphfile, len(graphfile)) + if status != Status.OK.value: + raise Exception(Status(status)) + return Graph(hgraph) + + +class Graph: + def __init__(self, handle): + self.handle = handle + self.userobjs = {} + + def SetGraphOption(self, opt, data): + data = c_int(data) + status = f.mvncSetGraphOption(self.handle, opt.value, pointer(data), sizeof(data)) + if status != Status.OK.value: + raise Exception(Status(status)) + + def GetGraphOption(self, opt): + if opt == GraphOption.ITERATIONS or opt == GraphOption.NETWORK_THROTTLE or opt == GraphOption.DONT_BLOCK: + optdata = c_int() + else: + optdata = POINTER(c_byte)() + optsize = c_uint() + status = f.mvncGetGraphOption(self.handle, opt.value, byref(optdata), byref(optsize)) + if status != Status.OK.value: + raise Exception(Status(status)) + if opt == GraphOption.ITERATIONS or opt == GraphOption.NETWORK_THROTTLE or opt == GraphOption.DONT_BLOCK: + return optdata.value + v = create_string_buffer(optsize.value) + memmove(v, optdata, optsize.value) + if opt == GraphOption.TIME_TAKEN: + return numpy.frombuffer(v.raw, dtype=numpy.float32) + if opt == GraphOption.DEBUG_INFO: + return v.raw[0:v.raw.find(0)].decode() + return int.from_bytes(v.raw, byteorder='little') + + def DeallocateGraph(self): + status = f.mvncDeallocateGraph(self.handle) + self.handle = 0 + if status != Status.OK.value: + raise Exception(Status(status)) + + def LoadTensor(self, tensor, userobj): + tensor = tensor.tostring() + userobj = py_object(userobj) + key = c_long(addressof(userobj)) + self.userobjs[key.value] = userobj + status = f.mvncLoadTensor(self.handle, tensor, len(tensor), key) + if status == Status.BUSY.value: + return False + if status != Status.OK.value: + del self.userobjs[key.value] + raise Exception(Status(status)) + return True + + def GetResult(self): + tensor = c_void_p() + tensorlen = c_uint() + userobj = c_long() + status = f.mvncGetResult(self.handle, byref(tensor), byref(tensorlen), byref(userobj)) + if status == Status.NO_DATA.value: + return None, None + if status != Status.OK.value: + raise Exception(Status(status)) + v = create_string_buffer(tensorlen.value) + memmove(v, tensor, tensorlen.value) + tensor = numpy.frombuffer(v.raw, dtype=numpy.float16) + retuserobj = self.userobjs[userobj.value] + del self.userobjs[userobj.value] + return tensor, retuserobj.value diff --git a/api/src/97-usbboot.rules b/api/src/97-usbboot.rules new file mode 100644 index 0000000..3d11e4d --- /dev/null +++ b/api/src/97-usbboot.rules @@ -0,0 +1,3 @@ +SUBSYSTEM=="usb", ATTRS{idProduct}=="2150", ATTRS{idVendor}=="03e7", GROUP="users", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1" +SUBSYSTEM=="usb", ATTRS{idProduct}=="f63b", ATTRS{idVendor}=="040e", GROUP="users", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1" +SUBSYSTEM=="tty", ATTRS{idProduct}=="2150", ATTRS{idVendor}=="03e7", GROUP="users", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1" diff --git a/api/src/Makefile b/api/src/Makefile new file mode 100644 index 0000000..0c92879 --- /dev/null +++ b/api/src/Makefile @@ -0,0 +1,79 @@ +ARCH := $(shell uname -m) + +LIBS += -lpthread -lusb-1.0 -ldl + +OUT := libmvnc.so.0 +OBJDIR := obj-$(ARCH) +INSTALLDIR := ${DESTDIR}/usr/local +PYTHON3DIST := $(shell python3 -c "import site; print(site.getsitepackages()[0])") +PYTHON2DIST := $(shell python -c "import site; print(site.getsitepackages()[0])") + +SRCS := \ + usb_boot.c \ + usb_link_vsc.c \ + mvnc_api.c + +INCLUDES := \ + -I. \ + -I../include \ + -I$(SYSROOT)/usr/include/libusb-1.0 \ + +CFLAGS += -O2 -Wall -pthread -fPIC -MMD -MP +LDFLAGS += -shared + +OBJS := $(SRCS:%.c=$(OBJDIR)/%.o) +DEPS := $(OBJS:.o=.d) + +$(OBJDIR)/$(OUT): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + ln -fs $(OBJDIR)/$(OUT) libmvnc.so + ln -fs $(OBJDIR)/$(OUT) $(OUT) + +$(OBJDIR)/%.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(OBJDIR): + @mkdir $@ + +-include $(DEPS) + +basicinstall: $(OBJDIR)/$(OUT) + mkdir -p $(INSTALLDIR)/include/ + mkdir -p $(INSTALLDIR)/lib/ + cp $(OBJDIR)/$(OUT) $(INSTALLDIR)/lib/ + ln -fs libmvnc.so.0 $(INSTALLDIR)/lib/libmvnc.so + cp ../include/*.h $(INSTALLDIR)/include/ + mkdir -p $(INSTALLDIR)/lib/mvnc + cp mvnc/MvNCAPI.mvcmd $(INSTALLDIR)/lib/mvnc/ + mkdir -p ${DESTDIR}/etc/udev/rules.d/ + cp 97-usbboot.rules ${DESTDIR}/etc/udev/rules.d/ + +pythoninstall: + mkdir -p ${DESTDIR}$(PYTHON3DIST) + mkdir -p ${DESTDIR}$(PYTHON2DIST) + cp -r ../python/mvnc ${DESTDIR}$(PYTHON3DIST)/ + cp -r ../python/mvnc ${DESTDIR}$(PYTHON2DIST)/ + +postinstall: + udevadm control --reload-rules + udevadm trigger + ldconfig + +install: basicinstall pythoninstall postinstall + +uninstall: + rm -f $(INSTALLDIR)/lib/libmvnc.so.0 + rm -f $(INSTALLDIR)/lib/libmvnc.so + rm -f $(INSTALLDIR)/include/mvnc.h + rm -f $(INSTALLDIR)/include/mvnc_deprecated.h + rm -f $(INSTALLDIR)/lib/mvnc/MvNCAPI.mvcmd + rm -rf $(INSTALLDIR)/lib/mvnc + rm -rf ${DESTDIR}$(PYTHON3DIST)/mvnc + rm -rf ${DESTDIR}$(PYTHON2DIST)/mvnc + rm -f ${DESTDIR}/etc/udev/rules.d/97-usbboot.rules + +clean: + rm -f $(OUT) + rm -f $(OBJS) + rm -rf $(OBJDIR) + rm -f libmvnc.so diff --git a/api/src/Makefile.rpi b/api/src/Makefile.rpi new file mode 100644 index 0000000..6cf9012 --- /dev/null +++ b/api/src/Makefile.rpi @@ -0,0 +1,43 @@ +ARCH := armv7l + +PIROOT := $(shell echo $(HOME))/piroot +CC := arm-linux-gnueabihf-gcc --sysroot=$(PIROOT) +LIBS += -ludev -lpthread -lusb-1.0 -ldl + +OUT := libmvnc.so.0 +OBJDIR := obj-$(ARCH) +INSTALLDIR := ${DESTDIR}/usr/local +PYTHON3DIST := $(shell python3 -c "import site; print(site.getsitepackages()[0])") +PYTHON2DIST := $(shell python -c "import site; print(site.getsitepackages()[0])") + +SRCS := \ + usb_boot.c \ + usb_link_vsc.c \ + mvnc_api.c + +INCLUDES := \ + -I. \ + -I../include \ + -I$(SYSROOT)/usr/include/libusb-1.0 \ + +CFLAGS += -O2 -Wall -pthread -fPIC -MMD -MP +LDFLAGS += -shared + +OBJS := $(SRCS:%.c=$(OBJDIR)/%.o) +DEPS := $(OBJS:.o=.d) + +$(OBJDIR)/$(OUT): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +$(OBJDIR)/%.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(OBJDIR): + @mkdir $@ + +-include $(DEPS) + +clean: + rm -f $(OUT) + rm -f $(OBJS) + rm -rf $(OBJDIR) diff --git a/api/src/USBLinkDefines.h b/api/src/USBLinkDefines.h new file mode 100644 index 0000000..4ec8cad --- /dev/null +++ b/api/src/USBLinkDefines.h @@ -0,0 +1,65 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +#ifndef _USBLINKCOMMONDEFINES_H +#define _USBLINKCOMMONDEFINES_H +#include + +#ifdef __cplusplus +extern "C" { +#endif +#define MAX_NAME_LENGTH 52 +// Packet length will define the maximum message length between pc and myriad. All bigger messages than this number will be split in multiple messages +#define PACKET_LENGTH (64*1024) + +typedef struct bufferEntryDesc_t { + char name[MAX_NAME_LENGTH]; + uint8_t *data; + uint32_t length; +} bufferEntryDesc_t; + +typedef enum { + USB_LINK_GET_MYRIAD_STATUS = 0, + USB_LINK_RESET_REQUEST, + USB_LINK_HOST_SET_DATA, + USB_LINK_HOST_GET_DATA +} hostcommands_t; + +typedef enum { + MYRIAD_NOT_INIT = 0, + MYRIAD_INITIALIZED = 0x11, + MYRIAD_WAITING = 0x22, + MYRIAD_RUNNING = 0x33, + MYRIAD_FINISHED = 0x44, + MYRIAD_PENDING = 0x55, +} myriadStatus_t; + +typedef struct usbHeader_t { + uint8_t cmd; + uint8_t hostready; + uint16_t reserved; + uint32_t dataLength; + uint32_t offset; + char name[MAX_NAME_LENGTH]; +} usbHeader_t; + +#ifdef __cplusplus +} +#endif +#endif +/* end of include file */ diff --git a/api/src/common.h b/api/src/common.h new file mode 100644 index 0000000..cfb9157 --- /dev/null +++ b/api/src/common.h @@ -0,0 +1,34 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +// Common logging macros +#define PRINT_DEBUG(...) {if (mvnc_loglevel > 1) fprintf(__VA_ARGS__);} +#define PRINT_DEBUG_F(...) {if (mvnc_loglevel > 1) \ + { fprintf(__VA_ARGS__); fflush(stderr); } }\ + +#define PRINT_INFO(...) {if (mvnc_loglevel > 0) fprintf(__VA_ARGS__);} +#define PRINT_INFO_F(...) {if (mvnc_loglevel > 0) \ + { fprintf(__VA_ARGS__); fflush(stderr); } }\ + +#define PRINT(...) fprintf(stderr,__VA_ARGS__) + +// Common defines +#define DEFAULT_VID 0x03E7 +#define DEFAULT_PID 0x2150 // Myriad2v2 ROM +#define DEFAULT_OPEN_VID 0x040e +#define DEFAULT_OPEN_PID 0xf63b // Once opened in VSC mode, VID/PID change diff --git a/api/src/mvnc_api.c b/api/src/mvnc_api.c new file mode 100644 index 0000000..8298bc6 --- /dev/null +++ b/api/src/mvnc_api.c @@ -0,0 +1,966 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +#define _GNU_SOURCE +#include // For dladdr +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mvnc.h" +#include "usb_link.h" +#include "usb_boot.h" +#include "common.h" + +// Graph file structure +#define HEADER_LENGTH 264 +#define STAGE_LENGTH 227 +#define VERSION_OFFSET 36 +#define GRAPH_VERSION 2 +#define N_STAGES_OFFSET 240 +#define FIRST_SHAVE_OFFSET 248 +#define N_OUTPUTS_OFFSET (HEADER_LENGTH + 136) +#define X_OUT_STRIDE_OFFSET (HEADER_LENGTH + 172) + +#define THERMAL_BUFFER_SIZE 100 +#define DEBUG_BUFFER_SIZE 120 + +#define MAX_OPTIMISATIONS 40 +#define OPTIMISATION_NAME_LEN 50 +#define OPTIMISATION_LIST_BUFFER_SIZE (MAX_OPTIMISATIONS * OPTIMISATION_NAME_LEN) + +#define MAX_PATH_LENGTH 255 +#define STATUS_WAIT_TIMEOUT 15 + +static int initialized = 0; +static pthread_mutex_t mm = PTHREAD_MUTEX_INITIALIZER; + +int mvnc_loglevel = 0; + +/////////////////////////// Structs ///////////////////////////// +struct Graph; + +struct Device { + int backoff_time_normal, backoff_time_high, backoff_time_critical; + int temperature_debug, throttle_happened; + float temp_lim_upper, temp_lim_lower; + float *thermal_stats; + char *dev_addr; // Device USB address as returned by usb_ + char *dev_file; // Device filename in /dev directory + char *optimisation_list; + void *usb_link; + struct Device *next; // Next device in chain + struct Graph *graphs; // List of associated graphs + pthread_mutex_t mm; +} *devices; + +struct Graph { + int started; + int have_data; + int dont_block; + int input_idx; + int output_idx; + int failed; + int iterations; + int network_throttle; + unsigned noutputs; + unsigned nstages; + struct Device *dev; + struct Graph *next; + char *aux_buffer; + char *debug_buffer; + float *time_taken; + void *user_param[2]; + void *output_data; +}; + +static double time_in_seconds() +{ + static double s; + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + if (!s) + s = ts.tv_sec + ts.tv_nsec * 1e-9; + return ts.tv_sec + ts.tv_nsec * 1e-9 - s; +} + +static void initialize() +{ + // We sanitize the situation by trying to reset the devices that have been left open + initialized = 1; + usblink_resetall(); +} + +mvncStatus mvncGetDeviceName(int index, char *name, unsigned int nameSize) +{ + if (index < 0 || !name || nameSize < MVNC_MAX_NAME_SIZE) + return MVNC_INVALID_PARAMETERS; + + pthread_mutex_lock(&mm); + if (!initialized) + initialize(); + int rc = usb_find_device(index, name, nameSize, 0, 0, 0); + pthread_mutex_unlock(&mm); + + return rc; +} + +static int is_device_opened(const char *name) +{ + struct Device *d = devices; + while (d) { + if (strcmp(d->dev_addr, name) == 0) + return 0; + d = d->next; + } + return -1; +} + +mvncStatus mvncOpenDevice(const char *name, void **deviceHandle) +{ + int rc; + FILE *fp; + char *tx_buf; + unsigned file_size; + char mv_cmd_file[MAX_PATH_LENGTH], *p; + char name2[MVNC_MAX_NAME_SIZE] = ""; + + if (!name || !deviceHandle) + return MVNC_INVALID_PARAMETERS; + + pthread_mutex_lock(&mm); + if (!initialized) + initialize(); + + // Search the mvnc executable in the same directory of this library, under mvnc + Dl_info info; + dladdr(mvncOpenDevice, &info); + strncpy(mv_cmd_file, info.dli_fname, sizeof(mv_cmd_file) - 40); + p = strrchr(mv_cmd_file, '/'); + if (p) + strcpy(p + 1, "mvnc/MvNCAPI.mvcmd"); + else + strcpy(mv_cmd_file, "mvnc/MvNCAPI.mvcmd"); + + // Load the mvnc executable + fp = fopen(mv_cmd_file, "rb"); + if (fp == NULL) { + if (mvnc_loglevel) + perror(mv_cmd_file); + pthread_mutex_unlock(&mm); + return MVNC_MVCMD_NOT_FOUND; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + rewind(fp); + if (!(tx_buf = malloc(file_size))) { + if (mvnc_loglevel) + perror("buffer"); + fclose(fp); + pthread_mutex_unlock(&mm); + return MVNC_OUT_OF_MEMORY; + } + + if (fread(tx_buf, 1, file_size, fp) != file_size) { + if (mvnc_loglevel) + perror(mv_cmd_file); + fclose(fp); + free(tx_buf); + pthread_mutex_unlock(&mm); + return MVNC_MVCMD_NOT_FOUND; + } + fclose(fp); + + // Boot it + rc = usb_boot(name, tx_buf, file_size); + free(tx_buf); + if (rc) { + pthread_mutex_unlock(&mm); + return rc; + } + + PRINT_DEBUG(stderr, "Boot successful, device address %s\n", name); + + // Now we should have a new /dev/ttyACM, try to open it + double waittm = time_in_seconds() + STATUS_WAIT_TIMEOUT; + while (time_in_seconds() < waittm) { + void *f = usblink_open(name); + + if (f == NULL) { //we might fail in case name changed after boot + int count = 0; + while (1) { + name2[0] = '\0'; + rc = usb_find_device(count, name2, + sizeof(name2), NULL, + DEFAULT_OPEN_VID, + DEFAULT_OPEN_PID); + if (rc < 0) //Error or no more devices found + break; + + //check if we already have name2 open + // if not, check if it's not already busy + if (is_device_opened(name2) < 0 && + (f = usblink_open(name2))) + break; + count++; + } + } + + if (f) { + myriadStatus_t status; + + if (!usblink_getmyriadstatus(f, &status) && status == MYRIAD_WAITING) { + struct Device *d = calloc(1, sizeof(*d)); + d->dev_addr = strlen(name2) > 0 ? strdup(name2) + : strdup(name); + d->usb_link = f; + d->next = devices; + d->temp_lim_upper = 95; + d->temp_lim_lower = 85; + d->backoff_time_normal = 0; + d->backoff_time_high = 100; + d->backoff_time_critical = 10000; + d->temperature_debug = 0; + pthread_mutex_init(&d->mm, 0); + devices = d; + *deviceHandle = d; + + PRINT_DEBUG(stderr, "done\n"); + PRINT_INFO(stderr, "Booted %s -> %s\n", + d->dev_addr, + d->dev_file ? d->dev_file : "VSC"); + pthread_mutex_unlock(&mm); + return MVNC_OK; + } else { + PRINT_DEBUG(stderr, + "found, but cannot get status\n"); + usblink_close(f); + } + } + // Error opening it, continue searching + usleep(10000); + } + + pthread_mutex_unlock(&mm); + return MVNC_ERROR; +} + +static int find_device(void *deviceHandle) +{ + struct Device *d = devices; + + while (d) { + if (d == deviceHandle) + return 0; + d = d->next; + } + + return -1; +} + +static int find_graph(void *graphHandle) +{ + struct Device *d = devices; + + while (d) { + struct Graph *g = d->graphs; + while (g) { + if (g == graphHandle) + return 0; + g = g->next; + } + d = d->next; + } + + return -1; +} + +// Defined here as it will be used twice +static int deallocate_graph(struct Graph *g) +{ + int found = 0; + + // Remove it from the list of the associated device + if (g->dev->graphs == g) { + g->dev->graphs = g->next; + found = 1; + } else { + struct Graph *gp = g->dev->graphs; + while (gp->next) { + if (gp->next == g) { + found = 1; + gp->next = gp->next->next; + break; + } + gp = gp->next; + } + } + + // Free it with all its data + if (found) { + free(g->aux_buffer); + free(g->output_data); + g->dev->thermal_stats = 0; + free(g); + } + + return -!found; +} + +mvncStatus mvncCloseDevice(void *deviceHandle) +{ + int found = 0; + + if (!deviceHandle) + return MVNC_INVALID_PARAMETERS; + + pthread_mutex_lock(&mm); + if (find_device(deviceHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + struct Device *d = (struct Device *) deviceHandle; + // Remove it from our list + if (devices == d) { + devices = d->next; + found = 1; + } else { + struct Device *dp = devices; + while (dp->next) { + if (dp->next == d) { + found = 1; + dp->next = dp->next->next; + break; + } + dp = dp->next; + } + } + + if (!found) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + // Deallocate all associated graphs + pthread_mutex_lock(&d->mm); + while (d->graphs) + deallocate_graph(d->graphs); + + // Reset + usblink_resetmyriad(d->usb_link); + usblink_close(d->usb_link); + if (d->optimisation_list) + free(d->optimisation_list); + + free(d->dev_addr); + free(d->dev_file); + pthread_mutex_unlock(&d->mm); + pthread_mutex_destroy(&d->mm); + free(d); + pthread_mutex_unlock(&mm); + + usleep(500000); + return MVNC_OK; +} + +static unsigned read_32bits(const unsigned char *ptr) +{ + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); +} + + +mvncStatus mvncAllocateGraph(void *deviceHandle, void **graphHandle, + const void *graphFile, unsigned int graphFileLength) +{ + if (!deviceHandle || !graphHandle || !graphFile) + return MVNC_INVALID_PARAMETERS; + + if (graphFileLength < HEADER_LENGTH + STAGE_LENGTH || + graphFileLength > 512 * 1024 * 1024) + return MVNC_UNSUPPORTED_GRAPH_FILE; + + unsigned char *graph = (unsigned char *) graphFile; + if (graph[VERSION_OFFSET] != GRAPH_VERSION) + return MVNC_UNSUPPORTED_GRAPH_FILE; + + unsigned nstages = graph[N_STAGES_OFFSET] + (graph[N_STAGES_OFFSET + 1] << 8); + unsigned noutputs = read_32bits(graph + N_OUTPUTS_OFFSET + + (nstages - 1) * STAGE_LENGTH) * + read_32bits(graph + N_OUTPUTS_OFFSET + + (nstages - 1) * STAGE_LENGTH + 4) * + read_32bits(graph + X_OUT_STRIDE_OFFSET + + (nstages - 1) * STAGE_LENGTH) / 2; + + // A reasonable check on graph correctness + if (nstages > 1024 || noutputs > 64 * 1024 * 1024) + return MVNC_UNSUPPORTED_GRAPH_FILE; + + pthread_mutex_lock(&mm); + struct Device *d = devices; + while (d) { + if (d == deviceHandle) + break; + d = d->next; + } + + if (!d) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + if (d->graphs) { + pthread_mutex_unlock(&mm); + return MVNC_BUSY; + } + + myriadStatus_t status; + double timeout = time_in_seconds() + 10; + do { + if (usblink_getmyriadstatus(d->usb_link, &status)) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + usleep(10000); + } while (status != MYRIAD_WAITING && time_in_seconds() < timeout); + + if (status != MYRIAD_WAITING) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + + if (usblink_setdata(d->usb_link, "blobFile", graphFile, graphFileLength, 0)) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + + struct Graph *g = calloc(1, sizeof(*g)); + g->dev = d; + g->nstages = nstages; + g->noutputs = noutputs; + + // aux_buffer + g->aux_buffer = calloc(1, 224 + nstages * sizeof(*g->time_taken)); + if (!g->aux_buffer) { + free(g); + pthread_mutex_unlock(&mm); + return MVNC_OUT_OF_MEMORY; + } + + if (usblink_setdata(g->dev->usb_link, "auxBuffer", g->aux_buffer, + 224 + nstages * sizeof(*g->time_taken), 0)) { + free(g->aux_buffer); + free(g); + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + + g->debug_buffer = g->aux_buffer; + g->time_taken = (float *) (g->aux_buffer + 224); + + // output_data + g->output_data = calloc(noutputs, 2); + if (!g->output_data) { + free(g->aux_buffer); + free(g); + pthread_mutex_unlock(&mm); + return MVNC_OUT_OF_MEMORY; + } + + g->dev->thermal_stats = (float *) (g->aux_buffer + DEBUG_BUFFER_SIZE); + + g->iterations = 1; + g->network_throttle = 1; + if (d->graphs) + g->next = d->graphs; + d->graphs = g; + *graphHandle = g; + pthread_mutex_unlock(&mm); + return MVNC_OK; +} + +mvncStatus mvncDeallocateGraph(void *graphHandle) +{ + if (!graphHandle) + return MVNC_INVALID_PARAMETERS; + + pthread_mutex_lock(&mm); + if (find_graph(graphHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + struct Device *d = ((struct Graph *) graphHandle)->dev; + + pthread_mutex_lock(&d->mm); + if (deallocate_graph((struct Graph *) graphHandle)) { + pthread_mutex_unlock(&d->mm); + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_unlock(&d->mm); + pthread_mutex_unlock(&mm); + return MVNC_OK; +} + +mvncStatus mvncSetGraphOption(void *graphHandle, int option, const void *data, + unsigned int dataLength) +{ + if (!graphHandle || !data || dataLength != 4) + return MVNC_INVALID_PARAMETERS; + + struct Graph *g = (struct Graph *) graphHandle; + pthread_mutex_lock(&mm); + if (find_graph(graphHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_lock(&g->dev->mm); + pthread_mutex_unlock(&mm); + switch (option) { + case MVNC_ITERATIONS: + g->iterations = *(int *) data; + break; + case MVNC_NETWORK_THROTTLE: + g->network_throttle = *(int *) data; + break; + case MVNC_DONT_BLOCK: + g->dont_block = *(int *) data; + break; + default: + pthread_mutex_unlock(&g->dev->mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_unlock(&g->dev->mm); + return MVNC_OK; +} + +mvncStatus mvncGetGraphOption(void *graphHandle, int option, void *data, + unsigned int *dataLength) +{ + if (!graphHandle || !data || !dataLength) + return MVNC_INVALID_PARAMETERS; + + struct Graph *g = (struct Graph *) graphHandle; + pthread_mutex_lock(&mm); + if (find_graph(graphHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_lock(&g->dev->mm); + pthread_mutex_unlock(&mm); + switch (option) { + case MVNC_ITERATIONS: + *(int *) data = g->iterations; + *dataLength = sizeof(int); + break; + case MVNC_NETWORK_THROTTLE: + *(int *) data = g->network_throttle; + *dataLength = sizeof(int); + break; + case MVNC_DONT_BLOCK: + *(int *) data = g->dont_block; + + *dataLength = sizeof(int); + break; + case MVNC_TIME_TAKEN: + *(float **) data = g->time_taken; + *dataLength = sizeof(*g->time_taken) * g->nstages; + break; + case MVNC_DEBUG_INFO: + *(char **) data = g->debug_buffer; + *dataLength = DEBUG_BUFFER_SIZE; + break; + default: + pthread_mutex_unlock(&g->dev->mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_unlock(&g->dev->mm); + return MVNC_OK; +} + +mvncStatus mvncSetGlobalOption(int option, const void *data, + unsigned int dataLength) +{ + if (!data || dataLength != 4) + return MVNC_INVALID_PARAMETERS; + + switch (option) { + case MVNC_LOG_LEVEL: + mvnc_loglevel = *(int *) data; + break; + default: + return MVNC_INVALID_PARAMETERS; + } + + return MVNC_OK; +} + +mvncStatus mvncGetGlobalOption(int option, void *data, unsigned int *dataLength) +{ + if (!data || !dataLength) + return MVNC_INVALID_PARAMETERS; + + switch (option) { + case MVNC_LOG_LEVEL: + *(int *) data = mvnc_loglevel; + *dataLength = sizeof(mvnc_loglevel); + break; + default: + return MVNC_INVALID_PARAMETERS; + } + return MVNC_OK; +} + +mvncStatus mvncSetDeviceOption(void *deviceHandle, int option, const void *data, + unsigned int dataLength) +{ + if (deviceHandle == 0 && option == MVNC_LOG_LEVEL) { + PRINT("Warning: MVNC_LOG_LEVEL is not a Device Option, \ + please use mvncSetGlobalOption()!\n"); + return mvncSetGlobalOption(option, data, dataLength); + } + + if (!deviceHandle || !data || dataLength != 4) + return MVNC_INVALID_PARAMETERS; + + struct Device *d = (struct Device *) deviceHandle; + pthread_mutex_lock(&mm); + if (find_device(d)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_lock(&d->mm); + pthread_mutex_unlock(&mm); + switch (option) { + case MVNC_TEMP_LIM_LOWER: + d->temp_lim_lower = *(float *) data; + break; + case MVNC_TEMP_LIM_HIGHER: + d->temp_lim_upper = *(float *) data; + break; + case MVNC_BACKOFF_TIME_NORMAL: + d->backoff_time_normal = *(int *) data; + break; + case MVNC_BACKOFF_TIME_HIGH: + d->backoff_time_high = *(int *) data; + break; + case MVNC_BACKOFF_TIME_CRITICAL: + d->backoff_time_critical = *(int *) data; + break; + case MVNC_TEMPERATURE_DEBUG: + d->temperature_debug = *(int *) data; + break; + default: + pthread_mutex_unlock(&d->mm); + return MVNC_INVALID_PARAMETERS; + } + pthread_mutex_unlock(&d->mm); + + return MVNC_OK; +} + +static mvncStatus get_optimisation_list(struct Device *d) +{ + int i, config[10]; + double timeout; + myriadStatus_t status; + char *p; + + if (d->optimisation_list) + return MVNC_OK; + + d->optimisation_list = calloc(OPTIMISATION_LIST_BUFFER_SIZE, 1); + if (!d->optimisation_list) + return MVNC_OUT_OF_MEMORY; + + memset(config, 0, sizeof(config)); + config[0] = 1; + config[1] = 1; + if (usblink_setdata(d->usb_link, "config", config, sizeof(config), 1)) + return MVNC_ERROR; + + timeout = time_in_seconds() + STATUS_WAIT_TIMEOUT; + do { + if (usblink_getmyriadstatus(d->usb_link, &status)) + return MVNC_ERROR; + usleep(10000); + } while (status != MYRIAD_WAITING && + status != MYRIAD_FINISHED && time_in_seconds() < timeout); + + if (status != MYRIAD_WAITING && status != MYRIAD_FINISHED) + return MVNC_TIMEOUT; + + if (usblink_getdata(d->usb_link, "optimizationList", + d->optimisation_list, OPTIMISATION_LIST_BUFFER_SIZE, 0, 0)) + return MVNC_ERROR; + + for (i = 0; i < MAX_OPTIMISATIONS; i++) { + p = strchr(d->optimisation_list + i * OPTIMISATION_NAME_LEN, '~'); + if (p) + *p = 0; + } + + config[1] = 0; + if (usblink_setdata(d->usb_link, "config", config, sizeof(config), 0)) + return MVNC_ERROR; + return MVNC_OK; +} + +mvncStatus mvncGetDeviceOption(void *deviceHandle, int option, void *data, + unsigned int *dataLength) +{ + mvncStatus rc; + + if (deviceHandle == 0 && option == MVNC_LOG_LEVEL) { + PRINT("Warning: MVNC_LOG_LEVEL is not a Device Option, \ + please use mvncGetGlobalOption()!\n"); + return mvncGetGlobalOption(option, data, dataLength); + } + + if (!deviceHandle || !data || !dataLength) + return MVNC_INVALID_PARAMETERS; + + struct Device *d = (struct Device *) deviceHandle; + pthread_mutex_lock(&mm); + if (find_device(d)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + pthread_mutex_lock(&d->mm); + pthread_mutex_unlock(&mm); + switch (option) { + case MVNC_TEMP_LIM_LOWER: + *(float *) data = d->temp_lim_lower; + *dataLength = sizeof(int); + break; + case MVNC_TEMP_LIM_HIGHER: + *(float *) data = d->temp_lim_upper; + *dataLength = sizeof(int); + break; + case MVNC_BACKOFF_TIME_NORMAL: + *(int *) data = d->backoff_time_normal; + *dataLength = sizeof(int); + break; + case MVNC_BACKOFF_TIME_HIGH: + *(int *) data = d->backoff_time_high; + *dataLength = sizeof(int); + break; + case MVNC_BACKOFF_TIME_CRITICAL: + *(int *) data = d->backoff_time_critical; + *dataLength = sizeof(int); + break; + case MVNC_TEMPERATURE_DEBUG: + *(int *) data = d->temperature_debug; + *dataLength = sizeof(int); + break; + case MVNC_THERMAL_STATS: + if (!d->thermal_stats) { + pthread_mutex_unlock(&d->mm); + return MVNC_NO_DATA; + } + *(float **) data = d->thermal_stats; + *dataLength = THERMAL_BUFFER_SIZE; + break; + case MVNC_OPTIMISATION_LIST: + rc = get_optimisation_list(d); + if (rc) { + pthread_mutex_unlock(&d->mm); + return rc; + } + *(char **) data = d->optimisation_list; + *dataLength = OPTIMISATION_LIST_BUFFER_SIZE; + break; + case MVNC_THERMAL_THROTTLING_LEVEL: + *(int *) data = d->throttle_happened; + *dataLength = sizeof(int); + break; + default: + pthread_mutex_unlock(&d->mm); + return MVNC_INVALID_PARAMETERS; + } + pthread_mutex_unlock(&d->mm); + + return MVNC_OK; +} + +static int send_opt_data(struct Graph *g) +{ + int config[10]; + + config[0] = 1; // Version + config[1] = 0; // Query disable + config[2] = g->iterations; + config[3] = g->dev->temp_lim_upper; + config[4] = g->dev->temp_lim_lower; + config[5] = g->dev->backoff_time_normal; + config[6] = g->dev->backoff_time_high; + config[7] = g->dev->backoff_time_critical; + config[8] = g->dev->temperature_debug; + config[9] = g->network_throttle; + + if (usblink_setdata(g->dev->usb_link, "config", config, sizeof(config), 0)) + return MVNC_ERROR; + + return MVNC_OK; +} + +mvncStatus mvncLoadTensor(void *graphHandle, const void *inputTensor, + unsigned int inputTensorLength, void *userParam) +{ + if (!graphHandle || !inputTensor || inputTensorLength < 2) + return MVNC_INVALID_PARAMETERS; + + struct Graph *g = (struct Graph *) graphHandle; + pthread_mutex_lock(&mm); + if (find_graph(graphHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + if (!g->started) { + if (send_opt_data(g)) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + g->started = 1; + } + + while (g->have_data == 2) { + if (g->dont_block) { + pthread_mutex_unlock(&mm); + return MVNC_BUSY; + } + if (g->failed) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + pthread_mutex_unlock(&mm); + usleep(1000); + pthread_mutex_lock(&mm); + if (find_graph(g)) { + pthread_mutex_unlock(&mm); + return MVNC_GONE; + } + } + pthread_mutex_lock(&g->dev->mm); + pthread_mutex_unlock(&mm); + + if (usblink_setdata(g->dev->usb_link, g->input_idx ? "input2" : "input1", + inputTensor, inputTensorLength, g->have_data == 0)) { + pthread_mutex_unlock(&mm); + return MVNC_ERROR; + } + + g->user_param[g->input_idx] = userParam; + g->input_idx = !g->input_idx; + g->have_data++; + pthread_mutex_unlock(&g->dev->mm); + return MVNC_OK; +} + +mvncStatus mvncGetResult(void *graphHandle, void **outputData, + unsigned int *outputDataLength, void **userParam) +{ + int rc, unlock_own = 0; + + if (!graphHandle || !outputData || !outputDataLength) + return MVNC_INVALID_PARAMETERS; + + struct Graph *g = (struct Graph *) graphHandle; + pthread_mutex_lock(&mm); + if (find_graph(graphHandle)) { + pthread_mutex_unlock(&mm); + return MVNC_INVALID_PARAMETERS; + } + + while (!g->have_data) { + if (g->dont_block) { + pthread_mutex_unlock(&mm); + return MVNC_NO_DATA; + } + pthread_mutex_unlock(&mm); + usleep(1000); + pthread_mutex_lock(&mm); + if (find_graph(g)) { + pthread_mutex_unlock(&mm); + return MVNC_GONE; + } + } + + double timeout = time_in_seconds() + STATUS_WAIT_TIMEOUT; + do { + pthread_mutex_lock(&g->dev->mm); + pthread_mutex_unlock(&mm); + if (!usblink_getdata(g->dev->usb_link, "output", g->output_data, + 2 * g->noutputs, 0, 0)) { + unsigned int length = DEBUG_BUFFER_SIZE + THERMAL_BUFFER_SIZE + + sizeof(int) + sizeof(*g->time_taken) * g->nstages; + + if (usblink_getdata(g->dev->usb_link, "auxBuffer", g->aux_buffer, + length, 0, g->have_data == 2)) { + g->failed = 1; + pthread_mutex_unlock(&g->dev->mm); + return MVNC_ERROR; + } + unlock_own = 1; + break; + } + pthread_mutex_unlock(&g->dev->mm); + usleep(1000); + pthread_mutex_lock(&mm); + if (find_graph(g)) { + pthread_mutex_unlock(&mm); + return MVNC_GONE; + } + } while (time_in_seconds() < timeout); + + g->dev->throttle_happened = *(int *) (g->aux_buffer + DEBUG_BUFFER_SIZE + + THERMAL_BUFFER_SIZE); + *outputData = g->output_data; + *outputDataLength = 2 * g->noutputs; + *userParam = g->user_param[g->output_idx]; + g->output_idx = !g->output_idx; + g->have_data--; + + if (unlock_own) { + rc = *g->debug_buffer ? MVNC_MYRIAD_ERROR : MVNC_OK; + if (rc) + g->failed = 1; + pthread_mutex_unlock(&g->dev->mm); + } else { + rc = MVNC_TIMEOUT; + g->failed = 1; + pthread_mutex_unlock(&mm); + } + + return rc; +} diff --git a/api/src/usb_boot.c b/api/src/usb_boot.c new file mode 100644 index 0000000..2f7cf27 --- /dev/null +++ b/api/src/usb_boot.c @@ -0,0 +1,335 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +// USB utility for use with Myriad2v2 ROM +// Very heavily modified from Sabre version of usb_boot +// Author: David Steinberg + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usb_boot.h" +#include "mvnc.h" +#include "common.h" + +#define DEFAULT_WRITE_TIMEOUT 2000 +#define DEFAULT_CONNECT_TIMEOUT 20 // in 100ms units +#define DEFAULT_CHUNK_SZ 1024 * 1024 + +static unsigned int bulk_chunk_len = DEFAULT_CHUNK_SZ; +static int write_timeout = DEFAULT_WRITE_TIMEOUT; +static int connect_timeout = DEFAULT_CONNECT_TIMEOUT; +static int initialized; + +void __attribute__ ((constructor)) usb_library_load() +{ + initialized = !libusb_init(NULL); +} + +void __attribute__ ((destructor)) usb_library_unload() +{ + if (initialized) + libusb_exit(NULL); +} + +typedef struct timespec highres_time_t; + +static inline void highres_gettime(highres_time_t *ptr) +{ + clock_gettime(CLOCK_REALTIME, ptr); +} + +static inline double highres_elapsed_ms(highres_time_t *start, highres_time_t *end) +{ + struct timespec temp; + if ((end->tv_nsec - start->tv_nsec) < 0) { + temp.tv_sec = end->tv_sec - start->tv_sec - 1; + temp.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec; + } else { + temp.tv_sec = end->tv_sec - start->tv_sec; + temp.tv_nsec = end->tv_nsec - start->tv_nsec; + } + return (double)(temp.tv_sec * 1000) + (((double)temp.tv_nsec) * 0.000001); +} + +static const char *gen_addr(libusb_device *dev) +{ + static char buff[4 * 7] = ""; // '255-' x 7 (also gives us nul-terminator for last entry) + uint8_t pnums[7]; + int pnum_cnt, i; + char *p; + + pnum_cnt = libusb_get_port_numbers(dev, pnums, 7); + if (pnum_cnt == LIBUSB_ERROR_OVERFLOW) { + // shouldn't happen! + strcpy(buff, ""); + return buff; + } + p = buff; + for (i = 0; i < pnum_cnt - 1; i++) + p += snprintf(p, sizeof(buff) - strlen(buff), "%u.", pnums[i]); + snprintf(p, sizeof(buff) - strlen(buff), "%u", pnums[i]); + return buff; +} + +// if device is NULL, return device address for device at index idx +// if device is not NULL, search by name and return device struct +int usb_find_device(unsigned idx, char *addr, unsigned addr_size, void **device, + int vid, int pid) +{ + static libusb_device **devs; + libusb_device *dev; + struct libusb_device_descriptor desc; + int count = 0; + size_t i; + int res; + + if (!initialized) { + PRINT_INFO(stderr, + "Library has not been initialized when loaded\n"); + return MVNC_ERROR; + } + if (!devs || idx == 0) { + if (devs) { + libusb_free_device_list(devs, 1); + devs = 0; + } + if ((res = libusb_get_device_list(NULL, &devs)) < 0) { + PRINT_INFO(stderr, + "Unable to get USB device list: %s\n", + libusb_strerror(res)); + return MVNC_ERROR; + } + } + + i = 0; + while ((dev = devs[i++]) != NULL) { + if ((res = libusb_get_device_descriptor(dev, &desc)) < 0) { + PRINT_INFO(stderr, + "Unable to get USB device descriptor: %s\n", + libusb_strerror(res)); + continue; + } + if ((desc.idVendor == vid && desc.idProduct == pid) || + (pid == 0 && vid == 0 && ((desc.idVendor == DEFAULT_VID + && desc.idProduct == DEFAULT_PID) + || (desc.idVendor == + DEFAULT_OPEN_VID && + desc.idProduct == + DEFAULT_OPEN_PID)))) { + if (device) { + const char *caddr = gen_addr(dev); + if (!strcmp(caddr, addr)) { + PRINT_DEBUG(stderr, + "Found Address: %s - VID/PID %04x:%04x\n", + addr, desc.idVendor, desc.idProduct); + libusb_ref_device(dev); + libusb_free_device_list(devs, 1); + *device = dev; + devs = 0; + return 0; + } + } else if (idx == count) { + const char *caddr = gen_addr(dev); + PRINT_DEBUG(stderr, + "Device %d Address: %s - VID/PID %04x:%04x\n", + idx, caddr, desc.idVendor, desc.idProduct); + strncpy(addr, caddr, addr_size); + return 0; + } + count++; + } + } + libusb_free_device_list(devs, 1); + devs = 0; + return MVNC_DEVICE_NOT_FOUND; +} + +static libusb_device_handle *usb_open_device(libusb_device *dev, uint8_t *endpoint, + char *err_string_buff, unsigned buff_size) +{ + struct libusb_config_descriptor *cdesc; + const struct libusb_interface_descriptor *ifdesc; + libusb_device_handle *h = NULL; + int res, i; + + if ((res = libusb_open(dev, &h)) < 0) { + snprintf(err_string_buff, buff_size, "cannot open device: %s\n", + libusb_strerror(res)); + return 0; + } + if ((res = libusb_set_configuration(h, 1)) < 0) { + snprintf(err_string_buff, buff_size, + "setting config 1 failed: %s\n", libusb_strerror(res)); + libusb_close(h); + return 0; + } + if ((res = libusb_claim_interface(h, 0)) < 0) { + snprintf(err_string_buff, buff_size, + "claiming interface 0 failed: %s\n", + libusb_strerror(res)); + libusb_close(h); + return 0; + } + if ((res = libusb_get_config_descriptor(dev, 0, &cdesc)) < 0) { + snprintf(err_string_buff, buff_size, + "Unable to get USB config descriptor: %s\n", + libusb_strerror(res)); + libusb_close(h); + return 0; + } + + ifdesc = cdesc->interface->altsetting; + for (i = 0; i < ifdesc->bNumEndpoints; i++) { + PRINT_DEBUG(stderr, + "Found EP 0x%02x : max packet size is %u bytes\n", + ifdesc->endpoint[i].bEndpointAddress, + ifdesc->endpoint[i].wMaxPacketSize); + if ((ifdesc->endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != + LIBUSB_TRANSFER_TYPE_BULK) + continue; + if (! + (ifdesc->endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)) { + *endpoint = ifdesc->endpoint[i].bEndpointAddress; + bulk_chunk_len = ifdesc->endpoint[i].wMaxPacketSize; + libusb_free_config_descriptor(cdesc); + return h; + } + } + libusb_free_config_descriptor(cdesc); + strcpy(err_string_buff, "Unable to find BULK OUT endpoint\n"); + libusb_close(h); + return 0; +} + +// timeout: -1 = no (infinite) timeout, 0 = must happen immediately +static int wait_findopen(const char *device_address, int timeout, + libusb_device ** dev, libusb_device_handle ** devh, + uint8_t * endpoint) +{ + int i, rc; + char last_open_dev_err[128]; + + usleep(100000); + if (mvnc_loglevel > 1) { + // I know about switch(), but for some reason -1 is picked up correctly + if (timeout == -1) + PRINT("Starting wait for connect, no timeout\n"); + else if (timeout == 0) + PRINT("Trying to connect\n"); + else + PRINT("Starting wait for connect with %ums timeout\n", timeout * 100); + } + + last_open_dev_err[0] = 0; + i = 0; + for (;;) { + rc = usb_find_device(0, (char *) device_address, 0, + (void **) dev, DEFAULT_VID, DEFAULT_PID); + if (rc < 0) + return MVNC_ERROR; + if (!rc) { + if ((*devh = usb_open_device(*dev, endpoint, last_open_dev_err, 128))) { + PRINT_DEBUG(stderr, "Found and opened device\n"); + return 0; + } + libusb_unref_device(*dev); + } + + if (timeout != -1 && i == timeout) { + PRINT_INFO(stderr, "%serror: device not found!\n", + last_open_dev_err[0] ? last_open_dev_err : ""); + return rc ? MVNC_DEVICE_NOT_FOUND : MVNC_TIMEOUT; + } + i++; + usleep(100000); + } +} + +static int send_file(libusb_device_handle * h, uint8_t endpoint, + const uint8_t * tx_buf, unsigned file_size) +{ + const uint8_t *p; + int rc; + int wb, twb, wbr; + double elapsed_time; + highres_time_t t1, t2; + + elapsed_time = 0; + twb = 0; + p = tx_buf; + PRINT_DEBUG(stderr, "Performing bulk write of %u bytes...\n", + file_size); + + while (twb < file_size) { + highres_gettime(&t1); + wb = file_size - twb; + if (wb > bulk_chunk_len) + wb = bulk_chunk_len; + wbr = 0; + rc = libusb_bulk_transfer(h, endpoint, (void *) p, wb, &wbr, + write_timeout); + + if (rc || (wb != wbr)) { + if (rc == LIBUSB_ERROR_NO_DEVICE) + break; + + PRINT_INFO(stderr, + "bulk write: %s (%d bytes written, %d bytes to write)\n", + libusb_strerror(rc), wbr, wb); + if (rc == LIBUSB_ERROR_TIMEOUT) + return MVNC_TIMEOUT; + else + return MVNC_ERROR; + } + highres_gettime(&t2); + elapsed_time += highres_elapsed_ms(&t1, &t2); + twb += wbr; + p += wbr; + } + PRINT_DEBUG(stderr, + "Successfully sent %u bytes of data in %lf ms (%lf MB/s)\n", + file_size, elapsed_time, + ((double) file_size / 1048576.) / (elapsed_time * 0.001)); + return 0; +} + +int usb_boot(const char *addr, const void *mvcmd, unsigned size) +{ + int rc; + libusb_device *dev; + libusb_device_handle *h; + uint8_t endpoint; + + rc = wait_findopen(addr, connect_timeout, &dev, &h, &endpoint); + if (rc) + return rc; + rc = send_file(h, endpoint, mvcmd, size); + libusb_release_interface(h, 0); + libusb_close(h); + libusb_unref_device(dev); + return rc; +} diff --git a/api/src/usb_boot.h b/api/src/usb_boot.h new file mode 100644 index 0000000..7659b5f --- /dev/null +++ b/api/src/usb_boot.h @@ -0,0 +1,21 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +extern int mvnc_loglevel; +int usb_find_device(unsigned idx, char *addr, unsigned addrsize, void **device, int vid, int pid); +int usb_boot(const char *addr, const void *mvcmd, unsigned size); diff --git a/api/src/usb_link.h b/api/src/usb_link.h new file mode 100644 index 0000000..4c99f35 --- /dev/null +++ b/api/src/usb_link.h @@ -0,0 +1,28 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +#include "USBLinkDefines.h" + +int usblink_sendcommand(void *f, hostcommands_t command); +int usblink_resetmyriad(void *f); +int usblink_getmyriadstatus(void *f, myriadStatus_t *myriadState); +void *usblink_open(const char *path); +void usblink_close(void *f); +int usblink_setdata(void *f, const char *name, const void *data, unsigned int length, int hostready); +int usblink_getdata(void *f, const char *name, void *data, unsigned int length, unsigned int offset, int hostready); +void usblink_resetall(); diff --git a/api/src/usb_link_vsc.c b/api/src/usb_link_vsc.c new file mode 100644 index 0000000..f5d267e --- /dev/null +++ b/api/src/usb_link_vsc.c @@ -0,0 +1,204 @@ +/* +* Copyright 2017 Intel Corporation. +* The source code, information and material ("Material") contained herein is +* owned by Intel Corporation or its suppliers or licensors, and title to such +* Material remains with Intel Corporation or its suppliers or licensors. +* The Material contains proprietary information of Intel or its suppliers and +* licensors. The Material is protected by worldwide copyright laws and treaty +* provisions. +* No part of the Material may be used, copied, reproduced, modified, published, +* uploaded, posted, transmitted, distributed or disclosed in any way without +* Intel's prior express written permission. No license under any patent, +* copyright or other intellectual property rights in the Material is granted to +* or conferred upon you, either expressly, by implication, inducement, estoppel +* or otherwise. +* Any license under such intellectual property rights must be express and +* approved by Intel in writing. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb_link.h" +#include "usb_boot.h" +#include "common.h" + +#define USB_ENDPOINT_IN 0x81 +#define USB_ENDPOINT_OUT 0x01 +#define USB_TIMEOUT 10000 +#define USB_MAX_PACKET_SIZE 1024 * 1024 * 10 + +static int usb_write(void *f, const void *data, size_t size) +{ + while (size > 0) { + int bt, ss = size; + if (ss > USB_MAX_PACKET_SIZE) + ss = USB_MAX_PACKET_SIZE; + if (libusb_bulk_transfer(f, USB_ENDPOINT_OUT, (unsigned char *) data, ss, &bt, + USB_TIMEOUT)) + return -1; + data = (char *) data + bt; + size -= bt; + } + return 0; +} + +static int usb_read(void *f, void *data, size_t size) +{ + while (size > 0) { + int bt, ss = size; + if (ss > USB_MAX_PACKET_SIZE) + ss = USB_MAX_PACKET_SIZE; + if (libusb_bulk_transfer(f, USB_ENDPOINT_IN, data, ss, &bt, USB_TIMEOUT)) + return -1; + data = (char *) data + bt; + size -= bt; + } + return 0; +} + +void *usblink_open(const char *path) +{ + int rc; + libusb_device_handle *h = NULL; + libusb_device *dev; + + rc = usb_find_device(0, (char *) path, 0, (void **) &dev, + DEFAULT_OPEN_VID, DEFAULT_OPEN_PID); + if (rc < 0) + return 0; + + rc = libusb_open(dev, &h); + if (rc < 0) { + libusb_unref_device(dev); + return 0; + } + + libusb_unref_device(dev); + rc = libusb_claim_interface(h, 0); + if (rc < 0) { + libusb_close(h); + return 0; + } + return h; +} + +void usblink_close(void *f) +{ + libusb_release_interface(f, 0); + libusb_close(f); +} + +void usblink_resetall() +{ + libusb_device **devs; + libusb_device *dev; + struct libusb_device_descriptor desc; + libusb_device_handle *h; + size_t i; + int rc, reset = 0; + + if ((rc = libusb_get_device_list(NULL, &devs)) < 0) + return; + i = 0; + while ((dev = devs[i++]) != NULL) { + if (libusb_get_device_descriptor(dev, &desc) < 0) + continue; + if (desc.idVendor == DEFAULT_OPEN_VID && + desc.idProduct == DEFAULT_OPEN_PID) { + rc = libusb_open(dev, &h); + if (rc < -1) + continue; + rc = libusb_claim_interface(h, 0); + if (rc < 0) { + libusb_close(h); + continue; + } + PRINT_DEBUG(stderr, "Found stale device, resetting\n"); + usblink_resetmyriad(h); + usblink_close(h); + reset = 1; + } + } + if (reset) + usleep(1000000); + libusb_free_device_list(devs, 1); +} + +int usblink_setdata(void *f, const char *name, const void *data, + unsigned int length, int host_ready) +{ + usbHeader_t header; + memset(&header, 0, sizeof(header)); + header.cmd = USB_LINK_HOST_SET_DATA; + header.hostready = host_ready; + strcpy(header.name, name); + header.dataLength = length; + if (usb_write(f, &header, sizeof(header))) + return -1; + + unsigned int operation_permit = 0xFFFF; + if (usb_read(f, &operation_permit, sizeof(operation_permit))) + return -1; + + if (operation_permit != 0xABCD) + return -1; + int rc = usb_write(f, data, length); + return rc; +} + +int usblink_getdata(void *f, const char *name, void *data, unsigned int length, + unsigned int offset, int host_ready) +{ + usbHeader_t header; + memset(&header, 0, sizeof(header)); + header.cmd = USB_LINK_HOST_GET_DATA; + header.hostready = host_ready; + strcpy(header.name, name); + header.dataLength = length; + header.offset = offset; + if (usb_write(f, &header, sizeof(header))) + return -1; + + unsigned int operation_permit = 0xFFFF; + if (usb_read(f, &operation_permit, sizeof(operation_permit))) + return -1; + + if (operation_permit != 0xABCD) + return -1; + return usb_read(f, data, length); +} + +int usblink_resetmyriad(void *f) +{ + usbHeader_t header; + memset(&header, 0, sizeof(header)); + header.cmd = USB_LINK_RESET_REQUEST; + if (usb_write(f, &header, sizeof(header))) + return -1; + return 0; +} + +int usblink_getmyriadstatus(void *f, myriadStatus_t* myriad_state) +{ + usbHeader_t header; + memset(&header, 0, sizeof(header)); + header.cmd = USB_LINK_GET_MYRIAD_STATUS; + if (usb_write(f, &header, sizeof(header))) + return -1; + return usb_read(f, myriad_state, sizeof(*myriad_state)); +} -- 2.34.1