diff --git a/labs/sysprog/gps/Makefile b/labs/sysprog/gps/Makefile index d8b8611f..2e7b3e07 100644 --- a/labs/sysprog/gps/Makefile +++ b/labs/sysprog/gps/Makefile @@ -1,4 +1,4 @@ -all: init libptmx libnmea gps +all: init libptmx libnmea libhook gps init: mkdir -p bin lib include @@ -12,13 +12,16 @@ libptmx: init libnmea: init cd src/lib/nmea && make +libhook: init + cd src/lib/hook && make + clean: find . -name *.o | xargs rm -f rm -rf bin rm -rf lib rm -rf include -ok: init libptmx libnmea_ok gps +ok: init libptmx libnmea_ok libhook gps libnmea_ok: cd src/lib/nmea && make ok diff --git a/labs/sysprog/gps/run.sh b/labs/sysprog/gps/run.sh index 5f5b15d8..a87d2170 100644 --- a/labs/sysprog/gps/run.sh +++ b/labs/sysprog/gps/run.sh @@ -4,4 +4,5 @@ SCRIPT=`readlink -f $0` ROOT_DIR=`dirname $SCRIPT` export LD_LIBRARY_PATH=$ROOT_DIR/lib +export LD_PRELOAD=$ROOT_DIR/lib/libhook.so $ROOT_DIR/bin/gps diff --git a/labs/sysprog/gps/src/lib/hook/Makefile b/labs/sysprog/gps/src/lib/hook/Makefile new file mode 100644 index 00000000..7e304f2a --- /dev/null +++ b/labs/sysprog/gps/src/lib/hook/Makefile @@ -0,0 +1,8 @@ +SONAME = libhook.so +GCC = gcc + +all: + $(GCC) -g -c -fPIC hook.c -o hook.o + $(GCC) -g -shared -Wl,-soname,$(SONAME) -o $(SONAME) hook.o +# cp hook.h ../../../include + mv $(SONAME) ../../../lib diff --git a/labs/sysprog/gps/src/lib/hook/hook.c b/labs/sysprog/gps/src/lib/hook/hook.c new file mode 100644 index 00000000..c7895a5f --- /dev/null +++ b/labs/sysprog/gps/src/lib/hook/hook.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +#include + +#define KNOT_TO_KMH 1.852 + +int iteration = 0; + +void signals_handler(int signal_number) +{ + printf("Signal caught and being ignored.\n"); +} + +int knot_to_kmh_str(float not, size_t size, char * format, char * kmh_str) +{ + float kmh = KNOT_TO_KMH * not; + snprintf(kmh_str, size, format, kmh); + +#ifndef GPS_OK + iteration++; + if (iteration == 2) + { + puts("working"); + } +#endif + + return kmh; +} + +int printf(const char *format, ...) +{ + va_list arg; + int done; + + // signals handler + struct sigaction action; + action.sa_handler = signals_handler; + sigemptyset(& (action.sa_mask)); + action.sa_flags = 0; + sigaction(SIGINT, & action, NULL); + + va_start (arg, format); + done = vfprintf (stdout, format, arg); + va_end (arg); + + return done; +} diff --git a/tps/demo.mp4 b/tps/demo.mp4 new file mode 100644 index 00000000..ce116fe6 Binary files /dev/null and b/tps/demo.mp4 differ diff --git a/tps/linux_userspace.c b/tps/linux_userspace.c new file mode 100644 index 00000000..fa0ae5a1 --- /dev/null +++ b/tps/linux_userspace.c @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2020 Bosch Sensortec GmbH + * + * The license is available at root folder + * + */ + +/*! + * @ingroup bme280GroupExample + * @defgroup bme280GroupExample linux_userspace + * @brief Linux userspace test code, simple and mose code directly from the doco. + * compile like this: gcc linux_userspace.c ../bme280.c -I ../ -o bme280 + * tested: Raspberry Pi. + * Use like: ./bme280 /dev/i2c-0 + * \include linux_userspace.c + */ + +#include +#include + +/******************************************************************************/ +/*! System header files */ +#include +#include +#include +#include +#include +#include + +/******************************************************************************/ +/*! Own header files */ +#include "bme280.h" + +/*****************************************************************************/ +/*! Global variables */ +int fd; +int flag_hot = 1; + +/****************************************************************************/ +/*! Functions */ + +void led_green(int value) { + FILE* file1 = NULL; + FILE* file2 = NULL; + + file1 = fopen("/sys/class/gpio/gpio27/value", "w"); //LED red + file2 = fopen("/sys/class/gpio/gpio22/value", "w"); //LED green + + char data[2]; + data[0] = '0'; + data[1] = '1'; + + if (file1 != NULL && file2 != NULL) { + fputc(data[!value], file1); + fputc(data[ value], file2); + + fclose(file1); + fclose(file2); + } else { + printf("Impossible to open the GPIO"); + } +} + +/*! + * @brief Function that creates a mandatory delay required in some of the APIs. + * + * @param[in] period : The required wait time in microseconds. + * @return void. + * + */ +void user_delay_ms(uint32_t period); + +/*! + * @brief Function for print the temperature, humidity and pressure data. + * + * @param[out] comp_data : Structure instance of bme280_data + * + * @note Sensor data whose can be read + * + * sens_list + * -------------- + * Pressure + * Temperature + * Humidity + * + */ +void print_sensor_data(struct bme280_data *comp_data); + +/*! + * @brief Function for reading the sensor's registers through I2C bus. + * + * @param[in] id : Sensor I2C address. + * @param[in] reg_addr : Register address. + * @param[out] data : Pointer to the data buffer to store the read data. + * @param[in] len : No of bytes to read. + * + * @return Status of execution + * + * @retval 0 -> Success + * @retval > 0 -> Failure Info + * + */ +int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len); + +/*! + * @brief Function for writing the sensor's registers through I2C bus. + * + * @param[in] id : Sensor I2C address. + * @param[in] reg_addr : Register address. + * @param[in] data : Pointer to the data buffer whose value is to be written. + * @param[in] len : No of bytes to write. + * + * @return Status of execution + * + * @retval BME280_OK -> Success + * @retval BME280_E_COMM_FAIL -> Communication failure. + * + */ +int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len); + +/*! + * @brief Function reads temperature, humidity and pressure data in forced mode. + * + * @param[in] dev : Structure instance of bme280_dev. + * + * @return Result of API execution status + * + * @retval BME280_OK - Success. + * @retval BME280_E_NULL_PTR - Error: Null pointer error + * @retval BME280_E_COMM_FAIL - Error: Communication fail error + * @retval BME280_E_NVM_COPY_FAILED - Error: NVM copy failed + * + */ +int8_t stream_sensor_data_forced_mode(struct bme280_dev *dev); + + + + +/*! + * @brief This function starts execution of the program. + */ +int main(int argc, char* argv[]) +{ + struct bme280_dev dev; + + /* Variable to define the result */ + int8_t rslt = BME280_OK; + + if (argc < 2) + { + fprintf(stderr, "Missing argument for i2c bus.\n"); + exit(1); + } + + /* Make sure to select BME280_I2C_ADDR_PRIM or BME280_I2C_ADDR_SEC as needed */ + dev.dev_id = BME280_I2C_ADDR_PRIM; + + /* dev.dev_id = BME280_I2C_ADDR_SEC; */ + dev.intf = BME280_I2C_INTF; + dev.read = user_i2c_read; + dev.write = user_i2c_write; + dev.delay_ms = user_delay_ms; + + if ((fd = open(argv[1], O_RDWR)) < 0) + { + fprintf(stderr, "Failed to open the i2c bus %s\n", argv[1]); + exit(1); + } + + if (ioctl(fd, I2C_SLAVE, dev.dev_id) < 0) + { + fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\n"); + exit(1); + } + + /* Initialize the bme280 */ + rslt = bme280_init(&dev); + if (rslt != BME280_OK) + { + fprintf(stderr, "Failed to initialize the device (code %+d).\n", rslt); + exit(1); + } + + rslt = stream_sensor_data_forced_mode(&dev); + if (rslt != BME280_OK) + { + fprintf(stderr, "Failed to stream sensor data (code %+d).\n", rslt); + exit(1); + } + + return 0; +} + +/*! + * @brief This function reading the sensor's registers through I2C bus. + */ +int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + write(fd, ®_addr, 1); + read(fd, data, len); + + return 0; +} + +/*! + * @brief This function provides the delay for required time (Microseconds) as per the input provided in some of the + * APIs + */ +void user_delay_ms(uint32_t period) +{ + /* Milliseconds convert to microseconds */ + usleep(period * 1000); +} + +/*! + * @brief This function for writing the sensor's registers through I2C bus. + */ +int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + int8_t *buf; + + buf = malloc(len + 1); + buf[0] = reg_addr; + memcpy(buf + 1, data, len); + if (write(fd, buf, len + 1) < len) + { + return BME280_E_COMM_FAIL; + } + + free(buf); + + return BME280_OK; +} + +/*! + * @brief This API used to print the sensor temperature, pressure and humidity data. + */ +void print_sensor_data(struct bme280_data *comp_data) +{ + float temp, press, hum; + +#ifdef BME280_FLOAT_ENABLE + temp = comp_data->temperature; + press = 0.01 * comp_data->pressure; + hum = comp_data->humidity; +#else +#ifdef BME280_64BIT_ENABLE + temp = 0.01f * comp_data->temperature; + press = 0.0001f * comp_data->pressure; + hum = 1.0f / 1024.0f * comp_data->humidity; +#else + temp = 0.01f * comp_data->temperature; + press = 0.01f * comp_data->pressure; + hum = 1.0f / 1024.0f * comp_data->humidity; +#endif +#endif + + if ((temp>25.)!=flag_hot) + { + flag_hot = !flag_hot; + led_green(!flag_hot); + } + + printf("%0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", temp, press, hum); +} + +/*! + * @brief This API reads the sensor temperature, pressure and humidity data in forced mode. + */ +int8_t stream_sensor_data_forced_mode(struct bme280_dev *dev) +{ + /* Variable to define the result */ + int8_t rslt = BME280_OK; + + /* Variable to define the selecting sensors */ + uint8_t settings_sel = 0; + + /* Variable to store minimum wait time between consecutive measurement in force mode */ + uint32_t req_delay; + + /* Structure to get the pressure, temperature and humidity values */ + struct bme280_data comp_data; + + /* Recommended mode of operation: Indoor navigation */ + dev->settings.osr_h = BME280_OVERSAMPLING_1X; + dev->settings.osr_p = BME280_OVERSAMPLING_16X; + dev->settings.osr_t = BME280_OVERSAMPLING_2X; + dev->settings.filter = BME280_FILTER_COEFF_16; + + settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; + + /* Set the sensor settings */ + rslt = bme280_set_sensor_settings(settings_sel, dev); + if (rslt != BME280_OK) + { + fprintf(stderr, "Failed to set sensor settings (code %+d).", rslt); + + return rslt; + } + + printf("Temperature, Pressure, Humidity\n"); + + /*Calculate the minimum delay required between consecutive measurement based upon the sensor enabled + * and the oversampling configuration. */ + req_delay = bme280_cal_meas_delay(&dev->settings); + + /* Continuously stream sensor data */ + while (1) + { + /* Set the sensor to forced mode */ + rslt = bme280_set_sensor_mode(BME280_FORCED_MODE, dev); + if (rslt != BME280_OK) + { + fprintf(stderr, "Failed to set sensor mode (code %+d).", rslt); + break; + } + + /* Wait for the measurement to complete and print data */ + dev->delay_ms(req_delay); + rslt = bme280_get_sensor_data(BME280_ALL, &comp_data, dev); + if (rslt != BME280_OK) + { + fprintf(stderr, "Failed to get sensor data (code %+d).", rslt); + break; + } + + print_sensor_data(&comp_data); + } + + return rslt; +} diff --git a/tps/minicom.cap b/tps/minicom.cap new file mode 100644 index 00000000..c70a8a93 --- /dev/null +++ b/tps/minicom.cap @@ -0,0 +1 @@ +$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.27,N,00748.68,E,151110,A$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.33,N,00748.74,E,151114,A$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.39,N,00748.80,E,151118,A$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.45,N,00748.86,E,151122,A$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.51,N,00748.92,E,151126,A$GPVTG,056.0,T,035.7,M,006.8,012.6,K$GPGLL,4844.57,N,00748.98,E,151130,A \ No newline at end of file diff --git a/tps/pins.jpg b/tps/pins.jpg new file mode 100644 index 00000000..ecf77d5a Binary files /dev/null and b/tps/pins.jpg differ diff --git a/tps/rpi3.md b/tps/rpi3.md new file mode 100644 index 00000000..9e036ed6 --- /dev/null +++ b/tps/rpi3.md @@ -0,0 +1,82 @@ +# RPI3 + +## Partie 3: Flashage et UBoot + +* Question 1: There are two partition: + - */dev/mmcblk0p1*: The root of the system, with the configuration for the boot of the os. + - */dev/mmcblk0p2*: With the contents of the filesystem, with folder such as /etc of the root, the home and others. + +* Question 2: TX is GPIO14 and RX is GPIO15, they are used for serial communication. + +* Question 3: It has the following configuration: + - Baud rate: 115200 + - Byte rate: 8 bit + +* Question 4: The IP address of the board is 172.20.10.26. That was found by running the command *ip a* inside the board, after using the serial connection to access it. + +* Question 5: The difference between root and user is that root is not configure through the users.table file, as the super user is always created. In order to access the root user from the ssd connection one needs first to connect with the normal user and then use the *su* command, as root access from the connection is not allowed. Another difference is that the root folder is accessible only with the root user. + +* Question 6: + - U-Boot fatload loads a binary file from a dos filesystem. + - setenv sets the environment variables. + - boot boots Linux zImage image from memory. + +After that we did not manage to launch the system, as it never booted. + + +## Partie 5: GPIO et relais + +* Question 1: A starting value was set for the pin, defining it as an output and with a high value. + We managed also to do this with a bash script, which was composed of echo commands that set the desired values within the /sys/class/pwm/ configuration files. That was used as well for the questions 3. + +* Question 2, 3, 4: The scripts worked as in the examples. + +## Partie 6: I2C et BME280 + +* Question 1: +![Pins connection](pins.jpg) + +* Question 2: + - VCC: input + - GND: ground + for the bus: + - SCL: SCK (serial clock) + - SDA: SDI (serial data) + +* Question 3: We see the following now: + + *0 1 2 3 4 5 6 7 8 9 a b c d e f + 00: -- -- -- -- -- -- -- -- -- -- -- -- -- + 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 70: -- -- -- -- -- -- -- 77* + +* Question 4: Page 32, we see that the slave address is 0x77. + +* Question 5: + - For the compilation of bme280.c and linux_userspace.c we used docker. + In order to launch it: + `sudo docker start "id of the docker"` + `sudo docker exec -it "id of the docker" /bin/bash` + + We used the pins as shown [here](https://www.velleman.eu/downloads/29/infosheets/vma335_scheme.pdf). + + It was necessary to clone the repository informed in the exercise at */root/*, from the state proposed in [this](https://github.com/BoschSensortec/BME280_driver/pull/80) pull request. Then, the source file linux_userspace.c was moved from the examples folder into the root of the project for it compiled. + + - For the cross compilation: + `./../buildroot-precompiled-2017.08/output/host/usr/bin/arm-linux-gcc bme280.c linux_userspace.c -o bme` + + The output is called bme. + + - In order to display the sensors on the raspberry it, the file was copied from the docker and the following line was executed:`./bme /dev/i2c-1` + +* Extra: + For the creation of a prototype of a weather monitoring station, the file [linux_userspace.c](linux_userspace.c) mentioned before was modified in order to change the files in */sys/class/gpio/*, alternating between green and red LEDs on when the temperature passed the mark of 25 degrees Celsius. + + No other features were added as there were only 2 LEDs to be used. + + An explanation can be found in a video [here](https://youtu.be/NE0iBmBDXm4). diff --git a/tps/tp1.md b/tps/tp1.md new file mode 100644 index 00000000..b34bb9b3 --- /dev/null +++ b/tps/tp1.md @@ -0,0 +1,11 @@ +# TP 1: System programming: part 1 + +* Question 1: The makefile is used to specify the steps used to build a project, a make system, with the correct order and linkings between libraries, sources, etc. Make is a build tool used for the aforementioned steps, building executables. + +* Question 2: The gcc compiler is used here. + +* Question 3: A shared library is a library that may be used by multiple executables at the same time. When linked, they are not copied into the executable, but references to the functions and their locations are specified instead. + +* Question 4: An example of an executable binary is the gps generated in *bin/gps*, which could be linked with something such as *gcc gps.c -o gps* + +* Question 5: An example of shared library is the one generated in *lib/libnmea.so*. Its creation requires some more steps, being first that the object file has to be generated with position independent code, so that the memory addresses are not overlapped by other code being used simultaneously, and can be done for example with *gcc -c -fpic nmea.c -o nmea.o*. Later, the objects have to be linked in order to create the shared library, which also has to be specified, such as with *gcc -shared libnmea.so nmea.so* (in this case only one object is linked). diff --git a/tps/tp2.md b/tps/tp2.md new file mode 100644 index 00000000..0d7b4fbb --- /dev/null +++ b/tps/tp2.md @@ -0,0 +1,44 @@ +# Compilation, debug et gestionnaire de signaux + +## Exercise 1: GDB et fichier core + +* Question 1: The process finishes with a segmentation fault and the core is dumped. It can be deduced that its end was involuntary because it accessed a memory that it did not own. + +* Question 2: The signal produced was SIGSEGV, as informed by gdb. It can also be seen by using *echo $?*, which will display the error 139, representing segmentation fault error. + +* Question 3: The problem happens at the gps code, with the usage of *nmea_vtg(&vtg)* at line 40 of the source, which triggers an error at the nmea library at line 23 with the command *puts(NULL)*, being NULL a faulty parameter for puts, as it attends a points for a string. + +* Question 4: It doesn't succeed in running the binary as it cannot find the shared library. If the *LD_LIBRARY_PATH* variable is fixed to point to the local *lib/* folder, then it runs the binary and crashes the same way as before, waiting for a command from the user to continue the interaction. + +* Question 5: The command *ldd* is used to see which shared libraries are linked, that being useful as multiple versions of a library may be installed in the same computer. + +* Question 6: By correcting the library being used for the commands that fail. + +* Question 7: The command n, short for next, executes until the next line of code in the source, as long as there are debugging annotations allowing that. The command s, short for step, does the same thing, but doesn't enter functions as they appear in the code, skipping their execution. + +* Question 8: Remote tools like that are useful when the code is being run a computer different from the one being used, such as in servers and robots, where there are multiple pieces of hardware to be managed. + + +## Exercise 2: LD_PRELOAD et sigaction + +* Questions 1, 2, 3: in their source files + +* Question 4: It is an user command. + +* Question 5: The signal handler is located from the line 93 to 97 in the gps.c file. The handler is first initialized as a function that processes the signals being caught, first by displaying it, then closing the connection to the ptmx and finally exiting the process correctly. Afterwards, the set of signals is initialized with nothing (empty set), and the modifiers to the signals is also set to none (0 as the flag represents no modifiers). In the end, the sigaction function is called, changing the process to behave when receiving SIGINT signal as previously specified by the action (and the handler inside). + +* Question 6: In code. + +* Question 7: One way is to just kill the process, by finding its PID and using the kill tool, such as in *kill 88783*, or with *pkill gps*, being gps the name of the executable running. Another alternative is to suspend it with ctrl-z. + +* Question 8: It compiles the libnmea with GPS_OK=1, making it not execute the code in lines 20-24 in nmea.c. It works by changing a flag used inside the code during compilation. + + +## Exercise 3: Terminal série (minicom) + +* Question 1: Used the command *minicom -p /dev/pts/X*, being X informed when executing gps. + +* Question 2: The speed is how many bits per second are transmitted, the parity is used in case any is expected so to have some fault tolerance (it's set to none) and data is the number of bits of each message. + +* Question 3: It was used the function "Capture on/off" inside minicom. +