项目作者: jameswalmsley

项目描述 :
Ultimate Error Code
高级语言: C
项目地址: git://github.com/jameswalmsley/ultimate-error-codes.git
创建时间: 2020-03-25T15:51:20Z
项目社区:https://github.com/jameswalmsley/ultimate-error-codes

开源协议:

下载


  1. Ultimate Error Codes
  2. Copyright (C) 2013 - 2020 James Walmsley <james@fullfat-fs.co.uk>
  3. Permission to use, copy, modify, and/or distribute this software for any
  4. purpose with or without fee is hereby granted, provided that the above
  5. copyright notice and this permission notice appear in all copies.
  6. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  7. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  8. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  9. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Ultimate Error Codes

This system allows an entire system to have a global set of error codes.
Any level of a system can emit an Error_t and that can be safely passed
back through to an external user API.

This ensures that errors are detected and emitted at their source.

If an Error_t is encountered it should not be discarded and overwritten
by an Error_t code from a calling function.

  • The system can have up to 256 global error codes.
  • The system can have up to 256 modules.
  • Each module can have up to 256 error codes.

  • The encoding space is flexible, i.e. lower line resolution for more modules/errors.

    • 256/256 modules/errors seems reasonable.
    • Once a project has decided on this split, it should not be changed.

In abstract an Error is an abstraction of a cause of an event (reason)
combined with a unique context (location).

This encoding scheme combines these properties.

Use

All errors are included globally with a simple:

  1. #include "error.h"

The error headers can be easily packaged and deployed for use in other projects,
allowing them to “pretty” print any errorcodes received.

Error-Code Space

  1. 0x80000000 // Top-bit (sign bit) is set - This is an error. (Otherwise a value).
  2. 0x40000000 // Global errors have an extra bit set.
  3. 0x0000ff00 // The module the error was emitted from.
  4. 0x000000ff // The specific error code.
  5. 0x0fff0000 // Line number of emitted error.
  6. 0x30000000 // Location resolution bits.

What errors look like?

A module specific error:

  1. Error : 0x80070101
  2. Module : MODULE_MAIN - main.c:7
  3. Details : ERR_NO_MEMORY - Could not allocate memory

A global error.

  1. Error : 0xc01a0301
  2. Module : MODULE_EXAMPLE - example.c:26
  3. Details : ERR_GENERIC - Generic error

Errors should always be printed as a 32-bit hex string.

Error Location

The error location is inserted into the error code when the error is emitted
using the ERROR() macro.

The ERROR() macro automatically determines the resolution based on the LINE number.

The encoding allows for files with lengths up to 61440 lines.

Resolution Binning Range (Begin) Range (End)
0 1 1 4096
1 2 4097 12288
2 4 12289 28672
3 8 28673 61440

Testing For Errors

Use the IS_ERROR() macro:

  1. Error_t err = uart_init();
  2. if(IS_ERROR(err))
  3. {
  4. LOGE("Uart initialisation failed\n");
  5. return err; // Pass the error up!
  6. }

Its also perfectly fine to do this:

  1. if(err < 0) {}

Comparing Errors

Use the GET_ERROR() macro to check for a specific error:

  1. Error_t mmu_error = init_mmu();
  2. if(GET_ERROR(mmu_error) == ERR_MMU_INIT_FAILED)
  3. {
  4. /* Fatal error cannot continue.*/
  5. printk("Kernel could not init mmu.");
  6. for(;;);
  7. }

Error Values

I’d recommend keeping values and errors separate, however its perfectly OK to do:

  1. int32_t value = read_adc();
  2. if(IS_ERROR(value))
  3. {
  4. LOGE("Adc read failed\n");
  5. }
  6. calculateParams(value);

Alternatively:

  1. int32_t value;
  2. Error_t err = read_adc(&value);
  3. if(IS_ERROR(err))
  4. {
  5. LOGE("Adc read failed\n");
  6. }
  7. ...

Error Info and Tables.

There is a global_errors.h file, to define the global errors:

  1. #ifndef GLOBAL_ERRORS_H
  2. #define GLOBAL_ERRORS_H
  3. #define DEF_GLOBAL_ERROR(code) (DEF_ERROR(MODULE_GLOBAL, code) | _ERR_GLOBAL_MASK)
  4. #define ERR_NONE (0)
  5. #define ERR_GENERIC DEF_GLOBAL_ERROR(1)
  6. #define ERR_INVAL DEF_GLOBAL_ERROR(2)
  7. #ifdef ERROR_USE_TABLES
  8. MODULE_ERRORS(MODULE_GLOBAL)
  9. {
  10. DEF_ERR_INFO(ERR_GENERIC, "Generic error"),
  11. DEF_ERR_INFO(ERR_INVAL, "Invalid parameter/value"),
  12. };
  13. #endif
  14. #endif

All other modules define a list of error codes and their description in the same way.

Defining Error Codes

Single prefix for all error codes:

  1. ERR_x_y_z

I’d recommend sticking to a convention like:

  1. ERR_MYMODULE_CANNOT_COMPUTE // Where MYMODULE namespaces the defines.