-
Notifications
You must be signed in to change notification settings - Fork 1
Core
The primary system structure is the system context, defined in include/upc2/up.h
:
typedef struct up_context_struct {
up_bio_t *bio;
int cur_arg;
int ttyfd;
int ttyflags;
struct termios tc;
int logfd;
int control_mode;
int console_mode;
} up_context_t;
The bio
field is a pointer to the back-end structure. All communications with the target device should go through this structure.
cur_arg
is used by the core logic as an index into the array of parsed arguments it is given. Nothing outside the core should fiddle with it.
The fields ttyfd
, ttyflags
and tc
are all associated with the console. ttyfd
is the file descriptor that should be used for console communications; it has been appropriately doctored to avoid translational problems. The other fields should be left alone; they contain the original state of the console which is restored when upc2 exits.
logfd
is the file descriptor of the log file for output, or -1 if there is no log file. Logging is for serial output, and generally only needs to be done by the core code.
control_mode
is a flag used to catch console escape sequences. The flag is set if the last character read from the console was C-a
.
Finally, console_mode
is a flag controlling the behaviour of the core logic. If set, the core logic will not call the protocol transfer function for the current boot stage, but simply pipes console input through to the back-end output. If clear (i.e. in upload mode), the transfer function is called.
The core logic is implemented by the function up_become_console()
in src/up.c
. It makes certain assumptions about the state of the system when it is called:
- All of the files to be uploaded have been opened, and their file descriptors stored in the
fd
field of the relevantup_load_art_t
entry. - All of the protocols (that will be used) have been initialised.
Processing then proceeds in three stages.
The function up_start_console()
is called to alter the terminal attributes of stdin
to be suitable for a remote console, for example not interpreting C-c
as a SIGINT
. The original attributes are stashed in the system context as described above. If an input socket other than stdin
is to be used, this function will need some changes.
The core logic also calls the prepare
entry point (if any) of the protocol descriptor of the first boot stage in preparation for the main loop, and checks to see if the first boot stage should start in console mode (see below).
The function up_operate_console()
is called repeatedly to operate the core logic. It takes the following steps:
-
The serial input and console input are polled, timing out after a second. The results of the polling are subsequently ignored, so all this really does is introduce slightly random delays and catch comms errors.
-
The serial input is read in a non-blocking manner. If this results in any bytes of input, these are copied to the console output and logged.
-
If the core logic is not in console mode, the
transfer
function for the current protocol is called. If this reports that the upload is finished, it will call thecomplete
entry point of this boot stage and advance to the next boot stage, calling theprepare
entry point of the new protocol and re-evaluating whether the system should be in console mode or not. If there is no file to upload or the boot stage is explicitly flagged as deferred, the system will go into console mode.Note that the transfer function may last for an arbitrarily long time. It is perfectly permissible (and usual) for the entire upload to be done in a single call to the function.
-
The console input is read in a non-blocking manner. If this results in any bytes of input, they are checked for escape sequences (which are removed and interpreted) and then copied to the serial output. (RMJ: arguably the latter should only happen in console mode -- see below.)
The main loop is exited when the function returns a negative value. In practise this is almost always because the user pressed C-a x
.
The core logic finishes up by calling the the complete
entry point of the current (final) boot stage protocol, then calls up_finish_console()
to restore the terminal attributes of the console.
It is presumed that the front-end will call the shutdown
entry of all protocols that it initialised, and close all the files it opened.
The system recognises a number of escape sequences, all beginning with C-a
. Most of these sequences should only be used in console mode, and may or may not be noted in upload mode. The sequences currently recognised are:
-
C-a x
quits the application. This works in all modes. -
C-a C-a
passes a literalC-a
through to the serial back-end. -
C-a l
lists the boot stages parsed by the command-line logic. The current boot stage is indicated with an asterisk. -
C-a 0
selects boot stage 0 as the current boot stage. It remains in console mode; to execute the boot stage, typeC-a c
. Similarly,C-a 1
selects boot stage 1,C-a 2
selects boot stage 2, and so on up toC-a 9
selecting boot stage 9. -
C-a n
selects the next boot stage. Again, it remains in console mode. -
C-a p
similarly selects the previous boot stage. -
C-a c
continues the boot at the current boot stage, switching from console mode into upload mode.
(RMJ: sort out console input reading. Arguably we should not read the console input if we are not in console mode, except by calling utils_check_critical_control()
to catch C-a x
interrupts.)