Compare commits

...

10 Commits

Author SHA1 Message Date
c3a855f314 Refactor QUEUE_WAIT_BLOCKING definition for clarity 2025-03-30 20:37:15 +02:00
Fabian
5120926a8a
Merge pull request #29 from p0l0us/water_temp_200_hack
Water temp 200 shown as 80 hack.
2024-04-08 17:47:39 +02:00
Martin Polehla
1086945fe2 Water temp 200 shown as 80 hack. 2024-03-13 11:29:05 +01:00
Your Name
e6fbece988 Add alde detection. 2024-03-10 17:17:06 +01:00
Your Name
a743ee12f8 Ingore last three bytes of truma_message_header #25. 2024-03-10 16:42:12 +01:00
Your Name
70aefdd705 Test MQTT example config 2024-03-10 16:14:34 +01:00
Your Name
2042ceccd1 Fix build issue 2024-03-10 15:37:43 +01:00
Your Name
694f0ffa68 Add config for TRUMA_MSG_QUEUE_LENGTH & TRUMA_LOG_QUEUE_LENGTH 2024-03-10 15:37:37 +01:00
Your Name
adc86f7488 Add jump from READ_STATE_BREAK to READ_STATE_SID. 2024-03-10 15:34:45 +01:00
Your Name
f03d722407 add WomoLinController example. 2023-08-18 15:18:04 +02:00
11 changed files with 567 additions and 16 deletions

View File

