Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
MemoryConfig.cxx
Go to the documentation of this file.
1
36
37#include <fcntl.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <unistd.h>
41#include "openmrn_features.h"
42#include "utils/logging.h"
43#ifdef __FreeRTOS__
44#include "freertos/can_ioctl.h"
45#elif defined(ESP32)
46#include "can_ioctl.h"
47#endif
48
50
51extern "C" {
55void enter_bootloader() __attribute__ ((weak));
57{
58}
59
60#if OPENMRN_FEATURE_REBOOT
62void reboot() __attribute__ ((weak));
63void reboot()
64{
65}
66#endif // OPENMRN_FEATURE_REBOOT
67}
68
69namespace openlcb
70{
71
72#ifdef GTEST
73static constexpr unsigned FACTORY_RESET_REBOOT_DELAY_MSEC = 50;
74#else
75static constexpr unsigned FACTORY_RESET_REBOOT_DELAY_MSEC = 500;
76#endif
77
78uint16_t __attribute__((weak, noinline))
79MemoryConfigHandler::app_handle_factory_reset(NodeID target)
80{
81 return Defs::ERROR_UNIMPLEMENTED;
82}
83
85{
86 if (target == dg_service()->iface()->get_default_node_id())
87 {
89 ->factory_reset();
90 (new RebootTimer(service()))
91 ->start(MSEC_TO_NSEC(FACTORY_RESET_REBOOT_DELAY_MSEC));
92 return 0;
93 }
94 else
95 {
96 return app_handle_factory_reset(target);
97 }
98}
99
101 : fileSize_(len)
102 , name_(nullptr)
103 , fd_(fd)
104{
105 HASSERT(fd_ >= 0);
106}
107
108FileMemorySpace::FileMemorySpace(const char *name, address_t len)
109 : fileSize_(len)
110 , name_(name)
111 , fd_(-1)
112{
113 HASSERT(name_);
114}
115
117{
118 if (fd_ < 0)
119 {
120 int opts = 0;
121 if (read_only()) {
122 opts = O_RDONLY;
123 } else {
124 opts = O_RDWR;
125 }
126#ifdef __FreeRTOS__
127 opts |= O_NONBLOCK;
128#endif
129 fd_ = open(name_, opts);
130 if (fd_ < 0)
131 {
132 LOG(WARNING, "Error opening file %s : %s", name_, strerror(errno));
133 return;
134 }
135 HASSERT(fd_ >= 0);
136 }
137 if (fileSize_ == AUTO_LEN)
138 {
139 struct stat buf;
140 HASSERT(fstat(fd_, &buf) >= 0);
141 fileSize_ = buf.st_size;
142 }
143}
144
145size_t FileMemorySpace::write(address_t destination, const uint8_t *data,
146 size_t len, errorcode_t *error, Notifiable *again)
147{
149 if (fd_ < 0)
150 {
151 *error = Defs::ERROR_PERMANENT;
152 return 0;
153 }
154 off_t actual_position = lseek(fd_, destination, SEEK_SET);
155 if ((address_t)actual_position != destination)
156 {
157 *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
158 return 0;
159 }
160 ssize_t ret = ::write(fd_, data, len);
161 if (ret < 0)
162 {
163 LOG(INFO, "Error writing to fd %d: %s", fd_, strerror(errno));
164 *error = Defs::ERROR_PERMANENT;
165 return 0;
166 }
167 else if ((size_t)ret < len)
168 {
169#ifdef __FreeRTOS__
170 *error = ERROR_AGAIN;
171 HASSERT(ioctl(fd_, CAN_IOC_WRITE_ACTIVE, again) == 0);
172#endif
173 return ret;
174 }
175 else
176 {
177 return ret;
178 }
179}
180
181size_t FileMemorySpace::read(address_t destination, uint8_t *dst, size_t len,
182 errorcode_t *error, Notifiable *again)
183{
185 if (fd_ < 0)
186 {
187 *error = Defs::ERROR_PERMANENT;
188 return 0;
189 }
190 off_t actual_position = lseek(fd_, destination, SEEK_SET);
191 if ((address_t)actual_position != destination)
192 {
193 *error = Defs::ERROR_PERMANENT;
194 return 0;
195 }
196 if (destination >= fileSize_)
197 {
198 *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
199 return 0;
200 }
201 if (destination + len > fileSize_)
202 {
203 len = fileSize_ - destination;
204 }
205 ssize_t ret = ::read(fd_, dst, len);
206 if (ret < 0)
207 {
208 LOG(INFO, "Error reading from fd %d: %s", fd_, strerror(errno));
209 *error = Defs::ERROR_PERMANENT;
210 return 0;
211 }
212 else if (ret == 0)
213 {
214 // EOF
215 *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
216 return 0;
217 }
218 else if ((size_t)ret < len)
219 {
220#ifdef __FreeRTOS__
221 *error = ERROR_AGAIN;
222 HASSERT(ioctl(fd_, CAN_IOC_READ_ACTIVE, again) == 0);
223#endif
224 return ret;
225 }
226 else
227 {
228 return ret;
229 }
230}
231
232} // namespace openlcb
int ioctl(int fd, unsigned long int key,...)
Request and ioctl transaction.
Definition Fileio.cxx:452
void enter_bootloader()
Implement this function (usually in HwInit.cxx) to enter the bootloader.
An object that can schedule itself on an executor to run.
static ConfigUpdateService * instance()
Definition Singleton.hxx:77
Service * service()
Return a pointer to the service I am bound to.
Implementation of the ConfigUpdateService: state flow issuing all the calls to the registered ConfigU...
void ensure_file_open()
Makes fd a valid parameter, and ensures fileSize is filled in.
size_t write(address_t destination, const uint8_t *data, size_t len, errorcode_t *error, Notifiable *again) OVERRIDE
size_t read(address_t source, uint8_t *dst, size_t len, errorcode_t *error, Notifiable *again) OVERRIDE
FileMemorySpace(int fd, address_t len=AUTO_LEN)
Creates a memory space based on an fd.
Used internally by the factory_reset implementation to reboot the binary asynchronously.
Implementation of the Memory Access Configuration Protocol for OpenLCB.
uint16_t handle_factory_reset(NodeID target)
Invokes the openlcb config handler to do a factory reset.
uint16_t app_handle_factory_reset(NodeID target)
Weak definition for invoking a factory reset on virtual nodes.
static const errorcode_t ERROR_AGAIN
This error code signals that the operation was only partially completed, the again notify was used an...
#define CAN_IOC_READ_ACTIVE
read active ioctl.
#define CAN_IOC_WRITE_ACTIVE
write active ioctl.
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int WARNING
Loglevel that is always printed, reporting a warning or a retryable error.
Definition logging.h:55
static const int INFO
Loglevel that is printed by default, reporting some status information.
Definition logging.h:57
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
uint64_t NodeID
48-bit NMRAnet Node ID type
#define MSEC_TO_NSEC(_msec)
Convert a millisecond value to a nanosecond value.
Definition os.h:268