Contiki 2.5
debug-uart.c
1 #include <debug-uart.h>
2 #include <sys-interrupt.h>
3 /* #include <strformat.h> */
4 #include <AT91SAM7S64.h>
5 #include <string.h>
6 #include <interrupt-utils.h>
7 
8 #ifndef DBG_XMIT_BUFFER_LEN
9 #define DBG_XMIT_BUFFER_LEN 3024
10 #endif
11 #ifndef DBG_RECV_BUFFER_LEN
12 #define DBG_RECV_BUFFER_LEN 256
13 #endif
14 
15 static unsigned char dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN];
16 static unsigned char dbg_recv_buffer[DBG_RECV_BUFFER_LEN];
17 static unsigned int dbg_recv_buffer_len = 0;
18 
19 void
20 dbg_setup_uart()
21 {
22  /* Setup PIO ports */
23  *AT91C_PIOA_OER = AT91C_PA10_DTXD;
24  *AT91C_PIOA_ODR = AT91C_PA9_DRXD;
25  *AT91C_PIOA_ASR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
26  *AT91C_PIOA_PDR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
27 
28  *AT91C_DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
29  *AT91C_DBGU_IDR= 0xffffffff;
30 
31  *AT91C_DBGU_BRGR = MCK / (115200 * 16);
32  *AT91C_DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
33 
34  *AT91C_DBGU_TPR = (unsigned int)dbg_xmit_buffer;
35  *AT91C_DBGU_TNPR = (unsigned int)dbg_xmit_buffer;
36 
37 
38 }
39 
40 static void (*input_func)(const char *inp, unsigned int len) = NULL;
41 
42 static int dbg_recv_handler_func()
43 {
44  if (!(*AT91C_DBGU_CSR & AT91C_US_RXRDY)) return 0;
45  unsigned char c = *AT91C_DBGU_RHR;
46  /* Leave one byte for '\0' */
47  if (dbg_recv_buffer_len < (DBG_RECV_BUFFER_LEN -1)) {
48  dbg_recv_buffer[dbg_recv_buffer_len++] = c;
49  }
50  if (c == '\n') {
51  dbg_recv_buffer[dbg_recv_buffer_len] = '\0';
52  if (input_func) input_func((char*)dbg_recv_buffer, dbg_recv_buffer_len);
53  dbg_recv_buffer_len = 0;
54  }
55  return 1;
56 }
57 
58 static SystemInterruptHandler dbg_recv_handler = {NULL, dbg_recv_handler_func};
59 
60 void
61 dbg_set_input_handler(void (*handler)(const char *inp, unsigned int len))
62 {
63  input_func = handler;
64  sys_interrupt_append_handler(&dbg_recv_handler);
65  sys_interrupt_enable();
66  *AT91C_DBGU_IER = AT91C_US_RXRDY;
67 }
68 static volatile unsigned char mutex = 0;
69 
70 unsigned int
71 dbg_send_bytes(const unsigned char *seq, unsigned int len)
72 {
73  unsigned short next_count;
74  unsigned short current_count;
75  unsigned short left;
76  unsigned int save = disableIRQ();
77  if (mutex) {
78  restoreIRQ(save);
79  return 0; /* Buffer being updated */
80  }
81  mutex = 1; /* Prevent interrupts from messing up the transmission */
82  *AT91C_DBGU_PTCR =AT91C_PDC_TXTDIS; /* Stop transmitting */
83  while(*AT91C_DBGU_PTSR & AT91C_PDC_TXTEN); /* Wait until stopped */
84  next_count = *AT91C_DBGU_TNCR;
85  current_count = *AT91C_DBGU_TCR;
86 
87  left = DBG_XMIT_BUFFER_LEN - next_count - current_count;
88  if (left > 0) {
89  if (left < len) len = left;
90  if (next_count > 0) {
91  /* Buffer is wrapped */
92  memcpy(&dbg_xmit_buffer[next_count], seq, len);
93  *AT91C_DBGU_TNCR = next_count + len;
94  } else {
95  unsigned char *to = ((unsigned char*)*AT91C_DBGU_TPR) + current_count;
96  left = &dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN] - to;
97  if (len > left) {
98  unsigned int wrapped = len - left;
99  memcpy(to, seq, left);
100  memcpy(dbg_xmit_buffer, &seq[left], wrapped);
101  *AT91C_DBGU_TCR = current_count + left;
102  *AT91C_DBGU_TNCR = wrapped;
103  } else {
104  memcpy(to, seq, len);
105  *AT91C_DBGU_TCR = current_count + len;
106  }
107  }
108  } else {
109  len = 0;
110  }
111 
112  *AT91C_DBGU_PTCR =AT91C_PDC_TXTEN; /* Restart transmission */
113  mutex = 0;
114  restoreIRQ(save);
115  return len;
116 }
117 static unsigned char dbg_write_overrun = 0;
118 
119 void
120 dbg_putchar(const char ch)
121 {
122  if (dbg_write_overrun) {
123  if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
124  }
125  dbg_write_overrun = 0;
126  if (dbg_send_bytes((const unsigned char*)&ch,1) != 1) {
127  dbg_write_overrun = 1;
128  }
129 }
130 
131 void
132 dbg_blocking_putchar(const char ch)
133 {
134  if (dbg_write_overrun) {
135  while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
136  }
137  dbg_write_overrun = 0;
138  while (dbg_send_bytes((const unsigned char*)&ch,1) != 1);
139 }
140 
141 #if 0
142 static StrFormatResult
143 dbg_write_cb(void *user_data, const char *data, unsigned int len)
144 {
145  if (dbg_send_bytes((const unsigned char*)data, len) != len) {
146  dbg_write_overrun = 1;
147  return STRFORMAT_FAILED;
148  }
149  return STRFORMAT_OK;
150 }
151 
152 void
153 dbg_printf(const char *format, ...)
154 {
155  static const StrFormatContext ctxt = {dbg_write_cb, NULL};
156  va_list ap;
157  if (dbg_write_overrun) {
158  if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
159  }
160  dbg_write_overrun = 0;
161  va_start(ap, format);
162  format_str_v(&ctxt, format, ap);
163  va_end(ap);
164 }
165 
166 static StrFormatResult
167 dbg_write_blocking_cb(void *user_data, const char *data, unsigned int len)
168 {
169  unsigned int left = len;
170  while(left > 0) {
171  unsigned int sent = dbg_send_bytes((const unsigned char*)data, left);
172  left -= sent;
173  data += sent;
174  }
175  return STRFORMAT_OK;
176 }
177 
178 void
179 dbg_blocking_printf(const char *format, ...)
180 {
181  static const StrFormatContext ctxt = {dbg_write_blocking_cb, NULL};
182  va_list ap;
183  if (dbg_write_overrun) {
184  while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
185  }
186  dbg_write_overrun = 0;
187  va_start(ap, format);
188  format_str_v(&ctxt, format, ap);
189  va_end(ap);
190 }
191 #endif
192 void
193 dbg_drain()
194 {
195  while(!(*AT91C_DBGU_CSR & AT91C_US_TXBUFE));
196 }