Uploaded by 16arms

1-Embedded Linux

advertisement
EC-ENG 231 (Spring 2023)
32 bit Lecture Series
Featuring Beaglebone Black
Embedded Linux
Fatima Anwar
fanwar@umass.edu
UMass Amherst
• Instructor Announcements through Moodle (like before)
• Instructor O ce hours: Mon/Wed from 1 to 2 pm starting April 12th,
• Location: KEB 209E (or occasionally online with ahead of time announcements)
• TA support hours and lab hours, and student lab days stay the same
• Follow the same biweekly lab schedule with mandatory attendance
• Piazza is for peer-peer communication and for asking questions from TAs,
• Do not expect an immediate response
• It might take at least 12 hours to get a response
• Email the instructor for matters speci c to you, and during an emergency
fi
2
ffi

Class related Communication

32 bit Schedule
Date
Topic
04/10
Embedded Linux
04/12
Embedded Linux (cont.) + BBB basics
04/17
Holiday - No Class
04/19
GPIO Programming - interrupts, polling
04/24
S/W Life Cycle: interrupts, threads
04/26
Sample code (lets do it together)
Lab 2: Multithreading
05/01
Multithreading, processes
LAB WEEK (5/1 ~ 5/5)
05/03
Sample code (lets do it together)
05/08
Clocks and Time
05/10
Sensors & Actuators
05/15
Sample code (lets do it together)
05/17
32 bit Review Day
05/22
32 bit Final Exam
** Patriots day holiday: lab trickles over to next week till Tuesday
Lab Assignment
Lab 1: BBB setup, cmd controls
LAB WEEK** (4/19 ~ 4/25)
Lab 3: Async events and sensing
LAB WEEK (5/15 ~ 5/19)
3

Guidelines for Labs
• Total 3 lab manuals: Lab1, Lab2, Lab3
• Lab1 is for setting up and getting acquainted to your board
• You’ll have enough time to set up your board (more than a week)
• Lab 1 also contains a simple graded module
• Once Lab2 starts, assumption is that you have a stable working setup
• Questions related to board setup will not be entertained once Lab2 is assigned
• Less time in between lab deadlines so start on time!
• Do not wait till the deadline to start
• For every day of late submission, 10% of your lab grade will be deducted
•
unless there is a valid reason
4

Textbook & Kits
• Textbook: D. Molloy, “Exploring BeagleBone: Tools and Techniques for Building
with Embedded Linux, 2014”. Available in paperback (~$17 >) and Kindle (~$24)
editions from Amazon. Also available at no charge on the O'Reily Safari Learning
Platform: “Exploring Beaglebone 2nd Edition 2019”
• Website for this book: www.exploringbeaglebone.com
• Datasheets:
• Sitara AM335x ARM Cortex-A8 Technical Reference Manual (TRM):
www.ti.com/product/am3358
• BeagleBone Black System Reference Manual (SRM): tiny.cc/beagle104
• Assumption is that everyone has access to the hardware by now,
• Beaglebone Black with USB cable
5

Hardware Platforms for Coursework
Embedded Design Space
• In lieu of textbook, you need to purchase two embedded platforms plus some
accessories to create systems of the following type
Atmega328P (baremetal)
Embedded
Device
Beaglebone Black (Linux OS)
Gateway
Embedded
Device
Wearable
Device
Implantable
Device
Mobile
PC
29
6
8-bit
32-bit
• Processes 8 bits of data at any given
time i.e. 8 bits per register
• Processes 32 bits of logic, registers, and bus
width
• 2^8 integers
• Low processing speed; runs at few MHz
• Bare-metal programming
• Handle numbers to 2^32
• Superior processing speed; runs at 100s MHz
• May run an operating system
• Handle few peripherals such as analog,
timer, serial interfaces
• Applications: gather measurements of
analog signals, power e ciency, time
predictability
• Handle multiple peripherals such as ethernet,
USB, CAN bus
• Applications: FFT calculations, image
processing, high quality audio or video, and
edge computing applications
• Example devices are ATiny, ATmega,
MSP430, etc.
• Example devices are Cortex-M3, ARM7,
PXA27X, etc.
7
ffi

