libpropeller
Making PropellerGCC Easier
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
serial.h
Go to the documentation of this file.
1 #ifndef LIBPROPELLER_SERIAL_H_
2 #define LIBPROPELLER_SERIAL_H_
3 
4 #include <cstdarg>
5 #include <propeller.h>
7 
8 extern char _load_start_serial_cog[];
9 
29 class Serial {
30 public:
31 
40  static const int kBufferLength = 512;
41 
42  ~Serial() {
43  Stop();
44  }
45 
56  bool Start(const int rxpin, const int txpin, const int rate,
57  const int ctspin = -1) {
58 
59  // Prevent garbage collection of the ASM code
60  volatile void * asm_driver_reference = NULL;
61  __asm__ volatile ("mov %[asm_driver_reference], #Fds_entry \n\t"
62  : [asm_driver_reference] "+r" (asm_driver_reference));
63 
64  Stop();
65 
66  extern char * Masktx asm("Masktx");
67  extern char * Maskrx asm("Maskrx");
68  extern char * Ctra_val asm("Ctra_val");
69  extern char * Ctrb_val asm("Ctrb_val");
70  extern char * Period_ptr asm("Period_ptr");
71  extern char * Rx_head_ptr asm("Rx_head_ptr");
72  extern char * Rx_end_ptr asm("Rx_end_ptr");
73  extern char * Update_head_ptr asm("Update_head_ptr");
74  extern char * Maskcts asm("Maskcts");
75 
76 
77  SetDriverLong(&Masktx, 0);
78  SetDriverLong(&Ctra_val, 0);
79  if (txpin >= 0) {
80  DIRA |= 1 << txpin;
81  SetDriverLong(&Masktx, 1 << txpin);
82  SetDriverLong(&Ctra_val, 0x10000000 | txpin);
83  }
84  SetDriverLong(&Maskrx, 0);
85  SetDriverLong(&Ctrb_val, 0);
86  if (rxpin >= 0) {
87  DIRA &= ~(1 << rxpin);
88 
89  SetDriverLong(&Maskrx, 1 << rxpin);
90  SetDriverLong(&Ctrb_val, 0x54000000 | rxpin);
91  }
92 
93 
94  SetDriverLong(&Maskcts, 0);
95  if (ctspin >= 0) {
96  //Set CTS pin to input:
97  DIRA &= ~(1 << ctspin);
98 
99  SetDriverLong(&Maskcts, 1 << ctspin);
100  }
101 
102 
103  SetBaud(rate);
104 
105  SetDriverLong(&Period_ptr, (int) &half_bit_period_);
106  memset((void *) &rx_buffer_, 0, 1 * (kBufferLength));
107 
108  SetDriverLong(&Rx_head_ptr, (int) &rx_buffer_);
109  SetDriverLong(&Rx_end_ptr, (int) &rx_buffer_ + kBufferLength);
110 
111  rx_head_ = 0;
112  rx_tail_ = 0;
113 
114  SetDriverLong(&Update_head_ptr, (int) &rx_head_);
115  write_buf_ptr_ = 1;
116  cog_ = 1 + cognew((int) (&(*(int *) &_load_start_serial_cog[0])), (int) (&write_buf_ptr_));
117  if (cog_) {
118  WaitForTransmissionCompletion();
119  return true;
120  }
121  return false;
122  }
123 
126  void Stop(void) {
127  WaitForTransmissionCompletion();
128  if (cog_) {
129  cogstop(cog_ - 1);
130  cog_ = 0;
131  }
132  }
133 
139  bool SetBaud(const int rate) {
140  return SetBaudClock(rate, CLKFREQ);
141  }
142 
154  bool SetBaudClock(const unsigned int rate, const unsigned int sysclock) {
155  WaitForTransmissionCompletion();
156 
157  // how many clocks per 1/2 bit (pre-round to the nearest integer)
158  int got_rate = ((sysclock >> 1) + (rate >> 1)) / rate;
159 
160  // clamp the period to the allowable range
161  half_bit_period_ = got_rate > kMinimumHalfPeriod ? got_rate : kMinimumHalfPeriod;
162 
163  // return true if the requested period was >= the allowable limit
164  return got_rate >= kMinimumHalfPeriod;
165  }
166 
171  void Put(const char character) {
172  WaitForTransmissionCompletion();
173  send_temp_ = character;
174  write_buf_ptr_ = (int) (&send_temp_);
175  }
176 
184  int Put(const char * buffer_ptr, const int count) {
185  WaitForTransmissionCompletion();
186  for (int i = 0; i < count; i++) {
187  Put(buffer_ptr[i]);
188  }
189  return count;
190  }
191 
199  int Put(const char * buffer_ptr) {
200  return Put(buffer_ptr, strlen(buffer_ptr));
201  }
202 
236  int PutFormatted(const char * format, ...) {
237  if (format == NULL) {
238  return 0;
239  }
240 
241  int bytesWritten = 0;
242 
243  va_list list;
244  va_start(list, format);
245 
246 
247  for (int stringIndex = 0; format[stringIndex] != 0; stringIndex++) {
248 
249  if (format[stringIndex] == '%') {
250  //Found formatter!
251  stringIndex++;
252  //Check for flags:
253  bool padZero = false;
254  int padAmount = 0;
255  if (format[stringIndex] == '0') {
256  padZero = true;
257  stringIndex++;
258  }
259  if (format[stringIndex] >= '1' and format[stringIndex] <= '9') {
260  char paddingBuffer[5];
261  int paddingIndex = 0;
262 
263 
264  //Non freezing version.
265  if (format[stringIndex] >= '0' and format[stringIndex] <= '9') {
266  paddingBuffer[paddingIndex++] = format[stringIndex++];
267  if (format[stringIndex] >= '0' and format[stringIndex] <= '9') {
268  paddingBuffer[paddingIndex++] = format[stringIndex++];
269  if (format[stringIndex] >= '0' and format[stringIndex] <= '9') {
270  paddingBuffer[paddingIndex++] = format[stringIndex++];
271  if (format[stringIndex] >= '0' and format[stringIndex] <= '9') {
272  paddingBuffer[paddingIndex++] = format[stringIndex++];
273  }
274  }
275  }
276  }
277 
278  //TO DO(SRLM): figure out what is happening with the freezing version.
279  //I think it freezes because of the CMM and fcache combination.
280  //Freezing version:
281  // while(format[stringIndex] >= '0' and format[stringIndex] <= '9'){
282  // paddingBuffer[paddingIndex++] = format[stringIndex];
284  // stringIndex++;
285  // }
286  paddingBuffer[paddingIndex] = 0;
287  padAmount = Numbers::Dec(paddingBuffer);
288  // printf("paddingBuffer[0] = %c\r\n", paddingBuffer[0]);
289  // printf("paddingBuffer[1] = %c\r\n", paddingBuffer[1]);
290  // printf("paddingIndex = %i\r\n", paddingIndex);
291  // printf("padAmount: %i\r\n", padAmount);
292 
293 
294  }
295 
296 
297 
298  if (format[stringIndex] == 0) {
299  // Throw away the '%' character if it's at the end of the string.
300  break;
301  }
302  if (format[stringIndex] == 'd' || format[stringIndex] == 'i') {
303  int number = va_arg(list, int);
304  int digits = Numbers::DecDigits(number);
305  if (padAmount > 0) {
306  for (int i = padAmount - digits; i > 0; --i) {
307  Put(' ');
308  }
309  }
310 
311  PutFormatted(Numbers::Dec(number));
312  bytesWritten += digits;
313  } else if (format[stringIndex] == 'x' || format[stringIndex] == 'X') {
314  int number = va_arg(list, int);
315  int digits = Numbers::HexDigits(number);
316  if (padAmount > 0) {
317  for (int i = padAmount - digits; i > 0; --i) {
318  if (padZero) {
319  Put('0');
320  } else {
321  Put(' ');
322  }
323  }
324  }
325 
326  PutFormatted(Numbers::Hex(number, digits));
327  bytesWritten += digits;
328  } else if (format[stringIndex] == 'c') {
329  char character = (char) (va_arg(list, int));
330  Put(character);
331  bytesWritten++;
332  } else if (format[stringIndex] == 's') {
333  char * string = (char *) (va_arg(list, int));
334  while (*string != 0) {
335  Put(*string++);
336  bytesWritten++;
337  }
338  } else if (format[stringIndex] == '%') {
339  Put('%');
340  bytesWritten++;
341  }
342 
343  } else {
344  Put(format[stringIndex]);
345  bytesWritten++;
346  }
347  }
348 
349  va_end(list);
350  return bytesWritten;
351  }
352 
367  int Get(const int timeout = -1) {
368  int rxbyte = 0;
369 
370  if (timeout <= -1) { //No timeout, wait forever
371 
372  while ((rxbyte = CheckBuffer()) < 0);
373  return (char) rxbyte;
374  } else {
375  unsigned int total_cycles = (CLKFREQ / 1000) * timeout;
376  unsigned int elapsed_cycles = 0;
377 
378  int previous_cnt = CNT;
379  do {
380  rxbyte = CheckBuffer();
381  int current_cnt = CNT;
382  elapsed_cycles += current_cnt - previous_cnt;
383  previous_cnt = current_cnt;
384  } while (rxbyte < 0 && elapsed_cycles < total_cycles);
385  return rxbyte;
386  }
387  }
388 
399  int Get(char * const buffer, const int length, const int timeout = -1) {
400  int character_count;
401  for (character_count = 0; character_count < length; ++character_count) {
402  int character = Get(timeout);
403  if (character <= -1) {
404  return character_count;
405  }
406  buffer[character_count] = (char) character;
407  }
408  return character_count;
409  }
410 
422  int Get(char * const buffer, const char terminator = '\n') {
423  int character_count;
424  char received_character = terminator + 1; // guarantee that they differ the first time.
425  for (character_count = 0; received_character != terminator; ++character_count) {
426  received_character = (char) Get();
427  buffer[character_count] = received_character;
428  }
429  buffer[character_count] = '\0';
430  return character_count;
431  }
432 
435  void GetFlush(void) {
436  rx_tail_ = rx_head_;
437  }
438 
441  int GetCount(void) const {
442  const int tail = rx_tail_;
443  const int head = rx_head_;
444  if (head >= tail) {
445  return head - tail;
446  } else {
447  return kBufferLength - tail + head;
448  }
449  }
450 
451 
452 private:
457  static const int kMinimumHalfPeriod = 86;
458 
459  volatile int write_buf_ptr_;
460  volatile int send_temp_;
461  volatile int half_bit_period_;
462  volatile short rx_head_;
463  volatile short rx_tail_;
464  volatile char rx_buffer_[kBufferLength];
465  int cog_;
466 
470  int CheckBuffer(void) {
471  int rxbyte = -1;
472  if (rx_tail_ != rx_head_) {
473  rxbyte = rx_buffer_[rx_tail_];
474  rx_buffer_[rx_tail_] = 0;
475  rx_tail_ = ((rx_tail_ + 1) % kBufferLength);
476  }
477  return rxbyte;
478  }
479 
480  void WaitForTransmissionCompletion(void) {
481  while (write_buf_ptr_) {
482  };
483  }
484 
485  void SetDriverLong(const int index, const int value) {
486  ((int *) &_load_start_serial_cog[index])[0] = value;
487  }
488 
489  /* Warning: SetDriverLong(char **, int) must be declared second, otherwise it calls itself! */
490  void SetDriverLong(char ** index, const int value) {
491  SetDriverLong((int) index, value);
492  }
493 };
494 
495 
496 
497 
498 //
499 // The Put(buffer) function doesn't seem to work in CMM mode. In the tests, I
500 // get a -1 for the matching Get(), instead of the character sent. The same code
501 // can pass in LMM mode.
502 
503 // Update: now, it doesn't work at all.
504 
505 //int Serial::PutBuffer(char * buffer_ptr, const bool wait, int buffer_bytes, const char terminator)
506 //{
507 // volatile char * volatile temp_ptr = buffer_ptr;
508 // if(buffer_bytes == -1){
509 // if(terminator == '\0'){
510 // buffer_bytes = strlen(buffer_ptr);
511 //
512 // }else{
513 // for(buffer_bytes = 0; buffer_ptr[buffer_bytes] != terminator; buffer_bytes++){}
514 // }
515 //
516 // }
517 
518 // buffer_bytes = 5;
519 
520 // if (buffer_bytes > 0 && buffer_ptr != NULL) {
521 //
522 // send_temp_ = (int)(buffer_ptr);
523 // write_buf_ptr_ = (send_temp_ | ((buffer_bytes - 1) << 16));
524 // }
525 //
526 // if(wait){
527 // while (write_buf_ptr_){}
528 // }
529 // return buffer_bytes;
530 //}
531 
532 #endif // LIBPROPELLER_SERIAL_H_