v4.6.0
This commit is contained in:
212
.logo.svg
Normal file
212
.logo.svg
Normal file
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg4986"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
xml:space="preserve"
|
||||
width="454.94739"
|
||||
height="132.55138"
|
||||
viewBox="0 0 454.94739 132.55138"
|
||||
sodipodi:docname="Hailo_Logo_RGB.svg"><metadata
|
||||
id="metadata4992"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs4990"><clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath5014"><path
|
||||
d="M 0,110 370,110 370,0 0,0 0,110 Z"
|
||||
id="path5016"
|
||||
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2048"
|
||||
inkscape:window-height="1100"
|
||||
id="namedview4988"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.9109866"
|
||||
inkscape:cx="216.90465"
|
||||
inkscape:cy="59.262279"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g4994"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" /><g
|
||||
id="g4994"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Hailo_Logo_RGB"
|
||||
transform="matrix(1.25,0,0,-1.25,-5.127625,136.24475)"><g
|
||||
id="g4996"
|
||||
transform="translate(172.3149,50.2915)"><path
|
||||
d="M 0,0 -14.161,0 -40.557,47.98 -40.674,48.181 -40.793,47.98 -67.189,0 -81.35,0 l 34.496,58.684 -0.011,0.02 0.023,0 12.334,0 0.023,0 -0.011,-0.02 L 0,0 Z"
|
||||
style="fill:#0098c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path4998"
|
||||
inkscape:connector-curvature="0" /></g><path
|
||||
d="m 186.287,50.291 14.16,0 0,58.704 -14.16,0 0,-58.704 z"
|
||||
style="fill:#0098c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5000"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
id="g5002"
|
||||
transform="translate(4.2656,50.2915)"><path
|
||||
d="m 0,0 14.298,0 0,24.747 44.268,0 0,-24.747 14.161,0 0,58.704 -14.161,0 0,-22.272 -44.268,0 0,22.272 L 0,58.704 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5004"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5006"
|
||||
transform="translate(221.0957,50.2915)"><path
|
||||
d="m 0,0 59.941,0 0,10.999 -45.643,0 0,47.705 L 0,58.704 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5008"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5010"><g
|
||||
id="g5012"
|
||||
clip-path="url(#clipPath5014)"><g
|
||||
id="g5018"
|
||||
transform="translate(368.06,64.1768)"><path
|
||||
d="m 0,0 0,30.933 c 0,11.274 -3.712,13.886 -15.123,13.886 l -44.956,0 c -11.411,0 -15.123,-2.612 -15.123,-13.886 l 0,-30.933 c 0,-11.136 3.575,-13.885 15.123,-13.885 l 44.956,0 C -3.712,-13.885 0,-11.136 0,0 m -14.16,-2.612 -46.881,0 0,36.569 46.881,0 0,-36.569 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5020"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5022"
|
||||
transform="translate(15.4511,10.2974)"><path
|
||||
d="m 0,0 0.106,-1.816 c -1.637,-0.106 -4.272,-0.16 -7.903,-0.16 -1.086,0 -1.945,0.289 -2.577,0.868 -0.632,0.578 -0.957,1.357 -0.975,2.337 l 0,12.068 c 0.018,0.979 0.343,1.758 0.975,2.337 0.632,0.578 1.491,0.867 2.577,0.867 3.631,0 6.266,-0.053 7.903,-0.16 L 0,14.499 l -7.396,0 c -1.069,0 -1.603,-0.587 -1.603,-1.762 l 0,-4.006 7.957,0 0,-1.896 -7.957,0 0,-5.046 C -8.999,0.596 -8.465,0 -7.396,0 L 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5024"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5026"
|
||||
transform="translate(23.7817,21.3521)"><path
|
||||
d="m 0,0 0.134,-2.056 c 1.833,1.584 3.604,2.376 5.313,2.376 1.816,0 2.911,-0.765 3.284,-2.296 1.763,1.531 3.507,2.296 5.234,2.296 1.121,0 1.98,-0.303 2.577,-0.907 0.596,-0.606 0.895,-1.496 0.895,-2.671 l 0,-9.746 -2.244,0 0,9.106 c -0.018,0.8 -0.182,1.383 -0.494,1.748 -0.311,0.365 -0.823,0.547 -1.535,0.547 -0.623,0 -1.224,-0.142 -1.802,-0.426 -0.579,-0.285 -1.402,-0.82 -2.47,-1.603 l 0,-9.372 -2.19,0 0,9.106 c 0,0.818 -0.164,1.405 -0.494,1.762 C 5.879,-1.78 5.367,-1.603 4.673,-1.603 4.05,-1.603 3.449,-1.745 2.871,-2.029 2.292,-2.314 1.469,-2.84 0.401,-3.605 l 0,-9.399 -2.27,0 L -1.869,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5028"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5030"
|
||||
transform="translate(50.1899,17.6938)"><path
|
||||
d="m 0,0 0,-6.889 c 1.815,-0.534 3.204,-0.801 4.166,-0.801 1.174,0 1.993,0.329 2.456,0.988 0.462,0.658 0.694,1.922 0.694,3.791 0,1.816 -0.218,3.089 -0.654,3.819 C 6.226,1.637 5.482,2.002 4.432,2.002 3.755,2.002 3.084,1.847 2.417,1.535 1.749,1.224 0.943,0.711 0,0 m -0.401,3.658 0.187,-2.083 c 0.694,0.748 1.531,1.335 2.51,1.762 0.979,0.428 1.94,0.642 2.884,0.642 1.549,0 2.679,-0.57 3.391,-1.709 0.712,-1.14 1.068,-2.867 1.068,-5.181 0,-2.456 -0.391,-4.196 -1.175,-5.22 -0.783,-1.024 -2.029,-1.535 -3.738,-1.535 -1.709,0 -3.311,0.445 -4.806,1.335 C -0.027,-8.937 0,-9.809 0,-10.948 l 0,-3.765 -2.27,0 0,18.371 1.869,0 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5032"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5034"
|
||||
transform="translate(74.581,18.7085)"><path
|
||||
d="m 0,0 c -0.543,0.694 -1.526,1.041 -2.95,1.041 -1.425,0 -2.404,-0.347 -2.938,-1.041 -0.534,-0.694 -0.8,-1.985 -0.8,-3.872 0,-1.887 0.266,-3.177 0.8,-3.872 0.534,-0.694 1.513,-1.041 2.938,-1.041 1.424,0 2.407,0.347 2.95,1.041 0.543,0.695 0.814,1.985 0.814,3.872 C 0.814,-1.985 0.543,-0.694 0,0 m -2.95,2.964 c 2.242,0 3.822,-0.517 4.739,-1.549 0.917,-1.033 1.375,-2.795 1.375,-5.287 0,-2.492 -0.458,-4.254 -1.375,-5.287 -0.917,-1.032 -2.497,-1.549 -4.739,-1.549 -2.226,0 -3.801,0.517 -4.727,1.549 -0.926,1.033 -1.388,2.795 -1.388,5.287 0,2.492 0.462,4.254 1.388,5.287 0.926,1.032 2.501,1.549 4.727,1.549"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5036"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5038"
|
||||
transform="translate(103.165,21.3521)"><path
|
||||
d="m 0,0 -3.792,-12.363 c -0.106,-0.428 -0.4,-0.641 -0.881,-0.641 l -2.056,0 c -0.213,0 -0.405,0.067 -0.574,0.2 -0.169,0.134 -0.271,0.307 -0.307,0.521 l -2.136,8.838 c -0.053,0.249 -0.125,0.601 -0.213,1.055 -0.09,0.454 -0.161,0.787 -0.214,1.001 l -0.321,0 -0.454,-2.056 -2.109,-8.838 c -0.125,-0.481 -0.427,-0.721 -0.908,-0.721 l -2.029,0 c -0.481,0 -0.775,0.213 -0.881,0.641 L -20.667,0 l 2.35,0 2.697,-9.586 c 0.16,-0.552 0.302,-1.202 0.427,-1.949 l 0.347,0 0.481,1.949 2.162,8.865 c 0.089,0.48 0.374,0.721 0.855,0.721 l 2.056,0 c 0.445,0 0.729,-0.25 0.854,-0.748 l 2.137,-8.838 c 0.035,-0.196 0.106,-0.512 0.213,-0.948 0.107,-0.436 0.187,-0.77 0.24,-1.001 l 0.348,0 c 0.017,0.089 0.075,0.369 0.173,0.841 0.098,0.471 0.191,0.841 0.281,1.108 L -2.35,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5040"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5042"
|
||||
transform="translate(110.2675,15.5044)"><path
|
||||
d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5044"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5046"
|
||||
transform="translate(133.9511,21.6724)"><path
|
||||
d="m 0,0 -0.267,-2.136 -0.748,0 c -0.658,0 -1.339,-0.13 -2.042,-0.387 -0.704,-0.259 -1.642,-0.681 -2.817,-1.269 l 0,-9.532 -2.27,0 0,13.004 1.763,0 0.24,-2.056 C -4.13,-0.792 -2.279,0 -0.587,0 L 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5048"
|
||||
inkscape:connector-curvature="0" /></g><path
|
||||
d="m 141.801,8.348 -2.243,0 0,13.004 2.243,0 0,-13.004 z m -1.656,18.531 1.069,0 c 0.462,0 0.694,-0.232 0.694,-0.694 l 0,-1.522 c 0,-0.463 -0.232,-0.694 -0.694,-0.694 l -1.069,0 c -0.462,0 -0.694,0.231 -0.694,0.694 l 0,1.522 c 0,0.462 0.232,0.694 0.694,0.694"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5050"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
id="g5052"
|
||||
transform="translate(150.6127,21.3521)"><path
|
||||
d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5054"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5056"
|
||||
transform="translate(169.25,15.6777)"><path
|
||||
d="m 0,0 c 0.516,-0.365 1.415,-0.547 2.697,-0.547 1.282,0 2.18,0.182 2.697,0.547 0.516,0.365 0.774,0.983 0.774,1.856 0,0.872 -0.254,1.491 -0.761,1.855 C 4.899,4.076 3.996,4.259 2.697,4.259 1.415,4.259 0.516,4.076 0,3.711 -0.517,3.347 -0.774,2.728 -0.774,1.856 -0.774,0.983 -0.517,0.365 0,0 M 4.593,-6.715 0.16,-6.101 c -0.908,-0.694 -1.362,-1.523 -1.362,-2.483 0,-0.908 0.267,-1.504 0.801,-1.79 0.534,-0.284 1.611,-0.427 3.231,-0.427 1.585,0 2.648,0.147 3.191,0.441 0.543,0.294 0.814,0.885 0.814,1.776 0,0.64 -0.138,1.077 -0.413,1.308 -0.276,0.231 -0.886,0.418 -1.829,0.561 M 9.666,4.419 7.743,4.259 C 8.099,3.671 8.277,2.871 8.277,1.856 8.277,0.396 7.859,-0.659 7.022,-1.309 6.186,-1.958 4.744,-2.283 2.697,-2.283 1.7,-2.283 0.801,-2.194 0,-2.016 c -0.338,-0.41 -0.437,-0.859 -0.294,-1.348 0.143,-0.49 0.543,-0.788 1.202,-0.895 l 4.86,-0.774 c 1.21,-0.178 2.06,-0.557 2.549,-1.135 0.49,-0.579 0.735,-1.419 0.735,-2.523 0,-1.513 -0.45,-2.564 -1.349,-3.151 -0.899,-0.588 -2.514,-0.881 -4.846,-0.881 -2.35,0 -3.983,0.289 -4.9,0.868 -0.917,0.578 -1.375,1.606 -1.375,3.084 0,0.765 0.16,1.379 0.48,1.842 0.321,0.463 0.864,0.899 1.629,1.308 -0.658,0.517 -0.961,1.202 -0.907,2.057 0.053,0.854 0.391,1.522 1.014,2.002 -1.104,0.587 -1.655,1.718 -1.655,3.391 0,1.495 0.414,2.564 1.241,3.204 0.828,0.641 2.274,0.962 4.34,0.962 1.228,0 2.233,-0.107 3.017,-0.321 l 4.058,0 -0.133,-1.255 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5058"
|
||||
inkscape:connector-curvature="0" /></g><path
|
||||
d="m 201.456,8.348 -2.35,0 0,18.424 2.35,0 0,-18.424 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5060"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
id="g5062"
|
||||
transform="translate(210.4013,21.3521)"><path
|
||||
d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5064"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5066"
|
||||
transform="translate(230.08,19.563)"><path
|
||||
d="M 0,0 0,-7.637 C 0,-8.26 0.133,-8.705 0.4,-8.972 0.667,-9.239 1.122,-9.373 1.762,-9.373 l 1.976,0 0.267,-1.735 c -0.819,-0.231 -1.798,-0.347 -2.937,-0.347 -1.086,0 -1.914,0.302 -2.483,0.908 -0.57,0.605 -0.855,1.477 -0.855,2.616 l 0,7.931 -2.35,0 0,1.655 2.35,0.107 0,3.872 2.27,0 0,-3.845 4.139,0 L 4.139,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5068"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5070"
|
||||
transform="translate(241.455,15.5044)"><path
|
||||
d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5072"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5074"
|
||||
transform="translate(259.0776,27.0391)"><path
|
||||
d="m 0,0 0,-15.113 c -0.018,-0.57 0.125,-1.001 0.427,-1.295 0.303,-0.294 0.748,-0.441 1.336,-0.441 l 1.255,0 0.267,-1.735 c -0.481,-0.231 -1.273,-0.347 -2.377,-0.347 -0.979,0 -1.754,0.289 -2.323,0.868 -0.57,0.578 -0.855,1.392 -0.855,2.443 L -2.27,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5076"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5078"
|
||||
transform="translate(269.7314,27.0391)"><path
|
||||
d="m 0,0 0,-15.113 c -0.018,-0.57 0.125,-1.001 0.427,-1.295 0.303,-0.294 0.748,-0.441 1.336,-0.441 l 1.255,0 0.267,-1.735 c -0.481,-0.231 -1.273,-0.347 -2.377,-0.347 -0.979,0 -1.754,0.289 -2.323,0.868 -0.57,0.578 -0.855,1.392 -0.855,2.443 L -2.27,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5080"
|
||||
inkscape:connector-curvature="0" /></g><path
|
||||
d="m 280.546,8.348 -2.243,0 0,13.004 2.243,0 0,-13.004 z m -1.656,18.531 1.068,0 c 0.463,0 0.694,-0.232 0.694,-0.694 l 0,-1.522 c 0,-0.463 -0.231,-0.694 -0.694,-0.694 l -1.068,0 c -0.463,0 -0.694,0.231 -0.694,0.694 l 0,1.522 c 0,0.462 0.231,0.694 0.694,0.694"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5082"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
id="g5084"
|
||||
transform="translate(289.8642,15.6777)"><path
|
||||
d="m 0,0 c 0.516,-0.365 1.415,-0.547 2.697,-0.547 1.282,0 2.18,0.182 2.697,0.547 0.516,0.365 0.774,0.983 0.774,1.856 0,0.872 -0.254,1.491 -0.761,1.855 C 4.899,4.076 3.996,4.259 2.697,4.259 1.415,4.259 0.516,4.076 0,3.711 -0.517,3.347 -0.774,2.728 -0.774,1.856 -0.774,0.983 -0.517,0.365 0,0 M 4.593,-6.715 0.16,-6.101 c -0.908,-0.694 -1.362,-1.523 -1.362,-2.483 0,-0.908 0.267,-1.504 0.801,-1.79 0.534,-0.284 1.611,-0.427 3.231,-0.427 1.585,0 2.648,0.147 3.191,0.441 0.543,0.294 0.814,0.885 0.814,1.776 0,0.64 -0.138,1.077 -0.413,1.308 -0.276,0.231 -0.886,0.418 -1.829,0.561 M 9.666,4.419 7.743,4.259 C 8.099,3.671 8.277,2.871 8.277,1.856 8.277,0.396 7.859,-0.659 7.022,-1.309 6.186,-1.958 4.744,-2.283 2.697,-2.283 1.7,-2.283 0.801,-2.194 0,-2.016 c -0.338,-0.41 -0.437,-0.859 -0.294,-1.348 0.143,-0.49 0.543,-0.788 1.202,-0.895 l 4.86,-0.774 c 1.21,-0.178 2.06,-0.557 2.549,-1.135 0.49,-0.579 0.735,-1.419 0.735,-2.523 0,-1.513 -0.45,-2.564 -1.349,-3.151 -0.899,-0.588 -2.514,-0.881 -4.846,-0.881 -2.35,0 -3.983,0.289 -4.9,0.868 -0.917,0.578 -1.375,1.606 -1.375,3.084 0,0.765 0.16,1.379 0.48,1.842 0.321,0.463 0.864,0.899 1.629,1.308 -0.658,0.517 -0.961,1.202 -0.907,2.057 0.053,0.854 0.391,1.522 1.014,2.002 -1.104,0.587 -1.655,1.718 -1.655,3.391 0,1.495 0.414,2.564 1.241,3.204 0.828,0.641 2.274,0.962 4.34,0.962 1.228,0 2.233,-0.107 3.017,-0.321 l 4.058,0 -0.133,-1.255 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5086"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5088"
|
||||
transform="translate(306.7929,15.5044)"><path
|
||||
d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5090"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5092"
|
||||
transform="translate(323.935,21.3521)"><path
|
||||
d="m 0,0 0.16,-2.056 c 2.1,1.584 4.041,2.376 5.821,2.376 2.35,0 3.525,-1.193 3.525,-3.578 l 0,-9.746 -2.27,0 0,9.106 c 0,0.854 -0.143,1.45 -0.427,1.788 -0.285,0.339 -0.766,0.507 -1.442,0.507 -0.712,0 -1.429,-0.16 -2.15,-0.48 -0.72,-0.32 -1.677,-0.846 -2.87,-1.575 l 0,-9.346 -2.27,0 L -1.923,0 0,0 Z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5094"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5096"
|
||||
transform="translate(349.7817,10.2173)"><path
|
||||
d="m 0,0 0.241,-1.522 c -1.282,-0.445 -2.769,-0.667 -4.46,-0.667 -2.242,0 -3.831,0.511 -4.766,1.535 -0.934,1.023 -1.402,2.79 -1.402,5.3 0,2.51 0.468,4.272 1.402,5.287 0.935,1.015 2.532,1.522 4.793,1.522 1.709,0 3.106,-0.205 4.192,-0.614 L -0.293,9.372 c -1.175,0.107 -2.35,0.16 -3.525,0.16 -1.567,0 -2.653,-0.346 -3.258,-1.041 -0.605,-0.694 -0.907,-1.976 -0.907,-3.845 0,-1.887 0.302,-3.177 0.907,-3.872 0.605,-0.694 1.691,-1.041 3.258,-1.041 1.424,0 2.697,0.089 3.818,0.267"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5098"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
id="g5100"
|
||||
transform="translate(357.125,15.5044)"><path
|
||||
d="M 0,0 5.5,0 C 6.444,0 6.916,0.641 6.916,1.922 6.898,2.759 6.649,3.355 6.168,3.711 5.687,4.067 4.869,4.245 3.711,4.245 2.34,4.245 1.389,3.947 0.854,3.351 0.32,2.754 0.036,1.637 0,0 m 6.088,-1.763 -6.061,0 c 0.124,-1.495 0.489,-2.501 1.095,-3.017 0.605,-0.516 1.61,-0.774 3.017,-0.774 1.477,0 2.981,0.107 4.512,0.32 l 0.241,-1.522 c -1.158,-0.48 -2.84,-0.721 -5.047,-0.721 -2.243,0 -3.841,0.521 -4.793,1.562 -0.952,1.042 -1.428,2.808 -1.428,5.301 0,2.51 0.462,4.267 1.388,5.273 0.926,1.006 2.457,1.509 4.592,1.509 C 5.545,6.168 6.96,5.816 7.85,5.113 8.74,4.41 9.186,3.346 9.186,1.922 9.221,-0.534 8.188,-1.763 6.088,-1.763"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path5102"
|
||||
inkscape:connector-curvature="0" /></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
102
CMakeLists.txt
Normal file
102
CMakeLists.txt
Normal file
@@ -0,0 +1,102 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
|
||||
option(HAILO_BUILD_PYBIND "Build Python binding" OFF)
|
||||
option(HAILO_BUILD_PYHAILORT_VENV "Build pyhailort in venv" ON)
|
||||
option(HAILO_BUILD_EMULATOR "Build hailort for emulator" OFF)
|
||||
option(HAILO_BUILD_UT "Build Unit Tests" OFF)
|
||||
option(HAILO_BUILD_GSTREAMER "Compile gstreamer plugins" OFF)
|
||||
option(HAILO_BUILD_EXAMPLES "Build examples" OFF)
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
project(HailoRT)
|
||||
|
||||
# Check build type
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Debug")
|
||||
set(CMAKE_BUILD_TYPE "Debug")
|
||||
endif()
|
||||
message(STATUS "Building ${PROJECT_NAME} in ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
# Set compiler flags in HAILORT_COMPILE_OPTIONS
|
||||
# TODO: Change HAILORT_COMPILE_OPTIONS to add_compile_options
|
||||
if(WIN32)
|
||||
# TODO: set this eventually? set(HAILORT_COMPILE_OPTIONS /Wall)
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS}
|
||||
/W4
|
||||
/WX
|
||||
/DWIN32_LEAN_AND_MEAN
|
||||
/DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own)
|
||||
/D_HAILO_EXPORTING
|
||||
/wd4201 # Anonymous union/struct
|
||||
/wd4251 # C++ ABI with STL
|
||||
)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Disable "unsafe function" warnings
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} /O2 /DNDEBUG /Zi)
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} /Od /Zi /DDEBUG)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/DEBUG>")
|
||||
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:REF>")
|
||||
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:ICF>")
|
||||
|
||||
elseif(UNIX)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -Werror -Wall -Wextra -Wconversion)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -Werror -Wall -Wextra
|
||||
# TODO: remove me warnings
|
||||
-Wno-conversion
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-inconsistent-missing-override
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid value for CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -O3 -DNDEBUG)
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -O0 -g -DDEBUG)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Unexpeced host, stopping build")
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
# Flag for emulator (FPGA/Veloce)
|
||||
if(HAILO_BUILD_EMULATOR)
|
||||
message(WARNING "HailoRT is building with Emulator flag on")
|
||||
set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -DHAILO_EMULATOR)
|
||||
endif()
|
||||
|
||||
# Prevent in-tree building
|
||||
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||
message(FATAL_ERROR "In-source builds are not allowed.
|
||||
Please remove the `CMakeCache.txt` file and `CMakeFiles` directory from `${CMAKE_SOURCE_DIR}`
|
||||
In order to build, please create a new `build` directory and run `cmake ..` from there.")
|
||||
endif()
|
||||
|
||||
# Enable output of compile commands during generation
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Set validation dir
|
||||
set(PLATFORM_VALIDATION_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/platform_internals/hailo_platform_internals/validation")
|
||||
|
||||
if (NOT DEFINED HEFS_DIR)
|
||||
set(HEFS_DIR "${PLATFORM_VALIDATION_DIRECTORY}/hefs/latest")
|
||||
message(STATUS "No HEFS_DIR provided, using default ('${HEFS_DIR}')")
|
||||
endif()
|
||||
|
||||
# Add subdirectories
|
||||
add_subdirectory(hailort)
|
||||
43
README.md
Normal file
43
README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
<p align="left">
|
||||
<img src=".logo.svg" />
|
||||
</p>
|
||||
|
||||
|
||||
# HailoRT #
|
||||
|
||||
HailoRT is a light-weight and production-grade run-time library, which runs on the host processor, and
|
||||
implements a robust user-space run-time library (HailoRT Library) responsible for operating a Hailo device, with intuitive APIs in C/C++ for optimized performance.
|
||||
|
||||
HailoRT is comprised of the following main components:
|
||||
- HailoRT Library.
|
||||
- HailoRT CLI - command line application used to control the Hailo device, run inference using the device,
|
||||
collect inference statistics and device events, etc.
|
||||
- [**HailoRT PCIe Driver**](https://github.com/hailo-ai/hailort-drivers) - the device driver used to manage the Hailo device, communicate with the device and transfer
|
||||
data to/from the device. The PCIe driver includes the Hailo-8 firmware that runs on the Hailo device, manages the boot and control of the Hailo device.
|
||||
- pyHailoRT - HailoRT Python API (wraps the run-time library)
|
||||
- HailoRT GStreamer element (HailoNet).
|
||||
|
||||
HailoRT supports Linux and Windows, and can be compiled from sources to be integrated with various x86 and ARM processors.
|
||||
|
||||
## Usage
|
||||
|
||||
See [**hailo.ai developer zone documentation**](https://hailo.ai/developer-zone/documentation/hailort/latest/) (registration is required for full documentation access).
|
||||
|
||||
## Changelog
|
||||
|
||||
See [**hailo.ai developer zone - HailoRT changelog**](https://hailo.ai/developer-zone/documentation/hailort/latest/?sp_referrer=changelog/changelog.html) (registration required).
|
||||
|
||||
## Contact
|
||||
|
||||
Contact information and support is available at [**hailo.ai**](https://hailo.ai/contact-us/).
|
||||
|
||||
## About Hailo-8™
|
||||
|
||||
Hailo-8 is a deep learning processor for edge devices. The Hailo-8 provides groundbraking efficiency for neural network deployment.
|
||||
The Hailo-8 edge AI processor, featuring up to 26 tera-operations per second (TOPS), significantly outperforms all other edge processors.
|
||||
Hailo-8 is available in various form-factors, including the Hailo-8 M.2 Module.
|
||||
|
||||
The Hailo-8 AI processor is designed to fit into a multitude of smart machines and devices, for a wide variety of sectors including Automotive, Smart Cities, Industry 4.0,
|
||||
Retail and Smart Homes.
|
||||
|
||||
For more information, please visit [**hailo.ai**](https://hailo.ai/).
|
||||
79
common/config_definitions.json
Normal file
79
common/config_definitions.json
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"_comment":
|
||||
[
|
||||
"This file defines the available fields of the firmwares config. It is not used to serialize any data.",
|
||||
"WARNING! DO NOT CHANGE THE ORDER OF THE DEFINITIONS AS IT WILL CHANGE THEIR GENERATED VALUES!"
|
||||
],
|
||||
"version": 0,
|
||||
"categories":
|
||||
{
|
||||
"network":
|
||||
{
|
||||
"entries":
|
||||
{
|
||||
"should_use_dhcp": {"size": 1, "deserialize_as": "bool"},
|
||||
"mac_address": {"size": 1, "length": 6, "deserialize_as": "mac_address"},
|
||||
"static_ip_address": {"size": 4, "deserialize_as": "ipv4"},
|
||||
"static_gw_address": {"size": 4, "deserialize_as": "ipv4"},
|
||||
"static_netmask": {"size": 4, "deserialize_as": "ipv4"},
|
||||
"rx_pause_frames_enable": {"size": 1, "deserialize_as": "bool"}
|
||||
}
|
||||
},
|
||||
"system":
|
||||
{
|
||||
"entries":
|
||||
{
|
||||
"name": {"size": 1, "length": 32, "deserialize_as": "str"},
|
||||
"app_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
|
||||
"app_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
|
||||
"core_watchdog_enable": {"size": 1, "deserialize_as": "bool"},
|
||||
"core_watchdog_cycles": {"size": 4, "deserialize_as": "int"},
|
||||
"watchdog_mode" : {"size": 1, "deserialize_as": "watchdog_mode"},
|
||||
"max_neural_network_core_clock_rate": {"size": 4, "deserialize_as": "clock_frequency"},
|
||||
"supported_aspm_states": {"size": 1, "deserialize_as": "supported_aspm_states"},
|
||||
"bus_0_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
|
||||
"bus_1_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
|
||||
"bus_2_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
|
||||
"bus_3_i2c_speed": {"size": 1, "deserialize_as": "i2c_speed"},
|
||||
"supported_aspm_l1_substates": {"size": 1, "deserialize_as": "supported_aspm_l1_substates"},
|
||||
"overcurrent_parameters_source": {"size": 1, "deserialize_as": "overcurrent_parameters_source"},
|
||||
"overcurrent_monitoring_red_threshold": {"size": 4, "deserialize_as": "int"},
|
||||
"overcurrent_conversion_time_microseconds": {"size": 4, "deserialize_as": "conversion_time"},
|
||||
"temperature_parameters_source": {"size": 1, "deserialize_as": "temperature_parameters_source"},
|
||||
"temperature_red_threshold": {"size": 1, "deserialize_as": "int"},
|
||||
"temperature_red_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
|
||||
"temperature_orange_threshold": {"size": 1, "deserialize_as": "int"},
|
||||
"temperature_orange_hysteresis_threshold": {"size": 1, "deserialize_as": "int"},
|
||||
"temperature_throttling_enable": {"size": 1, "deserialize_as": "bool"},
|
||||
"overcurrent_monitoring_orange_threshold_enable": {"size": 1, "deserialize_as": "bool"}
|
||||
}
|
||||
},
|
||||
"control":
|
||||
{
|
||||
"entries":
|
||||
{
|
||||
"udp_port": {"size": 2, "deserialize_as": "int"}
|
||||
}
|
||||
},
|
||||
"d2h_event":
|
||||
{
|
||||
"entries":
|
||||
{
|
||||
"host_udp_port": {"size": 2, "deserialize_as": "int"},
|
||||
"src_udp_port": {"size": 2, "deserialize_as": "int"},
|
||||
"host_ip_address": {"size": 4, "deserialize_as": "ipv4"},
|
||||
"connection_type": {"size": 1, "deserialize_as": "bool"}
|
||||
}
|
||||
},
|
||||
"logger":
|
||||
{
|
||||
"entries":
|
||||
{
|
||||
"send_via_pci": {"size": 1, "deserialize_as": "bool"},
|
||||
"send_via_uart": {"size": 1, "deserialize_as": "bool"},
|
||||
"logger_level": {"size": 4, "deserialize_as": "logger_level"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
144
common/config_schema.json
Normal file
144
common/config_schema.json
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "config_schema",
|
||||
"description": "schema for user config",
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"network":
|
||||
{
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"should_use_dhcp": {"type": "boolean"},
|
||||
"mac_address": {"$ref": "#/definitions/mac_address"},
|
||||
"static_ip_address": {"type": "string", "format": "ipv4"},
|
||||
"static_gw_address": {"type": "string", "format": "ipv4"},
|
||||
"static_netmask": {"type": "string", "format": "ipv4"},
|
||||
"rx_pause_frames_enable": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"system":
|
||||
{
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"name": {"type": "string", "maxLength": 32},
|
||||
"app_watchdog_enable": {"type": "boolean"},
|
||||
"app_watchdog_cycles": {"$ref": "#/definitions/uint16_t"},
|
||||
"core_watchdog_enable": {"type": "boolean"},
|
||||
"core_watchdog_cycles": {"$ref": "#/definitions/uint16_t"},
|
||||
"watchdog_mode" : {"$ref": "#/definitions/watchdog_mode"},
|
||||
"max_neural_network_core_clock_rate": {"$ref": "#/definitions/clock_frequency"},
|
||||
"supported_aspm_states": {"$ref": "#/definitions/supported_aspm_states"},
|
||||
"bus_0_i2c_speed": {"$ref": "#/definitions/i2c_speed"},
|
||||
"bus_1_i2c_speed": {"$ref": "#/definitions/i2c_speed"},
|
||||
"bus_2_i2c_speed": {"$ref": "#/definitions/i2c_speed"},
|
||||
"bus_3_i2c_speed": {"$ref": "#/definitions/i2c_speed"},
|
||||
"supported_aspm_l1_substates": {"$ref": "#/definitions/supported_aspm_l1_substates"},
|
||||
"overcurrent_parameters_source": {"$ref": "#/definitions/overcurrent_parameters_source"},
|
||||
"overcurrent_monitoring_red_threshold": {"$ref": "#/definitions/uint32_t"},
|
||||
"overcurrent_conversion_time_microseconds": {"$ref": "#/definitions/conversion_time"},
|
||||
"temperature_parameters_source": {"$ref": "#/definitions/temperature_parameters_source"},
|
||||
"temperature_red_threshold": {"$ref": "#/definitions/int8_t"},
|
||||
"temperature_red_hysteresis_threshold": {"$ref": "#/definitions/int8_t"},
|
||||
"temperature_orange_threshold": {"$ref": "#/definitions/int8_t"},
|
||||
"temperature_orange_hysteresis_threshold": {"$ref": "#/definitions/int8_t"},
|
||||
"overcurrent_monitoring_orange_threshold_enable": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"control":
|
||||
{
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"udp_port": {"$ref": "#/definitions/uint16_t"}
|
||||
}
|
||||
},
|
||||
"d2h_event":
|
||||
{
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"host_udp_port": {"$ref": "#/definitions/uint16_t"},
|
||||
"src_udp_port": {"$ref": "#/definitions/uint16_t"},
|
||||
"host_ip_address": {"type": "string", "format": "ipv4"},
|
||||
"connection_type": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"logger":
|
||||
{
|
||||
"type": "object",
|
||||
"properties":
|
||||
{
|
||||
"send_via_pci": {"type": "boolean"},
|
||||
"send_via_uart": {"type": "boolean"},
|
||||
"logger_level": {"$ref": "#/definitions/logger_level"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions":
|
||||
{
|
||||
"mac_address":
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9a-fA-F]{2}[:]){5}|([0-9a-fA-F]{2}){5})([0-9a-fA-F]{2})$"
|
||||
},
|
||||
"clock_frequency":
|
||||
{
|
||||
"enum":
|
||||
["100MHZ", "200MHZ", "400MHZ"]
|
||||
},
|
||||
"supported_aspm_states":
|
||||
{
|
||||
"enum":
|
||||
["ASPM_DISABLED", "ASPM_L1_ONLY", "ASPM_L0S_L1",
|
||||
"ASPM DISABLED", "ASPM L1 ONLY", "ASPM L0S L1"]
|
||||
},
|
||||
"i2c_speed":
|
||||
{
|
||||
"enum":
|
||||
["I2C_SPEED_STANDARD", "I2C_SPEED_FAST",
|
||||
"I2C SPEED STANDARD", "I2C SPEED FAST"]
|
||||
},
|
||||
"supported_aspm_l1_substates":
|
||||
{
|
||||
"enum":
|
||||
["ASPM_L1_SUBSTATES_DISABLED", "ASPM_L1_SUBSTATES_L11_ONLY", "ASPM_L1_SUBSTATES_L11_L12",
|
||||
"ASPM L1 SUBSTATES DISABLED", "ASPM L1 SUBSTATES L1.1 ONLY", "ASPM L1 SUBSTATES L1.1 L1.2"]
|
||||
},
|
||||
"watchdog_mode":
|
||||
{
|
||||
"enum":
|
||||
["WD_MODE_HW_SW", "WD_MODE_HW_ONLY",
|
||||
"WD MODE HW SW", "WD MODE HW ONLY"]
|
||||
},
|
||||
"logger_level":
|
||||
{
|
||||
"enum":
|
||||
["TRACE", "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"]
|
||||
},
|
||||
"overcurrent_parameters_source":
|
||||
{
|
||||
"enum":
|
||||
["FW_VALUES", "USER_CONFIG_VALUES",
|
||||
"BOARD_CONFIG_VALUES", "OVERCURRENT_DISABLED",
|
||||
"FW VALUES", "USER CONFIG VALUES",
|
||||
"BOARD CONFIG VALUES", "OVERCURRENT DISABLED"]
|
||||
},
|
||||
"temperature_parameters_source":
|
||||
{
|
||||
"enum":
|
||||
["FW_VALUES", "USER_CONFIG_VALUES",
|
||||
"FW VALUES", "USER CONFIG VALUES"]
|
||||
},
|
||||
"conversion_time":
|
||||
{
|
||||
"enum":
|
||||
[140, 204, 332, 588,
|
||||
1100, 2116, 4156, 8244]
|
||||
},
|
||||
"uint16_t": {"type": "integer", "minimum": 0, "maximum": 65535},
|
||||
"uint32_t": {"type": "integer", "minimum": 0, "maximum": 4294967295}
|
||||
}
|
||||
}
|
||||
70
common/include/byte_order.h
Normal file
70
common/include/byte_order.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file byte_order.h
|
||||
* @brief Defines byte order operations.
|
||||
**/
|
||||
|
||||
#ifndef __BYTE_ORDER_H__
|
||||
#define __BYTE_ORDER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__BYTE_ORDER__)
|
||||
// TODO: Check this better?
|
||||
#if defined(_MSC_VER)
|
||||
#define __ORDER_LITTLE_ENDIAN__ (1)
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#else
|
||||
#error "Unexpected byte order"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
|
||||
#define BYTE_ORDER__htonl(x) (x)
|
||||
#define BYTE_ORDER__ntohs(x) (x)
|
||||
#define BYTE_ORDER__ntohl(x) (x)
|
||||
#define BYTE_ORDER__htons(x) (x)
|
||||
#define BYTE_ORDER__ntohll(x) (x)
|
||||
#define BYTE_ORDER__htonll(x) (x)
|
||||
|
||||
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define BYTE_ORDER__htons(n) ((uint16_t)((uint16_t)((((uint16_t)(n) & 0xFF)) << 8) | (((uint16_t)(n) & 0xFF00) >> 8)))
|
||||
#define BYTE_ORDER__ntohs(n) ((uint16_t)((uint16_t)((((uint16_t)(n) & 0xFF)) << 8) | (((uint16_t)(n) & 0xFF00) >> 8)))
|
||||
|
||||
#define BYTE_ORDER__htonl(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
|
||||
((((uint32_t)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
#define BYTE_ORDER__ntohl(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
|
||||
((((uint32_t)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
#define BYTE_ORDER__htonll(n) (((uint64_t) BYTE_ORDER__htonl((n) & 0xFFFFFFFF) << 32) | \
|
||||
(uint64_t) BYTE_ORDER__htonl((n) >> 32))
|
||||
|
||||
#define BYTE_ORDER__ntohll(n) (((uint64_t) BYTE_ORDER__htonl((n) & 0xFFFFFFFF) << 32) | \
|
||||
(uint64_t) BYTE_ORDER__htonl((n) >> 32))
|
||||
|
||||
#endif
|
||||
|
||||
#define BYTE_ORDER__switch_endiannessl(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
|
||||
((((uint32_t)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BYTE_ORDER_H__ */
|
||||
300
common/include/context_switch_defs.h
Normal file
300
common/include/context_switch_defs.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file context_switch_defs.h
|
||||
* @brief Declerations of all context switch related structs.
|
||||
**/
|
||||
|
||||
#ifndef __CONTEXT_SWITCH_DEFS__
|
||||
#define __CONTEXT_SWITCH_DEFS__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "control_protocol.h"
|
||||
|
||||
/**********************************************************************
|
||||
* Defines
|
||||
**********************************************************************/
|
||||
|
||||
#define CONTEXT_SWITCH_DEFS__TIMESTAMP_INIT_VALUE (0xFFFFFFFF)
|
||||
#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_ADDRESS (1)
|
||||
#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT (2)
|
||||
#define CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_BATCH_SIZE (1)
|
||||
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_SHIFT (0)
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_WIDTH (4)
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_MASK (0x0f)
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_READ(src) \
|
||||
(((uint8_t)(src) & CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_MASK) >> CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_SHIFT)
|
||||
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_SHIFT (CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_WIDTH)
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_MASK (0x70)
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_READ(src) \
|
||||
(((uint8_t)(src) & CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_MASK) >> CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_SHIFT)
|
||||
|
||||
#define CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_SET(dst, cluster_index, lcu_index) \
|
||||
(dst) = (((lcu_index) << CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_SHIFT) & CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_MASK) | \
|
||||
(((cluster_index) << CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_SHIFT) & CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_MASK)
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint16_t core_bytes_per_buffer;
|
||||
uint16_t core_buffers_per_frame;
|
||||
uint16_t periph_bytes_per_buffer;
|
||||
uint16_t periph_buffers_per_frame;
|
||||
uint16_t feature_padding_payload;
|
||||
uint16_t buffer_padding_payload;
|
||||
uint16_t buffer_padding;
|
||||
} CONTEXT_SWITCH_DEFS__stream_reg_info_t;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
typedef enum : uint8_t {
|
||||
#else
|
||||
typedef enum __attribute__((packed)) {
|
||||
#endif
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS = 0,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_NON_DEFAULT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_DISABLE_LCU,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_INPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_OUTPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_INPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_OUTPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_INPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_OUTPUT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_VDMA_CHANNEL,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_CHANGE_VDMA_TO_STREAM_MAPPING,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ADD_DDR_PAIR_INFO,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_START,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_LCU_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_SEQUENCER_DONE_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_INPUT_CHANNEL_TRANSFER_DONE_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_OUTPUT_CHANNEL_TRANSFER_DONE_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_MODULE_CONFIG_DONE_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_APPLICATION_CHANGE_INTERRUPT,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_CFG_CHANNEL,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS,
|
||||
|
||||
/* Must be last */
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT
|
||||
} CONTEXT_SWITCH_DEFS__ACTION_TYPE_t;
|
||||
|
||||
typedef struct {
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type;
|
||||
uint32_t time_stamp;
|
||||
} CONTEXT_SWITCH_DEFS__common_action_header_t;
|
||||
|
||||
/**
|
||||
* The layout of a repeated action in the action_list will be as follows:
|
||||
* 1) CONTEXT_SWITCH_DEFS__common_action_header_t with 'action_type' CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION
|
||||
* 2) CONTEXT_SWITCH_DEFS__repeated_action_header_t
|
||||
* 3) 'count' sub-actions whose type matches the 'sub_action_type' defined by (1).
|
||||
* The sub-actions will be consecutive, and won't have 'CONTEXT_SWITCH_DEFS__common_action_header_t's
|
||||
*
|
||||
* E.g - 3 repeated 'CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t's:
|
||||
* |-------------------------------------------------------------------------------------------------------|
|
||||
* | action_list | data |
|
||||
* |-------------------------------------------------------------------------------------------------------|
|
||||
* | ... | |
|
||||
* | | | CONTEXT_SWITCH_DEFS__common_action_header_t { |
|
||||
* | | | .action_type = CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION; |
|
||||
* | | | .time_stamp = <time_of_last_executed_action_in_repeated>; |
|
||||
* | | | } |
|
||||
* | | | CONTEXT_SWITCH_DEFS__repeated_action_header_t { |
|
||||
* | | | .count = 3; |
|
||||
* | | | .last_executed = <last_action_executed_in_repeated>; |
|
||||
* | | | .sub_action_type = CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT; |
|
||||
* | | | } |
|
||||
* | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
|
||||
* | | | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
|
||||
* | V | CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t { .packed_lcu_id=<some_lcu_id>; } |
|
||||
* | ... | (Next action starting with CONTEXT_SWITCH_DEFS__common_action_header_t) |
|
||||
* |-------------------------------------------------------------------------------------------------------|
|
||||
* See also: "CONTROL_PROTOCOL__REPEATED_ACTION_t" in "control_protocol.h"
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count;
|
||||
uint8_t last_executed;
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t sub_action_type;
|
||||
} CONTEXT_SWITCH_DEFS__repeated_action_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t descriptors_count;
|
||||
uint8_t cfg_channel_number;
|
||||
} CONTEXT_SWITCH_DEFS__read_vdma_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t ccw_bursts;
|
||||
uint8_t cfg_channel_number;
|
||||
} CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t cluster_index;
|
||||
CONTORL_PROTOCOL__sequencer_config_t sequencer_config;
|
||||
} CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t packed_lcu_id;
|
||||
uint16_t kernel_done_address;
|
||||
uint32_t kernel_done_count;
|
||||
} CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t;
|
||||
|
||||
/* Default action - kernel_done_address and kernel_done_count has default values */
|
||||
typedef struct {
|
||||
uint8_t packed_lcu_id;
|
||||
} CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t packed_lcu_id;
|
||||
} CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t vdma_channel_index;
|
||||
uint8_t edge_layer_direction;
|
||||
bool is_inter_context;
|
||||
} CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t vdma_channel_index;
|
||||
uint8_t stream_index;
|
||||
uint32_t channel_credits;
|
||||
uint8_t credit_type;
|
||||
uint16_t periph_bytes_per_buffer;
|
||||
} CONTEXT_SWITCH_DEFS__fetch_data_action_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t vdma_channel_index;
|
||||
uint8_t stream_index;
|
||||
bool is_dummy_stream;
|
||||
} CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t h2d_vdma_channel_index;
|
||||
uint8_t d2h_vdma_channel_index;
|
||||
uint32_t descriptors_per_batch;
|
||||
uint16_t programmed_descriptors_count;
|
||||
} CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t;
|
||||
|
||||
/* wait for interrupt structs */
|
||||
typedef struct {
|
||||
uint8_t packed_lcu_id;
|
||||
} CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t vdma_channel_index;
|
||||
} CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sequencer_index;
|
||||
} CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t aggregator_index;
|
||||
uint8_t pred_cluster_ob_index;
|
||||
uint8_t pred_cluster_ob_cluster_index;
|
||||
uint8_t pred_cluster_ob_interface;
|
||||
uint8_t succ_prepost_ob_index;
|
||||
uint8_t succ_prepost_ob_interface;
|
||||
} CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t vdma_channel_index;
|
||||
uint8_t stream_index;
|
||||
bool is_inter_context;
|
||||
} CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t module_index;
|
||||
} CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t application_index;
|
||||
} CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t;
|
||||
|
||||
/* edge layers structs */
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
bool is_single_context_app;
|
||||
} CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
uint64_t host_descriptors_base_address;
|
||||
uint16_t initial_host_available_descriptors;
|
||||
uint8_t desc_list_depth;
|
||||
} CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
uint64_t host_descriptors_base_address;
|
||||
uint16_t initial_host_available_descriptors;
|
||||
uint8_t desc_list_depth;
|
||||
bool fw_managed_channel;
|
||||
} CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
uint32_t frame_credits_in_bytes;
|
||||
uint16_t desc_page_size;
|
||||
} CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
// TODO: add this to CONTEXT_SWITCH_DEFS__stream_reg_info_t
|
||||
uint32_t frame_credits_in_bytes;
|
||||
uint64_t host_descriptors_base_address;
|
||||
uint16_t initial_host_available_descriptors;
|
||||
uint16_t desc_page_size;
|
||||
uint8_t desc_list_depth;
|
||||
} CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t stream_index;
|
||||
uint8_t vdma_channel_index;
|
||||
CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info;
|
||||
uint32_t frame_credits_in_bytes;
|
||||
uint64_t host_descriptors_base_address;
|
||||
uint16_t initial_host_available_descriptors;
|
||||
uint16_t desc_page_size;
|
||||
uint8_t desc_list_depth;
|
||||
bool fw_managed_channel;
|
||||
} CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t channel_index;
|
||||
uint64_t host_descriptors_base_address;
|
||||
uint16_t initial_host_available_descriptors;
|
||||
} CONTEXT_SWITCH_DEFS__activate_cfg_channel_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t channel_index;
|
||||
} CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CONTEXT_SWITCH_DEFS__ */
|
||||
1735
common/include/control_protocol.h
Normal file
1735
common/include/control_protocol.h
Normal file
File diff suppressed because it is too large
Load Diff
167
common/include/d2h_events.h
Normal file
167
common/include/d2h_events.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file d2h_events.h
|
||||
* @brief Declares all d2h event manager structures relevant in the host.
|
||||
**/
|
||||
|
||||
#ifndef __D2H_EVENTS_H__
|
||||
#define __D2H_EVENTS_H__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "status.h"
|
||||
#include "stdfloat.h"
|
||||
|
||||
/**
|
||||
* @brief The d2h event manager structures relevant in the host
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
D2H_EVENT_PRIORITY_INFO = 0,
|
||||
D2H_EVENT_PRIORITY_CRITICAL,
|
||||
|
||||
/* Must be last */
|
||||
D2H_EVENT_PRIORITY_COUNT
|
||||
} D2H_EVENT_PRIORITY_t;
|
||||
|
||||
typedef enum {
|
||||
D2H_EVENT_COMMUNICATION_TYPE_UDP = 0,
|
||||
D2H_EVENT_COMMUNICATION_TYPE_PCIE,
|
||||
D2H_EVENT_COMMUNICATION_TYPE__COUNT
|
||||
} D2H_EVENT_COMMUNICATION_TYPE_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t sequence;
|
||||
uint32_t priority;
|
||||
uint32_t module_id;
|
||||
uint32_t event_id;
|
||||
uint32_t parameter_count;
|
||||
uint32_t payload_length;
|
||||
} D2H_EVENT_HEADER_t;
|
||||
|
||||
/* D2H_EVENT_ID_t Should be in the same order as the structs in D2H_EVENT__message_parameters_t union, since the host will parse according to this enum */
|
||||
/* For example ETHERNET_SERVICE_RX_ERROR_EVENT_ID is 0, so D2H_EVENT_rx_error_event_message_t is the first struct in D2H_EVENT__message_parameters_t */
|
||||
typedef enum {
|
||||
ETHERNET_SERVICE_RX_ERROR_EVENT_ID = 0,
|
||||
D2H_HOST_INFO_EVENT_ID,
|
||||
HEALTH_MONITOR_TEMPERATURE_ALARM_D2H_EVENT_ID,
|
||||
HEALTH_MONITOR_CLOSED_STREAMS_D2H_EVENT_ID,
|
||||
HEALTH_MONITOR_OVERCURRENT_PROTECTION_ALERT_EVENT_ID,
|
||||
HEALTH_MONITOR_LCU_ECC_CORRECTABLE_EVENT_ID,
|
||||
HEALTH_MONITOR_LCU_ECC_UNCORRECTABLE_EVENT_ID,
|
||||
HEALTH_MONITOR_CPU_ECC_ERROR_EVENT_ID,
|
||||
HEALTH_MONITOR_CPU_ECC_FATAL_EVENT_ID,
|
||||
CONTEXT_SWITCH_BREAKPOINT_REACHED,
|
||||
HEALTH_MONITOR_CLOCK_CHANGED_EVENT_ID,
|
||||
D2H_EVENT_ID_COUNT /* Must be last*/
|
||||
} D2H_EVENT_ID_t;
|
||||
|
||||
/* D2H_EVENT_rx_error_event_message_t should be the same as hailo_rx_error_notification_message_t */
|
||||
typedef struct {
|
||||
uint32_t error;
|
||||
uint32_t queue_number;
|
||||
uint32_t rx_errors_count;
|
||||
} D2H_EVENT_rx_error_event_message_t;
|
||||
#define D2H_EVENT_RX_ERROR_EVENT_PARAMETER_COUNT (3)
|
||||
|
||||
/* D2H_EVENT_host_info_event_message_t should be the same as hailo_debug_notification_message_t */
|
||||
typedef struct {
|
||||
uint32_t connection_status;
|
||||
uint32_t connection_type;
|
||||
uint32_t pcie_is_active;
|
||||
uint32_t host_port;
|
||||
uint32_t host_ip_addr;
|
||||
} D2H_EVENT_host_info_event_message_t;
|
||||
#define D2H_EVENT_HOST_INFO_EVENT_PARAMETER_COUNT (5)
|
||||
|
||||
/* D2H_EVENT_health_monitor_closed_streams_event_message_t should be the same as hailo_health_monitor_dataflow_shutdown_notification_message_t */
|
||||
typedef struct {
|
||||
uint32_t closed_input_streams;
|
||||
uint32_t closed_output_streams;
|
||||
float32_t ts0_temperature;
|
||||
float32_t ts1_temperature;
|
||||
} D2H_EVENT_health_monitor_closed_streams_event_message_t;
|
||||
|
||||
#define D2H_EVENT_HEALTH_MONITOR_CLOSED_STREAMS_EVENT_PARAMETER_COUNT (4)
|
||||
|
||||
/* D2H_EVENT_health_monitor_temperature_alarm_event_message_t should be the same as hailo_health_monitor_temperature_alarm_notification_message_t */
|
||||
typedef struct {
|
||||
uint32_t temperature_zone;
|
||||
uint32_t alarm_ts_id;
|
||||
float32_t ts0_temperature;
|
||||
float32_t ts1_temperature;
|
||||
} D2H_EVENT_health_monitor_temperature_alarm_event_message_t;
|
||||
|
||||
#define D2H_EVENT_HEALTH_MONITOR_TEMPERATURE_ALARM_EVENT_PARAMETER_COUNT (4)
|
||||
|
||||
/* D2H_EVENT_health_monitor_overcurrent_alert_event_message_t should be the same as hailo_health_monitor_overcurrent_alert_notification_message_t */
|
||||
typedef struct {
|
||||
uint32_t overcurrent_zone;
|
||||
float32_t exceeded_alert_threshold;
|
||||
float32_t sampled_current_during_alert;
|
||||
} D2H_EVENT_health_monitor_overcurrent_alert_event_message_t;
|
||||
|
||||
#define D2H_EVENT_HEALTH_MONITOR_OVERCURRENT_ALERT_EVENT_PARAMETER_COUNT (2)
|
||||
|
||||
/* D2H_EVENT_health_monitor_lcu_ecc_error_event_message_t should be the same as hailo_health_monitor_lcu_ecc_error_notification_message_t */
|
||||
typedef struct {
|
||||
uint16_t cluster_bitmap;
|
||||
} D2H_EVENT_health_monitor_lcu_ecc_error_event_message_t;
|
||||
|
||||
/* D2H_EVENT_health_monitor_cpu_ecc_event_message_t should be the same as hailo_health_monitor_cpu_ecc_error_notification_message_t */
|
||||
#define D2H_EVENT_HEALTH_MONITOR_LCU_ECC_ERROR_EVENT_PARAMETER_COUNT (1)
|
||||
typedef struct {
|
||||
uint32_t memory_bitmap;
|
||||
} D2H_EVENT_health_monitor_cpu_ecc_event_message_t;
|
||||
|
||||
#define D2H_EVENT_HEALTH_MONITOR_CPU_ECC_EVENT_PARAMETER_COUNT (1)
|
||||
|
||||
/* D2H_EVENT_context_switch_breakpoint_reached_event_massage_t should be the same as
|
||||
* CONTROL_PROTOCOL__context_switch_breakpoint_data_t and hailo_context_switch_breakpoint_reached_notification_message_t */
|
||||
typedef struct {
|
||||
uint8_t application_index;
|
||||
uint16_t batch_index;
|
||||
uint8_t context_index;
|
||||
uint16_t action_index;
|
||||
} D2H_EVENT_context_switch_breakpoint_reached_event_massage_t;
|
||||
|
||||
#define D2H_EVENT_CONTEXT_SWITCH_BREAKPOINT_REACHED_EVENT_PARAMETER_COUNT (4)
|
||||
|
||||
typedef struct {
|
||||
uint32_t previous_clock;
|
||||
uint32_t current_clock;
|
||||
} D2H_EVENT_health_monitor_clock_changed_event_message_t;
|
||||
|
||||
#define D2H_EVENT_HEALTH_MONITOR_CLOCK_CHANGED_EVENT_PARAMETER_COUNT (2)
|
||||
|
||||
/* D2H_EVENT__message_parameters_t should be in the same order as hailo_notification_message_parameters_t */
|
||||
typedef union {
|
||||
D2H_EVENT_rx_error_event_message_t rx_error_event;
|
||||
D2H_EVENT_host_info_event_message_t host_info_event;
|
||||
D2H_EVENT_health_monitor_closed_streams_event_message_t health_monitor_closed_streams_event;
|
||||
D2H_EVENT_health_monitor_temperature_alarm_event_message_t health_monitor_temperature_alarm_event;
|
||||
D2H_EVENT_health_monitor_overcurrent_alert_event_message_t health_monitor_overcurrent_alert_event;
|
||||
D2H_EVENT_health_monitor_lcu_ecc_error_event_message_t health_monitor_lcu_ecc_error_event;
|
||||
D2H_EVENT_health_monitor_cpu_ecc_event_message_t health_monitor_cpu_ecc_event;
|
||||
D2H_EVENT_context_switch_breakpoint_reached_event_massage_t context_switch_breakpoint_reached_event;
|
||||
D2H_EVENT_health_monitor_clock_changed_event_message_t health_monitor_clock_changed_event;
|
||||
} D2H_EVENT__message_parameters_t;
|
||||
|
||||
typedef struct {
|
||||
D2H_EVENT_HEADER_t header;
|
||||
D2H_EVENT__message_parameters_t message_parameters;
|
||||
} D2H_EVENT_MESSAGE_t;
|
||||
|
||||
#define PCIE_D2H_EVENT_MAX_SIZE (0x370)
|
||||
/**********************************************************************
|
||||
* Public Functions
|
||||
**********************************************************************/
|
||||
HAILO_COMMON_STATUS_t D2H_EVENTS__parse_event(D2H_EVENT_MESSAGE_t *d2h_event_message);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __D2H_EVENTS_H__ */
|
||||
85
common/include/firmware_header.h
Normal file
85
common/include/firmware_header.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file firmware_header.h
|
||||
* @brief Contains definitions needed for generating and handling a firmware header.
|
||||
**/
|
||||
|
||||
#ifndef __FIRMWARE_HEADER__
|
||||
#define __FIRMWARE_HEADER__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "utils.h"
|
||||
|
||||
#define FIRMWARE_HEADER_MAGIC_HAILO8 (0x1DD89DE0)
|
||||
#define FIRMWARE_HEADER_MAGIC_MERCURY (0xE905DAAB)
|
||||
|
||||
typedef enum {
|
||||
FIRMWARE_HEADER_VERSION_INITIAL = 0,
|
||||
|
||||
/* MUST BE LAST */
|
||||
FIRMWARE_HEADER_VERSION_COUNT
|
||||
} firmware_header_version_t;
|
||||
|
||||
typedef enum {
|
||||
FIRMWARE_TYPE_HAILO8 = 0,
|
||||
FIRMWARE_TYPE_MERCURY
|
||||
} firmware_type_t;
|
||||
|
||||
|
||||
#ifdef MERCURY
|
||||
#define COMPILED_FIRMWARE_TYPE (FIRMWARE_TYPE_MERCURY)
|
||||
#elif defined(HAILO8_B0)
|
||||
#define COMPILED_FIRMWARE_TYPE (FIRMWARE_TYPE_HAILO8)
|
||||
#endif /* MERCURY */
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t header_version;
|
||||
uint32_t firmware_major;
|
||||
uint32_t firmware_minor;
|
||||
uint32_t firmware_revision;
|
||||
uint32_t code_size;
|
||||
} firmware_header_t;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// TODO: warning C4200
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200)
|
||||
#endif
|
||||
typedef struct {
|
||||
uint32_t key_size;
|
||||
uint32_t content_size;
|
||||
uint8_t certificates_data[0];
|
||||
} secure_boot_certificate_t;
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#define MINIMUM_FIRMWARE_CODE_SIZE (20*4)
|
||||
// Tightly coupled with ld script
|
||||
#define MAXIMUM_APP_FIRMWARE_CODE_SIZE (0x40000)
|
||||
#define MAXIMUM_CORE_FIRMWARE_CODE_SIZE (0x18000)
|
||||
#define MAXIMUM_SECOND_STAGE_CODE_SIZE (0x80000)
|
||||
#define MAXIMUM_FIRMWARE_CERT_KEY_SIZE (0x1000)
|
||||
#define MAXIMUM_FIRMWARE_CERT_CONTENT_SIZE (0x1000)
|
||||
|
||||
typedef enum {
|
||||
FW_BINARY_TYPE_INVALID = 0,
|
||||
FW_BINARY_TYPE_APP_FIRMWARE,
|
||||
FW_BINARY_TYPE_CORE_FIRMWARE,
|
||||
FW_BINARY_TYPE_SECOND_STAGE_BOOT
|
||||
} FW_BINARY_TYPE_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FIRMWARE_HEADER__ */
|
||||
109
common/include/firmware_header_utils.h
Normal file
109
common/include/firmware_header_utils.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file firmware_header_utils.h
|
||||
* @brief Utilities for working with the firmware header.
|
||||
**/
|
||||
|
||||
#ifndef __FIRMWARE_HEADER_UTILS__
|
||||
#define __FIRMWARE_HEADER_UTILS__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "status.h"
|
||||
#include "firmware_header.h"
|
||||
#include "firmware_version.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define REVISION_NUMBER_SHIFT (0)
|
||||
#define REVISION_APP_CORE_FLAG_BIT_SHIFT (27)
|
||||
#define REVISION_RESERVED_0_FLAG_BIT_SHIFT (28)
|
||||
#define REVISION_RESERVED_1_FLAG_BIT_SHIFT (29)
|
||||
#define REVISION_DEV_FLAG_BIT_SHIFT (30)
|
||||
#define REVISION_SECOND_STAGE_FLAG_BIT_SHIFT (31)
|
||||
|
||||
#define REVISION_NUMBER_WIDTH (27U)
|
||||
#define REVISION_APP_CORE_FLAG_BIT_WIDTH (1U)
|
||||
#define REVISION_RESERVED_0_FLAG_BIT_WIDTH (1U)
|
||||
#define REVISION_RESERVED_1_FLAG_BIT_WIDTH (1U)
|
||||
#define REVISION_DEV_FLAG_BIT_WIDTH (1U)
|
||||
#define REVISION_SECOND_STAGE_FLAG_BIT_WIDTH (1U)
|
||||
|
||||
#define REVISION_NUMBER_MASK (GET_MASK(REVISION_NUMBER_WIDTH, REVISION_NUMBER_SHIFT))
|
||||
#define REVISION_APP_CORE_FLAG_BIT_MASK (GET_MASK(REVISION_APP_CORE_FLAG_BIT_WIDTH, REVISION_APP_CORE_FLAG_BIT_SHIFT))
|
||||
#define REVISION_RESERVED_0_FLAG_BIT_MASK (GET_MASK(REVISION_RESERVED_0_FLAG_BIT_WIDTH, REVISION_RESERVED_0_FLAG_BIT_SHIFT))
|
||||
#define REVISION_RESERVED_1_FLAG_BIT_MASK (GET_MASK(REVISION_RESERVED_1_FLAG_BIT_WIDTH, REVISION_RESERVED_1_FLAG_BIT_SHIFT))
|
||||
#define REVISION_DEV_FLAG_BIT_MASK (GET_MASK(REVISION_DEV_FLAG_BIT_WIDTH, REVISION_DEV_FLAG_BIT_SHIFT))
|
||||
#define REVISION_SECOND_STAGE_FLAG_BIT_MASK (GET_MASK(REVISION_SECOND_STAGE_FLAG_BIT_WIDTH, REVISION_SECOND_STAGE_FLAG_BIT_SHIFT))
|
||||
|
||||
#define GET_REVISION_NUMBER_VALUE(binary_revision) (REVISION_NUMBER_MASK & binary_revision)
|
||||
#define IS_REVISION_DEV(binary_revision) (REVISION_DEV_FLAG_BIT_MASK == (REVISION_DEV_FLAG_BIT_MASK & binary_revision))
|
||||
#define DEV_STRING_NOTE(__is_release) ((__is_release)? "" : " (dev)")
|
||||
|
||||
/**
|
||||
* Validates the FW headers.
|
||||
* this function is used from the firmware, from HailoRT and from the second_stage bootloader to validate the headers.
|
||||
* @param[in] address Address of the firmware.
|
||||
* @param[in] firmware_size Size of the firmware.
|
||||
* If the actual size is unknown, set this to the maximum possible size (for example the size of the Flash
|
||||
* section holding the FW).
|
||||
* @param[in] is_firmware_size_unknown Set to true if the firmware size is unknown (for example when loading from Flash).
|
||||
* @param[out] out_app_firmware_header (optional) App firmware header
|
||||
* @param[out] out_core_firmware_header (optional) Core firmware header
|
||||
* @param[out] out_firmware_cert (optional) Firmware certificate header
|
||||
*/
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_fw_headers(uintptr_t firmware_base_address,
|
||||
uint32_t firmware_size,
|
||||
bool is_firmware_size_unknown,
|
||||
firmware_header_t **out_app_firmware_header,
|
||||
firmware_header_t **out_core_firmware_header,
|
||||
secure_boot_certificate_t **out_firmware_cert,
|
||||
firmware_type_t firmware_type);
|
||||
/**
|
||||
* Validates the Second stage headers.
|
||||
* this function is used from the firmware and from HailoRT to validate the headers.
|
||||
* @param[in] address Address of the second stage.
|
||||
* @param[in] second_stage_size Size of the second_stage.
|
||||
* If the actual size is unknown, set this to the maximum possible size (for example the size of the Flash
|
||||
* section holding the Second stage).
|
||||
* @param[out] out_second_stage_header (optional) second_stage header
|
||||
*/
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_second_stage_headers(uintptr_t second_stage_base_size,
|
||||
uint32_t second_stage_size,
|
||||
firmware_header_t **out_second_stage_header,
|
||||
firmware_type_t firmware_type);
|
||||
|
||||
/**
|
||||
* Returns the binary type (App firmware, Core firmware or Second Stage boot)
|
||||
* @param[in] binary_revision The binary revision (Third part in binary version)
|
||||
*/
|
||||
FW_BINARY_TYPE_t FIRMWARE_HEADER_UTILS__get_fw_binary_type(uint32_t binary_revision);
|
||||
|
||||
/**
|
||||
* Returns true if the new binary version is older then the minumum allowed.
|
||||
* @param[in] new_binary_version A pointer to the new binary version to update to
|
||||
* @param[in] minimum_allowed_binary_version A pointer to the minimum binary version that is allowed to be upgraded to
|
||||
*/
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__is_binary_being_downgraded(const firmware_version_t *new_binary_version,
|
||||
const firmware_version_t *minimum_allowed_binary_version);
|
||||
|
||||
/**
|
||||
* Validates the binary version to prevent downgrade.
|
||||
* this function is used from the firmware and from HailoRT to prevent downgrade.
|
||||
* @param[in] new_binary_version A pointer to the new binary version to update to
|
||||
* @param[in] minimum_allowed_binary_version A pointer to the minimum binary version that is allowed to be upgraded to
|
||||
* @param[in] fw_binary_type A bit that indicates which binary type is passed (app firmware, core firmware, second stage boot)
|
||||
*/
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_binary_version(const firmware_version_t *new_binary_version,
|
||||
const firmware_version_t *minimum_allowed_binary_version,
|
||||
FW_BINARY_TYPE_t fw_binary_type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FIRMWARE_HEADER_UTILS__ */
|
||||
1025
common/include/firmware_status.h
Normal file
1025
common/include/firmware_status.h
Normal file
File diff suppressed because it is too large
Load Diff
25
common/include/firmware_version.h
Normal file
25
common/include/firmware_version.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file firmware_version.h
|
||||
* @brief Contains information regarding the firmware version.
|
||||
**/
|
||||
|
||||
#ifndef __FIRMWARE_VERSION__
|
||||
#define __FIRMWARE_VERSION__
|
||||
#include <stdint.h>
|
||||
typedef struct {
|
||||
uint32_t firmware_major;
|
||||
uint32_t firmware_minor;
|
||||
uint32_t firmware_revision;
|
||||
} firmware_version_t;
|
||||
|
||||
#define PACK_FW_VERSION(major, minor, revision) {(major), (minor), (revision)}
|
||||
#define MINIMUM_SECURED_FW_VERSION (firmware_version_t)PACK_FW_VERSION(2, 6, 0)
|
||||
|
||||
const firmware_version_t* FIRMWARE_VERSION__get_version(void);
|
||||
|
||||
|
||||
#endif /* __FIRMWARE_VERSION__ */
|
||||
22
common/include/logger_level.h
Normal file
22
common/include/logger_level.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file logger_level.h
|
||||
* @brief Contains the possible logger level information.
|
||||
**/
|
||||
|
||||
#ifndef __LOGGER_LEVEL__
|
||||
#define __LOGGER_LEVEL__
|
||||
|
||||
typedef enum {
|
||||
FW_LOGGER_LEVEL_TRACE = 0,
|
||||
FW_LOGGER_LEVEL_DEBUG,
|
||||
FW_LOGGER_LEVEL_INFO,
|
||||
FW_LOGGER_LEVEL_WARN,
|
||||
FW_LOGGER_LEVEL_ERROR,
|
||||
FW_LOGGER_LEVEL_FATAL
|
||||
} FW_LOGGER_LEVEL_t;
|
||||
|
||||
#endif //__LOGGER_LEVEL__
|
||||
49
common/include/md5.h
Normal file
49
common/include/md5.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See md5.c for more information.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/md5.h>
|
||||
#elif !defined(_MD5_H)
|
||||
#define _MD5_H
|
||||
|
||||
/** Start of modifications for the open source file. **/
|
||||
#include "stdint.h"
|
||||
typedef uint8_t MD5_SUM_t[16];
|
||||
/* Any 32-bit or wider unsigned integer data type will do */
|
||||
typedef size_t MD5_u32plus;
|
||||
/** End of modifications. **/
|
||||
|
||||
typedef struct {
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
extern void MD5_Init(MD5_CTX *ctx);
|
||||
extern void MD5_Update(MD5_CTX *ctx, const void *data, size_t size);
|
||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
|
||||
#endif
|
||||
68
common/include/sensor_config_exports.h
Normal file
68
common/include/sensor_config_exports.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file sensor_config_exports.h
|
||||
* @brief Sensor config exported defines.
|
||||
**/
|
||||
|
||||
#ifndef __SENSOR_CONFIG_EXPORT__
|
||||
#define __SENSOR_CONFIG_EXPORT__
|
||||
|
||||
|
||||
#define MAX_CONFIG_NAME_LEN 100
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t operation;
|
||||
uint8_t length; //how many bits of the register
|
||||
uint8_t page; //If SOC is limited to 8 bit addressing, or some array imager.
|
||||
uint32_t address;
|
||||
uint32_t bitmask;
|
||||
uint32_t value; //8/16/32-bit register value
|
||||
} SENSOR_CONFIG__operation_cfg_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
uint32_t sensor_type;
|
||||
uint32_t config_size;
|
||||
uint16_t reset_config_size;
|
||||
uint8_t is_free;
|
||||
uint8_t no_reset_offset;
|
||||
uint16_t config_height;
|
||||
uint16_t config_width;
|
||||
uint16_t config_fps;
|
||||
uint16_t section_version;
|
||||
uint8_t config_name[MAX_CONFIG_NAME_LEN];
|
||||
} SENSOR_CONFIG__section_info_t;
|
||||
|
||||
typedef enum {
|
||||
SENSOR_CONFIG_OPCODES_WR = 0,
|
||||
SENSOR_CONFIG_OPCODES_RD,
|
||||
SENSOR_CONFIG_OPCODES_RMW,
|
||||
SENSOR_CONFIG_OPCODES_DELAY,
|
||||
} SENSOR_CONFIG_OPCODES_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bus_index;
|
||||
uint16_t slave_address;
|
||||
uint8_t register_address_size;
|
||||
bool should_hold_bus;
|
||||
uint8_t endianness;
|
||||
} SENSOR_I2C_SLAVE_INFO_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_SLAVE_ENDIANNESS_BIG_ENDIAN = 0,
|
||||
I2C_SLAVE_ENDIANNESS_LITTLE_ENDIAN = 1,
|
||||
|
||||
I2C_SLAVE_ENDIANNESS_COUNT
|
||||
} i2c_slave_endianness_t;
|
||||
|
||||
#define SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT (8)
|
||||
#define SENSOR_CONFIG__SENSOR_SECTION_BLOCK_COUNT (7)
|
||||
#define SENSOR_CONFIG__ISP_SECTIONS_BLOCK_COUNT (SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT - SENSOR_CONFIG__SENSOR_SECTION_BLOCK_COUNT)
|
||||
#define SENSOR_CONFIG__ISP_SECTION_INDEX (SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT - SENSOR_CONFIG__ISP_SECTIONS_BLOCK_COUNT)
|
||||
#define SENSOR_SECTIONS_INFO_SIZE (SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT * sizeof(SENSOR_CONFIG__section_info_t))
|
||||
|
||||
#endif /* __SENSOR_CONFIG_EXPORT__ */
|
||||
61
common/include/status.h
Normal file
61
common/include/status.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file status.h
|
||||
* @brief Declares status enum for hailo c platform.
|
||||
**/
|
||||
|
||||
#ifndef __STATUS_H__
|
||||
#define __STATUS_H__
|
||||
|
||||
/**
|
||||
* @brief The enumeration of all status codes.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
/* global statuses */
|
||||
HAILO_COMMON_STATUS__SUCCESS = 0,
|
||||
HAILO_COMMON_STATUS__UNINITIALIZED,
|
||||
|
||||
/* Control protocol module errors */
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__OVERRUN_BEFORE_PARAMETER = 0x1000,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__NULL_ARGUMENT_PASSED,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__OVERRUN_AT_PARAMETER,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__UNEXPECTED_ACK_VALUE,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__INVALID_VERSION,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__PART_OF_THE_MESSAGE_NOT_PARSED,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__INVALID_BUFFER_SIZE,
|
||||
HAILO_STATUS__CONTROL_PROTOCOL__INVALID_ARGUMENT,
|
||||
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__CERT_TOO_LARGE = 0x2000,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_HEADER_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INCORRECT_FIRMWARE_HEADER_MAGIC,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__UNSUPPORTED_FIRMWARE__HEADER_VERSION,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__CODE_SIZE_BELOW_MINIMUM,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__CODE_OVERRUNS_RAM_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_CODE_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_HEADER_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_KEY_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_CONTENT_SIZE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_HEADER,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_CERTIFICATE_HEADER,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CORE_CPU_FIRMWARE_HEADER,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CORE_CPU_FIRMWARE_CERTIFICATE_HEADER,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__LEFTOVER_DATA_AFTER_LAST_FIRMWARE_HEADER,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__DETECTED_PROHIBITED_DOWNGRADE_ATTEMPT,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_BINARY_TYPE,
|
||||
HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_TYPE,
|
||||
|
||||
HAILO_STATUS__D2H_EVENTS__INCORRECT_PARAMETER_COUNT = 0x3000,
|
||||
HAILO_STATUS__D2H_EVENTS__INCORRECT_PARAMETER_LENGTH,
|
||||
HAILO_STATUS__D2H_EVENTS__INVALID_ARGUMENT,
|
||||
|
||||
HAILO_STATUS__FIRMWARE_STATUS__NULL_ARGUMENT_PASSED = 0x4000,
|
||||
HAILO_STATUS__FIRMWARE_STATUS__INVALID_COMPONENT_ID,
|
||||
HAILO_STATUS__FIRMWARE_STATUS__INVALID_MODULE_ID,
|
||||
HAILO_STATUS__FIRMWARE_STATUS__INVALID_STATUS_VALUE,
|
||||
} HAILO_COMMON_STATUS_t;
|
||||
|
||||
#endif /* __STATUS_H__ */
|
||||
16
common/include/stdfloat.h
Normal file
16
common/include/stdfloat.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file stdfloat.h
|
||||
* @brief Defines fixed-size float types.
|
||||
**/
|
||||
|
||||
#ifndef _STDFLOAT_H
|
||||
#define _STDFLOAT_H
|
||||
|
||||
typedef float float32_t;
|
||||
typedef double float64_t;
|
||||
|
||||
#endif /* _STDFLOAT_H */
|
||||
101
common/include/user_config_common.h
Normal file
101
common/include/user_config_common.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file user_config_common.h
|
||||
* @brief Contains information regarding the firmware user config.
|
||||
**/
|
||||
|
||||
#ifndef __USER_CONFIG_COMMON__
|
||||
#define __USER_CONFIG_COMMON__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "logger_level.h"
|
||||
|
||||
#define USER_CONFIG_OVERCURRENT_UNINITIALIZED_VALUE (0)
|
||||
|
||||
#define USER_CONFIG_TEMPERATURE_DEFAULT_RED_ALARM_THRESHOLD (120.f)
|
||||
#define USER_CONFIG_TEMPERATURE_DEFAULT_RED_HYSTERESIS_ALARM_THRESHOLD (116.f)
|
||||
#define USER_CONFIG_TEMPERATURE_DEFAULT_ORANGE_ALARM_THRESHOLD (104.f)
|
||||
#define USER_CONFIG_TEMPERATURE_DEFAULT_ORANGE_HYSTERESIS_ALARM_THRESHOLD (99.f)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200)
|
||||
#endif
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t entry_count;
|
||||
uint8_t entries[0];
|
||||
} USER_CONFIG_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t category;
|
||||
uint16_t entry_id;
|
||||
uint32_t entry_size;
|
||||
uint8_t value[0];
|
||||
} USER_CONFIG_ENTRY_t;
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#pragma pack(pop)
|
||||
|
||||
// Used by user config defaults
|
||||
typedef enum {
|
||||
ASPM_DISABLED = 0,
|
||||
ASPM_L1_ONLY,
|
||||
ASPM_L0S_L1
|
||||
} PCIE_CONFIG_SUPPOPRTED_ASPM_STATES_t;
|
||||
|
||||
typedef enum {
|
||||
ASPM_L1_SUBSTATES_DISABLED = 0,
|
||||
ASPM_L1_SUBSTATES_L11_ONLY,
|
||||
ASPM_L1_SUBSTATES_L11_L12
|
||||
} PCIE_CONFIG_SUPPOPRTED_L1_ASPM_SUBSTATES_t;
|
||||
|
||||
typedef enum {
|
||||
SOC__NN_CLOCK_400MHz = 400 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_375MHz = 375 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_350MHz = 350 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_325MHz = 325 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_300MHz = 300 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_275MHz = 275 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_250MHz = 250 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_225MHz = 225 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_200MHz = 200 * 1000 * 1000,
|
||||
SOC__NN_CLOCK_100MHz = 100 * 1000 * 1000
|
||||
} SOC__NN_CLOCK_HZ_t;
|
||||
|
||||
typedef enum {
|
||||
WD_SERVICE_MODE_HW_SW = 0,
|
||||
WD_SERVICE_MODE_HW_ONLY,
|
||||
WD_SERVICE_NUM_MODES
|
||||
} WD_SERVICE_wd_mode_t;
|
||||
|
||||
typedef enum {
|
||||
OVERCURRENT_PARAMETERS_SOURCE_FW_VALUES = 0,
|
||||
OVERCURRENT_PARAMETERS_SOURCE_USER_CONFIG_VALUES,
|
||||
OVERCURRENT_PARAMETERS_SOURCE_BOARD_CONFIG_VALUES,
|
||||
OVERCURRENT_PARAMETERS_SOURCE_OVERCURRENT_DISABLED,
|
||||
} OVERCURRENT_parameters_source_t;
|
||||
|
||||
typedef enum {
|
||||
OVERCURRENT_CONVERSION_PERIOD_140US = 140,
|
||||
OVERCURRENT_CONVERSION_PERIOD_204US = 204,
|
||||
OVERCURRENT_CONVERSION_PERIOD_332US = 332,
|
||||
OVERCURRENT_CONVERSION_PERIOD_588US = 588,
|
||||
OVERCURRENT_CONVERSION_PERIOD_1100US = 1100,
|
||||
OVERCURRENT_CONVERSION_PERIOD_2116US = 2116,
|
||||
OVERCURRENT_CONVERSION_PERIOD_4156US = 4156,
|
||||
OVERCURRENT_CONVERSION_PERIOD_8244US = 8244
|
||||
} OVERCURRENT_conversion_time_us_t;
|
||||
|
||||
typedef enum {
|
||||
TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_FW_VALUES = 0,
|
||||
TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_USER_CONFIG_VALUES
|
||||
} TEMPERATURE_PROTECTION_parameters_source_t;
|
||||
|
||||
#endif /* __USER_CONFIG_COMMON__ */
|
||||
114
common/include/utils.h
Normal file
114
common/include/utils.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file utils.h
|
||||
* @brief Defines common utilities.
|
||||
**/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
/** A compile time assertion check.
|
||||
*
|
||||
* Validate at compile time that the predicate is true without
|
||||
* generating code. This can be used at any point in a source file
|
||||
* where typedef is legal.
|
||||
*
|
||||
* On success, compilation proceeds normally.
|
||||
*
|
||||
* On failure, attempts to typedef an array type of negative size. The
|
||||
* offending line will look like
|
||||
* typedef assertion_failed_file_h_42[-1]
|
||||
* where file is the content of the second parameter which should
|
||||
* typically be related in some obvious way to the containing file
|
||||
* name, 42 is the line number in the file on which the assertion
|
||||
* appears, and -1 is the result of a calculation based on the
|
||||
* predicate failing.
|
||||
*
|
||||
* \param predicate The predicate to test. It must evaluate to
|
||||
* something that can be coerced to a normal C boolean.
|
||||
*
|
||||
* \param file A sequence of legal identifier characters that should
|
||||
* uniquely identify the source file in which this condition appears.
|
||||
*/
|
||||
#define CASSERT(predicate, file) \
|
||||
_impl_CASSERT_LINE(predicate,__LINE__,file) \
|
||||
|
||||
#define _impl_PASTE(a,b) a##b
|
||||
#define _impl_CASSERT_LINE(predicate, line, file) \
|
||||
ATTR_UNUSED typedef char _impl_PASTE(assertion_failed_##file##_,line)[2*!!(predicate)-1];
|
||||
|
||||
#define ARRAY_LENGTH(__array) (sizeof((__array)) / sizeof((__array)[0]))
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef DIV_ROUND_UP
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#endif
|
||||
|
||||
#ifndef ROUND_UNSIGNED_FLOAT
|
||||
#define ROUND_UNSIGNED_FLOAT(n) ((n - (uint32_t)(n)) > 0.5) ? (uint32_t)(n + 1) : (uint32_t)(n)
|
||||
#endif
|
||||
|
||||
#ifndef IS_POWEROF2
|
||||
#define IS_POWEROF2(v) ((v & (v - 1)) == 0)
|
||||
#endif
|
||||
|
||||
#define CPU_CYCLES_NUMBER_IN_MS (configCPU_CLOCK_HZ / 1000)
|
||||
|
||||
#define GET_MASK(width, shift) (((1U << (width)) - 1U) << (shift))
|
||||
|
||||
/* Argument counter for variadic macros */
|
||||
#define GET_ARG_COUNT(...) INTERNAL_GET_ARG_COUNT_PRIVATE(0, ## __VA_ARGS__, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define INTERNAL_GET_ARG_COUNT_PRIVATE(_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, count, ...) count
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ATTR_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define ATTR_UNUSED
|
||||
#endif
|
||||
|
||||
#define PP_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
|
||||
|
||||
#define PP_RSEQ_N() 6, 5, 4, 3, 2, 1, 0
|
||||
|
||||
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
|
||||
|
||||
#define PP_COMMASEQ_N() 1, 1, 1, 1, 1, 0
|
||||
|
||||
#define PP_COMMA(...) ,
|
||||
|
||||
#define PP_NARG_HELPER3_01(N) 0
|
||||
#define PP_NARG_HELPER3_00(N) 1
|
||||
#define PP_NARG_HELPER3_11(N) N
|
||||
#define PP_NARG_HELPER2(a, b, N) PP_NARG_HELPER3_ ## a ## b(N)
|
||||
#define PP_NARG_HELPER1(a, b, N) PP_NARG_HELPER2(a, b, N)
|
||||
|
||||
#define PP_HASCOMMA(...) \
|
||||
PP_NARG_(__VA_ARGS__, PP_COMMASEQ_N())
|
||||
|
||||
#define PP_NARG(...) \
|
||||
PP_NARG_HELPER1( \
|
||||
PP_HASCOMMA(__VA_ARGS__), \
|
||||
PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()),\
|
||||
PP_NARG_(__VA_ARGS__, PP_RSEQ_N()))
|
||||
|
||||
#define UNUSED0(...)
|
||||
#define UNUSED1(x) (void)(x)
|
||||
#define UNUSED2(x,y) (void)(x),(void)(y)
|
||||
#define UNUSED3(x,y,z) (void)(x),(void)(y),(void)(z)
|
||||
#define UNUSED4(a,x,y,z) (void)(a),(void)(x),(void)(y),(void)(z)
|
||||
#define UNUSED5(a,b,x,y,z) (void)(a),(void)(b),(void)(x),(void)(y),(void)(z)
|
||||
#define UNUSED6(a,b,x,y,z,c) (void)(a),(void)(b),(void)(x),(void)(y),(void)(z),(void)(c)
|
||||
|
||||
#define ALL_UNUSED_IMPL_(nargs) UNUSED ## nargs
|
||||
#define ALL_UNUSED_IMPL(nargs) ALL_UNUSED_IMPL_(nargs)
|
||||
#define ALL_UNUSED(...) ALL_UNUSED_IMPL( PP_NARG(__VA_ARGS__))(__VA_ARGS__ )
|
||||
|
||||
#endif /* __UTILS_H__ */
|
||||
279
common/src/firmware_header_utils.c
Normal file
279
common/src/firmware_header_utils.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file firmware_header_utils.c
|
||||
* @brief Utilities for working with the firmware header.
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "firmware_header.h"
|
||||
#include "firmware_version.h"
|
||||
#include "firmware_header_utils.h"
|
||||
#include "utils.h"
|
||||
#include "control_protocol.h"
|
||||
|
||||
/* when reading the firmware we don't want to read past the firmware_size,
|
||||
so we have a consumed_firmware_offset that is updated _before_ accessing data at that offset
|
||||
of firmware_base_address */
|
||||
#define CONSUME_FIRMWARE(__size, __status) do { \
|
||||
consumed_firmware_offset += (uint32_t) (__size); \
|
||||
if ((firmware_size < (__size)) || (firmware_size < consumed_firmware_offset)) { \
|
||||
status = __status; \
|
||||
goto exit; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static HAILO_COMMON_STATUS_t firmware_header_utils__validate_fw_header(uintptr_t firmware_base_address,
|
||||
uint32_t firmware_size,
|
||||
uint32_t max_code_size,
|
||||
uint32_t *outer_consumed_firmware_offset,
|
||||
firmware_header_t **out_firmware_header,
|
||||
firmware_type_t firmware_type)
|
||||
{
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
firmware_header_t *firmware_header = NULL;
|
||||
uint32_t consumed_firmware_offset = *outer_consumed_firmware_offset;
|
||||
uint32_t firmware_magic = 0;
|
||||
|
||||
firmware_header = (firmware_header_t *) (firmware_base_address + consumed_firmware_offset);
|
||||
CONSUME_FIRMWARE(sizeof(firmware_header_t), HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_HEADER_SIZE);
|
||||
|
||||
switch (firmware_type) {
|
||||
case FIRMWARE_TYPE_HAILO8:
|
||||
firmware_magic = FIRMWARE_HEADER_MAGIC_HAILO8;
|
||||
break;
|
||||
case FIRMWARE_TYPE_MERCURY:
|
||||
firmware_magic = FIRMWARE_HEADER_MAGIC_MERCURY;
|
||||
break;
|
||||
default:
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (firmware_magic != firmware_header->magic) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INCORRECT_FIRMWARE_HEADER_MAGIC;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Validate that the firmware header version is supported */
|
||||
switch(firmware_header->header_version) {
|
||||
case FIRMWARE_HEADER_VERSION_INITIAL:
|
||||
break;
|
||||
default:
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__UNSUPPORTED_FIRMWARE__HEADER_VERSION;
|
||||
goto exit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MINIMUM_FIRMWARE_CODE_SIZE > firmware_header->code_size) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__CODE_SIZE_BELOW_MINIMUM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (max_code_size < firmware_header->code_size) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__CODE_OVERRUNS_RAM_SIZE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
CONSUME_FIRMWARE(firmware_header->code_size, HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_FIRMWARE_CODE_SIZE);
|
||||
|
||||
*outer_consumed_firmware_offset = consumed_firmware_offset;
|
||||
*out_firmware_header = firmware_header;
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static HAILO_COMMON_STATUS_t firmware_header_utils__validate_cert_header(uintptr_t firmware_base_address,
|
||||
uint32_t firmware_size,
|
||||
uint32_t *outer_consumed_firmware_offset,
|
||||
secure_boot_certificate_t **out_firmware_cert)
|
||||
{
|
||||
|
||||
secure_boot_certificate_t *firmware_cert = NULL;
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
uint32_t consumed_firmware_offset = *outer_consumed_firmware_offset;
|
||||
|
||||
firmware_cert = (secure_boot_certificate_t *) (firmware_base_address + consumed_firmware_offset);
|
||||
CONSUME_FIRMWARE(sizeof(secure_boot_certificate_t), HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_HEADER_SIZE);
|
||||
|
||||
if ((MAXIMUM_FIRMWARE_CERT_KEY_SIZE < firmware_cert->key_size) ||
|
||||
(MAXIMUM_FIRMWARE_CERT_CONTENT_SIZE < firmware_cert->content_size)) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__CERT_TOO_LARGE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
CONSUME_FIRMWARE(firmware_cert->key_size, HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_KEY_SIZE);
|
||||
CONSUME_FIRMWARE(firmware_cert->content_size, HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CERT_CONTENT_SIZE);
|
||||
|
||||
*outer_consumed_firmware_offset = consumed_firmware_offset;
|
||||
*out_firmware_cert = firmware_cert;
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_fw_headers(uintptr_t firmware_base_address,
|
||||
uint32_t firmware_size,
|
||||
bool is_firmware_size_unknown,
|
||||
firmware_header_t **out_app_firmware_header,
|
||||
firmware_header_t **out_core_firmware_header,
|
||||
secure_boot_certificate_t **out_firmware_cert,
|
||||
firmware_type_t firmware_type)
|
||||
{
|
||||
firmware_header_t *app_firmware_header = NULL;
|
||||
firmware_header_t *core_firmware_header = NULL;
|
||||
secure_boot_certificate_t *firmware_cert = NULL;
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
uint32_t consumed_firmware_offset = 0;
|
||||
|
||||
status = firmware_header_utils__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_APP_FIRMWARE_CODE_SIZE,
|
||||
&consumed_firmware_offset, &app_firmware_header, firmware_type);
|
||||
if (HAILO_COMMON_STATUS__SUCCESS != status) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = firmware_header_utils__validate_cert_header(firmware_base_address, firmware_size,
|
||||
&consumed_firmware_offset, &firmware_cert);
|
||||
if (HAILO_COMMON_STATUS__SUCCESS != status) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_CERTIFICATE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = firmware_header_utils__validate_fw_header(firmware_base_address, firmware_size, MAXIMUM_CORE_FIRMWARE_CODE_SIZE,
|
||||
&consumed_firmware_offset, &core_firmware_header, firmware_type);
|
||||
if (HAILO_COMMON_STATUS__SUCCESS != status) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_CORE_CPU_FIRMWARE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((consumed_firmware_offset != firmware_size) && (!is_firmware_size_unknown)) {
|
||||
/* it is an error if there is leftover data after the last firmware header */
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__LEFTOVER_DATA_AFTER_LAST_FIRMWARE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* the out params are all optional */
|
||||
if (NULL != out_app_firmware_header) {
|
||||
*out_app_firmware_header = app_firmware_header;
|
||||
}
|
||||
if (NULL != out_firmware_cert) {
|
||||
*out_firmware_cert = firmware_cert;
|
||||
}
|
||||
if (NULL != out_core_firmware_header) {
|
||||
*out_core_firmware_header = core_firmware_header;
|
||||
}
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_second_stage_headers(uintptr_t second_stage_base_size,
|
||||
uint32_t second_stage_size,
|
||||
firmware_header_t **out_second_stage_header,
|
||||
firmware_type_t firmware_type)
|
||||
{
|
||||
firmware_header_t *second_stage_header = NULL;
|
||||
secure_boot_certificate_t *second_stage_cert = NULL;
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
uint32_t consumed_second_stage_offset = 0;
|
||||
|
||||
status = firmware_header_utils__validate_fw_header(second_stage_base_size, second_stage_size, MAXIMUM_SECOND_STAGE_CODE_SIZE,
|
||||
&consumed_second_stage_offset, &second_stage_header, firmware_type);
|
||||
if (HAILO_COMMON_STATUS__SUCCESS != status) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = firmware_header_utils__validate_cert_header(second_stage_base_size, second_stage_size,
|
||||
&consumed_second_stage_offset, &second_stage_cert);
|
||||
if (HAILO_COMMON_STATUS__SUCCESS != status) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_APP_CPU_FIRMWARE_CERTIFICATE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (consumed_second_stage_offset != second_stage_size) {
|
||||
/* it is an error if there is leftover data after the last firmware header */
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__LEFTOVER_DATA_AFTER_LAST_FIRMWARE_HEADER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* the out params are all optional */
|
||||
if (NULL != out_second_stage_header) {
|
||||
*out_second_stage_header = second_stage_header;
|
||||
}
|
||||
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
FW_BINARY_TYPE_t FIRMWARE_HEADER_UTILS__get_fw_binary_type(uint32_t binary_revision)
|
||||
{
|
||||
FW_BINARY_TYPE_t fw_binary_type = FW_BINARY_TYPE_INVALID;
|
||||
// Remove dev flag before checking binary type
|
||||
binary_revision &= ~(REVISION_DEV_FLAG_BIT_MASK);
|
||||
|
||||
if (REVISION_SECOND_STAGE_FLAG_BIT_MASK == (binary_revision & REVISION_SECOND_STAGE_FLAG_BIT_MASK)) {
|
||||
fw_binary_type = FW_BINARY_TYPE_SECOND_STAGE_BOOT;
|
||||
} else if (0 == (binary_revision & (REVISION_APP_CORE_FLAG_BIT_MASK))) {
|
||||
fw_binary_type = FW_BINARY_TYPE_APP_FIRMWARE;
|
||||
} else if (REVISION_APP_CORE_FLAG_BIT_MASK == (binary_revision & (REVISION_APP_CORE_FLAG_BIT_MASK))) {
|
||||
fw_binary_type = FW_BINARY_TYPE_CORE_FIRMWARE;
|
||||
} else {
|
||||
fw_binary_type = FW_BINARY_TYPE_INVALID;
|
||||
}
|
||||
|
||||
return fw_binary_type;
|
||||
}
|
||||
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__is_binary_being_downgraded(const firmware_version_t *new_binary_version,
|
||||
const firmware_version_t *minimum_allowed_binary_version)
|
||||
{
|
||||
bool is_binary_being_downgraded =
|
||||
// Check if minimum allowed binary's major is greater than new binary's major
|
||||
(minimum_allowed_binary_version->firmware_major > new_binary_version->firmware_major) ||
|
||||
// Check if minimum allowed binary's minor is greater than new binary's minor (If major is the same)
|
||||
((minimum_allowed_binary_version->firmware_major == new_binary_version->firmware_major) &&
|
||||
(minimum_allowed_binary_version->firmware_minor > new_binary_version->firmware_minor)) ||
|
||||
// Check if minimum allowed binary's revision is greater than new binary's revision (If major and minor are the same)
|
||||
((minimum_allowed_binary_version->firmware_major == new_binary_version->firmware_major) &&
|
||||
(minimum_allowed_binary_version->firmware_minor == new_binary_version->firmware_minor) &&
|
||||
(GET_REVISION_NUMBER_VALUE(minimum_allowed_binary_version->firmware_revision) >
|
||||
(GET_REVISION_NUMBER_VALUE(new_binary_version->firmware_revision))));
|
||||
return is_binary_being_downgraded;
|
||||
}
|
||||
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_HEADER_UTILS__validate_binary_version(const firmware_version_t *new_binary_version,
|
||||
const firmware_version_t *minimum_allowed_binary_version,
|
||||
FW_BINARY_TYPE_t fw_binary_type)
|
||||
{
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
// Make sure downgrade is not executed
|
||||
if (FIRMWARE_HEADER_UTILS__is_binary_being_downgraded(new_binary_version, minimum_allowed_binary_version)) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__DETECTED_PROHIBITED_DOWNGRADE_ATTEMPT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (FIRMWARE_HEADER_UTILS__get_fw_binary_type(new_binary_version->firmware_revision) != fw_binary_type) {
|
||||
status = HAILO_STATUS__FIRMWARE_HEADER_UTILS__INVALID_BINARY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
|
||||
}
|
||||
135
common/src/firmware_status.c
Normal file
135
common/src/firmware_status.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file firmware_status.c
|
||||
* @brief Defines firmware status codes.
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "firmware_status.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FIRMWARE_ARCH
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
const char *status_name;
|
||||
uint32_t status_id;
|
||||
} FIRMWARE_STATUS__status_record_t;
|
||||
|
||||
typedef struct {
|
||||
const char *module_name;
|
||||
uint32_t module_id;
|
||||
} FIRMWARE_STATUS__module_record_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#define FIRMWARE_STATUS_SECTION __attribute__((section(".firmware_statuses")))
|
||||
|
||||
#define FIRMWARE_MODULE__X(module) static const char module##_str[] FIRMWARE_STATUS_SECTION = #module;
|
||||
#define FIRMWARE_STATUS__X(name) static const char name##_str[] FIRMWARE_STATUS_SECTION = #name;
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
|
||||
const FIRMWARE_STATUS__module_record_t FIRMWARE_STATUS__module_records[] FIRMWARE_STATUS_SECTION = {
|
||||
#define FIRMWARE_MODULE__X(module) { .module_id = module, .module_name = module##_str },
|
||||
#define FIRMWARE_STATUS__X(name)
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
};
|
||||
|
||||
const FIRMWARE_STATUS__status_record_t FIRMWARE_STATUS__status_records[] FIRMWARE_STATUS_SECTION = {
|
||||
#define FIRMWARE_MODULE__X(module)
|
||||
#define FIRMWARE_STATUS__X(name) { .status_id = name, .status_name = name##_str },
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FIRMWARE_ARCH
|
||||
|
||||
static const char *FIRMWARE_STATUS__textual_format[] =
|
||||
{
|
||||
#define FIRMWARE_MODULE__X(module)
|
||||
#define FIRMWARE_STATUS__X(name) #name,
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
};
|
||||
|
||||
/* The FIRMWARE_STATUS__textual_format array stores the strings in "absolute" order.
|
||||
In order for us to know the absolute index of each status we store an array that for each module stores
|
||||
the absolute index of it's first status.
|
||||
This way we can compute the absolute index in O(1) time. */
|
||||
|
||||
#define HELPER_INDEX_NAME(__name) __HELPER_FIRMWARE_STATUS__##__name
|
||||
|
||||
/* the helper indices counts all module names and statuses.
|
||||
the goal here is to be able to count how many statuses occured prior to each module.
|
||||
we mark the module starts with the module__START elements, and in order
|
||||
to calculate the number of statuses prior to the current module, we take the
|
||||
module's module__START value, and subtract the number of __START element
|
||||
of previous modules, which is the enum value of the module. */
|
||||
typedef enum {
|
||||
#define FIRMWARE_MODULE__X(module) HELPER_INDEX_NAME(module##__START),
|
||||
#define FIRMWARE_STATUS__X(name) HELPER_INDEX_NAME(name),
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
} __FIRMWARE_STATUS__helper_indices_t;
|
||||
|
||||
static const uint32_t FIRMWARE_STATUS__absolute_module_indices[] = {
|
||||
#define FIRMWARE_MODULE__X(module) HELPER_INDEX_NAME(module##__START) - module,
|
||||
#define FIRMWARE_STATUS__X(name)
|
||||
FIRMWARE_STATUS__VARIABLES
|
||||
#undef FIRMWARE_STATUS__X
|
||||
#undef FIRMWARE_MODULE__X
|
||||
ARRAY_LENGTH(FIRMWARE_STATUS__textual_format)
|
||||
};
|
||||
|
||||
HAILO_COMMON_STATUS_t FIRMWARE_STATUS__get_textual(FIRMWARE_STATUS_t fw_status, const char **text)
|
||||
{
|
||||
HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED;
|
||||
uint32_t module_id = 0;
|
||||
uint32_t module_abs_index = 0;
|
||||
uint32_t next_module_abs_index = 0;
|
||||
uint32_t status_value = 0;
|
||||
|
||||
if (NULL == text) {
|
||||
status = HAILO_STATUS__FIRMWARE_STATUS__NULL_ARGUMENT_PASSED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (FIRMWARE_STATUS__COMPONENT_ID != FIRMWARE_STATUS__COMPONENT_GET(fw_status)) {
|
||||
status = HAILO_STATUS__FIRMWARE_STATUS__INVALID_COMPONENT_ID;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
module_id = FIRMWARE_STATUS__MODULE_INDEX_GET(fw_status);
|
||||
if (FIRMWARE_MODULE_COUNT <= module_id) {
|
||||
status = HAILO_STATUS__FIRMWARE_STATUS__INVALID_MODULE_ID;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
module_abs_index = FIRMWARE_STATUS__absolute_module_indices[module_id];
|
||||
next_module_abs_index = FIRMWARE_STATUS__absolute_module_indices[module_id+1];
|
||||
status_value = (uint32_t)FIRMWARE_STATUS__VALUE_GET(fw_status) - 1; /* status values start at 1 */
|
||||
|
||||
/* check status value is in the correct range */
|
||||
if (status_value >= next_module_abs_index - module_abs_index) {
|
||||
status = HAILO_STATUS__FIRMWARE_STATUS__INVALID_STATUS_VALUE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*text = FIRMWARE_STATUS__textual_format[module_abs_index + status_value];
|
||||
status = HAILO_COMMON_STATUS__SUCCESS;
|
||||
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
291
common/src/md5.c
Normal file
291
common/src/md5.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* (This is a heavily cut-down "BSD license".)
|
||||
*
|
||||
* This differs from Colin Plumb's older public domain implementation in that
|
||||
* no exactly 32-bit integer data type is required (any 32-bit or wider
|
||||
* unsigned integer data type will do), there's no compile-time endianness
|
||||
* configuration, and the function prototypes match OpenSSL's. No code from
|
||||
* Colin Plumb's implementation has been reused; this comment merely compares
|
||||
* the properties of the two independent implementations.
|
||||
*
|
||||
* The primary goals of this implementation are portability and ease of use.
|
||||
* It is meant to be fast, but not as fast as possible. Some known
|
||||
* optimizations are not included to reduce source code size and avoid
|
||||
* compile-time configuration.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_OPENSSL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
*/
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) (((x) ^ (y)) ^ (z))
|
||||
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them in a
|
||||
* properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned memory
|
||||
* accesses is just an optimization. Nothing will break if it fails to detect
|
||||
* a suitable architecture.
|
||||
*
|
||||
* Unfortunately, this optimization may be a C strict aliasing rules violation
|
||||
* if the caller's data buffer has effective type that cannot be aliased by
|
||||
* MD5_u32plus. In practice, this problem may occur if these MD5 routines are
|
||||
* inlined into a calling function, or with future and dangerously advanced
|
||||
* link-time optimizations. For the time being, keeping these MD5 routines in
|
||||
* their own translation unit avoids the problem.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
|
||||
#define SET(n) \
|
||||
(*(MD5_u32plus *)&ptr[(n) * 4])
|
||||
#define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
#define SET(n) \
|
||||
(ctx->block[(n)] = \
|
||||
(MD5_u32plus)ptr[(n) * 4] | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
|
||||
#define GET(n) \
|
||||
(ctx->block[(n)])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update the bit
|
||||
* counters. There are no alignment requirements.
|
||||
*/
|
||||
static const void *body(MD5_CTX *ctx, const void *data, size_t size)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (const unsigned char *)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MD5_Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
void MD5_Update(MD5_CTX *ctx, const void *data, size_t size)
|
||||
{
|
||||
MD5_u32plus saved_lo;
|
||||
size_t used, available;
|
||||
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
|
||||
ctx->hi++;
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
available = 64 - used;
|
||||
|
||||
if (size < available) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, available);
|
||||
data = (const unsigned char *)data + available;
|
||||
size -= available;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~(size_t)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
#define OUT(dst, src) \
|
||||
(dst)[0] = (unsigned char)(src); \
|
||||
(dst)[1] = (unsigned char)((src) >> 8); \
|
||||
(dst)[2] = (unsigned char)((src) >> 16); \
|
||||
(dst)[3] = (unsigned char)((src) >> 24);
|
||||
|
||||
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
{
|
||||
unsigned long used, available;
|
||||
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
available = 64 - used;
|
||||
|
||||
if (available < 8) {
|
||||
memset(&ctx->buffer[used], 0, available);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
|
||||
memset(&ctx->buffer[used], 0, available - 8);
|
||||
|
||||
ctx->lo <<= 3;
|
||||
OUT(&ctx->buffer[56], ctx->lo)
|
||||
OUT(&ctx->buffer[60], ctx->hi)
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
OUT(&result[0], ctx->a)
|
||||
OUT(&result[4], ctx->b)
|
||||
OUT(&result[8], ctx->c)
|
||||
OUT(&result[12], ctx->d)
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
#endif
|
||||
102
hailort/CMakeLists.txt
Normal file
102
hailort/CMakeLists.txt
Normal file
@@ -0,0 +1,102 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
|
||||
# Set firmware version
|
||||
add_definitions( -DFIRMWARE_VERSION_MAJOR=4 )
|
||||
add_definitions( -DFIRMWARE_VERSION_MINOR=6 )
|
||||
add_definitions( -DFIRMWARE_VERSION_REVISION=0 )
|
||||
|
||||
message(STATUS "Building pre_build")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/libhailort/cmake/execute_cmake.cmake)
|
||||
set(HAILO_EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/external)
|
||||
execute_cmake(
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build
|
||||
BUILD_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build/build
|
||||
CONFIGURE_ARGS
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_LIST_DIR}/pre_build/install
|
||||
-DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR}
|
||||
BUILD_ARGS
|
||||
--config ${CMAKE_BUILD_TYPE} --target install ${CMAKE_EXTRA_BUILD_ARGS}
|
||||
PARALLEL_BUILD
|
||||
)
|
||||
|
||||
# BENCHMARK_ENABLE_TESTING can be used by other 3rd party projects, therefore we define it
|
||||
# before adding projects
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Enable testing of the benchmark library.")
|
||||
add_subdirectory(external/benchmark EXCLUDE_FROM_ALL)
|
||||
|
||||
# Include host protobuf for protoc (https://stackoverflow.com/questions/53651181/cmake-find-protobuf-package-in-custom-directory)
|
||||
if(CMAKE_HOST_UNIX)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/pre_build/install/lib/cmake/protobuf/protobuf-config.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/pre_build/install/lib/cmake/protobuf/protobuf-module.cmake)
|
||||
else()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/pre_build/install/cmake/protobuf-config.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/pre_build/install/cmake/protobuf-module.cmake)
|
||||
endif()
|
||||
|
||||
# Add target protobuf directory and exclude its targets from all
|
||||
# Disable protobuf tests, protoc and MSVC static runtime unless they are already defined
|
||||
# NOTE: we can also force - set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests" FORCE)
|
||||
if(NOT protobuf_BUILD_TESTS)
|
||||
set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests")
|
||||
endif()
|
||||
if(NOT protobuf_BUILD_PROTOC_BINARIES)
|
||||
set(protobuf_BUILD_PROTOC_BINARIES OFF CACHE BOOL "Build libprotoc and protoc compiler")
|
||||
endif()
|
||||
if(MSVC AND NOT protobuf_MSVC_STATIC_RUNTIME)
|
||||
set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Protobuf MSVC static runtime")
|
||||
endif()
|
||||
if(NOT protobuf_WITH_ZLIB)
|
||||
set(protobuf_WITH_ZLIB OFF CACHE BOOL "Compile protobuf with zlib")
|
||||
endif()
|
||||
add_subdirectory(external/protobuf/cmake EXCLUDE_FROM_ALL)
|
||||
if(NOT MSVC)
|
||||
set_target_properties(libprotobuf PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
set(HAILORT_INC_DIR ${PROJECT_SOURCE_DIR}/hailort/libhailort/include)
|
||||
set(HAILORT_SRC_DIR ${PROJECT_SOURCE_DIR}/hailort/libhailort/src)
|
||||
set(HAILORT_COMMON_DIR ${PROJECT_SOURCE_DIR}/hailort/)
|
||||
set(COMMON_INC_DIR ${PROJECT_SOURCE_DIR}/common/include)
|
||||
set(DRIVER_INC_DIR ${PROJECT_SOURCE_DIR}/hailort/drivers/common)
|
||||
|
||||
if(HAILO_BUILD_PYBIND)
|
||||
add_subdirectory(external/pybind11 EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
add_subdirectory(external/Catch2 EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(external/CLI11 EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(external/json EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(external/DotWriter EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(external/spdlog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(libhailort)
|
||||
add_subdirectory(hailortcli)
|
||||
|
||||
# copy files to venv
|
||||
if(HAILO_BUILD_PYBIND AND HAILO_BUILD_PYHAILORT_VENV)
|
||||
set(VENV_DRIVERS_DIR ${CMAKE_SOURCE_DIR}/hailort/libhailort/bindings/python/platform/hailo_platform/drivers/hailort/)
|
||||
set(PYHAILORT_FILES_TO_COPY
|
||||
$<TARGET_FILE:_pyhailort>
|
||||
)
|
||||
set(VENV_PYHAILORT_INTERNAL_DIR ${CMAKE_SOURCE_DIR}/platform_internals/hailo_platform_internals/pyhailort/)
|
||||
set(PYHAILORT_INTERNAL_FILES_TO_COPY
|
||||
$<TARGET_FILE:_pyhailort_internal>
|
||||
)
|
||||
add_custom_target(
|
||||
pyhailort_venv ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PYHAILORT_FILES_TO_COPY} ${VENV_DRIVERS_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PYHAILORT_INTERNAL_FILES_TO_COPY} ${VENV_PYHAILORT_INTERNAL_DIR}
|
||||
)
|
||||
add_dependencies(pyhailort_venv libhailort _pyhailort)
|
||||
endif()
|
||||
|
||||
if(HAILO_WIN_DRIVER)
|
||||
add_subdirectory(drivers/win)
|
||||
add_subdirectory(packaging)
|
||||
endif()
|
||||
|
||||
# Compile PCIe Driver if QNX
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL QNX)
|
||||
add_subdirectory(drivers/qnx)
|
||||
endif()
|
||||
21
hailort/LICENSE
Normal file
21
hailort/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020-2022 Hailo Technologies Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
13
hailort/LICENSE-3RD-PARTY.md
Normal file
13
hailort/LICENSE-3RD-PARTY.md
Normal file
@@ -0,0 +1,13 @@
|
||||
| Package | Copyright (c) | License | Version | Notes | References |
|
||||
|:---------------------------------|:----------------------------------|:-------------------|:---------------|:-------------------------------------------|:------------------------------------------------------------------------------|
|
||||
| CLI11 | University of Cincinnati | 3-Clause BSD | 1.7 | Cloned entire package | https://github.com/CLIUtils/CLI11 |
|
||||
| Catch2 | Catch2 Authors | BSL-1.0 | 2.13.7 | Cloned entire package | https://github.com/catchorg/Catch2 |
|
||||
| protobuf | Google Inc. | BSD | 3.11.4 | Cloned entire package | https://github.com/protocolbuffers/protobuf |
|
||||
| pybind11 | Wenzel Jakob | BSD | 2.3.0 | Cloned entire package | https://github.com/pybind/pybind11 |
|
||||
| spdlog | Gabi Melman | MIT | 1.6.1 | Cloned entire package | https://github.com/gabime/spdlog |
|
||||
| folly | Facebook, Inc. and its affiliates | Apache License 2.0 | v2020.08.17.00 | Copied only the file `folly/TokenBucket.h` | https://github.com/facebook/folly |
|
||||
| nlohmann_json_cmake_fetchcontent | ArthurSonzogni | MIT License | v3.9.1 | Cloned entire package | https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent |
|
||||
| readerwriterqueue | Cameron Desrochers | Simplified BSD | 1.0.3 | Cloned entire package | https://github.com/cameron314/readerwriterqueue |
|
||||
| DotWriter | John Vilk | MIT License | master | Cloned entire package (forked) | https://github.com/jvilk/DotWriter |
|
||||
| benchmark | Google Inc. | Apache License 2.0 | 1.6.0 | Cloned entire package | https://github.com/google/benchmark.git |
|
||||
| md5 | Alexander Peslyak | cut-down BSD | - | Copied code from website | http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 |
|
||||
35
hailort/common/CMakeLists.txt
Normal file
35
hailort/common/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
|
||||
if(WIN32)
|
||||
set(HAILORT_COMMON_OS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/os/windows")
|
||||
elseif(UNIX)
|
||||
set(HAILORT_COMMON_OS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/os/posix")
|
||||
else()
|
||||
message(FATAL_ERROR "Unexpeced host, stopping build")
|
||||
endif()
|
||||
set(HAILORT_COMMON_OS_DIR ${HAILORT_COMMON_OS_DIR} PARENT_SCOPE)
|
||||
|
||||
set(SRC_FILES
|
||||
${HAILORT_COMMON_OS_DIR}/ethernet_utils.cpp
|
||||
${HAILORT_COMMON_OS_DIR}/filesystem.cpp
|
||||
${HAILORT_COMMON_OS_DIR}/socket.cpp
|
||||
${HAILORT_COMMON_OS_DIR}/process.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/barrier.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/file_utils.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/string_utils.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
# Windows only modules:
|
||||
set(SRC_FILES ${SRC_FILES}
|
||||
${HAILORT_COMMON_OS_DIR}/string_conversion.cpp
|
||||
)
|
||||
elseif(UNIX)
|
||||
# Unix only modules
|
||||
set(SRC_FILES ${SRC_FILES}
|
||||
${HAILORT_COMMON_OS_DIR}/traffic_control.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(HAILORT_COMMON_CPP_SOURCES ${SRC_FILES} PARENT_SCOPE)
|
||||
62
hailort/common/async_thread.hpp
Normal file
62
hailort/common/async_thread.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file async_thread.hpp
|
||||
**/
|
||||
|
||||
#ifndef _ASYNC_THREAD_HPP_
|
||||
#define _ASYNC_THREAD_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
/**
|
||||
* Basic implementation of an async result of a function on some new thread. We use this class instead of `std::async`
|
||||
* because std::async uses future object that store/throw exceptions, and we can't compile it to armv7l platform.
|
||||
*/
|
||||
template<typename T>
|
||||
class AsyncThread final {
|
||||
public:
|
||||
explicit AsyncThread(std::function<T(void)> func) :
|
||||
m_result(),
|
||||
m_thread([this, func]() {
|
||||
m_result.store(func());
|
||||
})
|
||||
{}
|
||||
|
||||
/**
|
||||
* NOTE! this object is not moveable by purpose, on creation we create a lambda that take `this`, if we
|
||||
* move the object `this` will change and the callback will be wrong. Use exeternal storage like std::unique_ptr
|
||||
* to move the object (or to put it inside a container)
|
||||
*/
|
||||
AsyncThread(const AsyncThread<T> &) = delete;
|
||||
AsyncThread(AsyncThread<T> &&other) = delete;
|
||||
AsyncThread<T>& operator=(const AsyncThread<T>&) = delete;
|
||||
AsyncThread<T>& operator=(AsyncThread<T> &&) = delete;
|
||||
|
||||
T get()
|
||||
{
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
return m_result.load();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<T> m_result;
|
||||
std::thread m_thread;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using AsyncThreadPtr = std::unique_ptr<AsyncThread<T>>;
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _ASYNC_THREAD_HPP_ */
|
||||
42
hailort/common/barrier.cpp
Normal file
42
hailort/common/barrier.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file barrier.cpp
|
||||
**/
|
||||
|
||||
#include "common/barrier.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Barrier::Barrier(size_t count) :
|
||||
m_original_count(count), m_count(count), m_generation(0), m_mutex(), m_cv(), m_is_activated(true)
|
||||
{}
|
||||
|
||||
void Barrier::arrive_and_wait()
|
||||
{
|
||||
// Consider adding timeout and returning HAILO_STATUS
|
||||
if (!m_is_activated.load()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
size_t current_generation = m_generation;
|
||||
if ((--m_count) == 0) {
|
||||
m_generation++;
|
||||
m_count = m_original_count;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
else {
|
||||
m_cv.wait(lock, [this, current_generation] { return ((current_generation != m_generation) || !m_is_activated); });
|
||||
}
|
||||
}
|
||||
|
||||
void Barrier::terminate()
|
||||
{
|
||||
m_is_activated.store(false);
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
56
hailort/common/barrier.hpp
Normal file
56
hailort/common/barrier.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file barrier.hpp
|
||||
**/
|
||||
|
||||
#ifndef _BARRIER_HPP_
|
||||
#define _BARRIER_HPP_
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
/**
|
||||
* A barrier is a synchronization object that allows an expected number of threads to block until all of them
|
||||
* arrive at the barrier.
|
||||
*
|
||||
* This class should be similar to std::barrier that will be released in c++20 (If we use c++20, please delete this class)
|
||||
*/
|
||||
class Barrier final {
|
||||
public:
|
||||
explicit Barrier(size_t count);
|
||||
|
||||
Barrier(const Barrier &) = delete;
|
||||
Barrier& operator=(const Barrier &) = delete;
|
||||
Barrier(Barrier &&) = delete;
|
||||
Barrier& operator=(Barrier &&) = delete;
|
||||
|
||||
/**
|
||||
* Decreases the count by 1 and blocks until all threads arrives.
|
||||
*/
|
||||
void arrive_and_wait();
|
||||
|
||||
/**
|
||||
* Signal all blocking occurrences, and further calls to 'arrive_and_wait()' will return immediately
|
||||
*/
|
||||
void terminate();
|
||||
|
||||
private:
|
||||
const size_t m_original_count;
|
||||
size_t m_count;
|
||||
size_t m_generation;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
std::atomic_bool m_is_activated;
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _BARRIER_HPP_ */
|
||||
107
hailort/common/circular_buffer.hpp
Normal file
107
hailort/common/circular_buffer.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file circular_buffer.hpp
|
||||
* @brief
|
||||
*
|
||||
**/
|
||||
|
||||
#ifndef __CIRCULAR_BUFFER_HEADER__
|
||||
#define __CIRCULAR_BUFFER_HEADER__
|
||||
|
||||
#include "hailo/platform.h"
|
||||
#include "common/utils.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
typedef struct {
|
||||
volatile int head;
|
||||
volatile int tail;
|
||||
int size;
|
||||
int size_mask;
|
||||
} circbuf_t;
|
||||
|
||||
//TODO: Do not change the behavior of this module. see PLDA descs impl..
|
||||
//TODO: optimize macros
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define _CB_FETCH(x) (InterlockedOr((LONG volatile*)(&x), (LONG)0))
|
||||
#define _CB_SET(x, value) (InterlockedExchange((LONG volatile*)(&x), (LONG)(value)))
|
||||
#else
|
||||
#define _CB_FETCH(x) (__sync_fetch_and_or(&(x), 0))
|
||||
#define _CB_SET(x, value) ((void)__sync_lock_test_and_set(&(x), value))
|
||||
#endif
|
||||
|
||||
#define CB_INIT(circbuf, s) \
|
||||
(circbuf).head = 0; \
|
||||
(circbuf).tail = 0; \
|
||||
(circbuf).size = static_cast<int>(s); \
|
||||
(circbuf).size_mask = static_cast<int>((s) - 1)
|
||||
#define CB_RESET(circbuf) \
|
||||
(circbuf).head = 0; \
|
||||
(circbuf).tail = 0
|
||||
#define CB_HEAD(x) _CB_FETCH((x).head)
|
||||
#define CB_TAIL(x) _CB_FETCH((x).tail)
|
||||
#define CB_SIZE(x) _CB_FETCH((x).size)
|
||||
#define CB_ENQUEUE(circbuf, value) _CB_SET((circbuf).head, ((circbuf).head + (value)) & ((circbuf).size_mask))
|
||||
#define CB_DEQUEUE(circbuf, value) _CB_SET((circbuf).tail, ((circbuf).tail + (value)) & ((circbuf).size_mask))
|
||||
#define CB_AVAIL(circbuf, head, tail) ((((circbuf).size)-1+(tail)-(head)) & ((circbuf).size_mask))
|
||||
#define CB_AVAIL_CONT(circbuf, head, tail) \
|
||||
MIN(CB_AVAIL((circbuf), (head), (tail)), (circbuf).size - (head))
|
||||
#define CB_PROG(circbuf, head, tail) ((((circbuf).size)+(head)-(tail)) & ((circbuf).size_mask))
|
||||
#define CB_PROG_CONT(circbuf, head, tail) \
|
||||
MIN(CB_PROG((circbuf), (head), (tail)), (circbuf).size - (tail))
|
||||
|
||||
|
||||
// TODO: implement more functionalities, better move semantic handle
|
||||
// TODO: support consts methods (front(), empty()), right now CB_* macros requires non const pointer to head+tail
|
||||
template<typename T>
|
||||
class CircularArray final
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_pod<T>::value, "CircularArray can be used only with POD type");
|
||||
|
||||
CircularArray(size_t storage_size)
|
||||
{
|
||||
// storage size must be a power of 2
|
||||
assert(is_powerof2(storage_size));
|
||||
CB_INIT(m_circ, storage_size);
|
||||
m_array.resize(storage_size);
|
||||
}
|
||||
|
||||
void push_back(const T& element)
|
||||
{
|
||||
// assert(CB_AVAIL(m_circ, CB_HEAD(m_circ), CB_TAIL(m_circ)));
|
||||
m_array[CB_HEAD(m_circ)] = element;
|
||||
CB_ENQUEUE(m_circ, 1);
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
CB_DEQUEUE(m_circ, 1);
|
||||
}
|
||||
|
||||
T& front()
|
||||
{
|
||||
return m_array[CB_TAIL(m_circ)];
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return CB_HEAD(m_circ) == CB_TAIL(m_circ);
|
||||
}
|
||||
|
||||
private:
|
||||
circbuf_t m_circ;
|
||||
std::vector<T> m_array;
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* __CIRCULAR_BUFFER_HEADER__ */
|
||||
55
hailort/common/compiler_extensions_compat.hpp
Normal file
55
hailort/common/compiler_extensions_compat.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file compiler_extensions_compat.hpp
|
||||
* @brief Defines compiler extensions and preprocessor macros that are compatible across MSVC and GNU compilers
|
||||
**/
|
||||
|
||||
#ifndef __COMPILER_EXTENSIONS_COMPAT_HPP__
|
||||
#define __COMPILER_EXTENSIONS_COMPAT_HPP__
|
||||
|
||||
|
||||
// https://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc
|
||||
// Initializer/finalizer sample for MSVC and GCC/Clang.
|
||||
// 2010-2016 Joe Lowe. Released into the public domain.
|
||||
#ifdef __cplusplus
|
||||
#define COMPAT__INITIALIZER(f) \
|
||||
static void f(void); \
|
||||
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
|
||||
static void f(void)
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma section(".CRT$XCU",read)
|
||||
#define INITIALIZER2_(f,p) \
|
||||
static void f(void); \
|
||||
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
|
||||
__pragma(comment(linker,"/include:" p #f "_")) \
|
||||
static void f(void)
|
||||
#ifdef _WIN64
|
||||
#define COMPAT__INITIALIZER(f) INITIALIZER2_(f,"")
|
||||
#else
|
||||
#define COMPAT__INITIALIZER(f) INITIALIZER2_(f,"_")
|
||||
#endif
|
||||
#else
|
||||
#define COMPAT__INITIALIZER(f) \
|
||||
static void f(void) __attribute__((constructor)); \
|
||||
static void f(void)
|
||||
#endif
|
||||
|
||||
#if !defined(UNREFERENCED_PARAMETER) && !defined(_MSC_VER)
|
||||
#define UNREFERENCED_PARAMETER(param) \
|
||||
do { \
|
||||
(void)(param); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
// Used to capture consts in lambda expressions. On mscv constants must be captures, while in clang it
|
||||
// causes a warning
|
||||
#if _MSC_VER
|
||||
#define LAMBDA_CONSTANT(constant_name) constant_name
|
||||
#else
|
||||
#define LAMBDA_CONSTANT(constant_name) constant_name=constant_name
|
||||
#endif
|
||||
|
||||
#endif /* __COMPILER_EXTENSIONS_COMPAT_HPP__ */
|
||||
101
hailort/common/ethernet_utils.hpp
Normal file
101
hailort/common/ethernet_utils.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file ethernet_utils.hpp
|
||||
* @brief TODO
|
||||
*
|
||||
* TODO
|
||||
**/
|
||||
|
||||
#ifndef __OS_ETHERNET_UTILS_H__
|
||||
#define __OS_ETHERNET_UTILS_H__
|
||||
|
||||
|
||||
#include <hailo/hailort.h>
|
||||
#include "hailo/expected.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <unordered_map>
|
||||
#include <ifmib.h>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class NetworkInterface;
|
||||
using NetworkInterfaces = std::vector<NetworkInterface>;
|
||||
|
||||
class NetworkInterface final
|
||||
{
|
||||
public:
|
||||
NetworkInterface(uint32_t index, const std::string& name, const std::string& friendly_name, const std::string& ip);
|
||||
~NetworkInterface() = default;
|
||||
|
||||
uint32_t index() const;
|
||||
std::string name() const;
|
||||
std::string friendly_name() const;
|
||||
std::string ip() const;
|
||||
|
||||
static Expected<NetworkInterfaces> get_all_interfaces();
|
||||
|
||||
private:
|
||||
const uint32_t m_index;
|
||||
const std::string m_name;
|
||||
const std::string m_friendly_name;
|
||||
const std::string m_ip;
|
||||
};
|
||||
|
||||
static const uint32_t MacAddressSize = 6;
|
||||
using MacAddress = std::array<uint8_t, MacAddressSize>;
|
||||
|
||||
class ArpTable final
|
||||
{
|
||||
public:
|
||||
~ArpTable() = default;
|
||||
Expected<MacAddress> get_mac_address(uint32_t ip) const;
|
||||
|
||||
static Expected<ArpTable> create(uint32_t interface_index);
|
||||
|
||||
private:
|
||||
ArpTable(const std::unordered_map<uint32_t, MacAddress>& table);
|
||||
|
||||
std::unordered_map<uint32_t, MacAddress> m_table;
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#else
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class EthernetUtils final
|
||||
{
|
||||
public:
|
||||
EthernetUtils() = delete;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
static const uint32_t MAX_INTERFACE_SIZE = MAX_INTERFACE_NAME_LEN;
|
||||
#else
|
||||
static const uint32_t MAX_INTERFACE_SIZE = IFNAMSIZ;
|
||||
#endif
|
||||
|
||||
static hailo_status get_interface_from_board_ip(const char *board_ip, char *interface_name, size_t interface_name_length);
|
||||
static hailo_status get_ip_from_interface(const char *interface_name, char *ip, size_t ip_length);
|
||||
|
||||
private:
|
||||
#if defined(__GNUG__)
|
||||
static hailo_status get_interface_from_arp_entry(char *arp_entry, char *interface_name,
|
||||
size_t max_interface_name_length);
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* __OS_ETHERNET_UTILS_H__ */
|
||||
54
hailort/common/file_utils.cpp
Normal file
54
hailort/common/file_utils.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file file_utils.cpp
|
||||
* @brief Utilities for file operations
|
||||
**/
|
||||
|
||||
#include "common/file_utils.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include <fstream>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Expected<size_t> get_istream_size(std::ifstream &s)
|
||||
{
|
||||
auto beg_pos = s.tellg();
|
||||
CHECK_AS_EXPECTED(-1 != beg_pos, HAILO_FILE_OPERATION_FAILURE, "ifstream::tellg() failed");
|
||||
|
||||
s.seekg(0, s.end);
|
||||
CHECK_AS_EXPECTED(s.good(), HAILO_FILE_OPERATION_FAILURE, "ifstream::seekg() failed");
|
||||
|
||||
auto size = s.tellg();
|
||||
CHECK_AS_EXPECTED(-1 != size, HAILO_FILE_OPERATION_FAILURE, "ifstream::tellg() failed");
|
||||
|
||||
s.seekg(beg_pos, s.beg);
|
||||
CHECK_AS_EXPECTED(s.good(), HAILO_FILE_OPERATION_FAILURE, "ifstream::seekg() failed");
|
||||
|
||||
auto total_size = static_cast<uint64_t>(size - beg_pos);
|
||||
CHECK_AS_EXPECTED(total_size <= std::numeric_limits<size_t>::max(), HAILO_FILE_OPERATION_FAILURE,
|
||||
"File size {} is too big", total_size);
|
||||
return Expected<size_t>(static_cast<size_t>(total_size));
|
||||
}
|
||||
|
||||
Expected<Buffer> read_binary_file(const std::string &file_path)
|
||||
{
|
||||
std::ifstream file(file_path, std::ios::in | std::ios::binary);
|
||||
CHECK_AS_EXPECTED(file.good(), HAILO_OPEN_FILE_FAILURE, "Error opening file {}", file_path);
|
||||
|
||||
auto file_size = get_istream_size(file);
|
||||
CHECK_EXPECTED(file_size, "Failed to get file size");
|
||||
|
||||
auto buffer = Buffer::create(file_size.value());
|
||||
CHECK_EXPECTED(buffer, "Failed to allocate file buffer ({} bytes}", file_size.value());
|
||||
|
||||
// Read the data
|
||||
file.read(reinterpret_cast<char*>(buffer->data()), buffer->size());
|
||||
CHECK_AS_EXPECTED(file.good(), HAILO_FILE_OPERATION_FAILURE, "Failed reading file {}", file_path);
|
||||
return buffer.release();
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
31
hailort/common/file_utils.hpp
Normal file
31
hailort/common/file_utils.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file file_utils.hpp
|
||||
* @brief Utilities for file operations
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FILE_UTILS_HPP_
|
||||
#define _HAILO_FILE_UTILS_HPP_
|
||||
|
||||
#include "hailo/expected.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns the amount of data left in the given file.
|
||||
*/
|
||||
Expected<size_t> get_istream_size(std::ifstream &s);
|
||||
|
||||
/**
|
||||
* Reads full file content into a `Buffer`
|
||||
*/
|
||||
Expected<Buffer> read_binary_file(const std::string &file_path);
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _HAILO_FILE_UTILS_HPP_ */
|
||||
97
hailort/common/filesystem.hpp
Normal file
97
hailort/common/filesystem.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file filesystem.hpp
|
||||
* @brief File system API
|
||||
**/
|
||||
|
||||
#ifndef _OS_FILESYSTEM_HPP_
|
||||
#define _OS_FILESYSTEM_HPP_
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/platform.h"
|
||||
|
||||
#include "hailo/expected.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class Filesystem final {
|
||||
public:
|
||||
Filesystem() = delete;
|
||||
|
||||
static Expected<std::vector<std::string>> get_files_in_dir_flat(const std::string &dir_path);
|
||||
static Expected<bool> is_directory(const std::string &path);
|
||||
static bool has_suffix(const std::string &file_name, const std::string &suffix)
|
||||
{
|
||||
return (file_name.size() >= suffix.size()) && equal(suffix.rbegin(), suffix.rend(), file_name.rbegin());
|
||||
}
|
||||
|
||||
private:
|
||||
// OS-specific filesystem directory separator char (i.e. backslash on Windows or forward slash on UNIX)
|
||||
static const char *SEPARATOR;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
struct FileInfo {
|
||||
std::string path;
|
||||
DWORD attrs;
|
||||
};
|
||||
|
||||
static bool is_regular_or_readonly_file(DWORD attrs);
|
||||
|
||||
// TODO: supoport unicode
|
||||
class FindFile final {
|
||||
public:
|
||||
static Expected<FindFile> create(const std::string &dir_path);
|
||||
~FindFile();
|
||||
FindFile(const FindFile &other) = delete;
|
||||
FindFile &operator=(const FindFile &other) = delete;
|
||||
FindFile &operator=(FindFile &&other) = delete;
|
||||
FindFile(FindFile &&other);
|
||||
|
||||
Filesystem::FileInfo get_cur_file_info();
|
||||
// Will return HAILO_INVALID_OPERATION when the iteration is complete or HAILO_FILE_OPERATION_FAILURE upon failure
|
||||
hailo_status next_file();
|
||||
|
||||
private:
|
||||
FindFile(HANDLE find_hadle, const WIN32_FIND_DATAA &find_data);
|
||||
|
||||
HANDLE m_find_handle;
|
||||
WIN32_FIND_DATAA m_find_data;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class DirWalker final {
|
||||
public:
|
||||
static Expected<DirWalker> create(const std::string &dir_path);
|
||||
~DirWalker();
|
||||
DirWalker(const DirWalker &other) = delete;
|
||||
DirWalker &operator=(const DirWalker &other) = delete;
|
||||
DirWalker &operator=(DirWalker &&other) = delete;
|
||||
DirWalker(DirWalker &&other);
|
||||
|
||||
dirent* next_file();
|
||||
|
||||
private:
|
||||
DirWalker(DIR *dir, const std::string &dir_path);
|
||||
|
||||
DIR *m_dir;
|
||||
const std::string m_path_string;
|
||||
};
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _OS_FILESYSTEM_HPP_ */
|
||||
131
hailort/common/latency_meter.hpp
Normal file
131
hailort/common/latency_meter.hpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file latency_meter.hpp
|
||||
* @brief Calculate inference frame latency
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_LATENCY_METER_HPP_
|
||||
#define _HAILO_LATENCY_METER_HPP_
|
||||
|
||||
#include "hailo/expected.hpp"
|
||||
#include "common/circular_buffer.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
/**
|
||||
* Used to measure latency of hailo datastream - the average amount of time between
|
||||
* the start of the action to the end of the last stream.
|
||||
*/
|
||||
class LatencyMeter final {
|
||||
public:
|
||||
using duration = std::chrono::nanoseconds;
|
||||
using TimestampsArray = CircularArray<duration>;
|
||||
|
||||
explicit LatencyMeter(const std::set<uint32_t> &output_channels, size_t timestamps_list_length) :
|
||||
m_start_timestamps(timestamps_list_length),
|
||||
m_latency_count(0),
|
||||
m_latency_sum(0)
|
||||
{
|
||||
for (uint32_t ch : output_channels) {
|
||||
m_end_timestamps_per_channel.emplace(ch, TimestampsArray(timestamps_list_length));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given timestamp as a start.
|
||||
* @note Assumes it is the only thread that is calling the function
|
||||
*/
|
||||
void add_start_sample(duration timestamp)
|
||||
{
|
||||
m_start_timestamps.push_back(timestamp);
|
||||
update_latency();
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the given timestamp as the end of the given channel. The operation is done
|
||||
* after this function is called on all channels.
|
||||
* @note Assumes that only one thread per channel is calling this function.
|
||||
*/
|
||||
void add_end_sample(uint32_t channel_index, duration timestamp)
|
||||
{
|
||||
// Safe to access from several threads (when each pass different channel) because the map cannot
|
||||
// be changed in runtime.
|
||||
assert(m_end_timestamps_per_channel.find(channel_index) != m_end_timestamps_per_channel.end());
|
||||
m_end_timestamps_per_channel.at(channel_index).push_back(timestamp);
|
||||
update_latency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries average latency. One can clear measured latency by passing clear=true.
|
||||
*/
|
||||
Expected<duration> get_latency(bool clear)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(m_lock);
|
||||
|
||||
if (m_latency_count == 0) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
duration latency = (m_latency_sum / m_latency_count);
|
||||
if (clear) {
|
||||
m_latency_sum = duration();
|
||||
m_latency_count = 0;
|
||||
}
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
private:
|
||||
void update_latency()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(m_lock);
|
||||
|
||||
if (m_start_timestamps.empty()) {
|
||||
// wait for begin sample
|
||||
return;
|
||||
}
|
||||
|
||||
duration start = m_start_timestamps.front();
|
||||
duration end(0);
|
||||
for (auto &end_timesatmps : m_end_timestamps_per_channel) {
|
||||
if (end_timesatmps.second.empty()) {
|
||||
// Wait for all channel samples
|
||||
return;
|
||||
}
|
||||
|
||||
end = std::max(end, end_timesatmps.second.front());
|
||||
}
|
||||
|
||||
// calculate the latency
|
||||
m_latency_sum += (end - start);
|
||||
m_latency_count++;
|
||||
|
||||
// pop fronts
|
||||
m_start_timestamps.pop_front();
|
||||
for (auto &end_timesatmps : m_end_timestamps_per_channel) {
|
||||
end_timesatmps.second.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex m_lock;
|
||||
|
||||
TimestampsArray m_start_timestamps;
|
||||
std::unordered_map<uint32_t, TimestampsArray> m_end_timestamps_per_channel;
|
||||
|
||||
size_t m_latency_count;
|
||||
duration m_latency_sum;
|
||||
};
|
||||
|
||||
using LatencyMeterPtr = std::shared_ptr<LatencyMeter>;
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _HAILO_LATENCY_METER_HPP_ */
|
||||
75
hailort/common/logger_macros.hpp
Normal file
75
hailort/common/logger_macros.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file logger_macros.hpp
|
||||
* @brief Declares logger macros used by hailort components.
|
||||
* Assumes spdlog::set_default_logger was called (otherwise uses spdlog default logger)
|
||||
**/
|
||||
|
||||
#ifndef _LOGGER_MACROS_HPP_
|
||||
#define _LOGGER_MACROS_HPP_
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
|
||||
#define SPDLOG_NO_EXCEPTIONS
|
||||
|
||||
/* Minimum log level availble at compile time */
|
||||
#ifndef SPDLOG_ACTIVE_LEVEL
|
||||
#ifndef NDEBUG
|
||||
#define SPDLOG_ACTIVE_LEVEL (SPDLOG_LEVEL_DEBUG)
|
||||
#else
|
||||
#define SPDLOG_ACTIVE_LEVEL (SPDLOG_LEVEL_INFO)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/fmt/ostr.h>
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const hailo_status& status)
|
||||
{
|
||||
auto status_str = hailo_get_status_message(status);
|
||||
if (status_str == nullptr) {
|
||||
return os << "<Invalid(" << static_cast<int>(status) << ")>";
|
||||
}
|
||||
return os << status_str << "(" << static_cast<int>(status) << ")";
|
||||
}
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
// Makes sure during compilation time that all strings in LOGGER__X macros are not in printf format, but in fmtlib format.
|
||||
constexpr bool string_not_printf_format(char const * str) {
|
||||
int i = 0;
|
||||
|
||||
while (str[i] != '\0') {
|
||||
if (str[i] == '%' && ((str[i+1] >= 'a' && str[i+1] <= 'z') || (str[i+1] >= 'A' && str[i+1] <= 'Z'))) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define EXPAND(x) x
|
||||
#define ASSERT_NOT_PRINTF_FORMAT(fmt, ...) static_assert(string_not_printf_format(fmt), "Error - Log string is in printf format and not in fmtlib format!")
|
||||
|
||||
#define LOGGER_TO_SPDLOG(level, ...)\
|
||||
do{\
|
||||
EXPAND(ASSERT_NOT_PRINTF_FORMAT(__VA_ARGS__));\
|
||||
level(__VA_ARGS__);\
|
||||
} while(0) // NOLINT: clang complains about this code never executing
|
||||
|
||||
#define LOGGER__TRACE(...) LOGGER_TO_SPDLOG(SPDLOG_TRACE, __VA_ARGS__)
|
||||
#define LOGGER__DEBUG(...) LOGGER_TO_SPDLOG(SPDLOG_DEBUG, __VA_ARGS__)
|
||||
#define LOGGER__INFO(...) LOGGER_TO_SPDLOG(SPDLOG_INFO, __VA_ARGS__)
|
||||
#define LOGGER__WARN(...) LOGGER_TO_SPDLOG(SPDLOG_WARN, __VA_ARGS__)
|
||||
#define LOGGER__WARNING LOGGER__WARN
|
||||
#define LOGGER__ERROR(...) LOGGER_TO_SPDLOG(SPDLOG_ERROR, __VA_ARGS__)
|
||||
#define LOGGER__CRITICAL(...) LOGGER_TO_SPDLOG(SPDLOG_CRITICAL, __VA_ARGS__)
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _LOGGER_MACROS_HPP_ */
|
||||
161
hailort/common/os/posix/ethernet_utils.cpp
Normal file
161
hailort/common/os/posix/ethernet_utils.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "utils.h"
|
||||
|
||||
#include <hailo/hailort.h>
|
||||
#include "common/utils.hpp"
|
||||
#include "common/logger_macros.hpp"
|
||||
#include "common/ethernet_utils.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
#define ETHERNET_UTILS__ARP_FILE ("/proc/net/arp")
|
||||
#define ETHERNET_UTILS__ARP_ENTRY_DELIMIETERS (" ,\n")
|
||||
#define ETHERNET_UTILS__ARP_MAX_ENTRY_LENGTH (512)
|
||||
#define ETHERNET_UTILS__ARP_DEVICE_NAME_INDEX (4)
|
||||
|
||||
|
||||
hailo_status EthernetUtils::get_interface_from_arp_entry(char *arp_entry, char *interface_name,
|
||||
size_t max_interface_name_length)
|
||||
{
|
||||
/* This function parses the interface name out from the arp entry
|
||||
* Each entry is built as follows:
|
||||
* IP address HW type Flags HW address Mask Device
|
||||
*
|
||||
* For example:
|
||||
* 10.0.0.163 0x1 0x2 80:00:de:ad:be:3f * enp1s0
|
||||
* */
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
size_t token_counter = 0;
|
||||
char* token = NULL;
|
||||
|
||||
/* Start splitting the arp entry into tokens according to the delimiter */
|
||||
token = strtok(arp_entry, ETHERNET_UTILS__ARP_ENTRY_DELIMIETERS);
|
||||
if (NULL == token) {
|
||||
LOGGER__ERROR("Invalid arp entry, could not split it to tokens");
|
||||
status = HAILO_ETH_FAILURE;
|
||||
goto l_exit;
|
||||
}
|
||||
|
||||
/* Iterate over the tokens until the device name is found */
|
||||
while (NULL != token) {
|
||||
token = strtok(NULL, ETHERNET_UTILS__ARP_ENTRY_DELIMIETERS);
|
||||
if (ETHERNET_UTILS__ARP_DEVICE_NAME_INDEX == token_counter) {
|
||||
LOGGER__DEBUG("Interface name: {}", token);
|
||||
strncpy(interface_name, token, max_interface_name_length);
|
||||
break;
|
||||
}
|
||||
token_counter++;
|
||||
}
|
||||
|
||||
status = HAILO_SUCCESS;
|
||||
l_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
hailo_status EthernetUtils::get_interface_from_board_ip(const char *board_ip, char *interface_name, size_t interface_name_length)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
FILE* arp_file = NULL;
|
||||
int fclose_rc = -1;
|
||||
char buffer[ETHERNET_UTILS__ARP_MAX_ENTRY_LENGTH] = {};
|
||||
|
||||
CHECK_ARG_NOT_NULL(interface_name);
|
||||
CHECK_ARG_NOT_NULL(board_ip);
|
||||
|
||||
/* Open arp file */
|
||||
arp_file = fopen(ETHERNET_UTILS__ARP_FILE, "r");
|
||||
if (NULL == arp_file) {
|
||||
LOGGER__ERROR("Cannot open file {}. Errno: {:#x}", ETHERNET_UTILS__ARP_FILE, errno);
|
||||
status = HAILO_OPEN_FILE_FAILURE;
|
||||
goto l_exit;
|
||||
}
|
||||
|
||||
/* Go over all of the lines at the file */
|
||||
while(fgets(buffer, ARRAY_LENGTH(buffer), arp_file)) {
|
||||
/* Check if the arp line contains the board_ip */
|
||||
if (strstr(buffer, board_ip)) {
|
||||
status = get_interface_from_arp_entry(buffer, interface_name, interface_name_length);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
goto l_exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status = HAILO_SUCCESS;
|
||||
l_exit:
|
||||
if (NULL != arp_file) {
|
||||
fclose_rc = fclose(arp_file);
|
||||
if (0 != fclose_rc) {
|
||||
LOGGER__ERROR("Cannot close arp file {} ", ETHERNET_UTILS__ARP_FILE);
|
||||
if (HAILO_SUCCESS == status) {
|
||||
status = HAILO_CLOSE_FAILURE;
|
||||
} else {
|
||||
LOGGER__ERROR("Did not override status. Left status value at: {} (not assigned {}",
|
||||
status,
|
||||
HAILO_CLOSE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
hailo_status EthernetUtils::get_ip_from_interface(const char *interface_name, char *ip, size_t ip_length)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
struct ifreq ifr = {};
|
||||
int fd = 0;
|
||||
int posix_rc = 0;
|
||||
|
||||
CHECK_ARG_NOT_NULL(interface_name);
|
||||
CHECK_ARG_NOT_NULL(ip);
|
||||
|
||||
/* Create socket */
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
LOGGER__ERROR("Failed to create socket. Errno: {:#x}", errno);
|
||||
status = HAILO_ETH_FAILURE;
|
||||
goto l_exit;
|
||||
}
|
||||
|
||||
/* Convert interface name to ip address */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
(void)strncpy(ifr.ifr_name, interface_name, IFNAMSIZ-1);
|
||||
posix_rc = ioctl(fd, SIOCGIFADDR, &ifr);
|
||||
if (0 > posix_rc) {
|
||||
LOGGER__ERROR("Interface was not found. ioctl with SIOCGIFADDR has failed. Errno: {:#x}", errno);
|
||||
status = HAILO_ETH_INTERFACE_NOT_FOUND;
|
||||
goto l_exit;
|
||||
}
|
||||
(void)strncpy(ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), ip_length);
|
||||
LOGGER__DEBUG("Interface {} | IP: {}", interface_name, ip);
|
||||
|
||||
status = HAILO_SUCCESS;
|
||||
l_exit:
|
||||
/* Close the socket if it was created */
|
||||
if (0 < fd) {
|
||||
posix_rc = close(fd);
|
||||
if (0 != posix_rc) {
|
||||
LOGGER__ERROR("Failed closing socket. Errno: {:#x}", errno);
|
||||
/* Update status if only in case there was not previous error */
|
||||
if (HAILO_SUCCESS == status) {
|
||||
status = HAILO_CLOSE_FAILURE;
|
||||
} else {
|
||||
LOGGER__ERROR("Did not override status. Left status value at: {} (not assigned {}",
|
||||
status,
|
||||
HAILO_CLOSE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
97
hailort/common/os/posix/filesystem.cpp
Normal file
97
hailort/common/os/posix/filesystem.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file filesystem.cpp
|
||||
* @brief Filesystem wrapper for Linux
|
||||
**/
|
||||
|
||||
#include "common/filesystem.hpp"
|
||||
#include "common/logger_macros.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
const char *Filesystem::SEPARATOR = "/";
|
||||
|
||||
Expected<Filesystem::DirWalker> Filesystem::DirWalker::create(const std::string &dir_path)
|
||||
{
|
||||
DIR *dir = opendir(dir_path.c_str());
|
||||
CHECK(nullptr != dir, make_unexpected(HAILO_FILE_OPERATION_FAILURE),
|
||||
"Could not open directory \"{}\" with errno {}", dir_path, errno);
|
||||
return DirWalker(dir, dir_path);
|
||||
}
|
||||
|
||||
Filesystem::DirWalker::DirWalker(DIR *dir, const std::string &dir_path) :
|
||||
m_dir(dir),
|
||||
m_path_string(dir_path)
|
||||
{}
|
||||
|
||||
Filesystem::DirWalker::~DirWalker()
|
||||
{
|
||||
if (nullptr != m_dir) {
|
||||
const auto result = closedir(m_dir);
|
||||
if (-1 == result) {
|
||||
LOGGER__ERROR("closedir on directory \"{}\" failed with errno {}", m_path_string.c_str(), errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Filesystem::DirWalker::DirWalker(DirWalker &&other) :
|
||||
m_dir(std::exchange(other.m_dir, nullptr)),
|
||||
m_path_string(other.m_path_string)
|
||||
{}
|
||||
|
||||
dirent* Filesystem::DirWalker::next_file()
|
||||
{
|
||||
return readdir(m_dir);
|
||||
}
|
||||
|
||||
#if defined(__unix__)
|
||||
|
||||
Expected<std::vector<std::string>> Filesystem::get_files_in_dir_flat(const std::string &dir_path)
|
||||
{
|
||||
const std::string dir_path_with_sep = has_suffix(dir_path, SEPARATOR) ? dir_path : dir_path + SEPARATOR;
|
||||
|
||||
auto dir = DirWalker::create(dir_path_with_sep);
|
||||
CHECK_EXPECTED(dir);
|
||||
|
||||
std::vector<std::string> files;
|
||||
struct dirent *entry = nullptr;
|
||||
while ((entry = dir->next_file()) != nullptr) {
|
||||
if (entry->d_type != DT_REG) {
|
||||
continue;
|
||||
}
|
||||
const std::string file_name = entry->d_name;
|
||||
files.emplace_back(dir_path_with_sep + file_name);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
// QNX
|
||||
#elif defined(__QNX__)
|
||||
Expected<std::vector<std::string>> Filesystem::get_files_in_dir_flat(const std::string &dir_path)
|
||||
{
|
||||
(void) dir_path;
|
||||
return make_unexpected(HAILO_NOT_IMPLEMENTED);
|
||||
}
|
||||
// Unsupported Platform
|
||||
#else
|
||||
static_assert(false, "Unsupported Platform!");
|
||||
#endif
|
||||
|
||||
Expected<bool> Filesystem::is_directory(const std::string &path)
|
||||
{
|
||||
struct stat path_stat{};
|
||||
CHECK(0 == stat(path.c_str(), &path_stat), make_unexpected(HAILO_FILE_OPERATION_FAILURE),
|
||||
"stat() on path \"{}\" failed. errno {}", path.c_str(), errno);
|
||||
|
||||
return S_ISDIR(path_stat.st_mode);
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
96
hailort/common/os/posix/process.cpp
Normal file
96
hailort/common/os/posix/process.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file process.cpp
|
||||
* @brief Process wrapper for Linux
|
||||
**/
|
||||
|
||||
#include "common/process.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "common/utils.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Expected<std::pair<int32_t, std::string>> Process::create_and_wait_for_output(const std::string &command_line, uint32_t max_output_size)
|
||||
{
|
||||
auto popen_expected = PopenWrapper::create(command_line);
|
||||
CHECK_EXPECTED(popen_expected);
|
||||
const auto output_expected = popen_expected->read_stdout(max_output_size);
|
||||
CHECK_EXPECTED(output_expected);
|
||||
const auto process_exit_code = popen_expected->close();
|
||||
return std::make_pair(process_exit_code, output_expected.value());
|
||||
}
|
||||
|
||||
Expected<Process::PopenWrapper> Process::PopenWrapper::create(const std::string &command_line)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
PopenWrapper popen(command_line, status);
|
||||
CHECK_SUCCESS_AS_EXPECTED(status);
|
||||
return popen;
|
||||
}
|
||||
|
||||
Process::PopenWrapper::PopenWrapper(const std::string &command_line, hailo_status &status) :
|
||||
m_command_line(command_line)
|
||||
{
|
||||
static const char* READONLY_MODE = "r";
|
||||
m_pipe = popen(command_line.c_str(), READONLY_MODE);
|
||||
if (nullptr == m_pipe) {
|
||||
LOGGER__ERROR("popen(\"{}\") failed with errno={}", command_line.c_str(), errno);
|
||||
status = HAILO_INTERNAL_FAILURE;
|
||||
} else {
|
||||
status = HAILO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Process::PopenWrapper::~PopenWrapper()
|
||||
{
|
||||
if (nullptr != m_pipe) {
|
||||
(void) close();
|
||||
}
|
||||
}
|
||||
|
||||
Process::PopenWrapper::PopenWrapper(PopenWrapper &&other) :
|
||||
m_pipe(std::exchange(other.m_pipe, nullptr))
|
||||
{}
|
||||
|
||||
Expected<std::string> Process::PopenWrapper::read_stdout(uint32_t max_output_size)
|
||||
{
|
||||
assert (nullptr != m_pipe);
|
||||
|
||||
// We zero out the bufer so that output won't contain junk from the heap
|
||||
auto output = Buffer::create(max_output_size, 0);
|
||||
CHECK_EXPECTED(output);
|
||||
|
||||
const auto num_read = fread(reinterpret_cast<char*>(output->data()), sizeof(uint8_t), output->size(), m_pipe);
|
||||
if (num_read != output->size()) {
|
||||
if (feof(m_pipe)) {
|
||||
// We remove the trailing newline we get from fread
|
||||
const auto output_as_str = output->to_string();
|
||||
if (output_as_str[output_as_str.length() - 1] == '\n') {
|
||||
return output_as_str.substr(0, num_read - 1);
|
||||
}
|
||||
return output_as_str.substr(0, num_read);
|
||||
} else {
|
||||
LOGGER__ERROR("fread failed with ferror={}", ferror(m_pipe));
|
||||
return make_unexpected(HAILO_INTERNAL_FAILURE);
|
||||
}
|
||||
} else {
|
||||
// Truncate output
|
||||
LOGGER__TRACE("Truncating output to {} chars long", max_output_size);
|
||||
return output->to_string();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Process::PopenWrapper::close()
|
||||
{
|
||||
assert (nullptr != m_pipe);
|
||||
const auto return_code = pclose(m_pipe);
|
||||
m_pipe = nullptr; // We only close the handle once
|
||||
return return_code;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
304
hailort/common/os/posix/socket.cpp
Normal file
304
hailort/common/os/posix/socket.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file socket.cpp
|
||||
* @brief Socket wrapper for Unix
|
||||
**/
|
||||
|
||||
#include "common/socket.hpp"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <array>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
#define LINUX_RMEM_MAX_PATH "/proc/sys/net/core/rmem_max"
|
||||
|
||||
hailo_status Socket::SocketModuleWrapper::init_module()
|
||||
{
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::SocketModuleWrapper::free_module()
|
||||
{
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<Socket> Socket::create(int af, int type, int protocol)
|
||||
{
|
||||
auto module_wrapper = SocketModuleWrapper::create();
|
||||
CHECK_EXPECTED(module_wrapper);
|
||||
|
||||
auto socket_fd = create_socket_fd(af, type, protocol);
|
||||
CHECK_EXPECTED(socket_fd);
|
||||
|
||||
auto obj = Socket(module_wrapper.release(), socket_fd.release());
|
||||
return obj;
|
||||
}
|
||||
|
||||
Socket::Socket(SocketModuleWrapper &&module_wrapper, const socket_t socket_fd) :
|
||||
m_module_wrapper(std::move(module_wrapper)), m_socket_fd(socket_fd)
|
||||
{
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
auto status = close_socket_fd();
|
||||
if (HAILO_SUCCESS != status) {
|
||||
LOGGER__ERROR("Failed to free socket fd with status {}", status);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<socket_t> Socket::create_socket_fd(int af, int type, int protocol)
|
||||
{
|
||||
socket_t local_socket = INVALID_SOCKET;
|
||||
|
||||
local_socket = socket(af, type, protocol);
|
||||
CHECK_VALID_SOCKET_AS_EXPECTED(local_socket);
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
hailo_status Socket::close_socket_fd()
|
||||
{
|
||||
if (INVALID_SOCKET != m_socket_fd) {
|
||||
int socket_rc = close(m_socket_fd);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed to close socket. errno={}", errno);
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::abort()
|
||||
{
|
||||
int socket_rc = shutdown(m_socket_fd, SHUT_RDWR);
|
||||
CHECK((0 == socket_rc) || ((-1 == socket_rc) && (ENOTCONN == errno)), HAILO_ETH_FAILURE, "Failed to shutdown (abort) socket. errno={}", errno);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::socket_bind(const sockaddr *addr, socklen_t len)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
|
||||
CHECK_ARG_NOT_NULL(addr);
|
||||
|
||||
socket_rc = bind(m_socket_fd, addr, len);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed to bind socket. errno={}", errno);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::get_sock_name(sockaddr *addr, socklen_t *len)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
|
||||
CHECK_ARG_NOT_NULL(addr);
|
||||
CHECK_ARG_NOT_NULL(len);
|
||||
|
||||
socket_rc = getsockname(m_socket_fd, addr, len);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed getsockname. errno={}", errno);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::ntop(int af, const void *src, char *dst, socklen_t size)
|
||||
{
|
||||
CHECK_ARG_NOT_NULL(src);
|
||||
CHECK_ARG_NOT_NULL(dst);
|
||||
|
||||
CHECK(NULL != inet_ntop(af, src, dst, size), HAILO_ETH_FAILURE,
|
||||
"Could not convert sockaddr struct to string ip address");
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::pton(int af, const char *src, void *dst)
|
||||
{
|
||||
int inet_rc = 0;
|
||||
|
||||
CHECK_ARG_NOT_NULL(src);
|
||||
CHECK_ARG_NOT_NULL(dst);
|
||||
|
||||
inet_rc = inet_pton(af, reinterpret_cast<const char*>(src), dst);
|
||||
CHECK(1 == inet_rc, HAILO_ETH_FAILURE, "Could not convert string ip address to sockaddr struct");
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::set_recv_buffer_size_max()
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
FILE *rmem_max_file = NULL;
|
||||
uint8_t rmem_max_buffer[20] = {};
|
||||
uint64_t rmem_max = 0;
|
||||
int file_status = 0;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
rmem_max_file = fopen(LINUX_RMEM_MAX_PATH, "r");
|
||||
if (NULL != rmem_max_file) {
|
||||
bytes_read = fread(rmem_max_buffer, sizeof(rmem_max_buffer), sizeof(*rmem_max_buffer), rmem_max_file);
|
||||
if ((0 != bytes_read) || (feof(rmem_max_file))) {
|
||||
rmem_max = strtoul((char *)rmem_max_buffer, NULL, 10);
|
||||
}
|
||||
|
||||
if (0 == rmem_max) {
|
||||
LOGGER__WARN("Could not read rmem_max value from file '{}'", LINUX_RMEM_MAX_PATH);
|
||||
rmem_max = UINT64_MAX;
|
||||
}
|
||||
|
||||
file_status = fclose(rmem_max_file);
|
||||
if (0 != file_status) {
|
||||
LOGGER__WARN("Could not close file '{}' errno - {}.", LINUX_RMEM_MAX_PATH, errno);
|
||||
}
|
||||
} else {
|
||||
LOGGER__WARN("Could not open file '{}' to read rmem_max value.", LINUX_RMEM_MAX_PATH);
|
||||
}
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_RCVBUF, &rmem_max, sizeof(rmem_max));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Cannot set the rcv socket buffer to {}", rmem_max);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::set_timeout(std::chrono::milliseconds timeout_ms, timeval_t *timeout)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
time_t seconds = 0;
|
||||
suseconds_t microseconds = 0;
|
||||
auto timeout_value = static_cast<uint32_t>(timeout_ms.count());
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(timeout);
|
||||
|
||||
seconds = (timeout_value / MILLISECONDS_IN_SECOND);
|
||||
microseconds = (timeout_value % MILLISECONDS_IN_SECOND) * MICROSECONDS_IN_MILLISECOND;
|
||||
|
||||
timeout->tv_sec = seconds;
|
||||
timeout->tv_usec = microseconds;
|
||||
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Cannot set receive timeout. Seconds: {}, microseconds {}", seconds,
|
||||
microseconds);
|
||||
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_SNDTIMEO, timeout, sizeof(*timeout));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Cannot set send timeout. Seconds: {}, microseconds {}", seconds,
|
||||
microseconds);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::enable_broadcast()
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
int enable_broadcast = 1;
|
||||
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_BROADCAST, &enable_broadcast, sizeof(enable_broadcast));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Cannot set socket to be broadcast");
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::send_to(const uint8_t *src_buffer, size_t src_buffer_size, int flags,
|
||||
const sockaddr *dest_addr, socklen_t dest_addr_size, size_t *bytes_sent)
|
||||
{
|
||||
ssize_t number_of_sent_bytes = 0;
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(src_buffer);
|
||||
CHECK_ARG_NOT_NULL(dest_addr);
|
||||
CHECK_ARG_NOT_NULL(bytes_sent);
|
||||
|
||||
number_of_sent_bytes = sendto(m_socket_fd, src_buffer, src_buffer_size, flags,
|
||||
dest_addr, dest_addr_size);
|
||||
if (-1 == number_of_sent_bytes) {
|
||||
if ((EWOULDBLOCK == errno) || (EAGAIN == errno)) {
|
||||
LOGGER__ERROR("Udp send timeout");
|
||||
return HAILO_TIMEOUT;
|
||||
} else if (EINTR == errno) {
|
||||
LOGGER__ERROR("Udp send interrupted!");
|
||||
return HAILO_INTERRUPTED_BY_SIGNAL;
|
||||
} else if (EPIPE == errno) {
|
||||
// When socket is aborted from another thread sendto will return errno EPIPE
|
||||
LOGGER__INFO("Udp send aborted!");
|
||||
return HAILO_STREAM_INTERNAL_ABORT;
|
||||
} else {
|
||||
LOGGER__ERROR("Udp failed to send data, errno:{}.", errno);
|
||||
return HAILO_ETH_SEND_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*bytes_sent = (size_t)number_of_sent_bytes;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::recv_from(uint8_t *dest_buffer, size_t dest_buffer_size, int flags,
|
||||
sockaddr *src_addr, socklen_t src_addr_size, size_t *bytes_received, bool log_timeouts_in_debug)
|
||||
{
|
||||
ssize_t number_of_received_bytes = 0;
|
||||
socklen_t result_src_addr_size = src_addr_size;
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(dest_buffer);
|
||||
CHECK_ARG_NOT_NULL(src_addr);
|
||||
CHECK_ARG_NOT_NULL(bytes_received);
|
||||
|
||||
number_of_received_bytes = recvfrom(m_socket_fd, dest_buffer, dest_buffer_size, flags,
|
||||
src_addr, &result_src_addr_size);
|
||||
if (-1 == number_of_received_bytes) {
|
||||
if ((EWOULDBLOCK == errno) || (EAGAIN == errno)) {
|
||||
if (log_timeouts_in_debug) {
|
||||
LOGGER__DEBUG("Udp recvfrom failed with timeout");
|
||||
} else {
|
||||
LOGGER__ERROR("Udp recvfrom failed with timeout");
|
||||
}
|
||||
return HAILO_TIMEOUT;
|
||||
} else if (EINTR == errno) {
|
||||
LOGGER__ERROR("Udp recv interrupted!");
|
||||
return HAILO_INTERRUPTED_BY_SIGNAL;
|
||||
} else {
|
||||
LOGGER__ERROR("Udp failed to recv data");
|
||||
return HAILO_ETH_RECV_FAILURE;
|
||||
}
|
||||
}
|
||||
else if ((0 == number_of_received_bytes) && (0 != dest_buffer_size)) {
|
||||
LOGGER__INFO("Udp socket was aborted");
|
||||
return HAILO_STREAM_INTERNAL_ABORT;
|
||||
}
|
||||
|
||||
if (result_src_addr_size > src_addr_size) {
|
||||
LOGGER__ERROR("src_addr size invalid");
|
||||
return HAILO_ETH_RECV_FAILURE;
|
||||
}
|
||||
|
||||
*bytes_received = (size_t)number_of_received_bytes;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::has_data(sockaddr *src_addr, socklen_t src_addr_size, bool log_timeouts_in_debug)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
static const size_t DEST_BUFFER_SIZE = 1;
|
||||
std::array<uint8_t, DEST_BUFFER_SIZE> dest_buffer{};
|
||||
size_t number_of_received_bytes = 0;
|
||||
|
||||
status = recv_from(dest_buffer.data(), dest_buffer.size(), 0, src_addr, src_addr_size, &number_of_received_bytes, log_timeouts_in_debug);
|
||||
if ((status == HAILO_TIMEOUT) && log_timeouts_in_debug) {
|
||||
LOGGER__DEBUG("recv_from failed with timeout");
|
||||
return HAILO_TIMEOUT;
|
||||
} else {
|
||||
CHECK_SUCCESS(status);
|
||||
assert(number_of_received_bytes > 0);
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
284
hailort/common/os/posix/traffic_control.cpp
Normal file
284
hailort/common/os/posix/traffic_control.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file traffic_control.cpp
|
||||
* @brief Traffic Control wrapper
|
||||
**/
|
||||
|
||||
#include "traffic_control.hpp"
|
||||
#include "common/process.hpp"
|
||||
#include "common/ethernet_utils.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
#include "byte_order.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Expected<TrafficControlUtil> TrafficControlUtil::create(const std::string &ip, uint16_t port, uint32_t rate_bytes_per_sec)
|
||||
{
|
||||
auto interface_name = get_interface_name(ip);
|
||||
CHECK_EXPECTED(interface_name, "get_interface_name failed with status {}", interface_name.status());
|
||||
|
||||
auto board_id = ip_to_board_id(ip);
|
||||
CHECK_EXPECTED(board_id, "ip_to_board_id failed with status {}", board_id.status());
|
||||
|
||||
auto is_sudo_needed = check_is_sudo_needed();
|
||||
CHECK_EXPECTED(is_sudo_needed, "check_is_sudo_needed failed with status {}", is_sudo_needed.status());
|
||||
|
||||
return TrafficControlUtil(ip, interface_name.release(), board_id.release(), port, port_to_port_id(port),
|
||||
rate_bytes_per_sec, is_sudo_needed.release());
|
||||
}
|
||||
|
||||
TrafficControlUtil::TrafficControlUtil(const std::string& board_address, const std::string& interface_name,
|
||||
uint32_t board_id, uint16_t board_port, uint16_t port_id, uint32_t rate_bytes_per_sec, bool is_sudo_needed) :
|
||||
m_board_address(board_address),
|
||||
m_interface_name(interface_name),
|
||||
m_board_id(board_id),
|
||||
m_board_port(board_port),
|
||||
m_port_id(port_id),
|
||||
m_rate_bytes_per_sec(rate_bytes_per_sec),
|
||||
m_is_sudo_needed(is_sudo_needed)
|
||||
{}
|
||||
|
||||
hailo_status TrafficControlUtil::set_rate_limit()
|
||||
{
|
||||
LOGGER__INFO("Setting UDP rate to {} Byte/sec for {}:{}", m_rate_bytes_per_sec, m_board_address, m_board_port);
|
||||
auto status = add_board_to_interface();
|
||||
CHECK_SUCCESS(status, "add_board_to_interface failed with status {}", status);
|
||||
status = add_input_to_inteface();
|
||||
CHECK_SUCCESS(status, "add_input_to_inteface failed with status {}", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::reset_rate_limit()
|
||||
{
|
||||
LOGGER__INFO("Resetting UDP rate for {}:{}", m_board_address, m_board_port);
|
||||
// Best effort
|
||||
const auto del_input_status = del_input();
|
||||
const auto del_board_status = del_board();
|
||||
|
||||
CHECK_SUCCESS(del_input_status);
|
||||
CHECK_SUCCESS(del_board_status);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::add_board_to_interface()
|
||||
{
|
||||
CHECK_SUCCESS(tc_qdisc_add_dev(m_interface_name));
|
||||
CHECK_SUCCESS(tc_class_add_dev_for_board(m_interface_name, m_board_id));
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::add_input_to_inteface()
|
||||
{
|
||||
CHECK_SUCCESS(tc_class_add_dev_for_input(m_interface_name, m_board_id, m_port_id, m_rate_bytes_per_sec));
|
||||
CHECK_SUCCESS(tc_filter_add_dev_for_input(m_interface_name, m_board_address, m_port_id, m_board_port));
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::del_input()
|
||||
{
|
||||
static const auto SLEEP_BETWEEN_DELS = std::chrono::milliseconds(200);
|
||||
CHECK_SUCCESS(tc_filter_del_dev_for_input(m_interface_name, m_board_address, m_port_id, m_board_port));
|
||||
std::this_thread::sleep_for(SLEEP_BETWEEN_DELS);
|
||||
CHECK_SUCCESS(tc_class_del_dev_for_input(m_interface_name, m_board_id, m_port_id));
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::del_board()
|
||||
{
|
||||
return tc_class_del_dev_for_board(m_interface_name, m_board_id);
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_qdisc_add_dev(const std::string &interface_name)
|
||||
{
|
||||
// Right now we do not delete the qdisc itself on cleanup
|
||||
// Hence, it's OK if the QDISC configuration already exists
|
||||
// On 18.04 the error is a bit different so adding another allowed error
|
||||
std::stringstream cmd;
|
||||
cmd << "tc qdisc add dev " << interface_name << " root handle 1: htb default 10 direct_qlen 2000";
|
||||
return run_command(cmd.str(), m_is_sudo_needed,
|
||||
{"RTNETLINK answers: File exists", "Error: Exclusivity flag on, cannot modify."});
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_class_add_dev_for_board(const std::string &interface_name, uint32_t board_id)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc class add dev " << interface_name << " parent 1: classid 1:" << board_id << " htb rate 1Gbit";
|
||||
return run_command(cmd.str(), m_is_sudo_needed,
|
||||
{"RTNETLINK answers: File exists", "Error: Exclusivity flag on, cannot modify."});
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_class_add_dev_for_input(const std::string &interface_name, uint32_t board_id,
|
||||
uint16_t port_id, uint32_t rate_bytes_per_sec)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc class add dev " << interface_name << " parent 1:" << board_id << " classid 1:" << port_id
|
||||
<< " htb rate " << rate_bytes_per_sec << "bps ceil " << rate_bytes_per_sec << "bps maxburst 1kb";
|
||||
return run_command(cmd.str(), m_is_sudo_needed);
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_filter_add_dev_for_input(const std::string &interface_name,
|
||||
const std::string &board_ip, uint16_t port_id, uint16_t board_port)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc filter add dev " << interface_name << " protocol ip parent 1:0 prio 1 u32 match ip dst " << board_ip
|
||||
<< " match ip dport " << board_port << " 0xffff flowid 1:" << port_id;
|
||||
return run_command(cmd.str(), m_is_sudo_needed);
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_filter_del_dev_for_input(const std::string &interface_name,
|
||||
const std::string &board_ip, uint16_t port_id, uint16_t board_port)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc filter del dev " << interface_name << " protocol ip parent 1:0 prio 1 u32 match ip dst "
|
||||
<< board_ip << " match ip dport " << board_port << " 0xffff flowid 1:" << port_id;
|
||||
return run_command(cmd.str(), m_is_sudo_needed, {}, true);
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_class_del_dev_for_input(const std::string &interface_name,
|
||||
uint32_t board_id, uint16_t port_id)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc class del dev " << interface_name << " parent 1:" << board_id << " classid 1:" << port_id;
|
||||
return run_command(cmd.str(), m_is_sudo_needed, {}, true);
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::tc_class_del_dev_for_board(const std::string &interface_name,
|
||||
uint32_t board_id)
|
||||
{
|
||||
std::stringstream cmd;
|
||||
cmd << "tc class del dev " << interface_name << " parent 1: classid 1:" << board_id;
|
||||
return run_command(cmd.str(), m_is_sudo_needed, {}, true);
|
||||
}
|
||||
|
||||
Expected<std::string> TrafficControlUtil::get_interface_name(const std::string &ip)
|
||||
{
|
||||
auto interface_name = Buffer::create(EthernetUtils::MAX_INTERFACE_SIZE, 0);
|
||||
CHECK_EXPECTED(interface_name);
|
||||
|
||||
CHECK_SUCCESS_AS_EXPECTED(EthernetUtils::get_interface_from_board_ip(ip.c_str(),
|
||||
interface_name->as_pointer<char>(), interface_name->size()));
|
||||
|
||||
return interface_name->to_string();
|
||||
}
|
||||
|
||||
Expected<uint32_t> TrafficControlUtil::ip_to_board_id(const std::string &ip)
|
||||
{
|
||||
// Takes last digit from 3 octet + the whole 4th octet
|
||||
// We try to get a unique id
|
||||
const auto last_dot_loc = ip.find_last_of('.');
|
||||
if (std::string::npos == last_dot_loc) {
|
||||
LOGGER__ERROR("\".\" character not found in ip=\"{}\"", ip.c_str());
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
std::string board_id_str = ip[last_dot_loc - 1] + ip.substr(last_dot_loc + 1);
|
||||
uint32_t board_id = std::atoi(board_id_str.c_str());
|
||||
if (0 == board_id) {
|
||||
LOGGER__ERROR("atoi failed parsing \"{}\"", board_id_str.c_str());
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
return board_id;
|
||||
}
|
||||
|
||||
uint16_t TrafficControlUtil::port_to_port_id(uint16_t port)
|
||||
{
|
||||
// We use % to make the id unique (hopefully)
|
||||
return port % 1000;
|
||||
}
|
||||
|
||||
Expected<bool> TrafficControlUtil::check_is_sudo_needed()
|
||||
{
|
||||
const auto result = Process::create_and_wait_for_output("id -u", MAX_COMMAND_OUTPUT_LENGTH);
|
||||
CHECK_EXPECTED(result);
|
||||
|
||||
// If the user id is zero then we don't need to add `sudo` to our commands
|
||||
return std::move(result->second != "0");
|
||||
}
|
||||
|
||||
hailo_status TrafficControlUtil::run_command(const std::string &commnad, bool add_sudo,
|
||||
const std::vector<std::string> &allowed_errors, bool ignore_fails)
|
||||
{
|
||||
// Note: we redirect stderr to stdout
|
||||
const auto result = Process::create_and_wait_for_output(
|
||||
add_sudo ? "sudo " + commnad + " 2>&1" : commnad + " 2>&1",
|
||||
MAX_COMMAND_OUTPUT_LENGTH);
|
||||
CHECK_EXPECTED_AS_STATUS(result);
|
||||
|
||||
const uint32_t exit_code = result->first;
|
||||
if (0 == exit_code) {
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
std::string cmd_output = result->second;
|
||||
// No output = everything was OK
|
||||
bool is_output_valid = cmd_output.empty();
|
||||
if ((!is_output_valid) && (!allowed_errors.empty())) {
|
||||
is_output_valid = (std::find(allowed_errors.cbegin(), allowed_errors.cend(), cmd_output) != allowed_errors.cend());
|
||||
}
|
||||
|
||||
if (is_output_valid || ignore_fails) {
|
||||
LOGGER__TRACE("Commnad \"{}\" returned a non-zero exit code ({});"
|
||||
"ignoring (ignore_fails={}, is_output_valid={}).",
|
||||
cmd_output.c_str(), exit_code, is_output_valid, ignore_fails);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
LOGGER__ERROR("Commnad \"{}\" returned a non-zero exit code ({}), failing.", cmd_output.c_str(), exit_code);
|
||||
return HAILO_TRAFFIC_CONTROL_FAILURE;
|
||||
}
|
||||
|
||||
Expected<TrafficControl> TrafficControl::create(const std::string &ip, uint16_t port, uint32_t rate_bytes_per_sec)
|
||||
{
|
||||
auto tc_util = TrafficControlUtil::create(ip, port, rate_bytes_per_sec);
|
||||
CHECK_EXPECTED(tc_util);
|
||||
|
||||
hailo_status rate_set_status = HAILO_UNINITIALIZED;
|
||||
TrafficControl tc(tc_util.release(), rate_set_status);
|
||||
CHECK_SUCCESS_AS_EXPECTED(rate_set_status, "Failed setting rate limit with status {}", rate_set_status);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
TrafficControl::~TrafficControl()
|
||||
{
|
||||
if (m_call_reset) {
|
||||
const auto status = m_tc_util.reset_rate_limit();
|
||||
if (HAILO_SUCCESS != status) {
|
||||
LOGGER__ERROR("reset_rate_limit failed with status={}", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrafficControl::TrafficControl(TrafficControl &&other) :
|
||||
m_tc_util(std::move(other.m_tc_util)),
|
||||
m_call_reset(std::exchange(other.m_call_reset, false))
|
||||
{}
|
||||
|
||||
TrafficControl::TrafficControl(TrafficControlUtil &&tc, hailo_status &rate_set_status) :
|
||||
m_tc_util(std::move(tc)),
|
||||
m_call_reset(false)
|
||||
{
|
||||
rate_set_status = m_tc_util.reset_rate_limit();
|
||||
if (HAILO_SUCCESS != rate_set_status) {
|
||||
// This should succeed if there were previous TC rules set or if there weren't any
|
||||
// Hence, we won't continue
|
||||
LOGGER__ERROR("reset_rate_limit failed with status={}", rate_set_status);
|
||||
return;
|
||||
}
|
||||
// We want to call reset in the dtor even if set_rate_limit fails
|
||||
m_call_reset = true;
|
||||
rate_set_status = m_tc_util.set_rate_limit();
|
||||
if (HAILO_SUCCESS != rate_set_status) {
|
||||
LOGGER__ERROR("set_rate_limit failed with status={}", rate_set_status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
95
hailort/common/os/posix/traffic_control.hpp
Normal file
95
hailort/common/os/posix/traffic_control.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file traffic_control.hpp
|
||||
* @brief Traffic Control wrapper
|
||||
*
|
||||
*
|
||||
**/
|
||||
#ifndef _TRAFFIC_CONTROL_HPP_
|
||||
#define _TRAFFIC_CONTROL_HPP_
|
||||
|
||||
#include "common/utils.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/expected.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
// Contains helper functions to work with the Traffic control command line tool
|
||||
class TrafficControlUtil final
|
||||
{
|
||||
public:
|
||||
static Expected<TrafficControlUtil> create(const std::string &ip, uint16_t port, uint32_t rate_bytes_per_sec);
|
||||
static Expected<std::string> get_interface_name(const std::string &ip);
|
||||
~TrafficControlUtil() = default;
|
||||
TrafficControlUtil(TrafficControlUtil&) = delete;
|
||||
TrafficControlUtil &operator=(const TrafficControlUtil &) = delete;
|
||||
TrafficControlUtil &operator=(TrafficControlUtil &&) = delete;
|
||||
TrafficControlUtil(TrafficControlUtil &&other) = default;
|
||||
|
||||
hailo_status set_rate_limit();
|
||||
hailo_status reset_rate_limit();
|
||||
|
||||
private:
|
||||
TrafficControlUtil(const std::string& board_address, const std::string& interface_name,
|
||||
uint32_t board_id, uint16_t board_port, uint16_t port_id, uint32_t rate_bytes_per_sec, bool is_sudo_needed);
|
||||
|
||||
hailo_status add_board_to_interface();
|
||||
hailo_status add_input_to_inteface();
|
||||
hailo_status del_input();
|
||||
hailo_status del_board();
|
||||
|
||||
hailo_status tc_qdisc_add_dev(const std::string &interface_name);
|
||||
hailo_status tc_class_add_dev_for_board(const std::string &interface_name, uint32_t board_id);
|
||||
hailo_status tc_class_add_dev_for_input(const std::string &interface_name, uint32_t board_id,
|
||||
uint16_t port_id, uint32_t rate_bytes_per_sec);
|
||||
hailo_status tc_filter_add_dev_for_input(const std::string &interface_name, const std::string &board_ip,
|
||||
uint16_t port_id, uint16_t board_port);
|
||||
hailo_status tc_filter_del_dev_for_input(const std::string &interface_name, const std::string &board_ip,
|
||||
uint16_t port_id, uint16_t board_port);
|
||||
hailo_status tc_class_del_dev_for_input(const std::string &interface_name, uint32_t board_id,
|
||||
uint16_t port_id);
|
||||
hailo_status tc_class_del_dev_for_board(const std::string &interface_name, uint32_t board_id);
|
||||
|
||||
static const uint32_t MAX_COMMAND_OUTPUT_LENGTH = 100;
|
||||
static Expected<std::string> get_interface_address(const struct in_addr *addr);
|
||||
|
||||
static Expected<uint32_t> ip_to_board_id(const std::string &ip);
|
||||
static uint16_t port_to_port_id(uint16_t port);
|
||||
static Expected<bool> check_is_sudo_needed();
|
||||
static hailo_status run_command(const std::string &commnad, bool add_sudo,
|
||||
const std::vector<std::string> &allowed_errors = {}, bool ignore_fails = false);
|
||||
|
||||
const std::string m_board_address;
|
||||
const std::string m_interface_name;
|
||||
const uint32_t m_board_id;
|
||||
const uint16_t m_board_port;
|
||||
const uint16_t m_port_id;
|
||||
const uint32_t m_rate_bytes_per_sec;
|
||||
const bool m_is_sudo_needed;
|
||||
};
|
||||
|
||||
// RAII for TrafficControlUtil
|
||||
class TrafficControl final
|
||||
{
|
||||
public:
|
||||
static Expected<TrafficControl> create(const std::string &ip, uint16_t port, uint32_t rate_bytes_per_sec);
|
||||
~TrafficControl();
|
||||
TrafficControl(TrafficControl&) = delete;
|
||||
TrafficControl &operator=(const TrafficControl &) = delete;
|
||||
TrafficControl &operator=(TrafficControl &&) = delete;
|
||||
TrafficControl(TrafficControl &&other);
|
||||
|
||||
private:
|
||||
TrafficControl(TrafficControlUtil &&tc, hailo_status &rate_set_status);
|
||||
|
||||
TrafficControlUtil m_tc_util;
|
||||
bool m_call_reset;
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _TRAFFIC_CONTROL_HPP_ */
|
||||
207
hailort/common/os/windows/ethernet_utils.cpp
Normal file
207
hailort/common/os/windows/ethernet_utils.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
|
||||
#include "common/ethernet_utils.hpp"
|
||||
|
||||
#include "common/socket.hpp"
|
||||
#include "common/os/windows/string_conversion.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "common/logger_macros.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
NetworkInterface::NetworkInterface(uint32_t index, const std::string& name, const std::string& friendly_name, const std::string& ip) :
|
||||
m_index(index),
|
||||
m_name(name),
|
||||
m_friendly_name(friendly_name),
|
||||
m_ip(ip)
|
||||
{}
|
||||
|
||||
uint32_t NetworkInterface::index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
std::string NetworkInterface::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::string NetworkInterface::friendly_name() const
|
||||
{
|
||||
return m_friendly_name;
|
||||
}
|
||||
|
||||
std::string NetworkInterface::ip() const
|
||||
{
|
||||
return m_ip;
|
||||
}
|
||||
|
||||
Expected<NetworkInterfaces> NetworkInterface::get_all_interfaces()
|
||||
{
|
||||
static const ULONG IPV4 = AF_INET;
|
||||
static const ULONG UNICAST_ONLY = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
|
||||
static const PVOID RESERVED = nullptr;
|
||||
static const PIP_ADAPTER_ADDRESSES NO_INTERFACE_INFO = nullptr;
|
||||
ULONG required_size = 0;
|
||||
ULONG ret_value = GetAdaptersAddresses(IPV4, UNICAST_ONLY, RESERVED, NO_INTERFACE_INFO, &required_size);
|
||||
if (ret_value != ERROR_BUFFER_OVERFLOW) {
|
||||
LOGGER__ERROR("Failed calculating necessary size for IP_ADAPTER_ADDRESSES. "
|
||||
"Expected ret_value=ERROR_BUFFER_OVERFLOW, received={}", ret_value);
|
||||
return make_unexpected(HAILO_UNEXPECTED_INTERFACE_INFO_FAILURE);
|
||||
}
|
||||
|
||||
auto interface_info_buffer = Buffer::create(required_size, 0);
|
||||
CHECK_EXPECTED(interface_info_buffer);
|
||||
ret_value = GetAdaptersAddresses(IPV4, UNICAST_ONLY, RESERVED,
|
||||
interface_info_buffer->as_pointer<IP_ADAPTER_ADDRESSES>(), &required_size);
|
||||
if (ret_value == ERROR_NO_DATA) {
|
||||
LOGGER__ERROR("No IPv4 interfaces found");
|
||||
return make_unexpected(HAILO_NO_IPV4_INTERFACES_FOUND);
|
||||
} else if (ret_value != NO_ERROR) {
|
||||
LOGGER__ERROR("GetInterfaceInfo failed with error: {}", ret_value);
|
||||
return make_unexpected(HAILO_UNEXPECTED_INTERFACE_INFO_FAILURE);
|
||||
}
|
||||
|
||||
NetworkInterfaces interfaces;
|
||||
PIP_ADAPTER_ADDRESSES interface_info = interface_info_buffer->as_pointer<IP_ADAPTER_ADDRESSES>();
|
||||
|
||||
while (interface_info != nullptr) {
|
||||
PIP_ADAPTER_UNICAST_ADDRESS first_unicast_address = interface_info->FirstUnicastAddress;
|
||||
// TODO: keep a vector of all addresses
|
||||
if (first_unicast_address == nullptr) {
|
||||
LOGGER__DEBUG("first_unicast_address is null. Skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto address_struct = first_unicast_address->Address.lpSockaddr;
|
||||
if ((address_struct == nullptr) || (address_struct->sa_family != AF_INET)) {
|
||||
LOGGER__DEBUG("Unicast address is invalid. Skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ip = Buffer::create(IPV4_STRING_MAX_LENGTH);
|
||||
CHECK_EXPECTED(ip);
|
||||
const auto result = Socket::ntop(AF_INET, &(reinterpret_cast<sockaddr_in *>(address_struct)->sin_addr),
|
||||
ip->as_pointer<char>(), EthernetUtils::MAX_INTERFACE_SIZE);
|
||||
if (result != HAILO_SUCCESS) {
|
||||
LOGGER__DEBUG("Failed converting unicast address to string (result={}). Skipping.", result);
|
||||
continue;
|
||||
}
|
||||
const auto friendly_name_ansi = StringConverter::utf16_to_ansi(interface_info->FriendlyName);
|
||||
if (!friendly_name_ansi.has_value()) {
|
||||
LOGGER__DEBUG("Failed converting the interface's friendly_name to ansi (result={}). Skipping.",
|
||||
friendly_name_ansi.status());
|
||||
continue;
|
||||
}
|
||||
interfaces.emplace_back(interface_info->IfIndex, interface_info->AdapterName,
|
||||
friendly_name_ansi.value(), ip->to_string());
|
||||
|
||||
interface_info = interface_info->Next;
|
||||
}
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
ArpTable::ArpTable(const std::unordered_map<uint32_t, MacAddress>& table) :
|
||||
m_table(table)
|
||||
{}
|
||||
|
||||
Expected<MacAddress> ArpTable::get_mac_address(uint32_t ip) const
|
||||
{
|
||||
auto search = m_table.find(ip);
|
||||
if (search == m_table.end()) {
|
||||
return make_unexpected(HAILO_MAC_ADDRESS_NOT_FOUND);
|
||||
}
|
||||
|
||||
return Expected<MacAddress>(m_table.at(ip));
|
||||
}
|
||||
|
||||
Expected<ArpTable> ArpTable::create(uint32_t interface_index)
|
||||
{
|
||||
static const PMIB_IPNETTABLE NO_NETTABLE = nullptr;
|
||||
static const BOOL SORTED = true;
|
||||
ULONG required_size = 0;
|
||||
ULONG ret_value = GetIpNetTable(NO_NETTABLE, &required_size, SORTED);
|
||||
if (ret_value != ERROR_INSUFFICIENT_BUFFER) {
|
||||
LOGGER__ERROR("Failed calculating necessary size for MIB_IPNETTABLE. Expected ret_value=ERROR_INSUFFICIENT_BUFFER, received={}", ret_value);
|
||||
return make_unexpected(HAILO_UNEXPECTED_ARP_TABLE_FAILURE);
|
||||
}
|
||||
|
||||
auto ip_net_table_buffer = Buffer::create(required_size, 0);
|
||||
CHECK_EXPECTED(ip_net_table_buffer);
|
||||
ret_value = GetIpNetTable(ip_net_table_buffer->as_pointer<MIB_IPNETTABLE>(), &required_size, SORTED);
|
||||
if (ret_value == ERROR_NO_DATA) {
|
||||
LOGGER__ERROR("No IPv4 interfaces found");
|
||||
return make_unexpected(HAILO_NO_IPV4_INTERFACES_FOUND);
|
||||
} else if (ret_value != NO_ERROR) {
|
||||
LOGGER__ERROR("GetIpNetTable failed with error: {}", ret_value);
|
||||
return make_unexpected(HAILO_UNEXPECTED_ARP_TABLE_FAILURE);
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, MacAddress> result;
|
||||
const PMIB_IPNETTABLE ip_net_table = ip_net_table_buffer->as_pointer<MIB_IPNETTABLE>();
|
||||
for (uint32_t i = 0; i < ip_net_table->dwNumEntries; i++) {
|
||||
if (ip_net_table->table[i].dwIndex != interface_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ip_net_table->table[i].dwPhysAddrLen != MacAddressSize) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t ip = ip_net_table->table[i].dwAddr;
|
||||
MacAddress mac{};
|
||||
memcpy(mac.data(), ip_net_table->table[i].bPhysAddr, MacAddressSize);
|
||||
result[ip] = mac;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
hailo_status EthernetUtils::get_interface_from_board_ip(const char *board_ip, char *interface_name, size_t interface_name_length)
|
||||
{
|
||||
CHECK_ARG_NOT_NULL(interface_name);
|
||||
CHECK_ARG_NOT_NULL(board_ip);
|
||||
|
||||
auto network_interfaces = NetworkInterface::get_all_interfaces();
|
||||
CHECK_EXPECTED_AS_STATUS(network_interfaces);
|
||||
|
||||
struct in_addr board_ip_struct{};
|
||||
auto status = Socket::pton(AF_INET, board_ip, &board_ip_struct);
|
||||
CHECK_SUCCESS(status);
|
||||
|
||||
for (const auto& network_interface : network_interfaces.value()) {
|
||||
auto arp_table = ArpTable::create(network_interface.index());
|
||||
CHECK_EXPECTED_AS_STATUS(arp_table);
|
||||
|
||||
const auto mac_address = arp_table->get_mac_address(static_cast<uint32_t>(board_ip_struct.S_un.S_addr));
|
||||
if (mac_address) {
|
||||
(void)strncpy(interface_name, network_interface.friendly_name().c_str(), interface_name_length);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return HAILO_ETH_INTERFACE_NOT_FOUND;
|
||||
}
|
||||
|
||||
hailo_status EthernetUtils::get_ip_from_interface(const char *interface_name, char *ip, size_t ip_length)
|
||||
{
|
||||
CHECK_ARG_NOT_NULL(interface_name);
|
||||
CHECK_ARG_NOT_NULL(ip);
|
||||
|
||||
auto network_interfaces = NetworkInterface::get_all_interfaces();
|
||||
CHECK_EXPECTED_AS_STATUS(network_interfaces);
|
||||
|
||||
for (const auto& network_interface : network_interfaces.value()) {
|
||||
if (network_interface.friendly_name() == interface_name) {
|
||||
(void)strncpy(ip, network_interface.ip().c_str(), ip_length);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return HAILO_ETH_INTERFACE_NOT_FOUND;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
132
hailort/common/os/windows/filesystem.cpp
Normal file
132
hailort/common/os/windows/filesystem.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file filesystem.cpp
|
||||
* @brief Filesystem wrapper for Windows
|
||||
**/
|
||||
|
||||
#include "common/filesystem.hpp"
|
||||
#include "common/logger_macros.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
const char *Filesystem::SEPARATOR = "\\";
|
||||
|
||||
Expected<Filesystem::FindFile> Filesystem::FindFile::create(const std::string &dir_path)
|
||||
{
|
||||
static const char *DIR_WALK_WILD_CARD = "*";
|
||||
const std::string dir_path_with_sep = has_suffix(dir_path, SEPARATOR) ? dir_path + DIR_WALK_WILD_CARD :
|
||||
dir_path + SEPARATOR + DIR_WALK_WILD_CARD;
|
||||
|
||||
WIN32_FIND_DATAA find_data{};
|
||||
auto find_handle = FindFirstFileA(dir_path_with_sep.c_str(), &find_data);
|
||||
if (INVALID_HANDLE_VALUE == find_handle) {
|
||||
const auto last_error = GetLastError();
|
||||
if (last_error == ERROR_FILE_NOT_FOUND) {
|
||||
LOGGER__ERROR("No matching files could be found \"{}\"", dir_path_with_sep.c_str());
|
||||
} else {
|
||||
LOGGER__ERROR("FindFirstFileA(\"{}\") failed with LE={}", dir_path_with_sep.c_str(), last_error);
|
||||
}
|
||||
return make_unexpected(HAILO_FILE_OPERATION_FAILURE);
|
||||
}
|
||||
|
||||
// Note: find_data will be copied into the m_find_data member (it doesn't contain pointers)
|
||||
return std::move(FindFile(find_handle, find_data));
|
||||
}
|
||||
|
||||
Filesystem::FindFile::FindFile(HANDLE find_hadle, const WIN32_FIND_DATAA &find_data) :
|
||||
m_find_handle(find_hadle),
|
||||
m_find_data(find_data)
|
||||
{}
|
||||
|
||||
Filesystem::FindFile::~FindFile()
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != m_find_handle) {
|
||||
const auto result = FindClose(m_find_handle);
|
||||
if (0 == result) {
|
||||
LOGGER__ERROR("FindClose on handle={} failed with LE={}", m_find_handle, GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Filesystem::FindFile::FindFile(FindFile &&other) :
|
||||
m_find_handle(std::exchange(other.m_find_handle, INVALID_HANDLE_VALUE)),
|
||||
m_find_data(other.m_find_data)
|
||||
{}
|
||||
|
||||
Filesystem::FileInfo Filesystem::FindFile::get_cur_file_info()
|
||||
{
|
||||
return {m_find_data.cFileName, m_find_data.dwFileAttributes};
|
||||
}
|
||||
|
||||
hailo_status Filesystem::FindFile::next_file()
|
||||
{
|
||||
const auto result = FindNextFileA(m_find_handle, &m_find_data);
|
||||
if (result) {
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
const auto last_error = GetLastError();
|
||||
if (last_error == ERROR_NO_MORE_FILES) {
|
||||
// No more files
|
||||
return HAILO_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
LOGGER__ERROR("FindNextFileA() failed with LE={}", last_error);
|
||||
return HAILO_FILE_OPERATION_FAILURE;
|
||||
}
|
||||
|
||||
bool Filesystem::is_regular_or_readonly_file(DWORD attrs)
|
||||
{
|
||||
return (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
Expected<std::vector<std::string>> Filesystem::get_files_in_dir_flat(const std::string &dir_path)
|
||||
{
|
||||
const std::string dir_path_with_sep = has_suffix(dir_path, SEPARATOR) ? dir_path : dir_path + SEPARATOR;
|
||||
|
||||
auto dir = FindFile::create(dir_path_with_sep);
|
||||
CHECK_EXPECTED(dir);
|
||||
|
||||
std::vector<std::string> files;
|
||||
auto file_info = dir->get_cur_file_info();
|
||||
if (is_regular_or_readonly_file(file_info.attrs)) {
|
||||
files.emplace_back(file_info.path);
|
||||
}
|
||||
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
while (true) {
|
||||
status = dir->next_file();
|
||||
if (HAILO_INVALID_OPERATION == status) {
|
||||
// We're done
|
||||
break;
|
||||
}
|
||||
if (HAILO_SUCCESS != status) {
|
||||
// Best effort
|
||||
LOGGER__ERROR("next_file failed with status {}; skipping", status);
|
||||
continue;
|
||||
}
|
||||
|
||||
file_info = dir->get_cur_file_info();
|
||||
if (is_regular_or_readonly_file(file_info.attrs)) {
|
||||
files.emplace_back(dir_path_with_sep + file_info.path);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
Expected<bool> Filesystem::is_directory(const std::string &path)
|
||||
{
|
||||
if (path.length() > MAX_PATH) {
|
||||
LOGGER__ERROR("path is too long (MAX_PATH={}, received length={}", MAX_PATH, path.length());
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
return PathIsDirectoryA(path.c_str());
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
25
hailort/common/os/windows/process.cpp
Normal file
25
hailort/common/os/windows/process.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file process.cpp
|
||||
* @brief Process wrapper for Windows
|
||||
**/
|
||||
|
||||
#include "common/process.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Expected<std::pair<int32_t, std::string>> Process::create_and_wait_for_output(const std::string &command_line, uint32_t max_output_size)
|
||||
{
|
||||
// TODO: Add windows impl (HRT-2510)
|
||||
command_line;
|
||||
max_output_size;
|
||||
return make_unexpected(HAILO_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
288
hailort/common/os/windows/socket.cpp
Normal file
288
hailort/common/os/windows/socket.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file socket.cpp
|
||||
* @brief Socket wrapper for Windows
|
||||
**/
|
||||
|
||||
#include "common/socket.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
#define WSA_VERSION MAKEWORD(2, 2)
|
||||
|
||||
hailo_status Socket::SocketModuleWrapper::init_module()
|
||||
{
|
||||
uint16_t wsa_version = WSA_VERSION;
|
||||
WSADATA wsa_data{};
|
||||
int wsa_rt = SOCKET_ERROR;
|
||||
|
||||
wsa_rt = WSAStartup(wsa_version, &wsa_data);
|
||||
CHECK(0 == wsa_rt, HAILO_ETH_FAILURE, "WSAStartup failed. rt={}", wsa_rt);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::SocketModuleWrapper::free_module()
|
||||
{
|
||||
int wsa_rt = SOCKET_ERROR;
|
||||
|
||||
wsa_rt = WSACleanup();
|
||||
CHECK(0 == wsa_rt, HAILO_ETH_FAILURE, "WSACleanup failed. LE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<Socket> Socket::create(int af, int type, int protocol)
|
||||
{
|
||||
auto module_wrapper = SocketModuleWrapper::create();
|
||||
CHECK_EXPECTED(module_wrapper);
|
||||
|
||||
auto socket_fd = create_socket_fd(af, type, protocol);
|
||||
CHECK_EXPECTED(socket_fd);
|
||||
|
||||
auto obj = Socket(module_wrapper.release(), socket_fd.release());
|
||||
return std::move(obj);
|
||||
}
|
||||
|
||||
Socket::Socket(SocketModuleWrapper &&module_wrapper, const socket_t socket_fd) :
|
||||
m_module_wrapper(std::move(module_wrapper)), m_socket_fd(socket_fd)
|
||||
{
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
auto status = close_socket_fd();
|
||||
if (HAILO_SUCCESS != status) {
|
||||
LOGGER__ERROR("Failed to free socket fd with status {:X}");
|
||||
}
|
||||
}
|
||||
|
||||
Expected<socket_t> Socket::create_socket_fd(int af, int type, int protocol)
|
||||
{
|
||||
socket_t local_socket = INVALID_SOCKET;
|
||||
|
||||
local_socket = socket(af, type, protocol);
|
||||
CHECK_VALID_SOCKET_AS_EXPECTED(local_socket);
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
hailo_status Socket::abort()
|
||||
{
|
||||
return HAILO_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
hailo_status Socket::close_socket_fd()
|
||||
{
|
||||
if (INVALID_SOCKET != m_socket_fd) {
|
||||
int socket_rc = closesocket(m_socket_fd);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed to close socket. WSALE={}", WSAGetLastError());
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::socket_bind(const sockaddr *addr, socklen_t len)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
|
||||
CHECK_ARG_NOT_NULL(addr);
|
||||
|
||||
socket_rc = bind(m_socket_fd, addr, len);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed to bind socket. WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::get_sock_name(sockaddr *addr, socklen_t *len)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
|
||||
CHECK_ARG_NOT_NULL(addr);
|
||||
CHECK_ARG_NOT_NULL(len);
|
||||
|
||||
socket_rc = getsockname(m_socket_fd, addr, len);
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed getsockname. WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::ntop(int af, const void *src, char *dst, socklen_t size)
|
||||
{
|
||||
CHECK_ARG_NOT_NULL(src);
|
||||
CHECK_ARG_NOT_NULL(dst);
|
||||
|
||||
auto module_wrapper = SocketModuleWrapper::create();
|
||||
CHECK_EXPECTED_AS_STATUS(module_wrapper);
|
||||
|
||||
const char *inet_result = inet_ntop(af, src, dst, size);
|
||||
CHECK(nullptr != inet_result, HAILO_ETH_FAILURE, "Failed inet_ntop. WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::pton(int af, const char *src, void *dst)
|
||||
{
|
||||
int inet_result = SOCKET_ERROR;
|
||||
|
||||
CHECK_ARG_NOT_NULL(src);
|
||||
CHECK_ARG_NOT_NULL(dst);
|
||||
|
||||
auto module_wrapper = SocketModuleWrapper::create();
|
||||
CHECK_EXPECTED_AS_STATUS(module_wrapper);
|
||||
|
||||
inet_result = inet_pton(af, src, dst);
|
||||
CHECK(1 == inet_result, HAILO_ETH_FAILURE, "Failed inet_pton. WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::set_recv_buffer_size_max()
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
|
||||
// TOOD: MAX_SIZE?? https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options
|
||||
const int MAX_RECV_BUFFER_SIZE = 52428800;
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_RCVBUF,
|
||||
reinterpret_cast<const char*>(&MAX_RECV_BUFFER_SIZE), sizeof(MAX_RECV_BUFFER_SIZE));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed setsockopt(SOL_SOCKET, SO_RCVBUF). WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::set_timeout(const std::chrono::milliseconds timeout_ms, timeval_t *timeout)
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
auto timeout_value = static_cast<uint32_t>(timeout_ms.count());
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(timeout);
|
||||
|
||||
// From https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options (SO_RCVTIMEO):
|
||||
// If the socket is created using the WSASocket function, then the dwFlags parameter must have the
|
||||
// WSA_FLAG_OVERLAPPED attribute set for the timeout to function properly. Otherwise the timeout never takes effect.
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_RCVTIMEO,
|
||||
reinterpret_cast<const char*>(&timeout_value), sizeof(timeout_value));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed setsockopt(SOL_SOCKET, SO_RCVTIMEO). WSALE={}", WSAGetLastError());
|
||||
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_SNDTIMEO,
|
||||
reinterpret_cast<const char*>(&timeout_value), sizeof(timeout_value));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed setsockopt(SOL_SOCKET, SO_SNDTIMEO). WSALE={}", WSAGetLastError());
|
||||
|
||||
timeout->tv_sec = timeout_value / MILLISECONDS_IN_SECOND;
|
||||
timeout->tv_usec = (timeout_value % MILLISECONDS_IN_SECOND) * MICROSECONDS_IN_MILLISECOND;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::enable_broadcast()
|
||||
{
|
||||
int socket_rc = SOCKET_ERROR;
|
||||
int enable_broadcast = 1;
|
||||
|
||||
socket_rc = setsockopt(m_socket_fd, SOL_SOCKET, SO_BROADCAST,
|
||||
reinterpret_cast<const char*>(&enable_broadcast), sizeof(enable_broadcast));
|
||||
CHECK(0 == socket_rc, HAILO_ETH_FAILURE, "Failed setsockopt(SOL_SOCKET, SO_BROADCAST). WSALE={}", WSAGetLastError());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::send_to(const uint8_t *src_buffer, size_t src_buffer_size, int flags,
|
||||
const sockaddr *dest_addr, socklen_t dest_addr_size, size_t *bytes_sent)
|
||||
{
|
||||
int number_of_sent_bytes = SOCKET_ERROR;
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(src_buffer);
|
||||
CHECK_ARG_NOT_NULL(dest_addr);
|
||||
CHECK_ARG_NOT_NULL(bytes_sent);
|
||||
|
||||
number_of_sent_bytes = sendto(m_socket_fd, reinterpret_cast<const char*>(src_buffer),
|
||||
static_cast<int>(src_buffer_size), flags, dest_addr, dest_addr_size);
|
||||
if (SOCKET_ERROR == number_of_sent_bytes) {
|
||||
const int wsale = WSAGetLastError();
|
||||
if (WSAETIMEDOUT == errno) {
|
||||
LOGGER__ERROR("Udp send timeout");
|
||||
return HAILO_TIMEOUT;
|
||||
} else {
|
||||
LOGGER__ERROR("Udp failed to send data, WSALE={}.", wsale);
|
||||
return HAILO_ETH_SEND_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*bytes_sent = (size_t)number_of_sent_bytes;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::recv_from(uint8_t *dest_buffer, size_t dest_buffer_size, int flags,
|
||||
sockaddr *src_addr, socklen_t src_addr_size, size_t *bytes_recieved, bool log_timeouts_in_debug)
|
||||
{
|
||||
int number_of_received_bytes = SOCKET_ERROR;
|
||||
socklen_t result_src_addr_size = src_addr_size;
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(dest_buffer);
|
||||
CHECK_ARG_NOT_NULL(src_addr);
|
||||
CHECK_ARG_NOT_NULL(bytes_recieved);
|
||||
|
||||
number_of_received_bytes = recvfrom(m_socket_fd, reinterpret_cast<char*>(dest_buffer),
|
||||
static_cast<int>(dest_buffer_size), flags, src_addr, &result_src_addr_size);
|
||||
if (SOCKET_ERROR == number_of_received_bytes) {
|
||||
const int wsale = WSAGetLastError();
|
||||
if (WSAETIMEDOUT == wsale) {
|
||||
if (log_timeouts_in_debug) {
|
||||
LOGGER__DEBUG("Udp recvfrom failed with timeout");
|
||||
} else {
|
||||
LOGGER__ERROR("Udp recvfrom failed with timeout");
|
||||
}
|
||||
return HAILO_TIMEOUT;
|
||||
} else {
|
||||
LOGGER__ERROR("Udp failed to recv data. WSALE={}.", wsale);
|
||||
return HAILO_ETH_RECV_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*bytes_recieved = static_cast<size_t>(number_of_received_bytes);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status Socket::has_data(sockaddr *src_addr, socklen_t src_addr_size, bool log_timeouts_in_debug)
|
||||
{
|
||||
int number_of_received_bytes = SOCKET_ERROR;
|
||||
socklen_t result_src_addr_size = src_addr_size;
|
||||
static const size_t DEST_BUFFER_SIZE = 1;
|
||||
std::array<char, DEST_BUFFER_SIZE> dest_buffer{};
|
||||
|
||||
/* Validate arguments */
|
||||
CHECK_ARG_NOT_NULL(src_addr);
|
||||
|
||||
static const int NO_FLAGS = 0;
|
||||
number_of_received_bytes = recvfrom(m_socket_fd, dest_buffer.data(), static_cast<int>(dest_buffer.size()), NO_FLAGS,
|
||||
src_addr, &result_src_addr_size);
|
||||
if (SOCKET_ERROR == number_of_received_bytes) {
|
||||
const int wsale = WSAGetLastError();
|
||||
if (WSAETIMEDOUT == wsale) {
|
||||
if (log_timeouts_in_debug) {
|
||||
LOGGER__DEBUG("Udp recvfrom failed with timeout");
|
||||
} else {
|
||||
LOGGER__ERROR("Udp recvfrom failed with timeout");
|
||||
}
|
||||
return HAILO_TIMEOUT;
|
||||
}
|
||||
// The message may be bigger than DEST_BUFFER_SIZE bytes, leading to WSAEMSGSIZE. This is ok
|
||||
if (WSAEMSGSIZE != wsale) {
|
||||
LOGGER__ERROR("Udp failed to recv data. WSALE={}.", wsale);
|
||||
return HAILO_ETH_RECV_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
63
hailort/common/os/windows/string_conversion.cpp
Normal file
63
hailort/common/os/windows/string_conversion.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/os/windows/string_conversion.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
Expected<std::wstring> StringConverter::ansi_to_utf16(const std::string& ansi_string)
|
||||
{
|
||||
static const UINT ANSI_CODE_PAGE = CP_ACP;
|
||||
static const DWORD FAIL_ON_INVALID_CHARS = MB_ERR_INVALID_CHARS;
|
||||
static const int CALCULATE_INPUT_LENGTH = -1;
|
||||
static const LPWSTR NO_WIDE_CHAR_BUFFER = nullptr;
|
||||
static const int CALCULATE_RESULT_LENGTH = 0;
|
||||
const int required_length = MultiByteToWideChar(ANSI_CODE_PAGE, FAIL_ON_INVALID_CHARS, ansi_string.c_str(),
|
||||
CALCULATE_INPUT_LENGTH, NO_WIDE_CHAR_BUFFER, CALCULATE_RESULT_LENGTH);
|
||||
if (0 == required_length) {
|
||||
LOGGER__ERROR("Failed calculating necessary length for '{}' as unicode string. LE={}", ansi_string, GetLastError());
|
||||
return make_unexpected(HAILO_ANSI_TO_UTF16_CONVERSION_FAILED );
|
||||
}
|
||||
|
||||
std::vector<wchar_t> result_buffer(required_length, L'\0');
|
||||
const int allocated_length = MultiByteToWideChar(ANSI_CODE_PAGE, FAIL_ON_INVALID_CHARS, ansi_string.c_str(),
|
||||
CALCULATE_INPUT_LENGTH, result_buffer.data(), required_length);
|
||||
if (0 == allocated_length || allocated_length != required_length) {
|
||||
LOGGER__ERROR("Failed converting '{}' to unicode string. LE={}", ansi_string, GetLastError());
|
||||
return make_unexpected(HAILO_ANSI_TO_UTF16_CONVERSION_FAILED );
|
||||
}
|
||||
|
||||
// result_buffer includes the terminating null
|
||||
return std::wstring(result_buffer.data());
|
||||
}
|
||||
|
||||
Expected<std::string> StringConverter::utf16_to_ansi(const std::wstring& utf16_string)
|
||||
{
|
||||
static const UINT ANSI_CODE_PAGE = CP_ACP;
|
||||
static const DWORD NO_FLAGS = 0;
|
||||
static const int CALCULATE_INPUT_LENGTH = -1;
|
||||
static const LPSTR NO_UTF8_BUFFER = nullptr;
|
||||
static const int CALCULATE_RESULT_LENGTH = 0;
|
||||
static const LPCCH USE_SYSTEM_DEFAULT_CHAR = nullptr;
|
||||
static const LPBOOL NO_CUSTOM_DEFAULT_CHAR = nullptr;
|
||||
const int required_length = WideCharToMultiByte(ANSI_CODE_PAGE, NO_FLAGS, utf16_string.c_str(),
|
||||
CALCULATE_INPUT_LENGTH, NO_UTF8_BUFFER, CALCULATE_RESULT_LENGTH, USE_SYSTEM_DEFAULT_CHAR, NO_CUSTOM_DEFAULT_CHAR);
|
||||
if (0 == required_length) {
|
||||
LOGGER__ERROR("Failed calculating necessary length for utf16_string as ansi string. LE={}", GetLastError());
|
||||
return make_unexpected(HAILO_UTF16_TO_ANSI_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
std::vector<char> result_buffer(required_length, '\0');
|
||||
const int allocated_length = WideCharToMultiByte(ANSI_CODE_PAGE, NO_FLAGS, utf16_string.c_str(),
|
||||
CALCULATE_INPUT_LENGTH, result_buffer.data(), required_length, USE_SYSTEM_DEFAULT_CHAR, NO_CUSTOM_DEFAULT_CHAR);
|
||||
if (0 == allocated_length || allocated_length != required_length) {
|
||||
LOGGER__ERROR("Failed converting utf16_string to ansi string. LE={}", GetLastError());
|
||||
return make_unexpected(HAILO_UTF16_TO_ANSI_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
// result_buffer includes the terminating null
|
||||
return std::string(result_buffer.data());
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
34
hailort/common/os/windows/string_conversion.hpp
Normal file
34
hailort/common/os/windows/string_conversion.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file string_conversion.hpp
|
||||
* @brief Safe string encoding conversions.
|
||||
**/
|
||||
|
||||
#ifndef _OS_STRING_CONVERSION_HPP_
|
||||
#define _OS_STRING_CONVERSION_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <hailo/platform.h>
|
||||
#include <hailo/hailort.h>
|
||||
#include "hailo/expected.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class StringConverter final
|
||||
{
|
||||
public:
|
||||
StringConverter() = delete;
|
||||
|
||||
static Expected<std::wstring> ansi_to_utf16(const std::string& ansi_string);
|
||||
static Expected<std::string> utf16_to_ansi(const std::wstring& utf16_string);
|
||||
};
|
||||
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _OS_STRING_CONVERSION_HPP_ */
|
||||
58
hailort/common/process.hpp
Normal file
58
hailort/common/process.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file process.hpp
|
||||
* @brief Create shell processes and retrieve output
|
||||
**/
|
||||
|
||||
#ifndef _OS_PROCESS_HPP_
|
||||
#define _OS_PROCESS_HPP_
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/platform.h"
|
||||
|
||||
#include "hailo/expected.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class Process final {
|
||||
public:
|
||||
// Note:
|
||||
// * This function will block!
|
||||
// * If the process' output size exceeds max_output_size, the output will be truncated to max_output_size
|
||||
// * We remove the trailing newline if it's the last char
|
||||
static Expected<std::pair<int32_t, std::string>> create_and_wait_for_output(const std::string &command_line, uint32_t max_output_size);
|
||||
Process() = delete;
|
||||
|
||||
private:
|
||||
#if defined(__GNUC__)
|
||||
class PopenWrapper final {
|
||||
public:
|
||||
static Expected<PopenWrapper> create(const std::string &command_line);
|
||||
~PopenWrapper();
|
||||
PopenWrapper(const PopenWrapper &other) = delete;
|
||||
PopenWrapper &operator=(const PopenWrapper &other) = delete;
|
||||
PopenWrapper &operator=(PopenWrapper &&other) = delete;
|
||||
PopenWrapper(PopenWrapper &&other);
|
||||
|
||||
Expected<std::string> read_stdout(uint32_t max_output_size);
|
||||
// This function is to be called only once!
|
||||
int32_t close();
|
||||
|
||||
private:
|
||||
PopenWrapper(const std::string &command_line, hailo_status &status);
|
||||
|
||||
const std::string m_command_line;
|
||||
FILE* m_pipe;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _OS_PROCESS_HPP_ */
|
||||
217
hailort/common/runtime_statistics_internal.hpp
Normal file
217
hailort/common/runtime_statistics_internal.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file runtime_statistics_internal.hpp
|
||||
* @brief Implementation of Accumulator<T> interface
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_RUNTIME_STATISTICS_INTERNAL_HPP_
|
||||
#define _HAILO_RUNTIME_STATISTICS_INTERNAL_HPP_
|
||||
|
||||
#include "hailo/runtime_statistics.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <limits>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
|
||||
class FullAccumulator : public Accumulator<T>
|
||||
{
|
||||
public:
|
||||
// Creation isn't thread safe
|
||||
FullAccumulator(const std::string& data_type) :
|
||||
Accumulator<T>(data_type),
|
||||
m_lock(),
|
||||
m_count(0),
|
||||
m_min(static_cast<double>(std::numeric_limits<T>::max())),
|
||||
m_max(static_cast<double>(std::numeric_limits<T>::min())),
|
||||
m_mean(0),
|
||||
m_M2(0)
|
||||
{}
|
||||
FullAccumulator(FullAccumulator &&) = default;
|
||||
FullAccumulator(const FullAccumulator &) = delete;
|
||||
FullAccumulator &operator=(FullAccumulator &&) = delete;
|
||||
FullAccumulator &operator=(const FullAccumulator &) = delete;
|
||||
virtual ~FullAccumulator() = default;
|
||||
|
||||
virtual void add_data_point(T data) override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
m_min = std::min(m_min, static_cast<double>(data));
|
||||
m_max = std::max(m_max, static_cast<double>(data));
|
||||
m_count++;
|
||||
|
||||
// mean, variance, sd and mean_sd are calculated using Welford's_online_algorithm.
|
||||
// See: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
const auto delta = static_cast<double>(data) - m_mean;
|
||||
m_mean += delta / static_cast<double>(m_count);
|
||||
m_M2 += delta * (static_cast<double>(data) - m_mean);
|
||||
}
|
||||
|
||||
virtual AccumulatorResults get() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
return AccumulatorResults(count(), min(), max(), mean(), var(), sd(), mean_sd());
|
||||
}
|
||||
|
||||
virtual AccumulatorResults get_and_clear() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
auto result = get();
|
||||
clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Expected<size_t> count() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
return Expected<size_t>(m_count);
|
||||
}
|
||||
|
||||
virtual Expected<double> min() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 1) {
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
return Expected<double>(m_min);
|
||||
}
|
||||
|
||||
virtual Expected<double> max() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 1) {
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
return Expected<double>(m_max);
|
||||
}
|
||||
|
||||
virtual Expected<double> mean() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 1) {
|
||||
// Otherwise we'll divide by zero
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
return Expected<double>(m_mean);
|
||||
}
|
||||
|
||||
// Sample variance
|
||||
virtual Expected<double> var() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 2) {
|
||||
// Otherwise we'll divide by zero
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
return Expected<double>(var_impl());
|
||||
}
|
||||
|
||||
// Sample sd
|
||||
virtual Expected<double> sd() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 2) {
|
||||
// Otherwise we'll divide by zero
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
return Expected<double>(sd_impl());
|
||||
}
|
||||
|
||||
// Sample mean sd
|
||||
virtual Expected<double> mean_sd() const override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(m_lock);
|
||||
if (m_count < 2) {
|
||||
// Otherwise we'll divide by zero
|
||||
return make_unexpected(HAILO_UNINITIALIZED);
|
||||
}
|
||||
// Calculation based on: https://en.wikipedia.org/wiki/Standard_deviation#Standard_deviation_of_the_mean
|
||||
return Expected<double>(sd_impl() / std::sqrt(m_count));
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable std::recursive_mutex m_lock;
|
||||
size_t m_count;
|
||||
double m_min;
|
||||
double m_max;
|
||||
double m_mean;
|
||||
double m_M2; // Sum {i=1...n} (x_i-x_mean)^2
|
||||
|
||||
// These functions are to be called after acquiring the mutex
|
||||
virtual void clear()
|
||||
{
|
||||
m_count = 0;
|
||||
m_min = static_cast<double>(std::numeric_limits<T>::max());
|
||||
m_max = static_cast<double>(std::numeric_limits<T>::min());
|
||||
m_mean = 0;
|
||||
m_M2 = 0;
|
||||
}
|
||||
|
||||
double var_impl() const
|
||||
{
|
||||
return m_M2 / static_cast<double>(m_count - 1);
|
||||
}
|
||||
|
||||
double sd_impl() const
|
||||
{
|
||||
return std::sqrt(var_impl());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
|
||||
class AverageFPSAccumulator : public FullAccumulator<T>
|
||||
{
|
||||
public:
|
||||
// Creation isn't thread safe
|
||||
AverageFPSAccumulator(const std::string& data_type) :
|
||||
FullAccumulator<T>(data_type),
|
||||
m_sum(0)
|
||||
{}
|
||||
AverageFPSAccumulator(AverageFPSAccumulator &&) = default;
|
||||
AverageFPSAccumulator(const AverageFPSAccumulator &) = delete;
|
||||
AverageFPSAccumulator &operator=(AverageFPSAccumulator &&) = delete;
|
||||
AverageFPSAccumulator &operator=(const AverageFPSAccumulator &) = delete;
|
||||
virtual ~AverageFPSAccumulator() = default;
|
||||
|
||||
|
||||
// data is a duration of time.
|
||||
// However, the statistics collected will be in frames per seconds (i.e. time^-1).
|
||||
virtual void add_data_point(T data) override
|
||||
{
|
||||
assert(0 != data);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock_guard(this->m_lock);
|
||||
m_sum += data;
|
||||
const double data_inverse = 1.0 / static_cast<double>(data);
|
||||
// Note: 'this' is needed to access protected members of a template base class
|
||||
this->m_min = std::min(this->m_min, data_inverse);
|
||||
this->m_max = std::max(this->m_max, data_inverse);
|
||||
this->m_count++;
|
||||
|
||||
// mean, variance, sd and mean_sd are calculated using Welford's_online_algorithm.
|
||||
// See: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
const auto delta = data_inverse - this->m_mean;
|
||||
// We calculate the arithmatic mean
|
||||
this->m_mean = static_cast<double>(this->m_count) / static_cast<double>(m_sum);
|
||||
this->m_M2 += delta * (data_inverse - this->m_mean);
|
||||
}
|
||||
|
||||
virtual void clear() override
|
||||
{
|
||||
m_sum = 0;
|
||||
FullAccumulator<T>::clear();
|
||||
}
|
||||
|
||||
private:
|
||||
T m_sum; // the sum of data added with add_data_point, before inversion
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _HAILO_RUNTIME_STATISTICS_INTERNAL_HPP_ */
|
||||
108
hailort/common/socket.hpp
Normal file
108
hailort/common/socket.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file socket.hpp
|
||||
* @brief TODO
|
||||
**/
|
||||
|
||||
#ifndef __OS_SOCKET_H__
|
||||
#define __OS_SOCKET_H__
|
||||
|
||||
#include <hailo/platform.h>
|
||||
#include <hailo/hailort.h>
|
||||
#include "common/utils.hpp"
|
||||
#include "hailo/expected.hpp"
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
// 12 for the octets (3 * 4, each octet<=255)
|
||||
// 3 for the dots (".")
|
||||
// 1 for the terminating null
|
||||
#define IPV4_STRING_MAX_LENGTH (16)
|
||||
|
||||
#define PADDING_BYTES_SIZE (6)
|
||||
#define PADDING_ALIGN_BYTES (8 - PADDING_BYTES_SIZE)
|
||||
#define MIN_UDP_PAYLOAD_SIZE (24)
|
||||
#define MAX_UDP_PAYLOAD_SIZE (1456)
|
||||
#define MAX_UDP_PADDED_PAYLOAD_SIZE (MAX_UDP_PAYLOAD_SIZE - PADDING_BYTES_SIZE - PADDING_ALIGN_BYTES)
|
||||
|
||||
#define CHECK_VALID_SOCKET_AS_EXPECTED(sock) CHECK((sock) != INVALID_SOCKET, make_unexpected(HAILO_ETH_FAILURE), "Invalid socket")
|
||||
|
||||
class Socket final {
|
||||
public:
|
||||
static Expected<Socket> create(int af, int type, int protocol);
|
||||
~Socket();
|
||||
Socket(const Socket &other) = delete;
|
||||
Socket &operator=(const Socket &other) = delete;
|
||||
Socket &operator=(Socket &&other) = delete;
|
||||
Socket(Socket &&other) noexcept :
|
||||
m_module_wrapper(std::move(other.m_module_wrapper)), m_socket_fd(std::exchange(other.m_socket_fd, INVALID_SOCKET))
|
||||
{};
|
||||
|
||||
static hailo_status ntop(int af, const void *src, char *dst, socklen_t size);
|
||||
static hailo_status pton(int af, const char *src, void *dst);
|
||||
|
||||
hailo_status socket_bind(const sockaddr *addr, socklen_t len);
|
||||
hailo_status get_sock_name(sockaddr *addr, socklen_t *len);
|
||||
|
||||
hailo_status set_recv_buffer_size_max();
|
||||
hailo_status set_timeout(const std::chrono::milliseconds timeout_ms, timeval_t *timeout);
|
||||
hailo_status enable_broadcast();
|
||||
hailo_status abort();
|
||||
|
||||
// TODO: Should these be in udp.cpp?
|
||||
// TODO: Work with const Buffer& instead of uint8_t*
|
||||
hailo_status send_to(const uint8_t *src_buffer, size_t src_buffer_size, int flags,
|
||||
const sockaddr *dest_addr, socklen_t dest_addr_size, size_t *bytes_sent);
|
||||
hailo_status recv_from(uint8_t *dest_buffer, size_t dest_buffer_size, int flags,
|
||||
sockaddr *src_addr, socklen_t src_addr_size, size_t *bytes_received, bool log_timeouts_in_debug = false);
|
||||
hailo_status has_data(sockaddr *src_addr, socklen_t src_addr_size, bool log_timeouts_in_debug = false);
|
||||
|
||||
private:
|
||||
class SocketModuleWrapper final {
|
||||
public:
|
||||
static Expected<SocketModuleWrapper> create()
|
||||
{
|
||||
auto status = HAILO_UNINITIALIZED;
|
||||
auto obj = SocketModuleWrapper(status);
|
||||
CHECK_SUCCESS_AS_EXPECTED(status);
|
||||
return obj;
|
||||
}
|
||||
|
||||
SocketModuleWrapper(hailo_status &status)
|
||||
{
|
||||
status = init_module();
|
||||
}
|
||||
|
||||
SocketModuleWrapper(const SocketModuleWrapper &other) = delete;
|
||||
SocketModuleWrapper &operator=(const SocketModuleWrapper &other) = delete;
|
||||
SocketModuleWrapper &operator=(SocketModuleWrapper &&other) = delete;
|
||||
SocketModuleWrapper(SocketModuleWrapper &&other) noexcept = default;
|
||||
|
||||
~SocketModuleWrapper()
|
||||
{
|
||||
auto status = free_module();
|
||||
if (HAILO_SUCCESS != status) {
|
||||
LOGGER__ERROR("Failed to free socket module.");
|
||||
}
|
||||
}
|
||||
private:
|
||||
static hailo_status init_module();
|
||||
static hailo_status free_module();
|
||||
};
|
||||
|
||||
Socket(SocketModuleWrapper &&module_wrapper, const socket_t socket_fd);
|
||||
static Expected<socket_t> create_socket_fd(int af, int type, int protocol);
|
||||
hailo_status close_socket_fd();
|
||||
|
||||
// Itialization dependency
|
||||
SocketModuleWrapper m_module_wrapper;
|
||||
socket_t m_socket_fd;
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* __OS_SOCKET_H__ */
|
||||
74
hailort/common/string_utils.cpp
Normal file
74
hailort/common/string_utils.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file string_utils.cpp
|
||||
* @brief Utilities for string
|
||||
**/
|
||||
|
||||
#include "common/string_utils.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
// TODO: make it templated
|
||||
Expected<uint32_t> StringUtils::to_uint32(const std::string &str, int base)
|
||||
{
|
||||
errno = 0;
|
||||
char *end_pointer = nullptr;
|
||||
|
||||
auto value = strtoul(str.c_str(), &end_pointer, base);
|
||||
static_assert(sizeof(value) >= sizeof(uint32_t), "Size of value must be equal or greater than size of uint32_t");
|
||||
CHECK_AS_EXPECTED(errno == 0, HAILO_INVALID_ARGUMENT, "Failed to convert string {} to uint32_t. strtoul failed with errno {}", str, errno);
|
||||
CHECK_AS_EXPECTED(((*end_pointer == '\0') || (*end_pointer == '\n') || (*end_pointer == ' ') || (*end_pointer == '\r')),
|
||||
HAILO_INVALID_ARGUMENT, "Failed to convert string {} to uint32_t. strtoul failed with errno {}", str, errno);
|
||||
if ((value == 0) && (end_pointer == str)) {
|
||||
LOGGER__ERROR("Failed to convert string {} to uint32_t.", str);
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
CHECK_AS_EXPECTED(((value >= std::numeric_limits<uint32_t>::min()) && (value <= std::numeric_limits<uint32_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed to convert string {} to uint32_t.", str);
|
||||
|
||||
return static_cast<uint32_t>(value);
|
||||
}
|
||||
|
||||
// TODO: make it templated
|
||||
Expected<int32_t> StringUtils::to_int32(const std::string &str, int base)
|
||||
{
|
||||
errno = 0;
|
||||
char *end_pointer = nullptr;
|
||||
|
||||
auto value = strtol(str.c_str(), &end_pointer, base);
|
||||
static_assert(sizeof(value) >= sizeof(int32_t), "Size of value must be equal or greater than size of int32_t");
|
||||
CHECK_AS_EXPECTED(errno == 0, HAILO_INVALID_ARGUMENT, "Failed to convert string {} to int32_t. strtol failed with errno {}", str, errno);
|
||||
CHECK_AS_EXPECTED(((*end_pointer == '\0') || (*end_pointer == '\n') || (*end_pointer == ' ') || (*end_pointer == '\r')),
|
||||
HAILO_INVALID_ARGUMENT, "Failed to convert string {} to int32_t. strtoul failed with errno {}", str, errno);
|
||||
if ((value == 0) && (end_pointer == str)) {
|
||||
LOGGER__ERROR("Failed to convert string {} to int32_t.", str);
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
CHECK_AS_EXPECTED(((value >= std::numeric_limits<int32_t>::min()) && (value <= std::numeric_limits<int32_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed to convert string {} to int32.", str);
|
||||
|
||||
return static_cast<int32_t>(value);
|
||||
}
|
||||
|
||||
Expected<uint8_t> StringUtils::to_uint8(const std::string &str, int base)
|
||||
{
|
||||
auto number = to_uint32(str, base);
|
||||
CHECK_EXPECTED(number);
|
||||
|
||||
CHECK_AS_EXPECTED(((number.value() >= std::numeric_limits<uint8_t>::min()) && (number.value() <= std::numeric_limits<uint8_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed to convert string {} to uint8_t.", str);
|
||||
|
||||
return static_cast<uint8_t>(number.value());
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
28
hailort/common/string_utils.hpp
Normal file
28
hailort/common/string_utils.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file string_utils.hpp
|
||||
* @brief Defines utilities methods for string.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_STRING_UTILS_HPP_
|
||||
#define _HAILO_STRING_UTILS_HPP_
|
||||
|
||||
#include "hailo/expected.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class StringUtils {
|
||||
public:
|
||||
static Expected<int32_t> to_int32(const std::string &str, int base);
|
||||
static Expected<uint8_t> to_uint8(const std::string &str, int base);
|
||||
static Expected<uint32_t> to_uint32(const std::string &str, int base);
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _HAILO_STRING_UTILS_HPP_ */
|
||||
246
hailort/common/utils.hpp
Normal file
246
hailort/common/utils.hpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file utils.hpp
|
||||
* @brief TODO: brief
|
||||
*
|
||||
* TODO: doc
|
||||
**/
|
||||
|
||||
#ifndef HAILO_UTILS_H_
|
||||
#define HAILO_UTILS_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <hailo/hailort.h>
|
||||
#include "common/logger_macros.hpp"
|
||||
#include <spdlog/fmt/bundled/core.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
#define IS_FIT_IN_UINT8(number) ((std::numeric_limits<uint8_t>::max() >= ((int32_t)(number))) && (std::numeric_limits<uint8_t>::min() <= ((int32_t)(number))))
|
||||
#define IS_FIT_IN_UINT16(number) ((std::numeric_limits<uint16_t>::max() >= ((int32_t)(number))) && (std::numeric_limits<uint16_t>::min() <= ((int32_t)(number))))
|
||||
|
||||
#define IS_FIT_IN_UINT16(number) ((std::numeric_limits<uint16_t>::max() >= ((int32_t)(number))) && (std::numeric_limits<uint16_t>::min() <= ((int32_t)(number))))
|
||||
|
||||
|
||||
template <typename T>
|
||||
static inline bool contains(const std::vector<T> &container, const T &value)
|
||||
{
|
||||
return std::find(container.begin(), container.end(), value) != container.end();
|
||||
}
|
||||
|
||||
template <typename T, typename Q>
|
||||
static inline bool contains(const std::map<Q, T> &container, Q value)
|
||||
{
|
||||
return (container.find(value) != container.end());
|
||||
}
|
||||
|
||||
template <typename T, typename Q>
|
||||
static inline bool contains(const std::unordered_map<Q, T> &container, Q value)
|
||||
{
|
||||
return (container.find(value) != container.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool contains(const std::set<T> &container, T value)
|
||||
{
|
||||
return (container.find(value) != container.end());
|
||||
}
|
||||
|
||||
// From https://stackoverflow.com/questions/57092289/do-stdmake-shared-and-stdmake-unique-have-a-nothrow-version
|
||||
template <class T, class... Args>
|
||||
static inline std::unique_ptr<T> make_unique_nothrow(Args&&... args)
|
||||
noexcept(noexcept(T(std::forward<Args>(args)...)))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
auto ptr = std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
if (nullptr == ptr) {
|
||||
LOGGER__ERROR("make_unique failed, pointer is null!");
|
||||
}
|
||||
return ptr;
|
||||
#else
|
||||
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
static inline std::shared_ptr<T> make_shared_nothrow(Args&&... args)
|
||||
noexcept(noexcept(T(std::forward<Args>(args)...)))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
auto ptr = std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
if (nullptr == ptr) {
|
||||
LOGGER__ERROR("make_shared failed, pointer is null!");
|
||||
}
|
||||
return ptr;
|
||||
#else
|
||||
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ASSERT assert
|
||||
|
||||
#define ARRAY_ENTRIES(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define RETURN_IF_ARG_NULL(arg) \
|
||||
do { \
|
||||
if (NULL == (arg)) { \
|
||||
LOGGER__ERROR("Invalid argument: "#arg); \
|
||||
return HAILO_INVALID_ARGUMENT; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define _FREE(var, invalid_value, func) \
|
||||
do { \
|
||||
if ((invalid_value) != (var)) { \
|
||||
free(var); \
|
||||
var = (invalid_value); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define FREE(p) _FREE(p, NULL, free)
|
||||
|
||||
#define _CLOSE(var, invalid_var_value, func, invalid_func_result, status) \
|
||||
do { \
|
||||
if ((invalid_var_value) != (var)) { \
|
||||
if ((invalid_func_result) == func(var)) { \
|
||||
LOGGER__ERROR("CLOSE failed"); \
|
||||
if (HAILO_SUCCESS == (status)) { \
|
||||
status = HAILO_CLOSE_FAILURE; \
|
||||
} \
|
||||
else { \
|
||||
LOGGER__ERROR("Not setting status to HAILO_CLOSE_FAILURE since it is not HAILO_SUCCESS"); \
|
||||
} \
|
||||
} \
|
||||
var = (invalid_var_value); \
|
||||
} \
|
||||
} while(0)
|
||||
// TODO: Add tests in tests/utils/main.cpp
|
||||
|
||||
#define CLOSE(fd, status) _CLOSE(fd, -1, close, -1, status)
|
||||
#define FCLOSE(file, status) _CLOSE(file, NULL, fclose, 0, status)
|
||||
|
||||
|
||||
// Detect empty macro arguments
|
||||
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
|
||||
#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
|
||||
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
|
||||
#define _TRIGGER_PARENTHESIS_(...) ,
|
||||
|
||||
#define ISEMPTY(...) \
|
||||
_ISEMPTY( \
|
||||
/* test if there is just one argument, eventually an empty \
|
||||
one */ \
|
||||
HAS_COMMA(__VA_ARGS__), \
|
||||
/* test if _TRIGGER_PARENTHESIS_ together with the argument \
|
||||
adds a comma */ \
|
||||
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
|
||||
/* test if the argument together with a parenthesis \
|
||||
adds a comma */ \
|
||||
HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
|
||||
/* test if placing it between _TRIGGER_PARENTHESIS_ and the \
|
||||
parenthesis adds a comma */ \
|
||||
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
|
||||
)
|
||||
|
||||
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
|
||||
#define _ISEMPTY(_0, _1, _2, _3) HAS_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
|
||||
#define _IS_EMPTY_CASE_0001 ,
|
||||
//
|
||||
|
||||
#define __CONSTRUCT_MSG_1(dft_fmt, usr_fmt, ...) dft_fmt, ##__VA_ARGS__
|
||||
#define __CONSTRUCT_MSG_0(dft_fmt, usr_fmt, ...) dft_fmt " - " usr_fmt, ##__VA_ARGS__
|
||||
#define __CONSTRUCT_MSG(is_dft, dft_fmt, usr_fmt, ...) __CONSTRUCT_MSG_##is_dft(dft_fmt, usr_fmt, ##__VA_ARGS__)
|
||||
#define _CONSTRUCT_MSG(is_dft, dft_fmt, usr_fmt, ...) __CONSTRUCT_MSG(is_dft, dft_fmt, usr_fmt, ##__VA_ARGS__)
|
||||
#define CONSTRUCT_MSG(dft_fmt, ...) _CONSTRUCT_MSG(ISEMPTY(__VA_ARGS__), dft_fmt, "" __VA_ARGS__)
|
||||
|
||||
|
||||
#define _CHECK(cond, ret_val, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
LOGGER__ERROR(__VA_ARGS__); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/** Returns ret_val when cond is false */
|
||||
#define CHECK(cond, ret_val, ...) _CHECK((cond), (ret_val), CONSTRUCT_MSG("CHECK failed", ##__VA_ARGS__))
|
||||
#define CHECK_AS_EXPECTED(cond, ret_val, ...) \
|
||||
_CHECK((cond), (make_unexpected(ret_val)), CONSTRUCT_MSG("CHECK_AS_EXPECTED failed", ##__VA_ARGS__))
|
||||
|
||||
#define CHECK_ARG_NOT_NULL(arg) _CHECK(nullptr != (arg), HAILO_INVALID_ARGUMENT, "CHECK_ARG_NOT_NULL for {} failed", #arg)
|
||||
|
||||
#define CHECK_ARG_NOT_NULL_AS_EXPECTED(arg) _CHECK(nullptr != (arg), make_unexpected(HAILO_INVALID_ARGUMENT), "CHECK_ARG_NOT_NULL_AS_EXPECTED for {} failed", #arg)
|
||||
|
||||
#define CHECK_NOT_NULL(arg, status) _CHECK(nullptr != (arg), status, "CHECK_NOT_NULL for {} failed", #arg)
|
||||
|
||||
#define CHECK_NOT_NULL_AS_EXPECTED(arg, status) _CHECK(nullptr != (arg), make_unexpected(status), "CHECK_NOT_NULL_AS_EXPECTED for {} failed", #arg)
|
||||
|
||||
#define _CHECK_SUCCESS(status, is_default, fmt, ...) \
|
||||
do { \
|
||||
const auto &__check_success_status = (status); \
|
||||
_CHECK( \
|
||||
HAILO_SUCCESS == __check_success_status, \
|
||||
__check_success_status, \
|
||||
_CONSTRUCT_MSG(is_default, "CHECK_SUCCESS failed with status={}", fmt, __check_success_status, ##__VA_ARGS__) \
|
||||
); \
|
||||
} while(0)
|
||||
#define CHECK_SUCCESS(status, ...) _CHECK_SUCCESS(status, ISEMPTY(__VA_ARGS__), "" __VA_ARGS__)
|
||||
|
||||
#define _CHECK_SUCCESS_AS_EXPECTED(status, is_default, fmt, ...) \
|
||||
do { \
|
||||
const auto &__check_success_status = (status); \
|
||||
_CHECK( \
|
||||
HAILO_SUCCESS == __check_success_status, \
|
||||
make_unexpected(__check_success_status), \
|
||||
_CONSTRUCT_MSG(is_default, "CHECK_SUCCESS_AS_EXPECTED failed with status={}", fmt, __check_success_status, ##__VA_ARGS__) \
|
||||
); \
|
||||
} while(0)
|
||||
#define CHECK_SUCCESS_AS_EXPECTED(status, ...) _CHECK_SUCCESS_AS_EXPECTED(status, ISEMPTY(__VA_ARGS__), "" __VA_ARGS__)
|
||||
|
||||
#define _CHECK_EXPECTED(obj, is_default, fmt, ...) \
|
||||
do { \
|
||||
const auto &__check_expected_obj = (obj); \
|
||||
_CHECK( \
|
||||
__check_expected_obj.has_value(), \
|
||||
make_unexpected(__check_expected_obj.status()), \
|
||||
_CONSTRUCT_MSG(is_default, "CHECK_EXPECTED failed with status={}", fmt, __check_expected_obj.status(), ##__VA_ARGS__) \
|
||||
); \
|
||||
} while(0)
|
||||
#define CHECK_EXPECTED(obj, ...) _CHECK_EXPECTED(obj, ISEMPTY(__VA_ARGS__), "" __VA_ARGS__)
|
||||
|
||||
|
||||
#define _CHECK_EXPECTED_AS_STATUS(obj, is_default, fmt, ...) \
|
||||
do { \
|
||||
const auto &__check_expected_obj = (obj); \
|
||||
_CHECK( \
|
||||
__check_expected_obj.has_value(), \
|
||||
__check_expected_obj.status(), \
|
||||
_CONSTRUCT_MSG(is_default, "CHECK_EXPECTED_AS_STATUS failed with status={}", fmt, __check_expected_obj.status(), ##__VA_ARGS__) \
|
||||
); \
|
||||
} while(0)
|
||||
#define CHECK_EXPECTED_AS_STATUS(obj, ...) _CHECK_EXPECTED_AS_STATUS(obj, ISEMPTY(__VA_ARGS__), "" __VA_ARGS__)
|
||||
|
||||
constexpr bool is_powerof2(size_t v) {
|
||||
// bit trick
|
||||
return (v & (v - 1)) == 0;
|
||||
}
|
||||
|
||||
constexpr uint32_t get_nearest_powerof_2(uint32_t value, uint32_t min_power_of_2)
|
||||
{
|
||||
assert(value <= 0x80000000);
|
||||
uint32_t power_of_2 = min_power_of_2;
|
||||
while (value > power_of_2) {
|
||||
power_of_2 <<= 1;
|
||||
}
|
||||
return power_of_2;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* HAILO_UTILS_H_ */
|
||||
349
hailort/drivers/common/hailo_ioctl_common.h
Normal file
349
hailort/drivers/common/hailo_ioctl_common.h
Normal file
@@ -0,0 +1,349 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT
|
||||
/**
|
||||
* Copyright (c) 2019-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_IOCTL_COMMON_H_
|
||||
#define _HAILO_IOCTL_COMMON_H_
|
||||
|
||||
// This value is not easily changeable.
|
||||
// For example: the channel interrupts ioctls assume we have up to 32 channels
|
||||
#define MAX_VDMA_CHANNELS (32)
|
||||
#define SIZE_OF_VDMA_DESCRIPTOR (16)
|
||||
#define VDMA_DEST_CHANNELS_START (16)
|
||||
|
||||
#define CHANNEL_IRQ_TIMESTAMPS_SIZE (128 * 2) // Should be same as MAX_IRQ_TIMESTAMPS_SIZE (hailort_driver.hpp)
|
||||
#define CHANNEL_IRQ_TIMESTAMPS_SIZE_MASK (CHANNEL_IRQ_TIMESTAMPS_SIZE - 1)
|
||||
|
||||
#define INVALID_CHANNEL_HANDLE_VALUE ((uint64_t)-1)
|
||||
#define INVALID_DRIVER_HANDLE_VALUE ((uintptr_t)-1)
|
||||
|
||||
// Used by windows and unix driver to raise the right CPU control handle to the FW. The same as in pcie_service FW
|
||||
#define FW_ACCESS_CORE_CPU_CONTROL_SHIFT (1)
|
||||
#define FW_ACCESS_CORE_CPU_CONTROL_MASK (1 << FW_ACCESS_CORE_CPU_CONTROL_SHIFT)
|
||||
#define FW_ACCESS_CONTROL_INTERRUPT_SHIFT (0)
|
||||
#define FW_ACCESS_APP_CPU_CONTROL_MASK (1 << FW_ACCESS_CONTROL_INTERRUPT_SHIFT)
|
||||
|
||||
#define INVALID_VDMA_CHANNEL (0xff)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined(bool) && !defined(__cplusplus)
|
||||
typedef uint8_t bool;
|
||||
#endif
|
||||
#if !defined(INT_MAX)
|
||||
#define INT_MAX 0x7FFFFFFF
|
||||
#endif
|
||||
#else
|
||||
#ifndef __KERNEL__
|
||||
// include the userspace headers only if this file is included by user space program
|
||||
// It is discourged to include them when compiling the driver (https://lwn.net/Articles/113349/)
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <linux/types.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/kernel.h>
|
||||
#endif
|
||||
|
||||
#if defined(__unix__)
|
||||
#include <linux/ioctl.h>
|
||||
#endif
|
||||
|
||||
#define _IOW_ _IOW
|
||||
#define _IOR_ _IOR
|
||||
#define _IOWR_ _IOWR
|
||||
#define _IO_ _IO
|
||||
|
||||
#define HAILO_GENERAL_IOCTL_MAGIC 'g'
|
||||
#define HAILO_VDMA_IOCTL_MAGIC 'v'
|
||||
#define HAILO_WINDOWS_IOCTL_MAGIC 'w'
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct hailo_channel_interrupt_timestamp {
|
||||
uint64_t timestamp_ns;
|
||||
uint16_t desc_num_processed;
|
||||
};
|
||||
|
||||
// This struct is the same as `enum dma_data_direction` (defined in linux/dma-direction)
|
||||
enum hailo_dma_data_direction {
|
||||
HAILO_DMA_BIDIRECTIONAL = 0,
|
||||
HAILO_DMA_TO_DEVICE = 1,
|
||||
HAILO_DMA_FROM_DEVICE = 2,
|
||||
HAILO_DMA_NONE = 3,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
HAILO_DMA_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
// Enum that determines if buffer should be allocated from user space or from driver
|
||||
enum hailo_allocation_mode {
|
||||
HAILO_ALLOCATION_MODE_USERSPACE = 0,
|
||||
HAILO_ALLOCATION_MODE_DRIVER = 1,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
HAILO_ALLOCATION_MODE_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_BUFFER_MAP */
|
||||
struct hailo_vdma_buffer_map_params {
|
||||
void* user_address; // in
|
||||
size_t size; // in
|
||||
enum hailo_dma_data_direction data_direction; // in
|
||||
uintptr_t allocated_buffer_handle; // in
|
||||
size_t mapped_handle; // out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_DESC_LIST_CREATE */
|
||||
struct hailo_desc_list_create_params {
|
||||
size_t desc_count; // in
|
||||
uintptr_t desc_handle; // out
|
||||
// Note: The dma address is required for CONTEXT_SWITCH firmware controls
|
||||
uint64_t dma_address; // out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_WINDOWS_DESC_LIST_MMAP */
|
||||
struct hailo_windows_desc_list_mmap_params {
|
||||
uintptr_t desc_handle; // in
|
||||
size_t size; // in
|
||||
void* user_address; // out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_DESC_LIST_BIND_VDMA_BUFFER */
|
||||
struct hailo_desc_list_bind_vdma_buffer_params {
|
||||
size_t buffer_handle; // in
|
||||
uintptr_t desc_handle; // in
|
||||
uint16_t desc_page_size; // in
|
||||
uint8_t channel_index; // in
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_ENABLE */
|
||||
struct hailo_vdma_channel_enable_params {
|
||||
uint32_t channel_index; // in
|
||||
enum hailo_dma_data_direction direction; // in
|
||||
// If desc_list_handle is set to valid handle (different than INVALID_DRIVER_HANDLE_VALUE),
|
||||
// the driver will start the channel with the given descriptors list.
|
||||
uintptr_t desc_list_handle; // in
|
||||
bool enable_timestamps_measure; // in
|
||||
uint64_t channel_handle; // out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_DISABLE */
|
||||
struct hailo_vdma_channel_disable_params {
|
||||
uint32_t channel_index; // in
|
||||
uint64_t channel_handle; // in
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_WAIT_INT */
|
||||
struct hailo_vdma_channel_wait_params {
|
||||
uint32_t channel_index; // in
|
||||
uint64_t channel_handle; // in
|
||||
uint64_t timeout_ms; // in
|
||||
struct hailo_channel_interrupt_timestamp *timestamps; // out
|
||||
uint32_t timestamps_count; // inout
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_ABORT */
|
||||
struct hailo_vdma_channel_abort_params {
|
||||
uint32_t channel_index; // in
|
||||
uint64_t channel_handle; // in
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_CLEAR_ABORT */
|
||||
struct hailo_vdma_channel_clear_abort_params {
|
||||
uint32_t channel_index; // in
|
||||
uint64_t channel_handle; // in
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_FW_CONTROL */
|
||||
#define MAX_CONTROL_LENGTH (1500)
|
||||
#define PCIE_EXPECTED_MD5_LENGTH (16)
|
||||
|
||||
|
||||
/* structure used in ioctl HAILO_FW_CONTROL and HAILO_READ_LOG */
|
||||
enum hailo_cpu_id {
|
||||
HAILO_CPU_ID_CPU0 = 0,
|
||||
HAILO_CPU_ID_CPU1,
|
||||
HAILO_CPU_ID_NONE,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
HAILO_CPU_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
struct hailo_fw_control {
|
||||
// expected_md5+buffer_len+buffer must be in this order at the start of the struct
|
||||
uint8_t expected_md5[PCIE_EXPECTED_MD5_LENGTH];
|
||||
uint32_t buffer_len;
|
||||
uint8_t buffer[MAX_CONTROL_LENGTH];
|
||||
uint32_t timeout_ms;
|
||||
enum hailo_cpu_id cpu_id;
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_BAR_TRANSFER */
|
||||
enum hailo_transfer_direction {
|
||||
TRANSFER_READ = 0,
|
||||
TRANSFER_WRITE,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
TRANSFER_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
struct hailo_bar_transfer_params {
|
||||
enum hailo_transfer_direction transfer_direction; // in
|
||||
uint32_t bar_index; // in
|
||||
off_t offset; // in
|
||||
size_t count; // in
|
||||
void* buffer; // in/out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_CHANNEL_REGISTERS */
|
||||
struct hailo_channel_registers_params {
|
||||
enum hailo_transfer_direction transfer_direction; // in
|
||||
off_t offset; // in
|
||||
size_t size; // in
|
||||
uint32_t data; // in/out
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_VDMA_BUFFER_SYNC */
|
||||
enum hailo_vdma_buffer_sync_type {
|
||||
HAILO_SYNC_FOR_HOST,
|
||||
HAILO_SYNC_FOR_DEVICE,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
HAILO_SYNC_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
struct hailo_vdma_buffer_sync_params {
|
||||
size_t handle; // in
|
||||
enum hailo_vdma_buffer_sync_type sync_type; // in
|
||||
void* buffer_address; // in
|
||||
uint64_t buffer_size; // in
|
||||
};
|
||||
|
||||
/* structure used in ioctl HAILO_READ_NOTIFICATION */
|
||||
struct hailo_d2h_notification {
|
||||
size_t buffer_len; // out
|
||||
uint8_t buffer[MAX_CONTROL_LENGTH]; // out
|
||||
};
|
||||
|
||||
enum hailo_board_type {
|
||||
HAILO8 = 0,
|
||||
HAILO_MERCURY,
|
||||
HAILO_BOARD_COUNT,
|
||||
HAILO_INVALID_BOARD = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
enum hailo_dma_type {
|
||||
HAILO_DMA_TYPE_PCIE,
|
||||
HAILO_DMA_TYPE_DRAM,
|
||||
|
||||
/** Max enum value to maintain ABI Integrity */
|
||||
HAILO_DMA_TYPE_MAX_ENUM = INT_MAX,
|
||||
};
|
||||
|
||||
struct hailo_device_properties {
|
||||
uint16_t desc_max_page_size;
|
||||
enum hailo_board_type board_type;
|
||||
enum hailo_allocation_mode allocation_mode;
|
||||
enum hailo_dma_type dma_type;
|
||||
};
|
||||
|
||||
struct hailo_driver_info {
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
uint32_t revision_version;
|
||||
};
|
||||
struct hailo_read_log_params {
|
||||
enum hailo_cpu_id cpu_id; // in
|
||||
uint8_t *buffer; // out
|
||||
size_t buffer_size; // in
|
||||
size_t read_bytes; // out
|
||||
};
|
||||
|
||||
struct hailo_allocate_buffer_params {
|
||||
size_t buffer_size; // in
|
||||
uintptr_t buffer_handle; // out
|
||||
};
|
||||
|
||||
struct hailo_mark_as_in_use_params {
|
||||
bool in_use; // out
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
enum hailo_general_ioctl_code {
|
||||
HAILO_BAR_TRANSFER_CODE,
|
||||
HAILO_FW_CONTROL_CODE,
|
||||
HAILO_READ_NOTIFICATION_CODE,
|
||||
HAILO_DISABLE_NOTIFICATION_CODE,
|
||||
HAILO_QUERY_DEVICE_PROPERTIES_CODE,
|
||||
HAILO_QUERY_DRIVER_INFO_CODE,
|
||||
HAILO_READ_LOG_CODE,
|
||||
HAILO_RESET_NN_CORE_CODE,
|
||||
|
||||
// Must be last
|
||||
HAILO_GENERAL_IOCTL_MAX_NR,
|
||||
};
|
||||
|
||||
#define HAILO_BAR_TRANSFER _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_BAR_TRANSFER_CODE, struct hailo_bar_transfer_params)
|
||||
#define HAILO_FW_CONTROL _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control)
|
||||
#define HAILO_READ_NOTIFICATION _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification)
|
||||
#define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE)
|
||||
#define HAILO_QUERY_DEVICE_PROPERTIES _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DEVICE_PROPERTIES_CODE, struct hailo_device_properties)
|
||||
#define HAILO_QUERY_DRIVER_INFO _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_QUERY_DRIVER_INFO_CODE, struct hailo_driver_info)
|
||||
#define HAILO_READ_LOG _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_LOG_CODE, struct hailo_read_log_params)
|
||||
#define HAILO_RESET_NN_CORE _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_RESET_NN_CORE_CODE)
|
||||
|
||||
enum hailo_vdma_ioctl_code {
|
||||
HAILO_VDMA_CHANNEL_ENABLE_CODE,
|
||||
HAILO_VDMA_CHANNEL_DISABLE_CODE,
|
||||
HAILO_VDMA_CHANNEL_WAIT_INT_CODE,
|
||||
HAILO_VDMA_CHANNEL_ABORT_CODE,
|
||||
HAILO_VDMA_CHANNEL_CLEAR_ABORT_CODE,
|
||||
HAILO_VDMA_CHANNEL_REGISTERS_CODE,
|
||||
HAILO_VDMA_BUFFER_MAP_CODE,
|
||||
HAILO_VDMA_BUFFER_UNMAP_CODE,
|
||||
HAILO_VDMA_BUFFER_SYNC_CODE,
|
||||
HAILO_DESC_LIST_CREATE_CODE,
|
||||
HAILO_DESC_LIST_RELEASE_CODE,
|
||||
HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE,
|
||||
HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE,
|
||||
HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE,
|
||||
HAILO_MARK_AS_IN_USE_CODE,
|
||||
|
||||
// Must be last
|
||||
HAILO_VDMA_IOCTL_MAX_NR,
|
||||
};
|
||||
|
||||
#define HAILO_VDMA_CHANNEL_ENABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ENABLE_CODE, struct hailo_vdma_channel_enable_params)
|
||||
#define HAILO_VDMA_CHANNEL_DISABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_DISABLE_CODE, struct hailo_vdma_channel_disable_params)
|
||||
#define HAILO_VDMA_CHANNEL_WAIT_INT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_WAIT_INT_CODE, struct hailo_vdma_channel_wait_params)
|
||||
#define HAILO_VDMA_CHANNEL_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ABORT_CODE, struct hailo_vdma_channel_abort_params)
|
||||
#define HAILO_VDMA_CHANNEL_CLEAR_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_CLEAR_ABORT_CODE, struct hailo_vdma_channel_clear_abort_params)
|
||||
#define HAILO_VDMA_CHANNEL_REGISTERS _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_REGISTERS_CODE, struct hailo_channel_registers_params)
|
||||
|
||||
#define HAILO_VDMA_BUFFER_MAP _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_MAP_CODE, struct hailo_vdma_buffer_map_params)
|
||||
#define HAILO_VDMA_BUFFER_UNMAP _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_UNMAP_CODE)
|
||||
#define HAILO_VDMA_BUFFER_SYNC _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_SYNC_CODE, struct hailo_vdma_buffer_sync_params)
|
||||
|
||||
#define HAILO_DESC_LIST_CREATE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_CREATE_CODE, struct hailo_desc_list_create_params)
|
||||
#define HAILO_DESC_LIST_RELEASE _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_RELEASE_CODE)
|
||||
#define HAILO_DESC_LIST_BIND_VDMA_BUFFER _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_DESC_LIST_BIND_VDMA_BUFFER_CODE, struct hailo_desc_list_bind_vdma_buffer_params)
|
||||
|
||||
#define HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_ALLOC_CODE, struct hailo_allocate_buffer_params)
|
||||
#define HAILO_VDMA_LOW_MEMORY_BUFFER_FREE _IO_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_LOW_MEMORY_BUFFER_FREE_CODE)
|
||||
|
||||
#define HAILO_MARK_AS_IN_USE _IOW_(HAILO_VDMA_IOCTL_MAGIC, HAILO_MARK_AS_IN_USE_CODE, struct hailo_mark_as_in_use_params)
|
||||
|
||||
enum hailo_windows_ioctl_code {
|
||||
HAILO_WINDOWS_DESC_LIST_MMAP_CODE,
|
||||
|
||||
// Must be last
|
||||
HAILO_WINDOWS_IOCTL_MAX_NR,
|
||||
};
|
||||
|
||||
#define HAILO_WINDOWS_DESC_LIST_MMAP _IOWR_(HAILO_WINDOWS_IOCTL_MAGIC, HAILO_WINDOWS_DESC_LIST_MMAP_CODE, struct hailo_windows_desc_list_mmap_params)
|
||||
|
||||
|
||||
#endif /* _HAILO_IOCTL_COMMON_H_ */
|
||||
69
hailort/hailortcli/CMakeLists.txt
Normal file
69
hailort/hailortcli/CMakeLists.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
|
||||
set(HAILORTCLI_CPP_FILES
|
||||
hailortcli.cpp
|
||||
command.cpp
|
||||
scan_command.cpp
|
||||
run_command.cpp
|
||||
inference_progress.cpp
|
||||
power_measurement_command.cpp
|
||||
fw_control_command.cpp
|
||||
fw_update_command.cpp
|
||||
ssb_update_command.cpp
|
||||
infer_stats_printer.cpp
|
||||
sensor_config_command.cpp
|
||||
board_config_command.cpp
|
||||
fw_config_command.cpp
|
||||
fw_logger_command.cpp
|
||||
fw_config_serializer.cpp
|
||||
common.cpp
|
||||
benchmark_command.cpp
|
||||
temp_measurement.cpp
|
||||
parse_hef_command.cpp
|
||||
graph_printer.cpp
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
# Unix only modules
|
||||
set(HAILORTCLI_CPP_FILES ${HAILORTCLI_CPP_FILES}
|
||||
udp_rate_limiter_command.cpp
|
||||
# TODO: We dont compile download_action_list_command on windows, as it uses packed enums (HRT-5919)
|
||||
download_action_list_command.cpp
|
||||
|
||||
)
|
||||
endif()
|
||||
|
||||
# 'config_definitions_json_file' is used in generate_definitions_json_str.in for configure_file()
|
||||
file(READ "${PROJECT_SOURCE_DIR}/common/config_definitions.json" config_definitions_json_file)
|
||||
set(config_definitions_header ${CMAKE_CURRENT_BINARY_DIR}/definitions_json.auto.hpp)
|
||||
set(CONFIG_DEFENITIONS_IN ${PROJECT_SOURCE_DIR}/hailort/hailortcli/generate_definitions_json_str.in)
|
||||
configure_file(${CONFIG_DEFENITIONS_IN} ${config_definitions_header})
|
||||
|
||||
add_executable(hailortcli
|
||||
${config_definitions_header}
|
||||
${HAILORTCLI_CPP_FILES}
|
||||
${HAILORT_COMMON_CPP_SOURCES}
|
||||
${PROJECT_SOURCE_DIR}/common/src/firmware_header_utils.c
|
||||
${PROJECT_SOURCE_DIR}/common/src/md5.c
|
||||
${HAILORT_SRC_DIR}/pipeline.cpp
|
||||
${HAILO_FULL_OS_DIR}/event.cpp
|
||||
)
|
||||
target_compile_options(hailortcli PRIVATE ${HAILORT_COMPILE_OPTIONS})
|
||||
set_property(TARGET hailortcli PROPERTY CXX_STANDARD 14)
|
||||
set_property(TARGET hailortcli PROPERTY INSTALL_RPATH "$ORIGIN") # Need to add "${CMAKE_INSTALL_LIBDIR}" when installing with cmake to /usr/local
|
||||
target_link_libraries(hailortcli libhailort CLI11::CLI11 nlohmann_json spdlog::spdlog readerwriterqueue)
|
||||
target_link_libraries(hailortcli DotWriter)
|
||||
if(WIN32)
|
||||
target_link_libraries(hailortcli Ws2_32 Iphlpapi Shlwapi)
|
||||
endif()
|
||||
target_include_directories(hailortcli
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR} # CMAKE_CURRENT_BINARY_DIR is necessary for config_definitions_header
|
||||
${HAILORT_COMMON_DIR}
|
||||
${COMMON_INC_DIR}
|
||||
${HAILORT_SRC_DIR}
|
||||
)
|
||||
|
||||
install(TARGETS hailortcli
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
CONFIGURATIONS Release)
|
||||
137
hailort/hailortcli/benchmark_command.cpp
Normal file
137
hailort/hailortcli/benchmark_command.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file benchmark_command.cpp
|
||||
* @brief measure basic performance on compiled network
|
||||
**/
|
||||
|
||||
#include "benchmark_command.hpp"
|
||||
#include "hailortcli.hpp"
|
||||
#include "infer_stats_printer.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
BenchmarkCommand::BenchmarkCommand(CLI::App &parent_app) :
|
||||
Command(parent_app.add_subcommand("benchmark", "Measure basic performance on compiled network")),
|
||||
m_params({})
|
||||
{
|
||||
add_device_options(m_app, m_params.device_params);
|
||||
add_vdevice_options(m_app, m_params.device_params);
|
||||
m_params.measure_overall_latency = false;
|
||||
m_params.power_measurement.measure_current = false;
|
||||
m_params.show_progress = true;
|
||||
m_params.transform.format_type = HAILO_FORMAT_TYPE_AUTO;
|
||||
|
||||
m_app->add_option("hef", m_params.hef_path, "Path of the HEF to load")
|
||||
->check(CLI::ExistingFile)
|
||||
->required();
|
||||
m_app->add_option("-t, --time-to-run", m_time, "Measurement time in seconds per hw_only/streaming/latency measurement mode")
|
||||
->check(CLI::PositiveNumber)
|
||||
->default_val(15);
|
||||
m_app->add_option("--no-power", m_not_measure_power, "Skip power measurement, even if the platform supports it. The default value is False")
|
||||
->default_val("false");
|
||||
m_app->add_option("--batch-size", m_params.batch_size, "Inference batch size (default is 1)")
|
||||
->default_val(1);
|
||||
m_app->add_option("--input-files", m_params.inputs_name_and_file_path, " The input files need to be in UINT8 before transformations.")
|
||||
->check(InputNameToFileMap);
|
||||
m_app->add_option("--csv", m_csv_file_path, "If set print the output as csv to the specified path");
|
||||
|
||||
auto measure_power_group = m_app->add_option_group("Measure Power");
|
||||
CLI::Option *power_sampling_period = measure_power_group->add_option("--sampling-period",
|
||||
m_params.power_measurement.sampling_period, "Sampling Period");
|
||||
CLI::Option *power_averaging_factor = measure_power_group->add_option("--averaging-factor",
|
||||
m_params.power_measurement.averaging_factor, "Averaging Factor");
|
||||
PowerMeasurementSubcommand::init_sampling_period_option(power_sampling_period);
|
||||
PowerMeasurementSubcommand::init_averaging_factor_option(power_averaging_factor);
|
||||
|
||||
// TODO HRT-5363 support multiple devices
|
||||
m_app->parse_complete_callback([this]() {
|
||||
PARSE_CHECK((this->m_params.device_params.vdevice_params.device_count == 1) || this->m_csv_file_path.empty() || this->m_not_measure_power,
|
||||
"Writing power measurements in csv format is not supported for multiple devices");
|
||||
});
|
||||
}
|
||||
|
||||
hailo_status BenchmarkCommand::execute()
|
||||
{
|
||||
std::cout << "Starting Measurements..." << std::endl;
|
||||
|
||||
std::cout << "Measuring FPS in hw_only mode" << std::endl;
|
||||
auto hw_only_mode_info = hw_only_mode();
|
||||
CHECK_EXPECTED_AS_STATUS(hw_only_mode_info, "hw_only measuring failed");
|
||||
|
||||
std::cout << "Measuring FPS " << (!m_not_measure_power ? "and Power " : "") << "in streaming mode" << std::endl;
|
||||
auto streaming_mode_info = fps_streaming_mode();
|
||||
CHECK_EXPECTED_AS_STATUS(streaming_mode_info, "FPS in streaming mode failed");
|
||||
|
||||
std::cout << "Measuring HW Latency" << std::endl;
|
||||
auto latency_info = latency();
|
||||
CHECK_EXPECTED_AS_STATUS(latency_info, "Latency measuring failed");
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "=======" << std::endl;
|
||||
std::cout << "Summary" << std::endl;
|
||||
std::cout << "=======" << std::endl;
|
||||
std::cout << "FPS (hw_only) = " << hw_only_mode_info->fps().value() <<std::endl;
|
||||
std::cout << " (streaming) = " << streaming_mode_info->fps().value() <<std::endl;
|
||||
if (auto hw_latency = latency_info->hw_latency()) {
|
||||
std::cout << "Latency (hw) = " << InferResultsFormatUtils::latency_result_to_ms(hw_latency.value()) << " ms" << std::endl;
|
||||
}
|
||||
if (auto overall_latency = latency_info->overall_latency()) {
|
||||
std::cout << " (overall) = " << InferResultsFormatUtils::latency_result_to_ms(overall_latency.value()) << " ms" << std::endl;
|
||||
}
|
||||
if (!m_not_measure_power) {
|
||||
for (const auto &pair : streaming_mode_info->m_power_measurements) {
|
||||
std::cout << "Device " << pair.first << ":" << std::endl;
|
||||
const auto &data = pair.second->data();
|
||||
const auto &power_units = pair.second->power_units();
|
||||
std::cout << " Power in streaming mode (average) = " << data.average_value << " " << power_units << std::endl;
|
||||
std::cout << " (max) = " << data.max_value << " " << power_units << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!m_csv_file_path.empty()){
|
||||
m_params.csv_output = m_csv_file_path;
|
||||
auto printer = InferStatsPrinter::create(m_params, false);
|
||||
CHECK_EXPECTED_AS_STATUS(printer, "Failed to initialize infer stats printer");
|
||||
printer->print_benchmark_csv_header();
|
||||
printer->print_benchmark_csv(m_params.hef_path, hw_only_mode_info.release(),
|
||||
streaming_mode_info.release(), latency_info.release());
|
||||
}
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<NetworkGroupInferResult> BenchmarkCommand::hw_only_mode()
|
||||
{
|
||||
m_params.transform.transform = (m_params.inputs_name_and_file_path.size() > 0);
|
||||
m_params.power_measurement.measure_power = false;
|
||||
m_params.measure_latency = false;
|
||||
m_params.mode = InferMode::HW_ONLY;
|
||||
m_params.time_to_run = m_time;
|
||||
return run_command_hef(m_params);
|
||||
}
|
||||
|
||||
Expected<NetworkGroupInferResult> BenchmarkCommand::fps_streaming_mode()
|
||||
{
|
||||
m_params.power_measurement.measure_power = !m_not_measure_power;
|
||||
m_params.mode = InferMode::STREAMING;
|
||||
m_params.measure_latency = false;
|
||||
m_params.transform.transform = true;
|
||||
m_params.transform.quantized = false;
|
||||
m_params.time_to_run = m_time;
|
||||
return run_command_hef(m_params);
|
||||
}
|
||||
|
||||
Expected<NetworkGroupInferResult> BenchmarkCommand::latency()
|
||||
{
|
||||
m_params.power_measurement.measure_power = false;
|
||||
m_params.measure_latency = true;
|
||||
m_params.mode = InferMode::STREAMING;
|
||||
m_params.transform.transform = true;
|
||||
m_params.transform.quantized = false;
|
||||
m_params.time_to_run = m_time;
|
||||
return run_command_hef(m_params);
|
||||
}
|
||||
34
hailort/hailortcli/benchmark_command.hpp
Normal file
34
hailort/hailortcli/benchmark_command.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file benchmarks_command.hpp
|
||||
* @brief measure basic performance on compiled network
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_BENCHMARK_COMMAND_HPP_
|
||||
#define _HAILO_BENCHMARK_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
#include "run_command.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
class BenchmarkCommand : public Command {
|
||||
public:
|
||||
explicit BenchmarkCommand(CLI::App &parent_app);
|
||||
hailo_status execute() override;
|
||||
|
||||
private:
|
||||
Expected<NetworkGroupInferResult> hw_only_mode();
|
||||
Expected<NetworkGroupInferResult> fps_streaming_mode();
|
||||
Expected<NetworkGroupInferResult> latency();
|
||||
|
||||
inference_runner_params m_params;
|
||||
bool m_not_measure_power;
|
||||
uint32_t m_time;
|
||||
std::string m_csv_file_path;
|
||||
};
|
||||
|
||||
#endif /*_HAILO_BENCHMARK_COMMAND_HPP_*/
|
||||
63
hailort/hailortcli/board_config_command.cpp
Normal file
63
hailort/hailortcli/board_config_command.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file board_config_command.cpp
|
||||
* @brief Board configuration command (fw static configuration).
|
||||
**/
|
||||
|
||||
#include "board_config_command.hpp"
|
||||
#include "common/file_utils.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
BoardConfigCommand::BoardConfigCommand(CLI::App &parent_app) :
|
||||
ContainerCommand(parent_app.add_subcommand("board-config", "Board configuration tool"))
|
||||
{
|
||||
// This will make the board-config command to be hidden in the --help print in the command line.
|
||||
m_app->group("");
|
||||
|
||||
add_subcommand<BoardConfigReadSubcommand>();
|
||||
add_subcommand<BoardConfigWriteSubcommand>();
|
||||
}
|
||||
|
||||
BoardConfigReadSubcommand::BoardConfigReadSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("read", "Read board configuration from device"))
|
||||
{
|
||||
m_app->add_option("output_file", m_output_file_path, "File path to dump board configuration into.")
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status BoardConfigReadSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto buffer = device.read_board_config();
|
||||
CHECK_EXPECTED_AS_STATUS(buffer, "Failed reading board config from device");
|
||||
|
||||
auto output_file = std::ofstream(m_output_file_path, std::ios::out | std::ios::binary);
|
||||
CHECK(output_file.is_open(), HAILO_OPEN_FILE_FAILURE, "Failed opening output file {} with errno: {}", m_output_file_path, errno);
|
||||
|
||||
output_file.write(reinterpret_cast<char*>(buffer->data()), buffer->size());
|
||||
CHECK(output_file.good(), HAILO_FILE_OPERATION_FAILURE, "Failed writing board config into file {}.", m_output_file_path);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
BoardConfigWriteSubcommand::BoardConfigWriteSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("write", "Write board configuration to device"))
|
||||
{
|
||||
m_app->add_option("input_file", m_input_file_path, "Board config binary file path.")
|
||||
->check(CLI::ExistingFile)
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status BoardConfigWriteSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto buffer = read_binary_file(m_input_file_path);
|
||||
CHECK_EXPECTED_AS_STATUS(buffer);
|
||||
|
||||
hailo_status status = device.write_board_config(MemoryView(buffer.value()));
|
||||
CHECK_SUCCESS(status, "Failed writing board config to device.");
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
47
hailort/hailortcli/board_config_command.hpp
Normal file
47
hailort/hailortcli/board_config_command.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file board_config_command.hpp
|
||||
* @brief Firmware configuration command.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_BOARD_CONFIG_COMMAND_HPP_
|
||||
#define _HAILO_BOARD_CONFIG_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
class BoardConfigReadSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit BoardConfigReadSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_output_file_path;
|
||||
};
|
||||
|
||||
class BoardConfigWriteSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit BoardConfigWriteSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_input_file_path;
|
||||
};
|
||||
|
||||
class BoardConfigCommand final : public ContainerCommand {
|
||||
public:
|
||||
explicit BoardConfigCommand(CLI::App &parent_app);
|
||||
};
|
||||
|
||||
#endif /* _HAILO_BOARD_CONFIG_COMMAND_HPP_ */
|
||||
71
hailort/hailortcli/command.cpp
Normal file
71
hailort/hailortcli/command.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file command.cpp
|
||||
* @brief Base classes for hailortcli commands.
|
||||
**/
|
||||
|
||||
|
||||
#include "command.hpp"
|
||||
|
||||
Command::Command(CLI::App *app) :
|
||||
m_app(app)
|
||||
{
|
||||
}
|
||||
|
||||
ContainerCommand::ContainerCommand(CLI::App *app) :
|
||||
Command(app)
|
||||
{
|
||||
m_app->require_subcommand(1);
|
||||
}
|
||||
|
||||
hailo_status ContainerCommand::execute()
|
||||
{
|
||||
for (auto &command : m_subcommands) {
|
||||
if (command->parsed()) {
|
||||
return command->execute();
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER__ERROR("No subommand found..");
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
DeviceCommand::DeviceCommand(CLI::App *app) :
|
||||
Command(app)
|
||||
{
|
||||
add_device_options(m_app, m_device_params);
|
||||
}
|
||||
|
||||
hailo_status DeviceCommand::execute()
|
||||
{
|
||||
auto device = create_device(m_device_params);
|
||||
if (!device) {
|
||||
return device.status();
|
||||
}
|
||||
|
||||
return execute_on_device(*device.value());
|
||||
}
|
||||
|
||||
PcieDeviceCommand::PcieDeviceCommand(CLI::App *app) :
|
||||
Command(app)
|
||||
{
|
||||
auto group = app->add_option_group("PCIE Device Options");
|
||||
|
||||
// PCIe options
|
||||
group->add_option("-s,--bdf", m_pcie_device_params.pcie_bdf,
|
||||
"Device id ([<domain>]:<bus>:<device>.<func>, same as in lspci command)")
|
||||
->default_val("");
|
||||
}
|
||||
|
||||
hailo_status PcieDeviceCommand::execute()
|
||||
{
|
||||
auto device = create_pcie_device(m_pcie_device_params);
|
||||
if (!device) {
|
||||
return device.status();
|
||||
}
|
||||
|
||||
return execute_on_device(*device.value());
|
||||
}
|
||||
90
hailort/hailortcli/command.hpp
Normal file
90
hailort/hailortcli/command.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file command.hpp
|
||||
* @brief Base classes for hailortcli commands.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_COMMAND_HPP_
|
||||
#define _HAILO_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class Command {
|
||||
public:
|
||||
explicit Command(CLI::App *app);
|
||||
virtual ~Command() = default;
|
||||
|
||||
virtual hailo_status execute() = 0;
|
||||
|
||||
bool parsed() const
|
||||
{
|
||||
return m_app->parsed();
|
||||
}
|
||||
|
||||
void set_description(const std::string &new_desc)
|
||||
{
|
||||
m_app->description(new_desc);
|
||||
}
|
||||
|
||||
void set_footer(const std::string &new_footer)
|
||||
{
|
||||
m_app->footer(new_footer);
|
||||
}
|
||||
|
||||
protected:
|
||||
CLI::App *m_app;
|
||||
};
|
||||
|
||||
// Command that only contains list of subcommand
|
||||
class ContainerCommand : public Command {
|
||||
public:
|
||||
explicit ContainerCommand(CLI::App *app);
|
||||
virtual hailo_status execute() override final;
|
||||
|
||||
protected:
|
||||
|
||||
template<typename CommandType>
|
||||
CommandType &add_subcommand(bool hidden = false)
|
||||
{
|
||||
// Unnamed "option groups" hide subcommands/options from the help message
|
||||
// (see https://github.com/CLIUtils/CLI11/blob/main/README.md)
|
||||
auto *parent = hidden ? m_app->add_option_group("") : m_app;
|
||||
auto command = std::make_shared<CommandType>(*parent);
|
||||
m_subcommands.push_back(command);
|
||||
return *command;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Command>> m_subcommands;
|
||||
};
|
||||
|
||||
class DeviceCommand : public Command {
|
||||
public:
|
||||
explicit DeviceCommand(CLI::App *app);
|
||||
virtual hailo_status execute() override final;
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) = 0;
|
||||
|
||||
private:
|
||||
hailo_device_params m_device_params;
|
||||
};
|
||||
|
||||
class PcieDeviceCommand : public Command {
|
||||
public:
|
||||
explicit PcieDeviceCommand(CLI::App *app);
|
||||
virtual hailo_status execute() override final;
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) = 0;
|
||||
|
||||
private:
|
||||
hailo_pcie_params m_pcie_device_params;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_COMMAND_HPP_ */
|
||||
74
hailort/hailortcli/common.cpp
Normal file
74
hailort/hailortcli/common.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file common.cpp
|
||||
* @brief Common functions.
|
||||
**/
|
||||
#include "common.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
std::string CliCommon::duration_to_string(std::chrono::seconds secs)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
bool neg = (secs < 0s);
|
||||
if (neg) {
|
||||
secs = -secs;
|
||||
}
|
||||
|
||||
auto h = duration_cast<hours>(secs);
|
||||
secs -= h;
|
||||
auto m = duration_cast<minutes>(secs);
|
||||
secs -= m;
|
||||
|
||||
std::stringstream result;
|
||||
if (neg) {
|
||||
result << '-';
|
||||
}
|
||||
|
||||
if (h < 10h) {
|
||||
result << '0';
|
||||
}
|
||||
result << (h/1h) << ':';
|
||||
|
||||
if (m < 10min) {
|
||||
result << '0';
|
||||
}
|
||||
result << m/1min << ':';
|
||||
|
||||
if (secs < 10s) {
|
||||
result << '0';
|
||||
}
|
||||
result << secs/1s;
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
|
||||
Expected<std::string> CliCommon::current_time_to_string()
|
||||
{
|
||||
const auto curr_time = std::time(nullptr);
|
||||
CHECK_AS_EXPECTED(static_cast<std::time_t>(-1) != curr_time, HAILO_INTERNAL_FAILURE, "std::time failed");
|
||||
const auto *local_time = std::localtime(&curr_time);
|
||||
CHECK_AS_EXPECTED(nullptr != local_time, HAILO_INTERNAL_FAILURE, "std::localtime failed");
|
||||
|
||||
std::stringstream result;
|
||||
// Standard date and time string (see: https://en.cppreference.com/w/cpp/io/manip/put_time)
|
||||
result << std::put_time(local_time, "%c");
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void CliCommon::reset_cursor(size_t lines_count)
|
||||
{
|
||||
for (size_t i = 0; i < lines_count; i++) {
|
||||
std::cout << FORMAT_CURSOR_UP_LINE;
|
||||
}
|
||||
}
|
||||
53
hailort/hailortcli/common.hpp
Normal file
53
hailort/hailortcli/common.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file common.hpp
|
||||
* @brief Common functions.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_HAILORTCLI_COMMON_HPP_
|
||||
#define _HAILO_HAILORTCLI_COMMON_HPP_
|
||||
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
#include "common/filesystem.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
|
||||
using namespace hailort;
|
||||
|
||||
// http://www.climagic.org/mirrors/VT100_Escape_Codes.html
|
||||
#define FORMAT_CLEAR_LINE "\033[2K\r"
|
||||
#define FORMAT_CURSOR_UP_LINE "\033[F"
|
||||
|
||||
class CliCommon final
|
||||
{
|
||||
public:
|
||||
CliCommon() = delete;
|
||||
|
||||
static std::string duration_to_string(std::chrono::seconds secs);
|
||||
static Expected<std::string> current_time_to_string();
|
||||
static void reset_cursor(size_t number_of_lines);
|
||||
};
|
||||
|
||||
// Validators
|
||||
struct FileSuffixValidator : public CLI::Validator {
|
||||
FileSuffixValidator(const std::string &suffix) {
|
||||
name_ = "FILE_SUFFIX";
|
||||
func_ = [suffix](const std::string &filename) {
|
||||
if (!Filesystem::has_suffix(filename, suffix)) {
|
||||
std::stringstream error_message;
|
||||
error_message << "File '" << filename << "' does not end with suffix '"
|
||||
<< suffix << "'." << std::endl;
|
||||
return error_message.str();
|
||||
}
|
||||
// Success
|
||||
return std::string();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _HAILO_HAILORTCLI_COMMON_HPP_ */
|
||||
429
hailort/hailortcli/download_action_list_command.cpp
Normal file
429
hailort/hailortcli/download_action_list_command.cpp
Normal file
@@ -0,0 +1,429 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file download_action_list_command.cpp
|
||||
* @brief Download action list command implementation
|
||||
**/
|
||||
|
||||
#include "download_action_list_command.hpp"
|
||||
#include "common.hpp"
|
||||
#include "common/file_utils.hpp"
|
||||
#include "md5.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
constexpr int DownloadActionListCommand::INVALID_NUMERIC_VALUE;
|
||||
|
||||
DownloadActionListCommand::DownloadActionListCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("action-list", "Download action list data, for run time profiler"))
|
||||
{
|
||||
static const char *JSON_SUFFIX = ".json";
|
||||
m_app->add_option("--output-file", m_output_file_path, "Output file path")
|
||||
->default_val("context_action_list.json")
|
||||
->check(FileSuffixValidator(JSON_SUFFIX));
|
||||
}
|
||||
|
||||
hailo_status DownloadActionListCommand::execute(Device &device, const std::string &output_file_path,
|
||||
const ConfiguredNetworkGroupVector &network_groups, const std::string &hef_file_path)
|
||||
{
|
||||
std::cout << "> Writing action list to '" << output_file_path << "'... ";
|
||||
|
||||
auto curr_time = CliCommon::current_time_to_string();
|
||||
CHECK_EXPECTED_AS_STATUS(curr_time);
|
||||
|
||||
// TODO: Get real clock rate (HRT-5998)
|
||||
static const uint32_t CLOCK_CYCLE = 200;
|
||||
ordered_json action_list_json = {
|
||||
{"version", ACTION_LIST_FORMAT_VERSION()},
|
||||
{"creation_time", curr_time.release()},
|
||||
{"clock_cycle_MHz", CLOCK_CYCLE},
|
||||
{"hef", json({})}
|
||||
};
|
||||
|
||||
if (!hef_file_path.empty()) {
|
||||
auto hef_info = parse_hef_metadata(hef_file_path);
|
||||
CHECK_EXPECTED_AS_STATUS(hef_info);
|
||||
action_list_json["hef"] = hef_info.release();
|
||||
}
|
||||
|
||||
auto network_groups_list_json = parse_network_groups(device, network_groups);
|
||||
CHECK_EXPECTED_AS_STATUS(network_groups_list_json);
|
||||
action_list_json["network_groups"] = network_groups_list_json.release();
|
||||
|
||||
CHECK_SUCCESS(write_json(action_list_json, output_file_path));
|
||||
|
||||
std::cout << "done." << std::endl;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status DownloadActionListCommand::execute_on_device(Device &device)
|
||||
{
|
||||
return execute(device, m_output_file_path);
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_hef_metadata(const std::string &hef_file_path)
|
||||
{
|
||||
CHECK_AS_EXPECTED(is_valid_hef(hef_file_path), HAILO_INTERNAL_FAILURE,
|
||||
"Hef '{}' is not valid", hef_file_path);
|
||||
|
||||
auto hef_md5 = calc_md5_hexdigest(hef_file_path);
|
||||
CHECK_EXPECTED(hef_md5);
|
||||
|
||||
ordered_json hef_info_json = {
|
||||
{"path", hef_file_path},
|
||||
{"file_hash", hef_md5.release()}
|
||||
};
|
||||
|
||||
return hef_info_json;
|
||||
}
|
||||
|
||||
bool DownloadActionListCommand::is_valid_hef(const std::string &hef_file_path)
|
||||
{
|
||||
// Open hef, to check that it's valid
|
||||
const auto hef = Hef::create(hef_file_path);
|
||||
return hef.has_value();
|
||||
}
|
||||
|
||||
Expected<std::string> DownloadActionListCommand::calc_md5_hexdigest(const std::string &hef_file_path)
|
||||
{
|
||||
auto hef_bin = read_binary_file(hef_file_path);
|
||||
CHECK_EXPECTED(hef_bin);
|
||||
|
||||
MD5_CTX md5_ctx{};
|
||||
MD5_SUM_t md5_sum{};
|
||||
MD5_Init(&md5_ctx);
|
||||
MD5_Update(&md5_ctx, hef_bin->data(), hef_bin->size());
|
||||
MD5_Final(md5_sum, &md5_ctx);
|
||||
|
||||
std::stringstream hexdigest;
|
||||
for (uint32_t i = 0; i < ARRAY_ENTRIES(md5_sum); i++) {
|
||||
// cast to int needed for proper formatting
|
||||
hexdigest << std::hex << static_cast<int>(md5_sum[i]);
|
||||
}
|
||||
|
||||
return hexdigest.str();
|
||||
}
|
||||
|
||||
hailo_status DownloadActionListCommand::write_json(const ordered_json &json_obj, const std::string &output_file_path,
|
||||
int tab_width)
|
||||
{
|
||||
std::ofstream output_file(output_file_path);
|
||||
CHECK(output_file, HAILO_INTERNAL_FAILURE, "Failed opening file '{}'", output_file_path);
|
||||
|
||||
output_file << std::setw(tab_width) << json_obj << std::endl;
|
||||
CHECK(!output_file.bad() && !output_file.fail(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed writing to file '{}'", output_file_path);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_action_data(uint32_t base_address, uint8_t *action,
|
||||
uint32_t current_buffer_offset, uint32_t *action_length, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type,
|
||||
uint32_t timestamp, uint8_t sub_action_index, bool sub_action_index_set, bool *is_repeated, uint8_t *num_repeated,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t *sub_action_type)
|
||||
{
|
||||
ordered_json action_json {
|
||||
{"address", base_address + current_buffer_offset},
|
||||
{"timestamp", timestamp},
|
||||
{"type", action_type}
|
||||
};
|
||||
|
||||
if (sub_action_index_set) {
|
||||
action_json["sub_action_index"] = sub_action_index;
|
||||
}
|
||||
|
||||
size_t action_length_local = 0;
|
||||
json data_json;
|
||||
switch (action_type) {
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION:
|
||||
{
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__repeated_action_header_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t);
|
||||
const auto *repeated_header = reinterpret_cast<CONTEXT_SWITCH_DEFS__repeated_action_header_t *>(action);
|
||||
*is_repeated = true;
|
||||
*num_repeated = repeated_header->count;
|
||||
*sub_action_type = repeated_header->sub_action_type;
|
||||
break;
|
||||
}
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_LCU_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_SEQUENCER_DONE_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_INPUT_CHANNEL_TRANSFER_DONE_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_OUTPUT_CHANNEL_TRANSFER_DONE_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_MODULE_CONFIG_DONE_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_APPLICATION_CHANGE_INTERRUPT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__read_vdma_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__read_vdma_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__fetch_data_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__fetch_data_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_VDMA_CHANNEL:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_NON_DEFAULT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_DISABLE_LCU:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_INPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_OUTPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_INPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_OUTPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_INPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_OUTPUT:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_CHANGE_VDMA_TO_STREAM_MAPPING:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ADD_DDR_PAIR_INFO:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_START:
|
||||
data_json = json({});
|
||||
action_length_local = 0;
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_CFG_CHANNEL:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__activate_cfg_channel_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__activate_cfg_channel_t);
|
||||
break;
|
||||
case CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL:
|
||||
data_json = *reinterpret_cast<CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t *>(action);
|
||||
action_length_local = sizeof(CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PARSING ERROR ! unknown action main type" << std::endl;
|
||||
return make_unexpected(HAILO_INTERNAL_FAILURE);
|
||||
}
|
||||
action_json["data"] = data_json;
|
||||
*action_length = static_cast<uint32_t>(action_length_local);
|
||||
return action_json;
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_single_repeated_action(uint32_t base_address,
|
||||
uint8_t *action, uint32_t current_buffer_offset, uint32_t *action_length,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type, uint32_t timestamp, uint8_t index_in_repeated_block)
|
||||
{
|
||||
static const bool SET_SUB_ACTION_INDEX = true;
|
||||
return parse_action_data(base_address, action, current_buffer_offset, action_length,
|
||||
action_type, timestamp, index_in_repeated_block, SET_SUB_ACTION_INDEX);
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_single_action(uint32_t base_address,
|
||||
uint8_t *context_action_list, uint32_t current_buffer_offset, uint32_t *action_length, bool *is_repeated,
|
||||
uint8_t *num_repeated, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t *sub_action_type, uint32_t *time_stamp)
|
||||
{
|
||||
const auto action_length_local = sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t);
|
||||
const auto *action_header = reinterpret_cast<CONTEXT_SWITCH_DEFS__common_action_header_t *>(&context_action_list[current_buffer_offset]);
|
||||
const auto time_stamp_local = CONTEXT_SWITCH_DEFS__TIMESTAMP_INIT_VALUE - action_header->time_stamp;
|
||||
current_buffer_offset += static_cast<uint32_t>(sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t));
|
||||
|
||||
static const bool DONT_SET_SUB_ACTION_INDEX = false;
|
||||
uint32_t action_data_length = 0;
|
||||
auto json = parse_action_data(base_address, &context_action_list[current_buffer_offset], current_buffer_offset, &action_data_length,
|
||||
action_header->action_type, time_stamp_local, 0, DONT_SET_SUB_ACTION_INDEX, is_repeated, num_repeated, sub_action_type);
|
||||
CHECK_EXPECTED(json);
|
||||
*action_length = static_cast<uint32_t>(action_length_local + action_data_length);
|
||||
*time_stamp = time_stamp_local;
|
||||
return json.release();
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_context(uint32_t action_list_base_address,
|
||||
uint8_t *context_action_list, uint16_t action_list_size, uint32_t batch_counter)
|
||||
{
|
||||
ordered_json context_json {
|
||||
{"action_list_base_address", action_list_base_address},
|
||||
{"action_list_size", action_list_size },
|
||||
{"batch_counter", batch_counter}
|
||||
};
|
||||
|
||||
ordered_json action_list_json;
|
||||
uint16_t current_buffer_offset = 0;
|
||||
while (current_buffer_offset < action_list_size) {
|
||||
bool is_repeated = false;
|
||||
uint8_t num_repeated = 0;
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t sub_action_type = CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT;
|
||||
uint32_t single_action_length = 0;
|
||||
uint32_t timestamp = 0;
|
||||
auto action_json = parse_single_action(action_list_base_address, context_action_list,
|
||||
current_buffer_offset, &single_action_length, &is_repeated, &num_repeated, &sub_action_type, ×tamp);
|
||||
CHECK_EXPECTED(action_json);
|
||||
current_buffer_offset = (uint16_t)(current_buffer_offset + single_action_length);
|
||||
action_list_json.emplace_back(action_json.release());
|
||||
|
||||
if (is_repeated) {
|
||||
for (uint8_t index_in_repeated_block = 0; index_in_repeated_block < num_repeated; index_in_repeated_block++) {
|
||||
uint32_t sub_action_length = 0;
|
||||
auto repeated_action_json = parse_single_repeated_action(action_list_base_address,
|
||||
context_action_list + current_buffer_offset, current_buffer_offset, &sub_action_length,
|
||||
sub_action_type, timestamp, index_in_repeated_block);
|
||||
CHECK_EXPECTED(repeated_action_json);
|
||||
current_buffer_offset = (uint16_t)(current_buffer_offset + sub_action_length);
|
||||
action_list_json.emplace_back(repeated_action_json.release());
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK_AS_EXPECTED(current_buffer_offset == action_list_size, HAILO_INTERNAL_FAILURE,
|
||||
"PARSING ERROR ! Reached forbidden memory space");
|
||||
|
||||
context_json["actions"] = action_list_json;
|
||||
|
||||
return context_json;
|
||||
}
|
||||
|
||||
double DownloadActionListCommand::get_accumulator_mean_value(const AccumulatorPtr &accumulator, double default_value)
|
||||
{
|
||||
auto mean_value = accumulator->mean();
|
||||
return mean_value ? mean_value.value() : default_value;
|
||||
}
|
||||
|
||||
Expected<ordered_json> DownloadActionListCommand::parse_network_groups(Device &device, const ConfiguredNetworkGroupVector &network_groups)
|
||||
{
|
||||
const auto number_of_contexts_per_network_group = device.get_number_of_contexts_per_network_group();
|
||||
CHECK_EXPECTED(number_of_contexts_per_network_group);
|
||||
|
||||
ordered_json network_group_list_json;
|
||||
uint8_t global_context_index = 0;
|
||||
for (uint32_t network_group_index = 0; network_group_index < number_of_contexts_per_network_group->size(); network_group_index++) {
|
||||
// TODO: network_group_name via Hef::get_network_groups_names (HRT-5997)
|
||||
ordered_json network_group_json = {
|
||||
{"mean_activation_time_ms", INVALID_NUMERIC_VALUE},
|
||||
{"mean_deactivation_time_ms", INVALID_NUMERIC_VALUE},
|
||||
{"contexts", json::array()}
|
||||
};
|
||||
// We assume the the order of the network_groups in the ConfiguredNetworkGroupVector and in the action_list
|
||||
// downloaded from the fw is the same. If the received ConfiguredNetworkGroupVector is empty, we leave the
|
||||
// mean_de/activation_time_ms with their default values (INVALID_NUMERIC_VALUE).
|
||||
if (network_groups.size() > network_group_index) {
|
||||
network_group_json["mean_activation_time_ms"] = get_accumulator_mean_value(
|
||||
network_groups[network_group_index]->get_activation_time_accumulator());
|
||||
network_group_json["mean_deactivation_time_ms"] = get_accumulator_mean_value(
|
||||
network_groups[network_group_index]->get_deactivation_time_accumulator());
|
||||
}
|
||||
|
||||
const auto num_contexts_in_network_group = number_of_contexts_per_network_group.value()[network_group_index];
|
||||
for (uint8_t i = 0; i < num_contexts_in_network_group; i++) {
|
||||
uint32_t batch_counter = 0;
|
||||
uint32_t base_address = 0;
|
||||
auto action_list = device.download_context_action_list(global_context_index, &base_address, &batch_counter);
|
||||
CHECK_EXPECTED(action_list);
|
||||
// Needs to fit in 2 bytes due to firmware limitation of action list size
|
||||
CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(action_list->size()), HAILO_INTERNAL_FAILURE,
|
||||
"Action list size is expected to fit in 2B. actual size is {}", action_list->size());
|
||||
|
||||
auto context_json = parse_context(base_address, action_list->data(),
|
||||
static_cast<uint16_t>(action_list->size()), batch_counter);
|
||||
CHECK_EXPECTED(context_json);
|
||||
|
||||
network_group_json["contexts"].emplace_back(context_json.release());
|
||||
|
||||
// Device::get_number_of_contexts_per_network_group guarantees no overflow
|
||||
global_context_index++;
|
||||
}
|
||||
network_group_list_json.emplace_back(network_group_json);
|
||||
}
|
||||
|
||||
return network_group_list_json;
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__read_vdma_action_data_t& data) {
|
||||
j = json{{"descriptors_count", data.descriptors_count}, {"channel_index", data.cfg_channel_number}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t& data) {
|
||||
j = json{{"channel_index", data.cfg_channel_number}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t& data) {
|
||||
const auto cluster_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_READ(data.packed_lcu_id);
|
||||
const auto lcu_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_READ(data.packed_lcu_id);
|
||||
j = json{{"cluster_index", cluster_index}, {"lcu_index", lcu_index}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t& data) {
|
||||
const auto cluster_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_READ(data.packed_lcu_id);
|
||||
const auto lcu_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_READ(data.packed_lcu_id);
|
||||
j = json{{"cluster_index", cluster_index}, {"lcu_index", lcu_index}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t& data) {
|
||||
const auto cluster_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_READ(data.packed_lcu_id);
|
||||
const auto lcu_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_READ(data.packed_lcu_id);
|
||||
j = json{{"cluster_index", cluster_index}, {"lcu_index", lcu_index}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t& data) {
|
||||
j = json{{"vdma_channel_index", data.vdma_channel_index}, {"stream_index", data.stream_index},
|
||||
{"type", data.is_dummy_stream ? "dummy" : "active"}};
|
||||
}
|
||||
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t& data) {
|
||||
const auto cluster_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_READ(data.packed_lcu_id);
|
||||
const auto lcu_index = CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_LCU_INDEX_READ(data.packed_lcu_id);
|
||||
j = json{{"cluster_index", cluster_index}, {"lcu_index", lcu_index}};
|
||||
}
|
||||
126
hailort/hailortcli/download_action_list_command.hpp
Normal file
126
hailort/hailortcli/download_action_list_command.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file download_action_list_command.hpp
|
||||
* @brief Download action list command
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_DOWNLOAD_ACTION_LIST_COMMAND_HPP_
|
||||
#define _HAILO_DOWNLOAD_ACTION_LIST_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "context_switch_defs.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
class DownloadActionListCommand : public DeviceCommand
|
||||
{
|
||||
public:
|
||||
explicit DownloadActionListCommand(CLI::App &parent_app);
|
||||
// To be used from external commands
|
||||
static hailo_status execute(Device &device, const std::string &output_file_path,
|
||||
const ConfiguredNetworkGroupVector &network_groups={}, const std::string &hef_file_path="");
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_output_file_path;
|
||||
static constexpr int DEFAULT_JSON_TAB_WIDTH = 4;
|
||||
static constexpr int INVALID_NUMERIC_VALUE = -1;
|
||||
static std::string ACTION_LIST_FORMAT_VERSION() { return "1.0"; }
|
||||
|
||||
static Expected<ordered_json> parse_hef_metadata(const std::string &hef_file_path);
|
||||
static bool is_valid_hef(const std::string &hef_file_path);
|
||||
static Expected<std::string> calc_md5_hexdigest(const std::string &hef_file_path);
|
||||
static hailo_status write_json(const ordered_json &json_obj, const std::string &output_file_path,
|
||||
int tab_width = DEFAULT_JSON_TAB_WIDTH);
|
||||
static Expected<ordered_json> parse_action_data(uint32_t base_address, uint8_t *action,
|
||||
uint32_t current_buffer_offset, uint32_t *action_length, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type,
|
||||
uint32_t timestamp, uint8_t sub_action_index = 0, bool sub_action_index_set = false,
|
||||
bool *is_repeated = nullptr, uint8_t *num_repeated = nullptr,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t *sub_action_type = nullptr);
|
||||
static Expected<ordered_json> parse_single_repeated_action(uint32_t base_address, uint8_t *action,
|
||||
uint32_t current_buffer_offset, uint32_t *action_length, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type,
|
||||
uint32_t timestamp, uint8_t index_in_repeated_block);
|
||||
static Expected<ordered_json> parse_single_action(uint32_t base_address, uint8_t *context_action_list,
|
||||
uint32_t current_buffer_offset, uint32_t *action_length, bool *is_repeated, uint8_t *num_repeated,
|
||||
CONTEXT_SWITCH_DEFS__ACTION_TYPE_t *sub_action_type, uint32_t *time_stamp);
|
||||
static Expected<ordered_json> parse_context(uint32_t action_list_base_address, uint8_t *context_action_list,
|
||||
uint16_t action_list_size, uint32_t batch_counter);
|
||||
static double get_accumulator_mean_value(const AccumulatorPtr &accumulator, double default_value = INVALID_NUMERIC_VALUE);
|
||||
static Expected<ordered_json> parse_network_groups(Device &device, const ConfiguredNetworkGroupVector &network_groups);
|
||||
};
|
||||
|
||||
// JSON serialization
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(CONTEXT_SWITCH_DEFS__ACTION_TYPE_t, {
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_VDMA_DESCRIPTORS, "fetch_vdma_descriptors"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER, "trigger_sequencer"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL, "fetch_data_from_vdma_channel"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT, "enable_lcu_default"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_NON_DEFAULT, "enable_lcu_non_default"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DISABLE_LCU, "disable_lcu"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_INPUT, "activate_boundary_input"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_OUTPUT, "activate_boundary_output"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_INPUT, "activate_inter_context_input"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_OUTPUT, "activate_inter_context_output"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_INPUT, "activate_ddr_buffer_input"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_OUTPUT, "activate_ddr_buffer_output"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_VDMA_CHANNEL, "deactivate_vdma_channel"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_CHANGE_VDMA_TO_STREAM_MAPPING, "change_vdma_to_stream_mapping"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ADD_DDR_PAIR_INFO, "add_ddr_pair_info"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_START, "ddr_buffering_start"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_LCU_INTERRUPT, "lcu_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_SEQUENCER_DONE_INTERRUPT, "sequencer_done_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_INPUT_CHANNEL_TRANSFER_DONE_INTERRUPT, "input_channel_transfer_done_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_OUTPUT_CHANNEL_TRANSFER_DONE_INTERRUPT, "output_channel_transfer_done_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_MODULE_CONFIG_DONE_INTERRUPT, "module_config_done_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_APPLICATION_CHANGE_INTERRUPT, "application_change_interrupt"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_CFG_CHANNEL, "activate_cfg_channel"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL, "deactivate_cfg_channel"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION, "repeated_action"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION, "wait_for_dma_idle_action"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE, "wait_for_nms_idle"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS, "fetch_ccw_bursts"},
|
||||
{CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT, nullptr},
|
||||
});
|
||||
|
||||
// Default implementions
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__repeated_action_header_t, count, last_executed, sub_action_type);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t, cluster_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t, vdma_channel_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__fetch_data_action_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t, h2d_vdma_channel_index, d2h_vdma_channel_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t, vdma_channel_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t, sequencer_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t, aggregator_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t, module_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t, application_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t, vdma_channel_index, stream_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__activate_cfg_channel_t, channel_index);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t, channel_index);
|
||||
|
||||
// Non-default implementations
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__read_vdma_action_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t& data);
|
||||
void to_json(json& j, const CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t& data);
|
||||
|
||||
#endif /* _HAILO_DOWNLOAD_ACTION_LIST_COMMAND_HPP_ */
|
||||
96
hailort/hailortcli/fw_config_command.cpp
Normal file
96
hailort/hailortcli/fw_config_command.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_config_command.cpp
|
||||
* @brief User Firmware configuration (persistent config) command.
|
||||
**/
|
||||
|
||||
#include "fw_config_command.hpp"
|
||||
|
||||
FwConfigReadSubcommand::FwConfigReadSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("read", "Read firmware configuration from device"))
|
||||
{
|
||||
m_app->add_option("--output-file", m_output_file, "File path to write user firmware configuration into.\n"
|
||||
"If not given the data will be printed to stdout.");
|
||||
}
|
||||
|
||||
hailo_status FwConfigReadSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto user_config_buffer = device.read_user_config();
|
||||
CHECK_EXPECTED_AS_STATUS(user_config_buffer, "Failed reading user config from device");
|
||||
|
||||
auto status = FwConfigJsonSerializer::deserialize_config(
|
||||
*reinterpret_cast<USER_CONFIG_header_t*>(user_config_buffer->data()),
|
||||
user_config_buffer->size(), m_output_file);
|
||||
CHECK_SUCCESS(status);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwConfigWriteSubcommand::FwConfigWriteSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("write", "Write firmware configuration to device"))
|
||||
{
|
||||
m_app->add_option("input_file", m_input_file, "User firmware configuration file path.")
|
||||
->check(CLI::ExistingFile)
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status FwConfigWriteSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto config_buffer = Buffer::create(FLASH_USER_CONFIG_SECTION_SIZE);
|
||||
CHECK_EXPECTED_AS_STATUS(config_buffer);
|
||||
|
||||
auto config_size = FwConfigJsonSerializer::serialize_config(
|
||||
*reinterpret_cast<USER_CONFIG_header_t*>(config_buffer->data()), config_buffer->size(), m_input_file);
|
||||
CHECK_EXPECTED_AS_STATUS(config_size);
|
||||
|
||||
// We only need to write config_size.value() bytes from config_buffer, so we "resize" the buffer
|
||||
CHECK(config_buffer->size() >= config_size.value(), HAILO_INTERNAL_FAILURE,
|
||||
"Unexpected config size {} (max_size={})", config_size.value(), config_buffer->size());
|
||||
auto resized_config_buffer = Buffer::create(config_buffer->data(), config_size.value());
|
||||
CHECK_EXPECTED_AS_STATUS(resized_config_buffer);
|
||||
|
||||
hailo_status status = device.write_user_config(MemoryView(resized_config_buffer.value()));
|
||||
CHECK_SUCCESS(status, "Failed writing user firmware configuration to device");
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwConfigSerializeSubcommand::FwConfigSerializeSubcommand(CLI::App &parent_app) :
|
||||
Command(parent_app.add_subcommand("serialize", "Serialize firmware configuration json to a binary file"))
|
||||
{
|
||||
m_app->add_option("input_file", m_input_file, "File path to firmware configuration json")
|
||||
->check(CLI::ExistingFile)
|
||||
->required();
|
||||
m_app->add_option("output_file", m_output_file, "File path to write binary firmware configuration into")
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status FwConfigSerializeSubcommand::execute()
|
||||
{
|
||||
auto config_buffer = Buffer::create(FLASH_USER_CONFIG_SECTION_SIZE);
|
||||
CHECK_EXPECTED_AS_STATUS(config_buffer);
|
||||
|
||||
USER_CONFIG_header_t *config_header = reinterpret_cast<USER_CONFIG_header_t*>(config_buffer->data());
|
||||
auto config_size = FwConfigJsonSerializer::serialize_config(*config_header, config_buffer->size(), m_input_file);
|
||||
CHECK_EXPECTED_AS_STATUS(config_size);
|
||||
|
||||
std::ofstream ofs(m_output_file, std::ios::out | std::ios::binary);
|
||||
CHECK(ofs.good(), HAILO_OPEN_FILE_FAILURE, "Failed opening file: {}, with errno: {}", m_output_file, errno);
|
||||
|
||||
ofs.write(reinterpret_cast<char*>(config_header), config_size.value());
|
||||
CHECK(ofs.good(), HAILO_FILE_OPERATION_FAILURE,
|
||||
"Failed writing binary firmware configuration to file: {}, with errno: {}", m_output_file, errno);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwConfigCommand::FwConfigCommand(CLI::App &parent_app) :
|
||||
ContainerCommand(parent_app.add_subcommand("fw-config", "User firmware configuration tool"))
|
||||
{
|
||||
add_subcommand<FwConfigReadSubcommand>();
|
||||
add_subcommand<FwConfigWriteSubcommand>();
|
||||
add_subcommand<FwConfigSerializeSubcommand>();
|
||||
}
|
||||
59
hailort/hailortcli/fw_config_command.hpp
Normal file
59
hailort/hailortcli/fw_config_command.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_config_command.hpp
|
||||
* @brief User firmware configuration command.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FW_CONFIG_COMMAND_HPP_
|
||||
#define _HAILO_FW_CONFIG_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "fw_config_serializer.hpp"
|
||||
#include "hailo/device.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
#define FLASH_USER_CONFIG_SECTION_SIZE (0x008000)
|
||||
|
||||
class FwConfigReadSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit FwConfigReadSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_output_file;
|
||||
};
|
||||
|
||||
class FwConfigWriteSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit FwConfigWriteSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_input_file;
|
||||
};
|
||||
|
||||
class FwConfigSerializeSubcommand final : public Command {
|
||||
public:
|
||||
explicit FwConfigSerializeSubcommand(CLI::App &parent_app);
|
||||
hailo_status execute() override;
|
||||
|
||||
private:
|
||||
std::string m_input_file;
|
||||
std::string m_output_file;
|
||||
};
|
||||
|
||||
class FwConfigCommand final : public ContainerCommand {
|
||||
public:
|
||||
explicit FwConfigCommand(CLI::App &parent_app);
|
||||
};
|
||||
|
||||
#endif /* _HAILO_FW_CONFIG_COMMAND_HPP_ */
|
||||
904
hailort/hailortcli/fw_config_serializer.cpp
Normal file
904
hailort/hailortcli/fw_config_serializer.cpp
Normal file
@@ -0,0 +1,904 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_config_serializer.cpp
|
||||
* @brief User firmware configuration serializer.
|
||||
**/
|
||||
|
||||
#include "fw_config_serializer.hpp"
|
||||
#include "definitions_json.auto.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "user_config_common.h"
|
||||
#include "common/file_utils.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
Expected<ordered_json> FwConfigJsonSerializer::read_json_file(const std::string &file_path)
|
||||
{
|
||||
std::ifstream ifs(file_path);
|
||||
CHECK_AS_EXPECTED(ifs.good(), HAILO_OPEN_FILE_FAILURE, "Failed opening json file: {} with errno: {}", file_path, errno);
|
||||
|
||||
ordered_json j;
|
||||
ifs >> j;
|
||||
CHECK_AS_EXPECTED(ifs.good(), HAILO_FILE_OPERATION_FAILURE, "Failed reading json file {}", file_path);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
Expected<std::map<std::string, std::map<std::string, ordered_json>>> FwConfigJsonSerializer::get_serialize_map()
|
||||
{
|
||||
ordered_json json_definitions = ordered_json::parse(g_fw_config_str_definitions);
|
||||
std::map<std::string, std::map<std::string, ordered_json>> definitions;
|
||||
|
||||
auto version = json_definitions.find("version");
|
||||
CHECK_AS_EXPECTED(version != json_definitions.end(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed to find version in definitions file");
|
||||
definitions["version"]["value"] = version.value();
|
||||
|
||||
auto categories = json_definitions.find("categories");
|
||||
CHECK_AS_EXPECTED(categories != json_definitions.end(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed to find categories in definitions file");
|
||||
|
||||
uint32_t category_id = 0;
|
||||
for (auto &category : categories->items()) {
|
||||
auto entries = category.value().find("entries");
|
||||
CHECK_AS_EXPECTED(entries != category.value().end(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed to find entries of category {} in definition file", category.key());
|
||||
|
||||
std::map<std::string, ordered_json> entries_map;
|
||||
uint32_t entry_id = 0;
|
||||
for (auto &entry : entries.value().items()) {
|
||||
entry.value()["category_id"] = category_id;
|
||||
entry.value()["entry_id"] = entry_id;
|
||||
entries_map[entry.key()] = entry.value();
|
||||
entry_id++;
|
||||
}
|
||||
definitions[category.key()] = entries_map;
|
||||
category_id++;
|
||||
}
|
||||
return definitions;
|
||||
}
|
||||
|
||||
Expected<std::vector<std::vector<ordered_json>>> FwConfigJsonSerializer::get_deserialize_vector()
|
||||
{
|
||||
ordered_json json_definitions = ordered_json::parse(g_fw_config_str_definitions);
|
||||
|
||||
auto categories = json_definitions.find("categories");
|
||||
CHECK_AS_EXPECTED(categories != json_definitions.end(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed to find categories in definitions file");
|
||||
|
||||
std::vector<std::vector<ordered_json>> categories_vector;
|
||||
for (auto &category : categories.value().items()) {
|
||||
auto entries = category.value().find("entries");
|
||||
CHECK_AS_EXPECTED(entries != category.value().end(), HAILO_INTERNAL_FAILURE,
|
||||
"Failed to find entries of category {} in definitions file", category.key());
|
||||
|
||||
std::vector<ordered_json> entries_vector;
|
||||
for (auto &entry : entries.value().items()) {
|
||||
entry.value()["category_name"] = category.key();
|
||||
entry.value()["entry_name"] = entry.key();
|
||||
entries_vector.emplace_back(entry.value());
|
||||
}
|
||||
categories_vector.emplace_back(entries_vector);
|
||||
}
|
||||
return categories_vector;
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::dump_config(const ordered_json &config_json, const std::string &file_path)
|
||||
{
|
||||
if (file_path.empty()) {
|
||||
std::cout << config_json.dump(JSON_PRINT_INDENTATION) << std::endl;
|
||||
CHECK(std::cout.good(), HAILO_FILE_OPERATION_FAILURE, "Failed writing config to stdout");
|
||||
}
|
||||
else {
|
||||
std::ofstream ofs(file_path);
|
||||
CHECK(ofs.good(), HAILO_OPEN_FILE_FAILURE, "Failed opening output file: {} with errno: {}", file_path, errno);
|
||||
|
||||
ofs << config_json.dump(JSON_PRINT_INDENTATION) << std::endl;
|
||||
CHECK(ofs.good(), HAILO_FILE_OPERATION_FAILURE, "Failed writing firmware configuration into file: {} with errno: {}", file_path, errno);
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
/* Deserialization */
|
||||
hailo_status FwConfigJsonSerializer::deserialize_config(const USER_CONFIG_header_t &user_config_header, size_t config_size, const std::string &file_path)
|
||||
{
|
||||
try {
|
||||
auto categories = get_deserialize_vector();
|
||||
CHECK_EXPECTED_AS_STATUS(categories);
|
||||
|
||||
ordered_json config_json;
|
||||
size_t current_deserialized_data_size = 0;
|
||||
uintptr_t current_entry_offset = (uintptr_t)(&(user_config_header.entries));
|
||||
for (size_t i = 0; i < user_config_header.entry_count; i++) {
|
||||
USER_CONFIG_ENTRY_t *config_entry = reinterpret_cast<USER_CONFIG_ENTRY_t*>(current_entry_offset);
|
||||
CHECK(config_entry->category < categories->size(), HAILO_INTERNAL_FAILURE,
|
||||
"Category id is out of bounds. Category id = {}, Max category id = {}", config_entry->category, (categories->size()-1));
|
||||
|
||||
auto category = categories.value()[config_entry->category];
|
||||
CHECK(config_entry->entry_id < category.size(), HAILO_INTERNAL_FAILURE,
|
||||
"Entry id is out of bounds. Entry id = {}, Max entry id = {}", config_entry->entry_id, (category.size() - 1));
|
||||
|
||||
current_deserialized_data_size += sizeof(USER_CONFIG_ENTRY_t) + config_entry->entry_size;
|
||||
CHECK((current_deserialized_data_size <= config_size), HAILO_INVALID_OPERATION,
|
||||
"Overrun configuration size. Deserialized data size = {}, configuration data size is: {}", current_deserialized_data_size, config_size);
|
||||
|
||||
hailo_status status = FwConfigJsonSerializer::deserialize_entry(config_json,
|
||||
category[config_entry->entry_id], reinterpret_cast<uint8_t*>(&(config_entry->value)));
|
||||
CHECK_SUCCESS(status);
|
||||
|
||||
current_entry_offset += sizeof(USER_CONFIG_ENTRY_t) + config_entry->entry_size;
|
||||
}
|
||||
|
||||
hailo_status status = dump_config(config_json, file_path);
|
||||
CHECK_SUCCESS(status, "Failed writing firmware configuration");
|
||||
}
|
||||
catch (json::exception &e) {
|
||||
LOGGER__ERROR("Exception caught: {}.\n Please check json definition file format", e.what());
|
||||
return HAILO_INTERNAL_FAILURE;
|
||||
}
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::deserialize_entry(ordered_json &config_json, const ordered_json &entry_definition, uint8_t *entry_value)
|
||||
{
|
||||
std::string category_name = entry_definition["category_name"].get<std::string>();
|
||||
std::string entry_name = entry_definition["entry_name"].get<std::string>();
|
||||
std::string deserialize_as = entry_definition["deserialize_as"].get<std::string>();
|
||||
uint32_t size = entry_definition.contains("length") ?
|
||||
(entry_definition["length"].get<uint32_t>() * entry_definition["size"].get<uint32_t>()) :
|
||||
entry_definition["size"].get<uint32_t>();
|
||||
|
||||
if (deserialize_as == "str") {
|
||||
auto str_val = deserialize_str(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(str_val);
|
||||
config_json[category_name][entry_name] = str_val.value();
|
||||
}
|
||||
else if (deserialize_as == "bool") {
|
||||
auto bool_val = deserialize_bool(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(bool_val);
|
||||
config_json[category_name][entry_name] = bool_val.value();
|
||||
}
|
||||
else if (deserialize_as == "int") {
|
||||
auto int_val = deserialize_int(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(int_val);
|
||||
config_json[category_name][entry_name] = int_val.value();
|
||||
}
|
||||
else if (deserialize_as == "i2c_speed") {
|
||||
auto i2c_speed_val = deserialize_i2c_speed(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(i2c_speed_val);
|
||||
config_json[category_name][entry_name]["value"] = i2c_speed_val.value();
|
||||
}
|
||||
else if (deserialize_as == "supported_aspm_states") {
|
||||
auto supported_aspm_states_val = deserialize_supported_aspm_states(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(supported_aspm_states_val);
|
||||
config_json[category_name][entry_name]["value"] = supported_aspm_states_val.value();
|
||||
}
|
||||
else if (deserialize_as == "supported_aspm_l1_substates") {
|
||||
auto supported_aspm_l1_substates_val = deserialize_supported_aspm_l1_substates(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(supported_aspm_l1_substates_val);
|
||||
config_json[category_name][entry_name]["value"] = supported_aspm_l1_substates_val.value();
|
||||
}
|
||||
else if (deserialize_as == "ipv4") {
|
||||
auto ipv4_val = deserialize_ipv4(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(ipv4_val);
|
||||
config_json[category_name][entry_name]["value"] = ipv4_val.value();
|
||||
}
|
||||
else if (deserialize_as == "mac_address") {
|
||||
auto mac_address_val = deserialize_mac_address(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(mac_address_val);
|
||||
config_json[category_name][entry_name]["value"] = mac_address_val.value();
|
||||
}
|
||||
else if (deserialize_as == "clock_frequency") {
|
||||
auto clock_frequency_val = deserialize_clock_frequency(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(clock_frequency_val);
|
||||
config_json[category_name][entry_name]["value"] = clock_frequency_val.value();
|
||||
}
|
||||
else if (deserialize_as == "logger_level") {
|
||||
auto logger_level = deserialize_logger_level(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(logger_level);
|
||||
config_json[category_name][entry_name]["value"] = logger_level.value();
|
||||
}
|
||||
else if (deserialize_as == "watchdog_mode") {
|
||||
auto watchdog_mode_val = deserialize_watchdog_mode(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(watchdog_mode_val);
|
||||
config_json[category_name][entry_name]["value"] = watchdog_mode_val.value();
|
||||
}
|
||||
else if (deserialize_as == "overcurrent_parameters_source") {
|
||||
auto overcurrent_parameters_source_val = deserialize_overcurrent_parameters_source(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(overcurrent_parameters_source_val);
|
||||
config_json[category_name][entry_name]["value"] = overcurrent_parameters_source_val.value();
|
||||
}
|
||||
else if (deserialize_as == "temperature_parameters_source") {
|
||||
auto temperature_parameters_source_val = deserialize_temperature_parameters_source(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(temperature_parameters_source_val);
|
||||
config_json[category_name][entry_name]["value"] = temperature_parameters_source_val.value();
|
||||
}
|
||||
else if (deserialize_as == "conversion_time") {
|
||||
auto conversion_time_val = deserialize_conversion_time(entry_value, size);
|
||||
CHECK_EXPECTED_AS_STATUS(conversion_time_val);
|
||||
config_json[category_name][entry_name]["value"] = conversion_time_val.value();
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed deserializing entry. Serialization format {} not found", deserialize_as);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_str(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
return json(std::string((char*)entry_value, strnlen((char*)entry_value, size)));
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_bool(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto bool_val = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(bool_val);
|
||||
json bool_str = bool_val.value() ? true : false;
|
||||
return bool_str;
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_ipv4(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
CHECK_AS_EXPECTED((IPV4_ADDRESS_LENGTH == size), HAILO_INTERNAL_FAILURE,
|
||||
"IPv4 address length is invalid. Length recieved is: {}, length expected: {}", size, IPV4_ADDRESS_LENGTH);
|
||||
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < IPV4_ADDRESS_LENGTH; i++) {
|
||||
if (i != 0) {
|
||||
ss << '.';
|
||||
}
|
||||
//TODO: HRT-3045 - Support big-endian.
|
||||
ss << (int)(entry_value[IPV4_ADDRESS_LENGTH-i-1]);
|
||||
}
|
||||
return json(ss.str());
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_mac_address(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
CHECK_AS_EXPECTED((MAC_ADDRESS_LENGTH == size), HAILO_INTERNAL_FAILURE,
|
||||
"Mac address length is invalid. Length recieved is: {}, length expected: {}", size, MAC_ADDRESS_LENGTH);
|
||||
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < MAC_ADDRESS_LENGTH; i++) {
|
||||
if (i != 0) {
|
||||
ss << ':';
|
||||
}
|
||||
ss.width(2);
|
||||
ss.fill('0');
|
||||
ss << std::uppercase << std::hex << (int)(entry_value[i]);
|
||||
}
|
||||
return json(ss.str());
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_supported_aspm_states(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto aspm_state = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(aspm_state);
|
||||
|
||||
switch (static_cast<PCIE_CONFIG_SUPPOPRTED_ASPM_STATES_t>(aspm_state.value())) {
|
||||
case ASPM_DISABLED:
|
||||
return json("ASPM DISABLED");
|
||||
case ASPM_L1_ONLY:
|
||||
return json("ASPM L1 ONLY");
|
||||
case ASPM_L0S_L1:
|
||||
return json("ASPM L0S L1");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing supported aspm states.");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_supported_aspm_l1_substates(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto aspm_l1_substate = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(aspm_l1_substate);
|
||||
|
||||
switch (static_cast<PCIE_CONFIG_SUPPOPRTED_L1_ASPM_SUBSTATES_t>(aspm_l1_substate.value())) {
|
||||
case ASPM_L1_SUBSTATES_DISABLED:
|
||||
return json("ASPM L1 SUBSTATES DISABLED");
|
||||
case ASPM_L1_SUBSTATES_L11_ONLY:
|
||||
return json("ASPM L1 SUBSTATES L1.1 ONLY");
|
||||
case ASPM_L1_SUBSTATES_L11_L12:
|
||||
return json("ASPM L1 SUBSTATES L1.1 L1.2");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing supported aspm l1 substates.");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_clock_frequency(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto clock_frequency = get_int_value<uint32_t>(entry_value, size);
|
||||
CHECK_EXPECTED(clock_frequency);
|
||||
|
||||
switch (clock_frequency.value()) {
|
||||
case SOC__NN_CLOCK_400MHz:
|
||||
return json("400MHZ");
|
||||
case SOC__NN_CLOCK_375MHz:
|
||||
return json("375MHZ");
|
||||
case SOC__NN_CLOCK_350MHz:
|
||||
return json("350MHZ");
|
||||
case SOC__NN_CLOCK_325MHz:
|
||||
return json("325MHZ");
|
||||
case SOC__NN_CLOCK_300MHz:
|
||||
return json("300MHZ");
|
||||
case SOC__NN_CLOCK_275MHz:
|
||||
return json("275MHZ");
|
||||
case SOC__NN_CLOCK_250MHz:
|
||||
return json("250MHZ");
|
||||
case SOC__NN_CLOCK_225MHz:
|
||||
return json("225MHZ");
|
||||
case SOC__NN_CLOCK_200MHz:
|
||||
return json("200MHZ");
|
||||
case SOC__NN_CLOCK_100MHz:
|
||||
return json("100MHZ");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing clock_frequency.");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_watchdog_mode(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto watchdog_mode = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(watchdog_mode);
|
||||
|
||||
switch (static_cast<WD_SERVICE_wd_mode_t>(watchdog_mode.value())) {
|
||||
case WD_SERVICE_MODE_HW_SW:
|
||||
return json("WD MODE HW SW");
|
||||
case WD_SERVICE_MODE_HW_ONLY:
|
||||
return json("WD MODE HW ONLY");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing watchdog_mode.");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_i2c_speed(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto i2c_speed = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(i2c_speed);
|
||||
|
||||
switch (static_cast<i2c_speed_mode_t>(i2c_speed.value())) {
|
||||
case I2C_SPEED_STANDARD:
|
||||
return json("I2C SPEED STANDARD");
|
||||
case I2C_SPEED_FAST:
|
||||
return json("I2C SPEED FAST");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing i2c speed");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_logger_level(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto logger_level = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(logger_level);
|
||||
|
||||
switch (static_cast<FW_LOGGER_LEVEL_t>(logger_level.value())) {
|
||||
case FW_LOGGER_LEVEL_TRACE:
|
||||
return json("TRACE");
|
||||
case FW_LOGGER_LEVEL_DEBUG:
|
||||
return json("DEBUG");
|
||||
case FW_LOGGER_LEVEL_INFO:
|
||||
return json("INFO");
|
||||
case FW_LOGGER_LEVEL_WARN:
|
||||
return json("WARNING");
|
||||
case FW_LOGGER_LEVEL_ERROR:
|
||||
return json("ERROR");
|
||||
case FW_LOGGER_LEVEL_FATAL:
|
||||
return json("FATAL");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing logger_level");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_overcurrent_parameters_source(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto overcurrent_parameters_source = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(overcurrent_parameters_source);
|
||||
|
||||
switch (static_cast<OVERCURRENT_parameters_source_t>(overcurrent_parameters_source.value())) {
|
||||
case OVERCURRENT_PARAMETERS_SOURCE_FW_VALUES:
|
||||
return json("FW VALUES");
|
||||
case OVERCURRENT_PARAMETERS_SOURCE_USER_CONFIG_VALUES:
|
||||
return json("USER CONFIG VALUES");
|
||||
case OVERCURRENT_PARAMETERS_SOURCE_BOARD_CONFIG_VALUES:
|
||||
return json("BOARD CONFIG VALUES");
|
||||
case OVERCURRENT_PARAMETERS_SOURCE_OVERCURRENT_DISABLED:
|
||||
return json("OVERCURRENT DISABLED");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing overcurrent thresholds source");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_temperature_parameters_source(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto temperature_parameters_source = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(temperature_parameters_source);
|
||||
|
||||
switch (static_cast<TEMPERATURE_PROTECTION_parameters_source_t>(temperature_parameters_source.value())) {
|
||||
case TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_FW_VALUES:
|
||||
return json("FW VALUES");
|
||||
case TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_USER_CONFIG_VALUES:
|
||||
return json("USER CONFIG VALUES");
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing overcurrent thresholds source");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_conversion_time(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
auto conversion_time = get_int_value<uint32_t>(entry_value, size);
|
||||
CHECK_EXPECTED(conversion_time);
|
||||
auto conversion_time_value = static_cast<OVERCURRENT_conversion_time_us_t>(conversion_time.value());
|
||||
|
||||
if (conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_140US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_204US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_332US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_588US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_1100US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_2116US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_4156US ||
|
||||
conversion_time_value == OVERCURRENT_CONVERSION_PERIOD_8244US) {
|
||||
|
||||
return json(conversion_time_value);
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Got unvalid valid option for conversion_time.");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<json> FwConfigJsonSerializer::deserialize_int(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof(uint8_t):
|
||||
{
|
||||
auto uint8_val = get_int_value<uint8_t>(entry_value, size);
|
||||
CHECK_EXPECTED(uint8_val);
|
||||
return json(uint8_val.value());
|
||||
}
|
||||
case sizeof(uint16_t):
|
||||
{
|
||||
auto uint16_val = get_int_value<uint16_t>(entry_value, size);
|
||||
CHECK_EXPECTED(uint16_val);
|
||||
return json(uint16_val.value());
|
||||
}
|
||||
case sizeof(uint32_t):
|
||||
{
|
||||
auto uint32_val = get_int_value<uint32_t>(entry_value, size);
|
||||
CHECK_EXPECTED(uint32_val);
|
||||
return json(uint32_val.value());
|
||||
}
|
||||
default:
|
||||
LOGGER__ERROR("Failed deserializing int value");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/* Serialization */
|
||||
Expected<uint32_t> FwConfigJsonSerializer::serialize_config(USER_CONFIG_header_t &user_config_header, size_t config_size, const std::string &file_path)
|
||||
{
|
||||
size_t data_size = sizeof(USER_CONFIG_header_t);
|
||||
|
||||
try {
|
||||
auto config_json = FwConfigJsonSerializer::read_json_file(file_path);
|
||||
CHECK_EXPECTED(config_json);
|
||||
|
||||
auto definitions = FwConfigJsonSerializer::get_serialize_map();
|
||||
CHECK_EXPECTED(definitions);
|
||||
|
||||
user_config_header.version = definitions.value()["version"]["value"].get<uint32_t>();
|
||||
user_config_header.magic = USER_CONFIG_MAGIC;
|
||||
user_config_header.entry_count = 0;
|
||||
|
||||
uintptr_t current_entry_offset = (uintptr_t)(&(user_config_header.entries));
|
||||
for (auto &config_category : config_json->items()) {
|
||||
for (auto &config_entry : config_category.value().items()) {
|
||||
ordered_json entry_definition = definitions.value()[config_category.key()][config_entry.key()];
|
||||
USER_CONFIG_ENTRY_t *curr_entry = (USER_CONFIG_ENTRY_t *)current_entry_offset;
|
||||
curr_entry->entry_size = entry_definition.contains("length") ?
|
||||
(entry_definition["length"].get<uint32_t>() * entry_definition["size"].get<uint32_t>()) :
|
||||
entry_definition["size"].get<uint32_t>();
|
||||
|
||||
data_size += sizeof(USER_CONFIG_ENTRY_t) + curr_entry->entry_size;
|
||||
CHECK_AS_EXPECTED((data_size <= config_size), HAILO_INVALID_OPERATION,
|
||||
"User config overrun! Configuration is too big, data size {}, firmware configuration size: {}",
|
||||
data_size, config_size);
|
||||
|
||||
hailo_status status = serialize_entry(*curr_entry, config_entry.value(), entry_definition);
|
||||
CHECK_SUCCESS_AS_EXPECTED(status, "Failed serializing json config category: {}, entry: {}",
|
||||
config_category.key(), config_entry.key());
|
||||
|
||||
user_config_header.entry_count++;
|
||||
current_entry_offset += sizeof(USER_CONFIG_ENTRY_t) + curr_entry->entry_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (json::exception &e) {
|
||||
LOGGER__ERROR("Exception caught: {}.\n Please check json files format", e.what());
|
||||
return make_unexpected(HAILO_INTERNAL_FAILURE);
|
||||
}
|
||||
|
||||
CHECK_AS_EXPECTED(((std::numeric_limits<uint32_t>::min() <= data_size) && (data_size <= std::numeric_limits<uint32_t>::max())),
|
||||
HAILO_INTERNAL_FAILURE, "Firmware configuration data size is out of bounds. data_size = {}", data_size);
|
||||
|
||||
return static_cast<uint32_t>(data_size);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_entry(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry, const ordered_json &entry_definition)
|
||||
{
|
||||
ordered_json inner_config_entry = config_entry;
|
||||
entry.category = entry_definition["category_id"].get<uint16_t>();
|
||||
entry.entry_id = entry_definition["entry_id"].get<uint16_t>();
|
||||
|
||||
std::string deserialize_as = entry_definition["deserialize_as"].get<std::string>();
|
||||
|
||||
if (deserialize_as == "str") {
|
||||
return serialize_str(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "bool") {
|
||||
return serialize_bool(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "int") {
|
||||
return serialize_int_by_size(entry, inner_config_entry);
|
||||
}
|
||||
else {
|
||||
if (!config_entry.contains("value"))
|
||||
{
|
||||
inner_config_entry = {{"value", config_entry}};
|
||||
}
|
||||
if (deserialize_as == "ipv4") {
|
||||
return serialize_ipv4(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "i2c_speed") {
|
||||
return serialize_i2c_speed(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "supported_aspm_states") {
|
||||
return serialize_supported_aspm_states(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "supported_aspm_l1_substates") {
|
||||
return serialize_supported_aspm_l1_substates(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "mac_address") {
|
||||
return serialize_mac_address(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "clock_frequency") {
|
||||
return serialize_clock_frequency(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "logger_level") {
|
||||
return serialize_logger_level(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "watchdog_mode") {
|
||||
return serialize_watchdog_mode(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "overcurrent_parameters_source") {
|
||||
return serialize_overcurrent_parameters_source(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "temperature_parameters_source") {
|
||||
return serialize_temperature_parameters_source(entry, inner_config_entry);
|
||||
}
|
||||
else if (deserialize_as == "conversion_time") {
|
||||
return serialize_conversion_time(entry, inner_config_entry);
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing entry. Serialization format {} not found", deserialize_as);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_str(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string str = config_entry.get<std::string>();
|
||||
|
||||
CHECK(0 != str.length(), HAILO_INVALID_ARGUMENT, "Failed serializing string. String length can't be 0.");
|
||||
|
||||
CHECK(entry.entry_size >= str.length(), HAILO_INVALID_ARGUMENT,
|
||||
"Failed serializing string value {}. String length must be equal or shorter than {}", str, entry.entry_size);
|
||||
|
||||
memcpy(&(entry.value), str.c_str(), str.length());
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_bool(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
uint8_t bool_value = config_entry.get<uint8_t>();
|
||||
return serialize_int(entry, bool_value);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_ipv4(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
CHECK(IPV4_ADDRESS_LENGTH == entry.entry_size, HAILO_INVALID_ARGUMENT,
|
||||
"IPv4 entry size is incompatible. Size recieved: {}, size expected: {}", entry.entry_size, IPV4_ADDRESS_LENGTH);
|
||||
|
||||
std::string ipv4_str = config_entry["value"].get<std::string>();
|
||||
uint8_t ip[IPV4_ADDRESS_LENGTH];
|
||||
|
||||
auto length = sscanf(ipv4_str.c_str(), "%hhd.%hhd.%hhd.%hhd", &ip[3], &ip[2], &ip[1], &ip[0]);
|
||||
CHECK(IPV4_ADDRESS_LENGTH == length, HAILO_INVALID_ARGUMENT, "Failed serializing ipv4: {}", ipv4_str);
|
||||
|
||||
memcpy(&(entry.value), &ip, entry.entry_size);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_i2c_speed(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string i2c_speed = config_entry["value"].get<std::string>();
|
||||
uint8_t val = 0;
|
||||
if (("I2C_SPEED_STANDARD" == i2c_speed) || ("I2C SPEED STANDARD" == i2c_speed)) {
|
||||
val = I2C_SPEED_STANDARD;
|
||||
}
|
||||
else if (("I2C_SPEED_FAST" == i2c_speed) || ("I2C SPEED FAST" == i2c_speed)) {
|
||||
val = I2C_SPEED_FAST;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing i2c speed {}", i2c_speed);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_logger_level(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string logger_level = config_entry["value"].get<std::string>();
|
||||
uint8_t val = 0;
|
||||
|
||||
if ("TRACE" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_TRACE;
|
||||
}
|
||||
else if ("DEBUG" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_DEBUG;
|
||||
}
|
||||
else if ("INFO" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_INFO;
|
||||
}
|
||||
else if ("WARNING" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_WARN;
|
||||
}
|
||||
else if ("ERROR" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_ERROR;
|
||||
}
|
||||
else if ("FATAL" == logger_level) {
|
||||
val = FW_LOGGER_LEVEL_FATAL;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing logger_level {}", logger_level);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_supported_aspm_states(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string aspm_state = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t val = 0;
|
||||
if (("ASPM_DISABLED" == aspm_state) || ("ASPM DISABLED" == aspm_state)) {
|
||||
val = ASPM_DISABLED;
|
||||
}
|
||||
else if (("ASPM_L1_ONLY" == aspm_state) || ("ASPM L1 ONLY" == aspm_state)) {
|
||||
val = ASPM_L1_ONLY;
|
||||
}
|
||||
else if (("ASPM_L0S_L1" == aspm_state) || ("ASPM L0S L1" == aspm_state)) {
|
||||
val = ASPM_L0S_L1;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing supported aspm state {}.", aspm_state);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_supported_aspm_l1_substates(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string aspm_l1_substate = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t val = 0;
|
||||
if (("ASPM_L1_SUBSTATES_DISABLED" == aspm_l1_substate) || ("ASPM L1 SUBSTATES DISABLED" == aspm_l1_substate)) {
|
||||
val = ASPM_L1_SUBSTATES_DISABLED;
|
||||
}
|
||||
else if (("ASPM_L1_SUBSTATES_L11_ONLY" == aspm_l1_substate) || ("ASPM L1 SUBSTATES L1.1 ONLY" == aspm_l1_substate)) {
|
||||
val = ASPM_L1_SUBSTATES_L11_ONLY;
|
||||
}
|
||||
else if (("ASPM_L1_SUBSTATES_L11_L12" == aspm_l1_substate) || ("ASPM L1 SUBSTATES L1.1 L1.2" == aspm_l1_substate)) {
|
||||
val = ASPM_L1_SUBSTATES_L11_L12;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing supported aspm l1 substate {}", aspm_l1_substate);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_mac_address(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string mac_addr_str = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t mac_address[MAC_ADDRESS_LENGTH];
|
||||
auto length = std::sscanf(mac_addr_str.c_str(),
|
||||
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&mac_address[0], &mac_address[1], &mac_address[2],
|
||||
&mac_address[3], &mac_address[4], &mac_address[5]);
|
||||
CHECK(MAC_ADDRESS_LENGTH == length, HAILO_INVALID_ARGUMENT, "Failed serializing mac address {}", mac_addr_str);
|
||||
|
||||
memcpy(&(entry.value), &mac_address, entry.entry_size);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_clock_frequency(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string clock_frequency = config_entry["value"].get<std::string>();
|
||||
|
||||
uint32_t val = 0;
|
||||
if ("400MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_400MHz;
|
||||
}
|
||||
else if ("375MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_375MHz;
|
||||
}
|
||||
else if ("350MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_350MHz;
|
||||
}
|
||||
else if ("325MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_325MHz;
|
||||
}
|
||||
else if ("300MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_300MHz;
|
||||
}
|
||||
else if ("275MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_275MHz;
|
||||
}
|
||||
else if ("250MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_250MHz;
|
||||
}
|
||||
else if ("225MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_225MHz;
|
||||
}
|
||||
else if ("200MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_200MHz;
|
||||
}
|
||||
else if ("100MHZ" == clock_frequency) {
|
||||
val = SOC__NN_CLOCK_100MHz;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing clock_frequency {}", clock_frequency);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_watchdog_mode(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string watchdog_mode = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t val = 0;
|
||||
if (("WD_MODE_HW_SW" == watchdog_mode) || ("WD MODE HW SW" == watchdog_mode)) {
|
||||
val = 0;
|
||||
}
|
||||
else if (("WD_MODE_HW_ONLY" == watchdog_mode) || ("WD MODE HW ONLY" == watchdog_mode)) {
|
||||
val = 1;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing watchdog_mode {}", watchdog_mode);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_overcurrent_parameters_source(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string overcurrent_parameters_source = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t val = 0;
|
||||
if (("FW_VALUES" == overcurrent_parameters_source) || ("FW VALUES" == overcurrent_parameters_source)) {
|
||||
val = OVERCURRENT_PARAMETERS_SOURCE_FW_VALUES;
|
||||
}
|
||||
else if (("USER_CONFIG_VALUES" == overcurrent_parameters_source) || ("USER CONFIG VALUES" == overcurrent_parameters_source)) {
|
||||
val = OVERCURRENT_PARAMETERS_SOURCE_USER_CONFIG_VALUES;
|
||||
}
|
||||
else if (("BOARD_CONFIG_VALUES" == overcurrent_parameters_source) || ("BOARD CONFIG VALUES" == overcurrent_parameters_source)) {
|
||||
val = OVERCURRENT_PARAMETERS_SOURCE_BOARD_CONFIG_VALUES;
|
||||
}
|
||||
else if (("OVERCURRENT_DISABLED" == overcurrent_parameters_source) || ("OVERCURRENT DISABLED" == overcurrent_parameters_source)) {
|
||||
val = OVERCURRENT_PARAMETERS_SOURCE_OVERCURRENT_DISABLED;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing overcurrent_parameters_source {}", overcurrent_parameters_source);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_temperature_parameters_source(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
std::string temperature_parameters_source = config_entry["value"].get<std::string>();
|
||||
|
||||
uint8_t val = 0;
|
||||
if (("FW_VALUES" == temperature_parameters_source) || ("FW VALUES" == temperature_parameters_source)) {
|
||||
val = TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_FW_VALUES;
|
||||
}
|
||||
else if (("USER_CONFIG_VALUES" == temperature_parameters_source) || ("USER CONFIG VALUES" == temperature_parameters_source)) {
|
||||
val = TEMPERATURE_PROTECTION_PARAMETERS_SOURCE_USER_CONFIG_VALUES;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing temperature_parameters_source {}", temperature_parameters_source);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_conversion_time(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
uint32_t conversion_time = config_entry["value"].get<uint32_t>();
|
||||
uint32_t val = 0;
|
||||
|
||||
if (conversion_time == OVERCURRENT_CONVERSION_PERIOD_140US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_204US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_332US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_588US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_1100US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_2116US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_4156US ||
|
||||
conversion_time == OVERCURRENT_CONVERSION_PERIOD_8244US) {
|
||||
|
||||
val = conversion_time;
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing conversion_time {}", conversion_time);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
return serialize_int(entry, val);
|
||||
}
|
||||
|
||||
hailo_status FwConfigJsonSerializer::serialize_int_by_size(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry)
|
||||
{
|
||||
int64_t value = config_entry.get<int64_t>();
|
||||
if (sizeof(uint8_t) == entry.entry_size) {
|
||||
CHECK(((std::numeric_limits<uint8_t>::min() <= value) && (value <= std::numeric_limits<uint8_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed serializing uint8_t value: {}. Value is out of numeric limits", value);
|
||||
|
||||
return serialize_int<uint8_t>(entry, static_cast<uint8_t>(value));
|
||||
}
|
||||
else if (sizeof(uint16_t) == entry.entry_size) {
|
||||
CHECK(((std::numeric_limits<uint16_t>::min() <= value) && (value <= std::numeric_limits<uint16_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed serializing uint16_t value: {}. Value is out of numeric limits", value);
|
||||
|
||||
return serialize_int<uint16_t>(entry, static_cast<uint16_t>(value));
|
||||
}
|
||||
else if (sizeof(uint32_t) == entry.entry_size) {
|
||||
CHECK(((std::numeric_limits<uint32_t>::min() <= value) && (value <= std::numeric_limits<uint32_t>::max())),
|
||||
HAILO_INVALID_ARGUMENT, "Failed serializing uint32_t value: {}. Value is out of numeric limits", value);
|
||||
|
||||
return serialize_int<uint32_t>(entry, static_cast<uint32_t>(value));
|
||||
}
|
||||
else {
|
||||
LOGGER__ERROR("Failed serializing int value. Invalid size {}", entry.entry_size);
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
100
hailort/hailortcli/fw_config_serializer.hpp
Normal file
100
hailort/hailortcli/fw_config_serializer.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_config_serializer.hpp
|
||||
* @brief User firmware configuration serializer.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FW_CONFIG_SERIALIZER_HPP_
|
||||
#define _HAILO_FW_CONFIG_SERIALIZER_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "user_config_common.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
#define MAC_ADDRESS_LENGTH (6)
|
||||
#define IPV4_ADDRESS_LENGTH (4)
|
||||
#define JSON_PRINT_INDENTATION (4)
|
||||
#define USER_CONFIG_MAGIC (0x1FF6A40B)
|
||||
|
||||
/* NOTE: Tightly coupled with I2C_speed_mode_t defined in "i2c_handler.h"
|
||||
Configuring I2c_speed_high is not supported. */
|
||||
typedef enum {
|
||||
I2C_SPEED_STANDARD = 1,
|
||||
I2C_SPEED_FAST = 2,
|
||||
} i2c_speed_mode_t;
|
||||
|
||||
// TODO: HRT-3045 - Add support for big-endian serialization
|
||||
class FwConfigJsonSerializer {
|
||||
public:
|
||||
FwConfigJsonSerializer() = delete;
|
||||
|
||||
static Expected<ordered_json> read_json_file(const std::string &file_path);
|
||||
static Expected<std::vector<std::vector<ordered_json>>> get_deserialize_vector();
|
||||
static Expected<std::map<std::string, std::map<std::string, ordered_json>>> get_serialize_map();
|
||||
static hailo_status dump_config(const ordered_json &config_json, const std::string &file_path);
|
||||
|
||||
static hailo_status deserialize_config(const USER_CONFIG_header_t &user_config_header, size_t config_size, const std::string &file_path);
|
||||
static hailo_status deserialize_entry(ordered_json &config_json, const ordered_json &entry_definition, uint8_t *entry_value);
|
||||
static Expected<json> deserialize_str(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_bool(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_supported_aspm_states(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_supported_aspm_l1_substates(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_mac_address(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_i2c_speed(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_logger_level(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_ipv4(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_clock_frequency(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_watchdog_mode(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_overcurrent_parameters_source(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_temperature_parameters_source(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_conversion_time(uint8_t *entry_value, uint32_t size);
|
||||
static Expected<json> deserialize_int(uint8_t *entry_value, uint32_t size);
|
||||
|
||||
static Expected<uint32_t> serialize_config(USER_CONFIG_header_t &user_config_header, size_t config_size, const std::string &file_path);
|
||||
static hailo_status serialize_entry(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry, const ordered_json &entry_definition);
|
||||
static hailo_status serialize_str(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_bool(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_ipv4(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_i2c_speed(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_logger_level(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_supported_aspm_states(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_supported_aspm_l1_substates(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_mac_address(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_clock_frequency(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_watchdog_mode(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_overcurrent_parameters_source(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_temperature_parameters_source(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_conversion_time(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
static hailo_status serialize_int_by_size(USER_CONFIG_ENTRY_t &entry, const ordered_json &config_entry);
|
||||
|
||||
template<typename IntegerType>
|
||||
static Expected<IntegerType> get_int_value(uint8_t *entry_value, uint32_t size)
|
||||
{
|
||||
CHECK_AS_EXPECTED((sizeof(IntegerType) == size), HAILO_INTERNAL_FAILURE, "Entry size is incompatible with integer type");
|
||||
auto val = *((IntegerType*)entry_value);
|
||||
return val;
|
||||
}
|
||||
|
||||
template<typename IntegerType>
|
||||
static hailo_status serialize_int(USER_CONFIG_ENTRY_t &entry, IntegerType value)
|
||||
{
|
||||
CHECK((sizeof(IntegerType) == entry.entry_size), HAILO_INVALID_ARGUMENT,
|
||||
"Entry size {} is incompatible with size of integer type {}", entry.entry_size, sizeof(IntegerType));
|
||||
|
||||
auto entry_value_ptr = (IntegerType*)(&entry.value);
|
||||
*entry_value_ptr = value;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _HAILO_FW_CONFIG_SERIALIZER_HPP_ */
|
||||
248
hailort/hailortcli/fw_control_command.cpp
Normal file
248
hailort/hailortcli/fw_control_command.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_control.cpp
|
||||
* @brief Several controls that can be sent to the firware
|
||||
**/
|
||||
|
||||
#include "fw_control_command.hpp"
|
||||
#include "firmware_header_utils.h"
|
||||
|
||||
|
||||
static const char *NOT_CONFIGURED_ATTR = "<Not Configured>";
|
||||
#define MHz (1000 * 1000)
|
||||
|
||||
|
||||
static std::string extended_device_information_boot_string(hailo_device_boot_source_t boot_source)
|
||||
{
|
||||
switch (boot_source) {
|
||||
case HAILO_DEVICE_BOOT_SOURCE_PCIE:
|
||||
return "PCIE";
|
||||
case HAILO_DEVICE_BOOT_SOURCE_FLASH:
|
||||
return "FLASH";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string extended_device_information_supported_features(hailo_device_supported_features_t supported_features)
|
||||
{
|
||||
std::string supported_features_str;
|
||||
|
||||
if(supported_features.current_monitoring) {
|
||||
supported_features_str.append("Current Monitoring, ");
|
||||
}
|
||||
if(supported_features.ethernet) {
|
||||
supported_features_str.append("Ethernet, ");
|
||||
}
|
||||
if(supported_features.mipi) {
|
||||
supported_features_str.append("MIPI, ");
|
||||
}
|
||||
if(supported_features.mdio) {
|
||||
supported_features_str.append("MDIO, ");
|
||||
}
|
||||
if(supported_features.pcie) {
|
||||
supported_features_str.append("PCIE, ");
|
||||
}
|
||||
|
||||
std::size_t last_comma_location = supported_features_str.find_last_of(",");
|
||||
supported_features_str = supported_features_str.substr(0,last_comma_location);
|
||||
|
||||
return supported_features_str;
|
||||
}
|
||||
|
||||
static void extended_device_information_print_array(uint8_t *array_for_print, size_t array_length, std::string splitter)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(i = 0; i < array_length; i++) {
|
||||
std::cout << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast<int>(array_for_print[i]);
|
||||
if(array_length != (i+1)) {
|
||||
std::cout << splitter;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static bool extended_device_information_is_array_not_empty(uint8_t *array_for_print, size_t array_length)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(i = 0; i < array_length; i++) {
|
||||
if(array_for_print[i] != 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static hailo_status print_extended_device_information(Device &device)
|
||||
{
|
||||
auto extended_info_expected = device.get_extended_device_information();
|
||||
CHECK_EXPECTED_AS_STATUS(extended_info_expected, "Failed identify");
|
||||
auto device_info = extended_info_expected.release();
|
||||
|
||||
// Print Board Extended information
|
||||
std::cout << "Boot source: " << extended_device_information_boot_string(device_info.boot_source) << std::endl;
|
||||
std::cout << "Neural Network Core Clock Rate: " << (device_info.neural_network_core_clock_rate/MHz) <<"MHz" <<std::endl;
|
||||
|
||||
std::string supported_features_str = extended_device_information_supported_features(device_info.supported_features);
|
||||
if(supported_features_str.length() > 0) {
|
||||
std::cout << "Device supported features: " << supported_features_str << std::endl;
|
||||
}
|
||||
std::cout << "LCS: " << static_cast<int>(device_info.lcs) << std::endl;
|
||||
|
||||
if(extended_device_information_is_array_not_empty(device_info.soc_id, sizeof(device_info.soc_id))){
|
||||
std::cout << "SoC ID: ";
|
||||
extended_device_information_print_array(device_info.soc_id, sizeof(device_info.soc_id), "");
|
||||
}
|
||||
|
||||
if(extended_device_information_is_array_not_empty(device_info.eth_mac_address, sizeof(device_info.eth_mac_address))){
|
||||
std::cout << "MAC Address: ";
|
||||
extended_device_information_print_array(device_info.eth_mac_address, sizeof(device_info.eth_mac_address), ":");
|
||||
}
|
||||
|
||||
if(extended_device_information_is_array_not_empty(device_info.unit_level_tracking_id, sizeof(device_info.unit_level_tracking_id))){
|
||||
std::cout << "ULT ID: ";
|
||||
extended_device_information_print_array(device_info.unit_level_tracking_id, sizeof(device_info.unit_level_tracking_id), "");
|
||||
}
|
||||
|
||||
if(extended_device_information_is_array_not_empty(device_info.soc_pm_values, sizeof(device_info.soc_pm_values))){
|
||||
std::cout << "PM Values: ";
|
||||
extended_device_information_print_array(device_info.soc_pm_values, sizeof(device_info.soc_pm_values), "");
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
static std::string fw_version_string(const hailo_device_identity_t &identity)
|
||||
{
|
||||
std::stringstream os;
|
||||
const auto fw_mode = ((identity.is_release) ? "release" : "develop");
|
||||
// Currently will always return FW_BINARY_TYPE_APP_FIRMWARE as version bit is cleared in HailoRT
|
||||
FW_BINARY_TYPE_t fw_binary_type = FIRMWARE_HEADER_UTILS__get_fw_binary_type(identity.fw_version.revision);
|
||||
auto fw_type = "invalid";
|
||||
if (FW_BINARY_TYPE_CORE_FIRMWARE == fw_binary_type) {
|
||||
fw_type = "core";
|
||||
} else if (FW_BINARY_TYPE_APP_FIRMWARE == fw_binary_type) {
|
||||
fw_type = "app";
|
||||
}
|
||||
os << identity.fw_version.major << "." << identity.fw_version.minor << "."
|
||||
<< identity.fw_version.revision << " (" << fw_mode << "," << fw_type << ")";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
static std::string identity_arch_string(const hailo_device_identity_t &identity)
|
||||
{
|
||||
switch (identity.device_architecture) {
|
||||
case HAILO_ARCH_HAILO8_B0:
|
||||
return "HAILO8_B0";
|
||||
case HAILO_ARCH_MERCURY_CA:
|
||||
return "MERCURY_CA";
|
||||
case HAILO_ARCH_MERCURY_VPU:
|
||||
return "MERCURY_VPU";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string identity_attr_string(const char *attr, size_t attr_max_len)
|
||||
{
|
||||
size_t actual_len = strnlen(attr, attr_max_len);
|
||||
if (actual_len == 0) {
|
||||
return NOT_CONFIGURED_ATTR;
|
||||
}
|
||||
return std::string(attr, actual_len);
|
||||
}
|
||||
|
||||
FwControlIdentifyCommand::FwControlIdentifyCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("identify", "Displays general information about the device")),
|
||||
m_is_extended(false)
|
||||
{
|
||||
m_app->add_flag("--extended", m_is_extended, "Print device extended information");
|
||||
}
|
||||
|
||||
hailo_status FwControlIdentifyCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto identity_expected = device.identify();
|
||||
CHECK_EXPECTED_AS_STATUS(identity_expected, "Failed identify");
|
||||
auto identity = identity_expected.release();
|
||||
|
||||
// Print board information
|
||||
std::cout << "Identifying board" << std::endl;
|
||||
std::cout << "Control Protocol Version: " << identity.protocol_version << std::endl;
|
||||
std::cout << "Firmware Version: " << fw_version_string(identity) << std::endl;
|
||||
std::cout << "Logger Version: " << identity.logger_version << std::endl;
|
||||
std::cout << "Board Name: " << std::string(identity.board_name, identity.board_name_length) << std::endl;
|
||||
std::cout << "Device Architecture: " << identity_arch_string(identity) << std::endl;
|
||||
std::cout << "Serial Number: " <<
|
||||
identity_attr_string(identity.serial_number, identity.serial_number_length) << std::endl;
|
||||
std::cout << "Part Number: " <<
|
||||
identity_attr_string(identity.part_number, identity.part_number_length) << std::endl;
|
||||
std::cout << "Product Name: " <<
|
||||
identity_attr_string(identity.product_name, identity.product_name_length) << std::endl;
|
||||
|
||||
if (m_is_extended) {
|
||||
print_extended_device_information(device);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwControlResetCommand::FwControlResetCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("reset", "Resets the device"))
|
||||
{
|
||||
m_app->add_option("--reset-type", m_reset_mode, "Reset type")
|
||||
->required()
|
||||
->transform(HailoCheckedTransformer<hailo_reset_device_mode_t>({
|
||||
{ "chip", HAILO_RESET_DEVICE_MODE_CHIP },
|
||||
{ "nn_core", HAILO_RESET_DEVICE_MODE_NN_CORE },
|
||||
{ "soft", HAILO_RESET_DEVICE_MODE_SOFT },
|
||||
{ "forced_soft", HAILO_RESET_DEVICE_MODE_FORCED_SOFT },
|
||||
}));
|
||||
}
|
||||
|
||||
hailo_status FwControlResetCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto status = device.reset(m_reset_mode);
|
||||
CHECK_SUCCESS(status, "Failed reset device");
|
||||
|
||||
std::cout << "Board has been reset successfully" << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwControlTestMemoriesCommand::FwControlTestMemoriesCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("test-memories", "Run a test of the chip's memories"))
|
||||
{}
|
||||
|
||||
hailo_status FwControlTestMemoriesCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto status = device.test_chip_memories();
|
||||
CHECK_SUCCESS(status, "Failed memory test");
|
||||
|
||||
std::cout << "Memory test has completed succesfully" << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
FwControlCommand::FwControlCommand(CLI::App &parent_app) :
|
||||
ContainerCommand(parent_app.add_subcommand("fw-control", "Useful firmware control operations"))
|
||||
{
|
||||
add_subcommand<FwControlIdentifyCommand>();
|
||||
add_subcommand<FwControlResetCommand>();
|
||||
|
||||
// TODO: Remove scan as a subcommand of fw_control_subcommand (HRT-2676)
|
||||
// Can also remove Command::set_description function after this, and the return value of `add_subcommand`
|
||||
auto &scan = add_subcommand<ScanSubcommand>();
|
||||
scan.set_description("Alias for root-level 'scan' command (i.e. 'hailortcli scan...')\n"
|
||||
"Note: 'scan' as a sub-command of 'fw-control' is deprecated; use 'hailortcli scan' instead\n"
|
||||
" (or 'hailo scan' when using the 'hailo' command).");
|
||||
|
||||
add_subcommand<FwControlTestMemoriesCommand>();
|
||||
// TODO: Support on windows (HRT-5919)
|
||||
#if defined(__GNUC__)
|
||||
// TODO: Unhide (HRT-6035)
|
||||
static const bool HIDDEN = true;
|
||||
add_subcommand<DownloadActionListCommand>(HIDDEN);
|
||||
#endif
|
||||
}
|
||||
58
hailort/hailortcli/fw_control_command.hpp
Normal file
58
hailort/hailortcli/fw_control_command.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_control.hpp
|
||||
* @brief Several controls that can be sent to the firware
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FW_CONTROL_COMMAND_HPP_
|
||||
#define _HAILO_FW_CONTROL_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
// TODO: Remove scan as a subcommand of fw_control_subcommand (HRT-2676)
|
||||
#include "scan_command.hpp"
|
||||
#if defined(__GNUC__)
|
||||
// TODO: Support on windows (HRT-5919)
|
||||
#include "download_action_list_command.hpp"
|
||||
#endif
|
||||
|
||||
class FwControlIdentifyCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit FwControlIdentifyCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
bool m_is_extended;
|
||||
};
|
||||
|
||||
class FwControlResetCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit FwControlResetCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
hailo_reset_device_mode_t m_reset_mode;
|
||||
};
|
||||
|
||||
class FwControlTestMemoriesCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit FwControlTestMemoriesCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
};
|
||||
|
||||
class FwControlCommand : public ContainerCommand {
|
||||
public:
|
||||
explicit FwControlCommand(CLI::App &parent_app);
|
||||
};
|
||||
|
||||
|
||||
#endif /* _HAILO_FW_CONTROL_COMMAND_HPP_ */
|
||||
81
hailort/hailortcli/fw_logger_command.cpp
Normal file
81
hailort/hailortcli/fw_logger_command.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_logger_command.cpp
|
||||
* @brief Write fw log to output file
|
||||
**/
|
||||
|
||||
#include "fw_logger_command.hpp"
|
||||
#include "common/file_utils.hpp"
|
||||
|
||||
#define AMOUNT_OF_BYTES_TO_READ 256
|
||||
|
||||
FwLoggerCommand::FwLoggerCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("fw-logger", "Download fw logs to a file")),
|
||||
m_should_overwrite(false)
|
||||
{
|
||||
m_app->add_option("output_file", m_output_file, "File path to write binary firmware log into")
|
||||
->required();
|
||||
m_app->add_flag("--overwrite", m_should_overwrite, "Should overwrite the file or not");
|
||||
}
|
||||
|
||||
hailo_status write_logs_to_file(Device &device, std::ofstream &ofs, hailo_cpu_id_t cpu_id){
|
||||
auto still_has_logs = true;
|
||||
static const auto buffer_size = AMOUNT_OF_BYTES_TO_READ;
|
||||
|
||||
auto expected_buffer = Buffer::create(buffer_size);
|
||||
CHECK_EXPECTED_AS_STATUS(expected_buffer);
|
||||
Buffer buffer = expected_buffer.release();
|
||||
|
||||
while(still_has_logs) {
|
||||
MemoryView response_view(buffer);
|
||||
auto response_size_expected = device.read_log(response_view, cpu_id);
|
||||
CHECK_EXPECTED_AS_STATUS(response_size_expected);
|
||||
|
||||
auto response_size = response_size_expected.release();
|
||||
if (response_size == 0) {
|
||||
still_has_logs = false;
|
||||
}
|
||||
else {
|
||||
ofs.write((char *)buffer.data(), response_size);
|
||||
CHECK(ofs.good(), HAILO_FILE_OPERATION_FAILURE,
|
||||
"Failed writing firmware logger to output file, with errno: {}", errno);
|
||||
}
|
||||
}
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status FwLoggerCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto ofs_flags = std::ios::out | std::ios::binary;
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
|
||||
if (!m_should_overwrite){
|
||||
ofs_flags |= std::ios::app;
|
||||
}
|
||||
|
||||
std::ofstream ofs(m_output_file, ofs_flags);
|
||||
CHECK(ofs.good(), HAILO_OPEN_FILE_FAILURE, "Failed opening file: {}, with errno: {}", m_output_file, errno);
|
||||
|
||||
if (Device::Type::ETH == device.get_type()) {
|
||||
LOGGER__ERROR("Read FW log is not supported over Eth device");
|
||||
return HAILO_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (Device::Type::CORE != device.get_type()) {
|
||||
status = write_logs_to_file(device, ofs, HAILO_CPU_ID_0);
|
||||
if (status != HAILO_SUCCESS){
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = write_logs_to_file(device, ofs, HAILO_CPU_ID_1);
|
||||
if (status != HAILO_SUCCESS){
|
||||
return status;
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
34
hailort/hailortcli/fw_logger_command.hpp
Normal file
34
hailort/hailortcli/fw_logger_command.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_logger_command.hpp
|
||||
* @brief Write fw log to output file
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FW_LOGGER_COMMAND_COMMAND_HPP_
|
||||
#define _HAILO_FW_LOGGER_COMMAND_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class FwLoggerCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit FwLoggerCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_output_file;
|
||||
bool m_should_overwrite;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_FW_LOGGER_COMMAND_COMMAND_HPP_ */
|
||||
44
hailort/hailortcli/fw_update_command.cpp
Normal file
44
hailort/hailortcli/fw_update_command.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_update_command.cpp
|
||||
* @brief Update fw on hailo device with flash
|
||||
**/
|
||||
|
||||
#include "fw_update_command.hpp"
|
||||
#include "common/file_utils.hpp"
|
||||
|
||||
FwUpdateCommand::FwUpdateCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("fw-update", "Firmware update tool (only for flash based devices)")),
|
||||
m_firmware_path(),
|
||||
m_skip_reset(false)
|
||||
{
|
||||
m_app->add_option("firmware", m_firmware_path, "The path to the firmware binary")
|
||||
->required()
|
||||
->check(CLI::ExistingFile);
|
||||
m_app->add_flag("--skip-reset", m_skip_reset, "Don't reset after update");
|
||||
}
|
||||
|
||||
hailo_status FwUpdateCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto firmware = read_binary_file(m_firmware_path);
|
||||
if (!firmware) {
|
||||
std::cerr << "Failed reading firmware file " << firmware.status() << std::endl;
|
||||
return firmware.status();
|
||||
}
|
||||
|
||||
std::cout << "Updating firmware" << std::endl;
|
||||
const bool should_reset = !m_skip_reset;
|
||||
auto status = device.firmware_update(MemoryView(firmware->data(), static_cast<uint32_t>(firmware->size())), should_reset);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Update firmware failed, error code " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
std::cout << "Firmware has been updated" << std::endl;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
34
hailort/hailortcli/fw_update_command.hpp
Normal file
34
hailort/hailortcli/fw_update_command.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file fw_update_command.hpp
|
||||
* @brief Update fw on hailo device with flash
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_FW_UPDATE_COMMAND_COMMAND_HPP_
|
||||
#define _HAILO_FW_UPDATE_COMMAND_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class FwUpdateCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit FwUpdateCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_firmware_path;
|
||||
bool m_skip_reset;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_FW_UPDATE_COMMAND_COMMAND_HPP_ */
|
||||
8
hailort/hailortcli/generate_definitions_json_str.in
Normal file
8
hailort/hailortcli/generate_definitions_json_str.in
Normal file
@@ -0,0 +1,8 @@
|
||||
/* THIS FILE IS AUTOGENERATED! DO NOT MANUALLY EDIT. */
|
||||
|
||||
#ifndef _DEFINITIONS_JSON_AUTO_HPP_
|
||||
#define _DEFINITIONS_JSON_AUTO_HPP_
|
||||
|
||||
static const char* g_fw_config_str_definitions = R"(${config_definitions_json_file})";
|
||||
|
||||
#endif /* _DEFINITIONS_JSON_AUTO_HPP_ */
|
||||
393
hailort/hailortcli/graph_printer.cpp
Normal file
393
hailort/hailortcli/graph_printer.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file graph_printer.cpp
|
||||
* @brief Implementation of graph_printer module
|
||||
**/
|
||||
|
||||
#include "graph_printer.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "common/filesystem.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "infer_stats_printer.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
|
||||
PipelineGraphNode::PipelineGraphNode(DotWriter::RootGraph &G, std::shared_ptr<PipelineElement> elem,
|
||||
const std::vector<AccumulatorPtr> &runtime_stats_accumulators,
|
||||
DotWriter::Color::e node_color, DotWriter::Color::e node_bg_color,
|
||||
const std::string &node_style, DotWriter::LabelLoc::e node_label_loc,
|
||||
const std::string &sink_source_style, DotWriter::Color::e sink_source_color,
|
||||
DotWriter::NodeShape::e sink_source_shape, double sink_source_height,
|
||||
double sink_source_width, DotWriter::LabelLoc::e sub_label_loc) :
|
||||
m_graph_node(nullptr),
|
||||
m_sinks(),
|
||||
m_sources(),
|
||||
m_visited(false)
|
||||
{
|
||||
assert(nullptr != elem);
|
||||
|
||||
const auto label = create_multiline_label({ elem->name() /* TODO: other info will go here */ });
|
||||
const auto sub_label = format_runtime_stats(runtime_stats_accumulators);
|
||||
|
||||
if (static_cast<std::string>(sub_label).empty()) {
|
||||
m_graph_node = G.AddCluster(label);
|
||||
assert(nullptr != m_graph_node);
|
||||
} else {
|
||||
auto *enclosing_cluster = G.AddCluster(sub_label);
|
||||
assert(nullptr != enclosing_cluster);
|
||||
|
||||
enclosing_cluster->GetAttributes().SetLabelLoc(sub_label_loc);
|
||||
enclosing_cluster->GetAttributes().SetPeripheries(0);
|
||||
|
||||
m_graph_node = enclosing_cluster->AddCluster(label);
|
||||
assert(nullptr != m_graph_node);
|
||||
m_graph_node->GetAttributes().SetTooltip(static_cast<std::string>(sub_label));
|
||||
}
|
||||
|
||||
m_graph_node->GetAttributes().SetColor(node_color);
|
||||
m_graph_node->GetAttributes().SetBGColor(node_bg_color);
|
||||
m_graph_node->GetAttributes().SetStyle(node_style);
|
||||
m_graph_node->GetAttributes().SetLabelLoc(node_label_loc);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetStyle(sink_source_style);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetColor(sink_source_color);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetShape(sink_source_shape);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetHeight(sink_source_height);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetWidth(sink_source_width);
|
||||
m_graph_node->GetDefaultNodeAttributes().SetFixedSize(true);
|
||||
|
||||
for (const auto &sink : elem->sinks()) {
|
||||
add_sink(sink);
|
||||
}
|
||||
if (0 == elem->sinks().size()) {
|
||||
add_dummy_sink();
|
||||
}
|
||||
|
||||
for (const auto &source : elem->sources()) {
|
||||
add_source(source);
|
||||
}
|
||||
if (0 == elem->sources().size()) {
|
||||
add_dummy_source();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DotWriter::HtmlString PipelineGraphNode::create_multiline_label(const std::vector<std::string> &lines, Align align_to)
|
||||
{
|
||||
if (lines.empty()) {
|
||||
// Note: A html <table> without any "<tr></tr>" tags is invalid, so if lines is empty, we return an empty string
|
||||
return DotWriter::HtmlString("");
|
||||
}
|
||||
|
||||
std::stringstream result;
|
||||
result << "<table border=\"0\">" << std::endl;
|
||||
for (const auto& line : lines) {
|
||||
result << "\t<tr><td align=\"text\">" << line;
|
||||
if (align_to == Align::LEFT) {
|
||||
result << "<br align=\"left\" />";
|
||||
} else if (align_to == Align::RIGHT) {
|
||||
result << "<br align=\"right\" />";
|
||||
}
|
||||
result << "</td></tr>" << std::endl;
|
||||
}
|
||||
result << "</table>";
|
||||
return DotWriter::HtmlString(result.str());
|
||||
}
|
||||
|
||||
DotWriter::HtmlString PipelineGraphNode::format_runtime_stats(const std::vector<AccumulatorPtr> &runtime_stats_accumulators)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
for (const auto &accumulator : runtime_stats_accumulators) {
|
||||
if (nullptr == accumulator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &accumulator_result = accumulator->get();
|
||||
if ((!accumulator_result.count()) || (accumulator_result.count().value() == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We split the statistics into two lines
|
||||
std::stringstream string_stream;
|
||||
string_stream << "<B>" << accumulator->get_data_type() << ": </B>";
|
||||
string_stream << "mean=" << InferResultsFormatUtils::format_statistic(accumulator_result.mean()) << ", ";
|
||||
string_stream << "min=" << InferResultsFormatUtils::format_statistic(accumulator_result.min()) << ", ";
|
||||
string_stream << "max=" << InferResultsFormatUtils::format_statistic(accumulator_result.max()) << ", ";
|
||||
lines.emplace_back(string_stream.str());
|
||||
|
||||
// Clear the stream and format the next line
|
||||
string_stream.str("");
|
||||
string_stream << "var=" << InferResultsFormatUtils::format_statistic(accumulator_result.var()) << ", ";
|
||||
string_stream << "sd=" << InferResultsFormatUtils::format_statistic(accumulator_result.sd()) << ", ";
|
||||
string_stream << "mean_sd=" << InferResultsFormatUtils::format_statistic(accumulator_result.mean_sd());
|
||||
lines.emplace_back(string_stream.str());
|
||||
}
|
||||
|
||||
return create_multiline_label(lines, Align::LEFT);
|
||||
}
|
||||
|
||||
void PipelineGraphNode::add_sink(const hailort::PipelinePad &pad)
|
||||
{
|
||||
auto *sink = m_graph_node->AddNode("sink");
|
||||
assert(nullptr != sink);
|
||||
sink->GetAttributes().SetTooltip(pad.name());
|
||||
|
||||
m_sinks.emplace(pad.name(), sink);
|
||||
}
|
||||
|
||||
void PipelineGraphNode::add_dummy_sink()
|
||||
{
|
||||
auto *sink = m_graph_node->AddNode();
|
||||
assert(nullptr != sink);
|
||||
sink->GetAttributes().SetStyle("invis");
|
||||
|
||||
m_sinks.emplace("dummy_sink", sink);
|
||||
}
|
||||
|
||||
void PipelineGraphNode::add_source(const hailort::PipelinePad &pad)
|
||||
{
|
||||
auto *source = m_graph_node->AddNode("source");
|
||||
assert(nullptr != source);
|
||||
source->GetAttributes().SetTooltip(pad.name());
|
||||
|
||||
m_sources.emplace(pad.name(), source);
|
||||
|
||||
if (!m_sinks.empty()) {
|
||||
const auto first_sink_name = m_sinks.cbegin()->first;
|
||||
auto *edge = m_graph_node->AddEdge(m_sinks[first_sink_name], source);
|
||||
assert(nullptr != edge);
|
||||
|
||||
edge->GetAttributes().SetStyle("invis");
|
||||
}
|
||||
}
|
||||
|
||||
void PipelineGraphNode::add_dummy_source()
|
||||
{
|
||||
auto *source = m_graph_node->AddNode();
|
||||
assert(nullptr != source);
|
||||
source->GetAttributes().SetStyle("invis");
|
||||
|
||||
m_sources.emplace("dummy_source", source);
|
||||
|
||||
if (!m_sinks.empty()) {
|
||||
const auto first_sink_name = m_sinks.cbegin()->first;
|
||||
auto *edge = m_graph_node->AddEdge(m_sinks[first_sink_name], source);
|
||||
assert(nullptr != edge);
|
||||
|
||||
edge->GetAttributes().SetStyle("invis");
|
||||
}
|
||||
}
|
||||
|
||||
DotWriter::Node *PipelineGraphNode::get_pad(const std::string &pad_name) const
|
||||
{
|
||||
if (m_sinks.count(pad_name) != 0) {
|
||||
return m_sinks.at(pad_name);
|
||||
}
|
||||
assert(m_sources.count(pad_name) != 0);
|
||||
return m_sources.at(pad_name);
|
||||
}
|
||||
|
||||
bool PipelineGraphNode::has_been_visited() const
|
||||
{
|
||||
return m_visited;
|
||||
}
|
||||
|
||||
void PipelineGraphNode::set_visited()
|
||||
{
|
||||
m_visited = true;
|
||||
}
|
||||
|
||||
hailo_status GraphPrinter::write_dot_file(const std::map<std::string, std::vector<InputVStream>> &input_vstreams_per_network,
|
||||
const std::map<std::string, std::vector<OutputVStream>> &output_vstreams_per_network, const std::string &graph_title,
|
||||
const std::string &output_path, bool write_pipeline_stats)
|
||||
{
|
||||
PipelineGraph graph(input_vstreams_per_network, output_vstreams_per_network, graph_title, write_pipeline_stats);
|
||||
return graph.write_dot_file(output_path);
|
||||
}
|
||||
|
||||
|
||||
GraphPrinter::PipelineGraph::PipelineGraph(const std::map<std::string, std::vector<InputVStream>> &input_vstreams_per_network,
|
||||
const std::map<std::string, std::vector<OutputVStream>> &output_vstreams_per_network,
|
||||
const std::string &graph_title, bool write_pipeline_stats) :
|
||||
m_graph(true, create_graph_title_label(graph_title, DefaultNodeAttrs::MAIN_LABEL_FONT_SIZE)),
|
||||
m_elems_in_graph()
|
||||
{
|
||||
size_t total_inputs_count = 0;
|
||||
for (auto &input_vstreams_pair : input_vstreams_per_network) {
|
||||
total_inputs_count += input_vstreams_pair.second.size();
|
||||
}
|
||||
size_t total_outputs_count = 0;
|
||||
for (auto &output_vstreams_pair : output_vstreams_per_network) {
|
||||
total_outputs_count += output_vstreams_pair.second.size();
|
||||
}
|
||||
|
||||
// Set the graph "graph title" label to be on top
|
||||
m_graph.GetAttributes().SetLabelLoc(DotWriter::LabelLoc::T);
|
||||
// Set the graph direction from left to right
|
||||
m_graph.GetAttributes().SetRankDir(DotWriter::RankDir::LR);
|
||||
m_graph.GetAttributes().SetPackMode(format_pack_mode(total_outputs_count + total_inputs_count));
|
||||
|
||||
// Note: This order is important (input pipelines will be printed above output pipelines)
|
||||
for (const auto &output_vstreams_pair : output_vstreams_per_network) {
|
||||
for (const auto &vstream : output_vstreams_pair.second) {
|
||||
update_graph_nodes(vstream.get_pipeline(), write_pipeline_stats);
|
||||
}
|
||||
}
|
||||
for (const auto &input_vstreams_pair : input_vstreams_per_network) {
|
||||
for (const auto &vstream : input_vstreams_pair.second) {
|
||||
update_graph_nodes(vstream.get_pipeline(), write_pipeline_stats);
|
||||
}
|
||||
}
|
||||
for (const auto &output_vstreams_pair : output_vstreams_per_network) {
|
||||
for (const auto &vstream : output_vstreams_pair.second) {
|
||||
update_edges_in_graph(vstream.get_pipeline(), "HW", "user_output");
|
||||
}
|
||||
}
|
||||
for (const auto &input_vstreams_pair : input_vstreams_per_network) {
|
||||
for (const auto &vstream : input_vstreams_pair.second) {
|
||||
update_edges_in_graph(vstream.get_pipeline(), "user_input", "HW");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hailo_status GraphPrinter::PipelineGraph::write_dot_file(const std::string &output_path)
|
||||
{
|
||||
CHECK(m_graph.WriteToFile(output_path), HAILO_FILE_OPERATION_FAILURE,
|
||||
"Faild writing graph '.dot' file to output_path='{}'", output_path);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
DotWriter::Node *GraphPrinter::PipelineGraph::add_external_node(const std::string &label,
|
||||
DotWriter::NodeShape::e shape, double height, double width)
|
||||
{
|
||||
auto *result = m_graph.AddNode(label);
|
||||
assert(nullptr != result);
|
||||
|
||||
result->GetAttributes().SetShape(shape);
|
||||
result->GetAttributes().SetHeight(height);
|
||||
result->GetAttributes().SetWidth(width);
|
||||
result->GetAttributes().SetFixedSize(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
void GraphPrinter::PipelineGraph::update_graph_nodes(const std::vector<std::shared_ptr<PipelineElement>> &pipeline,
|
||||
bool write_pipeline_stats)
|
||||
{
|
||||
// We assume that PipelineElement names are unique (also across different vstreams)
|
||||
for (const auto& elem : pipeline) {
|
||||
const auto elem_name = elem->name();
|
||||
if (m_elems_in_graph.count(elem_name) != 0) {
|
||||
// This elem appears in the graph
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<AccumulatorPtr> runtime_stats_accumulators;
|
||||
if (write_pipeline_stats) {
|
||||
if (nullptr != elem->get_fps_accumulator()) {
|
||||
runtime_stats_accumulators.emplace_back(elem->get_fps_accumulator());
|
||||
}
|
||||
if (nullptr != elem->get_latency_accumulator()) {
|
||||
runtime_stats_accumulators.emplace_back(elem->get_latency_accumulator());
|
||||
}
|
||||
for (const auto &queue_size_accumulator : elem->get_queue_size_accumulators()) {
|
||||
if (nullptr != queue_size_accumulator) {
|
||||
runtime_stats_accumulators.emplace_back(queue_size_accumulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
PipelineGraphNode curr_elem_graph_node(m_graph, elem, runtime_stats_accumulators);
|
||||
m_elems_in_graph.emplace(elem_name, std::move(curr_elem_graph_node));
|
||||
}
|
||||
}
|
||||
|
||||
void GraphPrinter::PipelineGraph::update_edges_in_graph_recursive(const PipelineElement &root,
|
||||
const std::string &output_elem_name)
|
||||
{
|
||||
auto &curr_elem_graph_node = m_elems_in_graph.at(root.name());
|
||||
if (curr_elem_graph_node.has_been_visited()) {
|
||||
return;
|
||||
}
|
||||
curr_elem_graph_node.set_visited();
|
||||
|
||||
for (const auto &source : root.sources()) {
|
||||
if (nullptr == source.next()) {
|
||||
auto *left = curr_elem_graph_node.get_pad(source.name());
|
||||
auto *right = add_external_node(output_elem_name);
|
||||
m_graph.AddEdge(left, right);
|
||||
continue;
|
||||
}
|
||||
const auto *sink = source.next();
|
||||
|
||||
const auto &next_elem = sink->element();
|
||||
const auto next_elem_name = next_elem.name();
|
||||
|
||||
auto *left = curr_elem_graph_node.get_pad(source.name());
|
||||
auto *right = m_elems_in_graph.at(next_elem_name).get_pad(sink->name());
|
||||
m_graph.AddEdge(left, right);
|
||||
|
||||
update_edges_in_graph_recursive(next_elem, output_elem_name);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphPrinter::PipelineGraph::update_edges_in_graph(const std::vector<std::shared_ptr<PipelineElement>> &pipeline,
|
||||
const std::string &input_elem_name, const std::string &output_elem_name)
|
||||
{
|
||||
for (const auto &root_elem : get_pipeline_root_elements(pipeline)) {
|
||||
auto &root_elem_graph_node = m_elems_in_graph.at(root_elem->name());
|
||||
if (root_elem_graph_node.has_been_visited()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &sink : root_elem->sinks()) {
|
||||
auto *left = add_external_node(input_elem_name);
|
||||
auto *right = root_elem_graph_node.get_pad(sink.name());
|
||||
m_graph.AddEdge(left, right);
|
||||
}
|
||||
|
||||
update_edges_in_graph_recursive(*root_elem, output_elem_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GraphPrinter::PipelineGraph::format_pack_mode(size_t num_rows)
|
||||
{
|
||||
// Align the graph as an array of num_rows rows (see https://graphviz.org/docs/attr-types/packMode/)
|
||||
std::stringstream result;
|
||||
result << "array_t" << std::to_string(num_rows);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
DotWriter::HtmlString GraphPrinter::PipelineGraph::create_graph_title_label(const std::string &hef_path,
|
||||
uint32_t font_size)
|
||||
{
|
||||
std::stringstream result;
|
||||
result << "<font point-size=\"" << std::to_string(font_size) << "\">";
|
||||
result << "<b>Network:</b> " << hef_path;
|
||||
result << "</font>";
|
||||
return DotWriter::HtmlString(result.str());
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<PipelineElement>> GraphPrinter::PipelineGraph::get_pipeline_root_elements(
|
||||
const std::vector<std::shared_ptr<PipelineElement>> &pipeline)
|
||||
{
|
||||
std::vector<std::shared_ptr<PipelineElement>> root_elems;
|
||||
for (auto& elem : pipeline) {
|
||||
if ((0 == elem->sinks().size()) || std::all_of(elem->sinks().begin(), elem->sinks().end(),
|
||||
[](auto &sink){ return nullptr == sink.prev(); })) {
|
||||
// A PipelineElement is a "root" if it has no sink pads or it's sink pads aren't connected to source pads
|
||||
root_elems.emplace_back(elem);
|
||||
}
|
||||
}
|
||||
|
||||
return root_elems;
|
||||
}
|
||||
|
||||
} /* namespace hailort */
|
||||
163
hailort/hailortcli/graph_printer.hpp
Normal file
163
hailort/hailortcli/graph_printer.hpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file graph_printer.hpp
|
||||
* @brief Print pipeline graphs to '.dot' files
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_GRAPH_PRINTER_HPP_
|
||||
#define _HAILO_GRAPH_PRINTER_HPP_
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/vstream.hpp"
|
||||
#include "pipeline.hpp"
|
||||
|
||||
#include "DotWriter.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace hailort
|
||||
{
|
||||
|
||||
class DefaultNodeAttrs final
|
||||
{
|
||||
public:
|
||||
DefaultNodeAttrs() = delete;
|
||||
|
||||
// Titles
|
||||
static constexpr uint32_t MAIN_LABEL_FONT_SIZE = 28;
|
||||
static constexpr uint32_t PIPELINE_LABEL_FONT_SIZE = 24;
|
||||
|
||||
// Pipeline nodes
|
||||
static constexpr DotWriter::Color::e PIPELINE_NODE_COLOR = DotWriter::Color::LIGHTGREY;
|
||||
static constexpr DotWriter::Color::e PIPELINE_NODE_BG_COLOR = DotWriter::Color::LIGHTGREY;
|
||||
static std::string PIPELINE_NODE_STYLE() { return "rounded"; };
|
||||
static constexpr DotWriter::LabelLoc::e PIPELINE_NODE_LABEL_LOC = DotWriter::LabelLoc::T;
|
||||
|
||||
// Sink/source nodes
|
||||
static std::string SINK_SOURCE_STYLE() { return "filled"; };
|
||||
static constexpr DotWriter::Color::e SINK_SOURCE_COLOR = DotWriter::Color::WHITE;
|
||||
static constexpr DotWriter::NodeShape::e SINK_SOURCE_SHAPE = DotWriter::NodeShape::RECTANGLE;
|
||||
static constexpr double SINK_SOURCE_HEIGHT = 0.5;
|
||||
static constexpr double SINK_SOURCE_WIDTH = 0.7;
|
||||
|
||||
// External nodes (HW, user_input, user_output)
|
||||
static constexpr DotWriter::NodeShape::e EXTERNAL_NODE_SHAPE = DotWriter::NodeShape::RECTANGLE;
|
||||
static constexpr double EXTERNAL_NODE_HEIGHT = 0.5;
|
||||
static constexpr double EXTERNAL_NODE_WIDTH = 1;
|
||||
|
||||
// Sublabel
|
||||
static constexpr DotWriter::LabelLoc::e SUBLABEL_LOC = DotWriter::LabelLoc::B;
|
||||
};
|
||||
|
||||
class PipelineGraphNode final
|
||||
{
|
||||
public:
|
||||
PipelineGraphNode(DotWriter::RootGraph &G, std::shared_ptr<PipelineElement> elem,
|
||||
const std::vector<AccumulatorPtr> &runtime_stats_accumulators,
|
||||
DotWriter::Color::e node_color = DefaultNodeAttrs::PIPELINE_NODE_COLOR,
|
||||
DotWriter::Color::e node_bg_color = DefaultNodeAttrs::PIPELINE_NODE_BG_COLOR,
|
||||
const std::string &node_style = DefaultNodeAttrs::PIPELINE_NODE_STYLE(),
|
||||
DotWriter::LabelLoc::e node_label_loc = DefaultNodeAttrs::PIPELINE_NODE_LABEL_LOC,
|
||||
const std::string &sink_source_style = DefaultNodeAttrs::SINK_SOURCE_STYLE(),
|
||||
DotWriter::Color::e sink_source_color = DefaultNodeAttrs::SINK_SOURCE_COLOR,
|
||||
DotWriter::NodeShape::e sink_source_shape = DefaultNodeAttrs::SINK_SOURCE_SHAPE,
|
||||
double sink_source_height = DefaultNodeAttrs::SINK_SOURCE_HEIGHT,
|
||||
double sink_source_width = DefaultNodeAttrs::SINK_SOURCE_WIDTH,
|
||||
DotWriter::LabelLoc::e sub_label_loc = DefaultNodeAttrs::SUBLABEL_LOC);
|
||||
|
||||
PipelineGraphNode(PipelineGraphNode &&) = default;
|
||||
PipelineGraphNode(const PipelineGraphNode &) = delete;
|
||||
PipelineGraphNode &operator=(PipelineGraphNode &&) = delete;
|
||||
PipelineGraphNode &operator=(const PipelineGraphNode &) = delete;
|
||||
~PipelineGraphNode() = default;
|
||||
|
||||
DotWriter::Node *get_pad(const std::string &pad_name) const;
|
||||
bool has_been_visited() const;
|
||||
void set_visited();
|
||||
|
||||
private:
|
||||
enum class Align
|
||||
{
|
||||
LEFT,
|
||||
RIGHT,
|
||||
CENTER
|
||||
};
|
||||
|
||||
// Creates a HtmlString with each line in lines on a new line, or an empty string if lines is empty
|
||||
static DotWriter::HtmlString create_multiline_label(const std::vector<std::string> &lines, Align align_to = Align::CENTER);
|
||||
static DotWriter::HtmlString format_runtime_stats(const std::vector<AccumulatorPtr> &runtime_stats_accumulators);
|
||||
|
||||
// Note:
|
||||
// * Sink/source pads are nested under the pipeline element node.
|
||||
// * Sinks always appear on the left side of the pipeline element node, and sources on the right.
|
||||
// * If an element has no sinks/soruces, then an invisible "dummy" sink/source is added.
|
||||
// This is used to align the other pads in the elem to the left/right (a Graphviz oddity).
|
||||
// E.g:
|
||||
// ------------------------------------ ------------------------------------
|
||||
// | Filter_Elem1 | | Sink_Elem1 |
|
||||
// | | | |
|
||||
// | -------- -------- | | -------- |
|
||||
// --|-->| sink | |source|----|---------------|-->| sink | (dummy source) |
|
||||
// | -------- -------- | | -------- (invisible) |
|
||||
// | | | |
|
||||
// ------------------------------------ ------------------------------------
|
||||
void add_sink(const hailort::PipelinePad &pad);
|
||||
void add_dummy_sink();
|
||||
void add_source(const hailort::PipelinePad &pad);
|
||||
void add_dummy_source();
|
||||
|
||||
DotWriter::Cluster *m_graph_node;
|
||||
std::map<std::string, DotWriter::Node *> m_sinks;
|
||||
std::map<std::string, DotWriter::Node *> m_sources;
|
||||
bool m_visited;
|
||||
};
|
||||
|
||||
class GraphPrinter
|
||||
{
|
||||
public:
|
||||
GraphPrinter() = delete;
|
||||
static hailo_status write_dot_file(const std::map<std::string, std::vector<InputVStream>> &input_vstreams_per_network,
|
||||
const std::map<std::string, std::vector<OutputVStream>> &output_vstreams_per_network,
|
||||
const std::string &graph_title, const std::string &output_path, bool write_pipeline_stats);
|
||||
|
||||
private:
|
||||
class PipelineGraph final
|
||||
{
|
||||
public:
|
||||
PipelineGraph(const std::map<std::string, std::vector<InputVStream>> &input_vstreams_per_network,
|
||||
const std::map<std::string, std::vector<OutputVStream>> &output_vstreams_per_network,
|
||||
const std::string &graph_title, bool write_pipeline_stats);
|
||||
hailo_status write_dot_file(const std::string &output_path);
|
||||
|
||||
private:
|
||||
DotWriter::RootGraph m_graph;
|
||||
std::map<std::string, PipelineGraphNode> m_elems_in_graph;
|
||||
|
||||
DotWriter::Node *add_external_node(const std::string &label,
|
||||
DotWriter::NodeShape::e shape = DefaultNodeAttrs::EXTERNAL_NODE_SHAPE,
|
||||
double height = DefaultNodeAttrs::EXTERNAL_NODE_HEIGHT,
|
||||
double width = DefaultNodeAttrs::EXTERNAL_NODE_WIDTH);
|
||||
// Add all the pipeline nodes in the graph to m_graph
|
||||
void update_graph_nodes(const std::vector<std::shared_ptr<PipelineElement>> &pipeline, bool write_pipeline_stats);
|
||||
// update_edges_* will be called after adding the graph nodes with 'update_graph_nodes'
|
||||
// Update the edges in the pipeline graph recursively, starting at root (using DFS)
|
||||
void update_edges_in_graph_recursive(const PipelineElement &root, const std::string &output_elem_name);
|
||||
// Update all of the edges in the pipeline graph
|
||||
void update_edges_in_graph(const std::vector<std::shared_ptr<PipelineElement>> &pipeline,
|
||||
const std::string &input_elem_name, const std::string &output_elem_name);
|
||||
|
||||
static std::string format_pack_mode(size_t num_rows);
|
||||
static DotWriter::HtmlString create_graph_title_label(const std::string &hef_path, uint32_t font_size);
|
||||
static std::vector<std::shared_ptr<PipelineElement>> get_pipeline_root_elements(
|
||||
const std::vector<std::shared_ptr<PipelineElement>> &pipeline);
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace hailort */
|
||||
|
||||
#endif /* _HAILO_GRAPH_PRINTER_HPP_ */
|
||||
246
hailort/hailortcli/hailortcli.cpp
Normal file
246
hailort/hailortcli/hailortcli.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file hailortcli.cpp
|
||||
* @brief HailoRT CLI.
|
||||
*
|
||||
* HailoRT command line interface.
|
||||
**/
|
||||
#include "hailortcli.hpp"
|
||||
#include "scan_command.hpp"
|
||||
#include "power_measurement_command.hpp"
|
||||
#include "run_command.hpp"
|
||||
#include "fw_update_command.hpp"
|
||||
#include "ssb_update_command.hpp"
|
||||
#include "sensor_config_command.hpp"
|
||||
#include "board_config_command.hpp"
|
||||
#include "fw_config_command.hpp"
|
||||
#include "fw_logger_command.hpp"
|
||||
#include "benchmark_command.hpp"
|
||||
#if defined(__GNUC__)
|
||||
#include "udp_rate_limiter_command.hpp"
|
||||
#endif
|
||||
#include "parse_hef_command.hpp"
|
||||
#include "fw_control_command.hpp"
|
||||
|
||||
#include "firmware_header_utils.h"
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/hailort_common.hpp"
|
||||
#include "hailo/device.hpp"
|
||||
#include "hailo/hef.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
|
||||
static Expected<hailo_pcie_device_info_t> get_pcie_device_info(const hailo_pcie_params &pcie_params)
|
||||
{
|
||||
if (pcie_params.pcie_bdf.empty()) {
|
||||
auto scan_result = Device::scan_pcie();
|
||||
if (!scan_result) {
|
||||
std::cerr << "Hailo PCIe scan failed (maybe pcie device not exists). status=" << scan_result.status() << std::endl;
|
||||
return make_unexpected(scan_result.status());
|
||||
}
|
||||
|
||||
if (scan_result->size() == 0) {
|
||||
std::cerr << "Hailo PCIe not found.." << std::endl;
|
||||
return make_unexpected(HAILO_INTERNAL_FAILURE);
|
||||
}
|
||||
return std::move(scan_result->at(0));
|
||||
} else {
|
||||
auto device_info_expected = Device::parse_pcie_device_info(pcie_params.pcie_bdf);
|
||||
if (!device_info_expected) {
|
||||
std::cerr << "Invalid pcie bdf format" << std::endl;
|
||||
return make_unexpected(device_info_expected.status());
|
||||
}
|
||||
return device_info_expected.release();
|
||||
}
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<Device>> create_pcie_device(const hailo_pcie_params &pcie_params)
|
||||
{
|
||||
auto device_info = get_pcie_device_info(pcie_params);
|
||||
if (!device_info) {
|
||||
return make_unexpected(device_info.status());
|
||||
}
|
||||
|
||||
auto device = Device::create_pcie(device_info.value());
|
||||
if (!device) {
|
||||
std::cerr << "Failed create pcie device. status=" << device.status() << std::endl;
|
||||
return make_unexpected(device.status());
|
||||
}
|
||||
|
||||
return Expected<std::unique_ptr<Device>>(device.release());
|
||||
}
|
||||
|
||||
static Expected<std::unique_ptr<Device>> create_eth_device(const hailo_eth_params ð_params)
|
||||
{
|
||||
auto device = Device::create_eth(eth_params.ip_addr);
|
||||
if (!device) {
|
||||
std::cerr << "Failed create ethernet device. status=" << device.status() << std::endl;
|
||||
return make_unexpected(device.status());
|
||||
}
|
||||
|
||||
return Expected<std::unique_ptr<Device>>(device.release());
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<Device>> create_device(const hailo_device_params &device_params)
|
||||
{
|
||||
switch (device_params.device_type) {
|
||||
case DeviceType::PCIE:
|
||||
return create_pcie_device(device_params.pcie_params);
|
||||
case DeviceType::ETH:
|
||||
return create_eth_device(device_params.eth_params);
|
||||
case DeviceType::DEFAULT:
|
||||
// If core driver is loaded (we are running on Mercury) then the default is core device; else, pcie device
|
||||
if (Device::is_core_driver_loaded()) {
|
||||
return Device::create_core_device();
|
||||
} else {
|
||||
return create_pcie_device(device_params.pcie_params);
|
||||
}
|
||||
default:
|
||||
std::cerr << "Invalid device type" << std::endl;
|
||||
return make_unexpected(HAILO_INVALID_ARGUMENT);
|
||||
}
|
||||
}
|
||||
|
||||
void add_device_options(CLI::App *app, hailo_device_params &device_params)
|
||||
{
|
||||
// Initialize the device type to default
|
||||
device_params.device_type = DeviceType::DEFAULT;
|
||||
|
||||
auto group = app->add_option_group("Device Options");
|
||||
|
||||
// TODO: `--target` and `udp` DeviceType::ETH are for backwards compatibility with the python implemention (`hailo`)
|
||||
// TODO: Remove them (HRT-2676)
|
||||
const HailoCheckedTransformer<DeviceType> device_type_transformer({
|
||||
{ "pcie", DeviceType::PCIE },
|
||||
{ "eth", DeviceType::ETH },
|
||||
{ "udp", DeviceType::ETH },
|
||||
});
|
||||
auto *device_type_option = group->add_option("-d,--device-type,--target", device_params.device_type,
|
||||
"Device type to use\n"
|
||||
"Default is pcie.\n"
|
||||
"Note: 'udp' is an alias for 'eth'.")
|
||||
->transform(device_type_transformer);
|
||||
|
||||
std::vector<DeprecationActionPtr> actions{ std::make_shared<ValueDeprecation>(device_type_option, "udp", "eth") };
|
||||
hailo_deprecate_options(app, actions, false);
|
||||
|
||||
// PCIe options
|
||||
auto *pcie_bdf_option = group->add_option("-s,--bdf", device_params.pcie_params.pcie_bdf,
|
||||
"Device id ([<domain>]:<bus>:<device>.<func>, same as in lspci command)")
|
||||
->default_val("");
|
||||
|
||||
// Ethernet options
|
||||
auto *ip_option = group->add_option("--ip", device_params.eth_params.ip_addr, "IP address of the target")
|
||||
->default_val("")
|
||||
->check(CLI::ValidIPV4);
|
||||
|
||||
group->parse_complete_callback([&device_params, device_type_option, pcie_bdf_option, ip_option](){
|
||||
// The user didn't put target, we can figure it ourself
|
||||
if (device_type_option->empty()) {
|
||||
if (!ip_option->empty()) {
|
||||
// User gave IP, target is eth
|
||||
device_params.device_type = DeviceType::ETH;
|
||||
} else if (!pcie_bdf_option->empty()) {
|
||||
// User gave bdf, target is pcie
|
||||
device_params.device_type = DeviceType::PCIE;
|
||||
}
|
||||
else {
|
||||
device_params.device_type = DeviceType::DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (ip_option->empty() && device_params.device_type == DeviceType::ETH) {
|
||||
throw CLI::ParseError("IP address is not set", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
|
||||
if (!ip_option->empty() && device_params.device_type != DeviceType::ETH) {
|
||||
throw CLI::ParseError("IP address is set on non eth device", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
|
||||
if (!pcie_bdf_option->empty() && device_params.device_type != DeviceType::PCIE) {
|
||||
throw CLI::ParseError("bdf (-s) is set on non pcie device", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void add_vdevice_options(CLI::App *app, hailo_device_params &device_params) {
|
||||
auto group = app->add_option_group("VDevice Options");
|
||||
|
||||
// VDevice options
|
||||
auto *device_count_option = group->add_option("--device-count", device_params.vdevice_params.device_count, "VDevice device count")
|
||||
->default_val(HAILO_DEFAULT_DEVICE_COUNT)
|
||||
->check(CLI::PositiveNumber);
|
||||
|
||||
group->parse_complete_callback([&device_params, device_count_option](){
|
||||
// The user gave device_count
|
||||
if (!device_count_option->empty()) {
|
||||
if ((device_params.vdevice_params.device_count > 1) &&
|
||||
((DeviceType::ETH == device_params.device_type) || (DeviceType::PCIE == device_params.device_type && !device_params.pcie_params.pcie_bdf.empty()))) {
|
||||
throw CLI::ParseError("Device type must not be specified when using multiple devices", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class HailoRTCLI : public ContainerCommand {
|
||||
public:
|
||||
HailoRTCLI(CLI::App *app) : ContainerCommand(app)
|
||||
{
|
||||
|
||||
m_app->add_flag_callback("-v,--version",
|
||||
[] () {
|
||||
std::cout << "hailortcli version " <<
|
||||
HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION << std::endl;
|
||||
// throw CLI::Success to stop parsing and not failing require_subcommand(1) we set earlier
|
||||
throw (CLI::Success{});
|
||||
},
|
||||
"Print program version and exit"
|
||||
);
|
||||
|
||||
add_subcommand<RunCommand>();
|
||||
add_subcommand<ScanSubcommand>();
|
||||
add_subcommand<BenchmarkCommand>();
|
||||
add_subcommand<PowerMeasurementSubcommand>();
|
||||
add_subcommand<SensorConfigCommand>();
|
||||
add_subcommand<BoardConfigCommand>();
|
||||
add_subcommand<FwConfigCommand>();
|
||||
add_subcommand<FwLoggerCommand>();
|
||||
add_subcommand<FwUpdateCommand>();
|
||||
add_subcommand<SSBUpdateCommand>();
|
||||
#if defined(__GNUC__)
|
||||
add_subcommand<UdpRateLimiterCommand>();
|
||||
#endif
|
||||
add_subcommand<ParseHefCommand>();
|
||||
add_subcommand<FwControlCommand>();
|
||||
}
|
||||
|
||||
int parse_and_execute(int argc, char **argv)
|
||||
{
|
||||
CLI11_PARSE(*m_app, argc, argv);
|
||||
return execute();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
|
||||
console_sink->set_level(spdlog::level::info);
|
||||
console_sink->set_pattern("[%n] [%^%l%$] %v");
|
||||
spdlog::set_default_logger(std::make_shared<spdlog::logger>("HailoRT CLI", console_sink));
|
||||
|
||||
CLI::App app{"HailoRT CLI"};
|
||||
HailoRTCLI cli(&app);
|
||||
return cli.parse_and_execute(argc, argv);
|
||||
}
|
||||
202
hailort/hailortcli/hailortcli.hpp
Normal file
202
hailort/hailortcli/hailortcli.hpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file hailortcli.hpp
|
||||
* @brief HailoRT CLI.
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_HAILORTCLI_HPP_
|
||||
#define _HAILO_HAILORTCLI_HPP_
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/expected.hpp"
|
||||
#include "hailo/device.hpp"
|
||||
#include "common/logger_macros.hpp"
|
||||
#include "common/utils.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
#include <string>
|
||||
|
||||
using namespace hailort;
|
||||
|
||||
#define PARSE_CHECK(cond, message) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
throw CLI::ParseError(message, CLI::ExitCodes::InvalidError); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct hailo_pcie_params {
|
||||
std::string pcie_bdf; // if empty use the first scanned
|
||||
};
|
||||
|
||||
struct hailo_eth_params {
|
||||
std::string ip_addr;
|
||||
};
|
||||
|
||||
struct hailo_vdevice_params {
|
||||
uint32_t device_count;
|
||||
};
|
||||
|
||||
enum class DeviceType {
|
||||
PCIE = 0,
|
||||
ETH,
|
||||
DEFAULT
|
||||
};
|
||||
|
||||
struct hailo_device_params {
|
||||
DeviceType device_type;
|
||||
hailo_pcie_params pcie_params;
|
||||
hailo_eth_params eth_params;
|
||||
hailo_vdevice_params vdevice_params;
|
||||
};
|
||||
|
||||
void add_device_options(CLI::App *app, hailo_device_params &device_params);
|
||||
void add_vdevice_options(CLI::App *app, hailo_device_params &device_params);
|
||||
Expected<std::unique_ptr<Device>> create_device(const hailo_device_params &device_params);
|
||||
Expected<std::unique_ptr<Device>> create_pcie_device(const hailo_pcie_params &pcie_params);
|
||||
|
||||
/**
|
||||
* CLI11 transformer object, converting enum argument from string.
|
||||
* Use this object instead of CLI::CheckedTransformer in order
|
||||
* to avoid ugly prints in the help message.
|
||||
*/
|
||||
template<typename EnumType>
|
||||
class HailoCheckedTransformer : public CLI::CheckedTransformer
|
||||
{
|
||||
public:
|
||||
HailoCheckedTransformer(std::vector<std::pair<std::string, EnumType>> values) :
|
||||
CLI::CheckedTransformer(values)
|
||||
{
|
||||
desc_function_ = [values]() {
|
||||
return CLI::detail::generate_map(CLI::detail::smart_deref(values), true);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class DeprecationAction
|
||||
{
|
||||
public:
|
||||
DeprecationAction() = default;
|
||||
virtual ~DeprecationAction() = default;
|
||||
|
||||
virtual std::string deprecate(bool message_inline) = 0;
|
||||
static std::string get_inline_description(CLI::Option *opt, const std::string &message)
|
||||
{
|
||||
const auto orig_desc = opt->get_description();
|
||||
std::stringstream new_desc;
|
||||
if (!orig_desc.empty()) {
|
||||
new_desc << orig_desc;
|
||||
if (orig_desc.back() != '\n') {
|
||||
new_desc << std::endl;
|
||||
}
|
||||
}
|
||||
new_desc << "Note: " << message;
|
||||
return new_desc.str();
|
||||
}
|
||||
};
|
||||
using DeprecationActionPtr = std::shared_ptr<DeprecationAction>;
|
||||
|
||||
class OptionDeprecation : public DeprecationAction
|
||||
{
|
||||
public:
|
||||
OptionDeprecation(CLI::Option *opt, const std::string &replacement) :
|
||||
DeprecationAction(),
|
||||
m_opt(opt),
|
||||
m_replacement(replacement)
|
||||
{
|
||||
assert(nullptr != opt);
|
||||
}
|
||||
|
||||
virtual ~OptionDeprecation() = default;
|
||||
|
||||
// Based off of CLI::deprecate_option, changed logic to suit our needs
|
||||
virtual std::string deprecate(bool message_inline) override
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "'" << m_opt->get_name() << "' is deprecated, please use '" << m_replacement << "' instead." << std::endl;
|
||||
CLI::Validator deprecate_warning(
|
||||
[message = message.str()](std::string &) {
|
||||
std::cout << message;
|
||||
return std::string();
|
||||
}, message_inline ? "" : "DEPRECATED");
|
||||
deprecate_warning.application_index(0);
|
||||
if (message_inline) {
|
||||
m_opt->description(get_inline_description(m_opt, message.str()));
|
||||
}
|
||||
m_opt->check(deprecate_warning);
|
||||
return message.str();
|
||||
}
|
||||
|
||||
private:
|
||||
CLI::Option *const m_opt;
|
||||
const std::string m_replacement;
|
||||
};
|
||||
|
||||
class ValueDeprecation : public DeprecationAction
|
||||
{
|
||||
public:
|
||||
ValueDeprecation(CLI::Option *opt, const std::string &value, const std::string &replacement) :
|
||||
DeprecationAction(),
|
||||
m_opt(opt),
|
||||
m_value(value),
|
||||
m_replacement(replacement)
|
||||
{
|
||||
assert(nullptr != opt);
|
||||
}
|
||||
|
||||
virtual ~ValueDeprecation() = default;
|
||||
|
||||
// Based off of CLI::deprecate_option, changed logic to suit our needs
|
||||
virtual std::string deprecate(bool message_inline) override
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "'" << m_value << "' is deprecated, please use '" << m_replacement << "' instead." << std::endl;
|
||||
// We capture the members by value (i.e. copy), since the Validator can outlive this object
|
||||
CLI::Validator deprecate_warning(
|
||||
[message = message.str(), opt = m_opt, value = m_value](std::string &) {
|
||||
const auto results = opt->results();
|
||||
if ((results.size() == 1) && (results[0] == value)) {
|
||||
std::cout << message;
|
||||
}
|
||||
return std::string();
|
||||
}, "");
|
||||
deprecate_warning.application_index(0);
|
||||
if (message_inline) {
|
||||
m_opt->description(get_inline_description(m_opt, message.str()));
|
||||
}
|
||||
// Hack: transform() and not check(), because we want the string values of opt->results() and not the enum values after HailoCheckedTransformer
|
||||
// transform places the Validator at the head of the validators in opt, so we'll get this check before the transformation is done
|
||||
m_opt->transform(deprecate_warning);
|
||||
return message.str();
|
||||
}
|
||||
|
||||
private:
|
||||
CLI::Option *const m_opt;
|
||||
const std::string m_value;
|
||||
const std::string m_replacement;
|
||||
};
|
||||
|
||||
inline void hailo_deprecate_options(CLI::App *app, const std::vector<DeprecationActionPtr> &actions, bool set_footer = true)
|
||||
{
|
||||
// std::set and not std::vector in case two actions have the smae deprection string
|
||||
std::set<std::string> deprecation_messages;
|
||||
for (const auto& deprecation_action : actions) {
|
||||
deprecation_messages.insert(deprecation_action->deprecate(!set_footer));
|
||||
}
|
||||
|
||||
if (set_footer) {
|
||||
std::stringstream footer_message;
|
||||
footer_message << "Deprecated flags/options:" << std::endl;
|
||||
for (const auto &message : deprecation_messages) {
|
||||
footer_message << " * " << message;
|
||||
if (message.back() != '\n') {
|
||||
footer_message << std::endl;
|
||||
}
|
||||
}
|
||||
app->footer(footer_message.str());
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _HAILO_HAILORTCLI_HPP_ */
|
||||
459
hailort/hailortcli/infer_stats_printer.cpp
Normal file
459
hailort/hailortcli/infer_stats_printer.cpp
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file infer_stats_printer.cpp
|
||||
* @brief Show inference progress
|
||||
**/
|
||||
|
||||
#include "infer_stats_printer.hpp"
|
||||
#include "run_command.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
static std::string infer_mode_to_string(InferMode infer_mode)
|
||||
{
|
||||
switch (infer_mode) {
|
||||
case InferMode::STREAMING:
|
||||
return "streaming";
|
||||
case InferMode::HW_ONLY:
|
||||
return "hw_only";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
std::string InferResultsFormatUtils::format_statistic(const Expected<double> &statistic, uint32_t precision)
|
||||
{
|
||||
if (!statistic.has_value()) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
std::stringstream string_stream;
|
||||
string_stream << std::fixed << std::setprecision(precision) << statistic.value();
|
||||
return string_stream.str();
|
||||
}
|
||||
|
||||
std::string InferResultsFormatUtils::format_statistic(const Expected<size_t> &statistic)
|
||||
{
|
||||
if (!statistic.has_value()) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
return std::to_string(statistic.value());
|
||||
}
|
||||
|
||||
double InferResultsFormatUtils::latency_result_to_ms(std::chrono::nanoseconds latency)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(latency).count();
|
||||
}
|
||||
|
||||
Expected<InferStatsPrinter> InferStatsPrinter::create(const inference_runner_params ¶ms, bool print_running_info)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
InferStatsPrinter printer(params, status, print_running_info);
|
||||
CHECK_SUCCESS_AS_EXPECTED(status);
|
||||
return printer;
|
||||
}
|
||||
|
||||
|
||||
InferStatsPrinter::InferStatsPrinter(const inference_runner_params ¶ms, hailo_status &output_status, bool print_running_info) :
|
||||
m_print_frame_count(0 != params.time_to_run)
|
||||
{
|
||||
if (!params.csv_output.empty()) {
|
||||
m_results_csv_path = params.csv_output;
|
||||
m_results_csv_file.open(params.csv_output.c_str(), std::ios::out);
|
||||
if (!m_results_csv_file.good()) {
|
||||
LOGGER__ERROR("Failed creating csv output file {}", params.csv_output);
|
||||
output_status = HAILO_OPEN_FILE_FAILURE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_measure_pipeline_stats(params)) {
|
||||
m_pipeline_stats_csv_path = params.pipeline_stats.pipeline_stats_output_path;
|
||||
m_pipeline_stats_csv_file.open(params.pipeline_stats.pipeline_stats_output_path.c_str(),
|
||||
std::ios::out);
|
||||
if (!m_pipeline_stats_csv_file.good()) {
|
||||
LOGGER__ERROR("Failed creating pipeline stats csv output file {}",
|
||||
params.pipeline_stats.pipeline_stats_output_path);
|
||||
output_status = HAILO_OPEN_FILE_FAILURE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (print_running_info) {
|
||||
std::cout << "Running " << infer_mode_to_string(params.mode) << " inference (" << params.hef_path << "):" << std::endl;
|
||||
std::cout << " Transform data: " << std::boolalpha << params.transform.transform << std::endl;
|
||||
if (params.transform.transform) {
|
||||
std::cout << " Type: " << format_type_to_string(params.transform.format_type) << std::endl;
|
||||
std::cout << " Quantized: " << std::boolalpha << params.transform.quantized << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!params.dot_output.empty()) {
|
||||
m_dot_output_path = params.dot_output;
|
||||
}
|
||||
|
||||
output_status = HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print(const std::string &network_group_name, Expected<NetworkGroupInferResult>& inference_result)
|
||||
{
|
||||
if (m_results_csv_file.is_open()) {
|
||||
std::cout << "> Writing inference results to '" << m_results_csv_path << "'... ";
|
||||
print_csv(network_group_name, inference_result);
|
||||
std::cout << "done." << std::endl;
|
||||
}
|
||||
if (m_pipeline_stats_csv_file.is_open()) {
|
||||
std::cout << "> Writing pipeline statistics to '" << m_pipeline_stats_csv_path << "'... ";
|
||||
m_pipeline_stats_csv_file << "net_name,vstream_name,param_type,element,mean,min,max,var,sd,mean_sd,index" << std::endl;
|
||||
print_pipeline_elem_stats_csv(network_group_name, inference_result->m_fps_accumulators);
|
||||
print_pipeline_elem_stats_csv(network_group_name, inference_result->m_latency_accumulators);
|
||||
print_pipeline_elem_stats_csv(network_group_name, inference_result->m_queue_size_accumulators);
|
||||
print_entire_pipeline_stats_csv(network_group_name, inference_result->m_pipeline_latency_accumulators);
|
||||
std::cout << "done." << std::endl;
|
||||
}
|
||||
print_stdout(inference_result);
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_csv_header()
|
||||
{
|
||||
m_results_csv_file << "net_name,status,status_description,fps,num_of_frames,send_rate,recv_rate,hw_latency,overall_latency,min_power,average_power,max_power,min_current,average_current,max_current,min_temp,average_temp,max_temp" << std::endl;
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_benchmark_csv_header()
|
||||
{
|
||||
m_results_csv_file << "net_name,fps,hw_only_fps,num_of_frames,num_of_frames_hw_only,hw_latency,overall_latency,min_power,average_power,max_power" << std::endl;
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_csv(const std::string &network_group_name, Expected<NetworkGroupInferResult>& inference_result)
|
||||
{
|
||||
auto status_description = hailo_get_status_message(inference_result.status());
|
||||
m_results_csv_file << network_group_name << "," << static_cast<uint32_t>(inference_result.status()) << "," << status_description;
|
||||
if (!inference_result) {
|
||||
m_results_csv_file << ",,,,,,,,,,,";
|
||||
}
|
||||
else {
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto fps = inference_result->fps()) {
|
||||
m_results_csv_file << fps.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto frames_count = inference_result->frames_count()) {
|
||||
m_results_csv_file << frames_count.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto send_data_rate = inference_result->send_data_rate_mbit_sec()) {
|
||||
m_results_csv_file << send_data_rate.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto recv_data_rate = inference_result->recv_data_rate_mbit_sec()) {
|
||||
m_results_csv_file << recv_data_rate.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto hw_latency = inference_result->hw_latency()) {
|
||||
m_results_csv_file << InferResultsFormatUtils::latency_result_to_ms(hw_latency.value());
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto overall_latency = inference_result->overall_latency()) {
|
||||
m_results_csv_file << InferResultsFormatUtils::latency_result_to_ms(overall_latency.value());
|
||||
}
|
||||
|
||||
// TODO HRT-5363 support multiple devices (Currently assumes 1 device in the map)
|
||||
if (1 == inference_result->m_power_measurements.size()) {
|
||||
for (const auto &pair : inference_result->m_power_measurements) {
|
||||
if (nullptr != pair.second) {
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().min_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().average_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().max_value;
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
|
||||
// TODO HRT-5363 support multiple devices (Currently assumes 1 device in the map)
|
||||
if (1 == inference_result->m_current_measurements.size()) {
|
||||
for (const auto &pair : inference_result->m_current_measurements) {
|
||||
if (nullptr != pair.second) {
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().min_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().average_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().max_value;
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
|
||||
// TODO HRT-5363 support multiple devices (Currently assumes 1 device in the map)
|
||||
if (1 == inference_result->m_temp_measurements.size()) {
|
||||
for (const auto &pair : inference_result->m_temp_measurements) {
|
||||
if (nullptr != pair.second) {
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->min_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->average_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->max_value;
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
}
|
||||
m_results_csv_file << std::endl;
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_pipeline_elem_stats_csv(const std::string &network_group_name,
|
||||
const std::map<std::string, std::map<std::string, AccumulatorPtr>> &inference_result)
|
||||
{
|
||||
if (inference_result.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &vstream_name_results_pair : inference_result) {
|
||||
for (const auto &elem_name_accumulator_pair : vstream_name_results_pair.second) {
|
||||
write_accumulator_results(m_pipeline_stats_csv_file, elem_name_accumulator_pair.second,
|
||||
network_group_name, vstream_name_results_pair.first, elem_name_accumulator_pair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_pipeline_elem_stats_csv(const std::string &network_group_name,
|
||||
const std::map<std::string, std::map<std::string, std::vector<AccumulatorPtr>>> &inference_result)
|
||||
{
|
||||
if (inference_result.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &vstream_name_results_pair : inference_result) {
|
||||
for (const auto &elem_name_accumulator_pair : vstream_name_results_pair.second) {
|
||||
for (uint32_t i = 0; i < elem_name_accumulator_pair.second.size(); i++) {
|
||||
write_accumulator_results(m_pipeline_stats_csv_file, elem_name_accumulator_pair.second[i],
|
||||
network_group_name, vstream_name_results_pair.first, elem_name_accumulator_pair.first, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_entire_pipeline_stats_csv(const std::string &network_group_name,
|
||||
const std::map<std::string, AccumulatorPtr> &inference_result)
|
||||
{
|
||||
if (inference_result.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &vstream_name_results_pair : inference_result) {
|
||||
write_accumulator_results(m_pipeline_stats_csv_file, vstream_name_results_pair.second,
|
||||
network_group_name, vstream_name_results_pair.first, "entire_pipeline");
|
||||
}
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_benchmark_csv(const std::string &network_group_name, const NetworkGroupInferResult &hw_inference_result,
|
||||
const NetworkGroupInferResult &streaming_inference_result, const NetworkGroupInferResult &hw_latency_result)
|
||||
{
|
||||
m_results_csv_file << network_group_name << ",";
|
||||
|
||||
if (auto fps = streaming_inference_result.fps()) {
|
||||
m_results_csv_file << fps.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto hw_only_fps = hw_inference_result.fps()) {
|
||||
m_results_csv_file << hw_only_fps.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto frames_count = streaming_inference_result.frames_count()) {
|
||||
m_results_csv_file << frames_count.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto frames_count = hw_inference_result.frames_count()) {
|
||||
m_results_csv_file << frames_count.value();
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto hw_latency = hw_latency_result.hw_latency()) {
|
||||
m_results_csv_file << InferResultsFormatUtils::latency_result_to_ms(hw_latency.value());
|
||||
}
|
||||
m_results_csv_file << ",";
|
||||
|
||||
if (auto overall_latency = hw_latency_result.overall_latency()) {
|
||||
m_results_csv_file << InferResultsFormatUtils::latency_result_to_ms(overall_latency.value());
|
||||
}
|
||||
|
||||
// TODO HRT-5363 support multiple devices (Currently assumes 1 device in the map)
|
||||
if (1 == streaming_inference_result.m_power_measurements.size()) {
|
||||
for (const auto &pair : streaming_inference_result.m_power_measurements) {
|
||||
if (nullptr != pair.second) {
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().min_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().average_value;
|
||||
m_results_csv_file << ",";
|
||||
m_results_csv_file << pair.second->data().max_value;
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_results_csv_file << ",,,";
|
||||
}
|
||||
|
||||
m_results_csv_file << std::endl;
|
||||
}
|
||||
template< typename T>
|
||||
void InferStatsPrinter::print_stdout_single_element(const T &results, size_t frames_count)
|
||||
{
|
||||
if (0 != frames_count) {
|
||||
std::cout << " Frames count: " << static_cast<uint32_t>(frames_count) << std::endl;
|
||||
} else if (auto duration = results.infer_duration()) {
|
||||
std::cout << " Duration: " << CliCommon::duration_to_string(std::chrono::seconds(static_cast<uint32_t>(*duration))) << std::endl;
|
||||
}
|
||||
|
||||
if (auto fps = results.fps()) {
|
||||
std::cout << " FPS: " << fps.value() << "" << std::endl;
|
||||
}
|
||||
|
||||
if (auto send_data_rate = results.send_data_rate_mbit_sec()) {
|
||||
std::cout << " Send Rate: " << send_data_rate.value() << " Mbit/s" << std::endl;
|
||||
}
|
||||
|
||||
if (auto recv_data_rate = results.recv_data_rate_mbit_sec()) {
|
||||
std::cout << " Recv Rate: " << recv_data_rate.value() << " Mbit/s" << std::endl;
|
||||
}
|
||||
|
||||
if (auto hw_latency = results.hw_latency()) {
|
||||
std::cout << " HW Latency: " << InferResultsFormatUtils::latency_result_to_ms(hw_latency.value()) << " ms" << std::endl;
|
||||
}
|
||||
if (auto overall_latency = results.overall_latency()) {
|
||||
std::cout << " Overall Latency: " << InferResultsFormatUtils::latency_result_to_ms(overall_latency.value()) << " ms" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InferStatsPrinter::print_stdout(Expected<NetworkGroupInferResult>& inference_result)
|
||||
{
|
||||
if (!inference_result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set precision and flags
|
||||
auto original_precision = std::cout.precision();
|
||||
auto original_flags(std::cout.flags());
|
||||
std::cout << std::setprecision(2) << std::fixed;
|
||||
std::cout << FORMAT_CLEAR_LINE << "> Inference result:" << std::endl;
|
||||
|
||||
if (1 < inference_result->m_result_per_network.size()) {
|
||||
// If there is more than 1 network, we print results per network, and than sum of bandwith
|
||||
for (auto &network_result_pair : inference_result->m_result_per_network) {
|
||||
std::cout << " Network: " << network_result_pair.first << std::endl;
|
||||
auto frames_count = (m_print_frame_count) ? network_result_pair.second.m_frames_count : 0;
|
||||
print_stdout_single_element<NetworkInferResult>(network_result_pair.second, frames_count);
|
||||
}
|
||||
std::stringstream bandwidth_stream;
|
||||
bandwidth_stream << std::setprecision(2) << std::fixed;
|
||||
if (auto send_data_rate = inference_result->send_data_rate_mbit_sec()) {
|
||||
bandwidth_stream << " Send Rate: " << send_data_rate.value() << " Mbit/s" << std::endl;
|
||||
}
|
||||
|
||||
if (auto recv_data_rate = inference_result->recv_data_rate_mbit_sec()) {
|
||||
bandwidth_stream << " Recv Rate: " << recv_data_rate.value() << " Mbit/s" << std::endl;
|
||||
}
|
||||
|
||||
if (0 != bandwidth_stream.rdbuf()->in_avail()) {
|
||||
std::cout << " Total bandwidth: " << std::endl;
|
||||
std::cout << bandwidth_stream.rdbuf();
|
||||
}
|
||||
} else {
|
||||
auto frames_count_exp = inference_result->frames_count();
|
||||
auto frames_count = ((frames_count_exp) && (m_print_frame_count)) ? frames_count_exp.value() : 0;
|
||||
print_stdout_single_element<NetworkGroupInferResult>(inference_result.value(), frames_count);
|
||||
}
|
||||
|
||||
if ((inference_result->m_power_measurements.size() != inference_result->m_current_measurements.size()) ||
|
||||
(inference_result->m_power_measurements.size() != inference_result->m_temp_measurements.size())) {
|
||||
LOGGER__ERROR("Error found different number of devices between different measurement types");
|
||||
}
|
||||
for (const auto &pair : inference_result->m_power_measurements) {
|
||||
std::stringstream measurement_stream;
|
||||
if (nullptr != pair.second) {
|
||||
const auto &data = pair.second->data();
|
||||
const auto &power_units = pair.second->power_units();
|
||||
measurement_stream << " Minimum power consumption: " << data.min_value << " " << power_units << std::endl;
|
||||
measurement_stream << " Average power consumption: " << data.average_value << " " << power_units << std::endl;
|
||||
measurement_stream << " Maximum power consumption: " << data.max_value << " " << power_units << std::endl;
|
||||
}
|
||||
auto current_measure_iter = inference_result->m_current_measurements.find(pair.first);
|
||||
if ((current_measure_iter != inference_result->m_current_measurements.end()) && (nullptr != current_measure_iter->second)) {
|
||||
const auto &data = current_measure_iter->second->data();
|
||||
const auto &power_units = current_measure_iter->second->power_units();
|
||||
measurement_stream << " Minimum current consumption: " << data.min_value << " " << power_units << std::endl;
|
||||
measurement_stream << " Average current consumption: " << data.average_value << " " << power_units << std::endl;
|
||||
measurement_stream << " Maximum current consumption: " << data.max_value << " " << power_units << std::endl;
|
||||
}
|
||||
auto temp_measure_iter = inference_result->m_temp_measurements.find(pair.first);
|
||||
if ((temp_measure_iter != inference_result->m_temp_measurements.end()) && (nullptr != temp_measure_iter->second)) {
|
||||
measurement_stream << " Minimum chip temperature: " << temp_measure_iter->second->min_value << "°C" << std::endl;
|
||||
measurement_stream << " Average chip temperature: " << temp_measure_iter->second->average_value << "°C" << std::endl;
|
||||
measurement_stream << " Maximum chip temperature: " << temp_measure_iter->second->max_value << "°C" << std::endl;
|
||||
}
|
||||
if (0 != measurement_stream.rdbuf()->in_avail()) {
|
||||
std::cout << " Device: " << pair.first << std::endl;
|
||||
std::cout << measurement_stream.rdbuf();
|
||||
}
|
||||
}
|
||||
|
||||
// Restore precision and flags
|
||||
std::cout.flags(original_flags);
|
||||
std::cout.precision(original_precision);
|
||||
}
|
||||
|
||||
void InferStatsPrinter::write_accumulator_results(std::ofstream &output_stream, AccumulatorPtr accumulator,
|
||||
const std::string &network_group_name, const std::string &vstream_name, const std::string &elem_name, uint32_t index)
|
||||
{
|
||||
const auto &accumulator_result = accumulator->get();
|
||||
if ((!accumulator_result.count()) || (accumulator_result.count().value() == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
output_stream << network_group_name << ",";
|
||||
output_stream << vstream_name << ",";
|
||||
output_stream << accumulator->get_data_type() << ",";
|
||||
output_stream << elem_name << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.mean()) << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.min()) << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.max()) << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.var()) << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.sd()) << ",";
|
||||
output_stream << InferResultsFormatUtils::format_statistic(accumulator_result.mean_sd()) << ",";
|
||||
if (NO_INDEX != index) {
|
||||
output_stream << index;
|
||||
}
|
||||
output_stream << std::endl;
|
||||
}
|
||||
66
hailort/hailortcli/infer_stats_printer.hpp
Normal file
66
hailort/hailortcli/infer_stats_printer.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file infer_stats_printer.hpp
|
||||
* @brief Prints the inference stats
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_INFER_STATS_PRINTER_HPP_
|
||||
#define _HAILO_INFER_STATS_PRINTER_HPP_
|
||||
|
||||
#include "inference_result.hpp"
|
||||
#include "run_command.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
class InferResultsFormatUtils final {
|
||||
public:
|
||||
InferResultsFormatUtils() = delete;
|
||||
|
||||
static const uint32_t DEFAULT_FLOATING_POINT_PRECISION = 4;
|
||||
|
||||
static std::string format_statistic(const Expected<double> &statistic, uint32_t precision = DEFAULT_FLOATING_POINT_PRECISION);
|
||||
static std::string format_statistic(const Expected<size_t> &statistic);
|
||||
static double latency_result_to_ms(std::chrono::nanoseconds latency);
|
||||
};
|
||||
|
||||
class InferStatsPrinter final {
|
||||
public:
|
||||
static Expected<InferStatsPrinter> create(const inference_runner_params ¶ms, bool print_running_info = true);
|
||||
void print(const std::string &network_name, Expected<NetworkGroupInferResult>& inference_result);
|
||||
void print_benchmark_csv(const std::string &network_name, const NetworkGroupInferResult &hw_inference_result,
|
||||
const NetworkGroupInferResult &streaming_inference_result, const NetworkGroupInferResult &hw_latency_result);
|
||||
void print_csv_header();
|
||||
void print_benchmark_csv_header();
|
||||
|
||||
private:
|
||||
static constexpr uint32_t NO_INDEX = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
InferStatsPrinter(const inference_runner_params ¶ms, hailo_status &output_status, bool print_running_info = true);
|
||||
void print_csv(const std::string &network_name, Expected<NetworkGroupInferResult>& inference_result);
|
||||
void print_pipeline_elem_stats_csv(const std::string &network_name,
|
||||
const std::map<std::string, std::map<std::string, AccumulatorPtr>> &inference_result);
|
||||
void print_pipeline_elem_stats_csv(const std::string &network_name,
|
||||
const std::map<std::string, std::map<std::string, std::vector<AccumulatorPtr>>> &inference_result);
|
||||
void print_entire_pipeline_stats_csv(const std::string &network_name,
|
||||
const std::map<std::string, AccumulatorPtr> &inference_result);
|
||||
void print_stdout(Expected<NetworkGroupInferResult>& inference_result);
|
||||
template <typename T>
|
||||
void print_stdout_single_element(const T &results, size_t frames_count);
|
||||
|
||||
// 'index' is only printed if it's not equal to 'NO_INDEX'
|
||||
static void write_accumulator_results(std::ofstream &output_stream, AccumulatorPtr accumulator,
|
||||
const std::string &network_name, const std::string &vstream_name, const std::string &elem_name,
|
||||
uint32_t index=NO_INDEX);
|
||||
|
||||
std::ofstream m_results_csv_file;
|
||||
std::ofstream m_pipeline_stats_csv_file;
|
||||
std::string m_results_csv_path;
|
||||
std::string m_pipeline_stats_csv_path;
|
||||
std::string m_dot_output_path;
|
||||
bool m_print_frame_count;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_INFER_STATS_PRINTER_HPP_ */
|
||||
133
hailort/hailortcli/inference_progress.cpp
Normal file
133
hailort/hailortcli/inference_progress.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file inference_progress.cpp
|
||||
* @brief Show inference progress
|
||||
**/
|
||||
#include "inference_progress.hpp"
|
||||
#include "infer_stats_printer.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
InferProgress::InferProgress(ConfiguredNetworkGroup &configured_network_group, const inference_runner_params ¶ms,
|
||||
std::chrono::duration<double> print_interval) :
|
||||
m_configured_network_group(configured_network_group), m_params(params),
|
||||
m_print_interval(print_interval), m_networks_progress(), m_stop(true) {}
|
||||
|
||||
void InferProgress::start()
|
||||
{
|
||||
m_stop = false;
|
||||
m_print_thread = std::thread([this] () {
|
||||
while (!m_stop.load()) {
|
||||
print_progress(true);
|
||||
std::this_thread::sleep_for(m_print_interval);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InferProgress::finish(bool should_print_progress)
|
||||
{
|
||||
m_stop = true;
|
||||
m_print_thread.join();
|
||||
if (should_print_progress) {
|
||||
print_progress(false);
|
||||
}
|
||||
}
|
||||
|
||||
void InferProgress::print_progress(bool should_reset_cursor)
|
||||
{
|
||||
for (auto &network_progress_bar : m_networks_progress) {
|
||||
std::cout << network_progress_bar->get_progress_text() << std::endl;
|
||||
}
|
||||
if (should_reset_cursor) {
|
||||
CliCommon::reset_cursor(m_networks_progress.size());
|
||||
}
|
||||
}
|
||||
|
||||
InferProgress::~InferProgress()
|
||||
{
|
||||
if (!m_stop.load()) {
|
||||
finish(false);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<std::shared_ptr<NetworkProgressBar>> InferProgress::create_network_progress_bar(const std::string &network_name)
|
||||
{
|
||||
std::shared_ptr<NetworkProgressBar> network_progress_ber =
|
||||
make_shared_nothrow<NetworkProgressBar>(m_configured_network_group, m_params, network_name);
|
||||
CHECK_NOT_NULL_AS_EXPECTED(network_progress_ber, HAILO_OUT_OF_HOST_MEMORY);
|
||||
|
||||
{
|
||||
// We create NetworkProgressBar from different threads
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_networks_progress.push_back(network_progress_ber);
|
||||
}
|
||||
|
||||
auto prog_bar_cpy = network_progress_ber;
|
||||
return prog_bar_cpy;
|
||||
}
|
||||
|
||||
NetworkProgressBar::NetworkProgressBar(ConfiguredNetworkGroup &configured_network_group,
|
||||
const inference_runner_params ¶ms, const std::string &network_name) :
|
||||
m_network_name(network_name), m_configured_network_group(configured_network_group), m_params(params),
|
||||
m_progress_count(0), m_start(std::chrono::steady_clock::now()) // NetworkProgressBar sets start time to its creation time
|
||||
{}
|
||||
|
||||
std::string NetworkProgressBar::get_progress_text()
|
||||
{
|
||||
std::stringstream res;
|
||||
auto elapsed_time = std::chrono::duration<double>(std::chrono::steady_clock::now() - m_start).count();
|
||||
auto progress_count = m_progress_count.load();
|
||||
auto fps = progress_count / elapsed_time;
|
||||
auto eta = std::chrono::seconds(0);
|
||||
if (0 == m_params.time_to_run) {
|
||||
eta = std::chrono::seconds(static_cast<uint32_t>(static_cast<double>(m_params.frames_count - progress_count) / fps));
|
||||
} else {
|
||||
eta = std::chrono::seconds(std::max(static_cast<int32_t>(0),
|
||||
static_cast<int32_t>(std::round(m_params.time_to_run - elapsed_time))));
|
||||
}
|
||||
|
||||
// Set precision and flags
|
||||
res << std::setprecision(2) << std::fixed;
|
||||
|
||||
uint32_t progress_percent = 0;
|
||||
if (0 == m_params.time_to_run) {
|
||||
progress_percent = 100 * progress_count / m_params.frames_count;
|
||||
} else {
|
||||
progress_percent = std::min(static_cast<uint32_t>(100 * elapsed_time / m_params.time_to_run), static_cast<uint32_t>(100));
|
||||
}
|
||||
|
||||
res << "Network " << m_network_name << ": " << progress_percent << "% | " << progress_count;
|
||||
if (0 == m_params.time_to_run) {
|
||||
res << "/" << m_params.frames_count;
|
||||
}
|
||||
|
||||
if (!m_params.measure_latency) {
|
||||
res << " | FPS: " << fps;
|
||||
} else {
|
||||
double avg_hw_latency = 0;
|
||||
auto latency_expected = m_configured_network_group.get_latency_measurement(m_network_name);
|
||||
if (latency_expected) {
|
||||
avg_hw_latency = InferResultsFormatUtils::latency_result_to_ms(latency_expected.release().avg_hw_latency);
|
||||
}
|
||||
|
||||
if (avg_hw_latency > 0) {
|
||||
res << " | HW Latency: " << avg_hw_latency << " ms";
|
||||
}
|
||||
else {
|
||||
res << " | HW Latency: NaN";
|
||||
}
|
||||
}
|
||||
res << " | ETA: " << CliCommon::duration_to_string(eta) << std::flush;
|
||||
|
||||
return res.str();
|
||||
}
|
||||
|
||||
void NetworkProgressBar::make_progress()
|
||||
{
|
||||
++m_progress_count;
|
||||
}
|
||||
58
hailort/hailortcli/inference_progress.hpp
Normal file
58
hailort/hailortcli/inference_progress.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file inference_progress.hpp
|
||||
* @brief Show inference progress
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_INFERENCE_PROGRESS_HPP_
|
||||
#define _HAILO_INFERENCE_PROGRESS_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "run_command.hpp"
|
||||
|
||||
#include "hailo/network_group.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class NetworkProgressBar final {
|
||||
public:
|
||||
NetworkProgressBar(ConfiguredNetworkGroup &configured_network_group,
|
||||
const inference_runner_params ¶ms, const std::string &network_name);
|
||||
|
||||
void make_progress();
|
||||
std::string get_progress_text();
|
||||
private:
|
||||
const std::string m_network_name;
|
||||
ConfiguredNetworkGroup &m_configured_network_group;
|
||||
const inference_runner_params m_params;
|
||||
std::atomic<uint32_t> m_progress_count;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start;
|
||||
};
|
||||
|
||||
class InferProgress final {
|
||||
public:
|
||||
InferProgress(ConfiguredNetworkGroup &configured_network_group,
|
||||
const inference_runner_params ¶ms, std::chrono::duration<double> print_interval);
|
||||
|
||||
~InferProgress();
|
||||
|
||||
Expected<std::shared_ptr<NetworkProgressBar>> create_network_progress_bar(const std::string &network_name);
|
||||
void start();
|
||||
void finish(bool should_print_progress = true);
|
||||
|
||||
private:
|
||||
void print_progress(bool should_reset_cursor);
|
||||
|
||||
ConfiguredNetworkGroup &m_configured_network_group;
|
||||
const inference_runner_params m_params;
|
||||
std::chrono::duration<double> m_print_interval;
|
||||
std::vector<std::shared_ptr<NetworkProgressBar>> m_networks_progress;
|
||||
std::atomic_bool m_stop;
|
||||
std::thread m_print_thread;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_INFERENCE_PROGRESS_HPP_ */
|
||||
326
hailort/hailortcli/inference_result.hpp
Normal file
326
hailort/hailortcli/inference_result.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file inference_result.hpp
|
||||
* @brief hold inference result
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_INFER_RESULT_
|
||||
#define _HAILO_INFER_RESULT_
|
||||
|
||||
#include "power_measurement_command.hpp"
|
||||
#include "temp_measurement.hpp"
|
||||
#include "hailo/runtime_statistics.hpp"
|
||||
#include "hailo/vstream.hpp"
|
||||
|
||||
static constexpr double MBIT_PER_BYTE = 8.0f / 1000.0f / 1000.0f;
|
||||
|
||||
struct NetworkInferResult
|
||||
{
|
||||
public:
|
||||
NetworkInferResult(size_t frames_count = 0, size_t total_send_frame_size = 0, size_t total_recv_frame_size = 0) :
|
||||
m_frames_count(frames_count),
|
||||
m_total_send_frame_size(total_send_frame_size),
|
||||
m_total_recv_frame_size(total_recv_frame_size),
|
||||
m_infer_duration(nullptr),
|
||||
m_hw_latency(nullptr),
|
||||
m_overall_latency(nullptr)
|
||||
{}
|
||||
|
||||
Expected<double> infer_duration() const{
|
||||
if (!m_infer_duration) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
auto infer_duration_cpy = *m_infer_duration;
|
||||
return infer_duration_cpy;
|
||||
}
|
||||
|
||||
Expected<double> fps() const
|
||||
{
|
||||
if (!m_infer_duration) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
return static_cast<double>(m_frames_count) / *m_infer_duration;
|
||||
}
|
||||
|
||||
Expected<double> send_data_rate_mbit_sec() const
|
||||
{
|
||||
if (!m_infer_duration) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
return (static_cast<double>(m_frames_count * m_total_send_frame_size) / *m_infer_duration) * MBIT_PER_BYTE;
|
||||
}
|
||||
|
||||
Expected<double> recv_data_rate_mbit_sec() const
|
||||
{
|
||||
if (!m_infer_duration) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
return (static_cast<double>(m_frames_count * m_total_recv_frame_size) / *m_infer_duration) * MBIT_PER_BYTE;
|
||||
}
|
||||
|
||||
Expected<std::chrono::nanoseconds> hw_latency() const
|
||||
{
|
||||
if (!m_hw_latency) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
std::chrono::nanoseconds latency_cpy = *m_hw_latency;
|
||||
return latency_cpy;
|
||||
}
|
||||
|
||||
Expected<std::chrono::nanoseconds> overall_latency() const
|
||||
{
|
||||
if (!m_overall_latency) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
std::chrono::nanoseconds latency_cpy = *m_overall_latency;
|
||||
return latency_cpy;
|
||||
}
|
||||
|
||||
size_t m_frames_count;
|
||||
size_t m_total_send_frame_size;
|
||||
size_t m_total_recv_frame_size;
|
||||
|
||||
// TODO: change to optional
|
||||
std::unique_ptr<double> m_infer_duration;
|
||||
std::unique_ptr<std::chrono::nanoseconds> m_hw_latency;
|
||||
std::unique_ptr<std::chrono::nanoseconds> m_overall_latency;
|
||||
};
|
||||
|
||||
struct NetworkGroupInferResult
|
||||
{
|
||||
public:
|
||||
NetworkGroupInferResult(std::map<std::string, NetworkInferResult> &&result_per_network = {}) :
|
||||
m_result_per_network(std::move(result_per_network)),
|
||||
m_power_measurements(),
|
||||
m_current_measurements(),
|
||||
m_temp_measurements(),
|
||||
m_fps_accumulators(),
|
||||
m_latency_accumulators(),
|
||||
m_queue_size_accumulators(),
|
||||
m_pipeline_latency_accumulators()
|
||||
{}
|
||||
|
||||
Expected<double> infer_duration(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
// We set m_infer_duration to be the max of all durations
|
||||
double max_duration = 0;
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto duration_per_network = network_result_pair.second.infer_duration();
|
||||
if(!duration_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
max_duration = std::max(max_duration, duration_per_network.value());
|
||||
}
|
||||
return max_duration;
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).infer_duration();
|
||||
}
|
||||
|
||||
Expected<double> fps(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
double acc_fps = 0;
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto fps_per_network = network_result_pair.second.fps();
|
||||
if (!fps_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
acc_fps += fps_per_network.value();
|
||||
}
|
||||
return (acc_fps / static_cast<double>(m_result_per_network.size()));
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).fps();
|
||||
}
|
||||
|
||||
Expected<double> send_data_rate_mbit_sec(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
double acc_send_data_rate_mbit_sec = 0;
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto send_data_rate_mbit_sec_per_network = network_result_pair.second.send_data_rate_mbit_sec();
|
||||
if(!send_data_rate_mbit_sec_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
acc_send_data_rate_mbit_sec += send_data_rate_mbit_sec_per_network.value();
|
||||
}
|
||||
return acc_send_data_rate_mbit_sec;
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).send_data_rate_mbit_sec();
|
||||
}
|
||||
|
||||
Expected<double> recv_data_rate_mbit_sec(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
double acc_recv_data_rate_mbit_sec = 0;
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto recv_data_rate_mbit_sec_per_network = network_result_pair.second.recv_data_rate_mbit_sec();
|
||||
if(!recv_data_rate_mbit_sec_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
acc_recv_data_rate_mbit_sec += recv_data_rate_mbit_sec_per_network.value();
|
||||
}
|
||||
return acc_recv_data_rate_mbit_sec;
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).send_data_rate_mbit_sec();
|
||||
}
|
||||
|
||||
Expected<std::chrono::nanoseconds> hw_latency(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
std::chrono::nanoseconds acc_hw_latency(0);
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto hw_latency_per_network = network_result_pair.second.hw_latency();
|
||||
if(!hw_latency_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
acc_hw_latency += hw_latency_per_network.value();
|
||||
}
|
||||
return static_cast<std::chrono::nanoseconds>(acc_hw_latency / m_result_per_network.size());
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).hw_latency();
|
||||
}
|
||||
|
||||
Expected<std::chrono::nanoseconds> overall_latency(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
std::chrono::nanoseconds acc_overall_latency(0);
|
||||
for (auto &network_result_pair : m_result_per_network) {
|
||||
auto overall_latency_per_network = network_result_pair.second.overall_latency();
|
||||
if(!overall_latency_per_network) {
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
acc_overall_latency += overall_latency_per_network.value();
|
||||
}
|
||||
return static_cast<std::chrono::nanoseconds>(acc_overall_latency / m_result_per_network.size());
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
return m_result_per_network.at(network_name).overall_latency();
|
||||
}
|
||||
|
||||
Expected<size_t> frames_count(const std::string &network_name = "") const
|
||||
{
|
||||
if (network_name.empty()) {
|
||||
if (1 == m_result_per_network.size()) {
|
||||
// If there is only one network, return its frames_count
|
||||
auto frames_count_cpy = m_result_per_network.begin()->second.m_frames_count;
|
||||
return frames_count_cpy;
|
||||
}
|
||||
return make_unexpected(HAILO_NOT_AVAILABLE);
|
||||
}
|
||||
CHECK_AS_EXPECTED(contains(m_result_per_network, network_name), HAILO_NOT_FOUND,
|
||||
"There is no results for network {}", network_name);
|
||||
auto frames_count_cpy = m_result_per_network.at(network_name).m_frames_count;
|
||||
return frames_count_cpy;
|
||||
}
|
||||
|
||||
// <network_name, network_inference_results>
|
||||
std::map<std::string, NetworkInferResult> m_result_per_network;
|
||||
|
||||
// <device_id, measurement>
|
||||
// TODO: create a struct contianing all device measurements, and keep only one map
|
||||
std::map<std::string, std::unique_ptr<LongPowerMeasurement>> m_power_measurements;
|
||||
std::map<std::string, std::unique_ptr<LongPowerMeasurement>> m_current_measurements;
|
||||
std::map<std::string, std::unique_ptr<TempMeasurementData>> m_temp_measurements;
|
||||
|
||||
// <vstream_name, accumulator>
|
||||
std::map<std::string, std::map<std::string, AccumulatorPtr>> m_fps_accumulators;
|
||||
std::map<std::string, std::map<std::string, AccumulatorPtr>> m_latency_accumulators;
|
||||
std::map<std::string, std::map<std::string, std::vector<AccumulatorPtr>>> m_queue_size_accumulators;
|
||||
std::map<std::string, AccumulatorPtr> m_pipeline_latency_accumulators;
|
||||
|
||||
void update_pipeline_stats(const std::map<std::string, std::vector<std::reference_wrapper<InputVStream>>> &inputs_per_network,
|
||||
const std::map<std::string, std::vector<std::reference_wrapper<OutputVStream>>> &outputs_per_network)
|
||||
{
|
||||
for (const auto &inputs_pair : inputs_per_network) {
|
||||
for (const auto &in_vstream : inputs_pair.second) {
|
||||
update_accumulator_map(m_fps_accumulators, in_vstream.get().name(), in_vstream.get().get_fps_accumulators());
|
||||
update_accumulator_map(m_latency_accumulators, in_vstream.get().name(), in_vstream.get().get_latency_accumulators());
|
||||
update_accumulator_map(m_queue_size_accumulators, in_vstream.get().name(), in_vstream.get().get_queue_size_accumulators());
|
||||
const auto pipeline_latency_accumulator = in_vstream.get().get_pipeline_latency_accumulator();
|
||||
if (nullptr != pipeline_latency_accumulator) {
|
||||
m_pipeline_latency_accumulators.emplace(in_vstream.get().name(), pipeline_latency_accumulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &outputs_pair : outputs_per_network) {
|
||||
for (const auto &out_vstream : outputs_pair.second) {
|
||||
update_accumulator_map(m_fps_accumulators, out_vstream.get().name(), out_vstream.get().get_fps_accumulators());
|
||||
update_accumulator_map(m_latency_accumulators, out_vstream.get().name(), out_vstream.get().get_latency_accumulators());
|
||||
update_accumulator_map(m_queue_size_accumulators, out_vstream.get().name(), out_vstream.get().get_queue_size_accumulators());
|
||||
const auto pipeline_latency_accumulator = out_vstream.get().get_pipeline_latency_accumulator();
|
||||
if (nullptr != pipeline_latency_accumulator) {
|
||||
m_pipeline_latency_accumulators.emplace(out_vstream.get().name(), pipeline_latency_accumulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_pipeline_stats(const std::map<std::string, std::vector<std::reference_wrapper<InputStream>>> &/*inputs_per_network*/,
|
||||
const std::map<std::string, std::vector<std::reference_wrapper<OutputStream>>> &/*outputs_per_network*/)
|
||||
{
|
||||
// Overloading fow hw_object inference - not using any pipelines so nothing to update
|
||||
}
|
||||
|
||||
void initialize_measurements(const std::vector<std::reference_wrapper<Device>> &devices)
|
||||
{
|
||||
for (const auto &device : devices) {
|
||||
m_power_measurements.emplace(device.get().get_dev_id(), std::unique_ptr<LongPowerMeasurement>{});
|
||||
m_current_measurements.emplace(device.get().get_dev_id(), std::unique_ptr<LongPowerMeasurement>{});
|
||||
m_temp_measurements.emplace(device.get().get_dev_id(), std::unique_ptr<TempMeasurementData>{});
|
||||
}
|
||||
}
|
||||
|
||||
hailo_status set_power_measurement(const std::string &device_id, std::unique_ptr<LongPowerMeasurement> &&power_measure)
|
||||
{
|
||||
auto iter = m_power_measurements.find(device_id);
|
||||
CHECK(m_power_measurements.end() != iter, HAILO_INVALID_ARGUMENT);
|
||||
iter->second = std::move(power_measure);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status set_current_measurement(const std::string &device_id, std::unique_ptr<LongPowerMeasurement> &¤t_measure)
|
||||
{
|
||||
auto iter = m_current_measurements.find(device_id);
|
||||
CHECK(m_current_measurements.end() != iter, HAILO_INVALID_ARGUMENT);
|
||||
iter->second = std::move(current_measure);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status set_temp_measurement(const std::string &device_id, std::unique_ptr<TempMeasurementData> &&temp_measure)
|
||||
{
|
||||
auto iter = m_temp_measurements.find(device_id);
|
||||
CHECK(m_temp_measurements.end() != iter, HAILO_INVALID_ARGUMENT);
|
||||
iter->second = std::move(temp_measure);
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename K, typename V>
|
||||
static void update_accumulator_map(std::map<K, V> &map,
|
||||
const K &key, const V &value)
|
||||
{
|
||||
if (value.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.emplace(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _HAILO_INFER_RESULT_ */
|
||||
161
hailort/hailortcli/parse_hef_command.cpp
Normal file
161
hailort/hailortcli/parse_hef_command.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file parse_hef_command.cpp
|
||||
* @brief Parses HEF and print info to stdout
|
||||
**/
|
||||
|
||||
#include "parse_hef_command.hpp"
|
||||
#include "common/filesystem.hpp"
|
||||
#include "hailo/hailort_common.hpp"
|
||||
|
||||
#define TAB (" ")
|
||||
|
||||
static std::string add_tabs(uint8_t count)
|
||||
{
|
||||
// Each TAB counts as 4 spaces
|
||||
std::string res = "";
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
res = res + TAB;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string get_shape_str(const hailo_stream_info_t &stream_info)
|
||||
{
|
||||
switch (stream_info.format.order)
|
||||
{
|
||||
case HAILO_FORMAT_ORDER_HAILO_NMS:
|
||||
return HailoRTCommon::get_format_type_str(stream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(stream_info.format.order) +
|
||||
"(number of classes: " + std::to_string(stream_info.nms_info.number_of_classes) +
|
||||
", max_bboxes_per_class: "+ std::to_string(stream_info.nms_info.max_bboxes_per_class) + ")";
|
||||
case HAILO_FORMAT_ORDER_NC:
|
||||
return HailoRTCommon::get_format_type_str(stream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(stream_info.format.order) +
|
||||
"(" + std::to_string(stream_info.hw_shape.features) + ")";
|
||||
case HAILO_FORMAT_ORDER_NHW:
|
||||
return HailoRTCommon::get_format_type_str(stream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(stream_info.format.order) +
|
||||
"(" + std::to_string(stream_info.hw_shape.height) + "x" + std::to_string(stream_info.hw_shape.width) + ")";
|
||||
default:
|
||||
return HailoRTCommon::get_format_type_str(stream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(stream_info.format.order) +
|
||||
"(" + std::to_string(stream_info.hw_shape.height) + "x" + std::to_string(stream_info.hw_shape.width) +
|
||||
"x" + std::to_string(stream_info.hw_shape.features) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string get_shape_str(const hailo_vstream_info_t &vstream_info)
|
||||
{
|
||||
switch (vstream_info.format.order)
|
||||
{
|
||||
case HAILO_FORMAT_ORDER_HAILO_NMS:
|
||||
return HailoRTCommon::get_format_type_str(vstream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(vstream_info.format.order) +
|
||||
"(number of classes: " + std::to_string(vstream_info.nms_shape.number_of_classes) +
|
||||
", max_bboxes_per_class: " + std::to_string(vstream_info.nms_shape.max_bboxes_per_class) + ")";
|
||||
case HAILO_FORMAT_ORDER_NC:
|
||||
return HailoRTCommon::get_format_type_str(vstream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(vstream_info.format.order) +
|
||||
"(" + std::to_string(vstream_info.shape.features) + ")";
|
||||
case HAILO_FORMAT_ORDER_NHW:
|
||||
return HailoRTCommon::get_format_type_str(vstream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(vstream_info.format.order) +
|
||||
"(" +std::to_string(vstream_info.shape.height) + "x" + std::to_string(vstream_info.shape.width) + ")";
|
||||
default:
|
||||
return HailoRTCommon::get_format_type_str(vstream_info.format.type) + ", " + HailoRTCommon::get_format_order_str(vstream_info.format.order) +
|
||||
"(" + std::to_string(vstream_info.shape.height) + "x" + std::to_string(vstream_info.shape.width) + "x" +
|
||||
std::to_string(vstream_info.shape.features) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
ParseHefCommand::ParseHefCommand(CLI::App &parent_app) :
|
||||
Command(parent_app.add_subcommand("parse-hef", "Parse HEF to get information about its components"))
|
||||
{
|
||||
m_app->add_option("hef", m_hef_path, "An existing HEF file/directory path")
|
||||
->check(CLI::ExistingFile | CLI::ExistingDirectory)
|
||||
->required();
|
||||
m_app->add_flag("--parse-streams", m_parse_streams, "Parse stream infos")->default_val(false);
|
||||
m_app->add_flag("--parse-vstreams", m_parse_vstreams, "Parse vstream infos")->default_val(true);
|
||||
}
|
||||
|
||||
|
||||
hailo_status ParseHefCommand::execute()
|
||||
{
|
||||
auto is_dir = Filesystem::is_directory(m_hef_path.c_str());
|
||||
CHECK_EXPECTED_AS_STATUS(is_dir, "Failed checking if path is directory");
|
||||
|
||||
if (is_dir.value()){
|
||||
return ParseHefCommand::parse_hefs_infos_dir(m_hef_path, m_parse_streams, m_parse_vstreams);
|
||||
} else {
|
||||
return ParseHefCommand::parse_hefs_info(m_hef_path, m_parse_streams, m_parse_vstreams);
|
||||
}
|
||||
}
|
||||
|
||||
hailo_status ParseHefCommand::parse_hefs_info(const std::string &hef_path, bool stream_infos, bool vstream_infos)
|
||||
{
|
||||
auto hef_exp = Hef::create(hef_path);
|
||||
CHECK_EXPECTED_AS_STATUS(hef_exp, "Failed to parse HEF");
|
||||
auto hef = hef_exp.release();
|
||||
|
||||
auto network_group_infos = hef.get_network_groups_infos();
|
||||
CHECK_EXPECTED_AS_STATUS(network_group_infos);
|
||||
for (auto &network_group_info : network_group_infos.release()) {
|
||||
auto contexts_str = (network_group_info.is_multi_context ? "Multi Context" : "Single Context");
|
||||
std::cout << "Network group name: " << network_group_info.name << " (" << contexts_str << ")" << std::endl;
|
||||
auto network_infos = hef.get_network_infos(network_group_info.name);
|
||||
CHECK_EXPECTED_AS_STATUS(network_infos, "Failed to parse networks infos");
|
||||
for (auto &network_info : network_infos.value()) {
|
||||
std::cout << add_tabs(1) << "Network name: " << network_info.name << std::endl;
|
||||
if (stream_infos) {
|
||||
std::cout << add_tabs(2) << "Stream infos:" << std::endl;
|
||||
auto input_stream_infos = hef.get_input_stream_infos(network_info.name);
|
||||
CHECK_EXPECTED_AS_STATUS(input_stream_infos, "Failed to parse input stream infos");
|
||||
for (auto &stream_info : input_stream_infos.value()) {
|
||||
auto shape_str = get_shape_str(stream_info);
|
||||
std::cout << add_tabs(3) << "Input " << stream_info.name << " " << shape_str << std::endl;
|
||||
}
|
||||
auto output_stream_infos = hef.get_output_stream_infos(network_info.name);
|
||||
CHECK_EXPECTED_AS_STATUS(output_stream_infos, "Failed to parse output stream infos");
|
||||
for (auto &stream_info : output_stream_infos.value()) {
|
||||
auto shape_str = get_shape_str(stream_info);
|
||||
std::cout << add_tabs(3) << "Output " << stream_info.name << " " << shape_str << std::endl;
|
||||
}
|
||||
}
|
||||
if (vstream_infos) {
|
||||
std::cout << add_tabs(2) << "VStream infos:" << std::endl;
|
||||
auto input_vstream_infos = hef.get_input_vstream_infos(network_info.name);
|
||||
CHECK_EXPECTED_AS_STATUS(input_vstream_infos, "Failed to parse input vstream infos");
|
||||
for (auto &vstream_info : input_vstream_infos.value()) {
|
||||
auto shape_str = get_shape_str(vstream_info);
|
||||
std::cout << add_tabs(3) << "Input " << vstream_info.name << " " << shape_str << std::endl;
|
||||
}
|
||||
auto output_vstream_infos = hef.get_output_vstream_infos(network_info.name);
|
||||
CHECK_EXPECTED_AS_STATUS(output_vstream_infos, "Failed to parse output vstream infos");
|
||||
for (auto &vstream_info : output_vstream_infos.value()) {
|
||||
auto shape_str = get_shape_str(vstream_info);
|
||||
std::cout << add_tabs(3) << "Output " << vstream_info.name << " " << shape_str << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_status ParseHefCommand::parse_hefs_infos_dir(const std::string &hef_path, bool stream_infos, bool vstream_infos)
|
||||
{
|
||||
bool contains_hef = false;
|
||||
std::string hef_dir = hef_path;
|
||||
const auto files = Filesystem::get_files_in_dir_flat(hef_dir);
|
||||
CHECK_EXPECTED_AS_STATUS(files);
|
||||
|
||||
for (const auto &full_path : files.value()) {
|
||||
if (Filesystem::has_suffix(full_path, ".hef")) {
|
||||
contains_hef = true;
|
||||
std::cout << std::string(80, '*') << std::endl << "Parsing " << full_path << ":"<< std::endl;
|
||||
auto status = ParseHefCommand::parse_hefs_info(full_path, stream_infos, vstream_infos);
|
||||
CHECK_SUCCESS(status, "Failed to parse HEF {}", full_path);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(contains_hef, HAILO_INVALID_ARGUMENT, "No HEF files were found in the directory: {}", hef_dir);
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
37
hailort/hailortcli/parse_hef_command.hpp
Normal file
37
hailort/hailortcli/parse_hef_command.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file parse_hef_command.hpp
|
||||
* @brief Parse HEF and print metadata to stdout
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_PARSE_COMMAND_COMMAND_HPP_
|
||||
#define _HAILO_PARSE_COMMAND_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class ParseHefCommand : public Command {
|
||||
public:
|
||||
explicit ParseHefCommand(CLI::App &parent_app);
|
||||
|
||||
virtual hailo_status execute() override;
|
||||
|
||||
private:
|
||||
static hailo_status parse_hefs_infos_dir(const std::string &hef_path, bool stream_infos, bool vstream_infos);
|
||||
static hailo_status parse_hefs_info(const std::string &hef_path, bool stream_infos, bool vstream_infos);
|
||||
|
||||
std::string m_hef_path;
|
||||
bool m_parse_streams;
|
||||
bool m_parse_vstreams;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_PARSE_COMMAND_COMMAND_HPP_ */
|
||||
283
hailort/hailortcli/power_measurement_command.cpp
Normal file
283
hailort/hailortcli/power_measurement_command.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file power_measurement_command.cpp
|
||||
* @brief Measure power of Hailo chip
|
||||
**/
|
||||
|
||||
#include "power_measurement_command.hpp"
|
||||
#include <thread>
|
||||
|
||||
#define POWER_MEASUREMENT_DELAY_MS(__sample_period, __average_factor) \
|
||||
(static_cast<uint32_t>((__sample_period) / 1000.0 * (__average_factor) * 2 * 1.2))
|
||||
|
||||
|
||||
PowerMeasurementSubcommand::PowerMeasurementSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("measure-power", "Measures power consumption")), m_params(),
|
||||
m_power_measurement_duration(0)
|
||||
{
|
||||
m_app->add_option("--duration", m_power_measurement_duration, "The duration in seconds to measure power consumption")
|
||||
->check(CLI::Validator(CLI::PositiveNumber));
|
||||
|
||||
CLI::Option *sampling_period = m_app->add_option("--sampling-period", m_params.sampling_period, "Sampling Period")
|
||||
->needs("--duration");
|
||||
CLI::Option *averaging_factor = m_app->add_option("--averaging-factor", m_params.averaging_factor, "Averaging Factor")
|
||||
->needs("--duration");
|
||||
init_dvm_option(m_app->add_option("--dvm", m_params.dvm_option,
|
||||
"DVM type. \n\
|
||||
Which DVM will be measured. Default (AUTO) will be different according to the board: \n\
|
||||
Default (AUTO) for EVB is an approximation to the total power consumption of the chip in PCIe setups. \n\
|
||||
It sums VDD_CORE, MIPI_AVDD and AVDD_H. Only POWER can measured with this option. \n\
|
||||
Default (AUTO) for platforms supporting current monitoring (such as M.2 and mPCIe): OVERCURRENT_PROTECTION"));
|
||||
init_measurement_type_option(m_app->add_option("--type", m_params.measurement_type, "Power Measurement type"));
|
||||
init_sampling_period_option(sampling_period);
|
||||
init_averaging_factor_option(averaging_factor);
|
||||
}
|
||||
|
||||
void PowerMeasurementSubcommand::init_dvm_option(CLI::Option *dvm_option)
|
||||
{
|
||||
dvm_option->transform(HailoCheckedTransformer<hailo_dvm_options_t>({
|
||||
{ "AUTO", HAILO_DVM_OPTIONS_AUTO },
|
||||
{ "VDD_CORE", HAILO_DVM_OPTIONS_VDD_CORE },
|
||||
{ "VDD_IO", HAILO_DVM_OPTIONS_VDD_IO },
|
||||
{ "MIPI_AVDD", HAILO_DVM_OPTIONS_MIPI_AVDD },
|
||||
{ "MIPI_AVDD_H", HAILO_DVM_OPTIONS_MIPI_AVDD_H },
|
||||
{ "USB_AVDD_IO", HAILO_DVM_OPTIONS_USB_AVDD_IO },
|
||||
{ "VDD_TOP", HAILO_DVM_OPTIONS_VDD_TOP },
|
||||
{ "USB_AVDD_IO_HV", HAILO_DVM_OPTIONS_USB_AVDD_IO_HV },
|
||||
{ "AVDD_H", HAILO_DVM_OPTIONS_AVDD_H },
|
||||
{ "SDIO_VDD_IO", HAILO_DVM_OPTIONS_SDIO_VDD_IO },
|
||||
{ "OVERCURRENT_PROTECTION", HAILO_DVM_OPTIONS_OVERCURRENT_PROTECTION }
|
||||
}))
|
||||
->default_val("AUTO");
|
||||
}
|
||||
|
||||
void PowerMeasurementSubcommand::init_measurement_type_option(CLI::Option *measurement_type)
|
||||
{
|
||||
measurement_type->transform(HailoCheckedTransformer<hailo_power_measurement_types_t>({
|
||||
{ "AUTO", HAILO_POWER_MEASUREMENT_TYPES__AUTO },
|
||||
{ "SHUNT_VOLTAGE", HAILO_POWER_MEASUREMENT_TYPES__SHUNT_VOLTAGE },
|
||||
{ "BUS_VOLTAGE", HAILO_POWER_MEASUREMENT_TYPES__BUS_VOLTAGE },
|
||||
{ "POWER", HAILO_POWER_MEASUREMENT_TYPES__POWER },
|
||||
{ "CURRENT", HAILO_POWER_MEASUREMENT_TYPES__CURRENT }
|
||||
}))
|
||||
->default_val("AUTO");
|
||||
}
|
||||
|
||||
void PowerMeasurementSubcommand::init_sampling_period_option(CLI::Option *sampling_period)
|
||||
{
|
||||
sampling_period->default_val(1100)
|
||||
->transform(CLI::IsMember({140, 204, 332, 588, 1100, 2116, 4156, 8244}));
|
||||
}
|
||||
|
||||
void PowerMeasurementSubcommand::init_averaging_factor_option(CLI::Option *averaging_factor)
|
||||
{
|
||||
averaging_factor->default_val(256)
|
||||
->transform(CLI::IsMember({1, 4, 16, 64, 128, 256, 512, 1024}));
|
||||
}
|
||||
|
||||
hailo_status PowerMeasurementSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
hailo_status status = HAILO_UNINITIALIZED;
|
||||
|
||||
if (0 < m_power_measurement_duration) {
|
||||
status = run_long_power_measurement(device);
|
||||
} else {
|
||||
status = run_single_power_measurement(device);
|
||||
}
|
||||
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed power measurement, status " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<LongPowerMeasurement> PowerMeasurementSubcommand::start_power_measurement(Device &device,
|
||||
hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type, uint32_t sampling_period,
|
||||
uint32_t averaging_factor)
|
||||
{
|
||||
hailo_sampling_period_t sampling_period_enum = get_sampling_period(
|
||||
sampling_period);
|
||||
if (HAILO_SAMPLING_PERIOD_MAX_ENUM == sampling_period_enum) {
|
||||
std::cerr << "Failed to parse sampling period: " << sampling_period << std::endl;
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
|
||||
hailo_averaging_factor_t averaging_factor_enum = get_averaging_factor(
|
||||
averaging_factor);
|
||||
if (HAILO_AVERAGE_FACTOR_MAX_ENUM == averaging_factor_enum) {
|
||||
std::cerr << "Failed to parse averaging factor: " << averaging_factor << std::endl;
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
|
||||
hailo_status status = hailo_stop_power_measurement(reinterpret_cast<hailo_device>(&device));
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed initial power measurement stop, status " << status << std::endl;
|
||||
return make_unexpected(status);
|
||||
}
|
||||
|
||||
status = hailo_set_power_measurement(reinterpret_cast<hailo_device>(&device), 0, dvm, measurement_type);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed to set power measurement parameters, status " << status << std::endl;
|
||||
return make_unexpected(status);
|
||||
}
|
||||
|
||||
uint32_t measurement_delay = POWER_MEASUREMENT_DELAY_MS(sampling_period, averaging_factor);
|
||||
// There is no logical way that measurement delay can be 0 - because sampling_period and averaging_factor cant be 0
|
||||
// Hence if it is 0 - it means it was 0.xx and we want to round up to 1 in that case
|
||||
if (0 == measurement_delay) {
|
||||
measurement_delay = 1;
|
||||
}
|
||||
status = hailo_start_power_measurement(reinterpret_cast<hailo_device>(&device), measurement_delay,
|
||||
averaging_factor_enum, sampling_period_enum);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed to start power measurement, status " << status << std::endl;
|
||||
return make_unexpected(status);
|
||||
}
|
||||
|
||||
return LongPowerMeasurement(device, measurement_type);
|
||||
}
|
||||
|
||||
LongPowerMeasurement::LongPowerMeasurement(Device &device,
|
||||
hailo_power_measurement_types_t measurement_type) : m_device(device),
|
||||
m_measurement_type(measurement_type), m_data(), m_power_units()
|
||||
{}
|
||||
|
||||
hailo_status LongPowerMeasurement::stop()
|
||||
{
|
||||
hailo_status status = hailo_stop_power_measurement(reinterpret_cast<hailo_device>(&m_device));
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed to stop power measurement, status " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = hailo_get_power_measurement(reinterpret_cast<hailo_device>(&m_device), 0, true, &m_data);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed to get power measurement results, status " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *power_units = PowerMeasurementSubcommand::get_power_units(m_measurement_type);
|
||||
if (nullptr == power_units) {
|
||||
std::cerr << "Failed to get power measurement units of type " << m_measurement_type << std::endl;
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
m_power_units = power_units;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
hailo_sampling_period_t PowerMeasurementSubcommand::get_sampling_period(uint32_t sampling_period)
|
||||
{
|
||||
switch (sampling_period) {
|
||||
case 140:
|
||||
return HAILO_SAMPLING_PERIOD_140US;
|
||||
case 204:
|
||||
return HAILO_SAMPLING_PERIOD_204US;
|
||||
case 332:
|
||||
return HAILO_SAMPLING_PERIOD_332US;
|
||||
case 588:
|
||||
return HAILO_SAMPLING_PERIOD_588US;
|
||||
case 1100:
|
||||
return HAILO_SAMPLING_PERIOD_1100US;
|
||||
case 2116:
|
||||
return HAILO_SAMPLING_PERIOD_2116US;
|
||||
case 4156:
|
||||
return HAILO_SAMPLING_PERIOD_4156US;
|
||||
case 8244:
|
||||
return HAILO_SAMPLING_PERIOD_8244US;
|
||||
default:
|
||||
return HAILO_SAMPLING_PERIOD_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
|
||||
hailo_averaging_factor_t PowerMeasurementSubcommand::get_averaging_factor(uint32_t averaging_factor)
|
||||
{
|
||||
switch (averaging_factor) {
|
||||
case 1:
|
||||
return HAILO_AVERAGE_FACTOR_1;
|
||||
case 4:
|
||||
return HAILO_AVERAGE_FACTOR_4;
|
||||
case 16:
|
||||
return HAILO_AVERAGE_FACTOR_16;
|
||||
case 64:
|
||||
return HAILO_AVERAGE_FACTOR_64;
|
||||
case 128:
|
||||
return HAILO_AVERAGE_FACTOR_128;
|
||||
case 256:
|
||||
return HAILO_AVERAGE_FACTOR_256;
|
||||
case 512:
|
||||
return HAILO_AVERAGE_FACTOR_512;
|
||||
case 1024:
|
||||
return HAILO_AVERAGE_FACTOR_1024;
|
||||
default:
|
||||
return HAILO_AVERAGE_FACTOR_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
|
||||
hailo_status PowerMeasurementSubcommand::run_long_power_measurement(Device &device)
|
||||
{
|
||||
auto long_power_measurement = start_power_measurement(device, m_params.dvm_option,
|
||||
m_params.measurement_type, m_params.sampling_period, m_params.averaging_factor);
|
||||
if (!long_power_measurement) {
|
||||
return long_power_measurement.status();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(m_power_measurement_duration));
|
||||
|
||||
hailo_status status = long_power_measurement.value().stop();
|
||||
if (HAILO_SUCCESS != status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
const hailo_power_measurement_data_t &measurement_data = long_power_measurement.value().data();
|
||||
const std::string &power_units = long_power_measurement.value().power_units();
|
||||
|
||||
std::cout << "Measuring power consumption over " << m_power_measurement_duration << " seconds:" << std::endl;
|
||||
std::cout << "Total samples: " << measurement_data.total_number_of_samples << std::endl;
|
||||
std::cout << "Max value (" << power_units << "): " << measurement_data.max_value << std::endl;
|
||||
std::cout << "Min value (" << power_units << "): " << measurement_data.min_value << std::endl;
|
||||
std::cout << "Average value (" << power_units << "): " << measurement_data.average_value << std::endl;
|
||||
std::cout << "Average time per sample (ms): " << measurement_data.average_time_value_milliseconds << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
const char *PowerMeasurementSubcommand::get_power_units(hailo_power_measurement_types_t measurement_type)
|
||||
{
|
||||
switch (measurement_type) {
|
||||
case HAILO_POWER_MEASUREMENT_TYPES__SHUNT_VOLTAGE:
|
||||
case HAILO_POWER_MEASUREMENT_TYPES__BUS_VOLTAGE:
|
||||
return "mV";
|
||||
case HAILO_POWER_MEASUREMENT_TYPES__AUTO:
|
||||
case HAILO_POWER_MEASUREMENT_TYPES__POWER:
|
||||
return "W";
|
||||
case HAILO_POWER_MEASUREMENT_TYPES__CURRENT:
|
||||
return "mA";
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
hailo_status PowerMeasurementSubcommand::run_single_power_measurement(Device &device)
|
||||
{
|
||||
float32_t measurement = 0.0f;
|
||||
hailo_status status = hailo_power_measurement(reinterpret_cast<hailo_device>(&device), m_params.dvm_option, m_params.measurement_type,
|
||||
&measurement);
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Failed to get power measurement results, status " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *power_units = get_power_units(m_params.measurement_type);
|
||||
if (nullptr == power_units) {
|
||||
std::cerr << "Failed to get power measurement units of type " << m_params.measurement_type << std::endl;
|
||||
return HAILO_NOT_FOUND;
|
||||
}
|
||||
|
||||
std::cout << "Current power consumption (" << power_units << "): " << measurement << std::endl;
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
75
hailort/hailortcli/power_measurement_command.hpp
Normal file
75
hailort/hailortcli/power_measurement_command.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file power_measurement_command.hpp
|
||||
* @brief Measure power of Hailo chip
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_POWER_MEASUREMENT_COMMAND_HPP_
|
||||
#define _HAILO_POWER_MEASUREMENT_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
class LongPowerMeasurement final {
|
||||
public:
|
||||
LongPowerMeasurement(Device &device, hailo_power_measurement_types_t measurement_type);
|
||||
~LongPowerMeasurement() = default;
|
||||
hailo_status stop();
|
||||
|
||||
const hailo_power_measurement_data_t &data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const std::string &power_units() const
|
||||
{
|
||||
return m_power_units;
|
||||
}
|
||||
|
||||
private:
|
||||
Device &m_device;
|
||||
hailo_power_measurement_types_t m_measurement_type;
|
||||
hailo_power_measurement_data_t m_data;
|
||||
std::string m_power_units;
|
||||
};
|
||||
|
||||
class PowerMeasurementSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit PowerMeasurementSubcommand(CLI::App &parent_app);
|
||||
|
||||
static Expected<LongPowerMeasurement> start_power_measurement(Device &device,
|
||||
hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type,
|
||||
uint32_t sampling_period, uint32_t averaging_factor);
|
||||
static void init_sampling_period_option(CLI::Option *sampling_period);
|
||||
static void init_averaging_factor_option(CLI::Option *averaging_factor);
|
||||
static hailo_sampling_period_t get_sampling_period(uint32_t sampling_period);
|
||||
static hailo_averaging_factor_t get_averaging_factor(uint32_t averaging_factor);
|
||||
static const char *get_power_units(hailo_power_measurement_types_t measurement_type);
|
||||
|
||||
protected:
|
||||
hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
struct power_measurement_params {
|
||||
hailo_dvm_options_t dvm_option;
|
||||
hailo_power_measurement_types_t measurement_type;
|
||||
uint32_t sampling_period;
|
||||
uint32_t averaging_factor;
|
||||
};
|
||||
|
||||
power_measurement_params m_params;
|
||||
uint32_t m_power_measurement_duration;
|
||||
|
||||
static void init_dvm_option(CLI::Option *dvm_option);
|
||||
static void init_measurement_type_option(CLI::Option *measurement_type);
|
||||
hailo_status run_long_power_measurement(Device &device);
|
||||
hailo_status run_single_power_measurement(Device &device);
|
||||
};
|
||||
|
||||
#endif /* _HAILO_POWER_MEASUREMENT_COMMAND_HPP_ */
|
||||
1229
hailort/hailortcli/run_command.cpp
Normal file
1229
hailort/hailortcli/run_command.cpp
Normal file
File diff suppressed because it is too large
Load Diff
162
hailort/hailortcli/run_command.hpp
Normal file
162
hailort/hailortcli/run_command.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file run_command.hpp
|
||||
* @brief Run inference on hailo device
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_RUN_COMMAND_HPP_
|
||||
#define _HAILO_RUN_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "power_measurement_command.hpp"
|
||||
#include "temp_measurement.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
#include "inference_result.hpp"
|
||||
|
||||
|
||||
enum class InferMode {
|
||||
STREAMING,
|
||||
HW_ONLY,
|
||||
};
|
||||
|
||||
struct transformation_params {
|
||||
bool transform;
|
||||
bool quantized;
|
||||
hailo_format_type_t format_type;
|
||||
};
|
||||
|
||||
struct measure_power_params {
|
||||
bool measure_power;
|
||||
bool measure_current;
|
||||
uint32_t sampling_period;
|
||||
uint32_t averaging_factor;
|
||||
};
|
||||
|
||||
struct pipeline_stats_measurement_params {
|
||||
bool measure_elem_fps;
|
||||
bool measure_elem_latency;
|
||||
bool measure_elem_queue_size;
|
||||
bool measure_vstream_fps;
|
||||
bool measure_vstream_latency;
|
||||
std::string pipeline_stats_output_path;
|
||||
};
|
||||
|
||||
struct runtime_data_params {
|
||||
bool download_runtime_data;
|
||||
std::string runtime_data_output_path;
|
||||
};
|
||||
|
||||
struct inference_runner_params {
|
||||
hailo_device_params device_params;
|
||||
std::string hef_path;
|
||||
uint32_t frames_count;
|
||||
uint32_t time_to_run;
|
||||
InferMode mode;
|
||||
std::string csv_output;
|
||||
std::vector<std::string> inputs_name_and_file_path;
|
||||
bool measure_latency;
|
||||
bool measure_overall_latency;
|
||||
bool show_progress;
|
||||
transformation_params transform;
|
||||
measure_power_params power_measurement;
|
||||
uint16_t batch_size;
|
||||
hailo_power_mode_t power_mode;
|
||||
pipeline_stats_measurement_params pipeline_stats;
|
||||
runtime_data_params runtime_data;
|
||||
std::string dot_output;
|
||||
bool measure_temp;
|
||||
std::vector<std::string> batch_per_network;
|
||||
};
|
||||
|
||||
bool should_measure_pipeline_stats(const inference_runner_params& params);
|
||||
CLI::App* create_run_command(CLI::App& parent, inference_runner_params& params);
|
||||
hailo_status run_command(const inference_runner_params ¶ms);
|
||||
Expected<NetworkGroupInferResult> run_command_hef(const inference_runner_params ¶ms);
|
||||
|
||||
std::string format_type_to_string(hailo_format_type_t format_type);
|
||||
|
||||
class RunCommand : public Command {
|
||||
public:
|
||||
explicit RunCommand(CLI::App &parent_app);
|
||||
hailo_status execute() override;
|
||||
|
||||
private:
|
||||
inference_runner_params m_params;
|
||||
};
|
||||
|
||||
class InputNameToFilePairValidator : public CLI::Validator {
|
||||
public:
|
||||
InputNameToFilePairValidator() : CLI::Validator("InputNameToFilePair"), m_first_run(true), m_must_fail(false) {
|
||||
func_ = [this](std::string &key_value_pair_str) {
|
||||
bool old_first_run = m_first_run;
|
||||
m_first_run = false;
|
||||
if (m_must_fail) { // If a previous argument was not in key-value pair form, there shouldn't be more parameters
|
||||
return std::string("Parse failed at (" + key_value_pair_str + ")");
|
||||
}
|
||||
|
||||
size_t first_delimiter = key_value_pair_str.find("=");
|
||||
if((std::string::npos == first_delimiter) || (key_value_pair_str.size() == first_delimiter + 1)) {
|
||||
if (old_first_run) { // We only accept non-key-value pair form if it's the very first parameter
|
||||
m_must_fail = true;
|
||||
return CLI::ExistingFile(key_value_pair_str);
|
||||
}
|
||||
return std::string("Failed parsing key-value pair: (" + key_value_pair_str + ")");
|
||||
}
|
||||
auto file_path = key_value_pair_str.substr(first_delimiter + 1);
|
||||
return CLI::ExistingFile(file_path);
|
||||
};
|
||||
|
||||
desc_function_ = []() {
|
||||
return "\t\tInput file path/paths. On single input network, give the full path of the data file.\n\
|
||||
\t\tOn multiple inputs network, the format is input_name1=path1 input_name2=path2, where\n\
|
||||
\t\tinput_name1 is the name of the input stream. If not given, random data will be used";
|
||||
};
|
||||
}
|
||||
private:
|
||||
bool m_first_run;
|
||||
bool m_must_fail;
|
||||
};
|
||||
|
||||
const static InputNameToFilePairValidator InputNameToFileMap;
|
||||
|
||||
class NetworkBatchValidator : public CLI::Validator {
|
||||
public:
|
||||
NetworkBatchValidator() : CLI::Validator(), m_must_fail(false) {
|
||||
func_ = [this](std::string &key_value_pair_str) {
|
||||
if (m_must_fail) { // If a previous argument was not in a valid key-value pair form, there shouldn't be more parameters
|
||||
return std::string("Parse failed at (" + key_value_pair_str + ")");
|
||||
}
|
||||
|
||||
size_t first_delimiter = key_value_pair_str.find("=");
|
||||
if((std::string::npos == first_delimiter) || (key_value_pair_str.size() == first_delimiter + 1)) {
|
||||
// We do not accept non-key-value pair form
|
||||
m_must_fail = true;
|
||||
return std::string("Failed parsing key-value pair: (" + key_value_pair_str + ")");
|
||||
}
|
||||
auto batch_size = key_value_pair_str.substr(first_delimiter + 1);
|
||||
auto network_name = key_value_pair_str.substr(0, first_delimiter);
|
||||
// Batch size must be a positive number
|
||||
if (!is_positive_number(batch_size)) {
|
||||
m_must_fail = true;
|
||||
return std::string("Failed parsing batch size (" + batch_size + ") for network (" + network_name + "). batch should be a positive number.");
|
||||
}
|
||||
return std::string("");
|
||||
};
|
||||
|
||||
}
|
||||
private:
|
||||
bool is_positive_number(const std::string &s)
|
||||
{
|
||||
bool is_number = (!s.empty()) && (std::all_of(s.begin(), s.end(), ::isdigit));
|
||||
return is_number && (0 < std::stoi(s));
|
||||
}
|
||||
|
||||
bool m_must_fail;
|
||||
};
|
||||
|
||||
const static NetworkBatchValidator NetworkBatchMap;
|
||||
|
||||
#endif /* _HAILO_RUN_COMMAND_HPP_ */
|
||||
154
hailort/hailortcli/scan_command.cpp
Normal file
154
hailort/hailortcli/scan_command.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file scan_command.cpp
|
||||
* @brief Scan hailo devices
|
||||
**/
|
||||
#include "scan_command.hpp"
|
||||
#include "hailortcli.hpp"
|
||||
#include "common/socket.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
ScanSubcommand::ScanSubcommand(CLI::App &parent_app) :
|
||||
Command(parent_app.add_subcommand("scan", "Shows all available devices")),
|
||||
m_device_type(Device::Type::PCIE)
|
||||
{
|
||||
// TODO: `--target` and `udp` Device::TYPE::ETH are for backwards compatibility with the python implemention (`hailo`)
|
||||
// TODO: Remove them (HRT-2676)
|
||||
const HailoCheckedTransformer<Device::Type> device_type_transformer({
|
||||
{ "pcie", Device::Type::PCIE },
|
||||
{ "eth", Device::Type::ETH },
|
||||
{ "udp", Device::Type::ETH },
|
||||
});
|
||||
auto *device_type_option = m_app->add_option("-d,--device-type,--target", m_device_type,
|
||||
"Device type to use\n"
|
||||
"Note: 'udp' is an alias for 'eth'.")
|
||||
->transform(device_type_transformer)
|
||||
->default_val("pcie");
|
||||
|
||||
// Ethernet options
|
||||
auto *eth_options_group = m_app->add_option_group("Ethernet Device Options");
|
||||
// TODO: `--ip` is for backwards compatibility with the python implemention (`hailo`)
|
||||
// TODO: Remove it (HRT-2676)
|
||||
auto *interface_ip_option = eth_options_group->add_option("--interface-ip", m_interface_ip_addr,
|
||||
"Interface IP address to scan")
|
||||
->default_val("")
|
||||
->check(CLI::ValidIPV4);
|
||||
auto *ip_option = eth_options_group->add_option("--ip", m_interface_ip_addr)
|
||||
->default_val("")
|
||||
->excludes(interface_ip_option)
|
||||
->check(CLI::ValidIPV4);
|
||||
|
||||
auto *interface_name_option = eth_options_group->add_option("--interface", m_interface_name, "Interface name to scan")
|
||||
->default_val("")
|
||||
->excludes(interface_ip_option)
|
||||
->excludes(ip_option);
|
||||
|
||||
m_app->parse_complete_callback([this, device_type_option, interface_ip_option, ip_option, interface_name_option]() {
|
||||
bool eth_options_given = !interface_ip_option->empty() || !ip_option->empty() || !interface_name_option->empty();
|
||||
|
||||
// The user didn't put target, we can figure it ourself
|
||||
if (device_type_option->empty()) {
|
||||
if (eth_options_given) {
|
||||
// User gave IP, target is eth
|
||||
m_device_type = Device::Type::ETH;
|
||||
}
|
||||
else {
|
||||
// Default is pcie
|
||||
m_device_type = Device::Type::PCIE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!eth_options_given && (m_device_type == Device::Type::ETH)) {
|
||||
throw CLI::ParseError("Ethernet options not set", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
|
||||
if (eth_options_given && (m_device_type != Device::Type::ETH)) {
|
||||
throw CLI::ParseError("Ethernet options set on non eth device", CLI::ExitCodes::InvalidError);
|
||||
}
|
||||
});
|
||||
|
||||
std::vector<DeprecationActionPtr> actions{
|
||||
std::make_shared<ValueDeprecation>(device_type_option, "udp", "eth"),
|
||||
std::make_shared<OptionDeprecation>(ip_option, "--interface-ip")
|
||||
};
|
||||
hailo_deprecate_options(m_app, actions, false);
|
||||
}
|
||||
|
||||
hailo_status ScanSubcommand::execute()
|
||||
{
|
||||
switch (m_device_type)
|
||||
{
|
||||
case Device::Type::PCIE:
|
||||
return scan_pcie();
|
||||
case Device::Type::ETH:
|
||||
return scan_ethernet(m_interface_ip_addr, m_interface_name).status();
|
||||
default:
|
||||
std::cerr << "Unkown target" << std::endl;
|
||||
return HAILO_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
hailo_status ScanSubcommand::scan_pcie()
|
||||
{
|
||||
auto scan_result = Device::scan_pcie();
|
||||
CHECK_SUCCESS(scan_result.status(), "Error scan failed status = {}", scan_result.status());
|
||||
|
||||
if (scan_result->size() == 0) {
|
||||
std::cout << "Hailo PCIe devices not found" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "Hailo PCIe Devices:" << std::endl;
|
||||
for (const auto& device_info : scan_result.value()) {
|
||||
auto device_info_str = Device::pcie_device_info_to_string(device_info);
|
||||
CHECK_EXPECTED_AS_STATUS(device_info_str);
|
||||
std::cout << "[-] Device BDF: " << device_info_str.value() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
Expected<std::vector<std::string>> ScanSubcommand::scan_ethernet(const std::string &interface_ip_addr,
|
||||
const std::string &interface_name)
|
||||
{
|
||||
const std::chrono::seconds timeout(3);
|
||||
std::vector<hailo_eth_device_info_t> device_infos;
|
||||
|
||||
if (!interface_ip_addr.empty()) {
|
||||
auto result = Device::scan_eth_by_host_address(interface_ip_addr, timeout);
|
||||
if (!result) {
|
||||
std::cerr << "Failed scanning ethernet device from host address (" << result.status() << ")" << std::endl;
|
||||
return make_unexpected(result.status());
|
||||
}
|
||||
device_infos = result.release();
|
||||
} else {
|
||||
auto result = Device::scan_eth(interface_name, timeout);
|
||||
if (!result) {
|
||||
std::cerr << "Failed scanning ethernet device from interface name (" << result.status() << ")" << std::endl;
|
||||
return make_unexpected(result.status());
|
||||
}
|
||||
device_infos = result.release();
|
||||
}
|
||||
|
||||
std::cout << "Hailo Ethernet Devices:" << std::endl;
|
||||
std::vector<std::string> ip_addresses;
|
||||
ip_addresses.reserve(device_infos.size());
|
||||
char textual_ip_address[INET_ADDRSTRLEN] = {};
|
||||
for (size_t i = 0; i < device_infos.size(); i++) {
|
||||
auto status = Socket::ntop(AF_INET, &(device_infos[i].device_address.sin_addr), textual_ip_address,
|
||||
INET_ADDRSTRLEN);
|
||||
if (status != HAILO_SUCCESS) {
|
||||
std::cerr << "Could not convert ip address to textual format (inet_ntop has failed)" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "[-] Board IP: " << textual_ip_address << std::endl;
|
||||
ip_addresses.emplace_back(textual_ip_address);
|
||||
}
|
||||
return ip_addresses;
|
||||
}
|
||||
38
hailort/hailortcli/scan_command.hpp
Normal file
38
hailort/hailortcli/scan_command.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file scan_command.hpp
|
||||
* @brief Scan hailo devices
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_SCAN_COMMAND_HPP_
|
||||
#define _HAILO_SCAN_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class ScanSubcommand final : public Command {
|
||||
public:
|
||||
explicit ScanSubcommand(CLI::App &parent_app);
|
||||
hailo_status execute() override;
|
||||
|
||||
static Expected<std::vector<std::string>> scan_ethernet(const std::string &interface_ip_addr,
|
||||
const std::string &interface_name);
|
||||
|
||||
private:
|
||||
hailo_status scan_pcie();
|
||||
|
||||
Device::Type m_device_type;
|
||||
|
||||
// Ethernet scan options
|
||||
std::string m_interface_ip_addr;
|
||||
std::string m_interface_name;
|
||||
};
|
||||
|
||||
#endif /* _HAILO_SCAN_COMMAND_HPP_ */
|
||||
209
hailort/hailortcli/sensor_config_command.cpp
Normal file
209
hailort/hailortcli/sensor_config_command.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file sensor_config_command.cpp
|
||||
* @brief Config sensor attached to the Hailo chip
|
||||
**/
|
||||
|
||||
#include "sensor_config_command.hpp"
|
||||
|
||||
SensorConfigCommand::SensorConfigCommand(CLI::App &parent_app) :
|
||||
ContainerCommand(parent_app.add_subcommand("sensor-config", "Config sensor attached to the Hailo chip"))
|
||||
{
|
||||
add_subcommand<SensorStoreConfigSubcommand>();
|
||||
add_subcommand<SensorLoadConfigSubcommand>();
|
||||
add_subcommand<SensorResetSubcommand>();
|
||||
add_subcommand<SensorSectionsInfoSubcommand>();
|
||||
add_subcommand<SensorDumpConfigSubcommand>();
|
||||
add_subcommand<SensorStoreISPConfigSubcommand>();
|
||||
add_subcommand<SensorSetGenericSlaveSubcommand>();
|
||||
}
|
||||
|
||||
Expected<std::string> convert_sensor_type_to_string(uint32_t sensor_type)
|
||||
{
|
||||
switch (sensor_type) {
|
||||
case HAILO_SENSOR_TYPES_GENERIC:
|
||||
return std::string("SENSOR_GENERIC");
|
||||
|
||||
case HAILO_SENSOR_TYPES_ONSEMI_AR0220AT:
|
||||
return std::string("ONSEMI_AR0220AT");
|
||||
|
||||
case HAILO_SENSOR_TYPES_RASPICAM:
|
||||
return std::string("SENSOR_RASPICAM");
|
||||
|
||||
case HAILO_SENSOR_TYPES_ONSEMI_AS0149AT:
|
||||
return std::string("ONSEMI_AS0149AT");
|
||||
|
||||
case HAILO_SENSOR_TYPES_HAILO8_ISP:
|
||||
return std::string("HAILO8_ISP");
|
||||
|
||||
default:
|
||||
LOGGER__ERROR("Failed converting sensor type to string");
|
||||
return make_unexpected(HAILO_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
SensorStoreConfigSubcommand::SensorStoreConfigSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("store-sensor-config", "Store a sensor configuration to a Hailo device")), m_store_config_params()
|
||||
{
|
||||
m_app->add_option("section_index", m_store_config_params.section_index, "Sensor index")
|
||||
->required();
|
||||
m_app->add_option("config_file_path", m_config_file_path, "Config file path (csv)")
|
||||
->check(CLI::ExistingFile)
|
||||
->required();
|
||||
m_app->add_option("sensor_type", m_store_config_params.sensor_type, "Type of sensor")
|
||||
->transform(HailoCheckedTransformer<hailo_sensor_types_t>({
|
||||
{ "SENSOR_GENERIC", HAILO_SENSOR_TYPES_GENERIC },
|
||||
{ "ONSEMI_AR0220AT", HAILO_SENSOR_TYPES_ONSEMI_AR0220AT },
|
||||
{ "SENSOR_RASPICAM", HAILO_SENSOR_TYPES_RASPICAM },
|
||||
{ "ONSEMI_AS0149AT", HAILO_SENSOR_TYPES_ONSEMI_AS0149AT },
|
||||
{ "HAILO8_ISP", HAILO_SENSOR_TYPES_HAILO8_ISP }
|
||||
}))
|
||||
->required();
|
||||
m_app->add_option("--reset-config-size", m_store_config_params.reset_config_size, "The size of the reset configuration data");
|
||||
m_app->add_option("--config-height", m_store_config_params.config_height, "Configuration resolution height");
|
||||
m_app->add_option("--config-width", m_store_config_params.config_width, "Configuration resolution width");
|
||||
m_app->add_option("--config-fps", m_store_config_params.config_fps, "Configuration resolution fps");
|
||||
m_app->add_option("--config-name", m_store_config_params.config_name, "Configuration name")
|
||||
->default_val("UNINITIALIZED");
|
||||
}
|
||||
|
||||
hailo_status SensorStoreConfigSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.store_sensor_config(m_store_config_params.section_index, m_store_config_params.sensor_type,
|
||||
m_store_config_params.reset_config_size, m_store_config_params.config_height,
|
||||
m_store_config_params.config_width, m_store_config_params.config_fps, m_config_file_path,
|
||||
m_store_config_params.config_name);
|
||||
}
|
||||
|
||||
SensorLoadConfigSubcommand::SensorLoadConfigSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("load-config", "Load the sensor configuration stored in the given section"))
|
||||
{
|
||||
m_app->add_option("section_index", m_section_index, "Sensor index")
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status SensorLoadConfigSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.sensor_load_and_start_config(m_section_index);
|
||||
}
|
||||
|
||||
SensorResetSubcommand::SensorResetSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("reset-sensor", "Load reset configuration stored in the given section"))
|
||||
{
|
||||
m_app->add_option("section_index", m_section_index, "Sensor index")
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status SensorResetSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.sensor_reset(m_section_index);
|
||||
}
|
||||
|
||||
SensorSectionsInfoSubcommand::SensorSectionsInfoSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("get-sections-info", "Get the flash sections information"))
|
||||
{}
|
||||
|
||||
hailo_status SensorSectionsInfoSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto sections_info = device.sensor_get_sections_info();
|
||||
CHECK_EXPECTED_AS_STATUS(sections_info);
|
||||
return print_sections_info((SENSOR_CONFIG__section_info_t*)sections_info->data());
|
||||
}
|
||||
|
||||
hailo_status SensorSectionsInfoSubcommand::print_sections_info(SENSOR_CONFIG__section_info_t *operation_cfg)
|
||||
{
|
||||
for (uint32_t section_index = 0; section_index < SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT; section_index++) {
|
||||
SENSOR_CONFIG__section_info_t *section_info = &operation_cfg[section_index];
|
||||
|
||||
std::cout << "======== section_index: " << section_index << " =========" << std::endl;
|
||||
|
||||
if (section_info->is_free) {
|
||||
std::cout << "Section is not active\n" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string reset_config = section_info->no_reset_offset ? "not valid" : "valid";
|
||||
auto sensor_type_expected = convert_sensor_type_to_string(section_info->sensor_type);
|
||||
CHECK_EXPECTED_AS_STATUS(sensor_type_expected, "Failed convert sensor type to string");
|
||||
|
||||
std::cout << "Configuration Name: " << section_info->config_name << "\n";
|
||||
std::cout << "Sensor Type: " << sensor_type_expected.value() << "\n";
|
||||
std::cout << "Configuration lines number: " << (section_info->config_size / sizeof(SENSOR_CONFIG__operation_cfg_t)) << "\n";
|
||||
std::cout << "Configuration size in bytes: " << section_info->config_size << "\n";
|
||||
std::cout << "Reset configuration: " << reset_config << "\n";
|
||||
std::cout << "Reset configuration lines number: " << section_info->reset_config_size << "\n";
|
||||
std::cout << "Configuration resolution: [height " << section_info->config_height << " : width " << section_info->config_width << "]" << "\n";
|
||||
std::cout << "Configuration fps: " << section_info->config_fps << "\n";
|
||||
std::cout << "Section configuration version: " << section_info->section_version << "\n";
|
||||
std::cout << "Section is active\n" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO: change "get-config" to "dump-config" after solving backward compatibility issues
|
||||
SensorDumpConfigSubcommand::SensorDumpConfigSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("get-config", "Dumps the configuration stored in the given section into a csv file"))
|
||||
{
|
||||
m_app->add_option("section_index", m_section_index, "Sensor index")
|
||||
->check(CLI::Range(0, (SENSOR_CONFIG__TOTAL_SECTIONS_BLOCK_COUNT - 1)))
|
||||
->required();
|
||||
m_app->add_option("config_file_path", m_output_file_path, "File path to write section configuration")
|
||||
->required();
|
||||
}
|
||||
|
||||
hailo_status SensorDumpConfigSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.sensor_dump_config(m_section_index, m_output_file_path);
|
||||
}
|
||||
|
||||
SensorStoreISPConfigSubcommand::SensorStoreISPConfigSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("store_isp_config", "Store an ISP configuration to Hailo device, in section index " + std::to_string(SENSOR_CONFIG__ISP_SECTION_INDEX))),
|
||||
m_store_config_params()
|
||||
{
|
||||
m_app->add_option("isp_static_config_file_path", m_isp_static_config_file_path, "ISP static config file path")
|
||||
->required();
|
||||
m_app->add_option("isp_runtime_config_file_path", m_isp_runtime_config_file_path, "ISP runtime config file path")
|
||||
->required();
|
||||
m_app->add_option("--reset-config-size", m_store_config_params.reset_config_size, "The size of the reset configuration data");
|
||||
m_app->add_option("--config-height", m_store_config_params.config_height, "Configuration resolution height");
|
||||
m_app->add_option("--config-width", m_store_config_params.config_width, "Configuration resolution width");
|
||||
m_app->add_option("--config-fps", m_store_config_params.config_fps, "Configuration resolution fps");
|
||||
m_app->add_option("--config-name", m_store_config_params.config_name, "Configuration name")
|
||||
->default_val("UNINITIALIZED");
|
||||
}
|
||||
|
||||
hailo_status SensorStoreISPConfigSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.store_isp_config(m_store_config_params.reset_config_size, m_store_config_params.config_height,
|
||||
m_store_config_params.config_width, m_store_config_params.config_fps, m_isp_static_config_file_path,
|
||||
m_isp_runtime_config_file_path, m_store_config_params.config_name);
|
||||
}
|
||||
|
||||
SensorSetGenericSlaveSubcommand::SensorSetGenericSlaveSubcommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("set_generic_slave", "Set a custom i2c slave that can be used"))
|
||||
{
|
||||
m_app->add_option("slave_address", m_sensor_i2c_slave_info.slave_address, "The address of the i2c slave")
|
||||
->required();
|
||||
m_app->add_option("register_address_size", m_sensor_i2c_slave_info.register_address_size, "Slave offset length in bytes")
|
||||
->required();
|
||||
m_app->add_option("bus_index", m_sensor_i2c_slave_info.bus_index, "The bus number the i2c slave is connected to")
|
||||
->required();
|
||||
m_app->add_option("--should-hold-bus", m_sensor_i2c_slave_info.should_hold_bus, "Should hold the bus during the read")
|
||||
->default_val("false");
|
||||
m_app->add_option("--slave-endianness", m_sensor_i2c_slave_info.endianness)
|
||||
->transform(HailoCheckedTransformer<i2c_slave_endianness_t>({
|
||||
{ "BIG_ENDIAN", I2C_SLAVE_ENDIANNESS_BIG_ENDIAN },
|
||||
{ "LITTLE_ENDIAN", I2C_SLAVE_ENDIANNESS_LITTLE_ENDIAN }
|
||||
}))
|
||||
->default_val(I2C_SLAVE_ENDIANNESS_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
hailo_status SensorSetGenericSlaveSubcommand::execute_on_device(Device &device)
|
||||
{
|
||||
return device.sensor_set_generic_i2c_slave(m_sensor_i2c_slave_info.slave_address, m_sensor_i2c_slave_info.register_address_size,
|
||||
m_sensor_i2c_slave_info.bus_index, m_sensor_i2c_slave_info.should_hold_bus, m_sensor_i2c_slave_info.endianness);
|
||||
}
|
||||
116
hailort/hailortcli/sensor_config_command.hpp
Normal file
116
hailort/hailortcli/sensor_config_command.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file sensor_config_command.hpp
|
||||
* @brief Config sensor attached to the Hailo chip
|
||||
**/
|
||||
|
||||
#ifndef _HAILO_SENSOR_CONFIG_COMMAND_HPP_
|
||||
#define _HAILO_SENSOR_CONFIG_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
#include "hailo/hailort.h"
|
||||
#include "sensor_config_exports.h"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
struct store_config_params_t {
|
||||
uint32_t section_index;
|
||||
hailo_sensor_types_t sensor_type;
|
||||
uint32_t reset_config_size;
|
||||
uint16_t config_height;
|
||||
uint16_t config_width;
|
||||
uint16_t config_fps;
|
||||
std::string config_name;
|
||||
};
|
||||
|
||||
class SensorStoreConfigSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorStoreConfigSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
store_config_params_t m_store_config_params;
|
||||
std::string m_config_file_path;
|
||||
};
|
||||
|
||||
class SensorLoadConfigSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorLoadConfigSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
uint8_t m_section_index;
|
||||
};
|
||||
|
||||
class SensorResetSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorResetSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
uint8_t m_section_index;
|
||||
};
|
||||
|
||||
class SensorSectionsInfoSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorSectionsInfoSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
static hailo_status print_sections_info(SENSOR_CONFIG__section_info_t *operation_cfg);
|
||||
};
|
||||
|
||||
class SensorDumpConfigSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorDumpConfigSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
uint8_t m_section_index;
|
||||
std::string m_output_file_path;
|
||||
};
|
||||
|
||||
class SensorStoreISPConfigSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorStoreISPConfigSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
store_config_params_t m_store_config_params;
|
||||
std::string m_isp_static_config_file_path;
|
||||
std::string m_isp_runtime_config_file_path;
|
||||
};
|
||||
|
||||
class SensorSetGenericSlaveSubcommand final : public DeviceCommand {
|
||||
public:
|
||||
explicit SensorSetGenericSlaveSubcommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
SENSOR_I2C_SLAVE_INFO_t m_sensor_i2c_slave_info;
|
||||
};
|
||||
|
||||
class SensorConfigCommand final : public ContainerCommand {
|
||||
public:
|
||||
explicit SensorConfigCommand(CLI::App &parent_app);
|
||||
};
|
||||
|
||||
#endif /* _HAILO_SENSOR_CONFIG_COMMAND_HPP_ */
|
||||
41
hailort/hailortcli/ssb_update_command.cpp
Normal file
41
hailort/hailortcli/ssb_update_command.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file ssb_update_command.cpp
|
||||
* @brief Update second stage boot on hailo device with flash
|
||||
**/
|
||||
|
||||
#include "ssb_update_command.hpp"
|
||||
#include "common/file_utils.hpp"
|
||||
|
||||
|
||||
SSBUpdateCommand::SSBUpdateCommand(CLI::App &parent_app) :
|
||||
DeviceCommand(parent_app.add_subcommand("ssb-update", "Second stage boot update command (only for flash based devices)")),
|
||||
m_second_stage_path()
|
||||
{
|
||||
m_app->add_option("file_path", m_second_stage_path, "The path to the second stage boot binary")
|
||||
->required()
|
||||
->check(CLI::ExistingFile);
|
||||
}
|
||||
|
||||
hailo_status SSBUpdateCommand::execute_on_device(Device &device)
|
||||
{
|
||||
auto second_stage = read_binary_file(m_second_stage_path);
|
||||
if (!second_stage) {
|
||||
std::cerr << "Failed reading second stage boot file " << second_stage.status() << std::endl;
|
||||
return second_stage.status();
|
||||
}
|
||||
|
||||
std::cout << "Updating second stage boot..." << std::endl;
|
||||
auto status = device.second_stage_update(second_stage->data(), static_cast<uint32_t>(second_stage->size()));
|
||||
if (HAILO_SUCCESS != status) {
|
||||
std::cerr << "Update second stage boot failed with error: " << status << std::endl;
|
||||
return status;
|
||||
}
|
||||
|
||||
std::cout << "second stage boot has been updated successfully" << std::endl;
|
||||
|
||||
return HAILO_SUCCESS;
|
||||
}
|
||||
33
hailort/hailortcli/ssb_update_command.hpp
Normal file
33
hailort/hailortcli/ssb_update_command.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
|
||||
* Distributed under the MIT license (https://opensource.org/licenses/MIT)
|
||||
**/
|
||||
/**
|
||||
* @file ssb_update_command.hpp
|
||||
* @brief Update second stage boot on hailo device with flash
|
||||
**/
|
||||
|
||||
#ifndef _HAILORTCLI_SSB_UPDATE_COMMAND_HPP_
|
||||
#define _HAILORTCLI_SSB_UPDATE_COMMAND_HPP_
|
||||
|
||||
#include "hailortcli.hpp"
|
||||
#include "command.hpp"
|
||||
|
||||
#include "hailo/hailort.h"
|
||||
#include "hailo/device.hpp"
|
||||
#include "hailo/buffer.hpp"
|
||||
#include "CLI/CLI.hpp"
|
||||
|
||||
|
||||
class SSBUpdateCommand : public DeviceCommand {
|
||||
public:
|
||||
explicit SSBUpdateCommand(CLI::App &parent_app);
|
||||
|
||||
protected:
|
||||
virtual hailo_status execute_on_device(Device &device) override;
|
||||
|
||||
private:
|
||||
std::string m_second_stage_path;
|
||||
};
|
||||
|
||||
#endif /* _HAILORTCLI_SSB_UPDATE_COMMAND_HPP_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user