Commit Graph

1846 Commits

Author SHA1 Message Date
Neels Hofmeyr 1c24962946 sockaddr_str: add conversion to,from osmo_sockaddr
Add functions to pass struct osmo_sockaddr to the
osmo_sockaddr_str_{to,from}* API directly.

So far the interface to osmo_sockaddr_str_ is:

  osmo_sockaddr_str_from_sockaddr(&my_sa_str, &my_osa->u.sas);

I'm working a lot with osmo_sockaddr at the moment, and the cumulated
time of forgetting to add 'u.sas' and having another compilation cycle
because of those is justifying this additional API.

Change-Id: I0df84b4bb8cb5d8434b735fa3a38e7f95be43e91
2024-03-28 03:42:07 +01:00
Eric Wild 43018ec161 Revert "Revert "logging: add log level cache""
This reverts commit 7f1fb3ea81 - slightly
amended with the new log_cache_enalbe() function.  The cache is hence
disabled by default, and applications can enable it, if they wish to
benefit from it.

Reason for the original revert was: some fallout expected due to log
manipulation in test code

Change-Id: I539872fc9e3c50b407e6bc388f1e091fa2c826c3
2024-03-20 14:57:13 +01:00
Harald Welte e988ec3b53 osmo_io: Massive improvement of API documentation
* introduce a new "Osmocom I/O interface" group to show up in API docs
* expand the documentation to turn it into something useful for somebody
  wanting to write an application using it.

Change-Id: I6315cfc7ff34a0f8971517edf035e1efcef3ed5c
2024-03-19 14:08:26 +01:00
Harald Welte b0db6495c5 ctrl: re-introduce duplicate declaration of ctrl_cmd_send()
In Change-Id Ic81af56e7ea6921ba39168727ef64c308e9c6754 we removed
the duplicate declaration of ctrl_cmd_send(), which was declared
both in control_if.h and in control_cmd.h.  Unfortunately  this broke
legacy openbsc.git, so let's re-introduce it.

Change-Id: I1d415c5e80cfb7ef9e11d33c0c3eaece40ebb1da
2024-03-12 14:36:22 +01:00
Harald Welte 09ab041b42 osmo_io: Log error message in case call-backs incompatible with mode
Change-Id: I50ba6a76c0144f249d67488874a6c4edf01ec6f2
2024-03-07 15:51:48 +01:00
Harald Welte 4f155022d8 cbsp: Add osmo_cbsp_segmentation_cb for message segmentation
This call-back can for example be used as segmentation call-back
for libosmo-netif stream_cli/stream_srv or directly for osmo_io.

Related: OS#5755
Change-Id: I5e922c54b3431d759b38e81e55076125c5a34008
2024-03-02 20:48:23 +01:00
Harald Welte 319a77e519 ctrl: Don't expose write_queue in ctrl_cmd_send() api
ctrl_cmd_send() should always have taken a 'struct ctrl_connection'
as argument, not directly its write_queue member.

Let's offer a ctrl_cmd_send2() which fixes the problem, and deprecate
the old ctrl_cmd_send().

Related: OS#5751
Change-Id: Ic81af56e7ea6921ba39168727ef64c308e9c6754
2024-03-02 18:59:16 +01:00
Harald Welte f574aea38f osmo_io: Add osmo_io_get_ioops() function
This function can be used by user code to obtain the currently-set io
operations, it's the inverse of osmo_io_set_ioops().

Change-Id: I03398c811b9534f50c6644b21eea89a04be29fb0
2024-02-29 09:15:43 +01:00
Harald Welte 1047ed7255 osmo_io: sendmsg/recvmsg support
Add support osmo_io operations resembling sendmsg() and recvmsg() socket
operations.  This is what will enable the implementation of higher-layer
functions like equivalents of sctp_recvmsg() and sctp_send() in
libosmo-netif and/or other users.

Change-Id: I89eb519b22d21011d61a7855b2364bc3c295df82
Related: OS#5751
2024-02-28 16:42:57 +01:00
Alexander Couzens 3938dfba5c gsup.h: define newly added PCO IE
PCO - Protocol Configuration Options 3GPP TS 24.008 / 10.5.6.3.
The PCO will be used by the osmo-epdg to pass PCO internally.
The PCO will be passed towards to the PGW in the Session Request.