8-bit v/s 32-bit Microcontrollers
• OS is just a bunch of APIs (abstractions) for you to talk to hardware
• We can bypass the OS, and write rmware that directly talks to hardware
• Why bare-metal?
• For situations where resources are too constrained to run an OS (CPU cycles,
power, memory)
• Programming registers and memory for peripherals directly through libraries
but not through an OS
• Must become familiar with the hardware
• Why OS?
• For complex code management
• To leverage existing software mechanisms such as multithreading, scheduling,
networking stack
• Why do everything when OS can do it for you
8
fi

Baremetal versus OS based Programming
Linux Operating System

Linux OS
• Unix/Linux: an open source operating system that manages hardware resources
and provides an interface to the users for multi-tasking
• Linux Distributions include the Linux kernel and supporting system software and
libraries
• Examples: Fedora, Ubuntu, Debian
• prominent examples of free and open-source software collaboration
• 90% of all cloud infrastructure is powered by Linux including supercomputers
and cloud providers
• 74% of smartphones in the world are Linux-based
10
• Modular Design
• A monolithic kernel, which handles process control, networking, access to
the peripherals, and le systems.
• Device drivers are either integrated directly with the kernel, or added as modules
that are loaded while the system is running
• Userspace access via de ned system calls
• Open source software
fi
11
fi

Why Linux is popular?
Kernal: The computer programs that allocate the system resources and coordinate all the
details of the computer's internals functions is called the kernel
User
Mode
Applications
Bash
System
Components
Daemons & other OS speci c libraries
C standard
Library
socket(), fopen()..
Mozilla Firefox
…
System Call Interface
Kernel
Mode
Linux Kernel
Sceduling
Inter process
Memory
File
Network
Comuunication Management System
Hardware (CPU, Memory, Data storage)
12
fi

Linux Layers
Linux File System
• Previously, we were directly writing bits to registers
• Data saved on any storage medium looks like a stream of bits
• File system is an abstraction that allows OS/users to e ciently manage data stored on
the storage medium
• Usage:
• Organize les on storage medium
• E cient read and write to the storage medium
• Identi cation and search in the stored data
• Access Management
• Maintains integrity of the stored data
• Single abstraction to communicate with heterogeneous I/O
ffi
fi
fi
14
ffi

Why use File System
• File: a le is computer resource that contains user data e.g. text, images etc
• Directories, a directory is an abstraction that contains a set of les and directories
inside
• A le system is a hierarchical structure where, each directory contains a set of les and
directories.
• The directory at the top is referred to as parent directory while the directories inside
are known as sub-directories
• The directory at the top of this hierarchy is known as the root directory
fi
fi
fi
15
fi

File System Organization
• /bin is a place for most commonly used terminal commands, like ls, mount, rm, etc
• /boot contains les needed to start up the system, including the Linux kernel, a RAM disk image and
bootloader con guration les
• /dev contains all device les, which are not regular les but instead refer to various hardware devices on the
system, including hard drives
• /etc contains system-global con guration les, which a ect the system's behavior for all users
• /home home sweet home, this is the place for users' home directories
• /lib contains very important dynamic libraries and kernel modules
• /media is intended as a mount point for external devices, such as hard drives or removable media ( oppies,
CDs, DVDs)
• /mnt is also a place for mount points, but dedicated speci cally to "temporarily mounted" devices, such as
network lesystems
• /opt can be used to store additional software for your system, which is not handled by the package manager
• /proc is a virtual lesystem that provides a mechanism for kernel to send information to processes
• /root is the superuser's home directory, not in /home/, to allow for booting the system even if /home/ is not
fl
fi
ff
fi
fi
fi
fi
fi
fi
fi
fi
available
fi