@ -0,0 +1,255 @@
esphome:
# https://womolin.de/products/womolin-lin-controller/
name: "womo_lin_controller"
external_components:
- source: github://Fabian-Schmidt/esphome-truma_inetbox
# - source:
# type: local
# path: ./components
components: ["truma_inetbox"]
esp32:
board: esp32dev
framework:
type: arduino
logger:
baud_rate: 2000000
# level: VERY_VERBOSE
# level: VERBOSE
# level: DEBUG
# level: INFO
# level: WARN
level: NONE
ethernet:
type: KSZ8081RNA
mdc_pin: 23
mdio_pin: 18
clk_mode: GPIO16_OUT
uart:
- id: lin_uart_bus
tx_pin: 15
rx_pin: 14
baud_rate: 9600
data_bits: 8
parity: NONE
stop_bits: 2
truma_inetbox:
id: truma_inetbox_id
uart_id: lin_uart_bus
# # Advanced users can use `on_heater_message` action. The heater data is in the `message` variable.
# on_heater_message:
# then:
# - logger.log:
# format: "Message from CP Plus."
# level: INFO
# - if:
# condition:
# lambda: return message->operating_status == truma_inetbox::OperatingStatus::OPERATING_STATUS_OFF;
# then:
# - logger.log:
# format: "Heater is off."
# level: INFO
binary_sensor:
- platform: truma_inetbox
name: "CP Plus alive"
type: CP_PLUS_CONNECTED
id: CP_PLUS_CONNECTED
- platform: truma_inetbox
name: "Room Heater active"
type: HEATER_ROOM
id: HEATER_ROOM
- platform: truma_inetbox
name: "Water Heater active"
type: HEATER_WATER
id: HEATER_WATER
- platform: truma_inetbox
name: "Heater mode Gas"
type: HEATER_GAS
- platform: truma_inetbox
name: "Heater mode Mix 1"
type: HEATER_MIX_1
- platform: truma_inetbox
name: "Heater mode Mix 2"
type: HEATER_MIX_2
- platform: truma_inetbox
name: "Heater mode Elec"
type: HEATER_ELECTRICITY
- platform: truma_inetbox
name: "Heater has error"
type: HEATER_HAS_ERROR
- platform: truma_inetbox
name: "Timer active"
type: TIMER_ACTIVE
id: TIMER_ACTIVE
- platform: truma_inetbox
name: "Timer Room Heater active"
type: TIMER_ROOM
- platform: truma_inetbox
name: "Timer Water Heater active"
type: TIMER_WATER
climate:
- platform: truma_inetbox
name: "Truma Room"
type: ROOM
- platform: truma_inetbox
name: "Truma Water"
type: WATER
number:
- platform: truma_inetbox
name: "Target Room Temperature"
type: TARGET_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Target Water Temperature"
type: TARGET_WATER_TEMPERATURE
- platform: truma_inetbox
name: "electric power level"
type: ELECTRIC_POWER_LEVEL
- platform: truma_inetbox
name: "Aircon Temperature"
type: AIRCON_MANUAL_TEMPERATURE
sensor:
- platform: truma_inetbox
name: "Current Room Temperature"
type: CURRENT_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Current Water Temperature"
type: CURRENT_WATER_TEMPERATURE
- platform: truma_inetbox
name: "Target Room Temperature"
type: TARGET_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Target Water Temperature"
type: TARGET_WATER_TEMPERATURE
- platform: truma_inetbox
name: "Heating mode"
type: HEATING_MODE
- platform: truma_inetbox
name: "electric power level"
type: ELECTRIC_POWER_LEVEL
- platform: truma_inetbox
name: "Energy mix"
type: ENERGY_MIX
- platform: truma_inetbox
name: "Operating status"
type: OPERATING_STATUS
- platform: truma_inetbox
name: "Heater error code"
type: HEATER_ERROR_CODE
switch:
- platform: template
name: "Activate Room Heater"
lambda: |-
return id(HEATER_ROOM).state;
turn_on_action:
- truma_inetbox.heater.set_target_room_temperature:
# You can use lambda functions
temperature: !lambda |-
return 16;
# Optional set heating mode: `"OFF"`, `ECO`, `HIGH`, `BOOST`
heating_mode: ECO
turn_off_action:
- truma_inetbox.heater.set_target_room_temperature:
# Disable heater by setting temperature to `0`.
temperature: 0
- platform: template
name: "Activate Water Heater"
lambda: |-
return id(HEATER_WATER).state;
turn_on_action:
- truma_inetbox.heater.set_target_water_temperature:
# Set water temp as number: `0`, `40`, `60`, `80`
temperature: 40
turn_off_action:
- truma_inetbox.heater.set_target_water_temperature:
# Disable heater by setting temperature to `0`.
temperature: 0
- platform: template
name: "Activate Water Heater (enum)"
lambda: |-
return id(HEATER_WATER).state;
turn_on_action:
- truma_inetbox.heater.set_target_water_temperature_enum:
# Set water temp as text: `"OFF"`, `ECO`, `HIGH`, `BOOST`
temperature: ECO
turn_off_action:
# You can also use the simplified syntax.
- truma_inetbox.heater.set_target_water_temperature_enum: "OFF"
- platform: template
name: "Active Timer"
lambda: |-
return id(TIMER_ACTIVE).state;
turn_on_action:
- truma_inetbox.timer.activate:
start: 7:00
stop: 9:30
# Required: Set room temp to a number between 5 and 30
room_temperature: 13
# Optional: Set heating mode: `"OFF"`, `ECO`, `HIGH`, `BOOST`
heating_mode: ECO
# Optional: Set water temp as number: `0`, `40`, `60`, `80`
water_temperature: 0
# Optional: Set energy mix to: `GAS`, `MIX`, `ELECTRICITY`
energy_mix: GAS
# Optional: Set electricity level to `0`, `900`, `1800`
watt: 0
turn_off_action:
# You can also use the simplified syntax.
- truma_inetbox.timer.disable
button:
- platform: template
name: "Energy mix GAS only"
on_press:
- truma_inetbox.heater.set_energy_mix:
# Set energy mix to: `GAS`, `MIX`, `ELECTRICITY`
energy_mix: GAS
- platform: template
name: "Energy mix MIX 1"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: MIX
# Set electricity level to `0`, `900`, `1800`
watt: 900W
- platform: template
name: "Energy mix MIX 2"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: MIX
watt: 1800
- platform: template
name: "Energy mix ELECTRICITY only"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: ELECTRICITY
watt: 1800W
- platform: template
name: "Set electric power level to 0 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 0
- platform: template
name: "Set electric power level to 900 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 900
- platform: template
name: "Set electric power level to 1800 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 1800
# web_server:
# port: 80
# local: true
# version: 2
# include_internal: true

