d8f8ce08f4c4c9cbe93ca063bb1c93464add7fd8
[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 #include "sim_vcd_file.h"
37
38 #include "mongoose.h"
39
40 #include "button.h"
41 #include "uart_pty.h"
42 #include "thermistor.h"
43 #include "thermistor.h"
44 #include "heatpot.h"
45 #include "stepper.h"
46
47 #define __AVR_ATmega644__
48 #include "marlin/pins.h"
49
50 #include <stdbool.h>
51 #define PROGMEM
52 #include "marlin/Configuration.h"
53
54 /*
55  * these are the sources of heat and cold to register to the heatpots
56  */
57 enum {
58         TALLY_HOTEND_PWM        = 1,
59         TALLY_HOTBED,
60         TALLY_HOTEND_FAN,
61 };
62
63 thermistor_t    therm_hotend;
64 thermistor_t    therm_hotbed;
65 thermistor_t    therm_spare;
66 heatpot_t               hotend;
67 heatpot_t               hotbed;
68
69 stepper_t               step_x, step_y, step_z, step_e;
70
71 uart_pty_t uart_pty;
72 avr_t * avr = NULL;
73 avr_vcd_t vcd_file;
74
75 typedef struct ardupin_t {
76         uint32_t port : 7, pin : 3, analog : 1, adc : 3, pwm : 1, ardupin;
77 } ardupin_t, *ardupin_p;
78
79 ardupin_t arduidiot_644[32] = {
80         [ 0] = { .ardupin =  0, .port = 'B', .pin =  0 },
81         [ 1] = { .ardupin =  1, .port = 'B', .pin =  1 },
82         [ 2] = { .ardupin =  2, .port = 'B', .pin =  2 },
83         [ 3] = { .ardupin =  3, .port = 'B', .pin =  3 },
84         [ 4] = { .ardupin =  4, .port = 'B', .pin =  4 },
85         [ 5] = { .ardupin =  5, .port = 'B', .pin =  5 },
86         [ 6] = { .ardupin =  6, .port = 'B', .pin =  6 },
87         [ 7] = { .ardupin =  7, .port = 'B', .pin =  7 },
88
89         [ 8] = { .ardupin =  8, .port = 'D', .pin =  0 },
90         [ 9] = { .ardupin =  9, .port = 'D', .pin =  1 },
91         [10] = { .ardupin = 10, .port = 'D', .pin =  2 },
92         [11] = { .ardupin = 11, .port = 'D', .pin =  3 },
93         [12] = { .ardupin = 12, .port = 'D', .pin =  4 },
94         [13] = { .ardupin = 13, .port = 'D', .pin =  5 },
95         [14] = { .ardupin = 14, .port = 'D', .pin =  6 },
96         [15] = { .ardupin = 15, .port = 'D', .pin =  7 },
97
98         [16] = { .ardupin = 16, .port = 'C', .pin =  0 },
99         [17] = { .ardupin = 17, .port = 'C', .pin =  1 },
100         [18] = { .ardupin = 18, .port = 'C', .pin =  2 },
101         [19] = { .ardupin = 19, .port = 'C', .pin =  3 },
102         [20] = { .ardupin = 20, .port = 'C', .pin =  4 },
103         [21] = { .ardupin = 21, .port = 'C', .pin =  5 },
104         [22] = { .ardupin = 22, .port = 'C', .pin =  6 },
105         [23] = { .ardupin = 23, .port = 'C', .pin =  7 },
106
107         [24] = { .ardupin = 24, .port = 'A', .pin =  7, .analog = 1, .adc = 7 },
108         [25] = { .ardupin = 25, .port = 'A', .pin =  6, .analog = 1, .adc = 6 },
109         [26] = { .ardupin = 26, .port = 'A', .pin =  5, .analog = 1, .adc = 5 },
110         [27] = { .ardupin = 27, .port = 'A', .pin =  4, .analog = 1, .adc = 4 },
111         [28] = { .ardupin = 28, .port = 'A', .pin =  3, .analog = 1, .adc = 3 },
112         [29] = { .ardupin = 29, .port = 'A', .pin =  2, .analog = 1, .adc = 2 },
113         [30] = { .ardupin = 30, .port = 'A', .pin =  1, .analog = 1, .adc = 1 },
114         [31] = { .ardupin = 31, .port = 'A', .pin =  0, .analog = 1, .adc = 0 },
115 };
116
117 // gnu hackery to make sure the parameter is expanded
118 #define _TERMISTOR_TABLE(num) \
119                 temptable_##num
120 #define TERMISTOR_TABLE(num) \
121                 _TERMISTOR_TABLE(num)
122
123 struct avr_irq_t *
124 get_ardu_irq(
125                 struct avr_t * avr,
126                 int ardupin,
127                 ardupin_t pins[])
128 {
129         if (pins[ardupin].ardupin != ardupin) {
130                 printf("%s pin %d isn't correct in table\n", __func__, ardupin);
131                 return NULL;
132         }
133         struct avr_irq_t * irq = avr_io_getirq(avr,
134                         AVR_IOCTL_IOPORT_GETIRQ(pins[ardupin].port), pins[ardupin].pin);
135         if (!irq) {
136                 printf("%s pin %d PORT%C%d not found\n", __func__, ardupin, pins[ardupin].port, pins[ardupin].pin);
137                 return NULL;
138         }
139         return irq;
140 }
141
142 /*
143  * called when the AVR change any of the pins on port B
144  * so lets update our buffer
145  */
146 void hotbed_change_hook(struct avr_irq_t * irq, uint32_t value, void * param)
147 {
148         printf("%s %d\n", __func__, value);
149 //      pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
150 }
151
152
153 char avr_flash_path[1024];
154 int avr_flash_fd = 0;
155
156 // avr special flash initalization
157 // here: open and map a file to enable a persistent storage for the flash memory
158 void avr_special_init( avr_t * avr)
159 {
160         // open the file
161         avr_flash_fd = open(avr_flash_path, O_RDWR|O_CREAT, 0644);
162         if (avr_flash_fd < 0) {
163                 perror(avr_flash_path);
164                 exit(1);
165         }
166         // resize and map the file the file
167         (void)ftruncate(avr_flash_fd, avr->flashend + 1);
168         ssize_t r = read(avr_flash_fd, avr->flash, avr->flashend + 1);
169         if (r != avr->flashend + 1) {
170                 fprintf(stderr, "unable to load flash memory\n");
171                 perror(avr_flash_path);
172                 exit(1);
173         }
174 }
175
176 // avr special flash deinitalization
177 // here: cleanup the persistent storage
178 void avr_special_deinit( avr_t* avr)
179 {
180         puts(__func__);
181         lseek(avr_flash_fd, SEEK_SET, 0);
182         ssize_t r = write(avr_flash_fd, avr->flash, avr->flashend + 1);
183         if (r != avr->flashend + 1) {
184                 fprintf(stderr, "unable to load flash memory\n");
185                 perror(avr_flash_path);
186         }
187         close(avr_flash_fd);
188         uart_pty_stop(&uart_pty);
189 }
190
191 static void *
192 mongoose_callback(
193         enum mg_event event,
194         struct mg_connection *conn,
195         const struct mg_request_info *request_info)
196 {
197         if (event == MG_NEW_REQUEST) {
198                 // Echo requested URI back to the client
199                 mg_printf(conn, "HTTP/1.1 200 OK\r\n"
200                                 "Content-Type: text/plain\r\n\r\n"
201                                 "%s", request_info->uri);
202                 return ""; // Mark as processed
203         } else {
204                 return NULL;
205         }
206 }
207
208 #define MEGA644_GPIOR0 0x3e
209
210 static void
211 reprap_relief_callback(
212                 struct avr_t * avr,
213                 avr_io_addr_t addr,
214                 uint8_t v,
215                 void * param)
216 {
217 //      printf("%s write %x\n", __func__, addr);
218         usleep(1000);
219 }
220
221
222 int main(int argc, char *argv[])
223 {
224         int debug = 0;
225
226         for (int i = 1; i < argc; i++)
227                 if (!strcmp(argv[i], "-d"))
228                         debug++;
229         avr = avr_make_mcu_by_name("atmega644");
230         if (!avr) {
231                 fprintf(stderr, "%s: Error creating the AVR core\n", argv[0]);
232                 exit(1);
233         }
234 //      snprintf(avr_flash_path, sizeof(avr_flash_path), "%s/%s", pwd, "simduino_flash.bin");
235         strcpy(avr_flash_path,  "reprap_flash.bin");
236         // register our own functions
237         avr->special_init = avr_special_init;
238         avr->special_deinit = avr_special_deinit;
239         avr_init(avr);
240         avr->frequency = 20000000;
241         avr->aref = avr->avcc = avr->vcc = 5 * 1000;    // needed for ADC
242
243         if (0) {
244                 elf_firmware_t f;
245                 const char * fname = "/opt/reprap/tvrrug/Marlin.base/Marlin/applet/Marlin.elf";
246                 elf_read_firmware(fname, &f);
247
248                 printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);
249                 avr_load_firmware(avr, &f);
250         } else {
251                 char path[1024];
252                 uint32_t base, size;
253 //              snprintf(path, sizeof(path), "%s/%s", pwd, "ATmegaBOOT_168_atmega328.ihex");
254                 strcpy(path, "marlin/Marlin.hex");
255 //              strcpy(path, "marlin/bootloader-644-20MHz.hex");
256                 uint8_t * boot = read_ihex_file(path, &size, &base);
257                 if (!boot) {
258                         fprintf(stderr, "%s: Unable to load %s\n", argv[0], path);
259                         exit(1);
260                 }
261                 printf("Firmware %04x(%04x in AVR talk): %d bytes (%d words)\n", base, base/2, size, size/2);
262                 memcpy(avr->flash + base, boot, size);
263                 free(boot);
264                 avr->pc = base;
265                 avr->codeend = avr->flashend;
266         }
267         //avr->trace = 1;
268
269         // even if not setup at startup, activate gdb if crashing
270         avr->gdb_port = 1234;
271         if (debug) {
272                 printf("AVR is stopped, waiting on gdb on port %d. Use 'target remote :%d' in avr-gdb\n",
273                                 avr->gdb_port, avr->gdb_port);
274                 avr->state = cpu_Stopped;
275                 avr_gdb_init(avr);
276         }
277
278         // Marlin doesn't loop, sleep, so we don't know when it's idle
279         // I changed Marlin to do a spurious write to the GPIOR0 register so we can trap it
280         avr_register_io_write(avr, MEGA644_GPIOR0, reprap_relief_callback, NULL);
281
282         uart_pty_init(avr, &uart_pty);
283         uart_pty_connect(&uart_pty, '0');
284
285         thermistor_init(avr, &therm_hotend, 0,
286                         (short*)TERMISTOR_TABLE(TEMP_SENSOR_0),
287                         sizeof(TERMISTOR_TABLE(TEMP_SENSOR_0)) / sizeof(short) / 2,
288                         OVERSAMPLENR, 25.0f);
289         thermistor_init(avr, &therm_hotbed, 2,
290                         (short*)TERMISTOR_TABLE(TEMP_SENSOR_BED),
291                         sizeof(TERMISTOR_TABLE(TEMP_SENSOR_BED)) / sizeof(short) / 2,
292                         OVERSAMPLENR, 30.0f);
293         thermistor_init(avr, &therm_spare, 1,
294                         (short*)temptable_5, sizeof(temptable_5) / sizeof(short) / 2,
295                         OVERSAMPLENR, 10.0f);
296
297         heatpot_init(avr, &hotend, "hotend", 28.0f);
298         heatpot_init(avr, &hotbed, "hotbed", 25.0f);
299
300         /* connect heatpot temp output to thermistors */
301         avr_connect_irq(hotend.irq + IRQ_HEATPOT_TEMP_OUT, therm_hotend.irq + IRQ_TERM_TEMP_VALUE_IN);
302         avr_connect_irq(hotbed.irq + IRQ_HEATPOT_TEMP_OUT, therm_hotbed.irq + IRQ_TERM_TEMP_VALUE_IN);
303
304         float axis_pp_per_mm[4] = DEFAULT_AXIS_STEPS_PER_UNIT;  // from Marlin!
305         {
306                 avr_irq_t * e = get_ardu_irq(avr, X_ENABLE_PIN, arduidiot_644);
307                 avr_irq_t * s = get_ardu_irq(avr, X_STEP_PIN, arduidiot_644);
308                 avr_irq_t * d = get_ardu_irq(avr, X_DIR_PIN, arduidiot_644);
309                 avr_irq_t * m = get_ardu_irq(avr, X_MIN_PIN, arduidiot_644);
310
311                 stepper_init(avr, &step_x, "X", axis_pp_per_mm[0], 100, 220, 0);
312                 stepper_connect(&step_x, s, d, e, m, stepper_endstop_inverted);
313         }
314         {
315                 avr_irq_t * e = get_ardu_irq(avr, Y_ENABLE_PIN, arduidiot_644);
316                 avr_irq_t * s = get_ardu_irq(avr, Y_STEP_PIN, arduidiot_644);
317                 avr_irq_t * d = get_ardu_irq(avr, Y_DIR_PIN, arduidiot_644);
318                 avr_irq_t * m = get_ardu_irq(avr, Y_MIN_PIN, arduidiot_644);
319
320                 stepper_init(avr, &step_y, "Y", axis_pp_per_mm[1], 100, 220, 0);
321                 stepper_connect(&step_y, s, d, e, m, stepper_endstop_inverted);
322         }
323         {
324                 avr_irq_t * e = get_ardu_irq(avr, Z_ENABLE_PIN, arduidiot_644);
325                 avr_irq_t * s = get_ardu_irq(avr, Z_STEP_PIN, arduidiot_644);
326                 avr_irq_t * d = get_ardu_irq(avr, Z_DIR_PIN, arduidiot_644);
327                 avr_irq_t * m = get_ardu_irq(avr, Z_MIN_PIN, arduidiot_644);
328
329                 stepper_init(avr, &step_z, "Z", axis_pp_per_mm[2], 20, 110, 0);
330                 stepper_connect(&step_z, s, d, e, m, stepper_endstop_inverted);
331         }
332         {
333                 avr_irq_t * e = get_ardu_irq(avr, E0_ENABLE_PIN, arduidiot_644);
334                 avr_irq_t * s = get_ardu_irq(avr, E0_STEP_PIN, arduidiot_644);
335                 avr_irq_t * d = get_ardu_irq(avr, E0_DIR_PIN, arduidiot_644);
336
337                 stepper_init(avr, &step_e, "E", axis_pp_per_mm[3], 0, 0, 0);
338                 stepper_connect(&step_e, s, d, e, NULL, 0);
339         }
340
341         const char *options[] = {"listening_ports", "9090", NULL};
342
343         struct mg_context *ctx = mg_start(&mongoose_callback, NULL, options);
344         printf("mongoose %p\n", ctx);
345
346         while (1) {
347                 int state = avr_run(avr);
348                 if ( state == cpu_Done || state == cpu_Crashed)
349                         break;
350         }
351         mg_stop(ctx);
352 }