A copy of the mbed USBDevice with USBSerial library
Dependents: STM32L0_LoRa Smartage STM32L0_LoRa Turtle_RadioShuttle
USBSerialBuffered/USBSerialBuffered.cpp@3:bddd92cd3a17, 2018-02-22 (annotated)
- Committer:
- Helmut Tschemernjak
- Date:
- Thu Feb 22 12:18:45 2018 +0100
- Revision:
- 3:bddd92cd3a17
- Child:
- 4:b6be2a43cb85
Added a buffered USB serial which allows to print on interrupts
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Helmut Tschemernjak | 3:bddd92cd3a17 | 1 | /* |
Helmut Tschemernjak | 3:bddd92cd3a17 | 2 | * $Id: bulkserial.h,v 1.3 2018/02/23 15:04:29 grimrath Exp $ |
Helmut Tschemernjak | 3:bddd92cd3a17 | 3 | * This is an unpublished work copyright (c) 2017 HELIOS Software GmbH |
Helmut Tschemernjak | 3:bddd92cd3a17 | 4 | * 30827 Garbsen, Germany |
Helmut Tschemernjak | 3:bddd92cd3a17 | 5 | */ |
Helmut Tschemernjak | 3:bddd92cd3a17 | 6 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 7 | #include <algorithm> |
Helmut Tschemernjak | 3:bddd92cd3a17 | 8 | #include <mbed.h> |
Helmut Tschemernjak | 3:bddd92cd3a17 | 9 | // #include "arch.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 10 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 11 | #ifdef FEATURE_USBSERIAL |
Helmut Tschemernjak | 3:bddd92cd3a17 | 12 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 13 | #include "USBSerial.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 14 | #include "USBSerialBuffered.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 15 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 16 | USBSerialBuffered::USBSerialBuffered(int MaxBuffSize, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 17 | : USBSerial(vendor_id, product_id, product_release, connect_blocking) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 18 | , mFullBuffSize(MaxBuffSize) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 19 | { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 20 | ASSERT(mFullBuffSize > CorkBuffSize && "FullBuff must be larger than CorkBuff"); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 21 | m_buff = new char[mFullBuffSize]; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 22 | m_irq_buffused = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 23 | POISONMEM(m_buff, mFullBuffSize); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 24 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 25 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 26 | USBSerialBuffered::~USBSerialBuffered() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 27 | delete[] m_buff; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 28 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 29 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 30 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 31 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 32 | int USBSerialBuffered::irqbuff_acquire() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 33 | core_util_critical_section_enter(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 34 | return help_atomic_load_relaxed(&m_irq_buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 35 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 36 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 37 | void USBSerialBuffered::irqbuff_release(int buffused) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 38 | help_atomic_store_relaxed(&m_irq_buffused, buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 39 | irq_barrier(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 40 | core_util_critical_section_exit(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 41 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 42 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 43 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 44 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 45 | int USBSerialBuffered::printf_irqsafe(const char *fmt, ...) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 46 | std::va_list va; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 47 | va_start(va, fmt); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 48 | int nchars = vprintf_irqsafe(fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 49 | va_end(va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 50 | return nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 51 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 52 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 53 | int USBSerialBuffered::vprintf_irqsafe(const char *fmt, std::va_list va) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 54 | if (RunningInInterrupt()) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 55 | int buffused = irqbuff_acquire(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 56 | int bspc = mFullBuffSize - buffused; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 57 | ASSERT(bspc >= 0); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 58 | int nchars = vsnprintf(m_buff + buffused, bspc, fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 59 | if (nchars >= bspc) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 60 | memcpy(m_buff + mFullBuffSize - 4, "...\n", 4); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 61 | buffused = mFullBuffSize; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 62 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 63 | buffused += nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 64 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 65 | irqbuff_release(buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 66 | return nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 67 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 68 | return USBSerial::vprintf(fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 69 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 70 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 71 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 72 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 73 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 74 | void USBSerialBuffered::flush() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 75 | int flushedbytes = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 76 | int buffused = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 77 | while (1) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 78 | bool wasequal = help_atomic_compare_and_swap(&m_irq_buffused, buffused, 0); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 79 | if (wasequal) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 80 | break; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 81 | // |
Helmut Tschemernjak | 3:bddd92cd3a17 | 82 | // This only works because @ref print_irq always _increases_ @c m_irq_buffused (but never(!) decreases this variable) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 83 | // |
Helmut Tschemernjak | 3:bddd92cd3a17 | 84 | buffused = help_atomic_load_relaxed(&m_irq_buffused); // __sync_* implementation requires this refetch |
Helmut Tschemernjak | 3:bddd92cd3a17 | 85 | while (buffused != flushedbytes) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 86 | int towrite = std::min(buffused - flushedbytes, static_cast<int>(CorkBuffSize)); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 87 | if (connected()) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 88 | writeBlock(reinterpret_cast<uint8_t *>(m_buff + flushedbytes), towrite); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 89 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 90 | flushedbytes += towrite; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 91 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 92 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 93 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 94 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 95 | void USBSerialBuffered::putc_normal(int c) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 96 | while (1) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 97 | int buffused = help_atomic_load_relaxed(&m_irq_buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 98 | if (buffused >= CorkBuffSize) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 99 | flush(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 100 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 101 | // static bool TESTonce; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 102 | // if (! TESTonce) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 103 | // printf_irqsafe("ppp"); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 104 | // TESTonce = true; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 105 | // } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 106 | ASSERT(buffused + 1 <= CorkBuffSize); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 107 | bool wasequal = help_atomic_compare_and_swap(&m_irq_buffused, buffused, buffused + 1); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 108 | if (wasequal) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 109 | m_buff[buffused] = c; // alloc successful |
Helmut Tschemernjak | 3:bddd92cd3a17 | 110 | return; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 111 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 112 | // An irq extended m_irq_buffused, start over |
Helmut Tschemernjak | 3:bddd92cd3a17 | 113 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 114 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 115 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 116 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 117 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 118 | int USBSerialBuffered::_putc(int c) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 119 | putc_normal(c); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 120 | if (c == '\n') { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 121 | flush(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 122 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 123 | return connected() ? 1 : 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 124 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 125 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 126 | #endif |