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