22 #ifndef I2C_HANDLER_COMMON_HH
23 #define I2C_HANDLER_COMMON_HH
26 #include "boards/board_traits.h"
103 constexpr I2CCommandType() =
default;
104 constexpr I2CCommandType(
const I2CCommandType&) =
default;
105 explicit constexpr I2CCommandType(uint8_t value) : value_{value} {}
106 constexpr I2CCommandType(
bool write,
bool stop,
bool finish,
bool end)
107 : value_{value(write, stop, finish, end)} {}
108 I2CCommandType& operator=(
const I2CCommandType&) =
default;
112 return value_ == NONE;
114 bool is_write()
const
116 return value_ & WRITE;
120 return value_ &
STOP;
122 bool is_finish()
const
124 return value_ & FINISH;
130 void add_flags(uint8_t value)
135 static constexpr uint8_t flags(
bool stop,
bool finish,
bool end)
141 static constexpr
const uint8_t NONE = 0;
142 static constexpr
const uint8_t NOT_NONE =
bits::BV8(0);
143 static constexpr
const uint8_t WRITE =
bits::BV8(1);
145 static constexpr
const uint8_t FINISH =
bits::BV8(3);
148 static constexpr uint8_t value(
bool write,
bool stop,
bool finish,
bool end)
150 return bits::ORIF8(
true, NOT_NONE, write, WRITE, stop,
STOP, finish, FINISH, end,
END);
153 uint8_t value_ = NONE;
155 friend bool operator==(
const I2CCommandType&,
const I2CCommandType&);
156 friend bool operator!=(
const I2CCommandType&,
const I2CCommandType&);
160 bool operator==(
const I2CCommandType& a,
const I2CCommandType& b);
161 bool operator!=(
const I2CCommandType& a,
const I2CCommandType& b);
181 constexpr
I2CLightCommand(I2CCommandType type, uint8_t byte_count) : type_{type}, byte_count_{byte_count} {}
183 I2CCommandType type()
const
187 I2CCommandType& type()
191 uint8_t byte_count()
const
195 void decrement_byte_count()
199 void update_byte_count(uint8_t read_count, uint8_t write_count)
201 if (byte_count_ == 0)
202 byte_count_ = (type_.is_write() ? write_count : read_count);
208 I2CCommandType type_ = I2CCommandType{};
210 uint8_t byte_count_ = 0;
238 uint8_t target()
const
247 void set_target(uint8_t target, T
future)
265 out <<
'{' << c.type() <<
','
273 template<
bool IS_DEBUG_ = false,
typename DEBUG_HOOK_ = I2C_DEBUG_HOOK>
struct I2CDebugSupport
275 explicit I2CDebugSupport(
UNUSED DEBUG_HOOK_ hook =
nullptr) {}
281 template<
typename DEBUG_HOOK_>
struct I2CDebugSupport<true, DEBUG_HOOK_>
283 explicit I2CDebugSupport(DEBUG_HOOK_ hook) : hook_{hook} {}
284 void call_hook(
DebugStatus status, uint8_t data = 0)
295 template<
bool IS_STATUS_ = false,
typename STATUS_HOOK_ = I2C_STATUS_HOOK>
struct I2CStatusSupport
297 explicit I2CStatusSupport(
UNUSED STATUS_HOOK_ hook =
nullptr) {}
303 template<
typename STATUS_HOOK_>
struct I2CStatusSupport<true, STATUS_HOOK_>
305 explicit I2CStatusSupport(STATUS_HOOK_ hook) : hook_{hook} {}
308 hook_(expected, actual);
317 template<
bool HAS_LIFECYCLE_ = false>
struct I2CLifeCycleSupport
320 template<
typename T>
static PROXY<T>
make_proxy(
const T& dest)
325 template<
typename T> T& resolve(PROXY<T> proxy)
const
330 template<>
struct I2CLifeCycleSupport<true>
333 template<
typename T>
static PROXY<T>
make_proxy(
const T& dest)
338 : lifecycle_manager_{*lifecycle_manager} {}
339 template<
typename T> T& resolve(PROXY<T> proxy)
const
341 return *proxy(lifecycle_manager_);
350 template<I2CMode MODE_ = I2CMode::STANDARD>
struct I2CMode_trait
352 static constexpr
I2CMode MODE = MODE_;
353 static constexpr uint32_t RATE = 100'000UL;
354 static constexpr uint32_t FREQUENCY = ((F_CPU / RATE) - 16UL) / 2;
366 static constexpr uint32_t RATE = 400'000UL;
367 static constexpr uint32_t FREQUENCY = ((F_CPU / RATE) - 16UL) / 2;
410 template<
typename ARCH_HANDLER_,
I2CMode MODE_,
bool HAS_LC_,
411 typename STATUS_HOOK_,
bool HAS_DEBUG_,
typename DEBUG_HOOK_>
415 using ARCH_HANDLER = ARCH_HANDLER_;
416 using MODE_TRAIT = I2CMode_trait<MODE_>;
417 using I2C_TRAIT = board_traits::TWI_trait;
418 using REG8 = board_traits::REG8;
419 using DEBUG = I2CDebugSupport<HAS_DEBUG_, DEBUG_HOOK_>;
420 using LC = I2CLifeCycleSupport<HAS_LC_>;
424 template<
typename T>
using PROXY =
typename LC::template PROXY<T>;
477 STATUS_HOOK_ status_hook =
nullptr,
478 DEBUG_HOOK_ debug_hook =
nullptr)
479 : handler_{status_hook}, lc_{lifecycle_manager}, debug_hook_{debug_hook} {}
483 bool ensure_num_commands_(
UNUSED uint8_t num_commands)
const
489 I2CLightCommand command, uint8_t target, PROXY<ABSTRACT_FUTURE> proxy)
492 const I2CCommandType type = command.type();
493 if (type.is_none())
return true;
494 if (clear_commands_)
return false;
495 ABSTRACT_FUTURE&
future = lc_.resolve(proxy);
497 bool ok = (no_stop_ ? exec_repeat_start_() : exec_start_());
498 stopped_already_ =
false;
500 return handle_error(
future);
505 if (!exec_send_slaw_(target))
506 return handle_error(
future);
508 while (command.byte_count() > 0)
510 if ((!exec_send_data_(command,
future)) && (command.byte_count() > 0))
511 return handle_error(
future);
516 if (!exec_send_slar_(target))
517 return handle_error(
future);
519 while (command.byte_count() > 0)
520 if (!exec_receive_data_(command,
future))
521 return handle_error(
future);
525 if (type.is_finish())
526 future.set_future_finish_();
531 no_stop_ = !type.is_stop();
535 void last_command_pushed_()
538 if ((!no_stop_) && (!stopped_already_) && (!clear_commands_))
543 clear_commands_ =
false;
544 stopped_already_ =
false;
547 template<
typename T> T& resolve(PROXY<T> proxy)
const
549 return lc_.resolve(proxy);
556 return handler_.exec_start_();
559 bool exec_repeat_start_()
562 return handler_.exec_repeat_start_();
565 bool exec_send_slar_(uint8_t target)
568 return handler_.exec_send_slar_(target);
571 bool exec_send_slaw_(uint8_t target)
574 return handler_.exec_send_slaw_(target);
577 bool exec_send_data_(I2CLightCommand& command, ABSTRACT_FUTURE&
future)
581 bool ok =
future.get_storage_value_(data);
590 command.decrement_byte_count();
591 return handler_.exec_send_data_(data);
594 bool exec_receive_data_(I2CLightCommand& command, ABSTRACT_FUTURE&
future)
597 const bool last_byte = (command.byte_count() == 1);
599 debug_hook_.call_hook(debug);
602 if (handler_.exec_receive_data_(last_byte, data))
604 const bool ok =
future.set_future_value_(data);
609 command.decrement_byte_count();
623 handler_.exec_stop_();
626 _delay_loop_1(MODE_TRAIT::DELAY_AFTER_STOP);
627 stopped_already_ =
true;
631 bool handle_error(ABSTRACT_FUTURE&
future)
639 clear_commands_ =
true;
646 bool no_stop_ =
false;
647 bool clear_commands_ =
false;
648 bool stopped_already_ =
false;
650 ARCH_HANDLER handler_;
654 template<
typename>
friend class I2CDevice;
659 template<
typename T>
struct I2CManager_trait
661 static constexpr
bool IS_I2CMANAGER =
false;
662 static constexpr
bool IS_ASYNC =
false;
663 static constexpr
bool HAS_LIFECYCLE =
false;
664 static constexpr
bool IS_DEBUG =
false;
665 static constexpr
bool IS_STATUS =
false;
669 template<
bool IS_ASYNC_,
bool HAS_LIFECYCLE_,
bool IS_STATUS_,
bool IS_DEBUG_, I2CMode MODE_>
670 struct I2CManager_trait_impl
672 static constexpr
bool IS_I2CMANAGER =
true;
673 static constexpr
bool IS_ASYNC = IS_ASYNC_;
674 static constexpr
bool HAS_LIFECYCLE = HAS_LIFECYCLE_;
675 static constexpr
bool IS_DEBUG = IS_DEBUG_;
676 static constexpr
bool IS_STATUS = IS_STATUS_;
677 static constexpr
I2CMode MODE = MODE_;
Useful bits manipulation utilities.
Base class for all FakeFutures.
Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future.
Abstract synchronous I2C Manager for all MCU architectures.
void begin_()
Prepare and enable the MCU for I2C transmission.
void end_()
Disable MCU I2C transmission.
void begin()
Prepare and enable the MCU for I2C transmission.
void end()
Disable MCU I2C transmission.
Atomic I2C command as used internally by an asynchronous I2C Manager.
Light atomic I2C command as prepared by an I2C device.
The abstract base class of all LifeCycleManager.
A kind of proxy class that encapsulates access to a fixed T instance.
A light proxy class that encapsulates access to a fixed T instance, or to a dynamic LifeCycle<T> inst...
Output stream wrapper to provide formatted output API, a la C++.
#define UNUSED
Specific GCC attribute to declare an argument or variable unused, so that the compiler does not emit ...
Utility API to handle the concept of futures.
I2C API common definitions.
Utility API to handle lifecycle of objects so that:
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
static constexpr uint8_t ORIF8(bool flag1, uint8_t val1, bool flag2, uint8_t val2)
Create a uint8_t bitwise OR boolean operation between uint8_t operands, conditioned by bool flags.
static constexpr const Tone END
This special tone marks the end of a melody (as a sequence of Tones).
constexpr const int EPROTO
Protocol error.
constexpr const int EILSEQ
Illegal byte sequence.
Contains the API around Future implementation.
@ ERROR
The status of a Future once a value provider has reported an error to it.
Define API to define and manage I2C devices.
void(*)(Status expected, Status actual) I2C_STATUS_HOOK
The default status observer hook type.
DebugStatus
List of debug states that are reported by the I2C Manager in debug mode.
@ SEND_OK
The latest sent byte has been acknowledged by the slave.
@ SEND_ERROR
The latest sent byte has not been acknowledged by the slave.
@ SLAR
A slave address has just been sent for reading.
@ RECV_OK
I2C Manager has acknowledged the latest received byte from the slave.
@ SEND
A byte has just be sent to the slave.
@ STOP
A stop condition has just been sent.
@ REPEAT_START
A repeat start condition has just been sent.
@ RECV_LAST
The last byte is being received from the slave.
@ START
A start condition has just been sent.
@ RECV
A byte is being received from the slave.
@ RECV_ERROR
I2C Manager has not acknowledged the latest received byte from the slave.
@ SLAW
A slave address has just been sent for writing.
void(*)(DebugStatus status, uint8_t data) I2C_DEBUG_HOOK
The default debugging hook type.
I2CMode
I2C available transmission modes.
@ STANDARD
I2C Standard mode, less than 100KHz.
@ FAST
I2C Fast mode, less than 400KHz.
Status
Transmission status codes.
DirectProxy< T > make_direct_proxy(const T &dest)
Utility template function to create a DirectProxy<T> from dest without the need to speicify T.
LightProxy< T > make_light_proxy(const T &dest)
Utility template function to create a LightProxy<T> from dest without the need to speicify T.
Proxy< T > make_proxy(const T &dest)
Utility template function to create a Proxy<T> from dest without the need to speicify T.
void flush(FSTREAM &stream)
Manipulator for an output stream, which will flush the stream buffer.
void hex(FSTREAM &stream)
Manipulator for an output or input stream, which will set the base, used to represent (output) or int...
bool operator==(const RTTTime &a, const RTTTime &b)
Compare 2 RTTTime instances.
bool operator!=(const RTTTime &a, const RTTTime &b)
Compare 2 RTTTime instances.
constexpr uint8_t calculate_delay1_count(float time_us)
Calculate the count to pass to delay1() in order to reach time_us microseconds delay.
Utility API to handle ring-buffer queue containers.
C++-like std::iostream facilities.
General utilities API that have broad application in programs.