Related: OS#6369
Related: osmo-gsm-manuals.git Change-Id Id912ead4e1205f84a40af6505a5ddf050d1e086d
Change-Id: I0f9de90c7c67fe194b441a9d118eba70f09afb5e
2024-02-27 17:08:18 +00:00
Harald Welte b365b1d094 osmo_io: Change struct osmo_io_ops to contain struct, not union
As we introduce more modes, and each mode aliases call-back function
pointers to those of another mode, we have more and more error cases
where we (for exampele) access read_cb, but in reality the user has
populated recvfrom_cb.

Let's use a struct, meaning that call-backs of one mode no longer alias
to the same memory locations of call-backs fro another mode.  This
allows us to properly check if the user actually provided the right
callbacks for the given mode of the iofd.

This breaks ABI, but luckily not API.  So a simple recompile of
higher-layer library + application code will work.

Change-Id: I9d302df8d00369e7b30437a52deb205f75882be3
2024-02-23 18:01:36 +01:00
Neels Hofmeyr 99d6acb52a comment: gsm_04_08.h: add a spec hint
Change-Id: I2a606047db88ea47317397a790611048dead6403
2024-02-06 02:14:32 +01:00
Matan Perelman 0df28e0779 ctrl: Add lchan node
Change-Id: Ibf2786f668ee7e4f5b6a9ef43f2141cd2d79b4e2
2024-01-30 18:31:26 +02:00
Vadim Yanitskiy 4a3d03e6e5 gsm: add more definitions from Table 10.5.112/3GPP TS 24.008
Change-Id: I25e40853ace09fa98b614f3893eeba600be8fcdc
Related: OS#4396
2024-01-25 17:23:17 +00:00
Pau Espin 74ee02420a gsup: Convert PDP-Type IE to PDP-Address IE
The previous PDP-Type IE should have been a PDP-Address from the
start, since having only PDP-Type with no address is only a specific
case (dynamic addressing).
This becomes clear by looking at other similar protocols like:
* MAP: APN-Configuration IE has servedPartyIP-IP{v4,v6}-Address IEs
* Diameter S6b, 3GPP TS 29.272 7.3.35 APN-Configuration contains
  Served-Party-IP-Address AVPs
* Diameter SWx, 3GPP TS 29.273 APN-Configuration.
* GTPv1C Ts 29.060 7.7.29 PDP Context containing PDP Address.

Since PDP-Type on its own really makes no sense, being it a special case
of PDP-Address, let's keep the IE by renaming it (keeping old name too
for API backward compat) and extend it to support lengths > 2 bytes.

Old implementation of libosmogsm gsup actually ignored lengths > 2
bytes, so we are safe acting against older implementations here, both
on the sending and receiving side on the wire.

The big drawback of this commit is that it breaks ABI compatibility due
to adding "struct osmo_sockaddr pdp_address[2];" to struct
osmo_gsup_pdp_info, which in turn affects shift of fields in struct
osmo_gsup_message. Unfortunately, there's not much that can be done to
improve the situation when adding the missing field, due to existing API
having the same struct for all messages. Ideally we'd have 1 union with
structs per message type inside, this way the ABI break would be far
less pronounced.

The GSUP test output change is becaue we now accept some of the len>2
cases for PDP-Type/Address IE which were being rejected since a couple
commits ago.

libosmogsm gsup code is now disabled in EMBEDDED mode, since it nows
depends on core/socket.h (struct osmo_sockaddr) which is not available
in EMBEDDED, and hence fails during build:
"""
In file included from /build/include/osmocom/gsm/gsup.h:45,
                 from /build/src/gsm/gsup_sms.c:28:
/build/include/osmocom/core/socket.h:15:10: fatal error: arpa/inet.h: No such file or directory
   15 | #include <arpa/inet.h>
      |          ^~~~~~~~~~~~~
"""

Related: OS#6091
Change-Id: I775ff9c3be165d9f30d6ab55d03f99b6104eadd6
2024-01-20 00:31:28 +01:00
Pau Espin 68a04dfc88 gsup: Deprecate field pdp_type in favour of pdp_type_nr and pdp_type_org
Having both fields in an uin16_t integer makes it difficult and
confusing for users for no good reason. Let's have separate fields for
each of them.

The new fields are defined so that they are ABI compatible with previous
uin16 field.

