// // Created by nano on 4/26/25. // #include "communication.h" #include #include #include struct sp_port *port; struct sp_event_set *event_data_ready; struct sp_event_set *event_ready_for_tx; /** * Initializes the serial communication for the usb -> uart board */ void comm_init_communication() { struct sp_port **port_list; comm_get_port_list(&port_list); int portnr = 0; comm_list_serial_ports(port_list); printf("Chose a port: "); scanf("%d", &portnr); sp_copy_port(port_list[portnr], &port); sp_free_port_list(port_list); comm_open_port(); } void comm_get_port_list(struct sp_port ***port_list) { enum sp_return result = sp_list_ports(port_list); if (result != SP_OK) { printf("Error listing serial ports\n"); exit(-1); } } void comm_list_serial_ports(struct sp_port **port_list) { printf("Port list:\n"); for (int i = 0; port_list[i] != NULL; i++) { char *port_name = sp_get_port_name(port_list[i]); printf("Port %d: %s\n", i, port_name); } } /** * 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. */ void comm_open_port() { check(sp_open(port, SP_MODE_READ_WRITE)); check(sp_set_baudrate(port, 9600)); 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_data_ready)); check(sp_new_event_set(&event_ready_for_tx)); sp_add_port_events(event_data_ready, port, SP_EVENT_RX_READY); sp_add_port_events(event_ready_for_tx, port, SP_EVENT_TX_READY); } /** * Ends the serial communication for the usb -> uart board */ void comm_end_communication() { check(sp_close(port)); sp_free_port(port); } /** * Wait till there is data available. * @param timeout how much time in ms to wait for the data * @returns SP_OK if data is ready. * @returns SP_ERR_FAIL if data was not available before timeout ended. */ int comm_await_data_ready(int timeout) { // Await data from the robot return sp_wait(event_data_ready, timeout); } /** * Wait till you can transmit again . * @param timeout how much time in ms to wait for the data * @returns SP_OK if data is ready. * @returns SP_ERR_FAIL if uart module wasnt ready for transmit before timeout ended. */ int comm_await_ready_for_tx(int timeout) { return sp_wait(event_ready_for_tx, timeout); } /** * Read a number of bytes from the buffer, store them in data without blocking the process. * @param data array where to store the data * @param amount_of_bytes * @return ALL_BYTES if the number of expected bytes was read * @return NOT_ENOUGH_BYTES if read less than expected * @return ERROR if read fails */ comm_result comm_nonblocking_read(byte *data, int amount_of_bytes) { //read available data int recv_bytes = sp_nonblocking_read(port, data, amount_of_bytes); if (recv_bytes == amount_of_bytes) { return ALL_BYTES; } if (recv_bytes >= 0) { return NOT_ENOUGH_BYTES; } return ERROR; } /** * Read a number of bytes from the buffer, store them in data, with a number of ms to wait in case that amount of data is not available.. * @param data array where to store the data * @param amount_of_bytes * @param timeout how much time in ms to wait for all data to be available. * @return ALL_BYTES if the number of expected bytes was read * @return NOT_ENOUGH_BYTES if read less than expected * @return ERROR if read fails */ comm_result comm_blocking_read(byte *data, int amount_of_bytes, int timeout) { //read available data int recv_bytes = sp_blocking_read(port, data, amount_of_bytes, timeout); printf("RECV: %d\n",*data); if (recv_bytes == amount_of_bytes) { return ALL_BYTES; } if (recv_bytes >= 0) { return NOT_ENOUGH_BYTES; } return ERROR; } /** * Write a number of bytes to the buffer, from data, with a number of ms to wait in case that amount of data is not available.. * @param data array where to store the data * @param amount_of_bytes * @param timeout how much time in ms to wait for all data to be available. * @return ALL_BYTES if the number of expected bytes was read * @return NOT_ENOUGH_BYTES if read less than expected * @return ERROR if read fails */ comm_result comm_blocking_write(byte *data, int amount_of_bytes, int timeout) { // 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 int sent_bytes = sp_blocking_write(port, data, amount_of_bytes, timeout); printf("SEND: %d \n",*data); if (sent_bytes == amount_of_bytes) { return ALL_BYTES; } if (sent_bytes >= 0) { return NOT_ENOUGH_BYTES; } return ERROR; } /** * Write a number of bytes to the buffer, from data. * @param data array where to store the data * @param amount_of_bytes * @return ALL_BYTES if the number of expected bytes was read * @return NOT_ENOUGH_BYTES if read less than expected * @return ERROR if read fails */ comm_result comm_nonblocking_write(byte *data, int amount_of_bytes) { // 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 int sent_bytes = sp_nonblocking_write(port, data, amount_of_bytes); if (sent_bytes == amount_of_bytes) { return ALL_BYTES; } if (sent_bytes >= 0) { return NOT_ENOUGH_BYTES; } return ERROR; } //Check if bytes are left to be sent int comm_output_waiting() { return sp_output_waiting(port); } /** 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(). */ char *error_message; switch (result) { case SP_ERR_ARG: printf("Error: Invalid argument.\n"); abort(); case SP_ERR_FAIL: error_message = sp_last_error_message(); printf("Error: Failed: %s\n", error_message); sp_free_error_message(error_message); abort(); case SP_ERR_SUPP: printf("Error: Not supported.\n"); abort(); case SP_ERR_MEM: printf("Error: Couldn't allocate memory.\n"); abort(); case SP_OK: default: return result; } }