simulator: Make time-scale=0 a cmdline option
Teach the simulator to run with no delays when time-scale=0. Let the user specify the time-scale on the command line.
This commit is contained in:
parent
c7b43782ce
commit
96495fb9bb
3
clock.c
3
clock.c
|
|
@ -80,6 +80,9 @@ void clock() {
|
|||
ifclock(clock_flag_10ms) {
|
||||
clock_10ms();
|
||||
}
|
||||
#ifdef SIMULATOR
|
||||
sim_time_warp();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -156,11 +156,18 @@ void sim_assert(bool cond, const char msg[]);
|
|||
void sim_gcode_ch(char ch);
|
||||
void sim_gcode(const char msg[]);
|
||||
|
||||
void sim_timer_init(void);
|
||||
/**
|
||||
* Initialize simulator timer and set time scale.
|
||||
*
|
||||
* @param scale time slow-down factor; 0=warp-speed, 1=real-time, 2-half-time, etc.
|
||||
*/
|
||||
void sim_timer_init(uint8_t scale);
|
||||
|
||||
void sim_timer_stop(void);
|
||||
void sim_setTimer(void);
|
||||
uint16_t sim_tick_counter(void);
|
||||
uint64_t sim_runtime_ns(void); ///< Simulated run-time in nanoseconds
|
||||
void sim_time_warp(void); ///< skip ahead to next timer interrupt, when time_scale==0
|
||||
|
||||
#define DIO0_PIN "proof of life"
|
||||
|
||||
|
|
|
|||
|
|
@ -74,10 +74,7 @@ void record_pin(int pin, int32_t state, uint64_t t) {
|
|||
|
||||
sim_assert(pin < MAX_PINS, "pin number invalid");
|
||||
|
||||
// Record previous state when new state value appears
|
||||
if ( t != prev_t ) {
|
||||
emit_log_data();
|
||||
}
|
||||
prev_t = t;
|
||||
values[pin] = state;
|
||||
}
|
||||
|
|
@ -87,3 +84,9 @@ void record_comment(const char * msg) {
|
|||
fprintf(file, "# %s\n", msg);
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
void record_raw(const char * msg) {
|
||||
if (!file) return;
|
||||
fprintf(file, "%s", msg);
|
||||
fflush(file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ void recorder_init(const char* filename);
|
|||
void record_pin(int pin, int32_t state, uint64_t time);
|
||||
void add_trace_var(const char* name, int pin);
|
||||
void record_comment(const char * msg);
|
||||
void record_raw(const char * msg);
|
||||
void record_comment_stream(char ch);
|
||||
|
||||
#endif /* DATA_RECORDER_H_ */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
|
||||
// If no time scale specified, use 1/10th real-time for simulator
|
||||
#define DEFAULT_TIME_SCALE 10
|
||||
|
||||
#include "simulator.h"
|
||||
#include "data_recorder.h"
|
||||
|
||||
|
|
@ -40,21 +43,25 @@ int verbose = 1; ///< 0=quiet, 1=normal, 2=noisy, 3=debug, etc.
|
|||
int trace_gcode = 0; ///< show gcode on the console
|
||||
int trace_pos = 0; ///< show print head position on the console
|
||||
|
||||
const char * shortopts = "qvo::";
|
||||
const char * shortopts = "qgpvt:o::";
|
||||
struct option opts[] = {
|
||||
{ "quiet", no_argument, &verbose , 0 },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "gcode", no_argument, NULL, 'g' },
|
||||
{ "pos", no_argument, NULL, 'p' },
|
||||
{ "time-scale", required_argument, NULL, 't' },
|
||||
{ "tracefile", optional_argument, NULL, 'o' }
|
||||
};
|
||||
|
||||
static void usage(const char *name) {
|
||||
printf("Usage: %s [-q || --quiet] [-v [-v] || --verbose[=n]] [-g || --gcode] [-p || --pos] [-o[outfile] || --tracefile[=outfile]] gcode-file || UART-tty\n", name);
|
||||
printf("Usage: %s [options] [gcode_file || uart_device_name]\n", name);
|
||||
printf("\n\n");
|
||||
printf(" -q || --quiet show less output\n");
|
||||
printf(" -v || --verbose show more output\n");
|
||||
printf(" -g || --gcode show gcode on console as it is processed\n");
|
||||
printf(" -p || --pos show head position on console\n");
|
||||
printf(" -o || --tracefile write simulator pin trace to 'outfile' (default filename=datalog.out)\n");
|
||||
printf(" -t || --time-scale=n set time-scale; 0=warp-speed, 1=real-time, 2=half-time, etc.\n");
|
||||
printf(" -o || --tracefile[=filename] write simulator pin trace to 'outfile' (default filename=datalog.out)\n");
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -64,8 +71,9 @@ char** g_argv;
|
|||
void sim_start(int argc, char** argv) {
|
||||
int c;
|
||||
int index;
|
||||
uint8_t time_scale = DEFAULT_TIME_SCALE;
|
||||
|
||||
while ((c = getopt_long (argc, argv, "qgpvo::", opts, &index)) != -1)
|
||||
while ((c = getopt_long (argc, argv, shortopts, opts, &index)) != -1)
|
||||
switch (c) {
|
||||
case 'q':
|
||||
verbose = 0;
|
||||
|
|
@ -79,6 +87,9 @@ void sim_start(int argc, char** argv) {
|
|||
case 'v':
|
||||
verbose += 1;
|
||||
break;
|
||||
case 't':
|
||||
time_scale = (uint8_t) atoi(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
recorder_init(optarg ? optarg : "datalog.out");
|
||||
break;
|
||||
|
|
@ -86,12 +97,23 @@ void sim_start(int argc, char** argv) {
|
|||
sim_error("Unexpected result in getopt_long handler");
|
||||
}
|
||||
|
||||
// Record the command line arguments to the datalog, if active
|
||||
record_raw("# commandline: ");
|
||||
for (index = 0; index < argc; index++) {
|
||||
record_raw(argv[index]);
|
||||
record_raw(" ") ;
|
||||
}
|
||||
record_raw("\n");
|
||||
|
||||
// Store remaining arguments list for serial sim
|
||||
g_argc = argc - optind + 1;
|
||||
g_argv = argv + optind - 1;
|
||||
|
||||
if (argc < 2) usage(argv[0]);
|
||||
|
||||
// Initialize timer
|
||||
sim_timer_init(time_scale);
|
||||
|
||||
// Record pin names in datalog
|
||||
#define NAME_PIN_AXES(x) \
|
||||
add_trace_var(#x "_X" , TRACE_##x + 0); \
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@
|
|||
#include <stdio.h> // printf
|
||||
#include <unistd.h> // usleep
|
||||
|
||||
#define TIME_SLOW_FACTOR 10
|
||||
#define TICKS_TO_US(t) (t / (F_CPU / 1000000))
|
||||
|
||||
static uint16_t time_scale = 1;
|
||||
|
||||
static void schedule_timer(uint32_t useconds);
|
||||
static void timer1_isr(void);
|
||||
|
||||
static bool timer_initialised = false;
|
||||
|
||||
|
|
@ -22,6 +25,8 @@ enum {
|
|||
};
|
||||
|
||||
static volatile uint8_t timer_reason; // Who scheduled this timer
|
||||
static uint64_t ticks;
|
||||
static uint32_t warpTarget;
|
||||
|
||||
static uint64_t now_ns(void) {
|
||||
struct timespec tv;
|
||||
|
|
@ -41,20 +46,40 @@ static uint64_t now_us(void) {
|
|||
return now_ns() / 1000;
|
||||
}
|
||||
|
||||
uint16_t sim_tick_counter(void) {
|
||||
// microseconds to 16-bit clock ticks
|
||||
return (now_us() / TIME_SLOW_FACTOR) US;
|
||||
void sim_time_warp(void) {
|
||||
if (time_scale || timer_reason == 0)
|
||||
return;
|
||||
|
||||
ticks += warpTarget;
|
||||
warpTarget = 0;
|
||||
|
||||
timer1_isr();
|
||||
}
|
||||
|
||||
uint16_t sim_tick_counter(void) {
|
||||
if (time_scale) {
|
||||
// microseconds to 16-bit clock ticks
|
||||
return (now_us() / time_scale) US;
|
||||
}
|
||||
return (uint16_t)(ticks % 0xFFFF);
|
||||
}
|
||||
|
||||
#ifdef SIM_DEBUG
|
||||
extern uint8_t clock_counter_10ms, clock_counter_250ms, clock_counter_1s;
|
||||
#endif
|
||||
|
||||
static uint64_t begin;
|
||||
static uint64_t then;
|
||||
void sim_timer_init(void) {
|
||||
void sim_timer_init(uint8_t scale) {
|
||||
time_scale = scale;
|
||||
then = begin = now_ns();
|
||||
sim_info("timer_init");
|
||||
if (scale==0)
|
||||
sim_info("timer_init: warp-speed");
|
||||
else if (scale==1)
|
||||
sim_info("timer_init: real-time");
|
||||
else
|
||||
sim_info("timer_init: 1/%u time", scale);
|
||||
timer_initialised = true;
|
||||
|
||||
sim_setTimer();
|
||||
}
|
||||
|
||||
void sim_timer_stop(void) {
|
||||
|
|
@ -63,15 +88,23 @@ void sim_timer_stop(void) {
|
|||
}
|
||||
|
||||
uint64_t sim_runtime_ns(void) {
|
||||
return (now_ns() - begin) / TIME_SLOW_FACTOR;
|
||||
if (time_scale)
|
||||
return (now_ns() - begin) / time_scale;
|
||||
return TICKS_TO_US(ticks) * 1000 ;
|
||||
}
|
||||
|
||||
static void timer1_isr(int cause, siginfo_t *HowCome, void *ucontext) {
|
||||
static void timer1_callback(int cause, siginfo_t *HowCome, void *ucontext) {
|
||||
timer1_isr();
|
||||
}
|
||||
|
||||
static void timer1_isr(void) {
|
||||
const uint8_t tr = timer_reason;
|
||||
if ( ! sim_interrupts) {
|
||||
// Interrupts disabled. Schedule another callback in 10us.
|
||||
schedule_timer(10);
|
||||
return;
|
||||
}
|
||||
timer_reason = 0;
|
||||
|
||||
cli();
|
||||
|
||||
|
|
@ -101,9 +134,8 @@ static void timer1_isr(int cause, siginfo_t *HowCome, void *ucontext) {
|
|||
then = now;
|
||||
#endif
|
||||
|
||||
if (timer_reason & TIMER_OCR1A) TIMER1_COMPA_vect();
|
||||
if (timer_reason & TIMER_OCR1B) TIMER1_COMPB_vect();
|
||||
timer_reason = 0;
|
||||
if (tr & TIMER_OCR1A) TIMER1_COMPA_vect();
|
||||
if (tr & TIMER_OCR1B) TIMER1_COMPB_vect();
|
||||
|
||||
sei();
|
||||
|
||||
|
|
@ -125,6 +157,7 @@ void sim_setTimer() {
|
|||
// 0 = No timer; 1-0x10000 = time until next occurrence
|
||||
if ( ! nextA) nextA = 0x10000;
|
||||
}
|
||||
|
||||
if (TIMSK1 & MASK(OCIE1B)) {
|
||||
sim_debug("Timer1 Interrupt B: Enabled");
|
||||
nextB = (OCR1B - now) & 0xFFFF;
|
||||
|
|
@ -134,16 +167,17 @@ void sim_setTimer() {
|
|||
|
||||
//-- Find the nearest event
|
||||
uint32_t next = nextA;
|
||||
if (nextB && ( ! next || (nextB < next))) {
|
||||
if (nextB && ( ! next || (nextB < next)))
|
||||
next = nextB;
|
||||
timer_reason = TIMER_OCR1B;
|
||||
}
|
||||
|
||||
//-- Flag the reasons for the next event
|
||||
timer_reason = 0;
|
||||
if (next == nextA) timer_reason |= TIMER_OCR1A;
|
||||
if (next == nextB) timer_reason |= TIMER_OCR1B;
|
||||
if (next && next == nextA) timer_reason |= TIMER_OCR1A;
|
||||
if (next && next == nextB) timer_reason |= TIMER_OCR1B;
|
||||
|
||||
warpTarget = next ;
|
||||
|
||||
if (time_scale) {
|
||||
// FIXME: We will miss events if they occur like this:
|
||||
// nextA = 0x1000
|
||||
// nextB = 0x1001
|
||||
|
|
@ -154,10 +188,11 @@ void sim_setTimer() {
|
|||
// Maybe store 32-bit tick value for next trigger time for each timer.
|
||||
|
||||
//-- Convert ticks to microseconds
|
||||
long actual = ((unsigned long)next) * TIME_SLOW_FACTOR / (1 US);
|
||||
long actual = ((unsigned long)next) * time_scale / (1 US);
|
||||
if ( next && !actual)
|
||||
actual++;
|
||||
|
||||
|
||||
if (next) {
|
||||
sim_debug("OCR1A:%04X OCR1B:%04X now=%04X", OCR1A, OCR1B, now );
|
||||
sim_debug(" next=%u real=%u", next, actual);
|
||||
|
|
@ -166,6 +201,7 @@ void sim_setTimer() {
|
|||
//-- Schedule the event
|
||||
schedule_timer(actual);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule Timer1 callback useconds from now.
|
||||
// Zero cancels any pending timer.
|
||||
|
|
@ -173,7 +209,8 @@ static void schedule_timer(uint32_t useconds) {
|
|||
struct itimerval itimer;
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_sigaction = timer1_isr;
|
||||
if (time_scale) {
|
||||
sa.sa_sigaction = timer1_callback;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGALRM, &sa, 0)) {
|
||||
|
|
@ -185,3 +222,4 @@ static void schedule_timer(uint32_t useconds) {
|
|||
itimer.it_value.tv_usec = useconds % 1000000;
|
||||
setitimer(ITIMER_REAL, &itimer, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue