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