File System - Examples
16
• /run is a tmpfs (temporary le system) available early in the boot process where ephemeral run-time data is
stored. Files under this directory are removed or truncated at the beginning of the boot process.
• (It deprecates various legacy locations such as /var/run, /var/lock, /lib/init/rw in otherwise non-ephemeral
directory trees as well as /dev/.* and /dev/shm which are not device les.)
• /sbin contains important administrative commands that should generally only be employed by the superuser.
• /srv can contain data directories of services such as HTTP (/srv/www/) or FTP.
• /sys is a virtual lesystem that can be accessed to set or obtain information about the kernel's view of the
system.
• /tmp is a place for temporary les used by applications.
• /usr contains the majority of user utilities and applications, and partly replicates the root directory structure,
containing for instance, among others, /usr/bin/ and /usr/lib.
• /var is dedicated to variable data, such as logs, databases, websites, and temporary spool (e-mail etc.) les
that persist from one boot to the next. A notable directory it contains is /var/log where system log les are kept
fi
fi
fi
fi
fi
17
fi

File System - Examples
• A le path speci es the location of a le in a le system hierarchy. File path is
composed of directory names starting with either current or root directory and ends
with the le name.
• Terminologies
• An absolute path name, pointing to a le:
> /usr/bin/test
• An absolute path name, but pointing to a directory instead of a regular le:
> /usr/bin/
• A relative path name, which will point to /usr/bin/test only if the current directory is bin
> bin/test
• A relative path name, which will point to /usr/bin/test if the current directory is any directory
in /usr/, for instance /usr/share/
>../bin/test
• A path name using the special shortcut ~, which refers to the current user's home directory:
> ~/Desktop/
fi
fi
fi
fi
fi
fi
18
fi

File System Paths
• We can navigate a le system using simple commands on a linux based system
• On a Linux terminal, the following command can be used to see the path of the current
directory: > pwd
• The les inside the current directory can be enlisted using the following command: > ls
• We can change the current directory using the following command: > cd ‘path/to/
directory’
• The argument to the command “cd” can either be an absolute path or path relative
to the working directory
• The above command when used with “..” switches to the parent of the current
directory
• On a linux system, symbol “..” when used as a path refers to the parent of the
current working directory while “.” refers to current working directory
fi
19
fi

File System - Navigation commands
• Shell: A command line program available
on unix/linux based OS that takes in user
commands, interprets them for the kernel
which subsequently executes the
command
• Shell refers to the command line tool
named “terminal” inside Ubuntu. It is also
sometimes referred to as “Bash”
• Two common commands that are used to
navigate linux operating system,
• ls: This command lists all the les and
subdirectories present inside the
current working directory
• cd: This command is used to change
the current working directory
fi

Shell - Terminal
20
• Linux is a multi-user and multi-tasking system, where each user has its own set of
resources e.g. les in our case.
• On linux, the access to les and directories are managed using a permission system
• This system associates with each directory/ le permissions metadata
• Access to a le/directory can fall into one of the following categories:
Permisison
Action
chmod
option
read
(view)
r or 4
write
(edit)
w or 2
execute
(execute)
x or 1
• Further, access to a le/directory can be managed for a single user, a group of users
or all users
fi
fi
fi
fi
21
fi

File System Permissions
• The permissions associated with a
le can be listed using the following
command: ls -l ‘path/to/directory/
le'
• Permissions can be changed
using the following command:
chmod {options} 'path/to/
directory/ le'
• Permissions can be understood
using the following table:
User
ls output
owner
-rwx--------
group
---- rwx---
other
---------rwx
22
fi
fi
fi

File System Permissions - commands

File System Permissions - chmod
23
Linux Environment Variables
• On Unix based systems, a set of variables known as Environment variables provide a
way to in uence the behavior of software on the system
• variable LANG determines the language used by the software programs
> echo $LANG
• variables can be enlisted using the command printenv in the terminal
> printenv
• Two types of variables,
• The ones which a ect the behavior of all programs running on the system known as
Environment variables
• The ones which a ect the behavior of current shell program and programs started by
the current shell are called shell variables
ff
ff
25
fl

Environment Variables
• Existing Environment variables can be set simply by using “=” sign
• > LANG=he_IL.UTF-8
• > echo $LANG
• A new environment variable can be de ned using a keyword export,
• For example, we can de ne a new variable “EDITOR” as follows:
• > EDITOR= gedit
• > export EDITOR
• > echo $EDITOR
• An environment variable can be deleted using the keyword “unset”
• > unset EDITOR
• These variables are local to the terminal hence called “shell variables”
• To make these variables “persist” across all programs, the environment variable should
be added to “/etc/environment”
> nano /etc/environment
fi
Add “EDITOR=nano” at the end of the file. Press “Ctrl+O”, then press “Ctrl+X”.
fi

