From 3028b297f31fa805db4c6f5077e1c3edb0ca5099 Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Mon, 18 Oct 2010 20:15:59 +0200 Subject: [PATCH] Add simulation code: use "make sim" --- Makefile | 22 ++++++++++ analog_sim.c | 17 ++++++++ clock_sim.c | 56 ++++++++++++++++++++++++ config.h.dist | 4 +- dda.c | 15 ++++++- dda_queue.c | 4 +- delay_sim.c | 15 +++++++ heater.c | 4 +- heater.h | 1 + mendel.c | 22 +++++++--- serial.h | 8 +++- serial_sim.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ sersendf.c | 16 ++++--- sersendf.h | 5 ++- simulation.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ simulation.h | 81 +++++++++++++++++++++++++++++++++++ temp.c | 6 ++- temp.h | 2 +- timer.h | 5 ++- timer_sim.c | 50 ++++++++++++++++++++++ 20 files changed, 531 insertions(+), 23 deletions(-) create mode 100644 analog_sim.c create mode 100644 clock_sim.c create mode 100644 delay_sim.c create mode 100644 serial_sim.c create mode 100644 simulation.c create mode 100644 simulation.h create mode 100644 timer_sim.c diff --git a/Makefile b/Makefile index d7b516b..4d78957 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,7 @@ program: $(PROGRAM).hex config.h clean: rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~ + rm -f sim size: $(PROGRAM).elf @echo " SIZE Atmega168 Atmega328p Atmega644" @@ -123,3 +124,24 @@ config.h: config.h.dist %.sym: %.elf @echo " SYM $@" @$(OBJDUMP) -t $< | perl -ne 'BEGIN { printf " ADDR NAME SIZE\n"; } /([0-9a-f]+)\s+(\w+)\s+O\s+\.(bss|data)\s+([0-9a-f]+)\s+(\w+)/ && printf "0x%04x %-20s +%d\n", eval("0x$$1") & 0xFFFF, $$5, eval("0x$$4")' | sort -k1 > $@ + + +############################################################################## +# # +# Simulation # +# # +############################################################################## + +SIM_SOURCES = $(PROGRAM).c serial_sim.c dda.c gcode.c timer_sim.c clock_sim.c temp.c sermsg.c dda_queue.c debug.c sersendf.c heater.c analog_sim.c delay_sim.c simulation.c +SIM_HEADERS = config.h serial.h dda.h gcode.h timer.h clock.h temp.h sermsg.h dda_queue.h debug.h sersendf.h heater.h analog.h delay.h simulation.h + +SIM_OBJ = $(patsubst %.c,%.sim.o,${SIM_SOURCES}) +SIM_CFLAGS = -g -Wall -Wstrict-prototypes -Os $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fshort-enums + +%.sim.o: %.c $(SIM_HEADERS) + @echo " CC $@" + @cc -DDEBUG -DSIMULATION -c $(SIM_CFLAGS) -o $@ $< + +sim: $(SIM_OBJ) + @echo " LINK $@" + @cc $(SIM_CFLAGS) -o $@ $^ diff --git a/analog_sim.c b/analog_sim.c new file mode 100644 index 0000000..d781547 --- /dev/null +++ b/analog_sim.c @@ -0,0 +1,17 @@ +#include "analog.h" +#include "simulation.h" + +static bool analog_initialised = false; +void analog_init(void) +{ + sim_info("analog_init: not implemented in simulation"); + analog_initialised = true; +} + +uint16_t analog_read(uint8_t channel) +{ + sim_assert(analog_initialised, "analog_init() was not called before analog_read()"); + sim_assert(sim_interrupts, "interrupts disabled"); + return 0; +} + diff --git a/clock_sim.c b/clock_sim.c new file mode 100644 index 0000000..f43612a --- /dev/null +++ b/clock_sim.c @@ -0,0 +1,56 @@ +#include +#include +#include + +#include "clock.h" +#include "simulation.h" + +static uint8_t clock_counter_250ms = 0; +static uint8_t clock_counter_1s = 0; +volatile uint8_t clock_flag = 0; + +static bool clock_initialised = false; +#define SIM_CLOCK_SLOWDOWN 50 + +static void timer2_isr(int cause, siginfo_t *HowCome, void *ucontext) +{ + if (!sim_interrupts) return; + + sim_interrupts = false; + + // 1/4 second tick + if (++clock_counter_250ms == 250 / SIM_CLOCK_SLOWDOWN) { + clock_flag |= CLOCK_FLAG_250MS; + clock_counter_250ms = 0; + if (++clock_counter_1s == 4) { + clock_flag |= CLOCK_FLAG_1S; + clock_counter_1s = 0; + } + } + + sim_interrupts = true; +} + +void clock_setup(void) +{ + struct itimerval itimer; + struct sigaction sa; + long unsigned int usec = 1000 * SIM_CLOCK_SLOWDOWN; + + sim_info("clock_setup: simulate timer 2 ISR at %luus", usec); + sa.sa_sigaction = timer2_isr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGPROF, &sa, 0)) { + sim_error("sigaction"); + } + + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 1000 * SIM_CLOCK_SLOWDOWN; + itimer.it_value.tv_sec = 0; + itimer.it_value.tv_usec = 1000 * SIM_CLOCK_SLOWDOWN; + setitimer(ITIMER_PROF, &itimer, NULL); + + clock_initialised = true; +} + diff --git a/config.h.dist b/config.h.dist index e1d0c55..1d144c7 100644 --- a/config.h.dist +++ b/config.h.dist @@ -132,7 +132,9 @@ - comment out pins not in use, as this drops the corresponding code and makes operations faster */ -#include "arduino.h" +#ifndef SIMULATION + #include "arduino.h" +#endif /* RESERVED pins diff --git a/dda.c b/dda.c index d079df4..c72716b 100644 --- a/dda.c +++ b/dda.c @@ -1,7 +1,10 @@ #include "dda.h" #include -#include + +#ifndef SIMULATION + #include +#endif #include "timer.h" #include "serial.h" @@ -333,7 +336,15 @@ void dda_create(DDA *dda, TARGET *target) { } if (debug_flags & DEBUG_DDA) { - sersendf_P(PSTR("\n{DDA:CA end_c:%lu, n:%ld, md:%lu, ssq:%lu, esq:%lu, dsq:%lu, msbssq:%u, msbtot:%u}\n"), dda->end_c >> 8, dda->n, move_duration, ssq, esq, dsq, msb_ssq, msb_tot); + sersendf_P(PSTR("\n{DDA:CA end_c:%lu, n:%ld, md:%lu, ssq:%lu, esq:%lu, dsq:%lu, msbssq:%u, msbtot:%u}\n"), + (long unsigned int)dda->end_c >> 8, + (long int)dda->n, + (long unsigned int)move_duration, + (long unsigned int)ssq, + (long unsigned int)esq, + (long unsigned int)dsq, + msb_ssq, + msb_tot); } dda->accel = 1; diff --git a/dda_queue.c b/dda_queue.c index fb3edb2..5c1916d 100644 --- a/dda_queue.c +++ b/dda_queue.c @@ -1,7 +1,9 @@ #include "dda_queue.h" #include -#include +#ifndef SIMULATION + #include +#endif #include "config.h" #include "timer.h" diff --git a/delay_sim.c b/delay_sim.c new file mode 100644 index 0000000..a2d1f0c --- /dev/null +++ b/delay_sim.c @@ -0,0 +1,15 @@ +#include + +#include "delay.h" +#include "simulation.h" + +void delay(uint32_t us) +{ + usleep(us); +} + +void delay_ms(uint32_t ms) +{ + usleep(ms * 1000); +} + diff --git a/heater.c b/heater.c index 320d3c9..819896a 100644 --- a/heater.c +++ b/heater.c @@ -2,7 +2,9 @@ #ifdef HEATER_PIN -#include +#ifndef SIMULATION + #include +#endif #include "sersendf.h" #include "debug.h" diff --git a/heater.h b/heater.h index 1e1a201..345eeac 100644 --- a/heater.h +++ b/heater.h @@ -2,6 +2,7 @@ #define _HEATER_H #include "config.h" +#include "simulation.h" #ifdef HEATER_PIN diff --git a/mendel.c b/mendel.c index 59ab865..cd54e8b 100644 --- a/mendel.c +++ b/mendel.c @@ -1,6 +1,7 @@ - -#include -#include +#ifndef SIMULATION + #include + #include +#endif #include "config.h" @@ -17,6 +18,7 @@ #include "sersendf.h" #include "heater.h" #include "analog.h" +#include "simulation.h" void io_init(void) { // disable modules we don't use @@ -127,10 +129,20 @@ void clock_250ms(void) { ifclock(CLOCK_FLAG_1S) { if (debug_flags & DEBUG_POSITION) { // current position - sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F); + sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"), + (long int)current_position.X, + (long int)current_position.Y, + (long int)current_position.Z, + (long int)current_position.E, + (long unsigned int)current_position.F); // target position - sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"), movebuffer[mb_tail].endpoint.X, movebuffer[mb_tail].endpoint.Y, movebuffer[mb_tail].endpoint.Z, movebuffer[mb_tail].endpoint.E, movebuffer[mb_tail].endpoint.F); + sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"), + (long int)movebuffer[mb_tail].endpoint.X, + (long int)movebuffer[mb_tail].endpoint.Y, + (long int)movebuffer[mb_tail].endpoint.Z, + (long int)movebuffer[mb_tail].endpoint.E, + (long unsigned int)movebuffer[mb_tail].endpoint.F); // Queue print_queue(); diff --git a/serial.h b/serial.h index cd6a54f..fa23a16 100644 --- a/serial.h +++ b/serial.h @@ -2,8 +2,12 @@ #define _SERIAL_H #include -#include -#include + +#ifndef SIMULATION + #include + #include +#endif +#include "simulation.h" // initialise serial subsystem void serial_init(void); diff --git a/serial_sim.c b/serial_sim.c new file mode 100644 index 0000000..558b0ea --- /dev/null +++ b/serial_sim.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +#include "serial.h" +#include "simulation.h" + +static int serial_fd; +static bool serial_initialised = false; + +void serial_init(void) +{ + struct termios options; + + // hack to get argv and argc + extern char ** environ; + int argc = 1; + char **argv = environ - 3; + + while((int)*argv != argc) + { + ++argc; + --argv; + } + argv++; + + sim_assert(argc >= 2, "please specify a serial port device name"); + + sim_info("opening serial port %s", argv[1]); + serial_fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY); + sim_assert(serial_fd != -1, "couldn't open serial port"); + sim_assert(isatty(serial_fd), "not a TTY"); + + sim_info("configuring port"); + // Get the current options for the port + if (tcgetattr(serial_fd, &options) != 0) + { + sim_error("tcgetattr"); + } + + // Set the baud rates + cfsetispeed(&options, B115200); + cfsetospeed(&options, B115200); + + // Enable the receiver and set local mode + options.c_cflag |= (CLOCAL | CREAD); + + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + + // Set the new options for the port + if (tcsetattr(serial_fd, TCSANOW, &options) != 0) + { + sim_error("tcsetattr"); + } + + // flush tx and rx buffers + tcflush(serial_fd, TCIOFLUSH); + + serial_initialised = true; +} + +// return number of characters in the receive buffer +uint8_t serial_rxchars(void) +{ + int rx_chars_nb; + sim_assert(serial_initialised, "serial interface not initialised"); + ioctl(serial_fd, FIONREAD, &rx_chars_nb); + return rx_chars_nb; +} + +// read one character +uint8_t serial_popchar(void) +{ + uint8_t c; + ssize_t count; + + sim_assert(serial_initialised, "serial interface not initialised"); + sim_assert(serial_rxchars() > 0, "no chars to read"); + count = read(serial_fd, &c, 1); + sim_assert(count == 1, "no character in serial RX buffer"); + return c; +} + +// send one character +void serial_writechar(uint8_t data) +{ + ssize_t count; + sim_assert(serial_initialised, "serial interface not initialised"); + putchar(data); + count = write(serial_fd, &data, 1); + sim_assert(count == 1, "could not write to serial port"); +} + +// read/write many characters +void serial_writestr(uint8_t *data) +{ + ssize_t count; + const char *str = (char *)data; + sim_assert(serial_initialised, "serial interface not initialised"); + puts(str); + count = write(serial_fd, str, strlen(str)); + sim_assert(count == strlen(str), "could not write to serial port"); +} + +// write from flash +void serial_writestr_P(PGM_P data) +{ + serial_writestr((uint8_t *)data); +} + diff --git a/sersendf.c b/sersendf.c index 99c184e..db3e655 100644 --- a/sersendf.c +++ b/sersendf.c @@ -1,7 +1,9 @@ #include "sersendf.h" #include -#include +#ifndef SIMULATION + #include +#endif #include "serial.h" #include "sermsg.h" @@ -23,14 +25,14 @@ void sersendf(char *format, ...) { if (j == 4) serwrite_uint32(va_arg(args, uint32_t)); else - serwrite_uint16(va_arg(args, uint16_t)); + serwrite_uint16(va_arg(args, unsigned int)); j = 0; break; case 'd': if (j == 4) serwrite_int32(va_arg(args, int32_t)); else - serwrite_int16(va_arg(args, int16_t)); + serwrite_int16(va_arg(args, int)); j = 0; break; case 'p': @@ -39,11 +41,11 @@ void sersendf(char *format, ...) { if (j == 4) serwrite_hex32(va_arg(args, uint32_t)); else - serwrite_hex16(va_arg(args, uint16_t)); + serwrite_hex16(va_arg(args, unsigned int)); j = 0; break; case 'c': - serial_writechar(va_arg(args, uint16_t)); + serial_writechar(va_arg(args, unsigned int)); j = 0; break; case 's': @@ -86,14 +88,14 @@ void sersendf_P(PGM_P format, ...) { if (j == 4) serwrite_uint32(va_arg(args, uint32_t)); else - serwrite_uint16(va_arg(args, uint16_t)); + serwrite_uint16(va_arg(args, unsigned int)); j = 0; break; case 'd': if (j == 4) serwrite_int32(va_arg(args, int32_t)); else - serwrite_int16(va_arg(args, int16_t)); + serwrite_int16(va_arg(args, int)); j = 0; break; /* case 'x': diff --git a/sersendf.h b/sersendf.h index 22aa592..4078464 100644 --- a/sersendf.h +++ b/sersendf.h @@ -1,7 +1,10 @@ #ifndef _SERSENDF_H #define _SERSENDF_H -#include +#ifndef SIMULATION + #include +#endif +#include "simulation.h" void sersendf(char *format, ...) __attribute__ ((format (printf, 1, 2))); void sersendf_P(PGM_P format, ...) __attribute__ ((format (printf, 1, 2))); diff --git a/simulation.c b/simulation.c new file mode 100644 index 0000000..622ad81 --- /dev/null +++ b/simulation.c @@ -0,0 +1,105 @@ +#include +#include +#include + +#include "simulation.h" + +uint8_t ACSR; +uint8_t TIMSK1; + + +/* -- debugging ------------------------------------------------------------ */ + +void sim_info(const char fmt[], ...) +{ + va_list ap; + fputs("\033[0;32m" , stdout); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fputs("\033[m\n", stdout); +} + +void sim_error(const char msg[]) +{ + printf("\033[0;31mERROR: %s\033[m\n", msg); + exit(-1); +} + +void sim_assert(bool cond, const char msg[]) +{ + if (!cond) + { + sim_error(msg); + } +} + + +/* -- interrupts ----------------------------------------------------------- */ + +volatile bool sim_interrupts = false; +void sei(void) +{ + sim_interrupts = true; +} + + +/* -- PIN I/O ------------------------------------------------------------ */ + +#define out true +#define in false + +static int x = 0, y = 0, z = 0, e = 0; + +static bool direction[PIN_NB]; +static bool state[PIN_NB]; + +static void print_pos(void) +{ + sim_info("x:%5d y:%5d z:%5d e:%5d", x, y, z, e); +} + +void WRITE(pin_t pin, bool s) +{ + bool old_state = state[pin]; + + if (direction[pin] == out) + { + state[pin] = s; + } + if (s && !old_state) /* rising edge */ + { + switch (pin) + { + case X_STEP_PIN: + x += state[X_DIR_PIN] ? 1 : -1; + print_pos(); + break; + case Y_STEP_PIN: + y += state[Y_DIR_PIN] ? 1 : -1; + print_pos(); + break; + case Z_STEP_PIN: + z += state[Z_DIR_PIN] ? 1 : -1; + print_pos(); + break; + case E_STEP_PIN: + e += state[E_DIR_PIN] ? 1 : -1; + print_pos(); + break; + default: + break; + } + } +} + +void SET_OUTPUT(pin_t pin) +{ + direction[pin] = out; +} + +void SET_INPUT(pin_t pin) +{ + direction[pin] = in; +} + diff --git a/simulation.h b/simulation.h new file mode 100644 index 0000000..e514284 --- /dev/null +++ b/simulation.h @@ -0,0 +1,81 @@ +#if !defined _SIMULATION_H && defined SIMULATION +#define _SIMULATION_H + +#include +#include + +#define PROGMEM +#define PGM_P const char * +#define PSTR(x) (x) +#define pgm_read_byte(x) (*((uint8_t *)(x))) +#define pgm_read_word(x) (*((uint16_t *)(x))) + +#define MASK(PIN) (1 << PIN) +#define ACD 7 +#define OCIE1A 1 + + +#undef X_STEP_PIN +#undef X_DIR_PIN +#undef X_MIN_PIN +#undef Y_STEP_PIN +#undef Y_DIR_PIN +#undef Y_MIN_PIN +#undef Z_STEP_PIN +#undef Z_DIR_PIN +#undef Z_MIN_PIN +#undef E_STEP_PIN +#undef E_DIR_PIN +#undef STEPPER_ENABLE_PIN +#undef HEATER_PIN +#undef FAN_PIN +#undef HEATER_PWM +#undef FAN_PWM + +typedef enum { + X_STEP_PIN, + X_DIR_PIN, + X_MIN_PIN, + Y_STEP_PIN, + Y_DIR_PIN, + Y_MIN_PIN, + Z_STEP_PIN, + Z_DIR_PIN, + Z_MIN_PIN, + E_STEP_PIN, + E_DIR_PIN, + + STEPPER_ENABLE_PIN, + + SCK, + MOSI, + MISO, + SS, + + PIN_NB +} pin_t; + +#undef TEMP_PIN_CHANNEL +#define TEMP_PIN_CHANNEL 0 + +extern uint8_t ACSR; +extern uint8_t TIMSK1; +extern volatile bool sim_interrupts; + +void WRITE(pin_t pin, bool on); +void SET_OUTPUT(pin_t pin); +void SET_INPUT(pin_t pin); + +void sei(void); + +#ifdef USE_WATCHDOG +#define wd_init() +#define wd_reset() +#endif + +void sim_info(const char fmt[], ...); +void sim_error(const char msg[]); +void sim_assert(bool cond, const char msg[]); + +#endif /* _SIMULATION_H */ + diff --git a/temp.c b/temp.c index 7e818c7..2117693 100644 --- a/temp.c +++ b/temp.c @@ -18,7 +18,9 @@ #include "temp.h" -#include +#ifndef SIMULATION + #include +#endif #include "clock.h" #include "serial.h" @@ -72,6 +74,8 @@ uint16_t temptable[NUMTEMPS][2] PROGMEM = { #endif #endif +#include "simulation.h" + uint16_t current_temp = 0; uint16_t target_temp = 0; diff --git a/temp.h b/temp.h index 9955a9e..ac72878 100644 --- a/temp.h +++ b/temp.h @@ -24,7 +24,7 @@ typedef union { } max6675_data_format; #endif -#ifdef TEMP_THERMISTOR +#if defined TEMP_THERMISTOR && !defined SIMULATION #include #endif diff --git a/timer.h b/timer.h index afb51f8..a9953d7 100644 --- a/timer.h +++ b/timer.h @@ -2,7 +2,10 @@ #define _TIMER_H #include -#include +#ifndef SIMULATION + #include +#endif +#include "simulation.h" // time-related constants #define US * (F_CPU / 1000000) diff --git a/timer_sim.c b/timer_sim.c new file mode 100644 index 0000000..62ff697 --- /dev/null +++ b/timer_sim.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "dda_queue.h" +#include "timer.h" +#include "simulation.h" + +static bool timer_initialised = false; + +void setupTimerInterrupt(void) +{ + disableTimerInterrupt(); + sim_info("setupTimerInterrupt"); + timer_initialised = true; +} + +static void timer1_isr(int cause, siginfo_t *HowCome, void *ucontext) +{ + if (!sim_interrupts || !timerInterruptIsEnabled()) return; + + sim_interrupts = false; + + WRITE(SCK, 1); + queue_step(); + WRITE(SCK, 0); + + sim_interrupts = true; +} + +void setTimer(uint32_t delay) +{ + struct itimerval itimer; + struct sigaction sa; + + sim_assert(timer_initialised, "timer not initialised"); + + sa.sa_sigaction = timer1_isr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGPROF, &sa, 0)) { + sim_error("sigaction"); + } + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = (long)delay * 8000000 / F_CPU; + itimer.it_value.tv_sec = 0; + itimer.it_value.tv_usec = itimer.it_interval.tv_usec; + setitimer(ITIMER_PROF, &itimer, NULL); +} +