%% Deep Learning Prediction with ARM Compute Using |codegen|
% 
% This example shows how to use |codegen| to generate code for a Logo
% classification application that uses deep learning on ARM(R) processors.
% The logo classification application uses the |LogoNet| series network to
% perform logo recognition from images. The generated code takes advantage
% of the ARM Compute library for computer vision and machine learning.
%
% Copyright 2018 The MathWorks, Inc.
%% Prerequisites
% * ARM processor that supports the NEON extension
% * Open Source Computer Vision Library (OpenCV) v3.1
% * Environment variables for ARM Compute and OpenCV libraries
% * MATLAB(R) Coder(TM) for C++ code generation
% * The support package MATLAB Coder Interface for Deep Learning
% * Deep Learning Toolbox(TM) for using the |SeriesNetwork| object
%
% For more information, see
% <docid:coder_ug#mw_99a4acec-aced-453c-aadd-a18e83133574>.
%
% This example is supported on Linux(R) and Windows(R) platforms and not
% supported for MATLAB Online.
%% Get the Pretrained SeriesNetwork
% Download the pretrained |LogoNet| network and save it as |logonet.mat|,
% if it does not exist. The network was developed in MATLAB(R) and its
% architecture is similar to that of AlexNet. This network can recognize 32
% logos under various lighting conditions and camera angles.
net = getLogonet();

%%
% The network contains 22 layers including convolution, fully connected,
% and the classification output layers.
net.Layers
%% Set Environment Variables 
% On the ARM target hardware, make sure that ARM_COMPUTELIB is set and that
% LD_LIBRARY_PATH contains the path to the ARM Compute Library folder.
%
% See <docid:coder_ug#mw_99a4acec-aced-453c-aadd-a18e83133574>.
% 

%% logonet_predict Function
% The |logonet_predict.m| entry-point function takes an image input and
% performs prediction on the image using the deep learning network saved in
% the |LogoNet| MAT-file. The function loads the network object from
% |LogoNet.mat| into a persistent network vairable _logonet_. On subsequent
% calls to the function, the persistent object is reused.
type logonet_predict

%% Set Up a Code Generation Configuration Object for a Static Library
% When you generate code targeting an ARM-based device and do not use a hardware
% support package, create a configuration object for a library. Do not create
% a configuration object for an executable program. 
% 
% Set up the configuration object for generation of C++ code and generation of code only. 
%
%   cfg = coder.config('lib');
%   cfg.TargetLang = 'C++';
%   cfg.GenCodeOnly = true;
%% Set Up a Configuration Object for Deep Learning Code Generation
% Create a |coder.ARMNEONConfig| object. Specify the library version and the 
% architecture of the target ARM processor. For example, suppose that 
% the target board is a HiKey/Rock960 board with ARMv8 architecture and ARM Compute
% Library version 19.05.
%
%   dlcfg = coder.DeepLearningConfig('arm-compute');
%   dlcfg.ArmComputeVersion = '19.05';
%   dlcfg.ArmArchitecture = 'armv8';
%% Attach the Deep Learning Configuration Object to the Code Generation Configuration Object
% Set the |DeepLearningConfig| property of the code generation
% configuration object to the deep learning configuration object.
%
%   cfg.DeepLearningConfig = dlcfg;
%% Generate Source C++ Code by Using |codegen|
%   codegen -config cfg logonet_predict -args {ones(227, 227, 3, 'single')} -d arm_compute
%%
% The code is generated in the |arm_compute| folder in the current working
% folder on the host computer.
%% Generate the Zip File Using the |packNGo| function 
% The packNGo function packages all relevant files in a compressed zip
% file.
%
%  zipFileName = 'arm_compute.zip'; 
%  bInfo = load(fullfile('arm_compute','buildInfo.mat'));
%  packNGo(bInfo.buildInfo, {'fileName', zipFileName,'minimalHeaders', false, 'ignoreFileMissing',true});

