Skip to content

Commit

Permalink
debian
Browse files Browse the repository at this point in the history
  • Loading branch information
igagis committed Mar 2, 2024
1 parent f7f9759 commit e056ded
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 104 deletions.
5 changes: 5 additions & 0 deletions debian/bedsidemon.install.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Since we have only 1 package listed in debian/control file,
# the dh_auto_install will take all files installed
# by "make install" automatically, no need to list them here.

# usr/bin/*
5 changes: 5 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bedsidemon (0.0.1) stable; urgency=low

* Initial release

-- Ivan Gagis <[email protected]> Fri, 23 Feb 2024 13:49:00 +0200
1 change: 1 addition & 0 deletions debian/compat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
10
24 changes: 24 additions & 0 deletions debian/control.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Source: bedsidemon
Section: utils
Priority: extra
Maintainer: Ivan Gagis <[email protected]>
Build-Depends:
debhelper (>= 9),
dpkg-dev (>=1.17.0),
prorab,
prorab-extra,
myci,
clang-tidy,
clang-format,
libtst-dev,
libclargs-dev,
libruisapp-dev
Build-Depends-Indep: doxygen
Standards-Version: 3.9.2

Package: bedsidemon
Section: utils
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Bed side monitor demo app.
Demo application of medical bed side monitor.
16 changes: 16 additions & 0 deletions debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/make -f

export PREFIX := /usr

# dbgsrc_pkg_name := $(filter %-dbgsrc, $(shell awk '/^Package: /{print $2}' debian/control))
# debug_prefix_map_arg := -fdebug-prefix-map=$(shell pwd)/src=$(PREFIX)/src/$(patsubst %-dbgsrc,%,$(dbgsrc_pkg_name))

# export PRORAB_INSTALL_DBGSRC := true

# export DEB_CFLAGS_MAINT_APPEND := $(debug_prefix_map_arg)
# export DEB_CXXFLAGS_MAINT_APPEND := $(debug_prefix_map_arg)
# export DEB_OBJCFLAGS_MAINT_APPEND := $(debug_prefix_map_arg)
# export DEB_OBJCXXFLAGS_MAINT_APPEND := $(debug_prefix_map_arg)

%:
dh $@
1 change: 1 addition & 0 deletions debian/source/format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0 (native)
7 changes: 4 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.

/* ================ LICENSE END ================ */

#include <clargs/parser.hpp>
#include <ruis/layouts/linear_layout.hpp>
#include <ruisapp/application.hpp>

#include <clargs/parser.hpp>

#include "spo2/contec_cms50d_plus.hpp"
#include "spo2/setocare_st_t130_u01.hpp"
#include "spo2/spo2_parameter_window.hpp"
Expand Down Expand Up @@ -95,7 +94,9 @@ const ruisapp::application_factory app_fac([](auto args) {

clargs::parser p;

p.add("window","run in window mode", [&](){window = true;});
p.add("window", "run in window mode", [&]() {
window = true;
});

p.parse(args);

Expand Down
14 changes: 7 additions & 7 deletions src/serial_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ serial_port::serial_port(std::string_view port_filename, baud_rate baud_rate) :
});

// TODO: move setting port config to the class's public method
termios newtermios{0};
newtermios.c_cflag = CBAUD | CS8 | CLOCAL | CREAD;
newtermios.c_iflag = IGNPAR | IGNBRK;
newtermios.c_oflag = 0;
newtermios.c_lflag = 0;
termios newtermios{
.c_iflag = IGNPAR | IGNBRK, //
.c_oflag = 0,
.c_cflag = CBAUD | CS8 | CLOCAL | CREAD,
.c_lflag = 0
};
newtermios.c_cc[VMIN] = 0;
newtermios.c_cc[VTIME] = 0;