Change-Id: Ie31c6080c90e468c01186259f2c42621e39b5cc6
2024-01-20 00:31:28 +01:00
Pau Espin f196b889dc gsm_04_08_gprs.h: Introduce packed struct gsm48_pdp_address
This can be used in several protocols, such as GTP, GSUP, etc.

Related: OS#6091
Change-Id: I453ced42dd36df3a6ddb5db67093df5a22cad18c
2024-01-20 00:31:23 +01:00
Pau Espin 8dfdfc38ad cosmetic: gsup.h: fix whitespace formatting
Change-Id: Icd5e38db1b99889ad15a2a4cbb83393292a54180
2024-01-18 17:23:56 +00:00
Vadim Yanitskiy 06922fad6c isdn: add a lookup table with E1/E2/E3 bits from Table 5/V.110
Let's make those E1/E2/E3 bit combinations publicly available in
form of a lookup table (key is enum osmo_v100_sync_ra1_rate).
Add convenience macros for setting and comparing these bits.
This lookup table will be used by osmocom-bb.git.

Change-Id: I6d2f8e250df31c233a2741163113dc07515409ae
Related: OS#4396
2024-01-16 20:04:00 +07:00
Eric Wild 7f1fb3ea81 Revert "logging: add log level cache"
This reverts commit 7dc6d4a629.

Reason for revert: other tests are failing

Change-Id: Ife4c49d1bb933e983ac68c57970c9c49b40e08be
2024-01-09 16:37:05 +00:00
Eric Wild 7dc6d4a629 logging: add log level cache
This ensures multithreaded logging attempts, in particular ones that do
nothing, do not hold the lock just for checking the level, which
interferes with other logging attempts.

Closes: OS#5818

Change-Id: I35f8dd9127dd6e7feae392094fd6b3ce2d32558d
2024-01-09 15:28:29 +00:00
Vadim Yanitskiy 85554db38d isdn: initial implementation of the V.110 TA
ITU-T recommendation V.110 defines Terminal Adaptor (TA) functions
for the connection of Terminal Equipment (TE) having standard V-series
interfaces to the ISDN.  This patch brings "software" implementation
of the TA to libosmoisdn.

The primary user for this soft-TA is the mobile-side implementation
of CSD (Circuit Switched Data) in osmocom-bb.  CSD is heavily based
on V.110, which is not surprising given that GSM is a "wireless ISDN".
Nevertheless, this code will likely also be useful in the context
of retro-networking.

Similarly to the existing V.110 code in libosmoisdn, the present
implementation aims to be functional and correct, rather than
efficient in any way.  It also has several limitations, which are
not critical for the CSD use case, but eventually may be a problem
for other use cases in the context of retro-networking.

Therefore, the V.110 TA API should be considered _unstable_,
and may be subject to change in the future.

  +-------+      +------+   B-channel   +------+      +-------+
  |  TE1  |------|  TA  |~~~~~~~~~~~~~~~|  TA  |------|  TE2  |
  +-------+      +------+               +------+      +-------+

TE (also known as DTE) is basically a computer, having a V-series
(usually RS-232) connection to TA (also known as DCE).  The TA acts
like a regular analog modem, except that it is not performing any
kind of modulation or demodulation itself.

The TE-TA interface is implemented by the user supplied callback
functions, configured during the allocation of a TA instance:

* .rx_cb() - receive call-back of the application,
* .tx_cb() - transmit call-back of the application,
* .status_update_cb() - status line update call-back.

In addition to that, the application (TE) can interact with the
V.24 status lines (circuits) using the following API:

* osmo_v110_ta_{get,set}_status(),
* osmo_v110_ta_{get,set}_circuit().

The Rx and Tx between TE and TA is always driven by the TA itself,
as a result of an interaction with the lower layer implementing
the B-channel interface.  There is currently no buffering and thus
no way for TE to initiate transmission or pull data on its own.

The TA-TA (B-channel) interface is implemented by the following
functions, which are meant to be called by the lower layer
transmitting and receiving V.110 frames over certain medium:

* osmo_v110_ta_frame_in() - indicate a received V.110 frame,
* osmo_v110_ta_frame_out() - pull a V.110 frame for transmission,
* osmo_v110_ta_[de]sync_ind() - indicate a synchronization event.

The lower layer is responsible for finding the synchronization
pattern (if needed), aligning to the frame boundaries, and doing
the V.110 frame coding.