Declaring Variables
26
• When you type any command on the command prompt, the shell has to locate the
command before it can be executed
• The PATH variable speci es the locations in which the shell should look for commands
• It is assigned the address of multiple directories separated by colon (:)
• > echo $PATH
• Some programs require adding their path to the environment before they can be
accessed from the terminal. For such programs path can be modi ed using keyword
export
• For changing it across the environment, the “PATH” variable can be modi ed in the le
“/etc/environment” by appending the directory address at the end of existing path
separated by colon(:)
fi
fi
fi
27
fi

PATH Variable
Shell Script
• Instead of running individual commands multiple times in a Terminal, a script can be
composed called Shell/Bash Script comprising multiple shell commands in a le
• This script is then executed inside the terminal using its lename
• The use of shell scripting o ers several advantages:
• Repetitive tasks can be automated using single shell script e.g. compilation of a
program
• Automate the projects using multiple tools
• Multiple steps of a project can be compressed into single shell script for ease of
sharing, which also hides unnecessary complexities from the users
• Create linux/unix based tools for projects
fi
fi
29
ff

Shell/Bash Scripts
• A very simple bash script which prints “Hello, world!” in the terminal
#!/bin/sh
echo 'Hello, world!'
• The rst line contains a string of characters “#!/bin/sh” it tells the kernel that le
contains shell script and must be the rst line in every le that contains shell script
• echo: this command takes the input string and prints it to the standard output
• To run this script,
• create a le test.sh and paste the above text in the le and save it
• Change le permission to executable (chmod u+x test.sh)
• Execute the script (./test.sh)
fi
fi
fi
fi
fi
fi
30
fi

Example
fi
fi
fi
fi

Examples - File/Directories/Branch (if, loop)
le1.sh
touch filename
#create a file
echo "Input text"
> filename
#write text to file
cat filename
#write text to the terminal
cat file > file2 #copy contents of file to file2
rm filename
#delete the file named filename
le2.sh
mkdir directory # create a new directory
rm -r directory # delete the directory with all it’s contents
le3.sh
if [[ -e readme.txt ]] ; then
echo 'The file "readme.txt" exists.'
else
echo 'The file "readme.txt" does not exist.'
fi
first statement checks if a file named “readme.txt” exists in the current folder
le4.sh
for i in {1..20} ; do
echo "$i"
done
The loop prints integers from 1 to 20 in the terminal output
31
MakeFile

Compilation
• The process of converting the source code into machine code
• Compilation process checks for errors e.g. syntax and link errors
• Automation tools are used to manage compilation process for large projects due to:
- Maintaining code standards
- Speed up the compilation process
- Allow for better documentation
- Facilitate code sharing
- Reduce compilation issues for users
• Two types of Automation tools,
• Integrated Development Environments
(IDE) e.g Atmel Studio
• Command Line Tools e.g. make
33
• make: A utility automatically determines which pieces of a large program need to be
recompiled, and issues commands to recompile them
• make le: a le that de nes tasks for make utility
• A simple make le consists of “rules” with the following shape:
target … : prerequisites …
recipe
…
…
• target: the name of a le that is generated by a program; examples of targets are executable or
object les. A target can also be the name of an action to carry out, such as ‘clean’
• prerequisites: le that is used as input to create the target. A target often depends on several
les
• recipe: an action that make carries out. A recipe may have more than one command, either on
the same line or each on its own line. Each recipe should always be preceded by “tab” character
fi
fi
fi
fi
fi
fi
34
fi

fi
Make
• Consider we have a project that includes following three les in a directory:
hellomake.c, hellofunc.c and hellomake.h
• On a linux distribution (this tutorial assumes a ubuntu installation), we can use the
following command to compile this code:
$ gcc -o hellomake hellomake.c hellofunc.c -I .
where:
•
•
•
gcc: an open source C/C++ compiler
-o: gcc ag that provides the name of output le
-I: gcc ag that provides path of header les
fi
fi
fi
fl
35
fl

