some refactoring, a little more code and a bit of documentation

This commit is contained in:
Nicholas Stănescu 2025-04-26 22:52:42 +02:00 committed by Nanokloon
parent d2c73c9fb1
commit dbca9b0d10
7 changed files with 293 additions and 55 deletions

View File

@ -6,6 +6,8 @@ include_directories(.)
add_executable(serial
communication.c
communication.h
utils.c
utils.h
main.c)
target_link_libraries(serial serialport)

View File

@ -8,9 +8,10 @@
#include <stdlib.h>
#include <string.h>
struct sp_port ** port_list;
struct sp_port * port;
struct sp_event_set *event_set;
void comm_init_communication() {
/*
@ -21,29 +22,39 @@ void comm_init_communication() {
comm_list_serial_ports(port_list);
printf("Chose a port: ");
scanf("%d",&portnr);
port=port_list[portnr];
sp_copy_port(port_list[portnr], &port);
sp_free_port_list(port_list);
comm_open_port(port);
}
void comm_end_communication(struct sp_port *port) {
/*
* Ends the serial communication for the usb -> uart board
*/
check(sp_close(port));
sp_free_port_list(port_list);
sp_free_port(port);
//sp_free_port_list(port_list);
}
int comm_write(byte data) {
int comm_await() {
// Await data from the robot
return (sp_wait(event_set, 50) == SP_OK);
}
int comm_read_byte(byte *data) {
//read available data
//TODO: IMPLEMENT
return 0;
}
int comm_write_byte(byte data) {
// we are writing 8 bit bytes to the fpga anyways and pc -> fpga only needs to tell what do to next, can be fit in 8 bits
//TODO: IMPLEMENT
return 0;
}
int comm_await() {
// Await data from the robot
//TODO: IMPLEMENT
return 0;
}
struct sp_port **comm_get_port_list() {
struct sp_port **port_list;
@ -66,15 +77,19 @@ void comm_list_serial_ports(struct sp_port **port_list) {
void comm_open_port(struct sp_port *port) {
/*
* Opens communication to the selected serial port and sets the correct parameters for the zigbee carrier board.
* Also add event to see when data arrives.
*/
check(sp_open(port,SP_MODE_READ_WRITE));
check(sp_set_baudrate(port,19200));
check(sp_set_bits(port,8));
check(sp_set_parity(port,SP_PARITY_NONE));
check(sp_set_stopbits(port,1));
check(sp_new_event_set(&event_set));
sp_add_port_events(event_set, port, SP_EVENT_RX_READY);
}
/* Helper function for error handling. Taken from libserialport examples */
/** Helper function for error handling. Taken from libserialport examples */
int check(enum sp_return result)
{
/* For this example we'll just exit on any error by calling abort(). */
@ -100,19 +115,3 @@ int check(enum sp_return result)
return result;
}
}
void uint8_to_bit_array(byte bit_array[], byte data) {
for (int i = 0; i < 8; i++) {
bit_array[i] = (data >> i) & 1;
}
}
byte bit_array_to_uint8(byte bit_array[]) {
byte data=0;
byte currentpow=1;
for (int i = 0; i < 8; i++) {
data+=bit_array[i]*currentpow;
currentpow*=2;
}
return data;
}

View File

@ -9,10 +9,13 @@
typedef u_int8_t byte;
/**
* Initializes the serial communication for the usb -> uart board
*/
void comm_init_communication();
/**
* Initializes the serial communication for the usb -> uart board
* Ends the serial communication for the usb -> uart board
*/
void comm_end_communication(struct sp_port *port);
@ -20,10 +23,16 @@ struct sp_port **comm_get_port_list();
void comm_list_serial_ports(struct sp_port **port_list);
/**
* Opens communication to the selected serial port and sets the correct parameters for the zigbee carrier board.
*/
void comm_open_port(struct sp_port *port);
int comm_await();
int check(enum sp_return result);
void uint8_to_bit_array(byte *bit_array, byte data);
byte bit_array_to_uint8(const byte bit_array[]);
#endif //COMMS_H

199
docs/readme.md Normal file
View File

@ -0,0 +1,199 @@
# Serial Communication Module Documentation
## Overview
This module provides serial communication functionality using `libserialport` to interface with USB/UART devices. It
handles port enumeration, configuration, and basic I/O operations.
---
## Data Structures
### `sp_port`
`struct sp_port`
Represents a serial port (opaque type from libserialport).
### `sp_port_list`
`struct sp_port **`
Linked list of available serial ports.
### `sp_event_set`
`struct sp_event_set *`
Event monitoring structure for asynchronous I/O.
---
## Core Functions
### Initialization & Cleanup
```c
void comm_init_communication()
```
- **Purpose**: Initialize serial communication
- **Workflow**:
1. Lists available ports
2. Prompts user for port selection
3. Configures port parameters (19200 baud, 8N1)
4. Sets up RX event monitoring
- **Note**: Must be called first
```c
void comm_end_communication(struct sp_port *port)
```
- **Purpose**: Clean up communication resources
- **Parameters**:
- `port`: Active port to close
- **Effects**:
- Closes port connection
- Releases port memory
---
### Port Management
```c
struct sp_port **comm_get_port_list()
```
- **Returns**: Linked list of available serial ports
- **Failure**: Exits program on error
```c
void comm_list_serial_ports(struct sp_port **port_list)
```
- **Purpose**: Display available ports
- **Output Format**:
Port 0: /dev/ttyUSB0
Port 1: /dev/ttyACM0
```c
void comm_open_port(struct sp_port *port)
```
- **Purpose**: Configure port parameters
- **Settings Applied**:
- Baudrate: 19200
- Data Bits: 8
- Parity: None
- Stop Bits: 1
- Event: RX Ready monitoring
---
### I/O Operations
```c
int comm_await()
```
- **Purpose**: Check for incoming data
- **Returns**:
- `1`: Data available
- `0`: No data/timeout
- **Timeout**: 50ms
```c
int comm_read_byte(byte *data)
```
- **Purpose**: Read single byte (UNIMPLEMENTED)
- **TODO**: Implement actual read logic
- **Returns**: Placeholder (0)
```c
int comm_write_byte(byte data)
```
- **Purpose**: Write single byte (UNIMPLEMENTED)
- **TODO**: Implement actual write logic
- **Returns**: Placeholder (0)
---
## Helper Function
```c
int check(enum sp_return result)
```
- **Error Handling**: Converts libserialport error codes to human-readable messages
- **Failure Modes**:
- Invalid arguments
- Operation failure
- Unsupported features
- Memory allocation errors
- **Behavior**: Aborts program on error
---
## Usage Example
```c
int main() {
comm_init_communication();
while(1) {
if(comm_await()) {
byte data;
if(comm_read_byte(&data)) {
// Process data
}
}
// comm_write_byte(0x55);
}
comm_end_communication(port);
return 0;
}
```
---
## Dependencies
- **libserialport**: Required for low-level serial operations
- **stdio.h**: For I/O operations
- **stdlib.h**: For memory management
---
## Error Handling
The module uses aggressive error handling through the `check()` helper:
- **Critical Errors**: Program termination via `abort()`
- **Error Types**:
- Invalid arguments
- Hardware failures
- Unsupported operations
- Memory issues
---
## Implementation Notes
1. **Port Selection**: Current implementation uses console input
2. **Baudrate**: Fixed at 19200 (modify in `comm_open_port()`)
3. **Thread Safety**: Not thread-safe in current implementation
4. **Event Handling**: Only monitors RX events currently
---
## TODO List
- [ ] Implement `comm_read_byte()`
- [ ] Implement `comm_write_byte()`
- [ ] Add timeout configuration
- [ ] Add error recovery logic
- [ ] Implement thread-safe operations
---

45
main.c
View File

@ -4,39 +4,32 @@
#include <stdio.h>
#include <stdlib.h>
#include "utils.h"
#include "communication.h"
extern struct sp_port *port;
int main(int argc, char *argv[]) {
comm_init_communication();
byte data = 205;
int size = 1;
printf("size: %d\n", size);
unsigned int timeout = 50 * size; //50 ms timeout per byte
check(sp_nonblocking_write(port, &data, size));
byte *buf = malloc(size + 1);
int result = check(sp_blocking_read(port, buf, size, timeout));
if (result == size) {
printf("Received the same amount of bytes back \n");
while (1) {
if (comm_await()) {
byte *buffer = malloc(sizeof(byte));
if (sp_nonblocking_read(port, buffer, 1) == 1) {
byte *bits = malloc(sizeof(byte) * 8);
byte_to_bit_array(bits, *buffer);
printf("Data received: ");
for (int i = 7; i; i--) {
printf("%d", bits[i]);
}
printf("\n");
free(buffer);
if (bits[7] == 1) {
free(bits);
break;
}
}
}
}
buf[result] = '\0';
printf("%s\n", buf);
byte bits[8];
uint8_to_bit_array(bits, buf);
for (int i = 0; i < 8; i++) {
printf("%d ", bits[i]);
}
byte reconv_data = bit_array_to_uint8(bits);
printf("data: %d\n", reconv_data);
printf("\n");
comm_end_communication(port);
return 0;
}

23
utils.c Normal file
View File

@ -0,0 +1,23 @@
//
// Created by nano on 4/26/25.
//
#include "utils.h"
#include "communication.h"
// Helper functions to convert from bits to bytes
void byte_to_bit_array(byte bit_array[], byte data) {
for (int i = 0; i < 8; i++) {
bit_array[i] = (data >> i) & 1; //shift through all bits and check if they're 1
}
}
void bit_array_to_byte(byte bit_array[], byte *data) {
*data=0;
u_int8_t currentpow=1;
for (int i = 0; i < 8; i++) {
data+=bit_array[i]*currentpow;
currentpow*=2;
} //2's complement notation
}

13
utils.h Normal file
View File

@ -0,0 +1,13 @@
//
// Created by nano on 4/26/25.
//
#include <stdlib.h>
#ifndef UTILS_H
#define UTILS_H
typedef u_int8_t byte;
void byte_to_bit_array(byte *bit_array, byte data);
void bit_array_to_byte(byte bit_array[], byte *data);
#endif //UTILS_H