#include "femtoos_code.h"#define abs(x) ((x)>0?(x):-(x))/** @ToDo: More flexible serialSendXXX methods, let the user choose the FIFO * * @ToDo: Serial driver configuration with config_application.h * * @ToDo: Rx * * @ToDo: Swap to an external file. * @ToDo: The first serialSendXXX call will only print some rubbish. *//** Initializes UART 0. This is copied from the arduio project (www.arduino.cc) * It configures the baud rate and enables the Tx part of UART 0. * * @param uint16_t baud: * The desired baud rate. UART 0 will be configured to this baud rate. * * @ToDo: Think about it ;-) */void serialInit(uint16_t baud){ uint8_t use_u2x; uint16_t baud_setting; // U2X mode is needed for baud rates higher than (CPU Hz / 16) if(baud > (F_CPU / 16UL)) { use_u2x = 1; } else { // figure out if U2X mode would allow for a better connection // calculate the percent difference between the baud-rate specified and // the real baud rate for both U2X and non-U2X mode (0-255 error percent) uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud))); uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud))); // prefer non-U2X mode because it handles clock skew better use_u2x = (nonu2x_baud_error > u2x_baud_error); } if(use_u2x) { UCSR0A = _BV(U2X0); baud_setting = (F_CPU / 4UL / baud - 1UL) / 2UL; } else { UCSR0A = 0; baud_setting = (F_CPU / 8UL / baud - 1UL) / 2UL; } // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) UBRR0H = baud_setting >> 8; UBRR0L = baud_setting; UCSR0B = _BV(TXEN0) | _BV(UDRIE0);}/************************************** * Tels the SerialSend task that he can now write the next byte on the wire. */void USART0_UDRE_vect(void) __attribute__ ( ( signal, naked, used, externally_visible ) );void USART0_UDRE_vect(void){ /// @ToDo: Is there an faster alternative? isrBegin(); // Tell the SerialSend task that it should look for free UARTs isrFireEventOnName(QueuSendEvent); // Disable this ISR, since this bit isn't cleard by hardware and we would be // caught in endless ISR loop. UCSR0B &= ~_BV(UDRIE0); /// @ToDo: Is there an faster alternative? isrEndYield();}/************************************** * Init everything. */void appBoot(void){ serialInit(9600UL);}/************************************** * Task reading UART Tx buffers and sending the data over the wire. */#if (preTaskDefined(SerialSend))void appLoop_SerialSend(void){ while (true) { // We check only whether the we can send something and won't block // because there could be more than one send queu to check. // // If we can send, lock the queu. // // If you have more UARTs on the chip and want to use it, copy and adapt // the following if block if((UCSR0A & _BV(UDRE0)) && taskQueuReadRequestOnName(Uart0Buffer, 1, defLockDoNotBlock)) { // Enable interrupts before we write the new byte to the wire. // Otherwise this task could be interrupted and we will miss the // event. UCSR0B |= _BV(UDRIE0); // Read the byte from the FIFO and write it to the wire. UDR0 = genQueuReadOnName(Uart0Buffer); taskQueuReleaseOnName(Uart0Buffer); } // Don't block for ever because we won't miss under any circumstances // an free UART. So we check on a regular basis for ourselves whether // the UART is free or not. taskWaitForEventOnName(QueuSendEvent, 1000); }}#endif/** Private implementation which sends a an uint16_t with the UART interface. * You can change the type of the value parameter to an other integer type as * required. You can also define a signed integer type. This version is * inspired by Lukás Chmelas C++ itoa method in version 0.4. * * @param uint16_t value: * The intager value which should be send with the UART interface in a base * defined by the base parameter. * * @param int base: * Defines in which base the value parameter should be written to the UART * interface. The base has to be betwen and including 2 and 16. * * @param int newLine: * If set to 0, no new line ("\r\n") will be appended to the value. * Otherwise a new line will be appended */void privSerialPrintInt(uint16_t value, int base, int newLine){ char result[10]; char* ptr = result; char* ptr1 = result; long int tmp_value; do { tmp_value = value; value /= base; *ptr++ = "FEDCBA9876543210123456789ABCDEF" [15 + (tmp_value - value * base)]; } while(value); // Apply negative sign if(tmp_value < 0) { *ptr++ = '-'; } if(taskQueuWriteRequestOnName(Uart0Buffer, ptr - ptr1 + (newLine != 0 ? 3 : 1), defLockBlockInfinite)) { while(ptr1 < ptr) { genQueuWriteOnName(Uart0Buffer, *(--ptr)); } if(newLine != 0) { genQueuWriteOnName(Uart0Buffer, '\r'); genQueuWriteOnName(Uart0Buffer, '\n'); } taskQueuReleaseOnName(Uart0Buffer); genFireEventOnName(QueuSendEvent); }}#define serialPrintInt(value, base) privSerialPrintInt(value, base, 0)#define serialPrintIntLn(value, base) privSerialPrintInt(value, base, 1)/** Sends a single character with the UART interface. * * @param const char character: * The character which should be send. */void serialPrintChar(const char character){ if(taskQueuWriteRequestOnName(Uart0Buffer, 1, defLockBlockInfinite)) { genQueuWriteOnName(Uart0Buffer, character); taskQueuReleaseOnName(Uart0Buffer); genFireEventOnName(QueuSendEvent); }}/** Sends a single character with the UART interface and appends a new line * ("\r\n"). * * @param const char character: * The character which should be send. */void serialPrintCharLn(const char character){ if(taskQueuWriteRequestOnName(Uart0Buffer, 3, defLockBlockInfinite)) { genQueuWriteOnName(Uart0Buffer, character); genQueuWriteOnName(Uart0Buffer, '\r'); genQueuWriteOnName(Uart0Buffer, '\n'); taskQueuReleaseOnName(Uart0Buffer); genFireEventOnName(QueuSendEvent); }}/** Sends text, terminated by an '\0' character, with the UART interface. * * @param const char text[]: * The '\0' character terminated text which should be send. */void serialPrintText(const char text[]){ if(taskQueuWriteRequestOnName(Uart0Buffer, strlen(text), defLockBlockInfinite)) { while(*text) { genQueuWriteOnName(Uart0Buffer, *text++); } taskQueuReleaseOnName(Uart0Buffer); genFireEventOnName(QueuSendEvent); }}/** Sends text, terminated by an '\0' character, with the UART interface and * appends a new line ("\r\n"). * * @param const char text[]: * The '\0' character terminated text which should be send. */void serialPrintTextLn(const char text[]){ if(taskQueuWriteRequestOnName(Uart0Buffer, strlen(text) + 2, defLockBlockInfinite)) { while(*text) { genQueuWriteOnName(Uart0Buffer, *text++); } genQueuWriteOnName(Uart0Buffer, '\r'); genQueuWriteOnName(Uart0Buffer, '\n'); taskQueuReleaseOnName(Uart0Buffer); genFireEventOnName(QueuSendEvent); }}/************************************** * Task that tries to write much as possible into the queu. */#if (preTaskDefined(Main))void appLoop_Main(void){ while (true) { serialPrintText("Current "); serialPrintTextLn("status"); serialPrintChar('O'); serialPrintCharLn('K'); serialPrintInt(13, 10); serialPrintIntLn(55, 16); taskDelayFromNow(4000); }}#endif