View File

@ -0,0 +1,260 @@
esphome:
# https://womolin.de/products/womolin-lin-controller/
name: "womo_lin_controller_mqtt"
external_components:
- source: github://Fabian-Schmidt/esphome-truma_inetbox
# - source:
# type: local
# path: ./components
components: ["truma_inetbox"]
esp32:
board: esp32dev
framework:
type: arduino
logger:
baud_rate: 2000000
# level: VERY_VERBOSE
# level: VERBOSE
# level: DEBUG
# level: INFO
# level: WARN
level: NONE
ethernet:
type: KSZ8081RNA
mdc_pin: 23
mdio_pin: 18
clk_mode: GPIO16_OUT
mqtt:
id: mqtt_client
broker: 192.168.1.1
username: womo_lin_controller
uart:
- id: lin_uart_bus
tx_pin: 15
rx_pin: 14
baud_rate: 9600
data_bits: 8
parity: NONE
stop_bits: 2
truma_inetbox:
id: truma_inetbox_id
uart_id: lin_uart_bus
# # Advanced users can use `on_heater_message` action. The heater data is in the `message` variable.
# on_heater_message:
# then:
# - logger.log:
# format: "Message from CP Plus."
# level: INFO
# - if:
# condition:
# lambda: return message->operating_status == truma_inetbox::OperatingStatus::OPERATING_STATUS_OFF;
# then:
# - logger.log:
# format: "Heater is off."
# level: INFO
binary_sensor:
- platform: truma_inetbox
name: "CP Plus alive"
type: CP_PLUS_CONNECTED
id: CP_PLUS_CONNECTED
- platform: truma_inetbox
name: "Room Heater active"
type: HEATER_ROOM
id: HEATER_ROOM
- platform: truma_inetbox
name: "Water Heater active"
type: HEATER_WATER
id: HEATER_WATER
- platform: truma_inetbox
name: "Heater mode Gas"
type: HEATER_GAS
- platform: truma_inetbox
name: "Heater mode Mix 1"
type: HEATER_MIX_1
- platform: truma_inetbox
name: "Heater mode Mix 2"
type: HEATER_MIX_2
- platform: truma_inetbox
name: "Heater mode Elec"
type: HEATER_ELECTRICITY
- platform: truma_inetbox
name: "Heater has error"
type: HEATER_HAS_ERROR
- platform: truma_inetbox
name: "Timer active"
type: TIMER_ACTIVE
id: TIMER_ACTIVE
- platform: truma_inetbox
name: "Timer Room Heater active"
type: TIMER_ROOM
- platform: truma_inetbox
name: "Timer Water Heater active"
type: TIMER_WATER
climate:
- platform: truma_inetbox
name: "Truma Room"
type: ROOM
- platform: truma_inetbox
name: "Truma Water"
type: WATER
number:
- platform: truma_inetbox
name: "Target Room Temperature"
type: TARGET_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Target Water Temperature"
type: TARGET_WATER_TEMPERATURE
- platform: truma_inetbox
name: "electric power level"
type: ELECTRIC_POWER_LEVEL
- platform: truma_inetbox
name: "Aircon Temperature"
type: AIRCON_MANUAL_TEMPERATURE
sensor:
- platform: truma_inetbox
name: "Current Room Temperature"
type: CURRENT_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Current Water Temperature"
type: CURRENT_WATER_TEMPERATURE
- platform: truma_inetbox
name: "Target Room Temperature"
type: TARGET_ROOM_TEMPERATURE
- platform: truma_inetbox
name: "Target Water Temperature"
type: TARGET_WATER_TEMPERATURE
- platform: truma_inetbox
name: "Heating mode"
type: HEATING_MODE
- platform: truma_inetbox
name: "electric power level"
type: ELECTRIC_POWER_LEVEL
- platform: truma_inetbox
name: "Energy mix"
type: ENERGY_MIX
- platform: truma_inetbox
name: "Operating status"
type: OPERATING_STATUS
- platform: truma_inetbox
name: "Heater error code"
type: HEATER_ERROR_CODE
switch:
- platform: template
name: "Activate Room Heater"
lambda: |-
return id(HEATER_ROOM).state;
turn_on_action:
- truma_inetbox.heater.set_target_room_temperature:
# You can use lambda functions
temperature: !lambda |-
return 16;
# Optional set heating mode: `"OFF"`, `ECO`, `HIGH`, `BOOST`
heating_mode: ECO
turn_off_action:
- truma_inetbox.heater.set_target_room_temperature:
# Disable heater by setting temperature to `0`.
temperature: 0
- platform: template
name: "Activate Water Heater"
lambda: |-
return id(HEATER_WATER).state;
turn_on_action:
- truma_inetbox.heater.set_target_water_temperature:
# Set water temp as number: `0`, `40`, `60`, `80`
temperature: 40
turn_off_action:
- truma_inetbox.heater.set_target_water_temperature:
# Disable heater by setting temperature to `0`.
temperature: 0
- platform: template
name: "Activate Water Heater (enum)"
lambda: |-
return id(HEATER_WATER).state;
turn_on_action:
- truma_inetbox.heater.set_target_water_temperature_enum:
# Set water temp as text: `"OFF"`, `ECO`, `HIGH`, `BOOST`
temperature: ECO
turn_off_action:
# You can also use the simplified syntax.
- truma_inetbox.heater.set_target_water_temperature_enum: "OFF"
- platform: template
name: "Active Timer"
lambda: |-
return id(TIMER_ACTIVE).state;
turn_on_action:
- truma_inetbox.timer.activate:
start: 7:00
stop: 9:30
# Required: Set room temp to a number between 5 and 30
room_temperature: 13
# Optional: Set heating mode: `"OFF"`, `ECO`, `HIGH`, `BOOST`
heating_mode: ECO
# Optional: Set water temp as number: `0`, `40`, `60`, `80`
water_temperature: 0
# Optional: Set energy mix to: `GAS`, `MIX`, `ELECTRICITY`
energy_mix: GAS
# Optional: Set electricity level to `0`, `900`, `1800`
watt: 0
turn_off_action:
# You can also use the simplified syntax.
- truma_inetbox.timer.disable
button:
- platform: template
name: "Energy mix GAS only"
on_press:
- truma_inetbox.heater.set_energy_mix:
# Set energy mix to: `GAS`, `MIX`, `ELECTRICITY`
energy_mix: GAS
- platform: template
name: "Energy mix MIX 1"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: MIX
# Set electricity level to `0`, `900`, `1800`
watt: 900W
- platform: template
name: "Energy mix MIX 2"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: MIX
watt: 1800
- platform: template
name: "Energy mix ELECTRICITY only"
on_press:
- truma_inetbox.heater.set_energy_mix:
energy_mix: ELECTRICITY
watt: 1800W
- platform: template
name: "Set electric power level to 0 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 0
- platform: template
name: "Set electric power level to 900 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 900
- platform: template
name: "Set electric power level to 1800 Watt"
on_press:
- truma_inetbox.heater.set_electric_power_level: 1800
# web_server:
# port: 80
# local: true
# version: 2
# include_internal: true

