From ef162ca3445d9adb000d7dfd1b68b181ef958926 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 14 Jun 2024 12:16:36 +0200 Subject: clean up pbdrv naming --- lib/pbdrv/drv/arduino/mod.cpp | 8 ++++---- lib/pbdrv/drv/arduino/mod.h | 2 +- lib/pbdrv/mod/main.h | 2 +- lib/pbdrv/pb-buf.c | 2 +- lib/pbdrv/pb-buf.h | 4 ++-- lib/pbdrv/pb-mod.c | 10 +++++----- lib/pbdrv/pb-mod.h | 10 +++++----- lib/pbdrv/pb-msg.c | 19 +++++++++++------- lib/pbdrv/pb-msg.h | 6 +++--- lib/pbdrv/pb-serial.c | 46 +++++++++++++++++++++---------------------- lib/pbdrv/pb-serial.h | 18 ++++++++--------- main/i2c.c | 4 ++-- main/init.c | 2 +- main/mod.c | 4 ++-- main/pbdrv.c | 28 +++++++++++++------------- main/pbdrv.h | 6 +++--- puzzle/dummy/main.cpp | 10 +++++----- test/pbdrv/msg.cpp | 10 +++++----- 18 files changed, 98 insertions(+), 93 deletions(-) diff --git a/lib/pbdrv/drv/arduino/mod.cpp b/lib/pbdrv/drv/arduino/mod.cpp index 8a38a5b..fab9dd5 100644 --- a/lib/pbdrv/drv/arduino/mod.cpp +++ b/lib/pbdrv/drv/arduino/mod.cpp @@ -18,17 +18,17 @@ static void recv_event(int bytes) { while (Wire.available()) data[size++] = Wire.read(); - pbdrv_i2c_recv(data, size); + pb_i2c_recv(data, size); } -void pbdrv_setup() { - Wire.begin((int) PBDRV_MOD_ADDR); +void pb_setup() { + Wire.begin((int) PB_MOD_ADDR); Wire.setWireTimeout(PB_TIMEOUT_US, true); Wire.setClock(PB_CLOCK_SPEED_HZ); Wire.onReceive(recv_event); } -__weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { +__weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { Wire.beginTransmission((int) addr); Wire.write(buf, sz); Wire.endTransmission(true); diff --git a/lib/pbdrv/drv/arduino/mod.h b/lib/pbdrv/drv/arduino/mod.h index 079941a..c4cb9ce 100644 --- a/lib/pbdrv/drv/arduino/mod.h +++ b/lib/pbdrv/drv/arduino/mod.h @@ -9,7 +9,7 @@ extern "C" { * * This function should be called from the Arduino \c setup() function. */ -void pbdrv_setup(); +void pb_setup(); #ifdef __cplusplus } diff --git a/lib/pbdrv/mod/main.h b/lib/pbdrv/mod/main.h index 535ce06..ec48acd 100644 --- a/lib/pbdrv/mod/main.h +++ b/lib/pbdrv/mod/main.h @@ -1,6 +1,6 @@ #pragma once -#include "../types.h" +#include "../pb-types.h" typedef struct { const i2c_addr_t mod_addr; diff --git a/lib/pbdrv/pb-buf.c b/lib/pbdrv/pb-buf.c index 673040f..5dfaa66 100644 --- a/lib/pbdrv/pb-buf.c +++ b/lib/pbdrv/pb-buf.c @@ -2,7 +2,7 @@ #include -void pbdrv_buf_free(pbdrv_buf_t * buf) { +void pb_buf_free(pb_buf_t * buf) { if (buf->data == NULL) return; free(buf->data); buf->data = NULL; diff --git a/lib/pbdrv/pb-buf.h b/lib/pbdrv/pb-buf.h index 149b384..671f344 100644 --- a/lib/pbdrv/pb-buf.h +++ b/lib/pbdrv/pb-buf.h @@ -10,9 +10,9 @@ extern "C" { typedef struct { char * data; //! pointer to data size_t size; //! size of data -} pbdrv_buf_t; +} pb_buf_t; -void pbdrv_buf_free(pbdrv_buf_t * buf); +void pb_buf_free(pb_buf_t * buf); #ifdef __cplusplus } diff --git a/lib/pbdrv/pb-mod.c b/lib/pbdrv/pb-mod.c index 740f2a5..f5c9a34 100644 --- a/lib/pbdrv/pb-mod.c +++ b/lib/pbdrv/pb-mod.c @@ -2,7 +2,7 @@ #include "pb.h" //! fallback module name -__weak const char * PBDRV_MOD_NAME = "???"; +__weak const char * PB_MOD_NAME = "???"; //! [private] placeholder global state variable static pb_global_state_t _global_state = PB_GS_NOINIT; @@ -10,17 +10,17 @@ static pb_global_state_t _global_state = PB_GS_NOINIT; //! [private] main controller global state static pb_global_state_t _main_state = PB_GS_NOINIT; -// __weak enum pb_state pbdrv_hook_mod_state_read() { +// __weak enum pb_state pb_hook_mod_state_read() { // return _global_state; // } -// __weak void pbdrv_hook_mod_state_write(enum pb_state state) { +// __weak void pb_hook_mod_state_write(enum pb_state state) { // _global_state = state; // } -__weak void pbdrv_i2c_recv(const uint8_t * buf, size_t sz) { +__weak void pb_i2c_recv(const uint8_t * buf, size_t sz) { return; } -__weak void pbdrv_hook_main_state_update(pb_global_state_t state) { } +__weak void pb_hook_main_state_update(pb_global_state_t state) { } diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index fa290bf..549bdcb 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -3,7 +3,7 @@ /** * \file puzzle bus driver implementation * - * Most \c pbdrv_* functions have a weak implementation, which may be + * Most \c pb_* functions have a weak implementation, which may be * overwritten by a custom implementation. This allows you to use the default * implementation where possible, and only implement extensions required for * your puzzle module. Please see spec.adoc for more information about how to @@ -21,12 +21,12 @@ extern "C" { #endif //! puzzle module name (optional, default = "???") -extern const char * PBDRV_MOD_NAME; +extern const char * PB_MOD_NAME; //! puzzle module bus address (required) -extern const i2c_addr_t PBDRV_MOD_ADDR; +extern const i2c_addr_t PB_MOD_ADDR; -void pbdrv_i2c_recv(const uint8_t * buf, size_t sz); -void pbdrv_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); +void pb_i2c_recv(const uint8_t * buf, size_t sz); +void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); #ifdef __cplusplus } diff --git a/lib/pbdrv/pb-msg.c b/lib/pbdrv/pb-msg.c index ead9f09..8ffd7cc 100644 --- a/lib/pbdrv/pb-msg.c +++ b/lib/pbdrv/pb-msg.c @@ -3,30 +3,35 @@ #include "pb-msg.h" #include "pb-serial.h" -pbdrv_buf_t pbdrv_msg_write(const pb_msg_t * msg) { - pbdrv_buf_t buf = { 0 }; +pb_buf_t pb_msg_write(const pb_msg_t * msg) { + pb_buf_t buf = { 0 }; mpack_writer_t writer; mpack_writer_init_growable(&writer, &buf.data, &buf.size); - pbdrv_serialize(&writer, msg); + pb_ser_w(&writer, msg); mpack_writer_destroy(&writer); return buf; } -pb_msg_t * pbdrv_msg_read(const pbdrv_buf_t * buf) { +pb_msg_t * pb_msg_read(const pb_buf_t * buf) { mpack_reader_t reader; mpack_reader_init_data(&reader, buf->data, buf->size); pb_msg_t * msg = malloc(sizeof(pb_msg_t)); - pbdrv_deserialize(&reader, msg); + pb_ser_r(&reader, msg); + mpack_reader_destroy(&reader); return msg; } -void pbdrv_msg_free(pb_msg_t * msg) { - pbdrv_free(msg); +void pb_msg_free(pb_msg_t * msg) { + // free message fields recursively + pb_ser_free(msg); + + // free message container that was created in \p pb_msg_read + free(msg); } diff --git a/lib/pbdrv/pb-msg.h b/lib/pbdrv/pb-msg.h index 9823d57..f27d4c4 100644 --- a/lib/pbdrv/pb-msg.h +++ b/lib/pbdrv/pb-msg.h @@ -7,9 +7,9 @@ extern "C" { #endif -pbdrv_buf_t pbdrv_msg_write(const pb_msg_t * msg); -pb_msg_t * pbdrv_msg_read(const pbdrv_buf_t * buf); -void pbdrv_msg_free(pb_msg_t * msg); +pb_buf_t pb_msg_write(const pb_msg_t * msg); +pb_msg_t * pb_msg_read(const pb_buf_t * buf); +void pb_msg_free(pb_msg_t * msg); #ifdef __cplusplus } diff --git a/lib/pbdrv/pb-serial.c b/lib/pbdrv/pb-serial.c index 95bb8fb..9b20bf9 100644 --- a/lib/pbdrv/pb-serial.c +++ b/lib/pbdrv/pb-serial.c @@ -3,68 +3,68 @@ #include "pb-serial.h" #include "pb-types.h" -void pbdrv_serialize(mpack_writer_t * writer, const pb_msg_t * msg) { - pbdrv_sr_msg_header(writer, msg); +void pb_ser_w(mpack_writer_t * writer, const pb_msg_t * msg) { + pb_ser_w_msg_header(writer, msg); if (msg->msg == NULL) return; switch (msg->type) { - case PB_CMD_REQ_READ: return pbdrv_sr_cmd_req_read(writer, msg); - case PB_CMD_RES_READ: return pbdrv_sr_cmd_res_read(writer, msg); + case PB_CMD_REQ_READ: return pb_ser_w_cmd_req_read(writer, msg); + case PB_CMD_RES_READ: return pb_ser_w_cmd_res_read(writer, msg); default: break; } } -void pbdrv_deserialize(mpack_reader_t * reader, pb_msg_t * msg) { - pbdrv_dsr_msg_header(reader, msg); +void pb_ser_r(mpack_reader_t * reader, pb_msg_t * msg) { + pb_ser_r_msg_header(reader, msg); switch (msg->type) { - case PB_CMD_REQ_READ: return pbdrv_dsr_cmd_req_read(reader, msg); - case PB_CMD_RES_READ: return pbdrv_dsr_cmd_res_read(reader, msg); + case PB_CMD_REQ_READ: return pb_ser_r_cmd_req_read(reader, msg); + case PB_CMD_RES_READ: return pb_ser_r_cmd_res_read(reader, msg); default: break; } } -void pbdrv_free(pb_msg_t * msg) { +void pb_ser_free(pb_msg_t * msg) { if (msg == NULL) return; switch (msg->type) { - case PB_CMD_REQ_READ: return pbdrv_free_cmd_req_read(msg); - case PB_CMD_RES_READ: return pbdrv_free_cmd_res_read(msg); + case PB_CMD_REQ_READ: return pb_ser_free_cmd_req_read(msg); + case PB_CMD_RES_READ: return pb_ser_free_cmd_res_read(msg); default: break; } - pbdrv_free_msg_header(msg); + pb_ser_free_msg_header(msg); } -void pbdrv_sr_msg_header(mpack_writer_t * writer, const pb_msg_t * msg) { +void pb_ser_w_msg_header(mpack_writer_t * writer, const pb_msg_t * msg) { mpack_write_u8(writer, msg->type); - // TODO: if pbdrv is compiled under the pbdrv-mod target, place - // PBDRV_MOD_ADDR in this field + // TODO: if pb is compiled under the pb-mod target, place + // PB_MOD_ADDR in this field mpack_write_u16(writer, msg->sender); } -void pbdrv_dsr_msg_header(mpack_reader_t * reader, pb_msg_t * msg) { +void pb_ser_r_msg_header(mpack_reader_t * reader, pb_msg_t * msg) { msg->type = mpack_expect_u8(reader); msg->sender = mpack_expect_u16(reader); } -void pbdrv_free_msg_header(pb_msg_t * msg) { } +void pb_ser_free_msg_header(pb_msg_t * msg) { } -void pbdrv_sr_cmd_req_read(mpack_writer_t * writer, const pb_msg_t * _msg) { +void pb_ser_w_cmd_req_read(mpack_writer_t * writer, const pb_msg_t * _msg) { pb_cmd_req_read_t * msg = _msg->msg; mpack_write_u8(writer, msg->propid); } -void pbdrv_dsr_cmd_req_read(mpack_reader_t * reader, pb_msg_t * _msg) { +void pb_ser_r_cmd_req_read(mpack_reader_t * reader, pb_msg_t * _msg) { pb_cmd_req_read_t * msg = _msg->msg = malloc(sizeof(pb_cmd_req_read_t)); msg->propid = mpack_expect_u8(reader); } -void pbdrv_free_cmd_req_read(pb_msg_t * _msg) { +void pb_ser_free_cmd_req_read(pb_msg_t * _msg) { if (_msg->msg != NULL) { free(_msg->msg); _msg->msg = NULL; } } -void pbdrv_sr_cmd_res_read(mpack_writer_t * writer, const pb_msg_t * _msg) { +void pb_ser_w_cmd_res_read(mpack_writer_t * writer, const pb_msg_t * _msg) { pb_cmd_res_read_t * msg = _msg->msg; mpack_write_u8(writer, msg->propid); mpack_write_bin(writer, (char *) msg->value, msg->_value_size); } -void pbdrv_dsr_cmd_res_read(mpack_reader_t * reader, pb_msg_t * _msg) { +void pb_ser_r_cmd_res_read(mpack_reader_t * reader, pb_msg_t * _msg) { pb_cmd_res_read_t * msg = _msg->msg = malloc(sizeof(pb_cmd_res_read_t)); msg->propid = mpack_expect_u8(reader); @@ -72,7 +72,7 @@ void pbdrv_dsr_cmd_res_read(mpack_reader_t * reader, pb_msg_t * _msg) { msg->value = (uint8_t *) mpack_read_bytes_alloc(reader, msg->_value_size); mpack_done_bin(reader); } -void pbdrv_free_cmd_res_read(pb_msg_t * _msg) { +void pb_ser_free_cmd_res_read(pb_msg_t * _msg) { if (_msg->msg != NULL) { pb_cmd_res_read_t * msg = _msg->msg; if (msg->value != NULL) { diff --git a/lib/pbdrv/pb-serial.h b/lib/pbdrv/pb-serial.h index ac89838..22031dc 100644 --- a/lib/pbdrv/pb-serial.h +++ b/lib/pbdrv/pb-serial.h @@ -9,18 +9,18 @@ extern "C" { #endif #define __pb_cmd(name) \ - pbdrv_serialize_t pbdrv_sr_##name; \ - pbdrv_deserialize_t pbdrv_dsr_##name; \ - pbdrv_free_t pbdrv_free_##name; + pb_ser_r_t pb_ser_r_##name; \ + pb_ser_w_t pb_ser_w_##name; \ + pb_ser_free_t pb_ser_free_##name; -typedef void pbdrv_serialize_t(mpack_writer_t * writer, const pb_msg_t * msg); -pbdrv_serialize_t pbdrv_serialize; +typedef void pb_ser_w_t(mpack_writer_t * writer, const pb_msg_t * msg); +pb_ser_w_t pb_ser_w; -typedef void pbdrv_deserialize_t(mpack_reader_t * reader, pb_msg_t * msg); -pbdrv_deserialize_t pbdrv_deserialize; +typedef void pb_ser_r_t(mpack_reader_t * reader, pb_msg_t * msg); +pb_ser_r_t pb_ser_r; -typedef void pbdrv_free_t(pb_msg_t * msg); -pbdrv_free_t pbdrv_free; +typedef void pb_ser_free_t(pb_msg_t * msg); +pb_ser_free_t pb_ser_free; __pb_cmd(msg_header) __pb_cmd(cmd_req_read) diff --git a/main/i2c.c b/main/i2c.c index 8edb1e8..77f4750 100644 --- a/main/i2c.c +++ b/main/i2c.c @@ -30,7 +30,7 @@ // return array; // } -void pbdrv_i2c_recv(const uint8_t * a, size_t b) { +void pb_i2c_recv(const uint8_t * a, size_t b) { printf("%.*s", b, a); } @@ -45,7 +45,7 @@ void bus_task() { while (true) { vTaskDelay(10 / portTICK_PERIOD_MS); - pbdrv_i2c_send(0x69, (uint8_t *) "bbbbbbbb", 9); + pb_i2c_send(0x69, (uint8_t *) "bbbbbbbb", 9); } // while(1) { diff --git a/main/init.c b/main/init.c index c1b6e9b..2d6f33d 100644 --- a/main/init.c +++ b/main/init.c @@ -32,7 +32,7 @@ static void init_i2c() { gpio_set_function(CFG_SDA_PIN, GPIO_FUNC_I2C); gpio_set_function(CFG_SCL_PIN, GPIO_FUNC_I2C); - pbdrv_setup(); + pb_setup(); } static void async_init() { diff --git a/main/mod.c b/main/mod.c index b34bbc9..b234f97 100644 --- a/main/mod.c +++ b/main/mod.c @@ -1,5 +1,5 @@ #include "pb-mod.h" -const char * PBDRV_MOD_NAME = "main controller"; -const i2c_addr_t PBDRV_MOD_ADDR = 0x20; +const char * PB_MOD_NAME = "main controller"; +const i2c_addr_t PB_MOD_ADDR = 0x20; diff --git a/main/pbdrv.c b/main/pbdrv.c index 9d9e499..323afbe 100644 --- a/main/pbdrv.c +++ b/main/pbdrv.c @@ -1,4 +1,4 @@ -#include "pbdrv.h" +#include "pb.h" #include "pb.h" #include "pb-types.h" @@ -11,7 +11,7 @@ #include #include -#define PBDRV_I2C i2c0 +#define PB_I2C i2c0 #define BUF_SIZE 256 #define MSGS_MAX 4 @@ -23,15 +23,15 @@ typedef struct { static i2c_msg_buf_t msgs[MSGS_MAX]; static size_t msg_index = 0; -static void async_pbdrv_i2c_recv(void * _msg, uint32_t _) { +static void async_pb_i2c_recv(void * _msg, uint32_t _) { i2c_msg_buf_t * msg = _msg; - pbdrv_i2c_recv(msg->data, msg->size); + pb_i2c_recv(msg->data, msg->size); } static void msg_complete(i2c_msg_buf_t * msg) { - // defer pbdrv_i2c_recv call to FreeRTOS scheduler as pbdrv_i2c_recv takes + // defer pb_i2c_recv call to FreeRTOS scheduler as pb_i2c_recv takes // too long to return from an ISR - xTimerPendFunctionCallFromISR(async_pbdrv_i2c_recv, msg, 0, NULL); + xTimerPendFunctionCallFromISR(async_pb_i2c_recv, msg, 0, NULL); // prepare next message for use msg_index = (msg_index + 1) % MSGS_MAX; @@ -45,7 +45,7 @@ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { switch (event) { case I2C_SLAVE_RECEIVE: { if (msg->size == BUF_SIZE) return; - msg->data[msg->size++] = i2c_read_byte_raw(PBDRV_I2C); + msg->data[msg->size++] = i2c_read_byte_raw(PB_I2C); break; } case I2C_SLAVE_FINISH: { @@ -56,17 +56,17 @@ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { } } -void pbdrv_setup() { - i2c_init(PBDRV_I2C, PB_CLOCK_SPEED_HZ); - i2c_slave_init(PBDRV_I2C, PBDRV_MOD_ADDR, &recv_event); +void pb_setup() { + i2c_init(PB_I2C, PB_CLOCK_SPEED_HZ); + i2c_slave_init(PB_I2C, PB_MOD_ADDR, &recv_event); } -__weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { - i2c_set_slave_mode(PBDRV_I2C, false, PBDRV_MOD_ADDR); +__weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { + i2c_set_slave_mode(PB_I2C, false, PB_MOD_ADDR); // false to write stop condition to i2c bus - i2c_write_timeout_us(PBDRV_I2C, addr, buf, sz, false, PB_TIMEOUT_US); + i2c_write_timeout_us(PB_I2C, addr, buf, sz, false, PB_TIMEOUT_US); - i2c_set_slave_mode(PBDRV_I2C, true, PBDRV_MOD_ADDR); + i2c_set_slave_mode(PB_I2C, true, PB_MOD_ADDR); } diff --git a/main/pbdrv.h b/main/pbdrv.h index d0d70c2..0b4ca21 100644 --- a/main/pbdrv.h +++ b/main/pbdrv.h @@ -4,7 +4,7 @@ /** * This is the RP2040 puzzle bus driver. This file is no longer inside - * lib/pbdrv/drv/rp2040 as it is tightly coupled to both the pico-sdk and + * lib/pb//rp2040 as it is tightly coupled to both the pico-sdk and * freertos functions. I have tried to get FreeRTOS to play nicely with the * CMake subproject layout, but the pico-sdk and the rp2040 port of freertos * both rely on CMake's import() functionality, which makes using FreeRTOS in a @@ -19,7 +19,7 @@ extern "C" { #endif //! puzzle bus driver setup -void pbdrv_setup(); +void pb_setup(); /** * While the RP2040's datasheet claims it supports multi-master configurations @@ -33,7 +33,7 @@ void pbdrv_setup(); * the time period between the invocation of this function and the bus becoming * idle (and the message is sent). */ -void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz); +void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz); #ifdef __cplusplus } diff --git a/puzzle/dummy/main.cpp b/puzzle/dummy/main.cpp index 3d84679..ab10760 100644 --- a/puzzle/dummy/main.cpp +++ b/puzzle/dummy/main.cpp @@ -20,17 +20,17 @@ #define MSG_DELAY 10 #endif -const char * PBDRV_MOD_NAME = "dummy"; -const i2c_addr_t PBDRV_MOD_ADDR = ADDR_RX; +const char * PB_MOD_NAME = "dummy"; +const i2c_addr_t PB_MOD_ADDR = ADDR_RX; void setup() { - pbdrv_setup(); + pb_setup(); } void loop() { - pbdrv_i2c_send(ADDR_TX, (uint8_t *) MSG, MSG_SIZE); + pb_i2c_send(ADDR_TX, (uint8_t *) MSG, MSG_SIZE); delay(MSG_DELAY); } -void pbdrv_i2c_recv(const uint8_t * data, size_t size) { } +void pb_i2c_recv(const uint8_t * data, size_t size) { } diff --git a/test/pbdrv/msg.cpp b/test/pbdrv/msg.cpp index 3d2b48d..320d6b3 100644 --- a/test/pbdrv/msg.cpp +++ b/test/pbdrv/msg.cpp @@ -2,7 +2,7 @@ #include "pb-msg.h" -TEST(pbdrv_msg_rw, cmd_req_read) { +TEST(pb_msg_rw, cmd_req_read) { pb_cmd_req_read_t content = { .propid = 2, }; @@ -11,13 +11,13 @@ TEST(pbdrv_msg_rw, cmd_req_read) { .sender = 0xff, .msg = &content, }; - pbdrv_buf_t buf = pbdrv_msg_write(&msg_write); + pb_buf_t buf = pb_msg_write(&msg_write); ASSERT_NE(buf.data, nullptr); ASSERT_GE(buf.size, 0); - pb_msg_t * msg_read = pbdrv_msg_read(&buf); - pbdrv_buf_free(&buf); + pb_msg_t * msg_read = pb_msg_read(&buf); + pb_buf_free(&buf); ASSERT_EQ(buf.data, nullptr); @@ -25,6 +25,6 @@ TEST(pbdrv_msg_rw, cmd_req_read) { EXPECT_EQ(msg_write.sender, msg_read->sender); EXPECT_EQ(((pb_cmd_req_read_t *) msg_write.msg)->propid, ((pb_cmd_req_read_t *) msg_read->msg)->propid); - pbdrv_msg_free(msg_read); + pb_msg_free(msg_read); } -- cgit v1.2.3