From 05d2bc1aa50638e24851b11cb4ae91669dad8ade Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Mon, 18 Oct 2010 20:15:59 +0200 Subject: [PATCH 1/4] 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 +++++++ gcode.c | 7 ++- 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 ++++++++++++++++++++++ 21 files changed, 537 insertions(+), 24 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 197697b..e58520c 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 762fc46..08deb06 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 71e3c3a..2953852 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/gcode.c b/gcode.c index 50a3ae1..f5e3ac0 100644 --- a/gcode.c +++ b/gcode.c @@ -637,7 +637,12 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { // M113- extruder PWM // M114- report XYZEF to host case 114: - sersendf_P("X:%ld,Y:%ld,Z:%ld,E:%ld,F:%ld\n", current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F); + sersendf_P("X:%ld,Y:%ld,Z:%ld,E:%ld,F:%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); break; #ifdef HEATER_PIN 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 1154ebd..260f641 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); +} + From d95b74651c185c313a3addbf099f60bd2a927d7d Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Mon, 18 Oct 2010 20:28:08 +0200 Subject: [PATCH 2/4] document simulation --- README | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README b/README index 3b5557c..6d750e7 100644 --- a/README +++ b/README @@ -75,6 +75,30 @@ The fixed-point stuff is fun, although we have to manually ensure that the decim The PID code in heater.c is probably quite generalisable, and seems to work well when tuned. Google knows of plenty of PID tuning guides. +############################################################################## +# # +# Simulation # +# # +############################################################################## + +To compile the simulation code, use + + $ make sim + +The simulation program will open a serial port for communication. If you don't want to connect a null modem cable, you can use 'socat' to connect a virtual serial port to your terminal: + + $ socat -d -d PTY READLINE + 2010/10/18 20:24:33 socat[3700] N PTY is /dev/pts/2 + 2010/10/18 20:24:33 socat[3700] N using readline on stdin for reading and stdio for writing + 2010/10/18 20:24:33 socat[3700] N starting data transfer loop with FDs [3,3] and [0,0] + +On the first line of output, socat will tell you the name of the virtual serial port. Pass this as an argument to the simulation program (in another terminal): + + $ ./sim /dev/pts/2 + +Now you can send G-codes from the socat terminal. The simulation code will print any data sent via the firmware's serial interface. Stepper positions will be shown in green, counting a rising slope on the pin as one step. + + ############################################################################## # # # File descriptions # @@ -129,6 +153,9 @@ This file associates various functions with particular pins on your avr *** README this file +*** simulation.[sh] +helper code to run the code on any Unix PC + *** sender.sh A simple talker From 009faa2a74271151ffa41c2401fb329b4ecccc2b Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Sat, 23 Oct 2010 23:57:31 +0200 Subject: [PATCH 3/4] Move simulation code into simulation/ directory. Fix timers in simulation. Clean up firmware code. --- Makefile | 21 ------ README | 3 +- arduino.h | 4 ++ clock_sim.c | 56 ---------------- config.h.dist | 6 +- dda.c | 5 +- dda_queue.c | 8 +-- heater.c | 6 +- heater.h | 2 +- mendel.c | 7 +- serial.h | 7 +- sersendf.c | 4 +- sersendf.h | 5 +- simulation/Makefile | 24 +++++++ analog_sim.c => simulation/analog.c | 2 +- simulation/avr/eeprom.h | 0 simulation/avr/interrupt.h | 7 ++ simulation/avr/io.h | 13 ++++ simulation/avr/pgmspace.h | 11 ++++ simulation/clock.c | 88 +++++++++++++++++++++++++ delay_sim.c => simulation/delay.c | 2 +- serial_sim.c => simulation/serial.c | 23 +------ simulation.c => simulation/simulation.c | 38 +++++++++-- simulation.h => simulation/simulation.h | 35 ++-------- simulation/timer.c | 70 ++++++++++++++++++++ simulation/util/atomic.h | 8 +++ temp.c | 6 +- temp.h | 2 +- timer.h | 5 +- timer_sim.c | 50 -------------- 30 files changed, 286 insertions(+), 232 deletions(-) delete mode 100644 clock_sim.c create mode 100644 simulation/Makefile rename analog_sim.c => simulation/analog.c (94%) create mode 100644 simulation/avr/eeprom.h create mode 100644 simulation/avr/interrupt.h create mode 100644 simulation/avr/io.h create mode 100644 simulation/avr/pgmspace.h create mode 100644 simulation/clock.c rename delay_sim.c => simulation/delay.c (86%) rename serial_sim.c => simulation/serial.c (82%) rename simulation.c => simulation/simulation.c (67%) rename simulation.h => simulation/simulation.h (58%) create mode 100644 simulation/timer.c create mode 100644 simulation/util/atomic.h delete mode 100644 timer_sim.c diff --git a/Makefile b/Makefile index 14a2e49..76b39b5 100644 --- a/Makefile +++ b/Makefile @@ -124,24 +124,3 @@ 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_parse.c gcode_process.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_parse.h gcode_process.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 -Wa,-adhlns=$(<:.c=.al) -c $(SIM_CFLAGS) -o $@ $< - -sim: $(SIM_OBJ) - @echo " LINK $@" - @cc $(SIM_CFLAGS) -o $@ $^ diff --git a/README b/README index bed0715..923a6a9 100644 --- a/README +++ b/README @@ -105,8 +105,9 @@ The PID code in heater.c is probably quite generalisable, and seems to work well # # ############################################################################## -To compile the simulation code, use +The directory simulation/ contains helper code to run the FiveD firmware on any PC, simulation the low-level hardware. This can be useful for debugging. To compile the simulation code, use + $ cd simulation $ make sim The simulation program will open a serial port for communication. If you don't want to connect a null modem cable, you can use 'socat' to connect a virtual serial port to your terminal: diff --git a/arduino.h b/arduino.h index d80089b..8ca09bb 100644 --- a/arduino.h +++ b/arduino.h @@ -57,6 +57,10 @@ #include "arduino_1280.h" #endif /* __AVR_ATmega1280__) */ +#if defined (SIMULATION) + #include "simulation/simulation.h" +#endif + #ifndef DIO0_PIN #error pins for this chip not defined in arduino.h! If you write an appropriate pin definition and have this firmware work on your chip, please tell us via the forum thread #endif diff --git a/clock_sim.c b/clock_sim.c deleted file mode 100644 index f43612a..0000000 --- a/clock_sim.c +++ /dev/null @@ -1,56 +0,0 @@ -#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 6b434f9..1629b24 100644 --- a/config.h.dist +++ b/config.h.dist @@ -132,10 +132,6 @@ - comment out pins not in use, as this drops the corresponding code and makes operations faster */ -#ifndef SIMULATION - #include "arduino.h" -#endif - /* RESERVED pins we NEED these for communication @@ -262,4 +258,6 @@ #define power_off() if (0) {} #endif +#include "arduino.h" + #endif /* _CONFIG_H */ diff --git a/dda.c b/dda.c index c72716b..1146d11 100644 --- a/dda.c +++ b/dda.c @@ -1,10 +1,7 @@ #include "dda.h" #include - -#ifndef SIMULATION - #include -#endif +#include #include "timer.h" #include "serial.h" diff --git a/dda_queue.c b/dda_queue.c index 92fc35f..5f79719 100644 --- a/dda_queue.c +++ b/dda_queue.c @@ -2,12 +2,8 @@ #include -#ifdef SIMULATION - #include "simulation.h" -#else - #include - #include -#endif +#include +#include #include "config.h" #include "timer.h" diff --git a/heater.c b/heater.c index 819896a..b307a80 100644 --- a/heater.c +++ b/heater.c @@ -2,9 +2,7 @@ #ifdef HEATER_PIN -#ifndef SIMULATION - #include -#endif +#include #include "sersendf.h" #include "debug.h" @@ -106,4 +104,4 @@ void heater_tick(int16_t current_temp, int16_t target_temp) { #endif } -#endif /* HEATER_PIN */ \ No newline at end of file +#endif /* HEATER_PIN */ diff --git a/heater.h b/heater.h index 345eeac..a841444 100644 --- a/heater.h +++ b/heater.h @@ -2,7 +2,7 @@ #define _HEATER_H #include "config.h" -#include "simulation.h" +#include "simulation/simulation.h" #ifdef HEATER_PIN diff --git a/mendel.c b/mendel.c index cd54e8b..e80e184 100644 --- a/mendel.c +++ b/mendel.c @@ -1,7 +1,5 @@ -#ifndef SIMULATION - #include - #include -#endif +#include +#include #include "config.h" @@ -18,7 +16,6 @@ #include "sersendf.h" #include "heater.h" #include "analog.h" -#include "simulation.h" void io_init(void) { // disable modules we don't use diff --git a/serial.h b/serial.h index fa23a16..85a0b9e 100644 --- a/serial.h +++ b/serial.h @@ -3,11 +3,8 @@ #include -#ifndef SIMULATION - #include - #include -#endif -#include "simulation.h" +#include +#include // initialise serial subsystem void serial_init(void); diff --git a/sersendf.c b/sersendf.c index db3e655..ef1000c 100644 --- a/sersendf.c +++ b/sersendf.c @@ -1,9 +1,7 @@ #include "sersendf.h" #include -#ifndef SIMULATION - #include -#endif +#include #include "serial.h" #include "sermsg.h" diff --git a/sersendf.h b/sersendf.h index 4078464..22aa592 100644 --- a/sersendf.h +++ b/sersendf.h @@ -1,10 +1,7 @@ #ifndef _SERSENDF_H #define _SERSENDF_H -#ifndef SIMULATION - #include -#endif -#include "simulation.h" +#include void sersendf(char *format, ...) __attribute__ ((format (printf, 1, 2))); void sersendf_P(PGM_P format, ...) __attribute__ ((format (printf, 1, 2))); diff --git a/simulation/Makefile b/simulation/Makefile new file mode 100644 index 0000000..f94cbb1 --- /dev/null +++ b/simulation/Makefile @@ -0,0 +1,24 @@ +############################################################################## +# # +# Simulation # +# # +############################################################################## + +include ../Makefile + +vpath %.c .. +vpath %.h .. +vpath config.h.dist .. + +ARCH = +DEFS += -DSIMULATION -DGLOBAL_CLOCK +SOURCES += simulation.c +OBJ = $(patsubst %.c,%.o,${SOURCES}) +CFLAGS = -g -Wall -Wstrict-prototypes -Os $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fshort-enums -I. +LDFLAGS = +LIBS = -lrt + +sim: $(OBJ) + @echo " LINK $@" + @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + diff --git a/analog_sim.c b/simulation/analog.c similarity index 94% rename from analog_sim.c rename to simulation/analog.c index d781547..4d71260 100644 --- a/analog_sim.c +++ b/simulation/analog.c @@ -1,4 +1,4 @@ -#include "analog.h" +#include "../analog.h" #include "simulation.h" static bool analog_initialised = false; diff --git a/simulation/avr/eeprom.h b/simulation/avr/eeprom.h new file mode 100644 index 0000000..e69de29 diff --git a/simulation/avr/interrupt.h b/simulation/avr/interrupt.h new file mode 100644 index 0000000..1ca2547 --- /dev/null +++ b/simulation/avr/interrupt.h @@ -0,0 +1,7 @@ +#ifndef _AVR_INTERRUPT_H +#define _AVR_INTERRUPT_H + +void sei(void); + +#endif /* _AVR_INTERRUPT_H */ + diff --git a/simulation/avr/io.h b/simulation/avr/io.h new file mode 100644 index 0000000..f56aad8 --- /dev/null +++ b/simulation/avr/io.h @@ -0,0 +1,13 @@ +#ifndef _AVR_IO_H +#define _AVR_IO_H + +#include + +#define ACD 7 +#define OCIE1A 1 + +extern uint8_t ACSR; +extern uint8_t TIMSK1; + +#endif /* _AVR_IO_H */ + diff --git a/simulation/avr/pgmspace.h b/simulation/avr/pgmspace.h new file mode 100644 index 0000000..0be5e58 --- /dev/null +++ b/simulation/avr/pgmspace.h @@ -0,0 +1,11 @@ +#ifndef _AVR_PGMSPACE_H +#define _AVR_PGMSPACE_H + +#define PGM_P const char * +#define PROGMEM +#define PSTR(x) (x) +#define pgm_read_byte(x) (*((uint8_t *)(x))) +#define pgm_read_word(x) (*((uint16_t *)(x))) + +#endif /* _AVR_PGMSPACE_H */ + diff --git a/simulation/clock.c b/simulation/clock.c new file mode 100644 index 0000000..4c9c522 --- /dev/null +++ b/simulation/clock.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include "../clock.h" +#include "simulation.h" + +#define SIM_CLOCK_SLOWDOWN 1 + +#ifdef GLOBAL_CLOCK +static volatile uint32_t gclock = 0; +#endif + +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 CLOCK_SIG (SIGRTMIN + 2) + +/* 1/4 second tick */ +static void timer2_isr(int cause, siginfo_t *HowCome, void *ucontext) +{ + if (!sim_interrupts) return; + + sim_interrupts = false; + + // global clock +#ifdef GLOBAL_CLOCK + gclock += SIM_CLOCK_SLOWDOWN; +#endif + // 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) +{ + timer_t timerid; + struct sigevent sev; + struct itimerspec its; + struct sigaction sa; + const long long nsec = SIM_CLOCK_SLOWDOWN * 1000 * 1000; + + /* Establish handler for timer signal */ + sa.sa_sigaction = timer2_isr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + if (sigaction(CLOCK_SIG, &sa, NULL) == -1) { + sim_error("sigaction"); + } + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = CLOCK_SIG; + sev.sigev_value.sival_ptr = &timerid; + if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) + { + sim_error("timer_create"); + } + + its.it_value.tv_sec = nsec / 1000000000; + its.it_value.tv_nsec = nsec % 1000000000; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + if (timer_settime(timerid, 0, &its, NULL) == -1) + { + sim_error("timer_settime"); + } + + clock_initialised = true; +} + +#ifdef GLOBAL_CLOCK +uint32_t clock_read() +{ + return gclock; +} +#endif + diff --git a/delay_sim.c b/simulation/delay.c similarity index 86% rename from delay_sim.c rename to simulation/delay.c index a2d1f0c..70b7211 100644 --- a/delay_sim.c +++ b/simulation/delay.c @@ -1,6 +1,6 @@ #include -#include "delay.h" +#include "../delay.h" #include "simulation.h" void delay(uint32_t us) diff --git a/serial_sim.c b/simulation/serial.c similarity index 82% rename from serial_sim.c rename to simulation/serial.c index 558b0ea..6a53530 100644 --- a/serial_sim.c +++ b/simulation/serial.c @@ -1,11 +1,10 @@ #include -#include #include #include #include #include -#include "serial.h" +#include "../serial.h" #include "simulation.h" static int serial_fd; @@ -15,22 +14,8 @@ 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_info("opening serial port %s", sim_serial_port); + serial_fd = open(sim_serial_port, O_RDWR | O_NOCTTY | O_NDELAY); sim_assert(serial_fd != -1, "couldn't open serial port"); sim_assert(isatty(serial_fd), "not a TTY"); @@ -92,7 +77,6 @@ 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"); } @@ -103,7 +87,6 @@ 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"); } diff --git a/simulation.c b/simulation/simulation.c similarity index 67% rename from simulation.c rename to simulation/simulation.c index 622ad81..8c04ce1 100644 --- a/simulation.c +++ b/simulation/simulation.c @@ -3,26 +3,50 @@ #include #include "simulation.h" +#include "../clock.h" uint8_t ACSR; uint8_t TIMSK1; +char *sim_serial_port; + +/* -- initialise simulation ------------------------------------------------ */ + +void sim_init(void) __attribute__((constructor)); +void sim_init(void) +{ + /* 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_serial_port = argv[1]; +} + /* -- debugging ------------------------------------------------------------ */ void sim_info(const char fmt[], ...) { va_list ap; - fputs("\033[0;32m" , stdout); + fputs("\033[0;32m" , stderr); va_start(ap, fmt); - vprintf(fmt, ap); + vfprintf(stderr, fmt, ap); va_end(ap); - fputs("\033[m\n", stdout); + fputs("\033[m\n", stderr); } void sim_error(const char msg[]) { - printf("\033[0;31mERROR: %s\033[m\n", msg); + fprintf(stderr, "\033[0;31mERROR: %s\033[m\n", msg); exit(-1); } @@ -44,7 +68,7 @@ void sei(void) } -/* -- PIN I/O ------------------------------------------------------------ */ +/* -- PIN I/O -------------------------------------------------------------- */ #define out true #define in false @@ -56,7 +80,7 @@ static bool state[PIN_NB]; static void print_pos(void) { - sim_info("x:%5d y:%5d z:%5d e:%5d", x, y, z, e); + printf("%6u %5d %5d %5d %5d\n", clock_read(), x, y, z, e); } void WRITE(pin_t pin, bool s) @@ -95,7 +119,7 @@ void WRITE(pin_t pin, bool s) void SET_OUTPUT(pin_t pin) { - direction[pin] = out; + direction[pin] = out; } void SET_INPUT(pin_t pin) diff --git a/simulation.h b/simulation/simulation.h similarity index 58% rename from simulation.h rename to simulation/simulation.h index 0d1ba57..baba954 100644 --- a/simulation.h +++ b/simulation/simulation.h @@ -4,29 +4,9 @@ #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))) +/* make arduino.h happy */ +#define DIO0_PIN -#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 @@ -58,16 +38,16 @@ typedef enum { #undef TEMP_PIN_CHANNEL #define TEMP_PIN_CHANNEL 0 -extern uint8_t ACSR; -extern uint8_t TIMSK1; extern volatile bool sim_interrupts; +extern char *sim_serial_port; +#undef WRITE +#undef SET_OUTPUT +#undef SET_INPUT 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() @@ -77,8 +57,5 @@ void sim_info(const char fmt[], ...); void sim_error(const char msg[]); void sim_assert(bool cond, const char msg[]); -#define ATOMIC_BLOCK(n) if (n) -#define ATOMIC_RESTORESTATE 1 - #endif /* _SIMULATION_H */ diff --git a/simulation/timer.c b/simulation/timer.c new file mode 100644 index 0000000..f7bc837 --- /dev/null +++ b/simulation/timer.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include "../dda_queue.h" +#include "../timer.h" +#include "simulation.h" + +#define TIMER_SIG (SIGRTMIN + 1) + +static bool timer_initialised = false; +static timer_t timerid; + +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 setupTimerInterrupt(void) +{ + disableTimerInterrupt(); + sim_info("setupTimerInterrupt"); + + struct sigevent sev; + struct sigaction sa; + + /* Establish handler for timer signal */ + sa.sa_sigaction = timer1_isr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + if (sigaction(TIMER_SIG, &sa, NULL) == -1) { + sim_error("sigaction"); + } + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = TIMER_SIG; + sev.sigev_value.sival_ptr = &timerid; + if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) + { + sim_error("timer_create"); + } + + timer_initialised = true; +} + +void setTimer(uint32_t delay) +{ + struct itimerspec its; + long long nsec = (long)delay * 8000000 / F_CPU * 1000; + + its.it_value.tv_sec = nsec / 1000000000; + its.it_value.tv_nsec = nsec % 1000000000; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + if (timer_settime(timerid, 0, &its, NULL) == -1) + { + sim_error("timer_settime"); + } +} + diff --git a/simulation/util/atomic.h b/simulation/util/atomic.h new file mode 100644 index 0000000..d25332a --- /dev/null +++ b/simulation/util/atomic.h @@ -0,0 +1,8 @@ +#ifndef _UTIL_ATOMIC_H +#define _UTIL_ATOMIC_H + +#define ATOMIC_BLOCK(n) if (n) +#define ATOMIC_RESTORESTATE 1 + +#endif /* _UTIL_ATOMIC_H */ + diff --git a/temp.c b/temp.c index 2117693..7e818c7 100644 --- a/temp.c +++ b/temp.c @@ -18,9 +18,7 @@ #include "temp.h" -#ifndef SIMULATION - #include -#endif +#include #include "clock.h" #include "serial.h" @@ -74,8 +72,6 @@ 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 ac72878..9dcb01a 100644 --- a/temp.h +++ b/temp.h @@ -24,7 +24,7 @@ typedef union { } max6675_data_format; #endif -#if defined TEMP_THERMISTOR && !defined SIMULATION +#ifdef TEMP_THERMISTOR #include #endif diff --git a/timer.h b/timer.h index a9953d7..afb51f8 100644 --- a/timer.h +++ b/timer.h @@ -2,10 +2,7 @@ #define _TIMER_H #include -#ifndef SIMULATION - #include -#endif -#include "simulation.h" +#include // time-related constants #define US * (F_CPU / 1000000) diff --git a/timer_sim.c b/timer_sim.c deleted file mode 100644 index 62ff697..0000000 --- a/timer_sim.c +++ /dev/null @@ -1,50 +0,0 @@ -#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); -} - From a568fe718986180e4254c490b57017ae23dbc44e Mon Sep 17 00:00:00 2001 From: Stephan Walter Date: Sat, 30 Oct 2010 21:07:53 +0200 Subject: [PATCH 4/4] fix simulation timers, add documentation and plotting script --- README | 20 ++------------------ simulation/Makefile | 2 +- simulation/README | 33 +++++++++++++++++++++++++++++++++ simulation/plot.sh | 34 ++++++++++++++++++++++++++++++++++ simulation/simulation.c | 25 ++++++++++++++++++++++++- simulation/timer.c | 2 +- 6 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 simulation/README create mode 100755 simulation/plot.sh diff --git a/README b/README index 923a6a9..8ba1153 100644 --- a/README +++ b/README @@ -105,23 +105,7 @@ The PID code in heater.c is probably quite generalisable, and seems to work well # # ############################################################################## -The directory simulation/ contains helper code to run the FiveD firmware on any PC, simulation the low-level hardware. This can be useful for debugging. To compile the simulation code, use - - $ cd simulation - $ make sim - -The simulation program will open a serial port for communication. If you don't want to connect a null modem cable, you can use 'socat' to connect a virtual serial port to your terminal: - - $ socat -d -d PTY READLINE - 2010/10/18 20:24:33 socat[3700] N PTY is /dev/pts/2 - 2010/10/18 20:24:33 socat[3700] N using readline on stdin for reading and stdio for writing - 2010/10/18 20:24:33 socat[3700] N starting data transfer loop with FDs [3,3] and [0,0] - -On the first line of output, socat will tell you the name of the virtual serial port. Pass this as an argument to the simulation program (in another terminal): - - $ ./sim /dev/pts/2 - -Now you can send G-codes from the socat terminal. The simulation code will print any data sent via the firmware's serial interface. Stepper positions will be shown in green, counting a rising slope on the pin as one step. +The directory simulation/ contains helper code to run the FiveD firmware on any PC, simulation the low-level hardware. This can be useful for debugging. See the README file in the simulation directory. ############################################################################## @@ -178,7 +162,7 @@ This file associates various functions with particular pins on your avr *** README this file -*** simulation.[sh] +*** simulation/*.[ch] helper code to run the code on any Unix PC *** sender.sh diff --git a/simulation/Makefile b/simulation/Makefile index f94cbb1..2eb292b 100644 --- a/simulation/Makefile +++ b/simulation/Makefile @@ -16,7 +16,7 @@ SOURCES += simulation.c OBJ = $(patsubst %.c,%.o,${SOURCES}) CFLAGS = -g -Wall -Wstrict-prototypes -Os $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fshort-enums -I. LDFLAGS = -LIBS = -lrt +LIBS = -lrt -lm sim: $(OBJ) @echo " LINK $@" diff --git a/simulation/README b/simulation/README new file mode 100644 index 0000000..161e3c1 --- /dev/null +++ b/simulation/README @@ -0,0 +1,33 @@ +############################################################################## +# # +# Simulation # +# # +############################################################################## + +This directory contains helper code to run the FiveD firmware on any PC, simulating the low-level hardware. This can be useful for debugging. To compile the simulation code, use + + $ make sim + +The simulation program will open a serial port for communication. If you don't want to connect a null modem cable, you can use 'socat' to connect a virtual serial port to your terminal: + + $ socat -d -d PTY READLINE + 2010/10/18 20:24:33 socat[3700] N PTY is /dev/pts/2 + 2010/10/18 20:24:33 socat[3700] N using readline on stdin for reading and stdio for writing + 2010/10/18 20:24:33 socat[3700] N starting data transfer loop with FDs [3,3] and [0,0] + +On the first line of output, socat will tell you the name of the virtual serial port. Pass this as an argument to the simulation program (in another terminal): + + $ ./sim /dev/pts/2 + +Now you can send G-codes from the socat terminal. The simulation code will print the time in seconds and x, y, z stepper positions, counting a rising slope on the pin as one step. + +The shell script plot.sh can be used to plot positions and speeds. Simply direct the output (stdout) of the simulation program to file + + $ ./sim /dev/pts/2 > example.txt + +Then, call plot.sh with the file as argument: + + $ ./plot.sh example.txt + +plot.sh will, using gnuplot, generate two files, example-xy.png and example-speed.png, showing position in the z-plane and speeds, respectively. + diff --git a/simulation/plot.sh b/simulation/plot.sh new file mode 100755 index 0000000..b49bd28 --- /dev/null +++ b/simulation/plot.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# uses gnuplot to plot the output from the sim program +# read the gnuplot manual to adapt this file to your needs + +if [ $# -ne 1 ]; then + echo "Usage: plot.sh " + exit +fi +base=${1%.*} + + +/usr/bin/gnuplot < #include #include +#include +#include "../config.h" #include "simulation.h" #include "../clock.h" @@ -80,7 +82,28 @@ static bool state[PIN_NB]; static void print_pos(void) { - printf("%6u %5d %5d %5d %5d\n", clock_read(), x, y, z, e); + static int x_old = 0, y_old = 0, z_old = 0; + float dx, dy, dz, d; + static uint32_t clk_old; + + uint32_t clk = clock_read(); + if (clk - clk_old < 50) return; /* output every 50ms */ + + /* calculate speeds in mm/minute */ + dx = 60000.0 * (x - x_old) / (clk - clk_old) / STEPS_PER_MM_X; + dy = 60000.0 * (y - y_old) / (clk - clk_old) / STEPS_PER_MM_Y; + dz = 60000.0 * (z - z_old) / (clk - clk_old) / STEPS_PER_MM_Z; + d = sqrt(dx*dx + dy*dy + dz*dz); + + printf("%.3f %.3f %.3f %.3f %.4f %.4f %.4f %.4f\n", + clk / 1000.0, + x / STEPS_PER_MM_X, + y / STEPS_PER_MM_Y, + z / STEPS_PER_MM_Z, + dx, dy, dz, d); + + clk_old = clk; + x_old = x; y_old = y; z_old = z; } void WRITE(pin_t pin, bool s) diff --git a/simulation/timer.c b/simulation/timer.c index f7bc837..f1e9f51 100644 --- a/simulation/timer.c +++ b/simulation/timer.c @@ -55,7 +55,7 @@ void setupTimerInterrupt(void) void setTimer(uint32_t delay) { struct itimerspec its; - long long nsec = (long)delay * 8000000 / F_CPU * 1000; + long long nsec = (long)delay * (1000000000 / F_CPU); its.it_value.tv_sec = nsec / 1000000000; its.it_value.tv_nsec = nsec % 1000000000;