%% Copy the Generated Zip File to the Target Hardware
% Copy the Zip file and extract into a folder. Remove the Zip file from the
% targer hardware.
%
% In the following commands, replace:
%
% * |password| with your password 
% * |username| with your user name
% * |targetname| with the name of your device
% * |targetloc| with the destination folder for the files
%
% Run these commands to copy and extract zip file from Linux.
%
%   if isunix, system(['sshpass -p password scp -r '  fullfile(pwd,zipFileName) ' username@targetname:targetloc/']), end
%   if isunix, system('sshpass -p password ssh username@targetname "if [ -d targetloc/arm_compute ]; then rm -rf targetloc/arm_compute; fi"'), end
%   if isunix, system(['sshpass -p password ssh username@targetname "unzip targetloc/' zipFileName ' -d targetloc/arm_compute"']), end
%   if isunix, system(['sshpass -p password ssh username@targetname "rm -rf  targetloc' zipFileName '"']), end
%
% Run these commands to copy and extract zip file from Windows.
%
%   if ispc, system(['pscp.exe -pw password -r '  fullfile(pwd,zipFileName) ' username@targetname:targetloc/']), end
%   if ispc, system('plink.exe -l username -pw password targetname "if [ -d targetloc/arm_compute ]; then rm -rf targetloc/arm_compute; fi"'), end
%   if ispc, system(['plink.exe -l username -pw password targetname "unzip targetloc/' zipFileName ' -d targetloc/arm_compute"']), end
%   if ispc, system(['plink.exe -l username -pw password targetname "rm -rf  targetloc' zipFileName '"']), end
%   
%% Copy Example Files to the Target Hardware
% Copy these supporting files from the host computer to the target hardware:
%
% * Input image, |coderdemo_google.png|
% * Makefile for generating the library, |logonet_predict_rtw.mk|
% * Makefile for building the executable program, |makefile_arm_logo.mk|
% * Synset dictionary, |synsetWordsLogoDet.txt|
%
% In the following commands, replace:
%
% * |password| with your password 
% * |username| with your user name
% * |targetname| with the name of your device
% * |targetloc| with the destination folder for the files
%
% Perform the steps below to copy all the required files when running from
% Linux
%
%   if isunix, system('sshpass -p password scp logonet_predict_rtw.mk username@targetname:targetloc/arm_compute/'), end
%   if isunix, system('sshpass -p password scp coderdemo_google.png username@targetname:targetloc/arm_compute/'), end
%   if isunix, system('sshpass -p password scp makefile_arm_logo.mk username@targetname:targetloc/arm_compute/'), end
%   if isunix, system('sshpass -p password scp synsetWordsLogoDet.txt username@targetname:targetloc/arm_compute/'), end
%
% Perform the steps below to copy all the required files when running from
% Windows
%
%   if ispc, system('pscp.exe -pw password logonet_predict_rtw.mk username@targetname:targetloc/arm_compute/'), end
%   if ispc, system('pscp.exe -pw password coderdemo_google.png username@targetname:targetloc/arm_compute/'), end
%   if ispc, system('pscp.exe -pw password makefile_arm_logo.mk username@targetname:targetloc/arm_compute/'), end
%   if ispc, system('pscp.exe -pw password synsetWordsLogoDet.txt username@targetname:targetloc/arm_compute/'), end
%
%% Build the Library on the Target Hardware
% To build the library on the target hardware, execute the generated makefile on the ARM
% hardware.
%
% Make sure that you set the environment variables ARM_COMPUTELIB and LD_LIBRARY_PATH
% on the target hardware. See <docid:coder_ug#mw_99a4acec-aced-453c-aadd-a18e83133574>.
% The ARM_ARCH variable is used in the Makefile to pass compiler flags based on Arm
% Architecture.
% ARM_VER variable is used in the Makefile to compile the code based on Arm
% Compute Version.
% Replace the hardware credentials and paths in these commands similar to previous section.
%  
% Perform the below steps to build the library from Linux. 
%
%   if isunix, system('sshpass -p password scp main_arm_logo.cpp username@targetname:targetloc/arm_compute/'), end
%   if isunix, system(['sshpass -p password ssh username@targetname "make -C targetloc/arm_compute/ -f logonet_predict_rtw.mk ARM_ARCH=' dlcfg.ArmArchitecture ' ARM_VER=' dlcfg.ArmComputeVersion ' "']), end
%  
% Perform the below steps to build the library from windows.
%
%   if ispc, system('pscp.exe -pw password main_arm_logo.cpp username@targetname:targetloc/arm_compute/'), end
%   if ispc, system(['plink.exe -l username -pw password targetname "make -C targetloc/arm_compute/ -f logonet_predict_rtw.mk ARM_ARCH=' dlcfg.ArmArchitecture ' ARM_VER=' dlcfg.ArmComputeVersion ' "']), end
%
%% Create Executable from the Library on the Target Hardware
% Build the library with the source main wrapper file to create the executable.
% |main_arm_logo.cpp| is the C++ main wrapper file which
% invokes the |logonet_predict function|.
%
% Run the below command to create the executable from Linux.
%
%   if isunix, system('sshpass -p password ssh username@targetname "make -C targetloc/arm_compute/ -f makefile_arm_logo.mk targetDirName=targetloc/arm_compute"'), end
%
% Run the below command to create the executable from Windows.
%
%   if ispc, system('plink.exe -l username -pw password targetname "make -C targetloc/arm_compute/ -f makefile_arm_logo.mk targetDirName=targetloc/arm_compute"'), end
%
%% Run the Executable on the Target Hardware
%  Run the executable from Linux using below command.
%
%   if isunix, system('sshpass -p password ssh username@targetname "cd targetloc/arm_compute/; ./logonet coderdemo_google.png"'), end
%   
%  Run the executable from Windows using below command.
%
%   if ispc, system('plink.exe -l username -pw password targetname "cd targetloc/arm_compute/; ./logonet coderdemo_google.png"'), end
%
%  Top 5 Predictions:
%  -----------------------------
%  99.992% google
%  0.003% corona
%  0.003% singha
%  0.001% esso
%  0.000% fedex
%
% <<../coderdemo_google.png>>