View File

@ -164,6 +164,7 @@ void LinBusListener::onReceive_() {
void LinBusListener::read_lin_frame_() {
u_int8_t buf;
QUEUE_LOG_MSG log_msg = QUEUE_LOG_MSG();
switch (this->current_state_) {
case READ_STATE_BREAK:
// Check if there was an unanswered message before break.
@ -187,14 +188,19 @@ void LinBusListener::read_lin_frame_() {
// Reset current state
this->current_state_reset_();
// First is Break expected
if (!this->read_byte(&buf) || buf != LIN_BREAK) {
// First is Break expected. Arduino platform does not relay BREAK if send as special.
if (!this->read_byte(&buf) || (buf != LIN_BREAK && buf != LIN_SYNC)) {
log_msg.type = QUEUE_LOG_MSG_TYPE::VV_READ_LIN_FRAME_BREAK_EXPECTED;
log_msg.current_PID = buf;
TRUMA_LOGVV_ISR(log_msg);
} else {
// ESP_LOGVV(TAG, "%02X BREAK received.", buf);
this->current_state_ = READ_STATE_SYNC;
if (buf == LIN_BREAK) {
// ESP_LOGVV(TAG, "%02X BREAK received.", buf);
this->current_state_ = READ_STATE_SYNC;
} else if (buf == LIN_SYNC) {
// ESP_LOGVV(TAG, "%02X SYNC found.", buf);
this->current_state_ = READ_STATE_SID;
}
}
break;
case READ_STATE_SYNC:
@ -239,7 +245,6 @@ void LinBusListener::read_lin_frame_() {
this->current_state_ = READ_STATE_BREAK;
return;
}
}
this->read_byte(&buf);
this->current_data_[this->current_data_count_] = buf;
this->current_data_count_++;
@ -249,6 +254,7 @@ void LinBusListener::read_lin_frame_() {
this->current_state_ = READ_STATE_ACT;
}
break;
}
default:
break;
}

View File

@ -15,6 +15,13 @@
#include <queue.h>
#endif // USE_RP2040
#ifndef TRUMA_MSG_QUEUE_LENGTH
#define TRUMA_MSG_QUEUE_LENGTH 6
#endif
#ifndef TRUMA_LOG_QUEUE_LENGTH
#define TRUMA_LOG_QUEUE_LENGTH 6
#endif
namespace esphome {
namespace truma_inetbox {
@ -109,18 +116,18 @@ class LinBusListener : public PollingComponent, public uart::UARTDevice {
void clear_uart_buffer_();
void setup_framework();
uint8_t lin_msg_static_queue_storage[6 * sizeof(QUEUE_LIN_MSG)];
uint8_t lin_msg_static_queue_storage[TRUMA_MSG_QUEUE_LENGTH * sizeof(QUEUE_LIN_MSG)];
StaticQueue_t lin_msg_static_queue_;
QueueHandle_t lin_msg_queue_ =
xQueueCreateStatic(/* uxQueueLength */ 6,
xQueueCreateStatic(/* uxQueueLength */ TRUMA_MSG_QUEUE_LENGTH,
/* uxItemSize */ sizeof(QUEUE_LIN_MSG),
/* pucQueueStorageBuffer */ lin_msg_static_queue_storage, &lin_msg_static_queue_);
#if ESPHOME_LOG_LEVEL > ESPHOME_LOG_LEVEL_NONE
uint8_t log_static_queue_storage[6 * sizeof(QUEUE_LOG_MSG)];
uint8_t log_static_queue_storage[TRUMA_LOG_QUEUE_LENGTH * sizeof(QUEUE_LOG_MSG)];
StaticQueue_t log_static_queue_;
QueueHandle_t log_queue_ =
xQueueCreateStatic(/* uxQueueLength */ 6,
xQueueCreateStatic(/* uxQueueLength */ TRUMA_LOG_QUEUE_LENGTH,
/* uxItemSize */ sizeof(QUEUE_LOG_MSG),
/* pucQueueStorageBuffer */ log_static_queue_storage, &log_static_queue_);
#endif

View File

@ -15,7 +15,7 @@ namespace truma_inetbox {
static const char *const TAG = "truma_inetbox.LinBusListener";
#define QUEUE_WAIT_BLOCKING (portTickType) portMAX_DELAY
#define QUEUE_WAIT_BLOCKING portMAX_DELAY
void LinBusListener::setup_framework() {
// uartSetFastReading

View File

@ -139,9 +139,15 @@ enum class ClockSource : u_int8_t {
CLOCK_SOURCE_PROG = 0x2,
};
enum class TRUMA_COMPANY : u_int8_t {
UNKNOWN = 0x00,
TRUMA = 0x1E,
ALDE = 0x1A,
};
enum class TRUMA_DEVICE : u_int8_t {
UNKNOWN = 0x00,
// Saphir Compact AC
AIRCON_DEVICE = 0x01,
@ -160,7 +166,7 @@ enum class TRUMA_DEVICE : u_int8_t {
HEATER_COMBI6D = 0x06,
};
enum class TRUMA_DEVICE_STATE : u_int8_t{
enum class TRUMA_DEVICE_STATE : u_int8_t {
OFFLINE = 0x00,
ONLINE = 0x01,
};

View File

@ -132,11 +132,15 @@ const u_int8_t *TrumaiNetBoxApp::lin_multiframe_recieved(const u_int8_t *message
if (message_len < truma_message_header.size()) {
return nullptr;
}
for (u_int8_t i = 1; i < truma_message_header.size(); i++) {
if (message[i] != truma_message_header[i]) {
for (u_int8_t i = 1; i < truma_message_header.size() - 3; i++) {
if (message[i] != truma_message_header[i] && message[i] != alde_message_header[i]) {
return nullptr;
}
}
if (message[4] != (u_int8_t) this->company_) {
ESP_LOGI(TAG, "Switch company to 0x%02x", message[4]);
this->company_ = (TRUMA_COMPANY) message[4];
}
if (message[0] == LIN_SID_READ_STATE_BUFFER) {
// Example: BA.00.1F.00.1E.00.00.22.FF.FF.FF (11)

View File

@ -52,6 +52,7 @@ class TrumaiNetBoxApp : public LinBusProtocol {
u_int8_t message_counter = 1;
// Truma heater conected to CP Plus.
TRUMA_COMPANY company_ = TRUMA_COMPANY::TRUMA;
TRUMA_DEVICE heater_device_ = TRUMA_DEVICE::UNKNOWN;
TRUMA_DEVICE aircon_device_ = TRUMA_DEVICE::UNKNOWN;

View File

@ -5,10 +5,11 @@ namespace esphome {
namespace truma_inetbox {
static const char *const TAG = "truma_inetbox.water_climate";
void TrumaWaterClimate::setup() {
this->parent_->get_heater()->add_on_message_callback([this](const StatusFrameHeater *status_heater) {
// Publish updated state
this->target_temperature = temp_code_to_decimal(status_heater->target_temp_water);
this->target_temperature = water_temp_200_fix(temp_code_to_decimal(status_heater->target_temp_water));
this->current_temperature = temp_code_to_decimal(status_heater->current_temp_water);
this->mode = (status_heater->target_temp_water == TargetTemp::TARGET_TEMP_OFF) ? climate::CLIMATE_MODE_OFF
: climate::CLIMATE_MODE_HEAT;

View File

@ -27,6 +27,13 @@ float temp_code_to_decimal(u_int16_t val, float zero) {
return ((float) val) / 10.0f - 273.0f;
}
float water_temp_200_fix(float val) {
if (val == 200) {
return 80;
}
return val;
}
float temp_code_to_decimal(TargetTemp val, float zero) { return temp_code_to_decimal((u_int16_t) val, zero); }
TargetTemp decimal_to_temp(u_int8_t val) { return (TargetTemp) ((((u_int16_t) val) + 273) * 10); }

View File

@ -5,14 +5,18 @@
namespace esphome {
namespace truma_inetbox {
// First byte is service identifier and to be ignored.
// First byte is service identifier and to be ignored. Last three bytes can be `xFF` or `x00` (see
// <https://github.com/Fabian-Schmidt/esphome-truma_inetbox/issues/25>).
// `truma_message_header` and `alde_message_header` must have the same size!
const std::array<u_int8_t, 11> truma_message_header = {0x00, 0x00, 0x1F, 0x00, 0x1E, 0x00,
0x00, 0x22, 0xFF, 0xFF, 0xFF};
const std::array<u_int8_t, 11> alde_message_header = {0x00, 0x00, 0x1F, 0x00, 0x1A, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF};
u_int8_t addr_parity(const u_int8_t pid);
u_int8_t data_checksum(const u_int8_t *message, u_int8_t length, uint16_t sum);
float temp_code_to_decimal(u_int16_t val, float zero = NAN);
float temp_code_to_decimal(TargetTemp val, float zero = NAN);
float water_temp_200_fix(float val);
TargetTemp decimal_to_temp(u_int8_t val);
TargetTemp decimal_to_temp(float val);
TargetTemp decimal_to_room_temp(u_int8_t val);