The D-channel signalling is behind the scope of this module.

Initial (Work-in-Progress) implementation by Harald Welte,
completed and co-authored by Vadim Yanitskiy.

Change-Id: I5716bd6fd0201ee7a7a29e72f775972cd374082f
Related: OS#4396
2024-01-09 13:11:04 +00:00
Vadim Yanitskiy b71f461263 fsm: fix OSMO_T_FMT_ARGS: add missing braces
Change-Id: I3ea7cbc8a51d310d9929ca5a805eb1d3d3880793
2024-01-09 13:11:04 +00:00
Vadim Yanitskiy 83c8c8002f core: osmo_tdef_fsm_inst_state_chg(): allow millisecond precision
This API predates commit 7b74551b9, which added support for millisecond
granularity to osmo_fsm.  Let's do the same for the tdef FSM wrapper
API, allowing the millisecond precision without rounding-up to seconds.

Of course, this patch changes behavior of the existing API, but having
more precise state timeouts is not going to make the API user
experience worse.

The old behavior of using seconds is for kept for:

* OSMO_TDEF_CUSTOM -- still treated as if it was OSMO_TDEF_S.
* \param[in] default_timeout -- still expected to be in seconds.

Change-Id: I4c4ee89e7e32e86f74cd215f5cbfa44ace5426c1
Related: 7b74551b9 "fsm: Allow millisecond granularity in osmo_fsm built-in timer"
2024-01-09 13:11:04 +00:00
Vadim Yanitskiy fb4ce0b029 utils: fix -Wsign-compare in definition of OSMO_STRBUF_CHAR_COUNT
We're seeing tons of -Wsign-compare warnings since I merged 0f59cebf:

include/osmocom/core/utils.h: In function 'size_t _osmo_strbuf_char_count(const osmo_strbuf*)':
include/osmocom/core/utils.h:24:29: error: comparison of integer expressions of different
                                    signedness: 'long int' and 'long unsigned int'
                                    [-Werror=sign-compare]
   24 | #define OSMO_MIN(a, b) ((a) >= (b) ? (b) : (a))
      |                         ~~~~^~~~~~
include/osmocom/core/utils.h:309:16: note: in expansion of macro 'OSMO_MIN'
  309 |         return OSMO_MIN(sb->pos - sb->buf, sb->len - 1);
      |                ^~~~~~~~

Interestingly enough, this -Wsign-compare problem has always been the
case, even before commit 0f59cebf.  And somehow this did not show up
when building libosmocore.git, but only when building C++ projects
(osmo-pcu and osmo-trx).

Perhaps it has something to do with how g++ compiles extern "C" code.

Change-Id: I8e396459409e4260b8715f9e890e8972d4609a31
Fixes: 0f59cebf "utils: improve readability of OSMO_STRBUF_CHAR_COUNT"
2023-12-31 16:59:40 +07:00
Vadim Yanitskiy 0f59cebf08 utils: improve readability of OSMO_STRBUF_CHAR_COUNT
Similarly to OSMO_STRBUF_REMAIN, let's improve the code readability
by adding a static inline function.  We should generally prefer using
static inline functions over macros, unless there is something that
only the proprocessor can do.

Change-Id: I71f24b87c13fd83952029171a6993f8da5e32e5b
2023-12-30 16:14:38 +00:00
Vadim Yanitskiy 9df820bf9b utils: fix OSMO_STRBUF_REMAIN to handle sb.pos == NULL correctly
Currently, OSMO_STRBUF_REMAIN would return a huge number if the given
strbuf has its .pos pointer set to NULL.  This macro is safe against
the .buf pointer being NULL, but not against .pos being NULL.

Fix this by adding a static inline function (for the sake of code
readability) and handle .pos being NULL properly by returning length
of the buffer.  Add a unit test.

Change-Id: I294a74a99c40995cf7fb5520d61f697d967be5a4
2023-12-30 16:14:38 +00:00
Pau Espin a37921aed1 socket: Introduce defines OSMO_SOCK_MULTIADDR_{PEER_STR,NAME}_MAXLEN
These values end up being used by API users of
osmo_sock_multiaddr_get_name_buf() and
osmo_multiaddr_ip_and_port_snprintf().

