diff --git a/coolant_control.c b/coolant_control.c index 60cbf2f..21fc106 100644 --- a/coolant_control.c +++ b/coolant_control.c @@ -46,7 +46,8 @@ void coolant_stop() void coolant_run(uint8_t mode) { if (sys.state == STATE_CHECK_MODE) { return; } - + + protocol_auto_cycle_start(); //temp fix for M8 lockup protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program. if (mode == COOLANT_FLOOD_ENABLE) { COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT); diff --git a/serial.c b/serial.c index 29e361c..2ef8eda 100644 --- a/serial.c +++ b/serial.c @@ -178,6 +178,7 @@ ISR(SERIAL_RX) #endif } + //TODO: else alarm on overflow? } } diff --git a/sim/.gitignore b/sim/.gitignore index 59a9a43..91eb721 100644 --- a/sim/.gitignore +++ b/sim/.gitignore @@ -1 +1,2 @@ grbl_sim.exe +*.dat diff --git a/sim/Makefile b/sim/Makefile index bece555..176587b 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -15,11 +15,14 @@ # You should have received a copy of the GNU General Public License # along with Grbl. If not, see . -OBJECTS = main.o simulator.o runtime.o ../protocol.o ../planner.o ../settings.o ../print.o ../nuts_bolts.o eeprom.o serial.o avr/pgmspace.o avr/interrupt.o util/delay.o util/floatunsisf.o ../stepper.o ../gcode.o ../spindle_control.o ../motion_control.o ../limits.o ../report.o ../coolant_control.o +PLATFORM = WINDOWS + +OBJECTS = main.o simulator.o serial.o ../main.o ../protocol.o ../planner.o ../settings.o ../print.o ../nuts_bolts.o eeprom.o ../serial.o avr/pgmspace.o avr/interrupt.o avr/io.o util/delay.o util/floatunsisf.o ../stepper.o ../gcode.o ../spindle_control.o ../motion_control.o ../limits.o ../report.o ../coolant_control.o ../probe.o ../system.o platform_$(PLATFORM).o CLOCK = 16000000 EXE_NAME = grbl_sim.exe -COMPILE = $(CC) -Wall -Os -DF_CPU=$(CLOCK) -include config.h -I. - +COMPILE = $(CC) -Wall -g -DF_CPU=$(CLOCK) -include config.h -I. -DPLAT_$(PLATFORM) +LINUX_LIBRARIES = -lrt -pthread +WINDOWS_LIBRARIES = # symbolic targets: all: main @@ -30,15 +33,18 @@ clean: # file targets: main: $(OBJECTS) - $(COMPILE) -o $(EXE_NAME) $(OBJECTS) -lm + $(COMPILE) -o $(EXE_NAME) $(OBJECTS) -lm $($(PLATFORM)_LIBRARIES) %.o: %.c - $(COMPILE) -c $< -o $@ - -../protocol.o: ../protocol.c - $(COMPILE) -include rename_execute_runtime.h -c $< -o $@ + $(COMPILE) -c $< -o $@ ../planner.o: ../planner.c $(COMPILE) -include planner_inject_accessors.c -c $< -o $@ +../serial.o: ../serial.c + $(COMPILE) -include serial_hooks.h -c $< -o $@ + +../main.o: ../main.c + $(COMPILE) -include rename_main.h -c $< -o $@ + diff --git a/sim/README.md b/sim/README.md index 6e266b4..19fd378 100644 --- a/sim/README.md +++ b/sim/README.md @@ -9,3 +9,10 @@ What can you do with Grbl Sim? - Visualize a g-code program by having the simulator parse and execute to a GUI. Fluctuations in feed rates by the acceleration planner can be viewed as well. - A powerful debugging tool for development. - Each of the AVR functions are replaced with dummy functions, like the stepper ISR. These could be written to whatever you need. For example, output simulated step pulses over time and examine its performance. + +Realtime modifications by Adam Shelly: + + Simulates Atmel hardware in separate thread. Runs in aproximate realtime. + + On Linux, use `socat PTY,raw,link=/dev/ttyFAKE,echo=0 "EXEC:'./grbl_sim.exe -n -s step.out -b block.out',pty,raw,echo=0"` to create a fake serial port connected to the simulator. This is useful for testing grbl interface software. + diff --git a/sim/avr/interrupt.c b/sim/avr/interrupt.c index 10b5225..2bcbe0d 100644 --- a/sim/avr/interrupt.c +++ b/sim/avr/interrupt.c @@ -21,23 +21,115 @@ */ #include "interrupt.h" +#include "io.h" + +//pseudo-Interrupt vector table +isr_fp compa_vect[6]={0}; +isr_fp compb_vect[6]={0}; +isr_fp ovf_vect[6]={0}; + + +void sei() {io.sreg|=SEI;} +void cli() {io.sreg&=~SEI;} + + + +int16_t sim_scaling[8]={0,1,8,64,256,1024,1,1}; //clock scalars +//Timer/Counter modes: these are incomplete, but enough for this application +enum sim_wgm_mode { + wgm_NORMAL, + wgm_CTC, + wgm_FAST_PWM, + wgm_PHASE_PWM, + wgm_PH_F_PWM, + wgm_RESERVED +}; + +enum sim_wgm_mode sim_wgm0[4] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_CTC,wgm_FAST_PWM}; +enum sim_wgm_mode sim_wgmN[8] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_PHASE_PWM,wgm_PH_F_PWM, + wgm_CTC, wgm_FAST_PWM, wgm_FAST_PWM, wgm_FAST_PWM}; + +void timer_interrupts() { + int i; + uint8_t ien = io.sreg&SEI; //interrupts enabled? + io.prescaler++; + + //all clocks + for (i=0;i<2;i++){ + + uint8_t cs = io.tccrb[i]&7; //clock select bits + int16_t increment = sim_scaling[cs]; + //check scaling to see if timer fires + if (increment && (io.prescaler&(increment-1))==0) { + + //select waveform generation mode + enum sim_wgm_mode mode; + if (i==0 || i==2) { //(T0 and T2 are different from rest) + uint8_t wgm = io.tccra[i]&3; //look at low 2 bits + mode = sim_wgm0[wgm]; + } + else { + uint8_t wgm = ((io.tccrb[i]&8)>>1) | (io.tccra[i]&3); //only using 3 bits for now + mode = sim_wgmN[wgm]; + } + + //tick + io.tcnt[i]++; + //comparators + if ((io.timsk[i]&(1< - -// dummy register variables -extern uint16_t timsk0; -extern uint16_t timsk1; -extern uint16_t timsk2; -extern uint16_t tcnt0; -extern uint16_t tcnt2; -extern uint16_t tccr0b; -extern uint16_t tccr0a; -extern uint16_t tccr2a; -extern uint16_t tccr2b; -extern uint16_t tccr1b; -extern uint16_t tccr1a; -extern uint16_t ocr1a; -extern uint16_t ocr2a; -extern uint16_t pcmsk0; -extern uint16_t pcicr; - // macros to turn avr interrupts into regular functions -#define TIMER1_COMPA_vect +//#define TIMER1_COMPA_vect #define ISR(a) void interrupt_ ## a () -// enable interrupts does nothing in the simulation environment +// Stub of the timer interrupt functions we need +void interrupt_TIMER0_COMPA_vect(); +void interrupt_TIMER1_COMPA_vect(); +void interrupt_TIMER0_OVF_vect(); +void interrupt_SERIAL_UDRE(); +void interrupt_SERIAL_RX(); + + +//pseudo-Interrupt vector table +typedef void(*isr_fp)(void); +extern isr_fp compa_vect[6]; +extern isr_fp compb_vect[6]; +extern isr_fp ovf_vect[6]; + + +// enable interrupts now does something in the simulation environment +#define SEI 0x80 void sei(); void cli(); -// dummy macros for interrupt related registers -#define TIMSK0 timsk0 -#define TIMSK1 timsk1 -#define TIMSK2 timsk2 -#define OCR1A ocr1a -#define OCR2A ocr2a -#define OCIE1A 0 -#define OCIE2A 0 -#define TCNT0 tcnt0 -#define TCNT2 tcnt2 -#define TCCR0B tccr0b -#define TCCR0A tccr0a -#define TCCR1A tccr1a -#define TCCR1B tccr1b -#define TCCR2A tccr2a -#define TCCR2B tccr2b -#define CS21 0 -#define CS10 0 -#define WGM13 0 -#define WGM12 0 -#define WGM11 0 -#define WGM10 0 -#define WGM21 0 -#define COM1A0 0 -#define COM1B0 0 -#define TOIE0 0 -#define TOIE2 0 -#define PCICR pcicr +//simulate timer operation +void timer_interrupts(); + + #endif diff --git a/sim/avr/io.c b/sim/avr/io.c new file mode 100644 index 0000000..8290fec --- /dev/null +++ b/sim/avr/io.c @@ -0,0 +1,4 @@ +#include "io.h" + +// dummy register variables +volatile io_sim_t io={{0}}; diff --git a/sim/avr/io.h b/sim/avr/io.h index 885021a..df8a515 100644 --- a/sim/avr/io.h +++ b/sim/avr/io.h @@ -1,5 +1,6 @@ /* - io.h - dummy replacement for the avr include of the same name + interrupt.h - replacement for the avr include of the same name to provide + dummy register variables and macros Part of Grbl Simulator @@ -19,3 +20,182 @@ along with Grbl. If not, see . */ + +#ifndef io_h +#define io_h + +#include + +union hilo16 { + uint16_t w; + struct { + uint8_t l; //TODO: check that these are right order on x86. Doesn't matter for current usage, but might someday + uint8_t h; + }; +}; + +enum { + SIM_A, SIM_B, SIM_C, SIM_D, SIM_E, + SIM_F, SIM_G, SIM_H, SIM_J, SIM_K, SIM_L, + SIM_PORT_COUNT +}; + +#define SIM_N_TIMERS 6 + + +// dummy register variables +typedef struct io_sim { + uint8_t ddr[SIM_PORT_COUNT]; + uint8_t port[SIM_PORT_COUNT]; + uint8_t pin[SIM_PORT_COUNT]; + uint8_t timsk[SIM_N_TIMERS]; + uint16_t ocra[SIM_N_TIMERS]; + uint16_t ocrb[SIM_N_TIMERS]; + uint16_t ocrc[SIM_N_TIMERS]; + uint16_t tcnt[SIM_N_TIMERS]; //tcint0 is really only 8bit + uint8_t tccra[SIM_N_TIMERS]; + uint8_t tccrb[SIM_N_TIMERS]; + uint8_t tifr[SIM_N_TIMERS]; + uint8_t pcicr; + uint8_t pcmsk[3]; + uint8_t ucsr0[3]; + uint8_t udr[3]; + union hilo16 ubrr0; + + uint16_t prescaler; //continuously running + uint8_t sreg; + + +} io_sim_t; +volatile extern io_sim_t io; + + + + +// dummy macros for interrupt related registers +#define PORTA io.port[SIM_A] +#define PORTB io.port[SIM_B] +#define PORTC io.port[SIM_C] +#define PORTD io.port[SIM_D] +#define PORTE io.port[SIM_E] +#define PORTF io.port[SIM_F] +#define PORTG io.port[SIM_G] +#define PORTH io.port[SIM_H] +#define PORTJ io.port[SIM_J] +#define PORTK io.port[SIM_K] +#define PORTL io.port[SIM_L] + +#define DDRA io.ddr[SIM_A] +#define DDRB io.ddr[SIM_B] +#define DDRC io.ddr[SIM_C] +#define DDRD io.ddr[SIM_D] +#define DDRE io.ddr[SIM_E] +#define DDRF io.ddr[SIM_F] +#define DDRG io.ddr[SIM_G] +#define DDRH io.ddr[SIM_H] +#define DDRJ io.ddr[SIM_J] + +#define PINA io.pin[SIM_A] +#define PINB io.pin[SIM_B] +#define PINC io.pin[SIM_C] +#define PIND io.pin[SIM_D] +#define PINE io.pin[SIM_E] +#define PINF io.pin[SIM_F] +#define PING io.pin[SIM_G] +#define PINH io.pin[SIM_H] +#define PINJ io.pin[SIM_J] +#define PINK io.pin[SIM_K] +#define PINL io.pin[SIM_L] + + +#define TIMSK0 io.timsk[0] +#define TIMSK1 io.timsk[1] +#define TIMSK2 io.timsk[2] +#define TIMSK3 io.timsk[3] +#define TIMSK4 io.timsk[4] +#define TIMSK5 io.timsk[5] + + +#define SIM_TOV 0 +#define SIM_OCA 1 +#define SIM_OCB 2 +#define SIM_OCC 3 +#define SIM_ICI 5 + +#define OCIE0A SIM_OCA +#define OCIE0B SIM_OCB +#define TOIE0 SIM_TOV + +#define ICIE1 SIM_ICI +#define OCIE1C SIM_OCC +#define OCIE1B SIM_OCB +#define OCIE1A SIM_OCA +#define TOIE1 SIM_ICI + +#define ICIE2 SIM_ICI +#define OCIE2C SIM_OCC +#define OCIE2B SIM_OCB +#define OCIE2A SIM_OCA +#define TOIE2 SIM_TOV + +#define OCR0A io.ocra[0] +#define OCR1A io.ocra[1] +#define OCR2A io.ocra[2] + //There are more.. + + +#define TCNT0 io.tcnt[0] +#define TCNT1 io.tcnt[1] +#define TCNT2 io.tcnt[2] + +#define TCCR0B io.tccra[0] +#define TCCR0A io.tccrb[0] +#define TCCR1A io.tccra[1] +#define TCCR1B io.tccrb[1] +#define TCCR2A io.tccra[2] +#define TCCR2B io.tccrb[2] + +#define CS00 0 +#define CS01 1 +#define CS12 2 +#define CS11 1 +#define CS10 0 +#define CS21 1 + +#define WGM13 4 +#define WGM12 3 +#define WGM11 1 +#define WGM10 0 +#define WGM21 1 + +#define COM1A1 7 +#define COM1A0 6 +#define COM1B1 5 +#define COM1B0 4 +#define COM1C1 3 +#define COM1C0 2 + + +#define PCICR io.pcicr +#define PCIE0 0 +#define PCIE1 1 + +//serial channel +#define UCSR0A io.ucsr0[SIM_A] +#define UCSR0B io.ucsr0[SIM_B] +#define UDR0 io.udr[0] +#define UDRIE0 0 +#define RXCIE0 1 +#define RXEN0 2 +#define TXEN0 3 +#define U2X0 4 +#define UBRR0H io.ubrr0.h +#define UBRR0L io.ubrr0.l + +#define PCMSK0 io.pcmsk[0] +#define PCMSK1 io.pcmsk[1] +#define PCMSK2 io.pcmsk[2] + + + +#endif diff --git a/sim/avr/wdt.h b/sim/avr/wdt.h new file mode 100644 index 0000000..482f4fd --- /dev/null +++ b/sim/avr/wdt.h @@ -0,0 +1 @@ +uint16_t wdt; diff --git a/sim/config.h b/sim/config.h index 404accd..5baa20c 100644 --- a/sim/config.h +++ b/sim/config.h @@ -24,94 +24,5 @@ #include "../config.h" #include - -// dummy register variables implemented in simulator.c -extern uint8_t stepping_ddr; -extern uint8_t stepping_port; -extern uint8_t spindle_ddr; -extern uint8_t spindle_port; -extern uint8_t limit_ddr; -extern uint8_t limit_port; -extern uint8_t limit_int_reg; -extern uint8_t pinout_ddr; -extern uint8_t pinout_port; -extern uint8_t pinout_int_reg; -extern uint8_t coolant_flood_ddr; -extern uint8_t coolant_flood_port; - -// ReDefine pin-assignments -#undef STEPPING_DDR -#define STEPPING_DDR stepping_ddr -#undef STEPPING_PORT -#define STEPPING_PORT stepping_port -#undef X_STEP_BIT -#define X_STEP_BIT 2 // Uno Digital Pin 2 -#undef Y_STEP_BIT -#define Y_STEP_BIT 3 // Uno Digital Pin 3 -#undef Z_STEP_BIT -#define Z_STEP_BIT 4 // Uno Digital Pin 4 -#undef X_DIRECTION_BIT -#define X_DIRECTION_BIT 5 // Uno Digital Pin 5 -#undef Y_DIRECTION_BIT -#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6 -#undef Z_DIRECTION_BIT -#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7 - -#undef STEPPERS_DISABLE_DDR -#define STEPPERS_DISABLE_DDR stepping_ddr -#undef STEPPERS_DISABLE_PORT -#define STEPPERS_DISABLE_PORT stepping_port -#undef STEPPERS_DISABLE_BIT -#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8 - -#undef LIMIT_DDR -#define LIMIT_DDR limit_ddr -#undef LIMIT_PORT -#define LIMIT_PORT limit_port -#undef LIMIT_PIN -#define LIMIT_PIN limit_port -#undef X_LIMIT_BIT -#define X_LIMIT_BIT 1 // Uno Digital Pin 9 -#undef Y_LIMIT_BIT -#define Y_LIMIT_BIT 2 // Uno Digital Pin 10 -#undef Z_LIMIT_BIT -#define Z_LIMIT_BIT 3 // Uno Digital Pin 11 -#undef LIMIT_INT -#define LIMIT_INT 0 -#undef LIMIT_PCMSK -#define LIMIT_PCMSK limit_int_reg - -#undef SPINDLE_ENABLE_DDR -#define SPINDLE_ENABLE_DDR spindle_ddr -#undef SPINDLE_ENABLE_PORT -#define SPINDLE_ENABLE_PORT spindle_port -#undef SPINDLE_ENABLE_BIT -#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12 - -#undef SPINDLE_DIRECTION_DDR -#define SPINDLE_DIRECTION_DDR spindle_ddr -#undef SPINDLE_DIRECTION_PORT -#define SPINDLE_DIRECTION_PORT spindle_port -#undef SPINDLE_DIRECTION_BIT -#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 - -#undef PINOUT_DDR -#define PINOUT_DDR pinout_ddr -#undef PINOUT_PORT -#define PINOUT_PORT pinout_port -#undef PINOUT_PIN -#define PINOUT_PIN pinout_port -#undef PINOUT_PCMSK -#define PINOUT_PCMSK pinout_int_reg -#undef PINOUT_INT -#define PINOUT_INT 0 - -#undef COOLANT_FLOOD_DDR -#define COOLANT_FLOOD_DDR coolant_flood_ddr -#undef COOLANT_FLOOD_PORT -#define COOLANT_FLOOD_PORT coolant_flood_port -#undef COOLANT_FLOOD_BIT -#define COOLANT_FLOOD_BIT 0 - - +#define AUTO_REPORT_MOVE_DONE #endif diff --git a/sim/eeprom.c b/sim/eeprom.c index 5c3c3f3..0291e85 100644 --- a/sim/eeprom.c +++ b/sim/eeprom.c @@ -21,18 +21,75 @@ */ // These are never called in the simulator +#include +#define MAX_EEPROM_SIZE 4096 //4KB EEPROM in Mega + + +FILE* eeprom_create_empty_file(){ + FILE* fp = fopen("EEPROM.DAT","w+b"); + int i; + if (fp){ + for(i=0;i 0; size--) { + checksum = (checksum << 1) || (checksum >> 7); + checksum += *source; + eeprom_put_char(destination++, *(source++)); + } + eeprom_put_char(destination, checksum); } int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) { - return 0; + unsigned char data, checksum = 0; + for(; size > 0; size--) { + data = eeprom_get_char(source++); + checksum = (checksum << 1) || (checksum >> 7); + checksum += data; + *(destination++) = data; + } + return(checksum == eeprom_get_char(source)); } // end of file diff --git a/sim/eeprom.h b/sim/eeprom.h new file mode 100644 index 0000000..6b9a562 --- /dev/null +++ b/sim/eeprom.h @@ -0,0 +1,3 @@ + +#include "../eeprom.h" +void eeprom_close(); diff --git a/sim/main.c b/sim/main.c index d157ac3..e2a4e2e 100644 --- a/sim/main.c +++ b/sim/main.c @@ -34,18 +34,106 @@ #include "simulator.h" +arg_vars_t args; +const char* progname; + +int usage(const char* badarg){ + if (badarg){ + printf("Unrecognized option %s\n",badarg); + } + printf("Usage: \n" + "%s [options] [time_step] [block_file]\n" + " Options:\n" + " -r : minimum time step for printing stepper values. Default=0=no print.\n" + " -t