C compiling
• To compile the same code using make utility, we place a le named “make le” in the
project directory including the following contents:
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I .
• The le uses one rule to manage the compilation process. Here,
• hellomake is the target
• hellomake.c, hellofunc.c are the prerequisites
• gcc compiler command is the recipe in this make le
fi
fi
fi
36
fi

Make - Usage
• We can also de ne variables in the make le. This allows for better code management:
CC=gcc
CFLAGS=-I .
hellomake: hellomake.c hellofunc.c
$(CC) -o hellomake hellomake.c hellofunc.c $(CFLAGS)
• This le contains two variables,
• CC is the compiler name gcc
• CFLAGS de nes the ags that will be included in the compilation command
• Note that the variables are references using round brackets preceded by $ sign. For
example the variable “CC” is referred using $(CC) in the recipe
• Both these variables CC and CFLAGS are special variables. They should only be used
to de ne compiler and compilation ags respectively
fi
fl
fl
fi
fi
fi
37
fi

Make - Variables
• So far, our make le only considers changes de ned inside the source les (with .c
extension). To include the header les (with .h extension in the compilation process), we
modify the make le as:
CC=gcc
CFLAGS=-I .
DEPS = hellomake.h
hellomake.o: hellomake.c $(DEPS)
$(CC) -c -o hellomake.o hellomake.c $(CFLAGS)
hellofunc.o: hellofunc.c $(DEPS)
$(CC) -c -o hellofunc.o hellofunc.c $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
• DEPS de nes the list of header les to be included in the project
• Now we have additional rules to compile each source le with hellomake.h as a
prerequisites, while the nal rule compiles the executable using object les
fi
38
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
(hellomake.o and hellofunc.o) generated using rst two rules
fi

Make - Header les
• Notice that in the previous make le, we had identical rules for both the source les. We
can merge the two rules into one using % symbol:
CC=gcc
CFLAGS=-I .
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o %.o %.c $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
• %.c tells make to use apply the rule to all les that end with “.c”
fi
fi
39
fi

Make - Usage
• After compilation the project is executed using the executable “hellomake”, while the
object les with extension “.o” are the intermediate products of the compilation
process. We can add an additional rule to remove such les:
CC=gcc
CFLAGS=-I .
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o %.o %.c $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
.PHONY: clean
clean:
rm -f hellomake.o hellofunc.o
fi
fi
fi
fi
fi
• clean is treated as a special rule in the make le used to delete les that are no
longer needed
• PHONY tells make le that directive clean should not be confused with a le named
clean
fi

Make - clean
40
Command Line Input/Outputs
• A program can be provided input in two ways:
• First using input arguments with the program executable. Using this method inputs can
only be provided at the start of the program execution. This is also referred to as
providing command line arguments
• A C program starts it’s execution with main() function, which is often declared with zero
input arguments as below:
int main() { /* ... */ }
• To receive command line arguments, the main() function declaration can be modi ed to
have two arguments as below:
int main(int argc, char **argv) { /
* ... */ }
• “argc” is an integer containing the total number of arguments provided
• “argv” is array of character pointers listing all the arguments
42
fi

C Program Inputs

C Program Inputs - Example 1
#include <stdio.h>
int main(int argc, char *argv[]) // to receive command line arguments
{
printf("\nReceived %d arguments from command line.\n", argc);
// printing command line arguments
for(int i=0; i<argc; i++){
printf("Argument number %d: %s\n", i, argv[i]);
}
}
43
• C programs can also receive inputs from inside the main() function, using the following
functions:
• scanf() to receive integers, oating point numbers and characters
•
int scanf(const char *format, …)
• gets() can be used to take input character array
•
int gets(const char *str)
• getchar() can be used to take input a single character
•
int getchar(int char)
44
fl

C Program Inputs - Example 2

