A copy of the mbed USBDevice with USBSerial library
Dependents: STM32L0_LoRa Smartage STM32L0_LoRa Turtle_RadioShuttle
USBSerialBuffered/USBSerialBuffered.cpp@8:961423d1da74, 2019-02-24 (annotated)
- Committer:
- Helmut Tschemernjak
- Date:
- Sun Feb 24 14:52:33 2019 +0100
- Revision:
- 8:961423d1da74
- Parent:
- 4:b6be2a43cb85
Added sleep manager support to avoids sleeps while a USB CDC
connection is active
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> |
Helmut64 | 4:b6be2a43cb85 | 9 | #include "PinMap.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 10 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 11 | #ifdef FEATURE_USBSERIAL |
Helmut Tschemernjak | 3:bddd92cd3a17 | 12 | #include "USBSerial.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 13 | #include "USBSerialBuffered.h" |
Helmut Tschemernjak | 3:bddd92cd3a17 | 14 | |
Helmut64 | 4:b6be2a43cb85 | 15 | #ifndef ASSERT |
Helmut64 | 4:b6be2a43cb85 | 16 | #define ASSERT MBED_ASSERT |
Helmut64 | 4:b6be2a43cb85 | 17 | #endif |
Helmut64 | 4:b6be2a43cb85 | 18 | #ifndef POISONMEM |
Helmut64 | 4:b6be2a43cb85 | 19 | static inline void POISONMEM(void *ptr, size_t sz) { |
Helmut64 | 4:b6be2a43cb85 | 20 | memset(ptr, 0x55, sz); |
Helmut64 | 4:b6be2a43cb85 | 21 | } |
Helmut64 | 4:b6be2a43cb85 | 22 | #endif |
Helmut64 | 4:b6be2a43cb85 | 23 | #if defined(__ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 24 | |
Helmut64 | 4:b6be2a43cb85 | 25 | #define help_atomic_load_relaxed(ptr) __atomic_load_n((ptr), __ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 26 | |
Helmut64 | 4:b6be2a43cb85 | 27 | #define help_atomic_store_relaxed(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 28 | |
Helmut64 | 4:b6be2a43cb85 | 29 | #define help_atomic_readclr_relaxed(ptr) __atomic_exchange_n((ptr), 0, __ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 30 | |
Helmut64 | 4:b6be2a43cb85 | 31 | #define help_atomic_or_relaxed(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 32 | |
Helmut64 | 4:b6be2a43cb85 | 33 | #ifdef __cplusplus |
Helmut64 | 4:b6be2a43cb85 | 34 | template<typename T> inline bool help_atomic_compare_and_swap(T *ptr, T checkval, T newval) { |
Helmut64 | 4:b6be2a43cb85 | 35 | return __atomic_compare_exchange_n(ptr, &checkval, newval, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED); |
Helmut64 | 4:b6be2a43cb85 | 36 | } |
Helmut64 | 4:b6be2a43cb85 | 37 | #else |
Helmut64 | 4:b6be2a43cb85 | 38 | #define help_atomic_compare_and_swap(ptr, checkval, newval) __sync_bool_compare_and_swap((ptr), (checkval), (newval)) |
Helmut64 | 4:b6be2a43cb85 | 39 | #endif |
Helmut64 | 4:b6be2a43cb85 | 40 | |
Helmut64 | 4:b6be2a43cb85 | 41 | #define sync_memory(mem) do { \ |
Helmut64 | 4:b6be2a43cb85 | 42 | asm volatile("" : "=m" (mem)); \ |
Helmut64 | 4:b6be2a43cb85 | 43 | __atomic_thread_fence(__ATOMIC_SEQ_CST); \ |
Helmut64 | 4:b6be2a43cb85 | 44 | } while (0) |
Helmut64 | 4:b6be2a43cb85 | 45 | |
Helmut64 | 4:b6be2a43cb85 | 46 | #define irq_barrier() __atomic_signal_fence(__ATOMIC_SEQ_CST) |
Helmut64 | 4:b6be2a43cb85 | 47 | |
Helmut64 | 4:b6be2a43cb85 | 48 | #define sync_memory_all() do { \ |
Helmut64 | 4:b6be2a43cb85 | 49 | asm volatile("" : : : "memory"); \ |
Helmut64 | 4:b6be2a43cb85 | 50 | __atomic_thread_fence(__ATOMIC_SEQ_CST); \ |
Helmut64 | 4:b6be2a43cb85 | 51 | } while (0) |
Helmut64 | 4:b6be2a43cb85 | 52 | |
Helmut64 | 4:b6be2a43cb85 | 53 | #else // defined(__ATOMIC_RELAXED) |
Helmut64 | 4:b6be2a43cb85 | 54 | |
Helmut64 | 4:b6be2a43cb85 | 55 | #define help_atomic_load_relaxed(ptr) (*(ptr)) |
Helmut64 | 4:b6be2a43cb85 | 56 | |
Helmut64 | 4:b6be2a43cb85 | 57 | #define help_atomic_store_relaxed(ptr, val) ((void)(*(ptr) = (val))) |
Helmut64 | 4:b6be2a43cb85 | 58 | |
Helmut64 | 4:b6be2a43cb85 | 59 | #define help_atomic_readclr_relaxed(ptr) __sync_fetch_and_and((ptr), 0) |
Helmut64 | 4:b6be2a43cb85 | 60 | |
Helmut64 | 4:b6be2a43cb85 | 61 | #define help_atomic_or_relaxed(ptr, val) __sync_fetch_and_or((ptr), (val)) |
Helmut64 | 4:b6be2a43cb85 | 62 | |
Helmut64 | 4:b6be2a43cb85 | 63 | #define help_atomic_compare_and_swap(ptr, checkval, newval) __sync_bool_compare_and_swap((ptr), (checkval), (newval)) |
Helmut64 | 4:b6be2a43cb85 | 64 | |
Helmut64 | 4:b6be2a43cb85 | 65 | #define sync_memory(mem) __sync_synchronize() |
Helmut64 | 4:b6be2a43cb85 | 66 | |
Helmut64 | 4:b6be2a43cb85 | 67 | #define sync_memory_all() __sync_synchronize() |
Helmut64 | 4:b6be2a43cb85 | 68 | |
Helmut64 | 4:b6be2a43cb85 | 69 | #define irq_barrier() __sync_synchronize() |
Helmut64 | 4:b6be2a43cb85 | 70 | |
Helmut64 | 4:b6be2a43cb85 | 71 | #endif |
Helmut64 | 4:b6be2a43cb85 | 72 | |
Helmut64 | 4:b6be2a43cb85 | 73 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 74 | USBSerialBuffered::USBSerialBuffered(int MaxBuffSize, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 75 | : USBSerial(vendor_id, product_id, product_release, connect_blocking) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 76 | , mFullBuffSize(MaxBuffSize) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 77 | { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 78 | ASSERT(mFullBuffSize > CorkBuffSize && "FullBuff must be larger than CorkBuff"); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 79 | m_buff = new char[mFullBuffSize]; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 80 | m_irq_buffused = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 81 | POISONMEM(m_buff, mFullBuffSize); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 82 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 83 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 84 | USBSerialBuffered::~USBSerialBuffered() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 85 | delete[] m_buff; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 86 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 87 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 88 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 89 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 90 | int USBSerialBuffered::irqbuff_acquire() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 91 | core_util_critical_section_enter(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 92 | return help_atomic_load_relaxed(&m_irq_buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 93 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 94 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 95 | void USBSerialBuffered::irqbuff_release(int buffused) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 96 | help_atomic_store_relaxed(&m_irq_buffused, buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 97 | irq_barrier(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 98 | core_util_critical_section_exit(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 99 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 100 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 101 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 102 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 103 | int USBSerialBuffered::printf_irqsafe(const char *fmt, ...) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 104 | std::va_list va; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 105 | va_start(va, fmt); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 106 | int nchars = vprintf_irqsafe(fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 107 | va_end(va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 108 | return nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 109 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 110 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 111 | int USBSerialBuffered::vprintf_irqsafe(const char *fmt, std::va_list va) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 112 | if (RunningInInterrupt()) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 113 | int buffused = irqbuff_acquire(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 114 | int bspc = mFullBuffSize - buffused; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 115 | ASSERT(bspc >= 0); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 116 | int nchars = vsnprintf(m_buff + buffused, bspc, fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 117 | if (nchars >= bspc) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 118 | memcpy(m_buff + mFullBuffSize - 4, "...\n", 4); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 119 | buffused = mFullBuffSize; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 120 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 121 | buffused += nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 122 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 123 | irqbuff_release(buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 124 | return nchars; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 125 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 126 | return USBSerial::vprintf(fmt, va); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 127 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 128 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 129 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 130 | //----------------------------------------------------------------------------- |
Helmut Tschemernjak | 3:bddd92cd3a17 | 131 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 132 | void USBSerialBuffered::flush() { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 133 | int flushedbytes = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 134 | int buffused = 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 135 | while (1) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 136 | bool wasequal = help_atomic_compare_and_swap(&m_irq_buffused, buffused, 0); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 137 | if (wasequal) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 138 | break; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 139 | // |
Helmut Tschemernjak | 3:bddd92cd3a17 | 140 | // This only works because @ref print_irq always _increases_ @c m_irq_buffused (but never(!) decreases this variable) |
Helmut Tschemernjak | 3:bddd92cd3a17 | 141 | // |
Helmut Tschemernjak | 3:bddd92cd3a17 | 142 | buffused = help_atomic_load_relaxed(&m_irq_buffused); // __sync_* implementation requires this refetch |
Helmut Tschemernjak | 3:bddd92cd3a17 | 143 | while (buffused != flushedbytes) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 144 | int towrite = std::min(buffused - flushedbytes, static_cast<int>(CorkBuffSize)); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 145 | if (connected()) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 146 | writeBlock(reinterpret_cast<uint8_t *>(m_buff + flushedbytes), towrite); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 147 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 148 | flushedbytes += towrite; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 149 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 150 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 151 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 152 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 153 | void USBSerialBuffered::putc_normal(int c) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 154 | while (1) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 155 | int buffused = help_atomic_load_relaxed(&m_irq_buffused); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 156 | if (buffused >= CorkBuffSize) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 157 | flush(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 158 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 159 | // static bool TESTonce; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 160 | // if (! TESTonce) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 161 | // printf_irqsafe("ppp"); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 162 | // TESTonce = true; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 163 | // } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 164 | ASSERT(buffused + 1 <= CorkBuffSize); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 165 | bool wasequal = help_atomic_compare_and_swap(&m_irq_buffused, buffused, buffused + 1); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 166 | if (wasequal) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 167 | m_buff[buffused] = c; // alloc successful |
Helmut Tschemernjak | 3:bddd92cd3a17 | 168 | return; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 169 | } else { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 170 | // An irq extended m_irq_buffused, start over |
Helmut Tschemernjak | 3:bddd92cd3a17 | 171 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 172 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 173 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 174 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 175 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 176 | int USBSerialBuffered::_putc(int c) { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 177 | putc_normal(c); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 178 | if (c == '\n') { |
Helmut Tschemernjak | 3:bddd92cd3a17 | 179 | flush(); |
Helmut Tschemernjak | 3:bddd92cd3a17 | 180 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 181 | return connected() ? 1 : 0; |
Helmut Tschemernjak | 3:bddd92cd3a17 | 182 | } |
Helmut Tschemernjak | 3:bddd92cd3a17 | 183 | |
Helmut Tschemernjak | 3:bddd92cd3a17 | 184 | #endif |