Skip to content

Introducing ErrorCode #253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions api/Client.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ namespace arduino {
class Client : public Stream {

public:
virtual int connect(IPAddress ip, uint16_t port) =0;
virtual int connect(const char *host, uint16_t port) =0;
virtual ErrorCode connect(IPAddress ip, uint16_t port) =0;
virtual ErrorCode connect(const char *host, uint16_t port) =0;
virtual size_t write(uint8_t) =0;
virtual size_t write(const uint8_t *buf, size_t size) =0;
virtual int available() = 0;
virtual int read() = 0;
virtual int read(uint8_t *buf, size_t size) = 0;
virtual int peek() = 0;
virtual ReturnValue available() = 0;
virtual ReturnValue read() = 0;
virtual ReturnValue read(uint8_t *buf, size_t size) = 0;
virtual ReturnValue peek() = 0;
virtual void flush() = 0;
virtual void stop() = 0;
virtual uint8_t connected() = 0;
Expand All @@ -43,4 +43,4 @@ class Client : public Stream {
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
};

}
}
142 changes: 142 additions & 0 deletions api/ErrorCodes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#pragma once
#include <stdint.h>

namespace arduino {

typedef int_fast32_t error_t;

enum : error_t {
ArduinoSuccess = 0,
ArduinoError = -1,

// TODO better names
ArduinoEPERM = -1, /**< Not owner */
ArduinoENOENT = -2, /**< No such file or directory */
ArduinoESRCH = -3, /**< No such context */
ArduinoEINTR = -4, /**< Interrupted system call */
ArduinoEIO = -5, /**< I/O error */
ArduinoENXIO = -6, /**< No such device or address */
ArduinoE2BIG = -7, /**< Arg list too long */
ArduinoENOEXEC = -8, /**< Exec format error */
ArduinoEBADF = -9, /**< Bad file number */
ArduinoECHILD = -10, /**< No children */
ArduinoEAGAIN = -11, /**< No more contexts */
ArduinoENOMEM = -12, /**< Not enough core */
ArduinoEACCES = -13, /**< Permission denied */
ArduinoEFAULT = -14, /**< Bad address */
ArduinoENOTBLK = -15, /**< Block device required */
ArduinoEBUSY = -16, /**< Mount device busy */
ArduinoEEXIST = -17, /**< File exists */
ArduinoEXDEV = -18, /**< Cross-device link */
ArduinoENODEV = -19, /**< No such device */
ArduinoENOTDIR = -20, /**< Not a directory */
ArduinoEISDIR = -21, /**< Is a directory */
ArduinoEINVAL = -22, /**< Invalid argument */
ArduinoENFILE = -23, /**< File table overflow */
ArduinoEMFILE = -24, /**< Too many open files */
ArduinoENOTTY = -25, /**< Not a typewriter */
ArduinoETXTBSY = -26, /**< Text file busy */
ArduinoEFBIG = -27, /**< File too large */
ArduinoENOSPC = -28, /**< No space left on device */
ArduinoESPIPE = -29, /**< Illegal seek */
ArduinoEROFS = -30, /**< Read-only file system */
ArduinoEMLINK = -31, /**< Too many links */
ArduinoEPIPE = -32, /**< Broken pipe */
ArduinoENOMSG = -35, /**< Unexpected message type */
ArduinoEDEADLK = -45, /**< Resource deadlock avoided */
ArduinoENOLCK = -46, /**< No locks available */
ArduinoENOSTR = -60, /**< STREAMS device required */
ArduinoENODATA = -61, /**< Missing expected message data */
ArduinoETIME = -62, /**< STREAMS timeout occurred */
ArduinoENOSR = -63, /**< Insufficient memory */
ArduinoEPROTO = -71, /**< Generic STREAMS error */
ArduinoEBADMSG = -77, /**< Invalid STREAMS message */
ArduinoENOSYS = -88, /**< Function not implemented */
ArduinoENOTEMPTY = -90, /**< Directory not empty */
ArduinoENAMETOOLONG = -91, /**< File name too long */
ArduinoELOOP = -92, /**< Too many levels of symbolic links */
ArduinoEOPNOTSUPP = -95, /**< Operation not supported on socket */
ArduinoEPFNOSUPPORT = -96, /**< Protocol family not supported */
ArduinoECONNRESET = -104, /**< Connection reset by peer */
ArduinoENOBUFS = -105, /**< No buffer space available */
ArduinoEAFNOSUPPORT = -106, /**< Addr family not supported */
ArduinoEPROTOTYPE = -107, /**< Protocol wrong type for socket */
ArduinoENOTSOCK = -108, /**< Socket operation on non-socket */
ArduinoENOPROTOOPT = -109, /**< Protocol not available */
ArduinoESHUTDOWN = -110, /**< Can't send after socket shutdown */
ArduinoECONNREFUSED = -111, /**< Connection refused */
ArduinoEADDRINUSE = -112, /**< Address already in use */
ArduinoECONNABORTED = -113, /**< Software caused connection abort */
ArduinoENETUNREACH = -114, /**< Network is unreachable */
ArduinoENETDOWN = -115, /**< Network is down */
ArduinoETIMEDOUT = -116, /**< Connection timed out */
ArduinoEHOSTDOWN = -117, /**< Host is down */
ArduinoEHOSTUNREACH = -118, /**< No route to host */
ArduinoEINPROGRESS = -119, /**< Operation now in progress */
ArduinoEALREADY = -120, /**< Operation already in progress */
ArduinoEDESTADDRREQ = -121, /**< Destination address required */
ArduinoEMSGSIZE = -122, /**< Message size */
ArduinoEPROTONOSUPPORT = -123, /**< Protocol not supported */
ArduinoESOCKTNOSUPPORT = -124, /**< Socket type not supported */
ArduinoEADDRNOTAVAIL = -125, /**< Can't assign requested address */
ArduinoENETRESET = -126, /**< Network dropped connection on reset */
ArduinoEISCONN = -127, /**< Socket is already connected */
ArduinoENOTCONN = -128, /**< Socket is not connected */
ArduinoETOOMANYREFS = -129, /**< Too many references: can't splice */
ArduinoENOTSUP = -134, /**< Unsupported value */
ArduinoEOVERFLOW = -139, /**< Value overflow */
ArduinoECANCELED = -140, /**< Operation canceled */
ArduinoEWOULDBLOCK = ArduinoEAGAIN, /**< Operation would block */
};

/* Error Codes:
* In Arduino if a function returns 0 is considered to have failed,
* while any value different from 0 is considered success.
* Errors are generally represented with an int type that may vary in size depending on the platform.
* For this reason in this representation error_t type is defined with an integer type with a defined size.
*/
class ErrorCode {
public:
constexpr ErrorCode(int value): error(value != 0? ArduinoSuccess : ArduinoError) {}
constexpr ErrorCode(error_t value): error(value) {}
const error_t error;

constexpr operator bool() const {
return error == ArduinoSuccess;
}
};

/* ReturnValueClass is meant to represent all the cases where with a single value
* we want to return an error, if the value is negative, or a meaningful result
* if greater than or equal to 0.
* In order to be retrocompatible with the previous definition boolean evaluation:
* - It must return true, if the value is greater than or equal 0
* - It must return false, if the value is negatie
* - It must be evaluable as the primitive type associated with
*/
template<typename T>
class ReturnValueClass {
public:
constexpr ReturnValueClass(T value)
: value(value >= 0? value : 0), error(value < 0? (error_t)value : ArduinoSuccess) {}

// it would be nice to have a default value on error to Success
constexpr ReturnValueClass(T value, error_t error)
: value(value), error(error) {}

const T value; // TODO should we leave the const modifier?
const error_t error;

constexpr operator bool() const {
return error == ArduinoSuccess;
}

constexpr operator T() const {
return error == ArduinoSuccess ? value : error;
}
};

using ReturnValue = ReturnValueClass<int>;
using ReturnLongValue = ReturnValueClass<int64_t>;

}
5 changes: 3 additions & 2 deletions api/HardwareCAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "CanMsg.h"
#include "CanMsgRingbuffer.h"
#include "ErrorCodes.h"

/**************************************************************************************
* TYPEDEF
Expand Down Expand Up @@ -53,7 +54,7 @@ namespace arduino
class HardwareCAN
{
public:
virtual ~HardwareCAN() {}
virtual ~HardwareCAN() = default;


/**
Expand All @@ -62,7 +63,7 @@ class HardwareCAN
* @param can_bitrate the bus bit rate
* @return true if initialization succeeded and the controller is operational
*/
virtual bool begin(CanBitRate const can_bitrate) = 0;
virtual ErrorCode begin(CanBitRate const can_bitrate) = 0;

/**
* Disable the CAN controller.
Expand Down
6 changes: 3 additions & 3 deletions api/HardwareI2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ namespace arduino {
class HardwareI2C : public Stream
{
public:
virtual void begin() = 0;
virtual void begin(uint8_t address) = 0;
virtual ErrorCode begin() = 0;
virtual ErrorCode begin(uint8_t address) = 0;
virtual void end() = 0;

virtual void setClock(uint32_t freq) = 0;

virtual void beginTransmission(uint8_t address) = 0;
virtual uint8_t endTransmission(bool stopBit) = 0;
virtual uint8_t endTransmission(void) = 0;
Expand Down
2 changes: 1 addition & 1 deletion api/HardwareSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class HardwareSPI
virtual void attachInterrupt() = 0;
virtual void detachInterrupt() = 0;

virtual void begin() = 0;
virtual ErrorCode begin() = 0;
virtual void end() = 0;
};

Expand Down
10 changes: 5 additions & 5 deletions api/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ namespace arduino {
class HardwareSerial : public Stream
{
public:
virtual void begin(unsigned long) = 0;
virtual void begin(unsigned long baudrate, uint16_t config) = 0;
virtual ErrorCode begin(unsigned long) = 0;
virtual ErrorCode begin(unsigned long baudrate, uint16_t config) = 0;
virtual void end() = 0;
virtual int available(void) = 0;
virtual int peek(void) = 0;
virtual int read(void) = 0;
virtual ReturnValue peek(void) = 0;
virtual ReturnValue read(void) = 0;
virtual void flush(void) = 0;
virtual size_t write(uint8_t) = 0;
using Print::write; // pull in write(str) and write(buf, size) from Print
Expand All @@ -103,4 +103,4 @@ class HardwareSerial : public Stream
// XXX: Are we keeping the serialEvent API?
extern void serialEventRun(void) __attribute__((weak));

}
}
11 changes: 6 additions & 5 deletions api/Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <inttypes.h>
#include "Print.h"
#include "ErrorCodes.h"

// compatibility macros for testing
/*
Expand Down Expand Up @@ -57,17 +58,17 @@ class Stream : public Print
int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout

public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual ReturnValue available() = 0;
virtual ReturnValue read() = 0;
virtual ReturnValue peek() = 0;

Stream() {_timeout=1000;}

// parsing methods

void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
unsigned long getTimeout(void) { return _timeout; }

bool find(const char *target); // reads data from the stream until the target string is found
bool find(const uint8_t *target) { return find ((const char *)target); }
// returns true if target string is found, false if timed out (see setTimeout)
Expand Down Expand Up @@ -130,4 +131,4 @@ class Stream : public Print

}

using arduino::Stream;
using arduino::Stream;
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ set(TEST_SRCS
src/Common/test_map.cpp
src/Common/test_max.cpp
src/Common/test_min.cpp
src/ErrorCodes/test_ErrorCodes.cpp
src/ErrorCodes/test_ReturnValues.cpp
src/IPAddress/test_toString.cpp
src/IPAddress/test_fromString.cpp
src/IPAddress/test_fromString6.cpp
Expand Down
6 changes: 3 additions & 3 deletions test/include/StreamMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class StreamMock : public arduino::Stream
void operator << (char const * str);

virtual size_t write(uint8_t ch) override;
virtual int available() override;
virtual int read() override;
virtual int peek() override;
arduino::ReturnValue available() override;
arduino::ReturnValue read() override;
arduino::ReturnValue peek() override;

private:
std::deque<char> _stream;
Expand Down
57 changes: 57 additions & 0 deletions test/src/ErrorCodes/test_ErrorCodes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2020 Arduino. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include <catch.hpp>

#include <api/ErrorCodes.h>

using namespace arduino;

/**************************************************************************************
* TEST CODE
**************************************************************************************/

