Restore simulation build target.

This code was accidentally removed long ago in a botched merge. This
patch recovers it and makes it build again. I've done minimal testing
and some necessary cleanup. It compiles and runs, but it probably still
has a few dust bunnies here and there.

I added registers and pin definitions to simulator.h and
simulator/simulator.c which I needed to match my Gen7-based config.
Other configs or non-AVR ports will need to define more or different
registers. Some registers are 16-bits, some are 8-bit, and some are just
constant values (enums). A more clever solution would read in the
chip-specific header and produce saner definitions which covered all
GPIOs. But this commit just takes the quick and easy path to support my
own hardware.

Most of this code originated in these commits:

	commit cbf41dd4ad
	Author: Stephan Walter <stephan@walter.name>
	Date:   Mon Oct 18 20:28:08 2010 +0200

	    document simulation

	commit 3028b297f3
	Author: Stephan Walter <stephan@walter.name>
	Date:   Mon Oct 18 20:15:59 2010 +0200

	    Add simulation code: use "make sim"

Additional tweaks:

Revert va_args processing for AVR, but keep 'int' generalization
for simulation. gcc wasn't lying. The sim really aborts without this.

Remove delay(us) from simulator (obsolete).

Improve the README.sim to demonstrate working pronterface connection
to sim. Also fix the build instructions.

Appease all stock configs.

Stub out intercom and shush usb_serial when building simulator.

Pretend to be all chip-types for config appeasement.

Replace sim_timer with AVR-simulator timer:

The original sim_timer and sim_clock provided direct replacements
for timer/clock.c in the main code. But when the main code changed,
simcode did not. The main clock.c was dropped and merged into timer.c.
Also, the timer.c now has movement calculation code in it in some
cases (ACCELERATION_TEMPORAL) and it would be wrong to teach the
simulator to do the same thing. Instead, teach the simulator to
emulate the AVR Timer1 functionality, reacting to values written to
OCR1A and OCR1B timer comparison registers.

Whenever OCR1A/B are changed, the sim_setTimer function needs to be
called. It is called automatically after a timer event, so changes
within the timer ISRs do not need to bother with this.

A C++ class could make this requirement go away by noticing the
assignment. On the other hand, a chip-agnostic timer.c would help
make the main code more portable. The latter cleanup is probably
better for us in the long run.
This commit is contained in:
Phil Hord 2013-10-24 10:27:43 -04:00 committed by Markus Hitter
parent 2f81386a7a
commit 452e2e5cd9
30 changed files with 847 additions and 25 deletions

View File

