12
12
#include < optional>
13
13
#include < type_traits>
14
14
15
- #define KOCHERGA_VERSION_MAJOR 1 // NOLINT NOSONAR
15
+ #define KOCHERGA_VERSION_MAJOR 2 // NOLINT NOSONAR
16
16
#define KOCHERGA_VERSION_MINOR 0 // NOLINT NOSONAR
17
17
18
18
#ifndef KOCHERGA_ASSERT
@@ -543,9 +543,30 @@ class IController
543
543
// / Unifies multiple INode and performs DSDL serialization. Manages the network at the presentation layer.
544
544
class Presenter final : public IReactor
545
545
{
546
+ struct FileLocationSpecifier final
547
+ {
548
+ std::uint8_t local_node_index{};
549
+ NodeID server_node_id{};
550
+ std::size_t path_length{};
551
+ std::array<std::uint8_t , dsdl::File::PathCapacity> path{};
552
+
553
+ struct Pending final
554
+ {
555
+ std::uint64_t offset;
556
+ std::chrono::microseconds response_deadline;
557
+ std::uint8_t remaining_attempts;
558
+ };
559
+ std::optional<Pending> pending;
560
+ };
561
+
546
562
public:
547
- Presenter (const SystemInfo& system_info, IController& controller) :
548
- system_info_ (system_info), controller_(controller)
563
+ struct Params final
564
+ {
565
+ std::uint8_t request_retry_limit;
566
+ };
567
+
568
+ Presenter (const SystemInfo& system_info, IController& controller, const Params& param) :
569
+ par_ (param), system_info_(system_info), controller_(controller)
549
570
{}
550
571
551
572
[[nodiscard]] auto addNode (INode* const node) -> bool
@@ -614,12 +635,20 @@ class Presenter final : public IReactor
614
635
if (file_loc_spec_)
615
636
{
616
637
FileLocationSpecifier& fls = *file_loc_spec_;
617
- if (fls .response_deadline && (uptime > * fls .response_deadline ))
638
+ if (fls .pending && (uptime > fls .pending -> response_deadline ))
618
639
{
619
- INode* const nd = nodes_.at (fls .local_node_index );
620
- nd->cancelRequest ();
621
- fls .response_deadline .reset ();
622
- controller_.handleFileReadResult ({});
640
+ if (fls .pending ->remaining_attempts > 0 )
641
+ {
642
+ fls .pending ->remaining_attempts --;
643
+ fls .pending ->response_deadline = uptime + ServiceResponseTimeout;
644
+ (void ) sendFileReadRequest (fls ); // Ignore the result, we will retry later if possible.
645
+ }
646
+ else
647
+ {
648
+ nodes_.at (fls .local_node_index )->cancelRequest ();
649
+ fls .pending .reset ();
650
+ controller_.handleFileReadResult ({});
651
+ }
623
652
}
624
653
}
625
654
@@ -633,39 +662,21 @@ class Presenter final : public IReactor
633
662
void setNodeHealth (const dsdl::Heartbeat::Health value) { node_health_ = value; }
634
663
void setNodeVSSC (const std::uint8_t value) { node_vssc_ = value; }
635
664
636
- // / The timeout will be managed by the presenter automatically.
665
+ // / The timeout and retries will be managed by the presenter automatically.
666
+ // / No timeout error will be reported until all retries are exhausted.
637
667
[[nodiscard]] auto requestFileRead (const std::uint64_t offset) -> bool
638
668
{
639
669
if (file_loc_spec_)
640
670
{
641
- std::array<std::uint8_t , dsdl::File::ReadRequestCapacity> buf{};
642
-
643
- auto of = offset;
644
- buf[0 ] = static_cast <std::uint8_t >(of);
645
- of >>= BitsPerByte;
646
- buf[1 ] = static_cast <std::uint8_t >(of);
647
- of >>= BitsPerByte;
648
- buf[2 ] = static_cast <std::uint8_t >(of);
649
- of >>= BitsPerByte;
650
- buf[3 ] = static_cast <std::uint8_t >(of);
651
- of >>= BitsPerByte;
652
- buf[4 ] = static_cast <std::uint8_t >(of);
653
-
654
- static constexpr auto length_minus_path = 6U ;
655
- FileLocationSpecifier& fls = *file_loc_spec_;
656
- buf.at (length_minus_path - 1U ) = static_cast <std::uint8_t >(fls .path_length );
657
- (void ) std::memmove (&buf.at (length_minus_path), fls .path .data (), fls .path_length );
658
- INode* const node = nodes_.at (fls .local_node_index );
659
-
660
- read_transfer_id_++;
661
- const bool out = node->sendRequest (ServiceID::FileRead,
662
- fls .server_node_id ,
663
- read_transfer_id_,
664
- fls .path_length + length_minus_path,
665
- buf.data ());
666
- if (out)
671
+ FileLocationSpecifier::Pending pend{};
672
+ pend.offset = offset;
673
+ pend.response_deadline = last_poll_at_ + ServiceResponseTimeout;
674
+ pend.remaining_attempts = par_.request_retry_limit ;
675
+ file_loc_spec_->pending .emplace (pend);
676
+ const bool out = sendFileReadRequest (*file_loc_spec_);
677
+ if (!out)
667
678
{
668
- fls . response_deadline = last_poll_at_ + ServiceResponseTimeout ;
679
+ file_loc_spec_-> pending . reset () ;
669
680
}
670
681
return out;
671
682
}
@@ -836,12 +847,12 @@ class Presenter final : public IReactor
836
847
if (file_loc_spec_ && (response_length >= dsdl::File::ReadResponseSizeMin))
837
848
{
838
849
FileLocationSpecifier& fls = *file_loc_spec_;
839
- if (fls .response_deadline && (fls .local_node_index == current_node_index_))
850
+ if (fls .pending && (fls .local_node_index == current_node_index_))
840
851
{
841
- fls .response_deadline .reset ();
852
+ fls .pending .reset ();
842
853
static const std::array<std::uint8_t , 2 > zero_error{};
843
854
std::optional<dsdl::File::ReadResponse> argument;
844
- if (std::equal (std:: begin (zero_error ), std:: end (zero_error ), response)) // Error = OK
855
+ if (std::equal (zero_error. begin (), zero_error. end (), response)) // Error = OK
845
856
{
846
857
argument = dsdl::File::ReadResponse{
847
858
static_cast <std::uint16_t >(
@@ -882,14 +893,33 @@ class Presenter final : public IReactor
882
893
++tid_heartbeat_;
883
894
}
884
895
885
- struct FileLocationSpecifier
896
+ [[nodiscard]] auto sendFileReadRequest ( FileLocationSpecifier& fls) -> bool
886
897
{
887
- std::uint8_t local_node_index{};
888
- NodeID server_node_id{};
889
- std::size_t path_length{};
890
- std::array<std::uint8_t , dsdl::File::PathCapacity> path{};
891
- std::optional<std::chrono::microseconds> response_deadline{};
892
- };
898
+ std::array<std::uint8_t , dsdl::File::ReadRequestCapacity> buf{};
899
+
900
+ auto of = fls .pending .value ().offset ;
901
+ buf[0 ] = static_cast <std::uint8_t >(of);
902
+ of >>= BitsPerByte;
903
+ buf[1 ] = static_cast <std::uint8_t >(of);
904
+ of >>= BitsPerByte;
905
+ buf[2 ] = static_cast <std::uint8_t >(of);
906
+ of >>= BitsPerByte;
907
+ buf[3 ] = static_cast <std::uint8_t >(of);
908
+ of >>= BitsPerByte;
909
+ buf[4 ] = static_cast <std::uint8_t >(of);
910
+
911
+ static constexpr auto length_minus_path = 6U ;
912
+ buf.at (length_minus_path - 1U ) = static_cast <std::uint8_t >(fls .path_length );
913
+ (void ) std::memmove (&buf.at (length_minus_path), fls .path .data (), fls .path_length );
914
+ INode* const node = nodes_.at (fls .local_node_index );
915
+
916
+ read_transfer_id_++;
917
+ return node->sendRequest (ServiceID::FileRead,
918
+ fls .server_node_id ,
919
+ read_transfer_id_,
920
+ fls .path_length + length_minus_path,
921
+ buf.data ());
922
+ }
893
923
894
924
void beginUpdate (const std::uint8_t local_node_index,
895
925
const NodeID file_server_node_id,
@@ -902,7 +932,7 @@ class Presenter final : public IReactor
902
932
fls .path_length = std::min (app_image_file_path_length, std::size (fls .path ));
903
933
(void ) std::memmove (fls .path .data (), app_image_file_path, fls .path_length );
904
934
905
- if (file_loc_spec_ && file_loc_spec_->response_deadline )
935
+ if (file_loc_spec_ && file_loc_spec_->pending )
906
936
{
907
937
nodes_.at (file_loc_spec_->local_node_index )->cancelRequest ();
908
938
}
@@ -913,6 +943,7 @@ class Presenter final : public IReactor
913
943
914
944
static constexpr std::uint8_t MaxNodes = 8 ;
915
945
946
+ const Params par_;
916
947
const SystemInfo system_info_;
917
948
std::array<INode*, MaxNodes> nodes_{};
918
949
std::uint8_t num_nodes_ = 0 ;
@@ -998,39 +1029,53 @@ enum class Final
998
1029
class Bootloader : public detail ::IController
999
1030
{
1000
1031
public:
1001
- // / The max application image size parameter is very important for performance reasons.
1002
- // / Without it, the bootloader may encounter an unrelated data structure in the ROM that looks like a
1003
- // / valid app descriptor (by virtue of having the same magic, which is only 64 bit long),
1004
- // / and it may spend a considerable amount of time trying to check the CRC that is certainly invalid.
1005
- // / Having an upper size limit for the application image allows the bootloader to weed out too large
1006
- // / values early, greatly improving the worst case boot time.
1007
- // /
1032
+ struct Params final
1033
+ {
1034
+ // / The max application image size parameter is very important for performance reasons.
1035
+ // / Without it, the bootloader may encounter an unrelated data structure in the ROM that looks like a
1036
+ // / valid app descriptor (by virtue of having the same magic, which is only 64 bit long),
1037
+ // / and it may spend a considerable amount of time trying to check the CRC that is certainly invalid.
1038
+ // / Having an upper size limit for the application image allows the bootloader to weed out too large
1039
+ // / values early, improving the worst case boot time.
1040
+ std::size_t max_app_size = std::numeric_limits<std::size_t >::max();
1041
+
1042
+ // / If the linger flag is set, the bootloader will not boot the application after the initial verification.
1043
+ // / If the application is valid, then the initial state will be BootCanceled instead of BootDelay.
1044
+ // / If the application is invalid, the flag will have no effect.
1045
+ // / It is designed to support the common use case where the application commands the bootloader to start and
1046
+ // / sit idle until instructed otherwise, or if the application itself commands the bootloader to begin the
1047
+ // / update. The flag affects only the initial verification and has no effect on all subsequent checks; for
1048
+ // / example, after the application is updated and validated, it will be booted after BootDelay regardless of
1049
+ // / this flag.
1050
+ bool linger = false ;
1051
+
1052
+ // / Wait this much time before booting the application. Keep zero if not sure.
1053
+ std::chrono::seconds boot_delay = std::chrono::seconds::zero();
1054
+
1055
+ // / If the allow_legacy_app_descriptors option is set, the bootloader will also accept legacy descriptors
1056
+ // / alongside the new format. This option should be set only if the bootloader is introduced to a product that
1057
+ // / was using the old app descriptor format in the past; refer to the PX4 Brickproof Bootloader for details. If
1058
+ // / you are not sure, leave the default value.
1059
+ bool allow_legacy_app_descriptors = false ;
1060
+
1061
+ // / The total maximum number of network service requests is this value plus one.
1062
+ // / The counter is reset after every successful request.
1063
+ std::uint8_t request_retry_limit = 5 ;
1064
+ };
1065
+
1008
1066
// / SystemInfo is used for responding to uavcan.node.GetInfo requests.
1009
- // /
1010
- // / If the linger flag is set, the bootloader will not boot the application after the initial verification.
1011
- // / If the application is valid, then the initial state will be BootCanceled instead of BootDelay.
1012
- // / If the application is invalid, the flag will have no effect.
1013
- // / It is designed to support the common use case where the application commands the bootloader to start and
1014
- // / sit idle until instructed otherwise, or if the application itself commands the bootloader to begin the update.
1015
- // / The flag affects only the initial verification and has no effect on all subsequent checks; for example,
1016
- // / after the application is updated and validated, it will be booted after BootDelay regardless of this flag.
1017
- // /
1018
- // / If the allow_legacy_app_descriptors option is set, the bootloader will also accept legacy descriptors alongside
1019
- // / the new format. This option should be set only if the bootloader is introduced to a product that was using
1020
- // / the old app descriptor format in the past; refer to the PX4 Brickproof Bootloader for details. If you are not
1021
- // / sure, leave the default value.
1022
- Bootloader (IROMBackend& rom_backend,
1023
- const SystemInfo& system_info,
1024
- const std::size_t max_app_size,
1025
- const bool linger,
1026
- const std::chrono::seconds boot_delay = std::chrono::seconds(0 ),
1027
- const bool allow_legacy_app_descriptors = false ) :
1028
- max_app_size_ (max_app_size),
1029
- boot_delay_ (boot_delay),
1067
+ // / The lifetime of params is unrestricted as the contents are copied.
1068
+ Bootloader (IROMBackend& rom_backend, const SystemInfo& system_info, const Params& param) :
1069
+ max_app_size_(param.max_app_size),
1070
+ boot_delay_(param.boot_delay),
1030
1071
backend_(rom_backend),
1031
- presentation_ (system_info, *this ),
1032
- linger_ (linger),
1033
- allow_legacy_app_descriptors_ (allow_legacy_app_descriptors)
1072
+ presentation_{
1073
+ system_info,
1074
+ *this ,
1075
+ detail::Presenter::Params{param.request_retry_limit },
1076
+ },
1077
+ linger_ (param.linger),
1078
+ allow_legacy_app_descriptors_(param.allow_legacy_app_descriptors)
1034
1079
{}
1035
1080
1036
1081
// / Nodes shall be registered using this method after the instance is constructed.
0 commit comments