Okay, so I'm burning through a bunch of these outstanding items that have been mostly implemented in the background, and now I need to finish in a hurry.
This one is the FPGA that controls power switching of the DC:DC modules that allow the MEGAphone to turn on and off the various sub-systems.
It's requirements are quite simple:
1. Provide an API to the low-power FPGA that controls power to all other modules.
2. Program the low-power FPGA so that it interprets these commands and sends signals to the various DC:DC converters to actually control the power.
3. Provide a mechanism to provide the list of sub-systems in a human-readable and machine parseable that the low-power FPGA knows about, to make it easier for user software to manage.
4. Monitor communications on a second UART, so that events from the cellular modem can be detected.
5. Relay communications from that second UART to the main FPGA.
6. Detect RING and +QIND strings from the cellular modem UART and turn on power to the main FPGA.
7. Log any +QIND strings from the cellular modem UART so that important events (like SMS reception) don't get missed, and the main FPGA knows what to do when it gets turned on.
8. Allow playing back of the log of cellular modem events to the main FPGA.
9. Allow clearing of the log of cellular modem events to the main FPGA.
10. Allow setting the baud rate that the cellular modem monitor uses, to allow setting the cellular modem UART to various speeds.
And then for the software interface:
11. Provide a C library that wraps the API for use by any software that wants to run on the MEGAphone and be power aware.
12. Provide functions that enumerate the various sub-systems.
13. Provide a function that maps a named sub-system or circuit to a circuit ID.
14. Provide functions to query and set the power of each individual sub-system by circuit ID.
15. Provide a function that allows easy retrieval of arbitrary configuration information from the power control FPGA.
This will consist of VHDL for requirements 1-10 above, and C for requirements 11-15.
These are simplifications of the previous requirements, based on the experience we've gained in progressing the project.
The low-power FPGA is an iCESugar Nano. We will be using one GPIO each for the DC:DC converter enable lines, and two GPIOs to make a UART interface for the main FPGA and software to talk to. Electrical isolation of the inter-FPGA interfaces is outside of the scope of this work item.
We'll use the open-source toolchain, so let's make sure it's all installed:
sudo apt install yosys ghdl-gcc yosys-plugin-ghdl gnat nextpnr-ice40 fpga-icestorm
Then we can test synthesis using the blinky "hello world" test that I'll use to populate src/power-control-firmware/
That generates blinky.asc, which can then be copied onto the fake mass-storage device that the iCESugar Nano presents via the USB cable.
We'll tie the USB UART in parallel with two pins for the main FPGA UART to ease debugging. Then we'll have cellular UART pass through (So that the low-power FPGA can intercept RING and other commands that should trigger a wake up of the main FPGA. That's six pins. We'll also have an I2C interface to talk to IO expanders so that we can monitor and control buttons, again, also so that we can trigger waking. But we will also have one button wired directly for robust waking, even if we don't have an I2C IO expander.
Okay, so I've implemented the cellular modem recording whenever a +QIND message occurs (which report SMS arrival among other handy things). The power to the main FPGA is also turned on in that case. Similarly if it sees RING it will turn on the main FPGA power. The power button short press to turn on, and long-press to turn off are also implemented.
The tiny FPGA is _really_ tiny, however, and is already >60% full with just those things.
Fortunately I just need the commands to turn power on and off, which can be done very simply.
The problem now is when I run the design, the ICELink firmware is also listening in on the UART pins and having kittens. Dropping the baud rate I'm using to 115,200 instead of 2Mbps seems to have fixed that problem. I can probably live with that.
But we still see no output from the FPGA's little program. So I'll have a bit of a poke at that.
Okay, fixed that.
Also simplified the cellular modem to main FPGA UART path: We only need one UART RX from the cellular modem in the FPGA, and for convenience, a relay of the cellular modem UART pin through the low-power FPGA and out to the main FPGA, so that we don't have a double load on the UART pin from the cellular modem.
That also means that we can have 6 instead of 4 power circuits.
I've also added a '?' command that reports information about the power control module, including which circuits control which devices.
I'm now writing a utility that lets you talk with this power control interface. This will be compilable on Linux as well as as a native library on the MEGA65 to support development and testing. This utility will support several commands:
config -- report the set of circuits that the module can control.
status -- show the state of each circuit, and whether there have been any cellular modem events since they were last purged
+<n|circuit name> -- turn on circuit n
-<n|circuit name> -- turf circuit n off
celspeed=<baud rate> -- Set the baud rate that the power control system expects the cellular modem UART to be talking at.
celplay -- play back any recorded cellular events
celclear -- clear the cellular recorded events buffer
Okay, so I've got those all implemented -- and the software library behind it to provide a simple API. This has been one of those situations where the challenge has been turning the general idea of what I want to do into something functional and simple. The need to keep the code small for the MEGAphone generally has been a really helpful challenge to work out what each sub-system needs to do, and what they don't need to do.
Requirements Verification
Anyway, it's all there and working now, so let's go back over our set of requirements, show how they are satisfied, and have a bit of a demo at the end.
1. Provide an API to the low-power FPGA that controls power to all other modules.
Okay, so let's tackle this one from a couple of different directions. First, here's the C header with the API (which we'll come back to in more detail later in this list):
https://github.com/MEGA65/megaphone-modular/blob/main/src/power-control-firmware/powerctl.h
Then we have documentation of the API here:
https://github.com/MEGA65/megaphone-modular/blob/main/src/power-control-firmware/README.md
2. Program the low-power FPGA so that it interprets these commands and sends signals to the various DC:DC converters to actually control the power.
Okay, this one we can see in the source for the low-power FPGA:
https://github.com/MEGA65/megaphone-modular/blob/main/src/power-control-firmware/megaphonepwr.vhdl
Sure, there are some other files involved, but the main code for the FPGA is <500 lines, reflecting the work done to make this interface as simple as possible, while still doing everything we need.
3. Provide a mechanism to provide the list of sub-systems in a human-readable and machine parseable that the low-power FPGA knows about, to make it easier for user software to manage.
This is done in a nice simple way in the above VHDL: I have a BRAM which is pre-populated with the contents of a text file, which the VHDL then plays out to the client if they use the '?' command. This means that the FPGA needs very little logic to implement this very helpful feature.
The file that actually gets sent is here:
https://github.com/MEGA65/megaphone-modular/blob/main/src/power-control-firmware/config_message.txt
The content of that is quite simple, but effective:
MEGAphone power management System
---------------------------------
https://github.com/MEGA65/megaphone-modular/tree/main/src/power-control-firmware
Produced with the support of the NLnet Foundation (nlnet.nl)
Commands:
? - Show this message
. - Report current status
P - Playback cellular modem event log
X - Clear cellular modem event log
0-9 - Power circuit (drive enable pin high)
shift 0-9 - De-power circuit (pull enable pin low)
A-G - Select UART speed for cellular modem tap
(2MBPS,1MBPS,230K4,115K2,19K2,9600,2400)
Playback ends with NUL (0x00) character.
Status indication at 0.5Hz (or as requested via '.'):
bit 7 : Always set to 1 (i.e., status bytes are 0x80 -- 0xff)
bit 6 : Set if cellular modem events logged
bits 5-0 : Status of first six power circuits
VER:1
MINOR:0
CIRCUITS:6
0:30:20:01:Main FPGA,LCD,LED,B6
1:31:21:02:Auxilliary device 1,C6
2:32:22:04:Auxilliary device 2,C5
3:33:23:08:Auxilliary device 3,E2
4:34:24:10:Auxilliary device 4,B5
5:35:25:20:Auxilliary device 5,C2
6:50:58:40:Cellular modem event flag
7:2e:2e:80:Status byte indicate
END
The top part of the file is the human readable part (obviously ;) and then below that we have some nice simple CSV lines that are machine parseable, but also still quite readable for a human.
First we have the major (VER) and minor (MINOR) version numbers, so that the library can check that it's talking to a supported version.
Then we have the number of circuits it can control (CIRCUITS), followed by a specification line for each circuit.
Those lines have the circuit ID, then the hex values for the characters to be sent to turn a circuit on or off, and then the bit mask in the status byte that corresponds to this circuit. Then finally we have the list of circuit(s) that it controls. For completeness, I also list the FPGA pin that this corresponds to.
Then for the two virtual circuits 6 and 7 I report what the other 2 bits in the status byte are, with the hex for the cellular modem event log playback (0x50 = 'P') and expunge/clear (0x58 = 'X').
Finally we have the END statement, so that the library knows it's reached the end of the specification, if that's required.
Right now the library assumes that for version 1.0 the hex values are fixed to save code size, but it would be quite easy to use the powerctl_getconfig() function to query those and use them. I will likely improve the library to do exactly that when I get the chance. But it works fine as is.
4. Monitor communications on a second UART, so that events from the cellular modem can be detected.
This is implemented in the FPGA by having a pair of pins that accept the UART's TX line, and then echoes it out on another pin:
-- Cellular modem UART interface
E3 : in std_logic;
-- Pass-through of cellular modem UART interface
E1 : out std_logic;
5. Relay communications from that second UART to the main FPGA.
This is one of those things that is so absurdly simple in an FPGA. It just takes a single line to continually cause the UART line to be copied out at 12MHz, which is more than fast enough for any UART:
-- And simple connection of the rest of the main FPGA to cellular modem
-- route.
E1 <= E3;
6. Detect RING and +QIND strings from the cellular modem UART and turn on power to the main FPGA.
Okay, this is the more complex part of this. First up, we need to implement a UART receiver block to monitor communications:
-- UART that listens to the cellular modem
cellular_uart_rx: entity work.uart_rx
port map (
clk => clk,
bit_rate_divisor => cel_uart_div,
data => cel_rx_data,
data_ready => cel_rx_ready,
data_acknowledge => cel_rx_ack,
uart_rx => E3
);
Then we have to have a way to look for the RING and +QIND strings. It's a bit longer, but in principle very simple once I boiled it down to it's essence:
case cel_rx_data is
when x"52" => -- 'R'
ring_rx_state <= 1;
when x"49" => -- 'I'
if ring_rx_state = 1 then
ring_rx_state <= 2;
else
ring_rx_state <= 0;
end if;
when x"4E" => -- 'N'
if ring_rx_state = 2 then
ring_rx_state <= 3;
else
ring_rx_state <= 0;
end if;
when x"47" => -- 'G'
if ring_rx_state = 3 then
-- Turn on power to main FPGA
LED <= '1';
report_power_status <= '1';
-- Insert that R into the log
cel_log_waddr <= cel_log_waddr + 1;
cel_log_we <= '1';
cel_log_wdata <= x"52"; -- ASCII 'R'
end if;
ring_rx_state <= 0;
when others => null;
end case;
-- And the +QIND detector
case cel_rx_data is
when x"2b" => -- '+'
qind_rx_state <= 1;
when x"51" => -- 'Q'
if qind_rx_state = 1 then
qind_rx_state <= 2;
else
qind_rx_state <= 0;
end if;
when x"49" => -- 'I'
if qind_rx_state = 2 then
qind_rx_state <= 3;
else
qind_rx_state <= 0;
end if;
when x"4E" => -- 'N'
if qind_rx_state = 3 then
qind_rx_state <= 4;
else
qind_rx_state <= 0;
end if;
when x"44" => -- 'D'
if qind_rx_state = 4 then
-- Turn on power to main FPGA
LED <= '1';
report_power_status <= '1';
-- And begin logging what the cellular modem has to say, so that
-- the main FPGA can interrogate us for it once they have powered
-- up. (note that it will skip the +QIND from each line logged, so
-- we put a 'Q' into the log to mark the cause of logging.
-- Log until the next CR or LF
log_cel <= '1';
-- Insert that Q into the log
cel_log_waddr <= cel_log_waddr + 1;
cel_log_we <= '1';
cel_log_wdata <= x"51"; -- ASCII 'Q'
end if;
qind_rx_state <= 0;
when others => null;
end case;
7. Log any +QIND strings from the cellular modem UART so that important events (like SMS reception) don't get missed, and the main FPGA knows what to do when it gets turned on.
Once the above detects these strings, it uses this simple block to record the rest of any line in a +QIND. But the above also inserts a R or Q character to indicate the type of event it's seen.
if cel_rx_ready = '1' and cel_rx_ready_last='0' then
cel_rx_ack <= '1';
cel_rx_data_last <= cel_rx_data;
-- Log output from the modem if required.
-- This continues until the end of a line is encountered
if log_cel = '1' then
-- We don't use the last byte in the cellular data log BRAM,
-- as we need that address free to confirm we have played back to
-- the end without looping back around.
if cel_log_waddr /= CEL_LOG_MAX_ADDR then
cel_log_waddr <= cel_log_waddr + 1;
cel_log_we <= '1';
cel_log_wdata <= std_logic_vector(cel_rx_data);
end if;
if cel_rx_data = x"0d" or cel_rx_data = x"0a" then
log_cel <= '0';
end if;
end if;
8. Allow playing back of the log of cellular modem events to the main FPGA.
Playing the log back is also a fairly simple affair. We check if the 'P' command is received:
case pwr_rx_data is
when x"50" => -- 'P' -- Play back logged cellular data.
if cel_log_waddr /= to_unsigned(0,CEL_LOG_BITS) then
cel_log_playback <= '1';
cel_log_raddr <= to_unsigned(1,CEL_LOG_BITS);
else
-- Nothing in the log, so just indicate that with a NUL byte
pwr_tx_data <= x"00";
pwr_tx_trigger <= '1';
end if;
And if so, that triggers the actual playback, reading from a BRAM where the events were logged:
elsif cel_log_playback = '1' then
if pwr_tx_ready = '1' and pwr_tx_trigger='0' then
pwr_tx_data <= unsigned(cel_log_rdata);
pwr_tx_trigger <= '1';
cel_log_raddr <= cel_log_raddr + 1;
-- If we reached the end of the log, then stop playing back.
if cel_log_raddr > cel_log_waddr then
pwr_tx_data <= x"00";
cel_log_playback <= '0';
cel_log_raddr <= to_unsigned(1,CEL_LOG_BITS);
end if;
else
-- See if we need to send anything else
null;
end if;
end if;
9. Allow clearing of the log of cellular modem events to the main FPGA.
This is even simpler, we just reset the write address into the log if the command is received:
when x"58" => -- 'X' Expunge cellular data log
cel_log_waddr <= to_unsigned(0,CEL_LOG_BITS);
cel_log_playback <= '0';
10. Allow setting the baud rate that the cellular modem monitor uses, to allow setting the cellular modem UART to various speeds.
Okay, this is the last of the VHDL bits, and is again fairly simple: Rather than a full numeric parser, it just supports single-byte commands to select the baud rate from a list of plausible values:
constant UART_DIV_2MBPS : integer := (12_000_000 / 1) / 2_000_000;
constant UART_DIV_1MBPS : integer := (12_000_000 / 1) / 1_000_000;
constant UART_DIV_230K : integer := (12_000_000 / 1) / 230_400;
constant UART_DIV_115K : integer := (12_000_000 / 1) / 115_200;
constant UART_DIV_19200 : integer := (12_000_000 / 1) / 19_200;
constant UART_DIV_9600 : integer := (12_000_000 / 1) / 9_600;
constant UART_DIV_2400 : integer := (12_000_000 / 1) / 2_400;
...
-- Default to 2Mbps for cellular UART
signal cel_uart_div : unsigned(23 downto 0) := to_unsigned(UART_DIV_115K,24);
...
-- Cellular modem tap UART speed set
when x"41" => cel_uart_div <= to_unsigned(UART_DIV_2MBPS,24);
when x"42" => cel_uart_div <= to_unsigned(UART_DIV_1MBPS,24);
when x"43" => cel_uart_div <= to_unsigned(UART_DIV_230K,24);
when x"44" => cel_uart_div <= to_unsigned(UART_DIV_115K,24);
when x"45" => cel_uart_div <= to_unsigned(UART_DIV_19200,24);
when x"46" => cel_uart_div <= to_unsigned(UART_DIV_9600,24);
when x"47" => cel_uart_div <= to_unsigned(UART_DIV_2400,24);
11. Provide a C library that wraps the API for use by any software that wants to run on the MEGAphone and be power aware.
Okay, and now for the software side. Let's start with the header and the functions it provides:
// Power management API
// Get the number of power circuits this unit controls
char powerctl_get_circuit_count(void);
// Retrieve the indicated field for the specified circuit
// e.g., asking for FIELD_CIRCUITNAME will return a human readable description of the
// circuit being controlled
char powerctl_getconfig(char circuit_id,char field_id,unsigned char *out,uint8_t out_len,
int mode);
// Switch a circuit on (non-zero) or off (zero)
char powerctl_switch_circuit(uint8_t circuit_id, char on_off);
// Find the first circuit that contains the specified string in its human-readable name
char powerctl_find_circuit_by_name(char *string);
In short, we can find circuits, and set and get their state and read their config. As is the intention, there is no fat here.
// Cellular event log API
// Set the speed of the tap into the cellular modem UART used to capture
// events that should wake the main FPGA.
// Setting to the incorrect baudrate will disable auto-waking of the main FPGA
// on RING or +QIND events.
// Use AT+QIND to tell the cellular modem which events should be reported, and thus
// should wake the main FPGA.
char powerctl_cel_setbaud(uint32_t speed);
// Clear the cellular modem event log
void powerctl_cellog_clear(void);
// Retrieve the log of cellular modem events
// Returns the number of bytes read. Excess bytes will be discarded.
uint16_t powerctl_cellog_retrieve(uint8_t *out, uint16_t buf_len);
Similarly the cellular event log API is super simple: We can tell it what baud rate the modem is using, and then we can read the event log and clear it. If you read it, and it has nothing in it, then there were no events :)
// Low-level utility functions:
// Synchronise with power control FPGA and return current status byte
uint8_t powerctl_sync(void);
// Verify that the power control system is using a compatible version to this
// library.
// If major and minor are not NULL, then return the major and minor version of the
// power control FPGA firmware
char powerctl_versioncheck(uint8_t *major, uint8_t *minor);
// Commence reading the configuration message from the power control FPGA
char powerctl_start_read_config(void);
And finally we have some low-level functions, in case the user wants to do something particularly low-level.
To demonstrate the use of these functions (and help me with testing, debugging and demonstration), if powerctl.c is compiled with the -DSTANDALONE flag, it also includes a simple command line tool that allows use of all of the functions. There's a video below showing this in action, as I go through how it satisfies the various requirement.
12. Provide functions that enumerate the various sub-systems.
See above. The command line tool uses these functions to show a list of circuits/sub-systems it can control:
else if (!strcmp(argv[i],"config")) {
// Do a first pass to get circuit count
char circuit_count = powerctl_get_circuit_count();
if (!circuit_count) {
fprintf(stderr,"ERROR: Could not read count of controlled circuits\n");
exit(-1);
}
fprintf(stderr,"INFO: System controls %d circuits\n",circuit_count);
for(int circuit_id=0;circuit_id<circuit_count;circuit_id++) {
// Stop when we fail to read info for a circuit
unsigned char field[128];
field[0]=0;
if (powerctl_getconfig(circuit_id,FIELD_CIRCUITNAME,field,sizeof(field),
(circuit_id?GETCONFIG_CONTINUE:GETCONFIG_RESTART))) {
fprintf(stderr,"ERROR: Failed to read information for circuit %d\n",circuit_id);
exit(-1);
}
fprintf(stderr,"INFO: Circuit %d : %s\n",
circuit_id,field);
}
}
13. Provide a function that maps a named sub-system or circuit to a circuit ID.
This function uses the powerctl_getconfig() function to allow searching for circuits by strings:
char powerctl_find_circuit_by_name(char *string)
{
// Do a first pass to get circuit count
char circuit_count = powerctl_get_circuit_count();
if (!circuit_count) {
return 0xff;
}
// Allow specifying circuit by number as well
if (string[0]&&(!string[1])) {
int circuit_id = string[0]-'0';
if (circuit_id>=0&&circuit_id<circuit_count) return circuit_id;
}
for(int circuit_id=0;circuit_id<circuit_count;circuit_id++) {
// Stop when we fail to read info for a circuit
unsigned char field[128];
field[0]=0;
if (powerctl_getconfig(circuit_id,FIELD_CIRCUITNAME,field,sizeof(field),
(circuit_id?GETCONFIG_CONTINUE:GETCONFIG_RESTART))) {
// Failed to read info for this circuit
return 0xff;
}
if (strstr((char *)field,string)) return circuit_id;
}
return 0xff;
}
14. Provide functions to query and set the power of each individual sub-system by circuit ID.
Querying status of circuits is done by obtaining the status byte. This is retrieved by calling powerctl_sync(), as we can see here in the implementation of the status command:
else if (!strcmp(argv[i],"status")) {
uint8_t st = powerctl_sync();
if (!(st&0x80)) {
fprintf(stderr,"ERROR: Failed to read status (received 0x%02x)\n",st);
exit(-1);
}
if (st&0x40) fprintf(stderr,"INFO: Cellular Event(s) Recorded\n");
else fprintf(stderr,"INFO: No Cellular Events Recorded\n");
for(int i=0;i<6;i++) {
if (st&(1<<i)) fprintf(stderr,"INFO: Circuit %d ON\n",i);
else fprintf(stderr,"INFO: Circuit %d OFF\n",i);
}
}
For setting, we have powerctl_switch_circuit(). Again, the example of using this from the command line utility is quite simple:
if (argv[i][0]=='+') {
int circuit_id = powerctl_find_circuit_by_name(&argv[i][1]);
if ((circuit_id<0)||(circuit_id>5)) {
fprintf(stderr,"ERROR: Could not find requested circuit.\n");
exit(-1);
}
if (powerctl_switch_circuit(circuit_id,1)) {
fprintf(stderr,"ERROR: Failed to switch circuit on\n");
exit(-1);
}
}
else if (argv[i][0]=='-') {
int circuit_id = powerctl_find_circuit_by_name(&argv[i][1]);
if ((circuit_id<0)||(circuit_id>5)) {
fprintf(stderr,"ERROR: Could not find requested circuit.\n");
exit(-1);
}
if (powerctl_switch_circuit(circuit_id,0)) {
fprintf(stderr,"ERROR: Failed to switch circuit off\n");
exit(-1);
}
}
15. Provide a function that allows easy retrieval of arbitrary configuration information from the power control FPGA.
We've already seen powerctl_getconfig() above.
Demonstration
The best way to show that this whole thing works is with a demonstration!
The test-rig I am using for this is the low-power IceSugar Nano board (left) connected to a USB UART that is pretending to be the cellular modem (right):
The yellow LED is tied in parallel to the main FPGA power output pin, so if we see that blink we know that it is switching power.Here's me driving it for a few minutes to show the key features:
First up, here's some examples of using the command-line tool:
$ ./powerctl /dev/ttyACM0 115200 config
INFO: System controls 6 circuits
INFO: Circuit 0 : Main FPGA,LCD,LED,B6
INFO: Circuit 1 : Auxilliary device 1,C6
INFO: Circuit 2 : Auxilliary device 2,C5
INFO: Circuit 3 : Auxilliary device 3,E2
INFO: Circuit 4 : Auxilliary device 4,B5
INFO: Circuit 5 : Auxilliary device 5,C2
$ ./powerctl /dev/ttyACM0 115200 status
INFO: No Cellular Events Recorded
INFO: Circuit 0 ON
INFO: Circuit 1 OFF
INFO: Circuit 2 OFF
INFO: Circuit 3 OFF
INFO: Circuit 4 OFF
INFO: Circuit 5 OFF
We can see that circuit 0 (which controls the main FPGA and LCD) is on. So let's try turning it off, and checking that it worked:
$ ./powerctl /dev/ttyACM0 115200 -LCD
$ ./powerctl /dev/ttyACM0 115200 status
INFO: No Cellular Events Recorded
INFO: Circuit 0 OFF
INFO: Circuit 1 OFF
INFO: Circuit 2 OFF
INFO: Circuit 3 OFF
INFO: Circuit 4 OFF
INFO: Circuit 5 OFF
And let's now try turning circuit 4 on by number:
$ ./powerctl /dev/ttyACM0 115200 +4
$ ./powerctl /dev/ttyACM0 115200 status
INFO: No Cellular Events Recorded
INFO: Circuit 0 OFF
INFO: Circuit 1 OFF
INFO: Circuit 2 OFF
INFO: Circuit 3 OFF
INFO: Circuit 4 ON
INFO: Circuit 5 OFF
And it told us there's nothing the cellular event log, but let's take a look anyway:
$ ./powerctl /dev/ttyACM0 115200 celplay
INFO: Cellular event log:
INFO: End of cellular event log
I've then connected a UART to the cellular modem pins on this, and typed a couple of RING messages, as well as a +QIND with some text after it. Let's see if they show up:
First up, we can see that events have been logged:
$ ./powerctl /dev/ttyACM0 115200 status
INFO: Cellular Event(s) Recorded
INFO: Circuit 0 ON
INFO: Circuit 1 OFF
INFO: Circuit 2 OFF
INFO: Circuit 3 OFF
INFO: Circuit 4 ON
INFO: Circuit 5 OFF
And then let's play it back:
$ ./powerctl /dev/ttyACM0 115200 celplay
INFO: Cellular event log:
RRQ A message from the cellular modem.
INFO: End of cellular event log
We can see RRQ at the start, which says 2x RING + 1x QIND, and then we get the body of the QIND following that, in this case "A message from the cellular modem", which is the literal string I typed in when I was pretending to be the cellular modem.
Finally, let's clear the log and check that that worked:
$ ./powerctl /dev/ttyACM0 115200 celclear
$ ./powerctl /dev/ttyACM0 115200 status
INFO: No Cellular Events Recorded
INFO: Circuit 0 ON
INFO: Circuit 1 OFF
INFO: Circuit 2 OFF
INFO: Circuit 3 OFF
INFO: Circuit 4 ON
INFO: Circuit 5 OFF
$ ./powerctl /dev/ttyACM0 115200 celplay
INFO: Cellular event log:
INFO: End of cellular event log
Mapping to Milestones
So we have six milestones tied to these requirements:
1.1b -Power managment effective control of all sub-systems: Implementation
SATISFIED: This is addressed by the implementation described above.
1.1c -Power managment effective control of all sub-systems: Testing
SATISFIED: This is addressed by the demonstration of the correct functioning of the power control FPGA as described and demonstrated in the video above.
1.1d -Power managment effective control of all sub-systems: Revision/Remediation
SATISFIED: This is addressed by the demonstration of the correct functioning of the system as described above. i.e., it is evidence that the necessary revisions and remediation occurred to achieve correct system function.
1.2b -Power managment interface for use by other software: Implementation
SATISFIED: This is addressed by the implementation described above.
1.2c -Power managment interface for use by other software: Testing
SATISFIED: This is addressed by the demonstration of the correct functioning of the system as described above.
1.2d -Power managment interface for use by other software: Revision/Remediation
SATISFIED: This is addressed by the demonstration of the correct functioning of the command-line utility as described above. i.e., it is evidence that the necessary revisions and remediation occurred to achieve correct system function.
In short, we're done and dusted with this part of the design.

No comments:
Post a Comment