Update project files and headers: ensure consistency and maintainability across the codebase.
This commit is contained in:
@@ -54,3 +54,5 @@ dkms.conf
|
||||
output/
|
||||
.vscode/
|
||||
|
||||
lighttam_journal
|
||||
TestList.csv
|
||||
Vendored
+3
-1
@@ -20,7 +20,9 @@
|
||||
"initializer_list": "c",
|
||||
"ranges": "c",
|
||||
"span": "c",
|
||||
"valarray": "c"
|
||||
"valarray": "c",
|
||||
"logger.h": "c",
|
||||
"stdint.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "enabled"
|
||||
}
|
||||
@@ -1,3 +1,97 @@
|
||||
# LightTAM
|
||||
LightTAM (Lightweight Time And Attendance Manager) is a free (as in freedom) and open-source, simple tool for managing the attendance of employees or students using RFID cards and readers. LightTAM consists of a server that manages the user database and an RFID card reader that users use to log in and out of the system. The reader's firmware and documentation are located in a [separate repository](https://git.edcs.cz/eduard.dlabal/LightTAM_RFID_Reader).
|
||||
|
||||
Zavernecna prace pro vyuku programovani na SPSE Jecna
|
||||
## Download and Start
|
||||
You can download a pre-built binary file for Linux from the Releases menu, or you can build it from source yourself. For testing functionality on your system, I recommend downloading the test user list from the Releases menu.
|
||||
You will need permission to access the serial port (most likely /dev/ttyUSB0) on your Linux system. On Fedora/RHEL or Ubuntu, you can obtain these permissions by typing the following command in your terminal and then rebooting your system:
|
||||
```bash
|
||||
sudo usermod -a -G dialout <your username>
|
||||
```
|
||||
## Usage
|
||||
|
||||
To start the program, run it with a single argument specifying the path to the user database file:
|
||||
|
||||
```bash
|
||||
./output/main <user list>
|
||||
```
|
||||
|
||||
### Main Menu
|
||||
|
||||
After launching, you will see the main administration menu with the following options:
|
||||
|
||||
1. **List all employees**
|
||||
Shows a list of all users in the database. Use the arrow keys to navigate, <kbd>Enter</kbd> to select a user for more details, and <kbd>q</kbd> or <kbd>Esc</kbd> to return.
|
||||
|
||||
2. **Find employee**
|
||||
Allows you to search for a user by name and surname. Enter the search term and navigate the results as above.
|
||||
|
||||
3. **Edit database**
|
||||
Lets you add, remove, or log a time event for a user:
|
||||
- **Add person to database**: Fill in the name, surname, and department to add a new user.
|
||||
- **Remove person from database**: Enter the UUID of the user to remove.
|
||||
- **Back**: Return to the main menu.
|
||||
|
||||
4. **Save**
|
||||
Saves the current state of the user database to the specified file.
|
||||
|
||||
5. **Export**
|
||||
Allows you to export the current database to a new file. Enter the desired filename and confirm.
|
||||
|
||||
6. **Exit**
|
||||
Closes the program.
|
||||
|
||||
### User Details
|
||||
|
||||
When viewing a user's details, you can:
|
||||
- **Print to file**: Export the user's information to a text file.
|
||||
- **Add Time Event**: Manually log a new time event for the user.
|
||||
- **Back**: Return to the previous menu.
|
||||
|
||||
### Keyboard Shortcuts
|
||||
|
||||
- <kbd>Tab</kbd>: Move between buttons and menu items.
|
||||
- <kbd>Arrow keys</kbd>: Navigate lists and menus.
|
||||
- <kbd>Enter</kbd>: Confirm selection or action.
|
||||
- <kbd>q</kbd> or <kbd>Esc</kbd>: Go back or exit the current menu.
|
||||
|
||||
### RFID Usage
|
||||
|
||||
When the RFID reader is connected and ready, users can log their attendance by simply placing their RFID card on the reader. The system will automatically record the event and update the database.
|
||||
|
||||
### Notes
|
||||
|
||||
- Make sure you have the necessary permissions to access the serial port for the RFID reader.
|
||||
- All actions and errors are logged in the `lighttam_journal` file for troubleshooting and auditing.
|
||||
|
||||
|
||||
## Build from Source
|
||||
|
||||
To build LightTAM from source, you need a Linux system with `gcc`, `make`, and the development headers for `ncurses` and `pthread`.
|
||||
|
||||
1. **Install dependencies** (example for Debian/Ubuntu):
|
||||
```bash
|
||||
sudo apt-get install build-essential libncurses5-dev libncursesw5-dev
|
||||
```
|
||||
|
||||
2. **Clone the repository** (if you haven't already):
|
||||
```bash
|
||||
git clone https://git.edcs.cz/eduard.dlabal/LightTAM
|
||||
cd LightTAM
|
||||
```
|
||||
|
||||
3. **Build the project**:
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
4. The compiled binary will be located in the `output/` directory as `main`.
|
||||
|
||||
5. **Run the program**:
|
||||
```bash
|
||||
./output/main <user list>
|
||||
```
|
||||
|
||||
If you encounter any errors during compilation, make sure all dependencies are installed and you are running the commands from the project root directory.
|
||||
|
||||
## Detailed documataton
|
||||
You can find more detailed information about LightTAM in [docs folder](docs) .
|
||||
+2
-2
@@ -28,5 +28,5 @@
|
||||
30,Marketa,Rezacova,3039,1,0,0
|
||||
31,Libor,Hanak,3040,1747561377,0,1
|
||||
32,Libor,Hanak,3040,1,0,0
|
||||
17767,Grzegorz,Brzeczyszczykiewicz,2502,1747576503,0,1
|
||||
9158,Tomas,Zima,2440,1747573483,12084,1
|
||||
17767,Grzegorz,Brzeczyszczykiewicz,2502,1747596887,18675,1
|
||||
9158,Tomas,Zima,2440,1747596873,33787,1
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @brief Provizorni modul pro praci se seznamy uzivatelu. Priprava pro implementaci uziti PostgreSQL
|
||||
* @brief Temporary modul for user list handling.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+10
-6
@@ -1,21 +1,25 @@
|
||||
#ifndef __LOGGER_H__
|
||||
#define __LOGGER_H__
|
||||
|
||||
#include "main.h"
|
||||
#include "rfid_handler.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
typedef struct Logger
|
||||
{
|
||||
pthread_mutex_t lock;
|
||||
FILE *f_log;
|
||||
} Logger;
|
||||
|
||||
extern Logger *logger_global;
|
||||
|
||||
Logger *initLogger(const char *_filename);
|
||||
int logErrorEvent(Logger *_logger, const char *_message);
|
||||
int logWarningEvent(Logger *_logger, const char *_message);
|
||||
int logHardwareEvent(Logger *_logger, const char *_event_origin, const char *_message);
|
||||
int logInfoEvent(Logger *_logger, const char *_message);
|
||||
int logErrorEvent(Logger *_logger, const char *_fmt, ...);
|
||||
int logWarningEvent(Logger *_logger, const char *_fmt, ...);
|
||||
int logHardwareEvent(Logger *_logger, const char *_event_origin, const char *_fmt, ...);
|
||||
int logInfoEvent(Logger *_logger, const char *_fmt, ...);
|
||||
int endLogger(Logger *_logger);
|
||||
|
||||
#endif
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
|
||||
#ifndef __MAIN_H__
|
||||
#define __MAIN_H__
|
||||
|
||||
@@ -20,10 +20,37 @@ typedef struct
|
||||
} UartThreadArgs;
|
||||
|
||||
// UART handler thread
|
||||
/**
|
||||
* @brief Thread function to listen for UART data.
|
||||
*
|
||||
* This function is intended to be run as a separate thread. It continuously listens
|
||||
* for incoming data on a UART interface and processes the received data accordingly.
|
||||
*
|
||||
* @param arg Pointer to arguments required by the UART listener (typically a struct with UART configuration).
|
||||
* @return void* Returns NULL upon thread completion.
|
||||
*/
|
||||
void *uartListener(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Parses an incoming RFID packet.
|
||||
*
|
||||
* This function processes the provided packet and extracts relevant information.
|
||||
*
|
||||
* @param _packet Pointer to the incoming packet data (array of BYTE).
|
||||
* @return uint16_t Parsed value.
|
||||
*/
|
||||
uint16_t parseIncommingPacket(BYTE *_packet);
|
||||
|
||||
/**
|
||||
* @brief Sends a data packet to a device over the specified UART interface.
|
||||
*
|
||||
* This function constructs and transmits a packet containing information about a person (node)
|
||||
* and a specified state to a device connected via UART.
|
||||
*
|
||||
* @param _uart The UART interface identifier to use for transmission.
|
||||
* @param _person Pointer to a node_t structure representing the person whose data is to be sent.
|
||||
* @param state The state value to include in the packet.
|
||||
*/
|
||||
void sendPacketToDevice(int _uart, node_t *_person, BYTE state);
|
||||
|
||||
#endif
|
||||
|
||||
+115
-1
@@ -15,27 +15,141 @@
|
||||
#define WARNING_WIN_COLOUR 8
|
||||
#define SUCCESS_WIN_COLOUR 9
|
||||
|
||||
/**
|
||||
* @brief Initializes a window with specified parameters and displays a header.
|
||||
*
|
||||
* @param _win Pointer to the WINDOW object to initialize.
|
||||
* @param window_x The width of the window.
|
||||
* @param terminal_x The x-coordinate position of the window in the terminal.
|
||||
* @param terminal_y The y-coordinate position of the window in the terminal.
|
||||
* @param window_colourpair The color pair attribute to use for the window.
|
||||
* @param header The header text to display at the top of the window.
|
||||
*/
|
||||
void initWindow(WINDOW *_win, int window_x, int terminal_x, int terminal_y, int window_colourpair, char *header);
|
||||
|
||||
// type = 1 - success, 2 - warning, 3 - failure
|
||||
/**
|
||||
* @brief Displays a dialog window with a message in the terminal.
|
||||
*
|
||||
* @param _type Type of dialog: 1 for success, 2 for warning, 3 for failure.
|
||||
* @param _message The message to display in the dialog window.
|
||||
* @param terminal_x The x-coordinate of the terminal where the dialog should appear.
|
||||
* @param terminal_y The y-coordinate of the terminal where the dialog should appear.
|
||||
*/
|
||||
void dialogWindow(BYTE _type, char *_message, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Opens a UART dialog interface at the specified terminal coordinates.
|
||||
*
|
||||
* This function initializes and displays a UART dialog using the provided UART address,
|
||||
* and positions the dialog at the specified (terminal_x, terminal_y) coordinates on the terminal.
|
||||
*
|
||||
* @param uart_adress Pointer to a string containing the UART address.
|
||||
* @param terminal_x X-coordinate for the dialog position in the terminal.
|
||||
* @param terminal_y Y-coordinate for the dialog position in the terminal.
|
||||
*/
|
||||
void uartDialog(char *uart_adress, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays and manages the main menu of the application.
|
||||
*
|
||||
* This function presents the main menu interface to the user, allowing interaction
|
||||
* with the list of persons and database file. It handles user input and updates
|
||||
* the application state accordingly.
|
||||
*
|
||||
* @param person_list Pointer to the list of persons to be managed.
|
||||
* @param db_filename Path to the database file used for storing person data.
|
||||
* @param terminal_x Width of the terminal window.
|
||||
* @param terminal_y Height of the terminal window.
|
||||
*/
|
||||
void mainMenu(list_t *person_list, char *db_filename, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays a list of persons in a terminal user interface.
|
||||
*
|
||||
* This function renders the provided list of persons within the terminal window,
|
||||
* using the specified terminal dimensions.
|
||||
*
|
||||
* @param person_list Pointer to a list_t structure containing person entries to display.
|
||||
* @param terminal_x The width of the terminal window in characters.
|
||||
* @param terminal_y The height of the terminal window in characters.
|
||||
*/
|
||||
void personListing(list_t *person_list, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Searches for a person in the given list and displays results in a terminal UI.
|
||||
*
|
||||
* This function allows the user to search for a person within the provided person_list.
|
||||
* The search interface is rendered within a terminal window of the specified dimensions.
|
||||
*
|
||||
* @param person_list Pointer to the list of persons to search.
|
||||
* @param terminal_x Width of the terminal window.
|
||||
* @param terminal_y Height of the terminal window.
|
||||
*/
|
||||
void personSearch(list_t *person_list, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays information about a person in a terminal user interface.
|
||||
*
|
||||
* This function presents the details of a person, represented by the node_t pointer,
|
||||
* within a list structure, at the specified terminal coordinates.
|
||||
*
|
||||
* @param _list Pointer to the list containing person nodes.
|
||||
* @param _person Pointer to the specific person node whose information will be displayed.
|
||||
* @param terminal_x X-coordinate in the terminal where the information should be shown.
|
||||
* @param terminal_y Y-coordinate in the terminal where the information should be shown.
|
||||
*/
|
||||
void personInfo(list_t *_list, node_t *_person, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays an export dialog in the terminal user interface.
|
||||
*
|
||||
* This function presents an export dialog to the user, allowing them to select
|
||||
* items from the provided list for export. The dialog is rendered at the specified
|
||||
* terminal coordinates.
|
||||
*
|
||||
* @param _list Pointer to a list_t structure containing items to display.
|
||||
* @param terminal_x The x-coordinate (column) for the dialog's position in the terminal.
|
||||
* @param terminal_y The y-coordinate (row) for the dialog's position in the terminal.
|
||||
* @return An integer status code indicating the result of the dialog operation.
|
||||
*/
|
||||
int exportDialog(list_t *_list, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays and manages the Edit Database menu in the terminal UI.
|
||||
*
|
||||
* This function presents the user with options to edit entries in the provided person list,
|
||||
* handling user input and updating the list as necessary. The menu is rendered according to
|
||||
* the specified terminal dimensions.
|
||||
*
|
||||
* @param _person_list Pointer to the list of persons to be edited.
|
||||
* @param terminal_x Width of the terminal window.
|
||||
* @param terminal_y Height of the terminal window.
|
||||
*/
|
||||
void editDatabaseMenu(list_t *_person_list, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays a dialog to add a new person to the provided list.
|
||||
*
|
||||
* This function opens a terminal-based dialog interface that allows the user
|
||||
* to input information for a new person. The new person is then added to the
|
||||
* specified person list.
|
||||
*
|
||||
* @param _person_list Pointer to the list where the new person will be added.
|
||||
* @param terminal_x The width of the terminal window (in characters).
|
||||
* @param terminal_y The height of the terminal window (in characters).
|
||||
*/
|
||||
void addPersonDialog(list_t *_person_list, int terminal_x, int terminal_y);
|
||||
|
||||
/**
|
||||
* @brief Displays a dialog to delete a person from the given list.
|
||||
*
|
||||
* This function presents a user interface dialog at the specified terminal coordinates,
|
||||
* allowing the user to select and delete a person from the provided list.
|
||||
*
|
||||
* @param _person_list Pointer to the list of persons to be managed.
|
||||
* @param terminal_x X-coordinate for the dialog's position in the terminal.
|
||||
* @param terminal_y Y-coordinate for the dialog's position in the terminal.
|
||||
*/
|
||||
void deletePersonDialog(list_t *_person_list, int terminal_x, int terminal_y);
|
||||
|
||||
#endif
|
||||
+76
-85
@@ -1,129 +1,120 @@
|
||||
/**
|
||||
* @file users.h
|
||||
* @brief User list management for LightTAM.
|
||||
*
|
||||
* Contains structures and functions for working with the user linked list,
|
||||
* including synchronization using a mutex.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#ifndef __USERS_H__
|
||||
#define __USERS_H__
|
||||
|
||||
/**
|
||||
* @struct person
|
||||
* @brief Structure representing a single user.
|
||||
*/
|
||||
typedef struct person
|
||||
{
|
||||
uint16_t uuid;
|
||||
|
||||
char *name;
|
||||
char *surname;
|
||||
uint32_t department;
|
||||
|
||||
time_t last_time_event;
|
||||
time_t total;
|
||||
|
||||
BYTE available;
|
||||
uint16_t uuid; ///< Unique user identifier
|
||||
char *name; ///< First name
|
||||
char *surname; ///< Last name
|
||||
uint32_t department; ///< Department number
|
||||
time_t last_time_event; ///< Last event timestamp
|
||||
time_t total; ///< Total presence time
|
||||
BYTE available; ///< Presence state (TRUE/FALSE)
|
||||
} person_t;
|
||||
|
||||
/**
|
||||
* @struct node
|
||||
* @brief Node of the user linked list.
|
||||
*/
|
||||
typedef struct node
|
||||
{
|
||||
person_t user;
|
||||
struct node *next;
|
||||
person_t user; ///< User data
|
||||
struct node *next; ///< Pointer to the next node
|
||||
} node_t;
|
||||
|
||||
/**
|
||||
* @struct list
|
||||
* @brief User linked list with a mutex for synchronization.
|
||||
*/
|
||||
typedef struct list
|
||||
{
|
||||
node_t *head;
|
||||
pthread_mutex_t lock;
|
||||
|
||||
node_t *head; ///< List head
|
||||
pthread_mutex_t lock; ///< Mutex for access synchronization
|
||||
} list_t;
|
||||
|
||||
/**
|
||||
* @brief Generates a unique identifier (UUID) for a new node in the linked list.
|
||||
*
|
||||
* This function traverses the linked list starting from the given head node
|
||||
* and generates a unique 16-bit unsigned integer identifier that does not
|
||||
* conflict with any existing UUIDs in the list.
|
||||
*
|
||||
* @param _head Pointer to the head node of the linked list.
|
||||
* @return A 16-bit unsigned integer representing the generated UUID.
|
||||
* @brief Generate a unique UUID not used in the list.
|
||||
* @param _list Pointer to the user list
|
||||
* @return New UUID
|
||||
*/
|
||||
uint16_t generateUUID(list_t *_list);
|
||||
|
||||
/**
|
||||
* @brief Searches for a UUID associated with a user by their name and surname.
|
||||
*
|
||||
* This function traverses a linked list of nodes to find a user whose name
|
||||
* and surname match the provided parameters. If a match is found, it returns
|
||||
* a pointer to the UUID associated with that user.
|
||||
*
|
||||
* @param _head Pointer to the head of the linked list.
|
||||
* @param _name Pointer to a string containing the user's first name.
|
||||
* @param _surname Pointer to a string containing the user's surname.
|
||||
* @return Pointer to the UUID of the user if found, or 0 if no match is found.
|
||||
* @brief Find all UUIDs by name and surname.
|
||||
* @param _list Pointer to the user list
|
||||
* @param _name First name
|
||||
* @param _surname Last name
|
||||
* @param _uuids_found Pointer to an array of found UUIDs (allocated inside the function)
|
||||
* @return Number of found UUIDs
|
||||
*/
|
||||
uint16_t searchUUIDByName(list_t *_list, char *_name, char *_surname, uint16_t **_uuids_found);
|
||||
|
||||
/**
|
||||
* @brief Searches for a person in a linked list by their UUID.
|
||||
*
|
||||
* This function traverses a linked list starting from the given head node
|
||||
* and searches for a node that matches the specified UUID.
|
||||
*
|
||||
* @param _head Pointer to the head node of the linked list.
|
||||
* @param _uuid The UUID of the person to search for.
|
||||
* @return Pointer to the node containing the person with the matching UUID,
|
||||
* or NULL if no such person is found.
|
||||
* @brief Find a user by UUID.
|
||||
* @param _list Pointer to the user list
|
||||
* @param _uuid Searched UUID
|
||||
* @return Pointer to the found node, or NULL if not found
|
||||
*/
|
||||
node_t *searchPersonByUUID(list_t *_list, uint16_t _uuid);
|
||||
|
||||
/**
|
||||
* @brief Adds a new person to the linked list.
|
||||
*
|
||||
* This function creates a new person and appends it to the end of the linked list.
|
||||
* It dynamically allocates memory for the new person and initializes their details.
|
||||
* If memory allocation fails or the input parameters are invalid, the function returns an error.
|
||||
*
|
||||
* @param _head Pointer to the head of the linked list (node_t **).
|
||||
* @param _name Pointer to a string containing the person's first name.
|
||||
* @param _surname Pointer to a string containing the person's last name.
|
||||
* @param _department The department number to which the person belongs.
|
||||
*
|
||||
* @return int Returns 1 if the person was successfully added, otherwise 0 on failure.
|
||||
*
|
||||
* @note Memory for the name and surname is dynamically allocated. It is the caller's
|
||||
* responsibility to free the memory for the entire list to avoid memory leaks.
|
||||
*
|
||||
* @example
|
||||
* ```c
|
||||
* node_t *head = NULL;
|
||||
* if (addPersonToList(&head, "John", "Doe", 101)) {
|
||||
* printf("Person successfully added.\n");
|
||||
* } else {
|
||||
* printf("Error adding person.\n");
|
||||
* }
|
||||
* ```
|
||||
* @brief Add a new user to the list.
|
||||
* @param _list Pointer to the user list
|
||||
* @param _name First name
|
||||
* @param _surname Last name
|
||||
* @param _department Department
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
int addPersonToList(list_t *_list, char *_name, char *_surname, uint32_t _department);
|
||||
|
||||
/**
|
||||
* @brief Load a user into the list (e.g. when loading from file).
|
||||
* @param _list Pointer to the user list
|
||||
* @param _uuid UUID
|
||||
* @param _name First name
|
||||
* @param _surname Last name
|
||||
* @param _department Department
|
||||
* @param _last_event Last event time
|
||||
* @param _total Total time
|
||||
* @param _available Presence state
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname, uint32_t _department, time_t _last_event, time_t _total, BYTE _available);
|
||||
|
||||
/**
|
||||
* @brief Adds a time event to the specified person's event list.
|
||||
*
|
||||
* This function associates a time-based event with the given person node.
|
||||
*
|
||||
* @param _person A pointer to the node_t structure representing the person
|
||||
* to whom the time event will be added.
|
||||
*
|
||||
* @return An integer indicating the success or failure of the operation.
|
||||
* Typically, 1 for success and a 0 for failure.
|
||||
* @brief Add a time event for a user (arrival/departure).
|
||||
* @param _person Pointer to the user node
|
||||
* @param _list Pointer to the user list
|
||||
* @return Event type (1 = arrival, 2 = departure)
|
||||
*/
|
||||
int addTimeEvent(node_t *_person, list_t *_list);
|
||||
|
||||
/**
|
||||
* @brief Removes a person node from a linked list.
|
||||
*
|
||||
* This function removes the node pointed to by _person from the linked list
|
||||
* whose head is pointed to by _head. Both parameters are double pointers to
|
||||
* allow modification of the head pointer and the node pointer.
|
||||
*
|
||||
* @param _head Double pointer to the head of the linked list.
|
||||
* @param _person Double pointer to the node representing the person to remove.
|
||||
* @return int Returns 0 on success, or a negative value on failure.
|
||||
* @brief Remove a user from the list.
|
||||
* @param _list Pointer to the user list
|
||||
* @param _person Pointer to the pointer to the node to remove
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
int removePersonFromList(list_t *_list, node_t **_person);
|
||||
|
||||
/**
|
||||
* @brief Free the entire user list from memory.
|
||||
* @param _list Pointer to the pointer to the user list
|
||||
*/
|
||||
void freePersonList(list_t ** _list);
|
||||
|
||||
#endif
|
||||
+1
-4
@@ -28,8 +28,7 @@ int loadListFromCSV(char *_filename, list_t *_list)
|
||||
}
|
||||
else
|
||||
{
|
||||
// vstupni databaze je vadna
|
||||
// neco jako ja
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -57,8 +56,6 @@ int saveListToCSV(char *_filename, list_t *_list)
|
||||
cursor = cursor->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fclose(f_out);
|
||||
return save_sum;
|
||||
}
|
||||
|
||||
+43
-16
@@ -1,5 +1,7 @@
|
||||
#include "logger.h"
|
||||
|
||||
Logger *logger_global = NULL;
|
||||
|
||||
Logger *initLogger(const char *_filename)
|
||||
{
|
||||
Logger *logger_struct = malloc(sizeof(Logger));
|
||||
@@ -19,58 +21,83 @@ Logger *initLogger(const char *_filename)
|
||||
return logger_struct;
|
||||
}
|
||||
|
||||
int logErrorEvent(Logger *_logger, const char *_message)
|
||||
int logErrorEvent(Logger *_logger, const char *_fmt, ...)
|
||||
{
|
||||
if (_logger == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char current_time_str[32];
|
||||
printDateAndTimeInString(time(NULL), current_time_str);
|
||||
|
||||
fprintf(_logger->f_log, "%s [ERROR] %s", current_time_str, _message);
|
||||
fprintf(_logger->f_log, "%s [ERROR] ", current_time_str);
|
||||
|
||||
va_list args;
|
||||
va_start(args, _fmt);
|
||||
vfprintf(_logger->f_log, _fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(_logger->f_log, "\n");
|
||||
fflush(_logger->f_log);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int logWarningEvent(Logger *_logger, const char *_message)
|
||||
int logWarningEvent(Logger *_logger, const char *_fmt, ...)
|
||||
{
|
||||
if (_logger == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char current_time_str[32];
|
||||
printDateAndTimeInString(time(NULL), current_time_str);
|
||||
|
||||
fprintf(_logger->f_log, "%s [WARNING] %s", current_time_str, _message);
|
||||
fprintf(_logger->f_log, "%s [WARNING] ", current_time_str);
|
||||
|
||||
va_list args;
|
||||
va_start(args, _fmt);
|
||||
vfprintf(_logger->f_log, _fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(_logger->f_log, "\n");
|
||||
fflush(_logger->f_log);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int logHardwareEvent(Logger *_logger, const char *_event_origin, const char *_message)
|
||||
int logHardwareEvent(Logger *_logger, const char *_event_origin, const char *_fmt, ...)
|
||||
{
|
||||
if (_logger == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char current_time_str[32];
|
||||
printDateAndTimeInString(time(NULL), current_time_str);
|
||||
|
||||
fprintf(_logger->f_log, "%s [%s] %s", current_time_str, _event_origin, _message);
|
||||
fprintf(_logger->f_log, "%s [%s] ", current_time_str, _event_origin);
|
||||
|
||||
va_list args;
|
||||
va_start(args, _fmt);
|
||||
vfprintf(_logger->f_log, _fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(_logger->f_log, "\n");
|
||||
fflush(_logger->f_log);
|
||||
return 1;
|
||||
}
|
||||
int logInfoEvent(Logger *_logger, const char *_message)
|
||||
|
||||
int logInfoEvent(Logger *_logger, const char *_fmt, ...)
|
||||
{
|
||||
if (_logger == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char current_time_str[32];
|
||||
printDateAndTimeInString(time(NULL), current_time_str);
|
||||
|
||||
fprintf(_logger->f_log, "%s [INFO] %s", current_time_str, _message);
|
||||
fprintf(_logger->f_log, "%s [INFO] ", current_time_str);
|
||||
|
||||
va_list args;
|
||||
va_start(args, _fmt);
|
||||
vfprintf(_logger->f_log, _fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(_logger->f_log, "\n");
|
||||
fflush(_logger->f_log);
|
||||
return 1;
|
||||
}
|
||||
int endLogger(Logger *_logger)
|
||||
|
||||
+6
-8
@@ -17,6 +17,8 @@ int main(int argc, char const **argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
logger_global = initLogger("lighttam_journal");
|
||||
|
||||
int y_max, x_max;
|
||||
char uart_address[51];
|
||||
pthread_t uart_thread;
|
||||
@@ -28,18 +30,14 @@ int main(int argc, char const **argv)
|
||||
{
|
||||
endwin();
|
||||
clear();
|
||||
logErrorEvent(logger_global, "Terminal Window is too small");
|
||||
endLogger(logger_global);
|
||||
puts("Terminal is too small. Exiting...\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
node_t *person_list_head = (node_t *)malloc(sizeof(node_t));
|
||||
if (person_list_head == NULL)
|
||||
{
|
||||
endwin();
|
||||
clear();
|
||||
puts("Memory allocation error. Exiting...\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
node_t *person_list_head = NULL;
|
||||
|
||||
list_t person_list;
|
||||
person_list.head = person_list_head;
|
||||
pthread_mutex_init(&person_list.lock, NULL);
|
||||
|
||||
+16
-2
@@ -1,6 +1,7 @@
|
||||
#include "rfid_handler.h"
|
||||
#include "users.h"
|
||||
#include "main.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -24,7 +25,7 @@ void *uartListener(void *arg)
|
||||
int uart = open(uart_address, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (uart == -1)
|
||||
{
|
||||
// perror("Failed to open UART");
|
||||
logErrorEvent(logger_global, "UART open failed for %s: %s", uart_address, strerror(errno));
|
||||
flags->wait_for_UART_flag = FALSE;
|
||||
flags->uart_status = FALSE;
|
||||
return NULL;
|
||||
@@ -50,10 +51,12 @@ void *uartListener(void *arg)
|
||||
|
||||
if (tcsetattr(uart, TCSANOW, &options) != 0)
|
||||
{
|
||||
logErrorEvent(logger_global, "UART tcsetattr failed: %s", strerror(errno));
|
||||
flags->wait_for_UART_flag = FALSE;
|
||||
flags->uart_status = FALSE;
|
||||
return NULL;
|
||||
}
|
||||
logInfoEvent(logger_global, "UART %s opened and configured", uart_address);
|
||||
|
||||
flags->uart_status = TRUE;
|
||||
flags->wait_for_UART_flag = FALSE;
|
||||
@@ -71,6 +74,7 @@ void *uartListener(void *arg)
|
||||
{
|
||||
if (flags->end_from_main_flag)
|
||||
{
|
||||
logInfoEvent(logger_global, "UART thread received end signal, closing UART.");
|
||||
close(uart);
|
||||
return NULL;
|
||||
}
|
||||
@@ -85,6 +89,9 @@ void *uartListener(void *arg)
|
||||
continue;
|
||||
}
|
||||
perror("read");
|
||||
logErrorEvent(logger_global, "UART read error: %s", strerror(errno));
|
||||
clear();
|
||||
endwin();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (n == 0)
|
||||
@@ -129,15 +136,17 @@ void *uartListener(void *arg)
|
||||
|
||||
if (crc == packet[5])
|
||||
{
|
||||
logInfoEvent(logger_global, "Valid packet received from UART (CRC OK)");
|
||||
BYTE success;
|
||||
uint16_t r_uuid = parseIncommingPacket(packet);
|
||||
node_t *selected = searchPersonByUUID(person_list, r_uuid);
|
||||
success = addTimeEvent(selected, person_list);
|
||||
sendPacketToDevice(uart, selected, success);
|
||||
logInfoEvent(logger_global, "Processed RFID event for UUID: %u, success: %u", r_uuid, success);
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr, "Chyba CRC!\n");
|
||||
logWarningEvent(logger_global, "UART packet CRC error");
|
||||
sendPacketToDevice(uart, NULL, 0);
|
||||
}
|
||||
state = SYNC0;
|
||||
@@ -147,6 +156,8 @@ void *uartListener(void *arg)
|
||||
}
|
||||
|
||||
close(uart);
|
||||
logInfoEvent(logger_global, "UART %s closed", uart_address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -206,4 +217,7 @@ void sendPacketToDevice(int _uart, node_t *_person, BYTE state)
|
||||
offset += 1;
|
||||
|
||||
write(_uart, packet, offset);
|
||||
logInfoEvent(logger_global, "Sent packet to device (state=%u, name=%s, surname=%s)", state,
|
||||
_person && _person->user.name ? _person->user.name : "(none)",
|
||||
_person && _person->user.surname ? _person->user.surname : "(none)");
|
||||
}
|
||||
+63
@@ -1,5 +1,6 @@
|
||||
#include "users.h"
|
||||
#include "main.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -47,11 +48,16 @@ node_t *searchPersonByUUID(
|
||||
{
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Person found by UUID: %u", _uuid);
|
||||
|
||||
return current;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logWarningEvent(logger_global, "Person with UUID %u not found", _uuid);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -62,6 +68,8 @@ uint16_t searchUUIDByName(list_t *_list, char *_name, char *_surname, uint16_t *
|
||||
if (uuids == NULL)
|
||||
{
|
||||
*_uuids_found = NULL;
|
||||
logErrorEvent(logger_global, "Memory allocation failed in searchUUIDByName");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,6 +88,8 @@ uint16_t searchUUIDByName(list_t *_list, char *_name, char *_surname, uint16_t *
|
||||
{
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
free(uuids);
|
||||
logErrorEvent(logger_global, "Memory allocation failed in searchUUIDByName (realloc)");
|
||||
endLogger(logger_global);
|
||||
puts("Fatal error: free memory is not sufficient for this operation");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -92,6 +102,9 @@ uint16_t searchUUIDByName(list_t *_list, char *_name, char *_surname, uint16_t *
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
*_uuids_found = uuids;
|
||||
|
||||
logInfoEvent(logger_global, "Found %u UUID(s) for name: %s %s", sum, _name, _surname);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
@@ -103,12 +116,16 @@ int addPersonToList(
|
||||
{
|
||||
node_t *new_node = (node_t *)malloc(sizeof(node_t));
|
||||
if (new_node == NULL)
|
||||
{
|
||||
logErrorEvent(logger_global, "Memory allocation failed in addPersonToList");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strlen(_name) || !strlen(_surname))
|
||||
{
|
||||
free(new_node);
|
||||
new_node = NULL;
|
||||
logWarningEvent(logger_global, "Attempted to add person with empty name or surname");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,6 +138,7 @@ int addPersonToList(
|
||||
free(new_node->user.name);
|
||||
free(new_node->user.surname);
|
||||
free(new_node);
|
||||
logErrorEvent(logger_global, "Memory allocation failed for name/surname in addPersonToList");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -140,6 +158,8 @@ int addPersonToList(
|
||||
_list->head = new_node;
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Added person (UUID: %u) as head: %s %s", new_node->user.uuid, _name, _surname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -151,6 +171,8 @@ int addPersonToList(
|
||||
current->next = new_node;
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Added person (UUID: %u): %s %s", new_node->user.uuid, _name, _surname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -158,6 +180,7 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
{
|
||||
if (!strlen(_name) || !strlen(_surname))
|
||||
{
|
||||
logWarningEvent(logger_global, "Attempted to load person with empty name or surname");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -169,6 +192,7 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
if (_list->head == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
logErrorEvent(logger_global, "Memory allocation failed in loadPersonToList (head)");
|
||||
return 0;
|
||||
}
|
||||
_list->head->next = NULL;
|
||||
@@ -188,6 +212,7 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
free(target->user.name);
|
||||
free(target->user.surname);
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
logErrorEvent(logger_global, "Memory allocation failed for name/surname in loadPersonToList (head)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -198,6 +223,9 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
target->user.total = _total;
|
||||
target->user.available = _available;
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Loaded person as head (UUID: %u): %s %s", _uuid, _name, _surname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -205,6 +233,7 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
if (new_node == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
logErrorEvent(logger_global, "Memory allocation failed in loadPersonToList (new node)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,6 +247,7 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
free(new_node->user.surname);
|
||||
free(new_node);
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
logErrorEvent(logger_global, "Memory allocation failed for name/surname in loadPersonToList (new node)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -237,6 +267,9 @@ int loadPersonToList(list_t *_list, uint16_t _uuid, char *_name, char *_surname,
|
||||
}
|
||||
current->next = new_node;
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Loaded person (UUID: %u): %s %s", _uuid, _name, _surname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -249,6 +282,7 @@ int addTimeEvent(
|
||||
|
||||
if (_person == NULL)
|
||||
{
|
||||
logWarningEvent(logger_global, "addTimeEvent called with NULL person");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,13 +304,18 @@ int addTimeEvent(
|
||||
_person->user.last_time_event = current_time;
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logInfoEvent(logger_global, "Time event for UUID %u: type %u, time %ld", _person->user.uuid, type, current_time);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
int removePersonFromList(list_t *_list, node_t **_person)
|
||||
{
|
||||
if (_list == NULL || _list->head == NULL || _person == NULL || *_person == NULL)
|
||||
{
|
||||
logWarningEvent(logger_global, "removePersonFromList called with invalid arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_list->lock);
|
||||
node_t *current = _list->head;
|
||||
@@ -294,6 +333,7 @@ int removePersonFromList(list_t *_list, node_t **_person)
|
||||
{
|
||||
prev->next = current->next;
|
||||
}
|
||||
logInfoEvent(logger_global, "Removing person (UUID: %u): %s %s", current->user.uuid, current->user.name, current->user.surname);
|
||||
free(current->user.name);
|
||||
free(current->user.surname);
|
||||
free(current);
|
||||
@@ -305,5 +345,28 @@ int removePersonFromList(list_t *_list, node_t **_person)
|
||||
current = current->next;
|
||||
}
|
||||
pthread_mutex_unlock(&_list->lock);
|
||||
|
||||
logWarningEvent(logger_global, "Person to remove not found in list");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freePersonList(list_t ** _list){
|
||||
if (_list == NULL || *_list == NULL)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&(*_list)->lock);
|
||||
node_t *current = (*_list)->head;
|
||||
while (current != NULL)
|
||||
{
|
||||
node_t *next = current->next;
|
||||
free(current->user.name);
|
||||
free(current->user.surname);
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
(*_list)->head = NULL;
|
||||
pthread_mutex_unlock(&(*_list)->lock);
|
||||
free(*_list);
|
||||
*_list = NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user