Change-Id: I18a0e1a652a3e8ef3e97154355eb1d07a14ef0bd
2023-12-12 14:00:12 +01:00
Pau Espin 19f27bb551 socket: Introduce API osmo_sock_sctp_get_peer_addr_info()
This is a convenience helper to reetrieve the whole set of remote
addresses and call getsockopt() on them, making it easy for users to
analyse the full set of remote addresses of a socket simply providing an
fd.

Related: SYS#6636
Change-Id: I3e1c84526b006baff435bbbca49dc6cf7d201cf5
2023-12-11 11:11:16 +01:00
Pau Espin 5ac8aa5852 socket: Introduce API osmo_sock_multiaddr_get_name_buf()
An extra osmo_multiaddr_ip_and_port_snprintf() API is introduced which
is used by osmo_sock_multiaddr_get_name_buf() but which will also be
used by other app uers willing to use
osmo_sock_multiaddr_get_ip_and_port() according to its needs (eg. only
printing the local side).

Related: SYS#6636
Change-Id: I48950754ed6f61ee5ffa04a447fab8903f10acc0
2023-12-07 13:23:06 +00:00
Pau Espin 6a2975c858 socket: Introduce API osmo_sock_multiaddr_get_ip_and_port()
This API will be used internally by osmo_sock_multiaddr_get_name_buf()
in a follow-up patch.
This API can also be used directly by user who wish to obtain a list of
local/remote IP addresses and port from an SCTP socket.

Related: SYS#6636
Related: OS#5581
Change-Id: I19d560ab4aadec18a4c0f94115675ec1d7ab14d7
2023-12-07 13:23:06 +00:00
Neels Hofmeyr d511a9d664 util: add osmo_strbuf macros to manipulate the strbuf tail
Upcoming patch adopts osmo_strbuf in logging.c, which sometimes needs to
steal and re-add trailing newline characters, and also needs to let
ctime_r() write to the buffer before updating the osmo_strbuf state.

Related: OS#6284
Related: Ib577a5e0d7450ce93ff21f37ba3262704cbf4752
Change-Id: I997707c328eab3ffa00a78fdb9a0a2cbe18404b4
2023-12-07 04:52:16 +01:00
Neels Hofmeyr 271baad068 util: add OSMO_STRBUF_REMAIN()
This code already exists twice, and upcoming patch will need this as
well in logging.c. Add a macro to remove the code dup.

Related: OS#6284
Related: Ib577a5e0d7450ce93ff21f37ba3262704cbf4752
Change-Id: I6f2991125882bff948708bbb4ae218f9f3d1e50c
2023-12-07 04:52:16 +01:00
Vadim Yanitskiy 6587dd0abb soft_uart: implement modem status lines and flow control
Change-Id: I26b93ce76f2f6b6fbf017f2684312007db3c6d48
Related: OS#4396
2023-12-04 04:23:07 +07:00
Vadim Yanitskiy 275c86e7ee soft_uart: improve doxygen documentation
Change-Id: I415a5e5392a7f91da4bf117d59694278779acc94
Related: OS#4396
2023-12-04 03:14:33 +07:00
Vadim Yanitskiy 59afb8f14c soft_uart: add osmo_soft_uart_{get,set}_name()
Change-Id: Iabf29f42d876035481011fa8e8a51c0590fe63b8
Related: OS#4396
2023-12-03 02:19:33 +00:00
Harald Welte be3c38ca55 Add a GSM RLP decoder and encoder
This code implements a decoder and encoder for the RLP (Radio Link
Protocol) as used in the bearer channel of GSM CSD (Circuit Switched
Data).

Change-Id: I2d9bd8eb4f0cd0f72c436996767b199429596917
2023-11-29 14:35:36 +00:00
Andreas Eversberg 285f3693de Add flag to enable RTS based polling
RTS based polling in LAPDm code is disabled by default. Make libosmogsm
stay compatible with existing applications that do not use RTS based
polling.

This patch fixes the issue that LAPDM_ENT_F_POLLING_ONLY did enable RTS
based polling too, which breaks existing applications like older
versions of osmo-bts.

Change-Id: I2a75c192bbc24e85bfc1656b2be21cea7a92814a
2023-11-29 14:19:48 +01:00
Andreas Eversberg 5560c040bd Fix union abis_rsl_chan_nr and abis_rsl_link_id
All bit fields in a union will overlap in memory, as all elements in a
union do. To prevent the bit fields from overlapping, wrap them into a
packed structure.