TEST_CASE ("An ErrorCode can be evaluated as boolean and respect Arduino values", "[ErrorCodes-Evaluation]") {
REQUIRE((bool)ErrorCode(1) == true);
REQUIRE((bool)ErrorCode(0) == false);
}

TEST_CASE ("An error is returned with a value different from 0 and 1", "[ErrorCodes-Evaluation]") {
THEN ("if the error is well defined the boolean evaluation of the error code respects Arduino standard") {
arduino::error_t err = 125;
ErrorCode ec(err);
REQUIRE((bool)ec == false);
REQUIRE(ec.error == err);
}
THEN ("if an int is provided the boolean evaluation of the error code respects Arduino standard and error is evaluated to ArduinoSuccess") {
int err = 1;
ErrorCode ec(err);
REQUIRE((bool)ec == true);
REQUIRE(ec.error == ArduinoSuccess);
}
THEN ("if an int is provided the boolean evaluation of the error code respects Arduino standard and error is evaluated to ArduinoError") {
int err = 0;
ErrorCode ec(err);
REQUIRE((bool)ec == false);
REQUIRE(ec.error == ArduinoError);
}
THEN ("if an int is provided the boolean evaluation of the error code respects Arduino standard and the value is not preserved") {
int err = 125;
ErrorCode ec(err);
REQUIRE((bool)ec == false);
REQUIRE(ec.error == ArduinoError);
}
THEN ("if an int is provided the boolean evaluation of the error code respects Arduino standard and the value is not preserved") {
ErrorCode ec(ArduinoELOOP);
REQUIRE((bool)ec == false);
REQUIRE(ec.error == ArduinoELOOP);
}
}

Loading
Loading