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