Change-Id: I5ef5aa62be8310da4ebe9ea73ebbedcbcc2ba49c
2023-11-29 10:15:33 +00:00
Alexander Couzens 505f70552a gsup: add message type for osmo-epdg CEAI interface
The CEIA interface is an interface between osmo-epdg and
strongswan.
It is used by the osmo-epdg to synchronize state.

Related: OS#6091
Change-Id: I6f7c20340c99f94b1326a8a7dc99c86cf6a0dbc3
2023-11-28 17:05:22 +00:00
Andreas Eversberg bd2b897b72 LAPDm: Add a flag to enable suppression of subsequent REJ frame
This behaviour was default in earlier versions of LAPDm/LAPD. Because it
is only required for osmocom-bb, a flag is added to enable it there.

Related: OS#5969
Change-Id: I93994dbbd1fc2c9edb8f3015c6b18ecd0fce0565
2023-11-27 16:25:53 +00:00
Andreas Eversberg f51f916e1c LAPDm: Add an extra queue for UI frames
The extra queue is used to transmit the UI frame only when there is no
frame in the regular TX queue. This allows to give LAPD frames prioity
over UI frame.

Related: OS#4074
Change-Id: I00c8ee73be8b7c564a4dee3fca3e893484f567da
2023-11-27 16:25:53 +00:00
Andreas Eversberg 2d7119d85b LAPDm: Add support for RTS based polling
The lower layer must set the 'POLLING_ONLY' flag and provide frame
number when polling a frame. If T200 is pending, it is started with a
timeout frame number in advance to given frame number.

The lower layer must call lapdm_t200_fn() after a frame has been
received or if a frame has not been received. Also it must be called
after a TCH frame has been received. LAPDm uses this to check the T200
timeout condition.

A new function is used to set the frame number based timeout values.

Related: OS#4074
Change-Id: I6ebe83f829d7751ea9de1d90eb478c7a628db64c
2023-11-27 16:25:53 +00:00
Andreas Eversberg 49b7087360 LAPD: Add support for RTS based polling and T200
The T200 timer is started when the current frame is polled at
PH-READY-TO-SEND event.

A flag is used to enable this feature. The user of LAPD core must track
frame numbers to check the timeout condition. Then it must call the
external timeout function.

Related: OS#4074
Change-Id: Ib961b5a44911b99b0487641533301749c0286995
2023-11-27 16:25:53 +00:00
Vadim Yanitskiy d4b94ceb88 soft_uart: fix spelling in doxygen docs
Change-Id: Ib719d1fe4ee6c058860e861c91ec2417d9dff0af
2023-11-24 03:00:02 +07:00
Harald Welte 38d8170fa4 osmo_io: rename unsupported SCTP mode to OSMO_IO_FD_MODE_SCTP_RECVMSG_SEND
The two functions of the SCTP socket interface we use in osmo-* are
sctp_send() and sctp_recvmsg().  We do not use sctp_sendmsg() at all,
so let's make sure the mode is named correctly.

Change-Id: Ie2d1c7ce6f211dbe025a0e843ad733443102ea15
Related: OS#5751
2023-11-22 12:20:12 +00:00
Harald Welte 641cc3c60d add new osmo_sockaddr_from_str_and_uint() function
The function is basically a shortcut for getaddrinfo with storing the
output data into our 'struct osmo_sockaddr'.

Change-Id: I6b5c0bf8ca97e6358d992fb2ff45ffd53ba15197
Related: SYS#6657
2023-11-22 12:18:26 +00:00
Vadim Yanitskiy 0d78a00b9f soft_uart: implement OSMO_SUART_PARITY_{MARK,SPACE}
Change-Id: I4c8fe5bfdcc2f4eb52c259d1e62d06684cd8f823
Related: OS#4396
2023-11-21 20:17:11 +07:00
Vadim Yanitskiy 03f0ed78ef soft_uart: allow manually flushing the receive buffer
Change-Id: Id600a2db99e6cb84866cbdcfcd4f78265e067291
Related: OS#4396
2023-11-21 18:50:09 +07:00
Vadim Yanitskiy c9fc77f541 soft_uart: implement the transmitter
Change-Id: Ibcd9643227e5616efd8bbd7a1430feda6fcef45c
Related: OS#4396
2023-11-21 00:58:53 +07:00