4bfc2e6f43d30e032d8515584578e3547fae3f45
[simavr] / examples / board_reprap / src / reprap.c
1 /*
2         simduino.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <libgen.h>
29 #include <pthread.h>
30
31 #include "sim_avr.h"
32 #include "avr_ioport.h"
33 #include "sim_elf.h"
34 #include "sim_hex.h"
35 #include "sim_gdb.h"
36
37 #include "reprap_gl.h"
38
39 #include "button.h"
40 #include "reprap.h"
41 #include "arduidiot_pins.h"
42
43 #define __AVR_ATmega644__
44 #include "marlin/pins.h"
45
46 #include <stdbool.h>
47 #define PROGMEM
48 #include "marlin/Configuration.h"
49
50 /*
51  * these are the sources of heat and cold to register to the heatpots
52  */
53 enum {
54         TALLY_AMBIANT = 1,
55         TALLY_HOTEND_PWM,
56         TALLY_HOTBED,
57         TALLY_HOTEND_FAN,
58 };
59
60 reprap_t reprap;
61
62 avr_t * avr = NULL;
63
64 // gnu hackery to make sure the parameter is expanded
65 #define _TERMISTOR_TABLE(num) \
66                 temptable_##num
67 #define TERMISTOR_TABLE(num) \
68                 _TERMISTOR_TABLE(num)
69
70 /*
71  * called when the AVR change any of the pins on port B
72  * so lets update our buffer
73  */
74 static void
75 hotbed_change_hook(
76                 struct avr_irq_t * irq,
77                 uint32_t value,
78                 void * param)
79 {
80 //      printf("%s %d\n", __func__, value);
81 //      pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
82         heatpot_tally(
83                         &reprap.hotbed,
84                         TALLY_HOTEND_PWM,
85                         value ? 1.0f : 0 );
86 }
87 static void
88 hotend_change_hook(
89                 struct avr_irq_t * irq,
90                 uint32_t value,
91                 void * param)
92 {
93 //      printf("%s %d\n", __func__, value);
94 //      pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
95         heatpot_tally(
96                         &reprap.hotend,
97                         TALLY_HOTBED,
98                         value ? 1.0f : 0 );
99 }
100 static void
101 hotend_fan_change_hook(
102                 struct avr_irq_t * irq,
103                 uint32_t value,
104                 void * param)
105 {
106         printf("%s %d\n", __func__, value);
107 //      pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
108         heatpot_tally(
109                         &reprap.hotend,
110                         TALLY_HOTEND_FAN,
111                         value ? -0.05 : 0 );
112 }
113
114
115
116 char avr_flash_path[1024];
117 int avr_flash_fd = 0;
118
119 // avr special flash initalization
120 // here: open and map a file to enable a persistent storage for the flash memory
121 void avr_special_init( avr_t * avr)
122 {
123         // open the file
124         avr_flash_fd = open(avr_flash_path, O_RDWR|O_CREAT, 0644);
125         if (avr_flash_fd < 0) {
126                 perror(avr_flash_path);
127                 exit(1);
128         }
129         // resize and map the file the file
130         (void)ftruncate(avr_flash_fd, avr->flashend + 1);
131         ssize_t r = read(avr_flash_fd, avr->flash, avr->flashend + 1);
132         if (r != avr->flashend + 1) {
133                 fprintf(stderr, "unable to load flash memory\n");
134                 perror(avr_flash_path);
135                 exit(1);
136         }
137 }
138
139 // avr special flash deinitalization
140 // here: cleanup the persistent storage
141 void avr_special_deinit( avr_t* avr)
142 {
143         puts(__func__);
144         lseek(avr_flash_fd, SEEK_SET, 0);
145         ssize_t r = write(avr_flash_fd, avr->flash, avr->flashend + 1);
146         if (r != avr->flashend + 1) {
147                 fprintf(stderr, "unable to load flash memory\n");
148                 perror(avr_flash_path);
149         }
150         close(avr_flash_fd);
151         uart_pty_stop(&reprap.uart_pty);
152 }
153
154 #define MEGA644_GPIOR0 0x3e
155
156 static void
157 reprap_relief_callback(
158                 struct avr_t * avr,
159                 avr_io_addr_t addr,
160                 uint8_t v,
161                 void * param)
162 {
163 //      printf("%s write %x\n", __func__, addr);
164         static uint16_t tick = 0;
165         if (!(tick++ & 0xf))
166                 usleep(100);
167 }
168
169 static void *
170 avr_run_thread(
171                 void * ignore)
172 {
173         while (1) {
174                 avr_run(avr);
175         }
176         return NULL;
177 }
178
179 void
180 reprap_init(
181                 avr_t * avr,
182                 reprap_p r)
183 {
184         r->avr = avr;
185         uart_pty_init(avr, &r->uart_pty);
186         uart_pty_connect(&r->uart_pty, '0');
187
188         thermistor_init(avr, &r->therm_hotend, 0,
189                         (short*)TERMISTOR_TABLE(TEMP_SENSOR_0),
190                         sizeof(TERMISTOR_TABLE(TEMP_SENSOR_0)) / sizeof(short) / 2,
191                         OVERSAMPLENR, 25.0f);
192         thermistor_init(avr, &r->therm_hotbed, 2,
193                         (short*)TERMISTOR_TABLE(TEMP_SENSOR_BED),
194                         sizeof(TERMISTOR_TABLE(TEMP_SENSOR_BED)) / sizeof(short) / 2,
195                         OVERSAMPLENR, 30.0f);
196         thermistor_init(avr, &r->therm_spare, 1,
197                         (short*)temptable_5, sizeof(temptable_5) / sizeof(short) / 2,
198                         OVERSAMPLENR, 10.0f);
199
200         heatpot_init(avr, &r->hotend, "hotend", 28.0f);
201         heatpot_init(avr, &r->hotbed, "hotbed", 25.0f);
202
203         heatpot_tally(&r->hotend, TALLY_AMBIANT, -0.5f);
204         heatpot_tally(&r->hotbed, TALLY_AMBIANT, -0.3f);
205
206         /* connect heatpot temp output to thermistors */
207         avr_connect_irq(r->hotend.irq + IRQ_HEATPOT_TEMP_OUT,
208                         r->therm_hotend.irq + IRQ_TERM_TEMP_VALUE_IN);
209         avr_connect_irq(r->hotbed.irq + IRQ_HEATPOT_TEMP_OUT,
210                         r->therm_hotbed.irq + IRQ_TERM_TEMP_VALUE_IN);
211
212         avr_irq_register_notify(
213                         get_ardu_irq(avr, HEATER_0_PIN, arduidiot_644),
214                         hotend_change_hook, NULL);
215         avr_irq_register_notify(
216                         get_ardu_irq(avr, FAN_PIN, arduidiot_644),
217                         hotend_fan_change_hook, NULL);
218         avr_irq_register_notify(
219                         get_ardu_irq(avr, HEATER_BED_PIN, arduidiot_644),
220                         hotbed_change_hook, NULL);
221
222         //avr_irq_register_notify()
223         float axis_pp_per_mm[4] = DEFAULT_AXIS_STEPS_PER_UNIT;  // from Marlin!
224         {
225                 avr_irq_t * e = get_ardu_irq(avr, X_ENABLE_PIN, arduidiot_644);
226                 avr_irq_t * s = get_ardu_irq(avr, X_STEP_PIN, arduidiot_644);
227                 avr_irq_t * d = get_ardu_irq(avr, X_DIR_PIN, arduidiot_644);
228                 avr_irq_t * m = get_ardu_irq(avr, X_MIN_PIN, arduidiot_644);
229
230                 stepper_init(avr, &r->step_x, "X", axis_pp_per_mm[0], 100, 200, 0);
231                 stepper_connect(&r->step_x, s, d, e, m, stepper_endstop_inverted);
232         }
233         {
234                 avr_irq_t * e = get_ardu_irq(avr, Y_ENABLE_PIN, arduidiot_644);
235                 avr_irq_t * s = get_ardu_irq(avr, Y_STEP_PIN, arduidiot_644);
236                 avr_irq_t * d = get_ardu_irq(avr, Y_DIR_PIN, arduidiot_644);
237                 avr_irq_t * m = get_ardu_irq(avr, Y_MIN_PIN, arduidiot_644);
238
239                 stepper_init(avr, &r->step_y, "Y", axis_pp_per_mm[1], 100, 200, 0);
240                 stepper_connect(&r->step_y, s, d, e, m, stepper_endstop_inverted);
241         }
242         {
243                 avr_irq_t * e = get_ardu_irq(avr, Z_ENABLE_PIN, arduidiot_644);
244                 avr_irq_t * s = get_ardu_irq(avr, Z_STEP_PIN, arduidiot_644);
245                 avr_irq_t * d = get_ardu_irq(avr, Z_DIR_PIN, arduidiot_644);
246                 avr_irq_t * m = get_ardu_irq(avr, Z_MIN_PIN, arduidiot_644);
247
248                 stepper_init(avr, &r->step_z, "Z", axis_pp_per_mm[2], 20, 130, 0);
249                 stepper_connect(&r->step_z, s, d, e, m, stepper_endstop_inverted);
250         }
251         {
252                 avr_irq_t * e = get_ardu_irq(avr, E0_ENABLE_PIN, arduidiot_644);
253                 avr_irq_t * s = get_ardu_irq(avr, E0_STEP_PIN, arduidiot_644);
254                 avr_irq_t * d = get_ardu_irq(avr, E0_DIR_PIN, arduidiot_644);
255
256                 stepper_init(avr, &r->step_e, "E", axis_pp_per_mm[3], 0, 0, 0);
257                 stepper_connect(&r->step_e, s, d, e, NULL, 0);
258         }
259
260 }
261
262 int main(int argc, char *argv[])
263 {
264         char path[256];
265         strcpy(path, argv[0]);
266         strcpy(path, dirname(path));
267         strcpy(path, dirname(path));
268         printf("Stripped base directory to '%s'\n", path);
269         chdir(path);
270
271         int debug = 0;
272
273         for (int i = 1; i < argc; i++)
274                 if (!strcmp(argv[i], "-d"))
275                         debug++;
276         avr = avr_make_mcu_by_name("atmega644");
277         if (!avr) {
278                 fprintf(stderr, "%s: Error creating the AVR core\n", argv[0]);
279                 exit(1);
280         }
281 //      snprintf(avr_flash_path, sizeof(avr_flash_path), "%s/%s", pwd, "simduino_flash.bin");
282         strcpy(avr_flash_path,  "reprap_flash.bin");
283         // register our own functions
284         avr->special_init = avr_special_init;
285         avr->special_deinit = avr_special_deinit;
286         avr_init(avr);
287         avr->frequency = 20000000;
288         avr->aref = avr->avcc = avr->vcc = 5 * 1000;    // needed for ADC
289
290         elf_firmware_t f;
291         const char * fname = "/opt/reprap/tvrrug/Marlin/Marlin/applet/Marlin.elf";
292         // try to load an ELF file, before trying the .hex
293         if (elf_read_firmware(fname, &f) == 0) {
294                 printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);
295                 avr_load_firmware(avr, &f);
296         } else {
297                 char path[1024];
298                 uint32_t base, size;
299 //              snprintf(path, sizeof(path), "%s/%s", pwd, "ATmegaBOOT_168_atmega328.ihex");
300                 strcpy(path, "marlin/Marlin.hex");
301 //              strcpy(path, "marlin/bootloader-644-20MHz.hex");
302                 uint8_t * boot = read_ihex_file(path, &size, &base);
303                 if (!boot) {
304                         fprintf(stderr, "%s: Unable to load %s\n", argv[0], path);
305                         exit(1);
306                 }
307                 printf("Firmware %04x(%04x in AVR talk): %d bytes (%d words)\n", base, base/2, size, size/2);
308                 memcpy(avr->flash + base, boot, size);
309                 free(boot);
310                 avr->pc = base;
311                 avr->codeend = avr->flashend;
312         }
313         //avr->trace = 1;
314
315         // even if not setup at startup, activate gdb if crashing
316         avr->gdb_port = 1234;
317         if (debug) {
318                 printf("AVR is stopped, waiting on gdb on port %d. Use 'target remote :%d' in avr-gdb\n",
319                                 avr->gdb_port, avr->gdb_port);
320                 avr->state = cpu_Stopped;
321                 avr_gdb_init(avr);
322         }
323
324         // Marlin doesn't loop, sleep, so we don't know when it's idle
325         // I changed Marlin to do a spurious write to the GPIOR0 register so we can trap it
326         avr_register_io_write(avr, MEGA644_GPIOR0, reprap_relief_callback, NULL);
327
328         reprap_init(avr, &reprap);
329
330         gl_init(argc, argv);
331         pthread_t run;
332         pthread_create(&run, NULL, avr_run_thread, NULL);
333
334         gl_runloop();
335
336 }