refactor logger
[simavr] / examples / board_simduino / simduino.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
30 #if __APPLE__
31 #include <GLUT/glut.h>
32 #else
33 #include <GL/glut.h>
34 #endif
35 #include <pthread.h>
36
37 #include "sim_avr.h"
38 #include "avr_ioport.h"
39 #include "sim_elf.h"
40 #include "sim_hex.h"
41 #include "sim_gdb.h"
42 #include "uart_pty.h"
43 #include "sim_vcd_file.h"
44
45 #include "button.h"
46
47 button_t button;
48 uart_pty_t uart_pty;
49 int do_button_press = 0;
50 avr_t * avr = NULL;
51 avr_vcd_t vcd_file;
52 uint8_t pin_state = 0;  // current port B
53
54 float pixsize = 64;
55 int window;
56
57 /*
58  * called when the AVR change any of the pins on port B
59  * so lets update our buffer
60  */
61 void pin_changed_hook(struct avr_irq_t * irq, uint32_t value, void * param)
62 {
63 //      pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
64 }
65
66 void displayCB(void)            /* function called whenever redisplay needed */
67 {
68         // OpenGL rendering goes here...
69         glClear(GL_COLOR_BUFFER_BIT);
70
71         // Set up modelview matrix
72         glMatrixMode(GL_MODELVIEW); // Select modelview matrix
73         glLoadIdentity(); // Start with an identity matrix
74
75         //float grid = pixsize;
76         //float size = grid * 0.8;
77     glBegin(GL_QUADS);
78         glColor3f(1,0,0);
79
80 #if 0
81         for (int di = 0; di < 8; di++) {
82                 char on = (pin_state & (1 << di)) != 0;
83                 if (on) {
84                         float x = (di) * grid;
85                         float y = 0; //(si * grid * 8) + (di * grid);
86                         glVertex2f(x + size, y + size);
87                         glVertex2f(x, y + size);
88                         glVertex2f(x, y);
89                         glVertex2f(x + size, y);
90                 }
91         }
92 #endif
93     glEnd();
94     glutSwapBuffers();
95     //glFlush();                                /* Complete any pending operations */
96 }
97
98 void keyCB(unsigned char key, int x, int y)     /* called on key press */
99 {
100         if (key == 'q')
101                 exit(0);
102         //static uint8_t buf[64];
103         switch (key) {
104                 case 'q':
105                 case 0x1f: // escape
106                         exit(0);
107                         break;
108                 case ' ':
109                         do_button_press++; // pass the message to the AVR thread
110                         break;
111                 case 'r':
112                         printf("Starting VCD trace\n");
113                         avr_vcd_start(&vcd_file);
114                         break;
115                 case 's':
116                         printf("Stopping VCD trace\n");
117                         avr_vcd_stop(&vcd_file);
118                         break;
119         }
120 }
121
122 // gl timer. if the pin have changed states, refresh display
123 void timerCB(int i)
124 {
125         //static uint8_t oldstate = 0xff;
126         // restart timer
127         glutTimerFunc(1000/64, timerCB, 0);
128 #if 0
129         if (oldstate != pin_state) {
130                 oldstate = pin_state;
131                 glutPostRedisplay();
132         }
133 #endif
134 }
135
136 static void * avr_run_thread(void * oaram)
137 {
138 //      int b_press = do_button_press;
139
140         while (1) {
141                 int state = avr_run(avr);
142                 if ( state == cpu_Done || state == cpu_Crashed)
143                         break;
144         }
145         return NULL;
146 }
147
148
149 char avr_flash_path[1024];
150 int avr_flash_fd = 0;
151
152 // avr special flash initalization
153 // here: open and map a file to enable a persistent storage for the flash memory
154 void avr_special_init( avr_t * avr)
155 {
156         // open the file
157         avr_flash_fd = open(avr_flash_path, O_RDWR|O_CREAT, 0644);
158         if (avr_flash_fd < 0) {
159                 perror(avr_flash_path);
160                 exit(1);
161         }
162         // resize and map the file the file
163         (void)ftruncate(avr_flash_fd, avr->flashend + 1);
164         ssize_t r = read(avr_flash_fd, avr->flash, avr->flashend + 1);
165         if (r != avr->flashend + 1) {
166                 fprintf(stderr, "unable to load flash memory\n");
167                 perror(avr_flash_path);
168                 exit(1);
169         }
170 }
171
172 // avr special flash deinitalization
173 // here: cleanup the persistent storage
174 void avr_special_deinit( avr_t* avr)
175 {
176         puts(__func__);
177         lseek(avr_flash_fd, SEEK_SET, 0);
178         ssize_t r = write(avr_flash_fd, avr->flash, avr->flashend + 1);
179         if (r != avr->flashend + 1) {
180                 fprintf(stderr, "unable to load flash memory\n");
181                 perror(avr_flash_path);
182         }
183         close(avr_flash_fd);
184         uart_pty_stop(&uart_pty);
185 }
186
187 int main(int argc, char *argv[])
188 {
189         //elf_firmware_t f;
190         //const char * pwd = dirname(argv[0]);
191
192         avr = avr_make_mcu_by_name("atmega328p");
193         if (!avr) {
194                 fprintf(stderr, "%s: Error creating the AVR core\n", argv[0]);
195                 exit(1);
196         }
197 //      snprintf(avr_flash_path, sizeof(avr_flash_path), "%s/%s", pwd, "simduino_flash.bin");
198         strcpy(avr_flash_path,  "simduino_flash.bin");
199         // register our own functions
200         avr->special_init = avr_special_init;
201         avr->special_deinit = avr_special_deinit;
202         //avr->reset = NULL;
203         avr_init(avr);
204         avr->frequency = 16000000;
205
206         // this trick creates a file that contains /and keep/ the flash
207         // in the same state as it was before. This allow the bootloader
208         // app to be kept, and re-run if the bootloader doesn't get a
209         // new one
210         {
211                 char path[1024];
212                 uint32_t base, size;
213 //              snprintf(path, sizeof(path), "%s/%s", pwd, "ATmegaBOOT_168_atmega328.ihex");
214                 strcpy(path, "ATmegaBOOT_168_atmega328.ihex");
215                 uint8_t * boot = read_ihex_file(path, &size, &base);
216                 if (!boot) {
217                         fprintf(stderr, "%s: Unable to load %s\n", argv[0], path);
218                         exit(1);
219                 }
220                 printf("Booloader %04x: %d\n", base, size);
221                 memcpy(avr->flash + base, boot, size);
222                 free(boot);
223                 avr->pc = base;
224                 avr->codeend = avr->flashend;
225         }
226         //avr->trace = 1;
227
228         // even if not setup at startup, activate gdb if crashing
229         avr->gdb_port = 1234;
230         if (0) {
231                 //avr->state = cpu_Stopped;
232                 avr_gdb_init(avr);
233         }
234
235         uart_pty_init(avr, &uart_pty);
236         uart_pty_connect(&uart_pty, '0');
237
238         /*
239          * OpenGL init, can be ignored
240          */
241         glutInit(&argc, argv);          /* initialize GLUT system */
242
243         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
244         glutInitWindowSize(8 * pixsize, 1 * pixsize);           /* width=400pixels height=500pixels */
245         window = glutCreateWindow("Glut");      /* create window */
246
247         // Set up projection matrix
248         glMatrixMode(GL_PROJECTION); // Select projection matrix
249         glLoadIdentity(); // Start with an identity matrix
250         glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10);
251         glScalef(1,-1,1);
252         glTranslatef(0, -1 * pixsize, 0);
253
254         glutDisplayFunc(displayCB);             /* set window's display callback */
255         glutKeyboardFunc(keyCB);                /* set window's key callback */
256         glutTimerFunc(1000 / 24, timerCB, 0);
257
258         // the AVR run on it's own thread. it even allows for debugging!
259         pthread_t run;
260         pthread_create(&run, NULL, avr_run_thread, NULL);
261
262         glutMainLoop();
263 }