[ fix ] missing exit prototype, include stdlib.h
[fw/stlink] / src / st-term.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 /* According to POSIX.1-2001 */
4 #include <sys/select.h>
5 #include <string.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <termios.h>
10 #include <fcntl.h>
11 #include <signal.h>
12 #include "stlink-common.h"
13
14 #define STLINKY_MAGIC 0xDEADF00D
15
16 struct stlinky {
17         stlink_t *sl;
18         uint32_t off;
19         size_t bufsize;
20 };
21
22
23 /* Detects stlinky in RAM, returns handler */
24 struct stlinky*  stlinky_detect(stlink_t* sl)
25 {
26         static const uint32_t sram_base = 0x20000000;
27         struct stlinky* st = malloc(sizeof(struct stlinky));
28         st->sl = sl;
29         printf("sram: 0x%x bytes @ 0x%x\n", sl->sram_base, sl->sram_size);
30         uint32_t off;
31         for (off = 0; off < sl->sram_size; off += 4) {
32                 stlink_read_mem32(sl, sram_base + off, 4);
33                 if ( STLINKY_MAGIC== *(uint32_t*) sl->q_buf)
34                 {
35                         printf("stlinky detected at 0x%x\n", sram_base + off);
36                         st->off = sram_base + off;
37                         stlink_read_mem32(sl, st->off + 4, 4);
38                         st->bufsize = (size_t) *(unsigned char*) sl->q_buf;
39                         printf("stlinky buffer size 0x%zu \n", st->bufsize);
40                         return st;
41                 }
42         }
43         return NULL;
44 }
45
46 int stlinky_canrx(struct stlinky *st)
47 {
48         stlink_read_mem32(st->sl, st->off+4, 4);
49         unsigned char tx = (unsigned char) st->sl->q_buf[1];
50         return (int) tx;
51 }
52
53 size_t stlinky_rx(struct stlinky *st, char* buffer)
54 {
55         unsigned char tx = 0;
56         while(tx == 0) {
57                 stlink_read_mem32(st->sl, st->off+4, 4);
58                 tx = (unsigned char) st->sl->q_buf[1];
59         }
60         size_t rs = tx + (4 - (tx % 4)); /* voodoo */
61         stlink_read_mem32(st->sl, st->off+8, rs);
62         memcpy(buffer, st->sl->q_buf, (size_t) tx);
63         *st->sl->q_buf=0x0;
64         stlink_write_mem8(st->sl, st->off+5, 1);
65         return (size_t) tx;
66 }
67
68 size_t stlinky_tx(struct stlinky *st, char* buffer, size_t sz)
69 {
70         unsigned char rx = 1;
71         while(rx != 0) {
72                 stlink_read_mem32(st->sl, st->off+4, 4);
73                 rx = (unsigned char) st->sl->q_buf[2];
74         }
75         memcpy(st->sl->q_buf, buffer, sz);
76         size_t rs = sz + (4 - (sz % 4)); /* voodoo */
77         stlink_write_mem32(st->sl, st->off+8+st->bufsize, rs);
78         *st->sl->q_buf=(unsigned char) sz;
79         stlink_write_mem8(st->sl, st->off+6, 1);
80         return (size_t) rx;
81 }
82
83 int kbhit()
84 {
85         struct timeval tv;
86         fd_set fds;
87         tv.tv_sec = 0;
88         tv.tv_usec = 0;
89         FD_ZERO(&fds);
90         FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
91         select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
92         return FD_ISSET(STDIN_FILENO, &fds);
93 }
94
95 void nonblock(int state)
96 {
97         struct termios ttystate;
98
99         //get the terminal state
100         tcgetattr(STDIN_FILENO, &ttystate);
101
102         if (state==1)
103         {
104                 //turn off canonical mode
105                 ttystate.c_lflag &= ~ICANON;
106                 ttystate.c_lflag &= ~ECHO;
107                 //minimum of number input read.
108                 ttystate.c_cc[VMIN] = 1;
109         }
110         else if (state==0)
111         {
112                 //turn on canonical mode
113                 ttystate.c_lflag |= ICANON | ECHO;
114         }
115         //set the terminal attributes.
116         tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
117
118 }
119
120 static int keep_running = 1;
121 static int sigcount=0;
122 void cleanup(int dummy)
123 {
124         sigcount++;
125         keep_running = 0;
126         printf("\n\nGot a signal\n");
127         if (sigcount==2) {
128                 printf("\n\nGot a second signal - bailing out\n");
129                 exit(1);
130         }
131 }
132
133
134 int main(int ac, char** av) {
135         stlink_t* sl;
136
137         /* unused */
138         ac = ac;
139         av = av;
140         sl = stlink_open_usb(10, 1);
141         if (sl != NULL) {
142                 printf("ST-Linky proof-of-concept terminal :: Created by Necromant for lulz\n");
143                 stlink_version(sl);
144                 stlink_enter_swd_mode(sl);
145                 printf("chip id: %#x\n", sl->chip_id);
146                 printf("core_id: %#x\n", sl->core_id);
147
148                 cortex_m3_cpuid_t cpuid;
149                 stlink_cpu_id(sl, &cpuid);
150                 printf("cpuid:impl_id = %0#x, variant = %#x\n", cpuid.implementer_id, cpuid.variant);
151                 printf("cpuid:part = %#x, rev = %#x\n", cpuid.part, cpuid.revision);
152
153                 stlink_reset(sl);
154                 stlink_force_debug(sl);
155                 stlink_run(sl);
156                 stlink_status(sl);
157
158                 /* wait for device to boot */
159                 /* TODO: Make timeout adjustable via command line */
160                 sleep(1);
161
162                 struct stlinky *st = stlinky_detect(sl);
163                 if (st == NULL)
164                 {
165                         printf("stlinky magic not found in sram :(\n");
166                         goto bailout;
167                 }
168                 char* rxbuf = malloc(st->bufsize);
169                 char* txbuf = malloc(st->bufsize);
170                 size_t tmp;
171                 nonblock(1);
172                 int fd = fileno(stdin);
173                 int saved_flags = fcntl(fd, F_GETFL);
174                 fcntl(fd, F_SETFL, saved_flags & ~O_NONBLOCK);
175                 signal(SIGINT, cleanup);
176                 printf("Entering interactive terminal. CTRL+C to exit\n\n\n");
177                 while(1) {
178                         if (stlinky_canrx(st)) {
179                                 tmp = stlinky_rx(st, rxbuf);
180                                 fwrite(rxbuf,tmp,1,stdout);
181                                 fflush(stdout);
182                         }
183                         if (kbhit()) {
184                                 tmp = read(fd, txbuf, st->bufsize);
185                                 stlinky_tx(st,txbuf,tmp);
186                         }
187                         if (!keep_running)
188                                 break;
189                 }
190         bailout:
191                 nonblock(0);
192                 stlink_exit_debug_mode(sl);
193                 stlink_close(sl);
194         }
195         return 0;
196 }