diff --git a/examples/simple/main.c b/examples/simple/main.c index dcf169a..a1cae75 100644 --- a/examples/simple/main.c +++ b/examples/simple/main.c @@ -1,101 +1,107 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file main.c * * \date Oct 11, 2011 * \author Alexandre Tuleu */ #include <stdio.h> //for all bus transfer definition #include <sbcpd/sbcpd.h> //for SBCP definitions #include <sbcpd/sbcp.h> +//Motordriver class 0xea #define DEVICE_CLASS 0xea static uint16_t firmware_code; static int received_status; //a basic callback. Callback should be as simple as possible. Think them //as interrupt void my_simple_firmware_callback(sbcpd_transfer * t){ if(t->status){//if status != 0, there was an error. received_status = 2; return; } firmware_code = t->in_buffer[SBCP_PAYLOAD_START_POS + 1]; firmware_code += t->in_buffer[SBCP_PAYLOAD_START_POS] << 8; received_status = 1; } int main(int argc, char ** argv){ //first the program shouldinitialize as soon as possible the library - sbcpd_bus * bus = sbcpd_default_oncilla_init(0); + sbcpd_error err; + sbcpd_bus * bus = sbcpd_default_oncilla_init(0,&err); if(bus == NULL){ - fprintf(stderr,"Unable to initialize library.\n"); + fprintf(stderr,"Unable to initialize library : %s.\n",err.msg); return 1; } if(argc <= 1){ fprintf(stderr,"Need at least the id of the board to reach.\n"); return 2; } unsigned int id = atoi(argv[1]); if(id < 0 || id > 0xff){ fprintf(stderr,"Bad id #%d, should be between 0x00 and 0xff.\n",id); return 3; } //ask for a new transfer with a payload of 0 sbcpd_transfer * t = sbcpd_bus_append_transfer(bus,0); //fill the packet destination - t->out_buffer[SBCP_CLASS_POS] = DEVICE_CLASS; //Motordriver board. + t->out_buffer[SBCP_CLASS_POS] = DEVICE_CLASS; t->out_buffer[SBCP_ID_POS] = id; //fill the packet instruction t->out_buffer[SBCP_INSTRUCTION_POS] = 0x00; //ask for firmware version //don't need to fill, payload, there is none. received_status = 0; //static data to wait for completion. //submission will make sure that our packet is correct for the communication - //layer - sbcpd_bus_submit_all_transfer(bus); + //layer (header,payload value, checksum) + if(sbcpd_bus_submit_all_transfer(bus)){ + fprintf(stderr,"Unable to initiate transfer : %s",bus->error.msg); + return 5; + } //wait until completion. while(received_status == 0){ } + if(received_status == 2){ fprintf(stderr,"Got an error during transfer.\n"); return 4; } printf("Device 0x%x : 0x%x has a firmare value of : 0x%x.\n", DEVICE_CLASS, id, firmware_code); return 0; } diff --git a/sbcpd/bus.c b/sbcpd/bus.c index 7d58c34..2992c4b 100644 --- a/sbcpd/bus.c +++ b/sbcpd/bus.c @@ -1,471 +1,487 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file bus.c * * \date Aug 15, 2011 * \author Alexandre Tuleu */ #include <stdlib.h> #include <string.h> #ifndef NDEBUG #include <stdio.h> #endif #include "bus.h" #include <ftdi.h> #include "transfer.h" #include "sbcp.h" #include "error.h" sbcpd_bus * sbcpd_create_bus(const sbcpd_bus_settings settings){ sbcpd_bus * bus = malloc(sizeof(sbcpd_bus)); sbcpd_init_error(&bus->error,SBCPD_BUS_ERROR); bus->flags = SBCPD_BUS_VOID; *((unsigned int*)&bus->max_frame_packets) = 8; *((unsigned int*)&bus->max_packet_size) = 64; bus->si = NULL; bus->in_buffer = NULL; bus->out_buffer = NULL; bus->out_buffer_actual_size = 0; *((unsigned int *)&bus->buffers_size) = 0; bus->transfers = NULL; bus->transfers_size = 0; memcpy((void*)&(bus->settings),&settings,sizeof(sbcpd_bus_settings)); printf("Created a new sbcpd_bus object. \n"); return bus; } #define CHECK_IF_BUS_ALLOCATED if(!bus){\ SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_NOT_ALLOCATED,\ "You passed a NULL pointer !");\ } #define CHECK_IF_BUS_OPENED(m)if(!(bus->flags & SBCPD_BUS_OPEN)){\ SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_IS_NOT_OPEN,\ m);\ } int sbcpd_bus_open(sbcpd_bus * bus, sbcpd_serial_interface * interface){ CHECK_IF_BUS_ALLOCATED if (bus -> si || (bus->flags & SBCPD_BUS_OPEN)){ SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_ALREADY_OPEN, "Bus is already opened, you cannot open" " it twice !"); } bus->si = interface; ///\todo : Check for the master board, ask for frame size and ///max packet size. *((unsigned int*)&(bus->buffers_size)) = sizeof(uint8_t) * bus->max_frame_packets * bus->max_packet_size; bus->out_buffer = malloc(bus->buffers_size); bus->in_buffer = malloc(bus->buffers_size); bus->out_buffer_actual_size = 0; bus->transfers = malloc(sizeof(sbcpd_transfer) * bus->max_frame_packets); bus->transfers_size = 0; bus->flags |= SBCPD_BUS_OPEN; return SBCPD_NO_ERROR; } int sbcpd_bus_close(sbcpd_bus * bus){ CHECK_IF_BUS_ALLOCATED if(!(bus->flags & SBCPD_BUS_OPEN)){ SBCPD_RETURN_WITH_ERROR(bus, SBCPD_EBUS_IS_NOT_OPEN, "Bus is not opened, cannot close it"); } //unlink all pending transfer. if(bus->flags & SBCPD_BUS_BUSY){ sbcpd_bus_unlink_all_transfer(bus); } if(bus->si){ (*(bus->si->close))(bus->si); (*(bus->si->free))(bus->si); bus->si = NULL; } if(bus->out_buffer){ free(bus->out_buffer); } if(bus->in_buffer){ free(bus->in_buffer); } *((unsigned int*)&bus->buffers_size) = 0; bus->out_buffer_actual_size = 0; if(bus->transfers){ free(bus->transfers); } bus->transfers_size = 0; bus->flags &= ~SBCPD_BUS_OPEN; return SBCPD_NO_ERROR; } int sbcpd_free_bus(sbcpd_bus * bus){ CHECK_IF_BUS_ALLOCATED if(bus->flags & SBCPD_BUS_OPEN){ sbcpd_bus_close(bus); } free(bus); return SBCPD_NO_ERROR; } sbcpd_transfer * sbcpd_bus_append_transfer(sbcpd_bus * bus, unsigned int payload_size){ if(!bus){ SBCPD_RETURN_WITH_ERROR_AND_VALUE(bus, SBCPD_EBUS_NOT_ALLOCATED, "You passed a NULL pointer for a bus", NULL); } if(!(bus->flags & SBCPD_BUS_OPEN)){ SBCPD_RETURN_WITH_ERROR_AND_VALUE(bus, SBCPD_EBUS_IS_NOT_OPEN, "You should open the bus to make transfers.", NULL); } if((bus->flags & SBCPD_BUS_BUSY)){ SBCPD_RETURN_WITH_ERROR_AND_VALUE(bus, SBCPD_EBUS_IS_BUSY, "You cannot create new transfer while " "transfering, please wait for other transfer to " "finish", NULL); } //no slot available if(bus->transfers_size == bus->max_frame_packets){ SBCPD_RETURN_WITH_ERROR_AND_VALUE(bus, SBCPD_EBUS_BUS_RESSOUCE_ALREADY_TOOK, "Not enough packet available in the frame", NULL); } if(payload_size > bus->max_packet_size - SBCP_MINIMAL_SIZE){ SBCPD_RETURN_WITH_ERROR_AND_VALUE(bus, SBCPD_EBUS_BAD_TRANSFER_DEFINITION, "payload size should be between 0 and " "bus->max_packet_size - 6", NULL); } sbcpd_transfer * t = &(bus->transfers[bus->transfers_size]); ++bus->transfers_size; t->status = SBCPD_TRANSFER_UNSTARTED; t->callback = NULL; *((uint8_t **)&(t->out_buffer)) = &(bus->out_buffer[bus->out_buffer_actual_size]); *((unsigned int *)&t->out_size) = payload_size + SBCP_MINIMAL_SIZE; bus->out_buffer_actual_size += t->out_size; *((uint8_t**)&t->in_buffer) = NULL; *((unsigned int*)&t->in_size) = 0; return t; } void sbcpd_bus_unlink_last_transfer(sbcpd_bus *bus){ } int sbcpd_bus_remove_last_transfer(sbcpd_bus * bus){ CHECK_IF_BUS_ALLOCATED CHECK_IF_BUS_OPENED("Bus should be opened."); if(bus->transfers_size == 0){ SBCPD_RETURN_WITH_ERROR(bus, SBCPD_EBUS_TRANSFER_LIST_EMPTY, "Need at least one transfer to remove."); } if(bus->flags & SBCPD_BUS_BUSY){ sbcpd_bus_unlink_last_transfer(bus); } --bus->transfers_size; return SBCPD_NO_ERROR; } int sbcpd_bus_clear_all_transfers(sbcpd_bus * bus){ CHECK_IF_BUS_ALLOCATED CHECK_IF_BUS_OPENED("Bus should be opened."); if(bus->transfers_size == 0){ SBCPD_RETURN_WITH_ERROR(bus, SBCPD_EBUS_TRANSFER_LIST_EMPTY, "Need at least one transfer to remove."); } if(bus->flags & SBCPD_BUS_BUSY){ sbcpd_bus_unlink_all_transfer(bus); } bus->transfers_size = 0; return SBCPD_NO_ERROR; } int sbcpd_bus_read_needed_byte(sbcpd_bus * bus, unsigned int current_packet, unsigned int needed_bytes){ unsigned int maxTrials = bus->settings.max_trials; while( bus->received_bytes < bus->parsed_bytes + needed_bytes && maxTrials > 0){ - bus->received_bytes += + int readout = (*bus->si->read_data)(bus->si, &(bus->in_buffer[bus->received_bytes]), bus->buffers_size - bus->received_bytes); + + if(readout < 0){ + maxTrials = 0; + break; + } + + bus->received_bytes += readout; --maxTrials; } if(maxTrials == 0 && bus->received_bytes < bus->parsed_bytes + needed_bytes){ for(; current_packet < bus->transfers_size; ++current_packet){ bus->transfers[current_packet].com_error = SBCPD_CERR_IMCOMPLETE_READOUT; bus->transfers[current_packet].status = SBCPD_TRANSFER_HAS_COMMUNICATION_ERROR; } return 1; } return SBCPD_NO_ERROR; } uint8_t sbcpd_compute_checksum_of_packet(const uint8_t * data){ uint8_t cs = 0; unsigned int i = SBCP_CLASS_POS; uint8_t cs_pos = data[SBCP_PAYLOAD_SIZE_POS] + SBCP_PAYLOAD_START_POS; for(;i < cs_pos; ++i){ cs += data[i]; } return cs; } void sbcpd_transfer_parse_communication_errors(sbcpd_transfer * t){ if(t->in_size != 7){ t->com_error = SBCPD_CERR_BAD_CERR_PACKET; return; } switch(t->in_buffer[SBCP_PAYLOAD_START_POS]){ case SBCP_CERR_INCORRECT_CHECKSUM : if(t->in_buffer[SBCP_CLASS_POS] == SBCP_MASTER_CLASS){ t->com_error = SBCPD_CERR_HOST_BAD_CHECKSUM; } else { t->com_error = SBCPD_CERR_MASTER_BAD_CHECKSUM; } break; case SBCP_CERR_HOST_BUS_TIMEOUT : t->com_error = SBCPD_CERR_HOST_TIMEDOUT; break; case SBCP_CERR_SLAVE_BUS_TIMEOUT : if(t->in_buffer[SBCP_CLASS_POS] == SBCP_MASTER_CLASS){ t->com_error = SBCPD_CERR_SLAVE_TIMEOUT; }else{ t->com_error = SBCPD_CERR_MASTER_TIMEDOUT; } break; case SBCP_CERR_HOST_BUS_FRAME_ERROR : t->com_error = SBCPD_CERR_HOST_FRAME_ERROR; break; case SBCP_CERR_SLAVE_BUS_FRAME_ERROR : if(t->in_buffer[SBCP_CLASS_POS] == SBCP_MASTER_CLASS){ t->com_error = SBCPD_CERR_SLAVE_FRAME_ERROR; } else { t->com_error = SBCPD_CERR_MASTER_FRAME_ERROR; } break; case SBCP_CERR_UNKNOWN_INSTRUCTION : t->com_error = SBCPD_CERR_UNKNOWN_INSTRUCTION_ERROR; break; default : t->status = SBCPD_CERR_BAD_CERR_PACKET; break; } } void sbcpd_transfer_check_response(sbcpd_transfer * t){ uint8_t cs = sbcpd_compute_checksum_of_packet(t->in_buffer); if(cs != t->in_size - 1 ){ t->com_error = SBCPD_CERR_SLAVE_BAD_CHECKSUM; t->status = SBCPD_TRANSFER_HAS_COMMUNICATION_ERROR; return; } if(t->in_buffer[SBCP_INSTRUCTION_POS] != SBCP_COMMUNICATION_ERROR){ t->status = SBCPD_TRANSFER_OK; return; } if(t->in_buffer[SBCP_INSTRUCTION_POS] != SBCP_NO_ERROR){ t->status = SBCPD_TRANSFER_HAS_APPLICATION_ERROR; return; } t->status = SBCPD_TRANSFER_HAS_COMMUNICATION_ERROR; //we got an error to parse. sbcpd_transfer_parse_communication_errors(t); } void sbcpd_bus_get_response_packets(sbcpd_bus * bus){ bus->parsed_bytes = 0; bus->received_bytes = 0; unsigned int i; for(i = 0; i < bus->transfers_size; ++i){ //getting the data from interface do{ if(sbcpd_bus_read_needed_byte(bus,i,SBCP_HEADER_POS + 1)){ return; } }while(bus->in_buffer[bus->parsed_bytes] != SBCP_HEADER_VALUE && ++bus->parsed_bytes); if(sbcpd_bus_read_needed_byte(bus,i,SBCP_PAYLOAD_SIZE_POS + 1)){ return; } unsigned int packet_total_size = bus->in_buffer[bus->parsed_bytes + SBCP_PAYLOAD_SIZE_POS] + SBCP_MINIMAL_SIZE; if(packet_total_size > bus->max_packet_size){ bus->transfers[i].status = SBCPD_TRANSFER_HAS_COMMUNICATION_ERROR; bus->transfers[i].com_error = SBCPD_CERR_INCONSISTENT_RESPONSE_SIZE; //ignore the rest of the data, continue parsing bus->parsed_bytes += SBCP_PAYLOAD_SIZE_POS + 1; continue; } if(sbcpd_bus_read_needed_byte(bus,i,packet_total_size)){ return; } //data is received, noy check the incoming packet sbcpd_transfer * t = &(bus->transfers[i]); *((uint8_t **)&t->in_buffer) = &(bus->in_buffer[bus->parsed_bytes]); *((unsigned int*)&t->in_size) = packet_total_size; bus->parsed_bytes += packet_total_size; //now we have to check out the incomming data sbcpd_transfer_check_response(t); } } int sbcpd_bus_submit_all_transfer(sbcpd_bus * bus){ CHECK_IF_BUS_ALLOCATED CHECK_IF_BUS_OPENED("Bus should be opened."); if(bus->transfers_size == 0){ SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_TRANSFER_LIST_EMPTY, "Need at least one transfer definition to send " "data over the bus"); } if(bus->flags & SBCPD_BUS_BUSY){ SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_IS_BUSY, "Bus is already sending data, wait for current" "transfer termination."); } bus->flags |= SBCPD_BUS_BUSY; // Preparing packet to send unsigned int i; for(i = 0; i < bus->transfers_size ; ++i){ if(bus->transfers[i].callback == NULL){ bus->flags &= ~SBCPD_BUS_BUSY; SBCPD_RETURN_WITH_ERROR(bus, SBCPD_EBUS_BAD_TRANSFER_DEFINITION, "Transfer does not have a callback set."); } //put the correct header bus->transfers[i].out_buffer[SBCP_HEADER_POS] = SBCP_HEADER_VALUE; //computes the right size uint8_t payload_size = bus->transfers[i].out_size - SBCP_MINIMAL_SIZE; bus->transfers[i].out_buffer[SBCP_PAYLOAD_SIZE_POS] = payload_size; //computes the right checksum bus->transfers[i].out_buffer[payload_size + SBCP_PAYLOAD_START_POS] = sbcpd_compute_checksum_of_packet(bus->transfers[i].out_buffer); } //all packet prepared successfully. //setting all the transfer status for(i = 0; i < bus->transfers_size ; ++i){ bus->transfers[i].status = SBCPD_TRANSFER_IN_PROGRESS; } //sending all the data over the host bus. - (*(bus->si->write_data))(bus->si, - bus->out_buffer, - bus->out_buffer_actual_size); + int sended_bytes = (*(bus->si->write_data))(bus->si, + bus->out_buffer, + bus->out_buffer_actual_size); + + if( sended_bytes < 0 ){ + for(i = 0; i < bus->transfers_size;++i){ + bus->transfers[i].status = SBCPD_TRANSFER_ABORTED; + } + + SBCPD_RETURN_WITH_ERROR(bus,SBCPD_EBUS_CANNOT_SEND_DATA, + "serial interface was not able to send data."); + } //now get all the response packet. sbcpd_bus_get_response_packets(bus); //all packet are received, the bus is not busy anymore. bus->flags &= ~SBCPD_BUS_BUSY; return SBCPD_NO_ERROR; } int sbcpd_bus_unlink_all_transfer(sbcpd_bus * bus){ return 0; } diff --git a/sbcpd/bus.h b/sbcpd/bus.h index 3bfed4c..ad68ceb 100644 --- a/sbcpd/bus.h +++ b/sbcpd/bus.h @@ -1,260 +1,261 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file bus.h * * \date Aug 15, 2011 * \author Alexandre Tuleu */ #ifndef SBCPD_BUS_H_ #define SBCPD_BUS_H_ #include "error.h" #include "transfer.h" #include "si/serial_interface.h" /** * Error code that could be returned by the \ref sbcpd_bus_m 'sfunctions. * \ingroup sbcpd_bus_m */ enum sbcpd_bus_error_code{ SBCPD_EBUS_NO_ERROR = 0x0000, //!< SBCPD_EBUS_NO_ERROR No errors happened. SBCPD_EBUS_ALREADY_OPEN, //!< SBCPD_EBUS_ALREADY_OPENED Bus is already opened. SBCPD_EBUS_NOT_ALLOCATED, //!< SBCPD_EBUS_NOT_ALLOCATED the bus is not allocated SBCPD_EBUS_IS_NOT_OPEN, //!< SBCPD_EBUS_IS_NOT_OPEN the bus was not opened when running the command. SBCPD_EBUS_BUS_RESSOUCE_ALREADY_TOOK, //!< SBCPD_EBUS_IS_ALREADY_OPENED the bus ressources is already allocated //!< to another application. SBCPD_EBUS_IS_BUSY, //!< SBCPD_EBUS_IS_BUSY The bus is currently busy, the operation could not //!< be performed. SBCPD_EBUS_TRANSFER_LIST_EMPTY, //!< SBCPD_EBUS_TRAMNSFER_LIST_EMPTY There is no transfer definition pending //!< for this bus. - SBCPD_EBUS_BAD_TRANSFER_DEFINITION + SBCPD_EBUS_BAD_TRANSFER_DEFINITION, //!< SBCPD_EBUS_BAD_TRANSFER_DEFINITION The transfer definition isn't //!< correct. + SBCPD_EBUS_CANNOT_SEND_DATA }; typedef enum sbcpd_bus_error_code sbcpd_bus_error_code; enum sbcpd_bus_flags{ SBCPD_BUS_VOID = 0x0, SBCPD_BUS_OPEN = 0x01, SBCPD_BUS_BUSY = 0x02 }; typedef enum sbcpd_bus_flags sbcpd_bus_flags; /** * Settings of the bus that should be set by the user before opening it. * \ingroup sbcpd_bus_m */ struct sbcpd_bus_settings { /** * The id of the master over the bus */ unsigned char master_id; /** * The frame rate of the bus, in ms. */ unsigned int frame_rate; /** * The number of trial before dropping a packet. */ unsigned int max_trials; }; typedef struct sbcpd_bus_settings sbcpd_bus_settings; /** * Represents a SBCP bus that could be issued to manipulate sbcpd_transfer. * End user should not write in any of the structure fields, at the exception of * the settings, before opening * \ingroup sbcpd_bus_m */ struct sbcpd_bus{ /** * Status of the bus. */ sbcpd_bus_flags flags; /** * \name some constants of the bus */ ///@{ /** * The maximal number of packet that a frame could contain. */ const unsigned int max_frame_packets; /** * The maximal total byte size of a packet over this bus. */ unsigned int max_packet_size; /** * User defined settings. */ const sbcpd_bus_settings settings; ///@} /** * The last error that occured on the bus. */ sbcpd_error error; sbcpd_serial_interface * si; const unsigned int buffers_size; uint8_t * out_buffer; uint8_t * in_buffer; unsigned int out_buffer_actual_size; struct sbcpd_transfer * transfers;; unsigned int transfers_size; unsigned int received_bytes; unsigned int parsed_bytes; }; typedef struct sbcpd_bus sbcpd_bus; /** * Creates a new bus. * \return */ sbcpd_bus * sbcpd_create_bus(const sbcpd_bus_settings settings); /** * Finds and opens a bus through a serial interface. Please notice that * the settings of the bus should already be set in the sbcpd_bus structure. * \ingroup sbcpd_bus_m * \param bus the bus structure with settings already set. * \param interface the sbcpd_serial_interface to use. * \return 0 on success, otherwise any of the following code : * - SBCPD_EBUS_NOT_FOUND if the specified device is not found. * - SBCPD_EBUS_ALREADY_OPEN if the specified bus is already opened. */ int sbcpd_bus_open(sbcpd_bus* bus, sbcpd_serial_interface * interface); /** * Closes a bus. This should be done to release ownership of the application on * the bus. * \ingroup sbcpd_bus_m * \param bus * \return */ int sbcpd_bus_close(sbcpd_bus * bus); /** * Free the memory used by a bus. * \ingroup sbcpd_bus_m * \param bus * \return */ int sbcpd_free_bus(sbcpd_bus * bus); /** * Append a new transfer definition to the bus * \param bus the sbcpd_bus to use * \param out_size the output size of the transfer. * \return a pointer to the new sbcpd_transfer structure when there is no error * or NULL otherwise. It may set the following bus errors : * - * \ingroup sbcpd_bus_m */ sbcpd_transfer * sbcpd_bus_append_transfer(sbcpd_bus * bus, unsigned int payload_size); /** * Removes the last requested transer. It will unlink it first. * \param bus * \return 0 on success, or any of the following error code otherwise : * \ingroup sbcpd_bus_m */ int sbcpd_bus_remove_last_transfer(sbcpd_bus * bus); /** * Removes all the transfer of the bus. it will unlink them first. * \param bus * \return 0 on success, or any of the following error code otherwise : * \ingroup sbcpd_bus_m */ int sbcpd_bus_clear_all_transfers(sbcpd_bus * bus); /** * Submits all the current affected tranfer to the bus. * \param bus * \return 0 on success, or any of the following error code otherwise : * \ingroup sbcpd_bus_m */ int sbcpd_bus_submit_all_transfer(sbcpd_bus * bus); /** * Unlinks all transfers of the bus. It will not prevent data to be sent, but * sbcpd_transfer callbacks will not be called. * \param bus * \return 0 on success, or any of the following error code otherwise : * \ingroup sbcpd_bus_m */ int sbcpd_bus_unlink_all_transfer(sbcpd_bus * bus); /** * \return the last bus error code * \ingroup sbcpd_bus_m * \param bus */ static inline sbcpd_bus_error_code sbcpd_bus_get_last_error_code(sbcpd_bus * bus){ return sbcpd_get_error_code(&(bus->error)); } /** * \return the last bus error code * \ingroup sbcpd_bus_m * \param bus * \return */ static inline const char * sbcpd_bus_get_last_error_message(sbcpd_bus * bus){ return bus->error.msg; } /** * \defgroup sbcpd_bus_m SBCP Bus * * * \ingroup sbcpd_m * */ #endif //SBCPD_BUS_H_ diff --git a/sbcpd/error.h b/sbcpd/error.h index 7fe4f4e..57397fb 100644 --- a/sbcpd/error.h +++ b/sbcpd/error.h @@ -1,138 +1,138 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file error.h * * \date Aug 24, 2011 * \author Alexandre Tuleu */ #ifndef SBCPD_ERROR_H_ #define SBCPD_ERROR_H_ #include <stdint.h> static const uint32_t SBCPD_NO_ERROR = 0; /** * Domain of errors that could occurs in the SBCP low level drivers. * \ingroup sbcpd_error_m */ enum sbcpd_error_domain{ - SBCPD_GLOBAL_ERROR = 0x0001, - SBCPD_BUS_ERROR = 0x0002, - SBCPD_FRAME_ERROR = 0x0003, - SBCPD_TRANSFER_ERROR = 0x0004, + SBCPD_GLOBAL_ERROR = 0x0001, + SBCPD_BUS_ERROR = 0x0002, + SBCPD_SERIAL_INTERFACE_ERROR = 0x0003, + SBCPD_TRANSFER_ERROR = 0x0004, }; typedef enum sbcpd_error_domain sbcpd_error_domain; /** * Represents an error of the sbcp low level driver. * \ingroup sbcpd_error_m */ struct sbcpd_error { /** * A code that represents the error. If it is zero, there is no error. */ uint32_t code; /** * The domain of the error. */ sbcpd_error_domain domain; /** * Message associated with the error. */ const char * msg; }; typedef struct sbcpd_error sbcpd_error; /** * Initializes the error. * \ingroup sbcpd_error_m * \param error the sbcpd_error to initialize. * \param domain the sbcpd_error_domain used for this error. */ void sbcpd_init_error(sbcpd_error * error, sbcpd_error_domain domain); /** * Creates a new error. * @return a pointer to the new sbcpd_error * \ingroup sbcpd_error_m */ sbcpd_error * sbcpd_create_global_error(); /** * Releases an allocated error. * @param error * \ingroup sbcpd_error_m */ void sbcpd_free_global_error(sbcpd_error * error); /** * \return the error code of an sbcpd_error * \param error the error to get the code from. * \ingroup sbcpd_error_m */ static inline uint16_t sbcpd_get_error_code(sbcpd_error * error){ return error->code; } /** * \return the domain of an sbcpd_error * * \ingroup sbcpd_error_m */ static inline sbcpd_error_domain sbcpd_get_error_domain(sbcpd_error * error){ return error->domain; } #define SBCPD_RETURN_WITH_ERROR_AND_VALUE(var,error_code,error_msg,value) do{\ var->error.code = error_code;\ var->error.msg = error_msg;\ return value;\ }while(0) /** * A convenience macro to return of a function that causes an error. * \ingroup sbcpd_error_m */ #define SBCPD_RETURN_WITH_ERROR(var, error_code , error_msg) \ SBCPD_RETURN_WITH_ERROR_AND_VALUE(var,error_code,error_msg,error_code) /** * \defgroup sbcpd_error_m Error Handling * * In the SBCP low level driver, errors are reported using an sbcpd_error * structure. It has an sbcpd_error_domain, which id unique for each module, * and an error code, which if it is zero, means that no errors occured. * \ingroup sbcpd_m */ #endif // SBCPD_ERROR_H_ diff --git a/sbcpd/sbcpd.c b/sbcpd/sbcpd.c index 3425a1c..24b9d41 100644 --- a/sbcpd/sbcpd.c +++ b/sbcpd/sbcpd.c @@ -1,56 +1,69 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file sbcpd.c * * \date Aug 15, 2011 * \author Alexandre Tuleu */ #include "sbcpd.h" +#include <stdlib.h> #include "si/ft2232h.h" -sbcpd_bus * sbcpd_default_oncilla_init(unsigned int master_id){ +sbcpd_bus * sbcpd_default_oncilla_init(unsigned int master_id, + sbcpd_error * err){ sbcpd_bus_settings settings; settings.frame_rate = 1; settings.master_id = master_id; settings.max_trials = 20; sbcpd_bus * bus = sbcpd_create_bus(settings); sbcpd_serial_interface * si = sbcpd_ft2232h_create_interface(); - sbcpd_ft2232h_open(si,3310000,0,2); + if(sbcpd_ft2232h_open(si,3310000,0,2) < 0 ){ + if(err){ + *err=si->error; + } + return NULL; + } - sbcpd_bus_open(bus,si); + + if(sbcpd_bus_open(bus,si) < 0){ + if(err){ + *err = bus->error; + } + return NULL; + } return bus; } /** * \defgroup sbcpd_m SBCP Driver Module * * \brief This module is responsible of the communication over SBCP buses. * Through the sbcpd_bus structure you can open and request the management of * one bus, where you can issue sbcpd_transfer request. * */ diff --git a/sbcpd/sbcpd.h b/sbcpd/sbcpd.h index 27e0289..377f48e 100644 --- a/sbcpd/sbcpd.h +++ b/sbcpd/sbcpd.h @@ -1,35 +1,36 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file sbcpd.h * * \date Aug 15, 2011 * \author Alexandre Tuleu */ #ifndef SBCPD_H_ #define SBCPD_H_ #include "common.h" #include "bus.h" #include "transfer.h" -sbcpd_bus * sbcpd_default_oncilla_init(); +sbcpd_bus * sbcpd_default_oncilla_init(unsigned int master_id, + sbcpd_error * err); #endif //SBCPD_H_ diff --git a/sbcpd/si/ft2232h.c b/sbcpd/si/ft2232h.c index 19675a6..71072cc 100644 --- a/sbcpd/si/ft2232h.c +++ b/sbcpd/si/ft2232h.c @@ -1,108 +1,122 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file ft2232h.c * * \date Oct 10, 2011 * \author Alexandre Tuleu */ #include "ft2232h.h" #include <sbcpd/ftdi/ft2232h.h> #include <ftdi.h> sbcpd_serial_interface * sbcpd_ft2232h_create_interface(){ sbcpd_serial_interface * si = malloc(sizeof(sbcpd_serial_interface)); struct ftdi_context * ftdi = malloc(sizeof(struct ftdi_context)); int f; if((f = ftdi_init(ftdi)) < 0){ //report it return si; } si->dev = ftdi; si->read_data = &sbcpd_ft2232h_read; si->write_data = &sbcpd_ft2232h_write; si->close = &sbcpd_ft2232h_close; si->free = &sbcpd_ft2232h_free; return si; } int sbcpd_ft2232h_open(sbcpd_serial_interface * si, unsigned int baudrate, unsigned char latency, unsigned int interface){ ftdi_set_interface(si->dev, interface < 6? interface : 5 ); int f; if((f = ftdi_usb_open(si->dev,0x403,0x6010)) < 0 ) { - - return f; + si->error.code = SBCPD_ESI_CANNOT_ACCESS_DEVICE; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_CANNOT_ACCESS_DEVICE; } if ((f = ft2232h_set_baudrate(si->dev,baudrate)) < 0 ){ - - return f; + si->error.code = SBCPD_ESI_CONFIGURE_ERROR; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_CONFIGURE_ERROR; } if ((f = ft2232h_set_latency_timer(si->dev,latency)) < 0){ - - return f; + si->error.code = SBCPD_ESI_CONFIGURE_ERROR; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_CONFIGURE_ERROR; } if((f = ftdi_usb_purge_buffers(si->dev)) < 0){ - + si->error.code = SBCPD_ESI_CONFIGURE_ERROR; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_CONFIGURE_ERROR; } - return 0; + return SBCPD_ESI_NO_ERROR; } -int sbcpd_ft2232h_close(sbcpd_serial_interface *si){ +void sbcpd_ft2232h_close(sbcpd_serial_interface *si){ ftdi_deinit(si->dev); - return 0; } void sbcpd_ft2232h_free(sbcpd_serial_interface *si){ sbcpd_ft2232h_close(si); ftdi_free(si->dev); } -unsigned int sbcpd_ft2232h_write(sbcpd_serial_interface * si, - const uint8_t * data, - unsigned int size){ +int sbcpd_ft2232h_write(sbcpd_serial_interface * si, + const uint8_t * data, + int size){ int ret = ftdi_write_data(si->dev,(uint8_t*)data,size); - return ret >= 0 ? ret : 0; + if(ret < 0){ + si->error.code = SBCPD_ESI_WRITE_ERROR; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_WRITE_ERROR; + } + return ret; } -unsigned int sbcpd_ft2232h_read(sbcpd_serial_interface * si, - uint8_t * data, - unsigned int size){ +int sbcpd_ft2232h_read(sbcpd_serial_interface * si, + uint8_t * data, + int size){ int ret = ftdi_read_data(si->dev,data,size); - return ret >= 0 ? ret : 0; + if(ret < 0){ + si->error.code = SBCPD_ESI_READ_ERROR; + si->error.msg = ftdi_get_error_string(si->dev); + return SBCPD_ESI_READ_ERROR; + } + return ret; } diff --git a/sbcpd/si/ft2232h.h b/sbcpd/si/ft2232h.h index b27ad3e..4448bcc 100644 --- a/sbcpd/si/ft2232h.h +++ b/sbcpd/si/ft2232h.h @@ -1,53 +1,53 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file ft2232.h * * \date Oct 6, 2011 * \author Alexandre Tuleu */ #ifndef SBCPD_SI_FT2232H_H_ #define SBCPD_SI_FT2232H_H_ #include "serial_interface.h" sbcpd_serial_interface * sbcpd_ft2232h_create_interface(); int sbcpd_ft2232h_open(sbcpd_serial_interface * si, unsigned int baudrate, unsigned char latency, unsigned int interface); -int sbcpd_ft2232h_close(sbcpd_serial_interface * si); +void sbcpd_ft2232h_close(sbcpd_serial_interface * si); void sbcpd_ft2232h_free(sbcpd_serial_interface * si); -unsigned int sbcpd_ft2232h_write(sbcpd_serial_interface * si, - const uint8_t * data, - unsigned int size); +int sbcpd_ft2232h_write(sbcpd_serial_interface * si, + const uint8_t * data, + int size); -unsigned int sbcpd_ft2232h_read(sbcpd_serial_interface * si, - uint8_t * data, - unsigned int size); +int sbcpd_ft2232h_read(sbcpd_serial_interface * si, + uint8_t * data, + int size); #endif // SBCPD_SI_FT2232_H_ diff --git a/sbcpd/si/serial_interface.h b/sbcpd/si/serial_interface.h index 7545146..07c91ed 100644 --- a/sbcpd/si/serial_interface.h +++ b/sbcpd/si/serial_interface.h @@ -1,57 +1,71 @@ /* * Copyright (c) 2011 Alexandre Tuleu <alexandre.tuleu.2005@polytechnique.org> * Ecole Polytechnique Fédérale de Lausanne. * * this file is part of sbcpd. * * sbcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sbcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with sbcpd. If not, see <http://www.gnu.org/licenses/>. */ /** * \file serial_interface.h * * \date Oct 6, 2011 * \author Alexandre Tuleu */ #ifndef SBCPD_SI_SERIAL_INTERFACE_H_ #define SBCPD_SI_SERIAL_INTERFACE_H_ #include <stdint.h> +#include <sbcpd/error.h> +/** + * Errors that can be returned by the modules functions. + */ +enum sbcpd_serial_interface_error{ + SBCPD_ESI_NO_ERROR = 0,//!< SBCPD_ESI_NO_ERROR + SBCPD_ESI_CANNOT_ACCESS_DEVICE = -1,//!< SBCPD_ESI_CANNOT_ACCESS_DEVICE + SBCPD_ESI_CONFIGURE_ERROR = -2,//!< SBCPD_ESI_CONFIGURE_ERROR + SBCPD_ESI_READ_ERROR = -3,//!< SBCPD_ESI_READ_ERROR + SBCPD_ESI_WRITE_ERROR = -4 //!< SBCPD_ESI_WRITE_ERROR +}; struct sbcpd_serial_interface; typedef struct sbcpd_serial_interface sbcpd_serial_interface; -typedef unsigned int (*sbcpd_si_write) (sbcpd_serial_interface * dev, +typedef int (*sbcpd_si_write) (sbcpd_serial_interface * dev, const uint8_t * data, - unsigned int size); + int size); -typedef unsigned int (*sbcpd_si_read) (sbcpd_serial_interface * dev, +typedef int (*sbcpd_si_read) (sbcpd_serial_interface * dev, uint8_t * data, - unsigned int size); + int size); -typedef int (*sbcpd_si_close)(sbcpd_serial_interface * si); +typedef void (*sbcpd_si_close)(sbcpd_serial_interface * si); typedef void (*sbcpd_si_free)(sbcpd_serial_interface * si); - +/** + * Represents a serial interface used to do Serial I/O from user space. + */ struct sbcpd_serial_interface { sbcpd_si_write write_data; sbcpd_si_read read_data; sbcpd_si_close close; sbcpd_si_free free; void * dev; + sbcpd_error error; }; #endif // SBCPD_SI_SERIAL_INTERFACE_H_