Skip to content
Rhodri James edited this page Dec 7, 2015 · 9 revisions

Upc2 Core

Core Structures

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.

Core Logic

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 relevant up_load_art_t entry.
  • All of the protocols (that will be used) have been initialised.

Processing then proceeds in three stages.

Start Console

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).

Operate Console

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 the complete entry point of this boot stage and advance to the next boot stage, calling the prepare 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.)

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.

Finish Console

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.

Escapes

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 literal C-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, type C-a c. Similarly, C-a 1 selects boot stage 1, C-a 2 selects boot stage 2, and so on up to C-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.)

Clone this wiki locally