ASSERT(size_t(baud_rate) < size_t(baud_rate::enum_size))
speed_t br = baud_rate_map[size_t(baud_rate)];
ASSERT(size_t(baud_rate) < size_t(baud_rate::enum_size)) speed_t br = baud_rate_map[size_t(baud_rate)];
cfsetospeed(&newtermios, br);
cfsetispeed(&newtermios, br);

Expand Down
46 changes: 26 additions & 20 deletions src/spo2/contec_cms50d_plus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void contec_cms50d_plus::request_live_data(uint32_t cur_ticks)
ASSERT(!this->is_sending)

this->last_ticks = cur_ticks;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
this->send({0x7d, 0x81, 0xa1, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80});
this->is_sending = true;
}
Expand All @@ -82,7 +83,7 @@ void contec_cms50d_plus::feed(uint8_t byte)
// ignore any data, it is not supposed to come from disconnected port
break;
case state::idle:
if (byte & 0x80) {
if (byte & utki::bit_7_mask) {
// not a packet type byte,
// need to wait for next packet start,
// ignore
Expand All @@ -91,7 +92,7 @@ void contec_cms50d_plus::feed(uint8_t byte)
this->handle_packet_type_byte(byte);
break;
case state::read_packet_high_bits:
if (!(byte & 0x80)) {
if (!(byte & utki::bit_7_mask)) {
// not a packet body byte, process it as packet type byte
this->state_v = state::idle;
this->handle_packet_type_byte(byte);
Expand Down Expand Up @@ -182,20 +183,18 @@ void contec_cms50d_plus::handle_packet()

if (this->packet_v.type == packet_type::live_data) {
ASSERT(this->packet_v.buffer.size() == live_data_packet_size)
live_data data;

data.signal_strength = this->packet_v.buffer[0] & utki::lower_nibble_mask;
data.searching_time_too_long = (this->packet_v.buffer[0] & utki::bit_4_mask) != 0;
data.pulse_beep = (this->packet_v.buffer[0] & utki::bit_6_mask) != 0;
data.finger_out = (this->packet_v.buffer[0] & utki::bit_7_mask) != 0;

data.waveform_point = this->packet_v.buffer[1] & (~utki::bit_7_mask);
data.searching_pulse = (this->packet_v.buffer[1] & utki::bit_7_mask) != 0;
data.is_pi_data_valid = (this->packet_v.buffer[2] & utki::bit_4_mask) == 0;

data.pulse_rate = this->packet_v.buffer[3];
data.spo2 = this->packet_v.buffer[4];
data.pi = utki::deserialize16le(&this->packet_v.buffer[5]);
live_data data{
.signal_strength = uint8_t(this->packet_v.buffer[0] & utki::lower_nibble_mask),
.searching_time_too_long = (this->packet_v.buffer[0] & utki::bit_4_mask) != 0,
.pulse_beep = (this->packet_v.buffer[0] & utki::bit_6_mask) != 0,
.finger_out = (this->packet_v.buffer[0] & utki::bit_7_mask) != 0,
.searching_pulse = (this->packet_v.buffer[1] & utki::bit_7_mask) != 0,
.is_pi_data_valid = (this->packet_v.buffer[2] & utki::bit_4_mask) == 0,
.waveform_point = uint8_t(this->packet_v.buffer[1] & (~utki::bit_7_mask)),
.pulse_rate = this->packet_v.buffer[3],
.spo2 = this->packet_v.buffer[4],
.pi = utki::deserialize16le(&this->packet_v.buffer[5]), // NOLINT(cppcoreguidelines-avoid-magic-numbers)
};

// std::cout << "signal_strength = " << unsigned(data.signal_strength) << "\n";
// std::cout << "\t" << "searching_time_too_long = " << data.searching_time_too_long << "\n";
Expand All @@ -210,16 +209,20 @@ void contec_cms50d_plus::handle_packet()
// std::cout << std::endl;

uint32_t cur_ticks = utki::get_ticks_ms();
uint16_t delta_time = uint16_t(cur_ticks - this->last_ticks);
auto delta_time = uint16_t(cur_ticks - this->last_ticks);
this->last_ticks = cur_ticks;

using std::min;
using std::max;

constexpr auto max_signal_strength = 10;
constexpr auto min_signal_strength = 4;

this->push(spo2_measurement{
.signal_strength = uint8_t(
(min(max(int(data.signal_strength), 4), 10) - 4) * std::centi::den / 6
), // value is from [4, 10]
(min(max(int(data.signal_strength), min_signal_strength), max_signal_strength) - min_signal_strength) *
std::centi::den / (max_signal_strength - min_signal_strength)
),
.pulse_beat = data.pulse_beep,
.finger_out = data.finger_out,
.waveform_point = float(data.waveform_point),
Expand All @@ -229,11 +232,14 @@ void contec_cms50d_plus::handle_packet()
.delta_time_ms = delta_time
});

constexpr auto sample_rate = 60;
constexpr auto acquisition_time_sec = 30;

// CMS50D+ has limitation of sending live data for only 30 seconds after it was requested.
// Workaround this limitation by requesting live data every ~15 seconds, assuming that it sends
// about 60 live data packets per second.
++this->num_live_data_packages_received;
if (this->num_live_data_packages_received > 60 * 15) {
if (this->num_live_data_packages_received > sample_rate * (acquisition_time_sec / 2)) {
this->num_live_data_packages_received = 0;
this->request_live_data(cur_ticks);
}
Expand Down
17 changes: 12 additions & 5 deletions src/spo2/contec_cms50d_plus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,28 @@ class contec_cms50d_plus :
};

struct packet {
uint8_t high_bits;
packet_type type;
size_t num_bytes_to_read;
uint8_t high_bits{};
packet_type type{packet_type::enum_size};
size_t num_bytes_to_read{};
std::vector<uint8_t> buffer;
} packet_v;

bool is_sending = false;

unsigned num_live_data_packages_received = 0;

uint32_t last_ticks;
uint32_t last_ticks{};

public:
contec_cms50d_plus(utki::shared_ref<spo2_parameter_window> pw, std::string_view port_filename);
~contec_cms50d_plus();

contec_cms50d_plus(const contec_cms50d_plus&) = delete;
contec_cms50d_plus& operator=(const contec_cms50d_plus&) = delete;

contec_cms50d_plus(contec_cms50d_plus&&) = delete;
contec_cms50d_plus& operator=(contec_cms50d_plus&&) = delete;

~contec_cms50d_plus() override;

private:
void on_data_received(utki::span<const uint8_t> data) override;
Expand Down
7 changes: 3 additions & 4 deletions src/spo2/setocare_st_t130_u01.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ setocare_st_t130_u01::setocare_st_t130_u01(utki::shared_ref<spo2_parameter_windo
spo2_sensor(std::move(pw)),
serial_port_thread(port_filename, serial_port_baud_rate)
{
this->state_v = state::wait_packet_first_byte;

this->start();
}

Expand Down Expand Up @@ -143,18 +141,19 @@ void setocare_st_t130_u01::handle_packet()
// std::cout << std::endl;

uint32_t cur_ticks = utki::get_ticks_ms();
uint16_t delta_time = uint16_t(cur_ticks - this->last_ticks);
auto delta_time = uint16_t(cur_ticks - this->last_ticks);
this->last_ticks = cur_ticks;

using std::min;

constexpr uint8_t max_signal_strength = 8;
constexpr auto max_pleth_value = 100;

this->push(spo2_measurement{
.signal_strength = min(signal_strength, max_signal_strength),
.pulse_beat = pulse_beep,
.finger_out = no_finger,
.waveform_point = pleth > 100 ? 50 : float(pleth),
.waveform_point = float(pleth > max_pleth_value ? max_pleth_value / 2 : pleth),
.pulse_rate = pulse_rate,
.spo2 = spo2,
.perfusion_index = 0,
Expand Down
15 changes: 11 additions & 4 deletions src/spo2/setocare_st_t130_u01.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,25 @@ class setocare_st_t130_u01 :
enum_size
};

state state_v = state::disconnected;
state state_v = state::wait_packet_first_byte;

struct packet {
size_t num_bytes_to_read;
size_t num_bytes_to_read{};
std::vector<uint8_t> buffer;
} packet_v;

uint32_t last_ticks;
uint32_t last_ticks{};

public:
setocare_st_t130_u01(utki::shared_ref<spo2_parameter_window> pw, std::string_view port_filename);
~setocare_st_t130_u01();

setocare_st_t130_u01(const setocare_st_t130_u01&) = delete;
setocare_st_t130_u01& operator=(const setocare_st_t130_u01&) = delete;

setocare_st_t130_u01(setocare_st_t130_u01&&) = delete;
setocare_st_t130_u01& operator=(setocare_st_t130_u01&&) = delete;

~setocare_st_t130_u01() override;

private:
void on_data_received(utki::span<const uint8_t> data) override;
Expand Down
15 changes: 10 additions & 5 deletions src/spo2/spo2_parameter_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.

#include "spo2_parameter_window.hpp"

#include <ratio>
#include <vector>

#include <ruis/layouts/linear_layout.hpp>
Expand All @@ -41,10 +42,12 @@ std::vector<utki::shared_ref<ruis::widget>> build_layout(utki::shared_ref<ruis::
using ruis::lp;

constexpr auto color_border = 0xff808080;
constexpr auto color_info_text = 0xff808080;
constexpr auto color_info_text = 0xff808080;
constexpr auto color_main_value = 0xffffff00;
constexpr auto color_secondary_value = 0xff00ffff;

constexpr auto font_size_label = 16;

constexpr auto font_size_main_value_pp = 60;
auto font_size_main_value = c.get().units.pp_to_px(font_size_main_value_pp);

Expand Down Expand Up @@ -98,7 +101,7 @@ std::vector<utki::shared_ref<ruis::widget>> build_layout(utki::shared_ref<ruis::
.color = color_info_text
},
.text_params = {
.font_size = 16
.font_size = font_size_label
}
},
U"SpO2 %"s
Expand Down Expand Up @@ -177,20 +180,22 @@ spo2_parameter_window::spo2_parameter_window(utki::shared_ref<ruis::context> con
void spo2_parameter_window::set(const spo2_measurement& meas)
{
// set oxygenation
if (meas.spo2 == 0 || meas.spo2 > 100) {
if (meas.spo2 == 0 || meas.spo2 > std::centi::den) {
// invalid value
this->spo2_value.set_text("---");
} else {
this->spo2_value.set_text(std::to_string(unsigned(meas.spo2)));
}

constexpr auto bpm_invalid_value = 0xff;

// set bpm
if (meas.pulse_rate == 0 || meas.pulse_rate == 0xff) {
if (meas.pulse_rate == 0 || meas.pulse_rate == bpm_invalid_value) {
// invalid value
this->bpm_value.set_text("---");
} else {
this->bpm_value.set_text(std::to_string(unsigned(meas.pulse_rate)));
}

this->waveform.push(meas.waveform_point, meas.delta_time_ms);
this->waveform.push(meas.waveform_point, meas.delta_time_ms);
}
6 changes: 6 additions & 0 deletions src/spo2/spo2_sensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ class spo2_sensor
public:
spo2_sensor(utki::shared_ref<spo2_parameter_window> pw);

spo2_sensor(const spo2_sensor&) = delete;
spo2_sensor& operator=(const spo2_sensor&) = delete;

spo2_sensor(spo2_sensor&&) = delete;
spo2_sensor& operator=(spo2_sensor&&) = delete;

virtual ~spo2_sensor() = default;

protected:
Expand Down
Loading

0 comments on commit e056ded

Please sign in to comment.