@ -142,3 +142,35 @@ size: $(BUILDDIR)/$(PROGRAM).elf
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes %3d%% %3d%% %3d%% %3d%%\n", $$a, ceil($$a * 100 / (14 * 1024)), ceil($$a * 100 / (30 * 1024)),ceil($$a * 100 / (62 * 1024)), ceil($$a * 100 / (126 * 1024)) }'
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes %3d%% %3d%% %3d%% %3d%%\n", $$a, ceil($$a * 100 / (1 * 1024)), ceil($$a * 100 / (2 * 1024)),ceil($$a * 100 / (4 * 1024)), ceil($$a * 100 / (8 * 1024)) }'
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes %3d%% %3d%% %3d%% %3d%%\n", $$a, ceil($$a * 100 / (1 * 1024)), ceil($$a * 100 / (2 * 1024)), ceil($$a * 100 / (2 * 1024)), ceil($$a * 100 / (4 * 1024)) }'
##############################################################################
# #
# Simulator #
# #
##############################################################################
SIM_PATH = simulator
SIM_SOURCES := $(subst $(SIM_PATH)/,,$(wildcard $(SIM_PATH)/*.c))
SIM_SOURCES += $(filter-out $(subst _sim.c,.c,$(SIM_SOURCES)),$(SOURCES))
SIM_HEADERS = config.h serial.h dda.h timer.h clock.h temp.h sermsg.h
SIM_HEADERS += dda_queue.h debug.h sersendf.h heater.h analog.h delay.h
SIM_HEADERS += simulator.h
SIM_OBJ = $(patsubst %.c,$(BUILDDIR)/%.sim.o,$(SIM_SOURCES))
SIM_CFLAGS = -g -Wall -Wstrict-prototypes -Wno-format -Os $(DEFS) -std=gnu99
SIM_CFLAGS += -funsigned-char -funsigned-bitfields -fshort-enums -I.. -I.
# Satisfy all current config chip targets
SIM_CFLAGS += -DSIMULATOR -D__AVR_ATmega644P__ -D__AVR_ATmega1280__
SIM_CFLAGS +=-D__AVR_ATmega2560__ -D__AVR_ATmega32U4__ -D__AVR_AT90USB1286__
$(BUILDDIR)/%.sim.o: %.c $(SIM_HEADERS)
@echo " CC $@"
@cc -DDEBUG -c $(SIM_CFLAGS) -o $@ $<
sim: $(SIM_OBJ)
@echo " LINK $@"
@cc $(SIM_CFLAGS) -o $@ $^
vpath %.c $(SIM_PATH)

28
README.sim Normal file
View File

@ -0,0 +1,28 @@
##############################################################################
# #
# Simulator of AVR-targetted code on a PC #
# #
##############################################################################
To compile the simulation code, use
$ make -f Makefile-AVR sim
The simulator will open a serial port for communication. If you don't want to
connect a null modem cable, you can use 'socat' to connect two serial ports:
socat -d -d PTY,raw,echo=0 PTY,raw,echo=0
2013/10/24 17:42:04 socat[3375] N PTY is /dev/pts/12
2013/10/24 17:42:04 socat[3375] N PTY is /dev/pts/13
2013/10/24 17:42:04 socat[3375] N starting data transfer loop with FDs [3,3] and [5,5]
On the first line of output, socat will tell you the name of the virtual serial
port. Pass this as an argument to the simulator (in another terminal):
$ ./sim /dev/pts/12
Give the other virtual serial port to an application like pronterface.
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.

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#ifndef SIMULATOR
#define REFERENCE_AREF 0
#define REFERENCE_AVCC 64
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
@ -24,6 +25,7 @@
#warning in your config.h
#error REFERENCE undefined
#endif
#endif /* SIMULATOR */
void analog_init(void);

View File

@ -8,7 +8,9 @@
#ifndef _ARDUINO_H
#define _ARDUINO_H
#ifndef SIMULATOR
#include <avr/io.h>
#endif
/*
utility functions
@ -66,7 +68,9 @@
added as necessary or if I feel like it- not a comprehensive list!
*/
#ifdef SIMULATOR
#include "simulator.h"
#else
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || \
defined (__AVR_ATmega328P__)
#include "arduino_168_328p.h"
@ -93,6 +97,7 @@
#if defined (__AVR_ATmega32U4__)
#include "arduino_32U4.h"
#endif
#endif /* SIMULATOR */
#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

29
crc.c
View File

@ -4,22 +4,23 @@
\brief crc16 routine
*/
#ifndef SIMULATOR
#include <util/crc16.h>
#else
// avr-libc's _crc16_update is equivalent to the following:
//
// uint16_t _crc16_update(uint16_t crc, uint8_t a) {
// int i;
// crc ^= a;
// for (i = 0; i < 8; ++i)
// {
// if (crc & 1)
// crc = (crc >> 1) ^ 0xA001;
// else
// crc = (crc >> 1);
// }
// return crc;
// }
// Equivalent to avr-libc's _crc16_update.
uint16_t _crc16_update(uint16_t crc, uint8_t a) {
int i;
crc ^= a;
for (i = 0; i < 8; ++i) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
#endif
/** block-at-once CRC16 calculator
\param *data data to find crc16 for

2
dda.c
View File

@ -7,7 +7,9 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifndef SIMULATOR
#include <avr/interrupt.h>
#endif
#include "dda_maths.h"
#include "dda_lookahead.h"

View File

@ -11,7 +11,9 @@
#include <stdlib.h>
#include <stddef.h>
#include <math.h>
#ifndef SIMULATOR
#include <avr/interrupt.h>
#endif
#include "dda_maths.h"
#include "dda.h"

View File

@ -5,7 +5,9 @@
*/
#include <string.h>
#ifndef SIMULATOR
#include <avr/interrupt.h>
#endif
#include "config.h"
#include "timer.h"

View File

@ -5,7 +5,9 @@
*/
#include <string.h>
#ifndef SIMULATOR
#include <avr/interrupt.h>
#endif
#include "gcode_parse.h"

View File

@ -3,6 +3,7 @@
#include "config.h"
#include <stdint.h>
#include "simulator.h"
#include "temp.h"
#undef DEFINE_HEATER

View File

@ -4,8 +4,10 @@
\brief motherboard <-> extruder board protocol
*/
#ifndef SIMULATOR
#include <avr/io.h>
#include <avr/interrupt.h>
#endif
#include "memory_barrier.h"
#include "config.h"

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include "config.h"
#ifndef enable_transmit
#ifdef MOTHERBOARD
#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR1B &=~MASK(RXEN1); } while(0)
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR1B &= ~(MASK(TXCIE1) | MASK(UDRIE1)); UCSR1B |= MASK(RXEN1); } while(0)
@ -11,6 +12,7 @@
#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR0B &= ~MASK(RXEN0); } while(0)
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B &= ~(MASK(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0)
#endif
#endif
/// list of error codes, not many so far...
enum {

View File

@ -1,6 +1,12 @@
#ifndef _MEMORY_BARRIER_H_
#define _MEMORY_BARRIER_H_
#ifdef SIMULATOR
#define CLI_SEI_BUG_MEMORY_BARRIER()
#define MEMORY_BARRIER()
#define ATOMIC_START
#define ATOMIC_END
#else
#include <util/atomic.h>
#include <avr/version.h>
@ -38,3 +44,4 @@
}
#endif
#endif

View File

@ -24,8 +24,10 @@
ctrl+d \endcode
*/
#ifndef SIMULATOR
#include <avr/io.h>
#include <avr/interrupt.h>
#endif
#include "config.h"
#include "fuses.h"
@ -46,6 +48,7 @@
#include "arduino.h"
#include "clock.h"
#include "intercom.h"
#include "simulator.h"
/// initialise all I/O - set pins as input or output, turn off unused subsystems, etc
void io_init(void) {
@ -228,8 +231,17 @@ void init(void) {
/// this is where it all starts, and ends
///
/// just run init(), then run an endless loop where we pass characters from the serial RX buffer to gcode_parse_char() and check the clocks
#ifdef SIMULATOR
int g_argc;
char** g_argv;
int main (int argc, char** argv)
{
g_argc = argc;
g_argv = argv;
#else
int main (void)
{
#endif
init();
// main loop

View File

@ -7,6 +7,10 @@
#include "config.h"
#ifdef SIMULATOR
#include "simulator.h"
#endif
/*
Power
*/

View File

@ -3,8 +3,11 @@
#include "config.h"
#include <stdint.h>
#ifndef SIMULATOR
#include <avr/io.h>
#include <avr/pgmspace.h>
#endif
#include "simulator.h"
#ifdef USB_SERIAL
#include "usb_serial.h"

View File

@ -5,7 +5,9 @@
*/
#include <stdarg.h>
#ifndef SIMULATOR
#include <avr/pgmspace.h>
#endif
#include "serial.h"
#include "sermsg.h"
@ -94,6 +96,13 @@
\code sersendf_P(PSTR("X:%ld Y:%ld temp:%u.%d flags:%sx Q%su/%su%c\n"), target.X, target.Y, current_temp >> 2, (current_temp & 3) * 25, dda.allflags, mb_head, mb_tail, (queue_full()?'F':(queue_empty()?'E':' '))) \endcode
*/
#ifdef SIMULATOR
#define GET_ARG(T) (va_arg(args, int))
#else
#define GET_ARG(T) (va_arg(args, T))
#endif
void sersendf_P(PGM_P format, ...) {
va_list args;
va_start(args, format);
@ -111,36 +120,36 @@ void sersendf_P(PGM_P format, ...) {
break;
case 'u':
if (j == 4)
serwrite_uint32(va_arg(args, uint32_t));
serwrite_uint32(GET_ARG(uint32_t));
else
serwrite_uint16(va_arg(args, uint16_t));
serwrite_uint16(GET_ARG(uint16_t));
j = 0;
break;
case 'd':
if (j == 4)
serwrite_int32(va_arg(args, int32_t));
serwrite_int32(GET_ARG(uint32_t));
else
serwrite_int16(va_arg(args, int16_t));
serwrite_int16(GET_ARG(uint16_t));
j = 0;
break;
case 'c':
serial_writechar(va_arg(args, uint16_t));
serial_writechar(GET_ARG(uint16_t));
j = 0;
break;
case 'x':
serial_writestr_P(PSTR("0x"));
if (j == 4)
serwrite_hex32(va_arg(args, uint32_t));
serwrite_hex32(GET_ARG(uint32_t));
else if (j == 1)
serwrite_hex8(va_arg(args, uint16_t));
serwrite_hex8(GET_ARG(uint16_t));
else
serwrite_hex16(va_arg(args, uint16_t));
serwrite_hex16(GET_ARG(uint16_t));
j = 0;
break;
/* case 'p':
serwrite_hex16(va_arg(args, uint16_t));*/
serwrite_hex16(GET_ARG(uint16_t));*/
case 'q':
serwrite_int32_vf(va_arg(args, int32_t), 3);
serwrite_int32_vf(GET_ARG(uint32_t), 3);
j = 0;
break;
default:

View File

@ -1,7 +1,10 @@
#ifndef _SERSENDF_H
#define _SERSENDF_H
#ifndef SIMULATOR
#include <avr/pgmspace.h>
#endif
#include "simulator.h"
void sersendf(char *format, ...) __attribute__ ((format (printf, 1, 2)));
void sersendf_P(PGM_P format, ...) __attribute__ ((format (printf, 1, 2)));

165
simulator.h Normal file
View File

@ -0,0 +1,165 @@
#ifdef SIMULATOR
#undef X_STEP_PIN
#undef X_DIR_PIN
#undef X_MIN_PIN
#undef X_ENABLE_PIN
#undef Y_STEP_PIN
#undef Y_DIR_PIN
#undef Y_MIN_PIN
#undef Y_ENABLE_PIN
#undef Z_STEP_PIN
#undef Z_DIR_PIN
#undef Z_MIN_PIN
#undef Z_ENABLE_PIN
#undef E_STEP_PIN
#undef E_DIR_PIN
#undef E_ENABLE_PIN
#undef STEPPER_ENABLE_PIN
#undef PS_MOSFET_PIN
#undef PS_ON_PIN
#undef RX_ENABLE_PIN
#undef TX_ENABLE_PIN
#undef X_MAX_PIN
#undef Y_MAX_PIN
#undef Z_MAX_PIN
#undef READ
#undef WRITE
#undef TOGGLE
#undef SET_INPUT
#undef SET_OUTPUT
#undef GET_INPUT
#undef GET_OUTPUT
// Compiler appeasement
#undef disable_transmit
#undef enable_transmit
#define disable_transmit()
#define enable_transmit()
#undef USB_SERIAL
#ifndef _SIMULATOR_H
#define _SIMULATOR_H
#include <stdint.h>
#include <stdbool.h>
#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
// TODO: Implement simulated EEMEM persistence
#define EEMEM
#define eeprom_read_dword(ptr32) (*(ptr32))
#define eeprom_read_word(ptr16) (*(ptr16))
#define eeprom_write_dword(ptr32, i32) (*(ptr32)=i32)
#define eeprom_write_word(ptr16, i16) (*(ptr16)=i16)
typedef enum {
// Define pins used
X_STEP_PIN,
X_DIR_PIN,
X_MIN_PIN,
X_ENABLE_PIN,
Y_STEP_PIN,
Y_DIR_PIN,
Y_MIN_PIN,
Y_ENABLE_PIN,
Z_STEP_PIN,
Z_DIR_PIN,
Z_MIN_PIN,
Z_ENABLE_PIN,
E_STEP_PIN,
E_DIR_PIN,
E_ENABLE_PIN,
STEPPER_ENABLE_PIN,
SCK,
MOSI,
MISO,
SS,
RX_ENABLE_PIN,
TX_ENABLE_PIN,
/*
* Not used in the simulator. Add them to this list to enable them if needed.
PS_MOSFET_PIN,
PS_ON_PIN,
X_MAX_PIN,
Y_MAX_PIN,
Z_MAX_PIN,
*/
PIN_NB /* End of PINS marker; Put all new pins before this one */
} pin_t;
// AVR stand-ins
typedef enum {
WGM00 = 0,
WGM01,
WGM20,
WGM21,
CS00 = 0,
CS02,
CS20,
CS21,
CS22,
} masks_t;
#undef TEMP_PIN_CHANNEL
#define TEMP_PIN_CHANNEL 0
extern uint8_t ACSR;
extern uint8_t TIMSK1;
extern volatile bool sim_interrupts;
bool READ(pin_t pin);
void WRITE(pin_t pin, bool on);
void SET_OUTPUT(pin_t pin);
void SET_INPUT(pin_t pin);
// Simulate AVR interrupts.
#define ISR(fn) void fn (void)
void TIMER1_COMPA_vect(void);
void TIMER1_COMPB_vect(void);
// Compare-timers for next interrupts.
extern uint16_t OCR1A, OCR1B;
// Interrupt control registers.
extern uint16_t TCCR1A, TCCR1B;
enum { CS10 = 1 , OCIE1B = 3 };
#define TCNT1 (sim_tick_counter())
void sei(void);
#ifdef USE_WATCHDOG
#define wd_init()
#define wd_reset()
#endif
void sim_start(int argc, char ** argv);
void sim_info(const char fmt[], ...);
void sim_debug(const char fmt[], ...);
void sim_error(const char msg[]);
void sim_assert(bool cond, const char msg[]);
void sim_timer_init(void);
void sim_timer_stop(void);
void sim_setTimer(void);
uint16_t sim_tick_counter(void);
inline void cli(void);
inline void cli() { }
#define DIO0_PIN "proof of life"
#endif /* _SIMULATOR_H */
#endif /* SIMULATOR */

15
simulator/analog_sim.c Normal file
View File

@ -0,0 +1,15 @@
#include "analog.h"
#include "simulator.h"
static bool analog_initialised = false;
void analog_init(void) {
sim_info("analog_init: not implemented in simulator");
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;
}

12
simulator/delay_sim.c Normal file
View File

@ -0,0 +1,12 @@
#include <unistd.h>
#include "delay.h"
#include "simulator.h"
void delay_ms(uint32_t ms) {
usleep(ms * 1000);
}
void delay_us(uint16_t us) {
usleep(us);
}

27
simulator/heater_sim.c Normal file
View File

@ -0,0 +1,27 @@
#include "heater.h"
void heater_init(void) {
}
void heater_set(heater_t index, uint8_t value) {
sim_info("heater not implemented in simulator.");
}
void heater_tick(heater_t h, temp_type_t type, uint16_t current_temp, uint16_t target_temp) {
}
uint8_t heaters_all_zero(void) {
return 1;
}
#ifdef EECONFIG
void pid_set_p(heater_t index, int32_t p) {}
void pid_set_i(heater_t index, int32_t i) {}
void pid_set_d(heater_t index, int32_t d) {}
void pid_set_i_limit(heater_t index, int32_t i_limit) {}
void heater_save_settings(void) {}
#endif /* EECONFIG */
void heater_print(uint16_t i) {
}

35
simulator/intercom_sim.c Normal file
View File

@ -0,0 +1,35 @@
#include "intercom.h"
/* Intercom stubs here to appease compiler for build testing.
* Functionally moot.
*/
void intercom_init(void) {
sim_error("simulated intercom is not supported");
}
void send_temperature(uint8_t index, uint16_t temperature) {
}
uint16_t read_temperature(uint8_t index) {
return 0;
}
#ifdef MOTHERBOARD
void set_dio(uint8_t index, uint8_t value) {
}
#else
uint8_t get_dio(uint8_t index) {
return 0;
}
#endif
void set_err(uint8_t err) {
}
uint8_t get_err() {
return 0;
}
void start_send(void) {
}

102
simulator/serial_sim.c Normal file
View File

@ -0,0 +1,102 @@
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include "serial.h"
#include "simulator.h"
static int serial_fd;
static bool serial_initialised = false;
extern int g_argc;
extern char ** g_argv;
void serial_init(void) {
struct termios options;
int argc = g_argc;
char **argv = g_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);
}

144
simulator/simulator.c Normal file
View File

@ -0,0 +1,144 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "simulator.h"
uint8_t ACSR;
uint8_t TIMSK1;
uint16_t
TCCR0A,
TCCR0B,
TCCR1A,
TCCR1B,
TCCR2A,
TCCR2B,
OCR0B,
OCR1A,
OCR1B,
OCR2A,
OCR2B,
TIMSK0,
TIMSK2;
volatile uint8_t
DIO1_WPORT,
DIO2_WPORT,
DIO3_WPORT,
DIO4_WPORT;
/* -- debugging ------------------------------------------------------------ */
static void fgreen(void) { fputs("\033[0;32m" , stdout); }
static void fred(void) { fputs("\033[0;31m" , stdout); }
static void fbreset(void) { fputs("\033[m" , stdout); }
void sim_info(const char fmt[], ...) {
va_list ap;
fgreen();
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
fbreset();
}
void sim_debug(const char fmt[], ...) {
#ifdef SIM_DEBUG
va_list ap;
fcyan();
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
fbreset();
#endif
}
void sim_error(const char msg[]) {
fred();
printf("ERROR: %s\n", msg);
fputc('\n', stdout);
fbreset();
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) {
printf("print_pos: %d, %d, %d, %d\n", x, y, z, e);
sim_info("x:%5d y:%5d z:%5d e:%5d", x, y, z, e);
}
bool READ(pin_t pin) {
sim_assert(pin < PIN_NB, "READ: Pin number out of range");
// Add any necessary reactive pin-handlers here.
return state[pin];
}
void WRITE(pin_t pin, bool s) {
bool old_state = state[pin];
sim_assert(pin < PIN_NB, "WRITE: Pin number out of range");
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) {
sim_assert(pin < PIN_NB, "Pin number out of range");
direction[pin] = out;
}
void SET_INPUT(pin_t pin) {
sim_assert(pin < PIN_NB, "Pin number out of range");
direction[pin] = in;
}

178
simulator/timer_ext.c Normal file
View File

@ -0,0 +1,178 @@
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include "dda_queue.h"
#include "timer.h"
#include "simulator.h"
#include <time.h>
#include <stdio.h> // printf
#include <unistd.h> // usleep
#define TIME_SLOW_FACTOR 1
static void schedule_timer(uint32_t useconds);
static bool timer_initialised = false;
enum {
// One bit per timer
TIMER_OCR1A = 0x1 ,
TIMER_OCR1B = 0x2 ,
};
static volatile uint8_t timer_reason; // Who scheduled this timer
static uint64_t now_us(void) {
struct timespec tv;
int n = clock_gettime(CLOCK_MONOTONIC, &tv);
sim_assert(n == 0, "clock_gettime failed");
// Convert tv to nanoseconds.
uint64_t nsec = tv.tv_sec;
nsec *= 1000 * 1000 * 1000;
nsec += tv.tv_nsec;
// nanoseconds to microseconds
return nsec / 1000;
}
uint16_t sim_tick_counter(void) {
// microseconds to 16-bit clock ticks
return (now_us() / TIME_SLOW_FACTOR) US;
}
extern uint8_t clock_counter_10ms, clock_counter_250ms, clock_counter_1s;
static uint64_t begin;
static uint64_t then;
void sim_timer_init(void) {
then = begin = now_us();
sim_info("timer_init");
timer_initialised = true;
sim_setTimer();
}
void sim_timer_stop(void) {
sim_info("timer_stop");
timer_reason = 0; // Cancel pending timer;
}
static void timer1_isr(int cause, siginfo_t *HowCome, void *ucontext) {
if ( ! sim_interrupts) {
// Interrupts disabled. Schedule another callback in 10us.
schedule_timer(10);
return;
}
sim_interrupts = false;
#ifdef SIM_DEBUG
uint64_t now = now_us();
static unsigned int cc_1s = 0, prev_1s = 0;
if ( ! clock_counter_1s && prev_1s) ++cc_1s;
prev_1s = clock_counter_1s;
//uint16_t now = sim_tick_counter();
uint64_t real = now-begin;
uint64_t avr = cc_1s * 4 + clock_counter_1s;
avr *= 250;
avr += clock_counter_250ms * 10;
avr += clock_counter_10ms;
avr *= 1000 ;
printf("test: Real: %us %u.%03ums AVR: %us %u.%03ums Real/AVR: %u\n",
real / 1000000 , (real % 1000000)/1000 , real % 1000 ,
avr / 1000000 , (avr % 1000000)/1000 , avr % 1000 ,
real / (avr?avr:1) );
printf("test: 10ms=%u 250ms=%u 1s=%u total=%lu actual=%lu\n",
clock_counter_10ms, clock_counter_250ms, clock_counter_1s,
now - begin , now - then);
//printf(" timer1_isr tick_time=%04X now=%04X delta=%u total=%u\n",
// TICK_TIME , now, now_us() - then, (now_us() - begin)/1000000 ) ;
then = now;
#endif
if (timer_reason & TIMER_OCR1A) TIMER1_COMPA_vect();
if (timer_reason & TIMER_OCR1B) TIMER1_COMPB_vect();
timer_reason = 0;
sim_interrupts = true;
// Setup next timer
sim_setTimer();
}
// TODO: Remove 'delay' value and use AVR regs instead
void sim_setTimer() {
// Set callbacks for COMPA and COMPB timers
uint32_t nextA = 0, nextB = 0;
uint16_t now = sim_tick_counter();
sim_assert(timer_initialised, "timer not initialised");
//-- Calculate time in clock ticks until next timer events
if (TIMSK1 & MASK(OCIE1A)) {
sim_debug("Timer1 Interrupt A: Enabled");
nextA = OCR1A - now;
// 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;
// 0 = No timer; 1-0x10000 = time until next occurrence
if ( ! nextB) nextB = 0x10000;
}
//-- Find the nearest event
uint32_t next = nextA;
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;
// FIXME: We will miss events if they occur like this:
// nextA = 0x1000
// nextB = 0x1001
// timer_reason = TIMER_OCR1A
// ISR is triggered and finishes at 0x1002
// => Next trigger for B will not occur until NEXT 0x1001 comes around
// Need some way to notice a missed trigger.
// 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);
if (next) {
sim_debug("OCR1A:%04X OCR1B:%04X now=%04X", OCR1A, OCR1B, now );
sim_debug(" next=%u real=%u", next, actual);
}
//-- Schedule the event
schedule_timer(actual);
}
// Schedule Timer1 callback useconds from now.
// Zero cancels any pending timer.
static void schedule_timer(uint32_t useconds) {
struct itimerval itimer;
struct sigaction sa;
sa.sa_sigaction = timer1_isr;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &sa, 0)) {
sim_error("sigaction");
}
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0; // If signal occurs , trigger again in 10us
itimer.it_value.tv_sec = useconds / 1000000;
itimer.it_value.tv_usec = useconds % 1000000;
setitimer(ITIMER_REAL, &itimer, NULL);
}

7
temp.c
View File

@ -7,8 +7,11 @@
*/
#include <stdlib.h>
#ifndef SIMULATOR
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#endif
#include "simulator.h"
#include "arduino.h"
#include "debug.h"
@ -47,7 +50,11 @@ typedef struct {
#undef DEFINE_TEMP_SENSOR
/// help build list of sensors from entries in config.h
#ifndef SIMULATOR
#define DEFINE_TEMP_SENSOR(name, type, pin, additional) { (type), (pin ## _ADC), (HEATER_ ## name), (additional) },
#else
#define DEFINE_TEMP_SENSOR(name, type, pin, additional) { (type), (TEMP_SENSOR_ ## name), (HEATER_ ## name), (additional) },
#endif
static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] =
{
#include "config.h"

14
timer.c
View File

@ -10,7 +10,9 @@
Teacup has tried numerous timer management methods, and this is the best so far.
*/
#ifndef SIMULATOR
#include <avr/interrupt.h>
#endif
#include "memory_barrier.h"
#include "arduino.h"
@ -119,6 +121,10 @@ void timer_init()
OCR1B = TICK_TIME & 0xFFFF;
// enable interrupt
TIMSK1 = MASK(OCIE1B);
#ifdef SIMULATOR
// Tell simulator
sim_timer_init();
#endif
}
#ifdef MOTHERBOARD
@ -201,11 +207,19 @@ void setTimer(uint32_t delay)
// timer1a interrupt to the far side of the return, protecting the
// stack from recursively clobbering memory.
TIMSK1 |= MASK(OCIE1A);
#ifdef SIMULATOR
// Tell simulator
sim_setTimer();
#endif
}
/// stop timers - emergency stop
void timer_stop() {
// disable all interrupts
TIMSK1 = 0;
#ifdef SIMULATOR
// Tell simulator
sim_timer_stop();
#endif
}
#endif /* ifdef MOTHERBOARD */

View File

@ -2,7 +2,10 @@
#define _TIMER_H
#include <stdint.h>
#ifndef SIMULATOR
#include <avr/io.h>
#endif
#include "simulator.h"
// time-related constants
#define US * (F_CPU / 1000000)

View File

@ -32,6 +32,7 @@
// 2012-10-17: Import to Teacup firmware
#include "config.h"
#include "simulator.h"
/* protect this file from Arduino IDE */
#ifdef USB_SERIAL