C Program Inputs - Example 2
C Program Inputs - Example 2
#include <stdio.h>
int main( ) {
int int_value;
float float_value;
char char_value;
#include <stdio.h>
char str[100];
int main(
) { ");
printf("Enter
a string:
gets(str); int int_value;
printf("Received
string: %s\n", str);
float float_value;
char_value;
printf("Enterchar
a character:
");
char
str[100];
char_value = getchar();
printf("Received
Character:
%c\n",
printf("Enter
a string:
"); char_value);
gets(str);
printf("Waiting
for input (e.g. integer,float):");
printf("Received
string: %s\n", str);
// takes comma separated inputs
scanf("%d,%f",
&int_value,
&float_value,
printf("Enter
a character:
"); &char_value);
printf("Received
following
inputs: %d, %f\n", int_value, float_value);
char_value
= getchar();
printf("Received Character: %c\n", char_value);
}
printf("Waiting for input (e.g. integer,float):");
// takes comma separated inputs
scanf("%d,%f", &int_value, &float_value, &char_value);
printf("Received following inputs: %d, %f\n", int_value, float_value);
}
45
• Computer programs often need to write out content to the screen. This is the part of user
interaction, and is used to either display current program status and accomplish other
program objectives
• In C, there are multiple ways to write output to the terminal
• The rst one uses printf function. It is the most commonly used method to write output to
the terminal in C
•
int printf(const char *format, …)
• There are two other methods used to write output to the terminal in C programs:
• puts() can be used to output character array
•
int puts(const char *str)
• putchar() can be used to output a single character
•
int putchar(int char)
• Example codes in next slide demonstrates the use of the above functions
46
fi

C Program Outputs

C Program Outputs - Examples
#include <stdio.h>
int main( ) {
// print a string
printf("Hello World !\n");
#include <stdio.h>
int main( ) {
//print an integer
printf("Integer: %d\n", -50);
char str[100] = "Hello World";
//print a floating point number
printf("Integer, Floating Point Number: %d, %f\n", -50, 3.1428);
// printing a character array
puts(str);
//print a character
printf("Integer, Floating Point Number: %d, %f, %c\n", -50, 3.1428, 'z');
//printing character
putchar('!');
putchar('\n');
//print a string
printf("Integer, Floating Point Number: %d, %f, %c, %s\n", -50, 3.1428, 'z', "String");
}
}
47
• Opening and Closing les
• When working with les, you need to declare a pointer of type le
• FILE *fptr;
• fopen("E:\\cprogram\\newprogram.txt","w");
• fclose(fptr);
• Reading and Writing to les,
• fwrite(const void *content, size_t size, size_t nmemb, FILE *fptr)
• Use fprintf(), fscanf()
• These are le versions of printf and scanf, and expect a pointer to the structure FILE
• Write: fprintf(fptr,”%d",num)
• Read: fscanf(fptr,”%d", &num)
• More details at, https://www.programiz.com/c-programming/c-
le-input-output
fi
fi
fi
fi
fi
48
fi

C Program I/O - File Operations
Putting Everything Together
• In your working directory make a subdirectory ‘source’ to place your working
code:
• > mkdir source
• In this sub-directory, save the given code
in le named “led.c”
Command line Input
Linux File system
( le operations)
Command line Output
fi
50
fi

C Program - Code
• Back in the working directory, create the “Make le” and paste the given contents in it
CC=gcc
CFLAGS=-I.
test.o: source/led.c
$(CC) -c -o test.o source/led.c
test: test.o
$(CC) -o test test.o
.PHONY: clean
clean:
rm -f test.o
• Compile the code using make command with the target test
• > make test
• For cleaning up extra les,
• > make clean
fi
fi
51
fi

C Program - Compile (Make le)
• Important things to remember when you write your make le
• Name of your make le has to be: make le or Make le
• You can only have one make le per directory
• Anything that can be entered at the terminal can be in the make le
• Each command must be preceded by a TAB and is immediately followed
by a carriage return
fi
fi
fi
fi
fi
fi
52
fi

Make le rules

C Program - Execute
• Execute the program using the command
• > ./test
• The output would be as follows
• You will observe the LED blinking at the mentioned rate
53
• Setup your terminals speci c to your OS (Windows, MAC, Linux)
• Practice all these concepts/commands on your terminals
• Book: Read the following topic from Chapter3: Exploring Embedded Linux Systems,
• Introducing Embedded Linux
• Advantages Disadvantages of Embedded Linux
• Is Linux open source and free
• Kernel Space and User Space
• Managing Linux Systems
• System Administration - Linux FileSystem
• Filesystem Permissions
• Linux Commands
54
fi

Reading
Download