├── .gitignore ├── CMakeLists.txt ├── gentaps.c ├── gentaps.o └── src ├── dsp ├── audio.h ├── block.h ├── buffer.h ├── clock_recovery.h ├── convertion.h ├── deframing.h ├── demodulator.h ├── falcon_fec.h ├── falcon_packet.h ├── filter.h ├── interpolation_taps.h ├── math.h ├── measure.h ├── noaa │ ├── hrpt.h │ └── tip.h ├── pll.h ├── processing.h ├── resampling.h ├── routing.h ├── sink.h ├── source.h ├── stream.h ├── types.h ├── utils │ ├── bitstream.h │ ├── ccsds.h │ └── macros.h ├── vfo.h └── window.h ├── libcorrect ├── convolutional │ ├── CMakeLists.txt │ ├── bit.c │ ├── convolutional.c │ ├── decode.c │ ├── encode.c │ ├── error_buffer.c │ ├── history_buffer.c │ ├── lookup.c │ ├── metric.c │ └── sse │ │ ├── CMakeLists.txt │ │ ├── convolutional.c │ │ ├── decode.c │ │ ├── encode.c │ │ └── lookup.c ├── correct-sse.h ├── correct.h ├── correct │ ├── convolutional.h │ ├── convolutional │ │ ├── bit.h │ │ ├── convolutional.h │ │ ├── error_buffer.h │ │ ├── history_buffer.h │ │ ├── lookup.h │ │ ├── metric.h │ │ └── sse │ │ │ ├── convolutional.h │ │ │ └── lookup.h │ ├── portable.h │ ├── reed-solomon.h │ ├── reed-solomon │ │ ├── decode.h │ │ ├── encode.h │ │ ├── field.h │ │ ├── polynomial.h │ │ └── reed-solomon.h │ └── util │ │ ├── error-sim-fec.h │ │ ├── error-sim-shim.h │ │ ├── error-sim-sse.h │ │ └── error-sim.h ├── fec_shim.c ├── fec_shim.h └── reed-solomon │ ├── CMakeLists.txt │ ├── decode.c │ ├── encode.c │ ├── polynomial.c │ └── reed-solomon.c ├── main.cpp ├── spdlog ├── async.h ├── async_logger-inl.h ├── async_logger.h ├── cfg │ ├── argv.h │ ├── env.h │ ├── helpers-inl.h │ ├── helpers.h │ └── log_levels.h ├── common-inl.h ├── common.h ├── details │ ├── backtracer-inl.h │ ├── backtracer.h │ ├── circular_q.h │ ├── console_globals.h │ ├── file_helper-inl.h │ ├── file_helper.h │ ├── fmt_helper.h │ ├── log_msg-inl.h │ ├── log_msg.h │ ├── log_msg_buffer-inl.h │ ├── log_msg_buffer.h │ ├── mpmc_blocking_q.h │ ├── null_mutex.h │ ├── os-inl.h │ ├── os.h │ ├── periodic_worker-inl.h │ ├── periodic_worker.h │ ├── registry-inl.h │ ├── registry.h │ ├── synchronous_factory.h │ ├── tcp_client-windows.h │ ├── tcp_client.h │ ├── thread_pool-inl.h │ ├── thread_pool.h │ └── windows_include.h ├── fmt │ ├── bin_to_hex.h │ ├── bundled │ │ ├── LICENSE.rst │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── locale.h │ │ ├── ostream.h │ │ ├── posix.h │ │ ├── printf.h │ │ └── ranges.h │ ├── fmt.h │ └── ostr.h ├── formatter.h ├── fwd.h ├── logger-inl.h ├── logger.h ├── pattern_formatter-inl.h ├── pattern_formatter.h ├── sinks │ ├── android_sink.h │ ├── ansicolor_sink-inl.h │ ├── ansicolor_sink.h │ ├── base_sink-inl.h │ ├── base_sink.h │ ├── basic_file_sink-inl.h │ ├── basic_file_sink.h │ ├── daily_file_sink.h │ ├── dist_sink.h │ ├── dup_filter_sink.h │ ├── msvc_sink.h │ ├── null_sink.h │ ├── ostream_sink.h │ ├── ringbuffer_sink.h │ ├── rotating_file_sink-inl.h │ ├── rotating_file_sink.h │ ├── sink-inl.h │ ├── sink.h │ ├── stdout_color_sinks-inl.h │ ├── stdout_color_sinks.h │ ├── stdout_sinks-inl.h │ ├── stdout_sinks.h │ ├── syslog_sink.h │ ├── systemd_sink.h │ ├── tcp_sink.h │ ├── win_eventlog_sink.h │ ├── wincolor_sink-inl.h │ └── wincolor_sink.h ├── spdlog-inl.h ├── spdlog.h ├── tweakme.h └── version.h ├── wav.h └── wavreader.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | *.old 4 | *.dll 5 | *.exe 6 | *.zip -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | project(dsptest) 3 | 4 | if (MSVC) 5 | set(CMAKE_CXX_FLAGS "-O2 /std:c++17") # 6 | else() 7 | set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") 8 | link_libraries(pthread) 9 | endif (MSVC) 10 | 11 | include_directories("src/") 12 | include_directories("src/libcorrect/") 13 | 14 | file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c") 15 | 16 | add_executable(dsptest ${SRC}) 17 | 18 | 19 | if (MSVC) 20 | target_include_directories(dsptest PUBLIC "C:/Program Files/PothosSDR/include/") 21 | target_link_directories(dsptest PUBLIC "C:/Program Files/PothosSDR/lib/") 22 | endif (MSVC) 23 | 24 | target_link_libraries(dsptest PUBLIC volk) 25 | -------------------------------------------------------------------------------- /gentaps.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexandreRouma/qdsp/a9c36d5f5176310373c47066c59f056ec1dc4c2b/gentaps.o -------------------------------------------------------------------------------- /src/dsp/deframing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define DSP_SIGN(n) ((n) >= 0) 6 | #define DSP_STEP(n) (((n) > 0.0f) ? 1.0f : -1.0f) 7 | 8 | namespace dsp { 9 | class Deframer : public generic_block { 10 | public: 11 | Deframer() {} 12 | 13 | Deframer(stream* in, int frameLen, uint8_t* syncWord, int syncLen) { init(in, frameLen, syncWord, syncLen); } 14 | 15 | ~Deframer() { 16 | generic_block::stop(); 17 | } 18 | 19 | void init(stream* in, int frameLen, uint8_t* syncWord, int syncLen) { 20 | _in = in; 21 | _frameLen = frameLen; 22 | _syncword = new uint8_t[syncLen]; 23 | _syncLen = syncLen; 24 | memcpy(_syncword, syncWord, syncLen); 25 | 26 | buffer = new uint8_t[STREAM_BUFFER_SIZE + syncLen]; 27 | memset(buffer, 0, syncLen); 28 | bufferStart = buffer + syncLen; 29 | 30 | generic_block::registerInput(_in); 31 | generic_block::registerOutput(&out); 32 | } 33 | 34 | int run() { 35 | count = _in->read(); 36 | if (count < 0) { return -1; } 37 | 38 | 39 | // Copy data into work buffer 40 | memcpy(bufferStart, _in->readBuf, count - 1); 41 | 42 | // Iterate through all symbols 43 | for (int i = 0; i < count;) { 44 | 45 | // If already in the process of reading bits 46 | if (bitsRead >= 0) { 47 | if ((bitsRead % 8) == 0) { out.writeBuf[bitsRead / 8] = 0; } 48 | out.writeBuf[bitsRead / 8] |= (buffer[i] << (7 - (bitsRead % 8))); 49 | i++; 50 | bitsRead++; 51 | 52 | if (bitsRead >= _frameLen) { 53 | if (!out.swap((bitsRead / 8) + ((bitsRead % 8) > 0))) { return -1; } 54 | bitsRead = -1; 55 | nextBitIsStartOfFrame = true; 56 | } 57 | 58 | continue; 59 | } 60 | 61 | // Else, check for a header 62 | else if (memcmp(buffer + i, _syncword, _syncLen) == 0) { 63 | bitsRead = 0; 64 | badFrameCount = 0; 65 | continue; 66 | } 67 | else if (nextBitIsStartOfFrame) { 68 | nextBitIsStartOfFrame = false; 69 | 70 | // try to save 71 | if (badFrameCount < 5) { 72 | badFrameCount++; 73 | bitsRead = 0; 74 | continue; 75 | } 76 | 77 | } 78 | 79 | else { i++; } 80 | 81 | nextBitIsStartOfFrame = false; 82 | 83 | } 84 | 85 | // Keep last _syncLen4 symbols 86 | memcpy(buffer, &_in->readBuf[count - _syncLen], _syncLen); 87 | 88 | //printf("Block processed\n"); 89 | callcount++; 90 | 91 | _in->flush(); 92 | return count; 93 | } 94 | 95 | stream out; 96 | 97 | private: 98 | uint8_t* buffer; 99 | uint8_t* bufferStart; 100 | uint8_t* _syncword; 101 | int count; 102 | int _frameLen; 103 | int _syncLen; 104 | int bitsRead = -1; 105 | 106 | int badFrameCount = 5; 107 | bool nextBitIsStartOfFrame = false; 108 | 109 | int callcount = 0; 110 | 111 | stream* _in; 112 | 113 | }; 114 | } -------------------------------------------------------------------------------- /src/dsp/falcon_packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dsp { 6 | struct FalconFrameHeader { 7 | uint32_t counter; 8 | uint16_t packet; 9 | }; 10 | 11 | class FalconPacketSync : public generic_block { 12 | public: 13 | FalconPacketSync() {} 14 | 15 | FalconPacketSync(stream* in) { init(in); } 16 | 17 | ~FalconPacketSync() { 18 | generic_block::stop(); 19 | } 20 | 21 | void init(stream* in) { 22 | _in = in; 23 | 24 | generic_block::registerInput(_in); 25 | generic_block::registerOutput(&out); 26 | } 27 | 28 | int run() { 29 | count = _in->read(); 30 | if (count < 0) { return -1; } 31 | 32 | // Parse frame header 33 | FalconFrameHeader header; 34 | header.packet = (_in->readBuf[3] | ((_in->readBuf[2] & 0b111) << 8)); 35 | header.counter = ((_in->readBuf[2] >> 3) | (_in->readBuf[1] << 5) | ((_in->readBuf[0] & 0b111111) << 13)); 36 | 37 | // Pointer to the data aera of the frame 38 | uint8_t* data = _in->readBuf + 4; 39 | int dataLen = 1191; 40 | 41 | // If a frame was missed, cancel reading the current packet 42 | if (lastCounter + 1 != header.counter) { 43 | packetRead = -1; 44 | } 45 | lastCounter = header.counter; 46 | 47 | // If frame is just a continuation of a single packet, save it 48 | // If we're not currently reading a packet 49 | if (header.packet == 2047 && packetRead >= 0) { 50 | memcpy(packet + packetRead, data, dataLen); 51 | packetRead += dataLen; 52 | _in->flush(); 53 | printf("Wow, all data\n"); 54 | return count; 55 | } 56 | else if (header.packet == 2047) { 57 | printf("Wow, all data\n"); 58 | _in->flush(); 59 | return count; 60 | } 61 | 62 | // Finish reading the last package and send it 63 | if (packetRead >= 0) { 64 | memcpy(packet + packetRead, data, header.packet); 65 | memcpy(out.writeBuf, packet, packetRead + header.packet); 66 | out.swap(packetRead + header.packet); 67 | packetRead = -1; 68 | } 69 | 70 | // Iterate through every packet of the frame 71 | for (int i = header.packet; i < dataLen;) { 72 | // First, check if we can read the header. If not, save and wait for next frame 73 | if (dataLen - i < 4) { 74 | packetRead = dataLen - i; 75 | memcpy(packet, &data[i], packetRead); 76 | break; 77 | } 78 | 79 | // Extract packet length 80 | uint16_t length = (((data[i] & 0b1111) << 8) | data[i + 1]) + 2; 81 | 82 | // Check if it's not an invalid zero length packet 83 | if (length <= 2) { 84 | packetRead = -1; 85 | break; 86 | } 87 | 88 | uint64_t pktId = ((uint64_t)data[i + 2] << 56) | ((uint64_t)data[i + 3] << 48) | ((uint64_t)data[i + 4] << 40) | ((uint64_t)data[i + 5] << 32) 89 | | ((uint64_t)data[i + 6] << 24) | ((uint64_t)data[i + 7] << 16) | ((uint64_t)data[i + 8] << 8) | data[i + 9]; 90 | 91 | // If the packet doesn't fit the frame, save and go to next frame 92 | if (dataLen - i < length) { 93 | packetRead = dataLen - i; 94 | memcpy(packet, &data[i], packetRead); 95 | break; 96 | } 97 | 98 | // Here, the package fits fully, read it and jump to the next 99 | memcpy(out.writeBuf, &data[i], length); 100 | out.swap(length); 101 | i += length; 102 | 103 | } 104 | 105 | _in->flush(); 106 | return count; 107 | } 108 | 109 | stream out; 110 | 111 | private: 112 | int count; 113 | uint32_t lastCounter = 0; 114 | 115 | int packetRead = -1; 116 | uint8_t packet[0x4008]; 117 | 118 | stream* _in; 119 | 120 | }; 121 | } -------------------------------------------------------------------------------- /src/dsp/measure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dsp { 10 | class LevelMeter : public generic_block { 11 | public: 12 | LevelMeter() {} 13 | 14 | LevelMeter(stream* in) { init(in); } 15 | 16 | void init(stream* in) { 17 | _in = in; 18 | generic_block::registerInput(_in); 19 | } 20 | 21 | void setInput(stream* in) { 22 | std::lock_guard lck(generic_block::ctrlMtx); 23 | generic_block::tempStop(); 24 | generic_block::unregisterInput(_in); 25 | _in = in; 26 | generic_block::registerInput(_in); 27 | generic_block::tempStart(); 28 | } 29 | 30 | int run() { 31 | int count = _in->read(); 32 | if (count < 0) { return -1; } 33 | 34 | float maxL = 0, maxR = 0; 35 | float absL, absR; 36 | for (int i = 0; i < count; i++) { 37 | absL = fabs(_in->readBuf[i].l); 38 | absR = fabs(_in->readBuf[i].r); 39 | if (absL > maxL) { maxL = absL; } 40 | if (absR > maxR) { maxR = absR; } 41 | } 42 | 43 | _in->flush(); 44 | 45 | float _lvlL = 10.0f * logf(maxL); 46 | float _lvlR = 10.0f * logf(maxR); 47 | 48 | // Update max values 49 | { 50 | std::lock_guard lck(lvlMtx); 51 | if (_lvlL > lvlL) { lvlL = _lvlL; } 52 | if (_lvlR > lvlR) { lvlR = _lvlR; } 53 | } 54 | 55 | 56 | return count; 57 | } 58 | 59 | float getLeftLevel() { 60 | std::lock_guard lck(lvlMtx); 61 | float ret = lvlL; 62 | lvlL = -90.0f; 63 | return ret; 64 | } 65 | 66 | float getRightLevel() { 67 | std::lock_guard lck(lvlMtx); 68 | float ret = lvlR; 69 | lvlR = -90.0f; 70 | return ret; 71 | } 72 | 73 | private: 74 | float lvlL = -90.0f; 75 | float lvlR = -90.0f; 76 | stream* _in; 77 | std::mutex lvlMtx; 78 | 79 | }; 80 | } -------------------------------------------------------------------------------- /src/dsp/noaa/hrpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dsp { 6 | namespace noaa { 7 | inline uint16_t HRPTReadWord(int offset, uint8_t* buffer) { 8 | return (uint16_t)readBits(offset * 10, 10, buffer); 9 | } 10 | 11 | class HRPTDemux : public generic_block { 12 | public: 13 | HRPTDemux() {} 14 | 15 | HRPTDemux(stream* in) { init(in); } 16 | 17 | void init(stream* in) { 18 | _in = in; 19 | generic_block::registerInput(_in); 20 | generic_block::registerOutput(&AVHRRChan1Out); 21 | generic_block::registerOutput(&AVHRRChan2Out); 22 | generic_block::registerOutput(&AVHRRChan3Out); 23 | generic_block::registerOutput(&AVHRRChan4Out); 24 | generic_block::registerOutput(&AVHRRChan5Out); 25 | } 26 | 27 | void setInput(stream* in) { 28 | std::lock_guard lck(generic_block::ctrlMtx); 29 | generic_block::tempStop(); 30 | generic_block::unregisterInput(_in); 31 | _in = in; 32 | generic_block::registerInput(_in); 33 | generic_block::tempStart(); 34 | } 35 | 36 | int run() { 37 | int count = _in->read(); 38 | if (count < 0) { return -1; } 39 | 40 | int minFrame = readBits(61, 2, _in->readBuf); 41 | 42 | // Extract TIP frames if present 43 | if (minFrame == 1) { 44 | for (int i = 0; i < 5; i++) { 45 | for (int j = 0; j < 104; j++) { 46 | TIPOut.writeBuf[j] = (HRPTReadWord(103 + (i * 104) + j, _in->readBuf) >> 2) & 0xFF; 47 | } 48 | if (!TIPOut.swap(104)) { return -1; }; 49 | } 50 | } 51 | 52 | // Exctact AIP otherwise 53 | else if (minFrame == 3) { 54 | for (int i = 0; i < 5; i++) { 55 | for (int j = 0; j < 104; j++) { 56 | AIPOut.writeBuf[j] = (HRPTReadWord(103 + (i * 104) + j, _in->readBuf) >> 2) & 0xFF; 57 | } 58 | if (!AIPOut.swap(104)) { return -1; }; 59 | } 60 | } 61 | 62 | // Extract AVHRR data 63 | for (int i = 0; i < 2048; i++) { 64 | AVHRRChan1Out.writeBuf[i] = HRPTReadWord(750 + (i * 5), _in->readBuf); 65 | AVHRRChan2Out.writeBuf[i] = HRPTReadWord(750 + (i * 5) + 1, _in->readBuf); 66 | AVHRRChan3Out.writeBuf[i] = HRPTReadWord(750 + (i * 5) + 2, _in->readBuf); 67 | AVHRRChan4Out.writeBuf[i] = HRPTReadWord(750 + (i * 5) + 3, _in->readBuf); 68 | AVHRRChan5Out.writeBuf[i] = HRPTReadWord(750 + (i * 5) + 4, _in->readBuf); 69 | } 70 | if (!AVHRRChan1Out.swap(2048)) { return -1; }; 71 | if (!AVHRRChan2Out.swap(2048)) { return -1; }; 72 | if (!AVHRRChan3Out.swap(2048)) { return -1; }; 73 | if (!AVHRRChan4Out.swap(2048)) { return -1; }; 74 | if (!AVHRRChan5Out.swap(2048)) { return -1; }; 75 | 76 | _in->flush(); 77 | return count; 78 | } 79 | 80 | stream TIPOut; 81 | stream AIPOut; 82 | 83 | stream AVHRRChan1Out; 84 | stream AVHRRChan2Out; 85 | stream AVHRRChan3Out; 86 | stream AVHRRChan4Out; 87 | stream AVHRRChan5Out; 88 | 89 | private: 90 | stream* _in; 91 | 92 | }; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/dsp/source.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dsp { 5 | class SineSource : public generic_block { 6 | public: 7 | SineSource() {} 8 | 9 | SineSource(int blockSize, float sampleRate, float freq) { init(blockSize, sampleRate, freq); } 10 | 11 | void init(int blockSize, float sampleRate, float freq) { 12 | _blockSize = blockSize; 13 | _sampleRate = sampleRate; 14 | _freq = freq; 15 | zeroPhase = (lv_32fc_t*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(lv_32fc_t), volk_get_alignment()); 16 | for (int i = 0; i < STREAM_BUFFER_SIZE; i++) { 17 | zeroPhase[i] = lv_cmake(1.0f, 0.0f); 18 | } 19 | phase = lv_cmake(1.0f, 0.0f); 20 | phaseDelta = lv_cmake(std::cos((_freq / _sampleRate) * 2.0f * FL_M_PI), std::sin((_freq / _sampleRate) * 2.0f * FL_M_PI)); 21 | generic_block::registerOutput(&out); 22 | } 23 | 24 | void setBlockSize(int blockSize) { 25 | std::lock_guard lck(generic_block::ctrlMtx); 26 | generic_block::tempStop(); 27 | _blockSize = blockSize; 28 | generic_block::tempStart(); 29 | } 30 | 31 | int getBlockSize() { 32 | return _blockSize; 33 | } 34 | 35 | void setSampleRate(float sampleRate) { 36 | // No need to restart 37 | _sampleRate = sampleRate; 38 | phaseDelta = lv_cmake(std::cos((_freq / _sampleRate) * 2.0f * FL_M_PI), std::sin((_freq / _sampleRate) * 2.0f * FL_M_PI)); 39 | } 40 | 41 | float getSampleRate() { 42 | return _sampleRate; 43 | } 44 | 45 | void setFrequency(float freq) { 46 | // No need to restart 47 | _freq = freq; 48 | phaseDelta = lv_cmake(std::cos((_freq / _sampleRate) * 2.0f * FL_M_PI), std::sin((_freq / _sampleRate) * 2.0f * FL_M_PI)); 49 | } 50 | 51 | float getFrequency() { 52 | return _freq; 53 | } 54 | 55 | int run() { 56 | volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)out.writeBuf, zeroPhase, phaseDelta, &phase, _blockSize); 57 | if(!out.swap(_blockSize)) { return -1; } 58 | return _blockSize; 59 | } 60 | 61 | stream out; 62 | 63 | private: 64 | int _blockSize; 65 | float _sampleRate; 66 | float _freq; 67 | lv_32fc_t phaseDelta; 68 | lv_32fc_t phase; 69 | lv_32fc_t* zeroPhase; 70 | 71 | }; 72 | 73 | template 74 | class HandlerSource : public generic_block> { 75 | public: 76 | HandlerSource() {} 77 | 78 | HandlerSource(int (*handler)(T* data, void* ctx), void* ctx) { init(handler, ctx); } 79 | 80 | void init(int (*handler)(T* data, void* ctx), void* ctx) { 81 | _handler = handler; 82 | _ctx = ctx; 83 | generic_block>::registerOutput(&out); 84 | } 85 | 86 | void setHandler(int (*handler)(T* data, void* ctx), void* ctx) { 87 | std::lock_guard lck(generic_block>::ctrlMtx); 88 | generic_block>::tempStop(); 89 | _handler = handler; 90 | _ctx = ctx; 91 | generic_block>::tempStart(); 92 | } 93 | 94 | int run() { 95 | int count = _handler(out.writeBuf, _ctx); 96 | if (count < 0) { return -1; } 97 | out.swap(count); 98 | return count; 99 | } 100 | 101 | stream out; 102 | 103 | private: 104 | int (*_handler)(T* data, void* ctx); 105 | void* _ctx; 106 | 107 | }; 108 | } -------------------------------------------------------------------------------- /src/dsp/stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | // 1MB buffer 7 | #define STREAM_BUFFER_SIZE 1000000 8 | 9 | namespace dsp { 10 | class untyped_steam { 11 | public: 12 | virtual bool swap(int size) { return false; } 13 | virtual int read() { return -1; } 14 | virtual void flush() {} 15 | virtual void stopWriter() {} 16 | virtual void clearWriteStop() {} 17 | virtual void stopReader() {} 18 | virtual void clearReadStop() {} 19 | }; 20 | 21 | template 22 | class stream : public untyped_steam { 23 | public: 24 | stream() { 25 | writeBuf = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T), volk_get_alignment()); 26 | readBuf = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T), volk_get_alignment()); 27 | } 28 | 29 | ~stream() { 30 | volk_free(writeBuf); 31 | volk_free(readBuf); 32 | } 33 | 34 | bool swap(int size) { 35 | { 36 | // Wait to either swap or stop 37 | std::unique_lock lck(swapMtx); 38 | swapCV.wait(lck, [this]{ return (canSwap || writerStop); }); 39 | 40 | // If writer was stopped, abandon operation 41 | if (writerStop) { return false; } 42 | 43 | // Swap buffers 44 | dataSize = size; 45 | T* temp = writeBuf; 46 | writeBuf = readBuf; 47 | readBuf = temp; 48 | canSwap = false; 49 | } 50 | 51 | // Notify reader that some data is ready 52 | { 53 | std::lock_guard lck(rdyMtx); 54 | dataReady = true; 55 | } 56 | rdyCV.notify_all(); 57 | 58 | return true; 59 | } 60 | 61 | int read() { 62 | // Wait for data to be ready or to be stopped 63 | std::unique_lock lck(rdyMtx); 64 | rdyCV.wait(lck, [this]{ return (dataReady || readerStop); }); 65 | 66 | return (readerStop ? -1 : dataSize); 67 | } 68 | 69 | void flush() { 70 | // Clear data ready 71 | { 72 | std::lock_guard lck(rdyMtx); 73 | dataReady = false; 74 | } 75 | 76 | // Notify writer that buffers can be swapped 77 | { 78 | std::lock_guard lck(swapMtx); 79 | canSwap = true; 80 | } 81 | 82 | swapCV.notify_all(); 83 | } 84 | 85 | void stopWriter() { 86 | { 87 | std::lock_guard lck(swapMtx); 88 | writerStop = true; 89 | } 90 | swapCV.notify_all(); 91 | } 92 | 93 | void clearWriteStop() { 94 | writerStop = false; 95 | } 96 | 97 | void stopReader() { 98 | { 99 | std::lock_guard lck(rdyMtx); 100 | readerStop = true; 101 | } 102 | rdyCV.notify_all(); 103 | } 104 | 105 | void clearReadStop() { 106 | readerStop = false; 107 | } 108 | 109 | T* writeBuf; 110 | T* readBuf; 111 | 112 | private: 113 | std::mutex swapMtx; 114 | std::condition_variable swapCV; 115 | bool canSwap = true; 116 | 117 | std::mutex rdyMtx; 118 | std::condition_variable rdyCV; 119 | bool dataReady = false; 120 | 121 | bool readerStop = false; 122 | bool writerStop = false; 123 | 124 | int dataSize = 0; 125 | }; 126 | } -------------------------------------------------------------------------------- /src/dsp/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define FL_M_PI 3.1415926535f 5 | 6 | namespace dsp { 7 | struct complex_t { 8 | complex_t operator*(const float b) { 9 | return complex_t{re*b, im*b}; 10 | } 11 | 12 | complex_t operator/(const float b) { 13 | return complex_t{re/b, im/b}; 14 | } 15 | 16 | complex_t operator*(const complex_t& b) { 17 | return complex_t{(re*b.re) - (im*b.im), (im*b.re) + (re*b.im)}; 18 | } 19 | 20 | complex_t operator+(const complex_t& b) { 21 | return complex_t{re+b.re, im+b.im}; 22 | } 23 | 24 | complex_t operator-(const complex_t& b) { 25 | return complex_t{re-b.re, im-b.im}; 26 | } 27 | 28 | inline complex_t conj() { 29 | return complex_t{re, -im}; 30 | } 31 | 32 | inline float phase() { 33 | return atan2f(im, re); 34 | } 35 | 36 | inline float fastPhase() { 37 | float abs_im = fabsf(im); 38 | float r, angle; 39 | if (re == 0.0f && im == 0.0f) { return 0.0f; } 40 | if (re>=0.0f) { 41 | r = (re - abs_im) / (re + abs_im); 42 | angle = (FL_M_PI / 4.0f) - (FL_M_PI / 4.0f) * r; 43 | } 44 | else { 45 | r = (re + abs_im) / (abs_im - re); 46 | angle = (3.0f * (FL_M_PI / 4.0f)) - (FL_M_PI / 4.0f) * r; 47 | } 48 | if (im < 0.0f) { 49 | return -angle; 50 | } 51 | return angle; 52 | } 53 | 54 | inline float amplitude() { 55 | return sqrt((re*re) + (im*im)); 56 | } 57 | 58 | inline float fastAmplitude() { 59 | float re_abs = fabsf(re); 60 | float im_abs = fabsf(re); 61 | if (re_abs > im_abs) { return re_abs + 0.4f * im_abs; } 62 | return im_abs + 0.4f * re_abs; 63 | } 64 | 65 | float re; 66 | float im; 67 | }; 68 | 69 | struct stereo_t { 70 | stereo_t operator*(const float b) { 71 | return stereo_t{l*b, r*b}; 72 | } 73 | 74 | stereo_t operator+(const stereo_t& b) { 75 | return stereo_t{l+b.l, r+b.r}; 76 | } 77 | 78 | stereo_t operator-(const stereo_t& b) { 79 | return stereo_t{l-b.l, r-b.r}; 80 | } 81 | 82 | float l; 83 | float r; 84 | }; 85 | } -------------------------------------------------------------------------------- /src/dsp/utils/bitstream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dsp { 4 | inline uint64_t readBits(int offset, int length, uint8_t* buffer) { 5 | uint64_t outputValue = 0; 6 | 7 | int lastBit = offset + (length - 1); 8 | 9 | int firstWord = offset / 8; 10 | int lastWord = lastBit / 8; 11 | int firstOffset = offset - (firstWord * 8); 12 | int lastOffset = lastBit - (lastWord * 8); 13 | 14 | int wordCount = (lastWord - firstWord) + 1; 15 | 16 | // If the data fits in a single byte, just get it 17 | if (wordCount == 1) { 18 | return (buffer[firstWord] & (0xFF >> firstOffset)) >> (7 - lastOffset); 19 | } 20 | 21 | int bitsRead = length; 22 | for (int i = 0; i < wordCount; i++) { 23 | // First word 24 | if (i == 0) { 25 | bitsRead -= 8 - firstOffset; 26 | outputValue |= (uint64_t)(buffer[firstWord] & (0xFF >> firstOffset)) << bitsRead; 27 | continue; 28 | } 29 | 30 | // Last word 31 | if (i == (wordCount - 1)) { 32 | outputValue |= (uint64_t)buffer[lastWord] >> (7 - lastOffset); 33 | break; 34 | } 35 | 36 | // Just a normal byte 37 | bitsRead -= 8; 38 | outputValue |= (uint64_t)buffer[firstWord + i] << bitsRead; 39 | } 40 | 41 | return outputValue; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/dsp/utils/macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define DSP_SIGN(n) ((n) >= 0) 5 | #define DSP_STEP_CPLX(c) (complex_t{(c.re > 0.0f) ? 1.0f : -1.0f, (c.im > 0.0f) ? 1.0f : -1.0f}) 6 | #define DSP_STEP(n) (((n) > 0.0f) ? 1.0f : -1.0f) -------------------------------------------------------------------------------- /src/dsp/vfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace dsp { 9 | class VFO { 10 | public: 11 | VFO() {} 12 | 13 | ~VFO() { stop(); } 14 | 15 | VFO(stream* in, float offset, float inSampleRate, float outSampleRate, float bandWidth) { 16 | init(in, offset, inSampleRate, outSampleRate, bandWidth); 17 | }; 18 | 19 | void init(stream* in, float offset, float inSampleRate, float outSampleRate, float bandWidth) { 20 | _in = in; 21 | _offset = offset; 22 | _inSampleRate = inSampleRate; 23 | _outSampleRate = outSampleRate; 24 | _bandWidth = bandWidth; 25 | 26 | float realCutoff = std::min(_bandWidth, std::min(_inSampleRate, _outSampleRate)) / 2.0f; 27 | 28 | xlator.init(_in, _inSampleRate, -_offset); 29 | win.init(realCutoff, realCutoff, inSampleRate); 30 | resamp.init(&xlator.out, &win, _inSampleRate, _outSampleRate); 31 | 32 | win.setSampleRate(_inSampleRate * resamp.getInterpolation()); 33 | resamp.updateWindow(&win); 34 | 35 | out = &resamp.out; 36 | } 37 | 38 | void start() { 39 | if (running) { return; } 40 | xlator.start(); 41 | resamp.start(); 42 | } 43 | 44 | void stop() { 45 | if (!running) { return; } 46 | xlator.stop(); 47 | resamp.stop(); 48 | } 49 | 50 | void setInSampleRate(float inSampleRate) { 51 | _inSampleRate = inSampleRate; 52 | if (running) { xlator.stop(); resamp.stop(); } 53 | xlator.setSampleRate(_inSampleRate); 54 | resamp.setInSampleRate(_inSampleRate); 55 | float realCutoff = std::min(_bandWidth, std::min(_inSampleRate, _outSampleRate)) / 2.0f; 56 | win.setSampleRate(_inSampleRate * resamp.getInterpolation()); 57 | win.setCutoff(realCutoff); 58 | win.setTransWidth(realCutoff); 59 | resamp.updateWindow(&win); 60 | if (running) { xlator.start(); resamp.start(); } 61 | } 62 | 63 | void setOutSampleRate(float outSampleRate) { 64 | _outSampleRate = outSampleRate; 65 | if (running) { resamp.stop(); } 66 | resamp.setOutSampleRate(_outSampleRate); 67 | float realCutoff = std::min(_bandWidth, std::min(_inSampleRate, _outSampleRate)) / 2.0f; 68 | win.setSampleRate(_inSampleRate * resamp.getInterpolation()); 69 | win.setCutoff(realCutoff); 70 | win.setTransWidth(realCutoff); 71 | resamp.updateWindow(&win); 72 | if (running) { resamp.start(); } 73 | } 74 | 75 | void setOutSampleRate(float outSampleRate, float bandWidth) { 76 | _outSampleRate = outSampleRate; 77 | _bandWidth = bandWidth; 78 | if (running) { resamp.stop(); } 79 | resamp.setOutSampleRate(_outSampleRate); 80 | float realCutoff = std::min(_bandWidth, std::min(_inSampleRate, _outSampleRate)) / 2.0f; 81 | win.setSampleRate(_inSampleRate * resamp.getInterpolation()); 82 | win.setCutoff(realCutoff); 83 | win.setTransWidth(realCutoff); 84 | resamp.updateWindow(&win); 85 | if (running) { resamp.start(); } 86 | } 87 | 88 | void setOffset(float offset) { 89 | _offset = offset; 90 | xlator.setFrequency(-_offset); 91 | } 92 | 93 | void setBandwidth(float bandWidth) { 94 | _bandWidth = bandWidth; 95 | float realCutoff = std::min(_bandWidth, std::min(_inSampleRate, _outSampleRate)) / 2.0f; 96 | win.setCutoff(realCutoff); 97 | win.setTransWidth(realCutoff); 98 | resamp.updateWindow(&win); 99 | } 100 | 101 | stream* out; 102 | 103 | private: 104 | bool running = false; 105 | float _offset, _inSampleRate, _outSampleRate, _bandWidth; 106 | filter_window::BlackmanWindow win; 107 | stream* _in; 108 | FrequencyXlator xlator; 109 | PolyphaseResampler resamp; 110 | 111 | }; 112 | } -------------------------------------------------------------------------------- /src/libcorrect/convolutional/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRCFILES bit.c metric.c history_buffer.c error_buffer.c lookup.c convolutional.c encode.c decode.c) 2 | add_library(correct-convolutional OBJECT ${SRCFILES}) 3 | if(HAVE_SSE) 4 | add_subdirectory(sse) 5 | endif() 6 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/convolutional.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/convolutional.h" 2 | 3 | // https://www.youtube.com/watch?v=b3_lVSrPB6w 4 | 5 | correct_convolutional *_correct_convolutional_init(correct_convolutional *conv, 6 | size_t rate, size_t order, 7 | const polynomial_t *poly) { 8 | if (order > 8 * sizeof(shift_register_t)) { 9 | // XXX turn this into an error code 10 | // printf("order must be smaller than 8 * sizeof(shift_register_t)\n"); 11 | return NULL; 12 | } 13 | if (rate < 2) { 14 | // XXX turn this into an error code 15 | // printf("rate must be 2 or greater\n"); 16 | return NULL; 17 | } 18 | 19 | conv->order = order; 20 | conv->rate = rate; 21 | conv->numstates = 1 << order; 22 | 23 | unsigned int *table = malloc(sizeof(unsigned int) * (1 << order)); 24 | fill_table(conv->rate, conv->order, poly, table); 25 | *(unsigned int **)&conv->table = table; 26 | 27 | conv->bit_writer = bit_writer_create(NULL, 0); 28 | conv->bit_reader = bit_reader_create(NULL, 0); 29 | 30 | conv->has_init_decode = false; 31 | return conv; 32 | } 33 | 34 | correct_convolutional *correct_convolutional_create(size_t rate, size_t order, 35 | const polynomial_t *poly) { 36 | correct_convolutional *conv = malloc(sizeof(correct_convolutional)); 37 | correct_convolutional *init_conv = _correct_convolutional_init(conv, rate, order, poly); 38 | if (!init_conv) { 39 | free(conv); 40 | } 41 | return init_conv; 42 | } 43 | 44 | void _correct_convolutional_teardown(correct_convolutional *conv) { 45 | free(*(unsigned int **)&conv->table); 46 | bit_writer_destroy(conv->bit_writer); 47 | bit_reader_destroy(conv->bit_reader); 48 | if (conv->has_init_decode) { 49 | pair_lookup_destroy(conv->pair_lookup); 50 | history_buffer_destroy(conv->history_buffer); 51 | error_buffer_destroy(conv->errors); 52 | free(conv->distances); 53 | } 54 | } 55 | 56 | void correct_convolutional_destroy(correct_convolutional *conv) { 57 | _correct_convolutional_teardown(conv); 58 | free(conv); 59 | } 60 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/encode.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/convolutional.h" 2 | 3 | size_t correct_convolutional_encode_len(correct_convolutional *conv, size_t msg_len) { 4 | size_t msgbits = 8 * msg_len; 5 | size_t encodedbits = conv->rate * (msgbits + conv->order + 1); 6 | return encodedbits; 7 | } 8 | 9 | // shift in most significant bit every time, one byte at a time 10 | // shift register takes most recent bit on right, shifts left 11 | // poly is written in same order, just & mask message w/ poly 12 | 13 | // assume that encoded length is long enough? 14 | size_t correct_convolutional_encode(correct_convolutional *conv, 15 | const uint8_t *msg, 16 | size_t msg_len, 17 | uint8_t *encoded) { 18 | // convolutional code convolves filter coefficients, given by 19 | // the polynomial, with some history from our message. 20 | // the history is stored as single subsequent bits in shiftregister 21 | shift_register_t shiftregister = 0; 22 | 23 | // shiftmask is the shiftregister bit mask that removes bits 24 | // that extend beyond order 25 | // e.g. if order is 7, then remove the 8th bit and beyond 26 | unsigned int shiftmask = (1 << conv->order) - 1; 27 | 28 | size_t encoded_len_bits = correct_convolutional_encode_len(conv, msg_len); 29 | size_t encoded_len = (encoded_len_bits % 8) ? (encoded_len_bits / 8 + 1) : (encoded_len_bits / 8); 30 | bit_writer_reconfigure(conv->bit_writer, encoded, encoded_len); 31 | 32 | bit_reader_reconfigure(conv->bit_reader, msg, msg_len); 33 | 34 | for (size_t i = 0; i < 8 * msg_len; i++) { 35 | // shiftregister has oldest bits on left, newest on right 36 | shiftregister <<= 1; 37 | shiftregister |= bit_reader_read(conv->bit_reader, 1); 38 | shiftregister &= shiftmask; 39 | // shift most significant bit from byte and move down one bit at a time 40 | 41 | // we do direct lookup of our convolutional output here 42 | // all of the bits from this convolution are stored in this row 43 | unsigned int out = conv->table[shiftregister]; 44 | bit_writer_write(conv->bit_writer, out, conv->rate); 45 | } 46 | 47 | // now flush the shiftregister 48 | // this is simply running the loop as above but without any new inputs 49 | // or rather, the new input string is all 0s 50 | for (size_t i = 0; i < conv->order + 1; i++) { 51 | shiftregister <<= 1; 52 | shiftregister &= shiftmask; 53 | unsigned int out = conv->table[shiftregister]; 54 | bit_writer_write(conv->bit_writer, out, conv->rate); 55 | } 56 | 57 | // 0-fill any remaining bits on our final byte 58 | bit_writer_flush_byte(conv->bit_writer); 59 | 60 | return encoded_len_bits; 61 | } 62 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/error_buffer.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/error_buffer.h" 2 | 3 | error_buffer_t *error_buffer_create(unsigned int num_states) { 4 | error_buffer_t *buf = calloc(1, sizeof(error_buffer_t)); 5 | 6 | // how large are the error buffers? 7 | buf->num_states = num_states; 8 | 9 | // save two error metrics, one for last round and one for this 10 | // (double buffer) 11 | // the error metric is the aggregated number of bit errors found 12 | // at a given path which terminates at a particular shift register state 13 | buf->errors[0] = calloc(sizeof(distance_t), num_states); 14 | buf->errors[1] = calloc(sizeof(distance_t), num_states); 15 | 16 | // which buffer are we using, 0 or 1? 17 | buf->index = 0; 18 | 19 | buf->read_errors = buf->errors[0]; 20 | buf->write_errors = buf->errors[1]; 21 | 22 | return buf; 23 | } 24 | 25 | void error_buffer_destroy(error_buffer_t *buf) { 26 | free(buf->errors[0]); 27 | free(buf->errors[1]); 28 | free(buf); 29 | } 30 | 31 | void error_buffer_reset(error_buffer_t *buf) { 32 | memset(buf->errors[0], 0, buf->num_states * sizeof(distance_t)); 33 | memset(buf->errors[1], 0, buf->num_states * sizeof(distance_t)); 34 | buf->index = 0; 35 | buf->read_errors = buf->errors[0]; 36 | buf->write_errors = buf->errors[1]; 37 | } 38 | 39 | void error_buffer_swap(error_buffer_t *buf) { 40 | buf->read_errors = buf->errors[buf->index]; 41 | buf->index = (buf->index + 1) % 2; 42 | buf->write_errors = buf->errors[buf->index]; 43 | } 44 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/lookup.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/lookup.h" 2 | 3 | // table has numstates rows 4 | // each row contains all of the polynomial output bits concatenated together 5 | // e.g. for rate 2, we have 2 bits in each row 6 | // the first poly gets the LEAST significant bit, last poly gets most significant 7 | void fill_table(unsigned int rate, 8 | unsigned int order, 9 | const polynomial_t *poly, 10 | unsigned int *table) { 11 | for (shift_register_t i = 0; i < 1 << order; i++) { 12 | unsigned int out = 0; 13 | unsigned int mask = 1; 14 | for (size_t j = 0; j < rate; j++) { 15 | out |= (popcount(i & poly[j]) % 2) ? mask : 0; 16 | mask <<= 1; 17 | } 18 | table[i] = out; 19 | } 20 | } 21 | 22 | pair_lookup_t pair_lookup_create(unsigned int rate, 23 | unsigned int order, 24 | const unsigned int *table) { 25 | pair_lookup_t pairs; 26 | 27 | pairs.keys = malloc(sizeof(unsigned int) * (1 << (order - 1))); 28 | pairs.outputs = calloc((1 << (rate * 2)), sizeof(unsigned int)); 29 | unsigned int *inv_outputs = calloc((1 << (rate * 2)), sizeof(unsigned int)); 30 | unsigned int output_counter = 1; 31 | // for every (even-numbered) shift register state, find the concatenated output of the state 32 | // and the subsequent state that follows it (low bit set). then, check to see if this 33 | // concatenated output has a unique key assigned to it already. if not, give it a key. 34 | // if it does, retrieve the key. assign this key to the shift register state. 35 | for (unsigned int i = 0; i < (1 << (order - 1)); i++) { 36 | // first get the concatenated pair of outputs 37 | unsigned int out = table[i * 2 + 1]; 38 | out <<= rate; 39 | out |= table[i * 2]; 40 | 41 | // does this concatenated output exist in the outputs table yet? 42 | if (!inv_outputs[out]) { 43 | // doesn't exist, allocate a new key 44 | inv_outputs[out] = output_counter; 45 | pairs.outputs[output_counter] = out; 46 | output_counter++; 47 | } 48 | // set the opaque key for the ith shift register state to the concatenated output entry 49 | pairs.keys[i] = inv_outputs[out]; 50 | } 51 | pairs.outputs_len = output_counter; 52 | pairs.output_mask = (1 << (rate)) - 1; 53 | pairs.output_width = rate; 54 | pairs.distances = calloc(pairs.outputs_len, sizeof(distance_pair_t)); 55 | free(inv_outputs); 56 | return pairs; 57 | } 58 | 59 | void pair_lookup_destroy(pair_lookup_t pairs) { 60 | free(pairs.keys); 61 | free(pairs.outputs); 62 | free(pairs.distances); 63 | } 64 | 65 | void pair_lookup_fill_distance(pair_lookup_t pairs, distance_t *distances) { 66 | for (unsigned int i = 1; i < pairs.outputs_len; i += 1) { 67 | output_pair_t concat_out = pairs.outputs[i]; 68 | unsigned int i_0 = concat_out & pairs.output_mask; 69 | concat_out >>= pairs.output_width; 70 | unsigned int i_1 = concat_out; 71 | 72 | pairs.distances[i] = (distances[i_1] << 16) | distances[i_0]; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/metric.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/metric.h" 2 | 3 | // measure the square of the euclidean distance between x and y 4 | // since euclidean dist is sqrt(a^2 + b^2 + ... + n^2), the square is just 5 | // a^2 + b^2 + ... + n^2 6 | distance_t metric_soft_distance_quadratic(unsigned int hard_x, const uint8_t *soft_y, size_t len) { 7 | distance_t dist = 0; 8 | for (unsigned int i = 0; i < len; i++) { 9 | // first, convert hard_x to a soft measurement (0 -> 0, 1 - > 255) 10 | unsigned int soft_x = (hard_x & 1) ? 255 : 0; 11 | hard_x >>= 1; 12 | int d = soft_y[i] - soft_x; 13 | dist += d*d; 14 | } 15 | return dist >> 3; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/sse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRCFILES lookup.c convolutional.c encode.c decode.c) 2 | add_library(correct-convolutional-sse OBJECT ${SRCFILES}) 3 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/sse/convolutional.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/sse/convolutional.h" 2 | 3 | correct_convolutional_sse *correct_convolutional_sse_create(size_t rate, 4 | size_t order, 5 | const polynomial_t *poly) { 6 | correct_convolutional_sse *conv = malloc(sizeof(correct_convolutional_sse)); 7 | correct_convolutional *init_conv = _correct_convolutional_init(&conv->base_conv, rate, order, poly); 8 | if (!init_conv) { 9 | free(conv); 10 | conv = NULL; 11 | } 12 | return conv; 13 | } 14 | 15 | void correct_convolutional_sse_destroy(correct_convolutional_sse *conv) { 16 | if (conv->base_conv.has_init_decode) { 17 | oct_lookup_destroy(conv->oct_lookup); 18 | } 19 | _correct_convolutional_teardown(&conv->base_conv); 20 | free(conv); 21 | } 22 | -------------------------------------------------------------------------------- /src/libcorrect/convolutional/sse/encode.c: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/sse/convolutional.h" 2 | 3 | size_t correct_convolutional_sse_encode_len(correct_convolutional_sse *conv, size_t msg_len) { 4 | return correct_convolutional_encode_len(&conv->base_conv, msg_len); 5 | } 6 | 7 | size_t correct_convolutional_sse_encode(correct_convolutional_sse *conv, const uint8_t *msg, size_t msg_len, uint8_t *encoded) { 8 | return correct_convolutional_encode(&conv->base_conv, msg, msg_len, encoded); 9 | } 10 | -------------------------------------------------------------------------------- /src/libcorrect/correct-sse.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_SSE_H 2 | #define CORRECT_SSE_H 3 | #include 4 | 5 | struct correct_convolutional_sse; 6 | typedef struct correct_convolutional_sse correct_convolutional_sse; 7 | 8 | /* SSE versions of libcorrect's convolutional encoder/decoder. 9 | * These instances should not be used with the non-sse functions, 10 | * and non-sse instances should not be used with the sse functions. 11 | */ 12 | 13 | correct_convolutional_sse *correct_convolutional_sse_create( 14 | size_t rate, size_t order, const correct_convolutional_polynomial_t *poly); 15 | 16 | void correct_convolutional_sse_destroy(correct_convolutional_sse *conv); 17 | 18 | size_t correct_convolutional_sse_encode_len(correct_convolutional_sse *conv, size_t msg_len); 19 | 20 | size_t correct_convolutional_sse_encode(correct_convolutional_sse *conv, const uint8_t *msg, 21 | size_t msg_len, uint8_t *encoded); 22 | 23 | ssize_t correct_convolutional_sse_decode(correct_convolutional_sse *conv, const uint8_t *encoded, 24 | size_t num_encoded_bits, uint8_t *msg); 25 | 26 | ssize_t correct_convolutional_sse_decode_soft(correct_convolutional_sse *conv, 27 | const correct_convolutional_soft_t *encoded, 28 | size_t num_encoded_bits, uint8_t *msg); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_CONVOLUTIONAL 2 | #define CORRECT_CONVOLUTIONAL 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "correct.h" 13 | #include "correct/portable.h" 14 | 15 | typedef unsigned int shift_register_t; 16 | typedef uint16_t polynomial_t; 17 | typedef uint64_t path_t; 18 | typedef uint8_t soft_t; 19 | static const soft_t soft_max = UINT8_MAX; 20 | 21 | typedef uint16_t distance_t; 22 | static const distance_t distance_max = UINT16_MAX; 23 | 24 | typedef enum { 25 | CORRECT_SOFT_LINEAR, 26 | CORRECT_SOFT_QUADRATIC, 27 | } soft_measurement_t; 28 | #endif 29 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/bit.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_CONVOLUTIONAL_BIT 2 | #define CORRECT_CONVOLUTIONAL_BIT 3 | #include "correct/convolutional.h" 4 | 5 | typedef struct { 6 | uint8_t current_byte; 7 | unsigned int current_byte_len; 8 | uint8_t *bytes; 9 | size_t byte_index; 10 | size_t len; 11 | } bit_writer_t; 12 | 13 | bit_writer_t *bit_writer_create(uint8_t *bytes, size_t len); 14 | 15 | void bit_writer_reconfigure(bit_writer_t *w, uint8_t *bytes, size_t len); 16 | 17 | void bit_writer_destroy(bit_writer_t *w); 18 | 19 | void bit_writer_write(bit_writer_t *w, uint8_t val, unsigned int n); 20 | 21 | void bit_writer_write_1(bit_writer_t *w, uint8_t val); 22 | 23 | void bit_writer_write_bitlist_reversed(bit_writer_t *w, uint8_t *l, size_t len); 24 | 25 | void bit_writer_flush_byte(bit_writer_t *w); 26 | 27 | size_t bit_writer_length(bit_writer_t *w); 28 | 29 | typedef struct { 30 | uint8_t current_byte; 31 | size_t byte_index; 32 | size_t len; 33 | size_t current_byte_len; 34 | const uint8_t *bytes; 35 | } bit_reader_t; 36 | 37 | bit_reader_t *bit_reader_create(const uint8_t *bytes, size_t len); 38 | 39 | void bit_reader_reconfigure(bit_reader_t *r, const uint8_t *bytes, size_t len); 40 | 41 | void bit_reader_destroy(bit_reader_t *r); 42 | 43 | uint8_t bit_reader_read(bit_reader_t *r, unsigned int n); 44 | #endif 45 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/convolutional.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_CONVOLUTIONAL_H 2 | #define CORRECT_CONVOLUTIONAL_H 3 | #include "correct/convolutional.h" 4 | #include "correct/convolutional/bit.h" 5 | #include "correct/convolutional/metric.h" 6 | #include "correct/convolutional/lookup.h" 7 | #include "correct/convolutional/history_buffer.h" 8 | #include "correct/convolutional/error_buffer.h" 9 | 10 | struct correct_convolutional { 11 | const unsigned int *table; // size 2**order 12 | size_t rate; // e.g. 2, 3... 13 | size_t order; // e.g. 7, 9... 14 | unsigned int numstates; // 2**order 15 | bit_writer_t *bit_writer; 16 | bit_reader_t *bit_reader; 17 | 18 | bool has_init_decode; 19 | distance_t *distances; 20 | pair_lookup_t pair_lookup; 21 | soft_measurement_t soft_measurement; 22 | history_buffer *history_buffer; 23 | error_buffer_t *errors; 24 | }; 25 | 26 | correct_convolutional *_correct_convolutional_init(correct_convolutional *conv, 27 | size_t rate, size_t order, 28 | const polynomial_t *poly); 29 | void _correct_convolutional_teardown(correct_convolutional *conv); 30 | 31 | // portable versions 32 | void _convolutional_decode_init(correct_convolutional *conv, unsigned int min_traceback, unsigned int traceback_length, unsigned int renormalize_interval); 33 | void convolutional_decode_warmup(correct_convolutional *conv, unsigned int sets, 34 | const uint8_t *soft); 35 | void convolutional_decode_inner(correct_convolutional *conv, unsigned int sets, 36 | const uint8_t *soft); 37 | void convolutional_decode_tail(correct_convolutional *conv, unsigned int sets, 38 | const uint8_t *soft); 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/error_buffer.h: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional.h" 2 | 3 | typedef struct { 4 | unsigned int index; 5 | distance_t *errors[2]; 6 | unsigned int num_states; 7 | 8 | const distance_t *read_errors; 9 | distance_t *write_errors; 10 | } error_buffer_t; 11 | 12 | error_buffer_t *error_buffer_create(unsigned int num_states); 13 | void error_buffer_destroy(error_buffer_t *buf); 14 | void error_buffer_reset(error_buffer_t *buf); 15 | void error_buffer_swap(error_buffer_t *buf); 16 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/history_buffer.h: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional.h" 2 | #include "correct/convolutional/bit.h" 3 | 4 | // ring buffer of path histories 5 | // generates output bits after accumulating sufficient history 6 | typedef struct { 7 | // history entries must be at least this old to be decoded 8 | const unsigned int min_traceback_length; 9 | // we'll decode entries in bursts. this tells us the length of the burst 10 | const unsigned int traceback_group_length; 11 | // we will store a total of cap entries. equal to min_traceback_length + 12 | // traceback_group_length 13 | const unsigned int cap; 14 | 15 | // how many states in the shift register? this is one of the dimensions of 16 | // history table 17 | const unsigned int num_states; 18 | // what's the high order bit of the shift register? 19 | const shift_register_t highbit; 20 | 21 | // history is a compact history representation for every shift register 22 | // state, 23 | // one bit per time slice 24 | uint8_t **history; 25 | 26 | // which slice are we writing next? 27 | unsigned int index; 28 | 29 | // how many valid entries are there? 30 | unsigned int len; 31 | 32 | // temporary store of fetched bits 33 | uint8_t *fetched; 34 | 35 | // how often should we renormalize? 36 | unsigned int renormalize_interval; 37 | unsigned int renormalize_counter; 38 | } history_buffer; 39 | 40 | history_buffer *history_buffer_create(unsigned int min_traceback_length, 41 | unsigned int traceback_group_length, 42 | unsigned int renormalize_interval, 43 | unsigned int num_states, 44 | shift_register_t highbit); 45 | void history_buffer_destroy(history_buffer *buf); 46 | void history_buffer_reset(history_buffer *buf); 47 | void history_buffer_step(history_buffer *buf); 48 | uint8_t *history_buffer_get_slice(history_buffer *buf); 49 | shift_register_t history_buffer_search(history_buffer *buf, 50 | const distance_t *distances, 51 | unsigned int search_every); 52 | void history_buffer_traceback(history_buffer *buf, shift_register_t bestpath, 53 | unsigned int min_traceback_length, 54 | bit_writer_t *output); 55 | void history_buffer_process_skip(history_buffer *buf, distance_t *distances, 56 | bit_writer_t *output, unsigned int skip); 57 | void history_buffer_process(history_buffer *buf, distance_t *distances, 58 | bit_writer_t *output); 59 | void history_buffer_flush(history_buffer *buf, bit_writer_t *output); 60 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/lookup.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_CONVOLUTIONAL_LOOKUP 2 | #define CORRECT_CONVOLUTIONAL_LOOKUP 3 | #include "correct/convolutional.h" 4 | 5 | typedef unsigned int distance_pair_key_t; 6 | typedef uint32_t output_pair_t; 7 | typedef uint32_t distance_pair_t; 8 | 9 | typedef struct { 10 | distance_pair_key_t *keys; 11 | output_pair_t *outputs; 12 | output_pair_t output_mask; 13 | unsigned int output_width; 14 | size_t outputs_len; 15 | distance_pair_t *distances; 16 | } pair_lookup_t; 17 | 18 | void fill_table(unsigned int order, 19 | unsigned int rate, 20 | const polynomial_t *poly, 21 | unsigned int *table); 22 | pair_lookup_t pair_lookup_create(unsigned int rate, 23 | unsigned int order, 24 | const unsigned int *table); 25 | void pair_lookup_destroy(pair_lookup_t pairs); 26 | void pair_lookup_fill_distance(pair_lookup_t pairs, distance_t *distances); 27 | #endif 28 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/metric.h: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional.h" 2 | 3 | // measure the hamming distance of two bit strings 4 | // implemented as population count of x XOR y 5 | static inline distance_t metric_distance(unsigned int x, unsigned int y) { 6 | return popcount(x ^ y); 7 | } 8 | 9 | static inline distance_t metric_soft_distance_linear(unsigned int hard_x, const uint8_t *soft_y, size_t len) { 10 | distance_t dist = 0; 11 | for (unsigned int i = 0; i < len; i++) { 12 | unsigned int soft_x = ((int8_t)(0) - (hard_x & 1)) & 0xff; 13 | hard_x >>= 1; 14 | int d = soft_y[i] - soft_x; 15 | dist += (d < 0) ? -d : d; 16 | } 17 | return dist; 18 | } 19 | 20 | distance_t metric_soft_distance_quadratic(unsigned int hard_x, const uint8_t *soft_y, size_t len); 21 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/sse/convolutional.h: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/convolutional.h" 2 | #include "correct/convolutional/sse/lookup.h" 3 | // BIG HEAPING TODO sort out the include mess 4 | #include "correct-sse.h" 5 | #ifdef _MSC_VER 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | 12 | struct correct_convolutional_sse { 13 | correct_convolutional base_conv; 14 | oct_lookup_t oct_lookup; 15 | }; 16 | -------------------------------------------------------------------------------- /src/libcorrect/correct/convolutional/sse/lookup.h: -------------------------------------------------------------------------------- 1 | #include "correct/convolutional/lookup.h" 2 | #ifdef _MSC_VER 3 | #include 4 | #else 5 | #include 6 | #endif 7 | 8 | typedef unsigned int distance_quad_key_t; 9 | typedef unsigned int output_quad_t; 10 | typedef uint64_t distance_quad_t; 11 | 12 | typedef struct { 13 | distance_quad_key_t *keys; 14 | output_quad_t *outputs; 15 | output_quad_t output_mask; 16 | unsigned int output_width; 17 | size_t outputs_len; 18 | distance_quad_t *distances; 19 | } quad_lookup_t; 20 | 21 | typedef uint16_t distance_oct_key_t; 22 | typedef uint64_t output_oct_t; 23 | typedef uint64_t distance_oct_t; 24 | 25 | typedef struct { 26 | distance_oct_key_t *keys; 27 | output_oct_t *outputs; 28 | output_oct_t output_mask; 29 | unsigned int output_width; 30 | size_t outputs_len; 31 | distance_oct_t *distances; 32 | } oct_lookup_t; 33 | 34 | quad_lookup_t quad_lookup_create(unsigned int rate, 35 | unsigned int order, 36 | const unsigned int *table); 37 | void quad_lookup_destroy(quad_lookup_t quads); 38 | void quad_lookup_fill_distance(quad_lookup_t quads, distance_t *distances); 39 | distance_oct_key_t oct_lookup_find_key(output_oct_t *outputs, output_oct_t out, size_t num_keys); 40 | oct_lookup_t oct_lookup_create(unsigned int rate, 41 | unsigned int order, 42 | const unsigned int *table); 43 | void oct_lookup_destroy(oct_lookup_t octs); 44 | static inline void oct_lookup_fill_distance(oct_lookup_t octs, distance_t *distances) { 45 | distance_pair_t *pairs = (distance_pair_t*)octs.distances; 46 | for (unsigned int i = 1; i < octs.outputs_len; i += 1) { 47 | output_oct_t concat_out = octs.outputs[i]; 48 | unsigned int i_0 = concat_out & 0xff; 49 | unsigned int i_1 = (concat_out >> 8) & 0xff; 50 | unsigned int i_2 = (concat_out >> 16) & 0xff; 51 | unsigned int i_3 = (concat_out >> 24) & 0xff; 52 | 53 | pairs[i*4 + 1] = distances[i_3] << 16 | distances[i_2]; 54 | pairs[i*4 + 0] = distances[i_1] << 16 | distances[i_0]; 55 | 56 | concat_out >>= 32; 57 | unsigned int i_4 = concat_out & 0xff; 58 | unsigned int i_5 = (concat_out >> 8) & 0xff; 59 | unsigned int i_6 = (concat_out >> 16) & 0xff; 60 | unsigned int i_7 = (concat_out >> 24) & 0xff; 61 | 62 | pairs[i*4 + 3] = distances[i_7] << 16 | distances[i_6]; 63 | pairs[i*4 + 2] = distances[i_5] << 16 | distances[i_4]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/libcorrect/correct/portable.h: -------------------------------------------------------------------------------- 1 | #ifdef __GNUC__ 2 | #define HAVE_BUILTINS 3 | #endif 4 | 5 | 6 | #ifdef HAVE_BUILTINS 7 | #define popcount __builtin_popcount 8 | #define prefetch __builtin_prefetch 9 | #else 10 | 11 | static inline int popcount(int x) { 12 | /* taken from the helpful http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel */ 13 | x = x - ((x >> 1) & 0x55555555); 14 | x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 15 | return ((x + (x >> 4) & 0x0f0f0f0f) * 0x01010101) >> 24; 16 | } 17 | 18 | static inline void prefetch(void *x) {} 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/libcorrect/correct/reed-solomon.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_REED_SOLOMON 2 | #define CORRECT_REED_SOLOMON 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "correct.h" 11 | #include "correct/portable.h" 12 | 13 | // an element in GF(2^8) 14 | typedef uint8_t field_element_t; 15 | 16 | // a power of the primitive element alpha 17 | typedef uint8_t field_logarithm_t; 18 | 19 | // give us some bits of headroom to do arithmetic 20 | // variables of this type aren't really in any proper space 21 | typedef uint16_t field_operation_t; 22 | 23 | // generated by find_poly 24 | typedef struct { 25 | const field_element_t *exp; 26 | const field_logarithm_t *log; 27 | } field_t; 28 | 29 | typedef struct { 30 | field_element_t *coeff; 31 | unsigned int order; 32 | } polynomial_t; 33 | 34 | struct correct_reed_solomon { 35 | size_t block_length; 36 | size_t message_length; 37 | size_t min_distance; 38 | 39 | field_logarithm_t first_consecutive_root; 40 | field_logarithm_t generator_root_gap; 41 | 42 | field_t field; 43 | 44 | polynomial_t generator; 45 | field_element_t *generator_roots; 46 | field_logarithm_t **generator_root_exp; 47 | 48 | polynomial_t encoded_polynomial; 49 | polynomial_t encoded_remainder; 50 | 51 | field_element_t *syndromes; 52 | field_element_t *modified_syndromes; 53 | polynomial_t received_polynomial; 54 | polynomial_t error_locator; 55 | polynomial_t error_locator_log; 56 | polynomial_t erasure_locator; 57 | field_element_t *error_roots; 58 | field_element_t *error_vals; 59 | field_logarithm_t *error_locations; 60 | 61 | field_logarithm_t **element_exp; 62 | 63 | // scratch 64 | // (do no allocations at steady state) 65 | 66 | // used during find_error_locator 67 | polynomial_t last_error_locator; 68 | 69 | // used during error value search 70 | polynomial_t error_evaluator; 71 | polynomial_t error_locator_derivative; 72 | polynomial_t init_from_roots_scratch[2]; 73 | bool has_init_decode; 74 | 75 | }; 76 | #endif 77 | -------------------------------------------------------------------------------- /src/libcorrect/correct/reed-solomon/decode.h: -------------------------------------------------------------------------------- 1 | #include "correct/reed-solomon.h" 2 | #include "correct/reed-solomon/field.h" 3 | #include "correct/reed-solomon/polynomial.h" 4 | -------------------------------------------------------------------------------- /src/libcorrect/correct/reed-solomon/encode.h: -------------------------------------------------------------------------------- 1 | #include "correct/reed-solomon.h" 2 | #include "correct/reed-solomon/field.h" 3 | #include "correct/reed-solomon/polynomial.h" 4 | -------------------------------------------------------------------------------- /src/libcorrect/correct/reed-solomon/polynomial.h: -------------------------------------------------------------------------------- 1 | #include "correct/reed-solomon.h" 2 | #include "correct/reed-solomon/field.h" 3 | 4 | polynomial_t polynomial_create(unsigned int order); 5 | void polynomial_destroy(polynomial_t polynomial); 6 | void polynomial_mul(field_t field, polynomial_t l, polynomial_t r, polynomial_t res); 7 | void polynomial_mod(field_t field, polynomial_t dividend, polynomial_t divisor, polynomial_t mod); 8 | void polynomial_formal_derivative(field_t field, polynomial_t poly, polynomial_t der); 9 | field_element_t polynomial_eval(field_t field, polynomial_t poly, field_element_t val); 10 | field_element_t polynomial_eval_lut(field_t field, polynomial_t poly, const field_logarithm_t *val_exp); 11 | field_element_t polynomial_eval_log_lut(field_t field, polynomial_t poly_log, const field_logarithm_t *val_exp); 12 | void polynomial_build_exp_lut(field_t field, field_element_t val, unsigned int order, field_logarithm_t *val_exp); 13 | polynomial_t polynomial_init_from_roots(field_t field, unsigned int nroots, field_element_t *roots, polynomial_t poly, polynomial_t *scratch); 14 | polynomial_t polynomial_create_from_roots(field_t field, unsigned int nroots, field_element_t *roots); 15 | -------------------------------------------------------------------------------- /src/libcorrect/correct/reed-solomon/reed-solomon.h: -------------------------------------------------------------------------------- 1 | #include "correct/reed-solomon.h" 2 | #include "correct/reed-solomon/field.h" 3 | #include "correct/reed-solomon/polynomial.h" 4 | -------------------------------------------------------------------------------- /src/libcorrect/correct/util/error-sim-fec.h: -------------------------------------------------------------------------------- 1 | #include "correct/util/error-sim.h" 2 | 3 | #include 4 | 5 | void conv_fec27_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 6 | void conv_fec29_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 7 | void conv_fec39_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 8 | void conv_fec615_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 9 | -------------------------------------------------------------------------------- /src/libcorrect/correct/util/error-sim-shim.h: -------------------------------------------------------------------------------- 1 | #include "correct/util/error-sim.h" 2 | #include "fec_shim.h" 3 | 4 | ssize_t conv_shim27_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 5 | ssize_t conv_shim29_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 6 | ssize_t conv_shim39_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 7 | ssize_t conv_shim615_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 8 | -------------------------------------------------------------------------------- /src/libcorrect/correct/util/error-sim-sse.h: -------------------------------------------------------------------------------- 1 | #include "correct/util/error-sim.h" 2 | 3 | #include "correct-sse.h" 4 | 5 | size_t conv_correct_sse_enclen(void *conv_v, size_t msg_len); 6 | void conv_correct_sse_encode(void *conv_v, uint8_t *msg, size_t msg_len, uint8_t *encoded); 7 | ssize_t conv_correct_sse_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 8 | -------------------------------------------------------------------------------- /src/libcorrect/correct/util/error-sim.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "correct.h" 9 | #include "correct/portable.h" 10 | 11 | size_t distance(uint8_t *a, uint8_t *b, size_t len); 12 | void gaussian(double *res, size_t n_res, double sigma); 13 | 14 | void encode_bpsk(uint8_t *msg, double *voltages, size_t n_syms, double bpsk_voltage); 15 | void byte2bit(uint8_t *bytes, uint8_t *bits, size_t n_bits); 16 | void decode_bpsk(uint8_t *soft, uint8_t *msg, size_t n_syms); 17 | void decode_bpsk_soft(double *voltages, uint8_t *soft, size_t n_syms, double bpsk_voltage); 18 | double log2amp(double l); 19 | double amp2log(double a); 20 | double sigma_for_eb_n0(double eb_n0, double bpsk_bit_energy); 21 | void build_white_noise(double *noise, size_t n_syms, double eb_n0, double bpsk_bit_energy); 22 | void add_white_noise(double *signal, double *noise, size_t n_syms); 23 | 24 | typedef struct { 25 | uint8_t *msg_out; 26 | size_t msg_len; 27 | uint8_t *encoded; 28 | double *v; 29 | double *corrupted; 30 | uint8_t *soft; 31 | double *noise; 32 | size_t enclen; 33 | size_t enclen_bytes; 34 | void (*encode)(void *, uint8_t *msg, size_t msg_len, uint8_t *encoded); 35 | void *encoder; 36 | ssize_t (*decode)(void *, uint8_t *soft, size_t soft_len, uint8_t *msg); 37 | void *decoder; 38 | } conv_testbench; 39 | 40 | conv_testbench *resize_conv_testbench(conv_testbench *scratch, size_t (*enclen)(void *, size_t), void *enc, size_t msg_len); 41 | void free_scratch(conv_testbench *scratch); 42 | int test_conv_noise(conv_testbench *scratch, uint8_t *msg, size_t n_bytes, 43 | double bpsk_voltage); 44 | 45 | size_t conv_correct_enclen(void *conv_v, size_t msg_len); 46 | void conv_correct_encode(void *conv_v, uint8_t *msg, size_t msg_len, uint8_t *encoded); 47 | ssize_t conv_correct_decode(void *conv_v, uint8_t *soft, size_t soft_len, uint8_t *msg); 48 | -------------------------------------------------------------------------------- /src/libcorrect/fec_shim.h: -------------------------------------------------------------------------------- 1 | #ifndef CORRECT_FEC_H 2 | #define CORRECT_FEC_H 3 | // libcorrect's libfec shim header 4 | // this is a partial implementation of libfec 5 | // header signatures derived from found usages of libfec -- some things may be different 6 | #include 7 | 8 | // Reed-Solomon 9 | void *init_rs_char(int symbol_size, int primitive_polynomial, int first_consecutive_root, 10 | int root_gap, int number_roots, unsigned int pad); 11 | void free_rs_char(void *rs); 12 | void encode_rs_char(void *rs, const unsigned char *msg, unsigned char *parity); 13 | void decode_rs_char(void *rs, unsigned char *block, int *erasure_locations, int num_erasures); 14 | 15 | // Convolutional Codes 16 | 17 | // Polynomials 18 | // These have been determined via find_conv_libfec_poly.c 19 | // We could just make up new ones, but we use libfec's here so that 20 | // codes encoded by this library can be decoded by the original libfec 21 | // and vice-versa 22 | #define V27POLYA 0155 23 | #define V27POLYB 0117 24 | 25 | #define V29POLYA 0657 26 | #define V29POLYB 0435 27 | 28 | #define V39POLYA 0755 29 | #define V39POLYB 0633 30 | #define V39POLYC 0447 31 | 32 | #define V615POLYA 042631 33 | #define V615POLYB 047245 34 | #define V615POLYC 056507 35 | #define V615POLYD 073363 36 | #define V615POLYE 077267 37 | #define V615POLYF 064537 38 | 39 | // Convolutional Methods 40 | void *create_viterbi27(int num_decoded_bits); 41 | int init_viterbi27(void *vit, int _mystery); 42 | int update_viterbi27_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups); 43 | int chainback_viterbi27(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery); 44 | void delete_viterbi27(void *vit); 45 | 46 | void *create_viterbi29(int num_decoded_bits); 47 | int init_viterbi29(void *vit, int _mystery); 48 | int update_viterbi29_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups); 49 | int chainback_viterbi29(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery); 50 | void delete_viterbi29(void *vit); 51 | 52 | void *create_viterbi39(int num_decoded_bits); 53 | int init_viterbi39(void *vit, int _mystery); 54 | int update_viterbi39_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups); 55 | int chainback_viterbi39(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery); 56 | void delete_viterbi39(void *vit); 57 | 58 | void *create_viterbi615(int num_decoded_bits); 59 | int init_viterbi615(void *vit, int _mystery); 60 | int update_viterbi615_blk(void *vit, unsigned char *encoded_soft, int n_encoded_groups); 61 | int chainback_viterbi615(void *vit, unsigned char *decoded, unsigned int n_decoded_bits, unsigned int _mystery); 62 | void delete_viterbi615(void *vit); 63 | 64 | // Misc other 65 | static inline int parity(unsigned int x) { 66 | /* http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel */ 67 | x ^= x >> 16; 68 | x ^= x >> 8; 69 | x ^= x >> 4; 70 | x &= 0xf; 71 | return (0x6996 >> x) & 1; 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/libcorrect/reed-solomon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRCFILES polynomial.c reed-solomon.c encode.c decode.c) 2 | add_library(correct-reed-solomon OBJECT ${SRCFILES}) 3 | -------------------------------------------------------------------------------- /src/libcorrect/reed-solomon/encode.c: -------------------------------------------------------------------------------- 1 | #include "correct/reed-solomon/encode.h" 2 | 3 | ssize_t correct_reed_solomon_encode(correct_reed_solomon *rs, const uint8_t *msg, size_t msg_length, uint8_t *encoded) { 4 | if (msg_length > rs->message_length) { 5 | return -1; 6 | } 7 | 8 | size_t pad_length = rs->message_length - msg_length; 9 | for (unsigned int i = 0; i < msg_length; i++) { 10 | // message goes from high order to low order but libcorrect polynomials go low to high 11 | // so we reverse on the way in and on the way out 12 | // we'd have to do a copy anyway so this reversal should be free 13 | rs->encoded_polynomial.coeff[rs->encoded_polynomial.order - (i + pad_length)] = msg[i]; 14 | } 15 | 16 | // 0-fill the rest of the coefficients -- this length will always be > 0 17 | // because the order of this poly is block_length and the msg_length <= message_length 18 | // e.g. 255 and 223 19 | memset(rs->encoded_polynomial.coeff + (rs->encoded_polynomial.order + 1 - pad_length), 0, pad_length); 20 | memset(rs->encoded_polynomial.coeff, 0, (rs->encoded_polynomial.order + 1 - rs->message_length)); 21 | 22 | polynomial_mod(rs->field, rs->encoded_polynomial, rs->generator, rs->encoded_remainder); 23 | 24 | // now return byte order to highest order to lowest order 25 | for (unsigned int i = 0; i < msg_length; i++) { 26 | encoded[i] = rs->encoded_polynomial.coeff[rs->encoded_polynomial.order - (i + pad_length)]; 27 | } 28 | 29 | for (unsigned int i = 0; i < rs->min_distance; i++) { 30 | encoded[msg_length + i] = rs->encoded_remainder.coeff[rs->min_distance - (i + 1)]; 31 | } 32 | 33 | return rs->block_length; 34 | } 35 | -------------------------------------------------------------------------------- /src/spdlog/async.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // 7 | // Async logging using global thread pool 8 | // All loggers created here share same global thread pool. 9 | // Each log message is pushed to a queue along with a shared pointer to the 10 | // logger. 11 | // If a logger deleted while having pending messages in the queue, it's actual 12 | // destruction will defer 13 | // until all its messages are processed by the thread pool. 14 | // This is because each message in the queue holds a shared_ptr to the 15 | // originating logger. 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace spdlog { 26 | 27 | namespace details { 28 | static const size_t default_async_q_size = 8192; 29 | } 30 | 31 | // async logger factory - creates async loggers backed with thread pool. 32 | // if a global thread pool doesn't already exist, create it with default queue 33 | // size of 8192 items and single thread. 34 | template 35 | struct async_factory_impl 36 | { 37 | template 38 | static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) 39 | { 40 | auto ®istry_inst = details::registry::instance(); 41 | 42 | // create global thread pool if not already exists.. 43 | 44 | auto &mutex = registry_inst.tp_mutex(); 45 | std::lock_guard tp_lock(mutex); 46 | auto tp = registry_inst.get_tp(); 47 | if (tp == nullptr) 48 | { 49 | tp = std::make_shared(details::default_async_q_size, 1); 50 | registry_inst.set_tp(tp); 51 | } 52 | 53 | auto sink = std::make_shared(std::forward(args)...); 54 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); 55 | registry_inst.initialize_logger(new_logger); 56 | return new_logger; 57 | } 58 | }; 59 | 60 | using async_factory = async_factory_impl; 61 | using async_factory_nonblock = async_factory_impl; 62 | 63 | template 64 | inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&... sink_args) 65 | { 66 | return async_factory::create(std::move(logger_name), std::forward(sink_args)...); 67 | } 68 | 69 | template 70 | inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&... sink_args) 71 | { 72 | return async_factory_nonblock::create(std::move(logger_name), std::forward(sink_args)...); 73 | } 74 | 75 | // set global thread pool. 76 | inline void init_thread_pool(size_t q_size, size_t thread_count, std::function on_thread_start) 77 | { 78 | auto tp = std::make_shared(q_size, thread_count, on_thread_start); 79 | details::registry::instance().set_tp(std::move(tp)); 80 | } 81 | 82 | // set global thread pool. 83 | inline void init_thread_pool(size_t q_size, size_t thread_count) 84 | { 85 | init_thread_pool(q_size, thread_count, [] {}); 86 | } 87 | 88 | // get the global thread pool. 89 | inline std::shared_ptr thread_pool() 90 | { 91 | return details::registry::instance().get_tp(); 92 | } 93 | } // namespace spdlog 94 | -------------------------------------------------------------------------------- /src/spdlog/async_logger-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | SPDLOG_INLINE spdlog::async_logger::async_logger( 17 | std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, async_overflow_policy overflow_policy) 18 | : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) 19 | {} 20 | 21 | SPDLOG_INLINE spdlog::async_logger::async_logger( 22 | std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, async_overflow_policy overflow_policy) 23 | : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) 24 | {} 25 | 26 | // send the log message to the thread pool 27 | SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) 28 | { 29 | if (auto pool_ptr = thread_pool_.lock()) 30 | { 31 | pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); 32 | } 33 | else 34 | { 35 | throw_spdlog_ex("async log: thread pool doesn't exist anymore"); 36 | } 37 | } 38 | 39 | // send flush request to the thread pool 40 | SPDLOG_INLINE void spdlog::async_logger::flush_() 41 | { 42 | if (auto pool_ptr = thread_pool_.lock()) 43 | { 44 | pool_ptr->post_flush(shared_from_this(), overflow_policy_); 45 | } 46 | else 47 | { 48 | throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); 49 | } 50 | } 51 | 52 | // 53 | // backend functions - called from the thread pool to do the actual job 54 | // 55 | SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) 56 | { 57 | for (auto &sink : sinks_) 58 | { 59 | if (sink->should_log(msg.level)) 60 | { 61 | SPDLOG_TRY 62 | { 63 | sink->log(msg); 64 | } 65 | SPDLOG_LOGGER_CATCH() 66 | } 67 | } 68 | 69 | if (should_flush_(msg)) 70 | { 71 | backend_flush_(); 72 | } 73 | } 74 | 75 | SPDLOG_INLINE void spdlog::async_logger::backend_flush_() 76 | { 77 | for (auto &sink : sinks_) 78 | { 79 | SPDLOG_TRY 80 | { 81 | sink->flush(); 82 | } 83 | SPDLOG_LOGGER_CATCH() 84 | } 85 | } 86 | 87 | SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) 88 | { 89 | auto cloned = std::make_shared(*this); 90 | cloned->name_ = std::move(new_name); 91 | return cloned; 92 | } 93 | -------------------------------------------------------------------------------- /src/spdlog/async_logger.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Fast asynchronous logger. 7 | // Uses pre allocated queue. 8 | // Creates a single back thread to pop messages from the queue and log them. 9 | // 10 | // Upon each log write the logger: 11 | // 1. Checks if its log level is enough to log the message 12 | // 2. Push a new copy of the message to a queue (or block the caller until 13 | // space is available in the queue) 14 | // Upon destruction, logs all remaining messages in the queue before 15 | // destructing.. 16 | 17 | #include 18 | 19 | namespace spdlog { 20 | 21 | // Async overflow policy - block by default. 22 | enum class async_overflow_policy 23 | { 24 | block, // Block until message can be enqueued 25 | overrun_oldest // Discard oldest message in the queue if full when trying to 26 | // add new item. 27 | }; 28 | 29 | namespace details { 30 | class thread_pool; 31 | } 32 | 33 | class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger 34 | { 35 | friend class details::thread_pool; 36 | 37 | public: 38 | template 39 | async_logger(std::string logger_name, It begin, It end, std::weak_ptr tp, 40 | async_overflow_policy overflow_policy = async_overflow_policy::block) 41 | : logger(std::move(logger_name), begin, end) 42 | , thread_pool_(std::move(tp)) 43 | , overflow_policy_(overflow_policy) 44 | {} 45 | 46 | async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, 47 | async_overflow_policy overflow_policy = async_overflow_policy::block); 48 | 49 | async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, 50 | async_overflow_policy overflow_policy = async_overflow_policy::block); 51 | 52 | std::shared_ptr clone(std::string new_name) override; 53 | 54 | protected: 55 | void sink_it_(const details::log_msg &msg) override; 56 | void flush_() override; 57 | void backend_sink_it_(const details::log_msg &incoming_log_msg); 58 | void backend_flush_(); 59 | 60 | private: 61 | std::weak_ptr thread_pool_; 62 | async_overflow_policy overflow_policy_; 63 | }; 64 | } // namespace spdlog 65 | 66 | #ifdef SPDLOG_HEADER_ONLY 67 | #include "async_logger-inl.h" 68 | #endif 69 | -------------------------------------------------------------------------------- /src/spdlog/cfg/argv.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | // 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" 10 | // 11 | // set all loggers to debug level: 12 | // example.exe "SPDLOG_LEVEL=debug" 13 | 14 | // set logger1 to trace level 15 | // example.exe "SPDLOG_LEVEL=logger1=trace" 16 | 17 | // turn off all logging except for logger1 and logger2: 18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" 19 | 20 | namespace spdlog { 21 | namespace cfg { 22 | 23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels 24 | void load_argv_levels(int argc, const char **argv) 25 | { 26 | const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; 27 | for (int i = 1; i < argc; i++) 28 | { 29 | std::string arg = argv[i]; 30 | if (arg.find(spdlog_level_prefix) == 0) 31 | { 32 | auto levels_string = arg.substr(spdlog_level_prefix.size()); 33 | auto levels = helpers::extract_levels(levels_string); 34 | details::registry::instance().update_levels(std::move(levels)); 35 | } 36 | } 37 | } 38 | 39 | void load_argv_levels(int argc, char **argv) 40 | { 41 | load_argv_levels(argc, const_cast(argv)); 42 | } 43 | 44 | } // namespace cfg 45 | } // namespace spdlog 46 | -------------------------------------------------------------------------------- /src/spdlog/cfg/env.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Init levels and patterns from env variables SPDLOG_LEVEL 11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). 12 | // Note - fallback to "info" level on unrecognized levels 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: 17 | // export SPDLOG_LEVEL=debug 18 | // 19 | // turn off all logging except for logger1: 20 | // export SPDLOG_LEVEL="off,logger1=debug" 21 | // 22 | 23 | // turn off all logging except for logger1 and logger2: 24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" 25 | 26 | namespace spdlog { 27 | namespace cfg { 28 | void load_env_levels() 29 | { 30 | auto env_val = details::os::getenv("SPDLOG_LEVEL"); 31 | auto levels = helpers::extract_levels(env_val); 32 | details::registry::instance().update_levels(std::move(levels)); 33 | } 34 | 35 | } // namespace cfg 36 | } // namespace spdlog 37 | -------------------------------------------------------------------------------- /src/spdlog/cfg/helpers-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace spdlog { 19 | namespace cfg { 20 | namespace helpers { 21 | 22 | // inplace convert to lowercase 23 | inline std::string &to_lower_(std::string &str) 24 | { 25 | std::transform( 26 | str.begin(), str.end(), str.begin(), [](char ch) { return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); 27 | return str; 28 | } 29 | 30 | // inplace trim spaces 31 | inline std::string &trim_(std::string &str) 32 | { 33 | const char *spaces = " \n\r\t"; 34 | str.erase(str.find_last_not_of(spaces) + 1); 35 | str.erase(0, str.find_first_not_of(spaces)); 36 | return str; 37 | } 38 | 39 | // return (name,value) trimmed pair from given "name=value" string. 40 | // return empty string on missing parts 41 | // "key=val" => ("key", "val") 42 | // " key = val " => ("key", "val") 43 | // "key=" => ("key", "") 44 | // "val" => ("", "val") 45 | 46 | inline std::pair extract_kv_(char sep, const std::string &str) 47 | { 48 | auto n = str.find(sep); 49 | std::string k, v; 50 | if (n == std::string::npos) 51 | { 52 | v = str; 53 | } 54 | else 55 | { 56 | k = str.substr(0, n); 57 | v = str.substr(n + 1); 58 | } 59 | return std::make_pair(trim_(k), trim_(v)); 60 | } 61 | 62 | // return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." 63 | // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} 64 | inline std::unordered_map extract_key_vals_(const std::string &str) 65 | { 66 | std::string token; 67 | std::istringstream token_stream(str); 68 | std::unordered_map rv{}; 69 | while (std::getline(token_stream, token, ',')) 70 | { 71 | if (token.empty()) 72 | { 73 | continue; 74 | } 75 | auto kv = extract_kv_('=', token); 76 | rv[kv.first] = kv.second; 77 | } 78 | return rv; 79 | } 80 | 81 | SPDLOG_INLINE log_levels extract_levels(const std::string &input) 82 | { 83 | auto key_vals = extract_key_vals_(input); 84 | log_levels rv; 85 | 86 | for (auto &name_level : key_vals) 87 | { 88 | auto &logger_name = name_level.first; 89 | auto level_name = to_lower_(name_level.second); 90 | auto level = level::from_str(level_name); 91 | // fallback to "info" if unrecognized level name 92 | if (level == level::off && level_name != "off") 93 | { 94 | level = level::info; 95 | } 96 | rv.set(logger_name, level); 97 | } 98 | return rv; 99 | } 100 | 101 | } // namespace helpers 102 | } // namespace cfg 103 | } // namespace spdlog 104 | -------------------------------------------------------------------------------- /src/spdlog/cfg/helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace cfg { 10 | namespace helpers { 11 | // 12 | // Init levels from given string 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: "debug" 17 | // turn off all logging except for logger1: "off,logger1=debug" 18 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" 19 | // 20 | SPDLOG_API log_levels extract_levels(const std::string &txt); 21 | } // namespace helpers 22 | 23 | } // namespace cfg 24 | } // namespace spdlog 25 | 26 | #ifdef SPDLOG_HEADER_ONLY 27 | #include "helpers-inl.h" 28 | #endif // SPDLOG_HEADER_ONLY 29 | -------------------------------------------------------------------------------- /src/spdlog/cfg/log_levels.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace spdlog { 11 | namespace cfg { 12 | class log_levels 13 | { 14 | std::unordered_map levels_; 15 | spdlog::level::level_enum default_level_ = level::info; 16 | 17 | public: 18 | void set(const std::string &logger_name, level::level_enum lvl) 19 | { 20 | if (logger_name.empty()) 21 | { 22 | default_level_ = lvl; 23 | } 24 | else 25 | { 26 | levels_[logger_name] = lvl; 27 | } 28 | } 29 | 30 | void set_default(level::level_enum lvl) 31 | { 32 | default_level_ = lvl; 33 | } 34 | 35 | level::level_enum get(const std::string &logger_name) 36 | { 37 | auto it = levels_.find(logger_name); 38 | return it != levels_.end() ? it->second : default_level_; 39 | } 40 | 41 | level::level_enum default_level() 42 | { 43 | return default_level_; 44 | } 45 | }; 46 | } // namespace cfg 47 | } // namespace spdlog 48 | -------------------------------------------------------------------------------- /src/spdlog/common-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace level { 12 | static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; 13 | 14 | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; 15 | 16 | SPDLOG_INLINE string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 17 | { 18 | return level_string_views[l]; 19 | } 20 | 21 | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 22 | { 23 | return short_level_names[l]; 24 | } 25 | 26 | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT 27 | { 28 | int level = 0; 29 | for (const auto &level_str : level_string_views) 30 | { 31 | if (level_str == name) 32 | { 33 | return static_cast(level); 34 | } 35 | level++; 36 | } 37 | // check also for "warn" and "err" before giving up.. 38 | if (name == "warn") 39 | { 40 | return level::warn; 41 | } 42 | if (name == "err") 43 | { 44 | return level::err; 45 | } 46 | return level::off; 47 | } 48 | } // namespace level 49 | 50 | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) 51 | : msg_(std::move(msg)) 52 | {} 53 | 54 | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) 55 | { 56 | memory_buf_t outbuf; 57 | fmt::format_system_error(outbuf, last_errno, msg); 58 | msg_ = fmt::to_string(outbuf); 59 | } 60 | 61 | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT 62 | { 63 | return msg_.c_str(); 64 | } 65 | 66 | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) 67 | { 68 | SPDLOG_THROW(spdlog_ex(msg, last_errno)); 69 | } 70 | 71 | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) 72 | { 73 | SPDLOG_THROW(spdlog_ex(std::move(msg))); 74 | } 75 | 76 | } // namespace spdlog 77 | -------------------------------------------------------------------------------- /src/spdlog/details/backtracer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | namespace spdlog { 10 | namespace details { 11 | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) 12 | { 13 | std::lock_guard lock(other.mutex_); 14 | enabled_ = other.enabled(); 15 | messages_ = other.messages_; 16 | } 17 | 18 | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT 19 | { 20 | std::lock_guard lock(other.mutex_); 21 | enabled_ = other.enabled(); 22 | messages_ = std::move(other.messages_); 23 | } 24 | 25 | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) 26 | { 27 | std::lock_guard lock(mutex_); 28 | enabled_ = other.enabled(); 29 | messages_ = std::move(other.messages_); 30 | return *this; 31 | } 32 | 33 | SPDLOG_INLINE void backtracer::enable(size_t size) 34 | { 35 | std::lock_guard lock{mutex_}; 36 | enabled_.store(true, std::memory_order_relaxed); 37 | messages_ = circular_q{size}; 38 | } 39 | 40 | SPDLOG_INLINE void backtracer::disable() 41 | { 42 | std::lock_guard lock{mutex_}; 43 | enabled_.store(false, std::memory_order_relaxed); 44 | } 45 | 46 | SPDLOG_INLINE bool backtracer::enabled() const 47 | { 48 | return enabled_.load(std::memory_order_relaxed); 49 | } 50 | 51 | SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) 52 | { 53 | std::lock_guard lock{mutex_}; 54 | messages_.push_back(log_msg_buffer{msg}); 55 | } 56 | 57 | // pop all items in the q and apply the given fun on each of them. 58 | SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) 59 | { 60 | std::lock_guard lock{mutex_}; 61 | while (!messages_.empty()) 62 | { 63 | auto &front_msg = messages_.front(); 64 | fun(front_msg); 65 | messages_.pop_front(); 66 | } 67 | } 68 | } // namespace details 69 | } // namespace spdlog 70 | -------------------------------------------------------------------------------- /src/spdlog/details/backtracer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // Store log messages in circular buffer. 14 | // Useful for storing debug data in case of error/warning happens. 15 | 16 | namespace spdlog { 17 | namespace details { 18 | class SPDLOG_API backtracer 19 | { 20 | mutable std::mutex mutex_; 21 | std::atomic enabled_{false}; 22 | circular_q messages_; 23 | 24 | public: 25 | backtracer() = default; 26 | backtracer(const backtracer &other); 27 | 28 | backtracer(backtracer &&other) SPDLOG_NOEXCEPT; 29 | backtracer &operator=(backtracer other); 30 | 31 | void enable(size_t size); 32 | void disable(); 33 | bool enabled() const; 34 | void push_back(const log_msg &msg); 35 | 36 | // pop all items in the q and apply the given fun on each of them. 37 | void foreach_pop(std::function fun); 38 | }; 39 | 40 | } // namespace details 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | #include "backtracer-inl.h" 45 | #endif -------------------------------------------------------------------------------- /src/spdlog/details/circular_q.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | // circular q view of std::vector. 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace spdlog { 11 | namespace details { 12 | template 13 | class circular_q 14 | { 15 | size_t max_items_ = 0; 16 | typename std::vector::size_type head_ = 0; 17 | typename std::vector::size_type tail_ = 0; 18 | size_t overrun_counter_ = 0; 19 | std::vector v_; 20 | 21 | public: 22 | using value_type = T; 23 | 24 | // empty ctor - create a disabled queue with no elements allocated at all 25 | circular_q() = default; 26 | 27 | explicit circular_q(size_t max_items) 28 | : max_items_(max_items + 1) // one item is reserved as marker for full q 29 | , v_(max_items_) 30 | {} 31 | 32 | circular_q(const circular_q &) = default; 33 | circular_q &operator=(const circular_q &) = default; 34 | 35 | // move cannot be default, 36 | // since we need to reset head_, tail_, etc to zero in the moved object 37 | circular_q(circular_q &&other) SPDLOG_NOEXCEPT 38 | { 39 | copy_moveable(std::move(other)); 40 | } 41 | 42 | circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT 43 | { 44 | copy_moveable(std::move(other)); 45 | return *this; 46 | } 47 | 48 | // push back, overrun (oldest) item if no room left 49 | void push_back(T &&item) 50 | { 51 | if (max_items_ > 0) 52 | { 53 | v_[tail_] = std::move(item); 54 | tail_ = (tail_ + 1) % max_items_; 55 | 56 | if (tail_ == head_) // overrun last item if full 57 | { 58 | head_ = (head_ + 1) % max_items_; 59 | ++overrun_counter_; 60 | } 61 | } 62 | } 63 | 64 | // Return reference to the front item. 65 | // If there are no elements in the container, the behavior is undefined. 66 | const T &front() const 67 | { 68 | return v_[head_]; 69 | } 70 | 71 | T &front() 72 | { 73 | return v_[head_]; 74 | } 75 | 76 | // Return number of elements actually stored 77 | size_t size() const 78 | { 79 | if (tail_ >= head_) 80 | { 81 | return tail_ - head_; 82 | } 83 | else 84 | { 85 | return max_items_ - (head_ - tail_); 86 | } 87 | } 88 | 89 | // Return const reference to item by index. 90 | // If index is out of range 0…size()-1, the behavior is undefined. 91 | const T &at(size_t i) const 92 | { 93 | assert(i < size()); 94 | return v_[(head_ + i) % max_items_]; 95 | } 96 | 97 | // Pop item from front. 98 | // If there are no elements in the container, the behavior is undefined. 99 | void pop_front() 100 | { 101 | head_ = (head_ + 1) % max_items_; 102 | } 103 | 104 | bool empty() const 105 | { 106 | return tail_ == head_; 107 | } 108 | 109 | bool full() const 110 | { 111 | // head is ahead of the tail by 1 112 | if (max_items_ > 0) 113 | { 114 | return ((tail_ + 1) % max_items_) == head_; 115 | } 116 | return false; 117 | } 118 | 119 | size_t overrun_counter() const 120 | { 121 | return overrun_counter_; 122 | } 123 | 124 | private: 125 | // copy from other&& and reset it to disabled state 126 | void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT 127 | { 128 | max_items_ = other.max_items_; 129 | head_ = other.head_; 130 | tail_ = other.tail_; 131 | overrun_counter_ = other.overrun_counter_; 132 | v_ = std::move(other.v_); 133 | 134 | // put &&other in disabled, but valid state 135 | other.max_items_ = 0; 136 | other.head_ = other.tail_ = 0; 137 | other.overrun_counter_ = 0; 138 | } 139 | }; 140 | } // namespace details 141 | } // namespace spdlog 142 | -------------------------------------------------------------------------------- /src/spdlog/details/console_globals.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | struct console_mutex 13 | { 14 | using mutex_t = std::mutex; 15 | static mutex_t &mutex() 16 | { 17 | static mutex_t s_mutex; 18 | return s_mutex; 19 | } 20 | }; 21 | 22 | struct console_nullmutex 23 | { 24 | using mutex_t = null_mutex; 25 | static mutex_t &mutex() 26 | { 27 | static mutex_t s_mutex; 28 | return s_mutex; 29 | } 30 | }; 31 | } // namespace details 32 | } // namespace spdlog 33 | -------------------------------------------------------------------------------- /src/spdlog/details/file_helper-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace spdlog { 21 | namespace details { 22 | 23 | SPDLOG_INLINE file_helper::~file_helper() 24 | { 25 | close(); 26 | } 27 | 28 | SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) 29 | { 30 | close(); 31 | filename_ = fname; 32 | auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); 33 | 34 | for (int tries = 0; tries < open_tries_; ++tries) 35 | { 36 | // create containing folder if not exists already. 37 | os::create_dir(os::dir_name(fname)); 38 | if (!os::fopen_s(&fd_, fname, mode)) 39 | { 40 | return; 41 | } 42 | 43 | details::os::sleep_for_millis(open_interval_); 44 | } 45 | 46 | throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno); 47 | } 48 | 49 | SPDLOG_INLINE void file_helper::reopen(bool truncate) 50 | { 51 | if (filename_.empty()) 52 | { 53 | throw_spdlog_ex("Failed re opening file - was not opened before"); 54 | } 55 | this->open(filename_, truncate); 56 | } 57 | 58 | SPDLOG_INLINE void file_helper::flush() 59 | { 60 | std::fflush(fd_); 61 | } 62 | 63 | SPDLOG_INLINE void file_helper::close() 64 | { 65 | if (fd_ != nullptr) 66 | { 67 | std::fclose(fd_); 68 | fd_ = nullptr; 69 | } 70 | } 71 | 72 | SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) 73 | { 74 | size_t msg_size = buf.size(); 75 | auto data = buf.data(); 76 | if (std::fwrite(data, 1, msg_size, fd_) != msg_size) 77 | { 78 | throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); 79 | } 80 | } 81 | 82 | SPDLOG_INLINE size_t file_helper::size() const 83 | { 84 | if (fd_ == nullptr) 85 | { 86 | throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)); 87 | } 88 | return os::filesize(fd_); 89 | } 90 | 91 | SPDLOG_INLINE const filename_t &file_helper::filename() const 92 | { 93 | return filename_; 94 | } 95 | 96 | // 97 | // return file path and its extension: 98 | // 99 | // "mylog.txt" => ("mylog", ".txt") 100 | // "mylog" => ("mylog", "") 101 | // "mylog." => ("mylog.", "") 102 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") 103 | // 104 | // the starting dot in filenames is ignored (hidden files): 105 | // 106 | // ".mylog" => (".mylog". "") 107 | // "my_folder/.mylog" => ("my_folder/.mylog", "") 108 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") 109 | SPDLOG_INLINE std::tuple file_helper::split_by_extension(const filename_t &fname) 110 | { 111 | auto ext_index = fname.rfind('.'); 112 | 113 | // no valid extension found - return whole path and empty string as 114 | // extension 115 | if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) 116 | { 117 | return std::make_tuple(fname, filename_t()); 118 | } 119 | 120 | // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" 121 | auto folder_index = fname.rfind(details::os::folder_sep); 122 | if (folder_index != filename_t::npos && folder_index >= ext_index - 1) 123 | { 124 | return std::make_tuple(fname, filename_t()); 125 | } 126 | 127 | // finally - return a valid base and extension tuple 128 | return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); 129 | } 130 | 131 | } // namespace details 132 | } // namespace spdlog 133 | -------------------------------------------------------------------------------- /src/spdlog/details/file_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | // Helper class for file sinks. 13 | // When failing to open a file, retry several times(5) with a delay interval(10 ms). 14 | // Throw spdlog_ex exception on errors. 15 | 16 | class SPDLOG_API file_helper 17 | { 18 | public: 19 | explicit file_helper() = default; 20 | 21 | file_helper(const file_helper &) = delete; 22 | file_helper &operator=(const file_helper &) = delete; 23 | ~file_helper(); 24 | 25 | void open(const filename_t &fname, bool truncate = false); 26 | void reopen(bool truncate); 27 | void flush(); 28 | void close(); 29 | void write(const memory_buf_t &buf); 30 | size_t size() const; 31 | const filename_t &filename() const; 32 | 33 | // 34 | // return file path and its extension: 35 | // 36 | // "mylog.txt" => ("mylog", ".txt") 37 | // "mylog" => ("mylog", "") 38 | // "mylog." => ("mylog.", "") 39 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") 40 | // 41 | // the starting dot in filenames is ignored (hidden files): 42 | // 43 | // ".mylog" => (".mylog". "") 44 | // "my_folder/.mylog" => ("my_folder/.mylog", "") 45 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") 46 | static std::tuple split_by_extension(const filename_t &fname); 47 | 48 | private: 49 | const int open_tries_ = 5; 50 | const int open_interval_ = 10; 51 | std::FILE *fd_{nullptr}; 52 | filename_t filename_; 53 | }; 54 | } // namespace details 55 | } // namespace spdlog 56 | 57 | #ifdef SPDLOG_HEADER_ONLY 58 | #include "file_helper-inl.h" 59 | #endif 60 | -------------------------------------------------------------------------------- /src/spdlog/details/fmt_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Some fmt helpers to efficiently format and pad ints and strings 11 | namespace spdlog { 12 | namespace details { 13 | namespace fmt_helper { 14 | 15 | inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT 16 | { 17 | return spdlog::string_view_t{buf.data(), buf.size()}; 18 | } 19 | 20 | inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) 21 | { 22 | auto *buf_ptr = view.data(); 23 | dest.append(buf_ptr, buf_ptr + view.size()); 24 | } 25 | 26 | template 27 | inline void append_int(T n, memory_buf_t &dest) 28 | { 29 | fmt::format_int i(n); 30 | dest.append(i.data(), i.data() + i.size()); 31 | } 32 | 33 | template 34 | inline unsigned int count_digits(T n) 35 | { 36 | using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; 37 | return static_cast(fmt:: 38 | // fmt 7.0.0 renamed the internal namespace to detail. 39 | // See: https://github.com/fmtlib/fmt/issues/1538 40 | #if FMT_VERSION < 70000 41 | internal 42 | #else 43 | detail 44 | #endif 45 | ::count_digits(static_cast(n))); 46 | } 47 | 48 | inline void pad2(int n, memory_buf_t &dest) 49 | { 50 | if (n >= 0 && n < 100) // 0-99 51 | { 52 | dest.push_back(static_cast('0' + n / 10)); 53 | dest.push_back(static_cast('0' + n % 10)); 54 | } 55 | else // unlikely, but just in case, let fmt deal with it 56 | { 57 | fmt::format_to(dest, "{:02}", n); 58 | } 59 | } 60 | 61 | template 62 | inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) 63 | { 64 | static_assert(std::is_unsigned::value, "pad_uint must get unsigned T"); 65 | for (auto digits = count_digits(n); digits < width; digits++) 66 | { 67 | dest.push_back('0'); 68 | } 69 | append_int(n, dest); 70 | } 71 | 72 | template 73 | inline void pad3(T n, memory_buf_t &dest) 74 | { 75 | static_assert(std::is_unsigned::value, "pad3 must get unsigned T"); 76 | if (n < 1000) 77 | { 78 | dest.push_back(static_cast(n / 100 + '0')); 79 | n = n % 100; 80 | dest.push_back(static_cast((n / 10) + '0')); 81 | dest.push_back(static_cast((n % 10) + '0')); 82 | } 83 | else 84 | { 85 | append_int(n, dest); 86 | } 87 | } 88 | 89 | template 90 | inline void pad6(T n, memory_buf_t &dest) 91 | { 92 | pad_uint(n, 6, dest); 93 | } 94 | 95 | template 96 | inline void pad9(T n, memory_buf_t &dest) 97 | { 98 | pad_uint(n, 9, dest); 99 | } 100 | 101 | // return fraction of a second of the given time_point. 102 | // e.g. 103 | // fraction(tp) -> will return the millis part of the second 104 | template 105 | inline ToDuration time_fraction(log_clock::time_point tp) 106 | { 107 | using std::chrono::duration_cast; 108 | using std::chrono::seconds; 109 | auto duration = tp.time_since_epoch(); 110 | auto secs = duration_cast(duration); 111 | return duration_cast(duration) - duration_cast(secs); 112 | } 113 | 114 | } // namespace fmt_helper 115 | } // namespace details 116 | } // namespace spdlog 117 | -------------------------------------------------------------------------------- /src/spdlog/details/log_msg-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace details { 14 | 15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, 16 | spdlog::level::level_enum lvl, spdlog::string_view_t msg) 17 | : logger_name(a_logger_name) 18 | , level(lvl) 19 | , time(log_time) 20 | #ifndef SPDLOG_NO_THREAD_ID 21 | , thread_id(os::thread_id()) 22 | #endif 23 | , source(loc) 24 | , payload(msg) 25 | {} 26 | 27 | SPDLOG_INLINE log_msg::log_msg( 28 | spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 29 | : log_msg(os::now(), loc, a_logger_name, lvl, msg) 30 | {} 31 | 32 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 33 | : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) 34 | {} 35 | 36 | } // namespace details 37 | } // namespace spdlog 38 | -------------------------------------------------------------------------------- /src/spdlog/details/log_msg.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | struct SPDLOG_API log_msg 12 | { 13 | log_msg() = default; 14 | log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 15 | log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 16 | log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); 17 | log_msg(const log_msg &other) = default; 18 | 19 | string_view_t logger_name; 20 | level::level_enum level{level::off}; 21 | log_clock::time_point time; 22 | size_t thread_id{0}; 23 | 24 | // wrapping the formatted text with color (updated by pattern_formatter). 25 | mutable size_t color_range_start{0}; 26 | mutable size_t color_range_end{0}; 27 | 28 | source_loc source; 29 | string_view_t payload; 30 | }; 31 | } // namespace details 32 | } // namespace spdlog 33 | 34 | #ifdef SPDLOG_HEADER_ONLY 35 | #include "log_msg-inl.h" 36 | #endif 37 | -------------------------------------------------------------------------------- /src/spdlog/details/log_msg_buffer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) 14 | : log_msg{orig_msg} 15 | { 16 | buffer.append(logger_name.begin(), logger_name.end()); 17 | buffer.append(payload.begin(), payload.end()); 18 | update_string_views(); 19 | } 20 | 21 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) 22 | : log_msg{other} 23 | { 24 | buffer.append(logger_name.begin(), logger_name.end()); 25 | buffer.append(payload.begin(), payload.end()); 26 | update_string_views(); 27 | } 28 | 29 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} 30 | { 31 | update_string_views(); 32 | } 33 | 34 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) 35 | { 36 | log_msg::operator=(other); 37 | buffer.clear(); 38 | buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); 39 | update_string_views(); 40 | return *this; 41 | } 42 | 43 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT 44 | { 45 | log_msg::operator=(other); 46 | buffer = std::move(other.buffer); 47 | update_string_views(); 48 | return *this; 49 | } 50 | 51 | SPDLOG_INLINE void log_msg_buffer::update_string_views() 52 | { 53 | logger_name = string_view_t{buffer.data(), logger_name.size()}; 54 | payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; 55 | } 56 | 57 | } // namespace details 58 | } // namespace spdlog 59 | -------------------------------------------------------------------------------- /src/spdlog/details/log_msg_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace details { 10 | 11 | // Extend log_msg with internal buffer to store its payload. 12 | // This is needed since log_msg holds string_views that points to stack data. 13 | 14 | class SPDLOG_API log_msg_buffer : public log_msg 15 | { 16 | memory_buf_t buffer; 17 | void update_string_views(); 18 | 19 | public: 20 | log_msg_buffer() = default; 21 | explicit log_msg_buffer(const log_msg &orig_msg); 22 | log_msg_buffer(const log_msg_buffer &other); 23 | log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 24 | log_msg_buffer &operator=(const log_msg_buffer &other); 25 | log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 26 | }; 27 | 28 | } // namespace details 29 | } // namespace spdlog 30 | 31 | #ifdef SPDLOG_HEADER_ONLY 32 | #include "log_msg_buffer-inl.h" 33 | #endif 34 | -------------------------------------------------------------------------------- /src/spdlog/details/mpmc_blocking_q.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // multi producer-multi consumer blocking queue. 7 | // enqueue(..) - will block until room found to put the new message. 8 | // enqueue_nowait(..) - will return immediately with false if no room left in 9 | // the queue. 10 | // dequeue_for(..) - will block until the queue is not empty or timeout have 11 | // passed. 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace spdlog { 19 | namespace details { 20 | 21 | template 22 | class mpmc_blocking_queue 23 | { 24 | public: 25 | using item_type = T; 26 | explicit mpmc_blocking_queue(size_t max_items) 27 | : q_(max_items) 28 | {} 29 | 30 | #ifndef __MINGW32__ 31 | // try to enqueue and block if no room left 32 | void enqueue(T &&item) 33 | { 34 | { 35 | std::unique_lock lock(queue_mutex_); 36 | pop_cv_.wait(lock, [this] { return !this->q_.full(); }); 37 | q_.push_back(std::move(item)); 38 | } 39 | push_cv_.notify_one(); 40 | } 41 | 42 | // enqueue immediately. overrun oldest message in the queue if no room left. 43 | void enqueue_nowait(T &&item) 44 | { 45 | { 46 | std::unique_lock lock(queue_mutex_); 47 | q_.push_back(std::move(item)); 48 | } 49 | push_cv_.notify_one(); 50 | } 51 | 52 | // try to dequeue item. if no item found. wait upto timeout and try again 53 | // Return true, if succeeded dequeue item, false otherwise 54 | bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) 55 | { 56 | { 57 | std::unique_lock lock(queue_mutex_); 58 | if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) 59 | { 60 | return false; 61 | } 62 | popped_item = std::move(q_.front()); 63 | q_.pop_front(); 64 | } 65 | pop_cv_.notify_one(); 66 | return true; 67 | } 68 | 69 | #else 70 | // apparently mingw deadlocks if the mutex is released before cv.notify_one(), 71 | // so release the mutex at the very end each function. 72 | 73 | // try to enqueue and block if no room left 74 | void enqueue(T &&item) 75 | { 76 | std::unique_lock lock(queue_mutex_); 77 | pop_cv_.wait(lock, [this] { return !this->q_.full(); }); 78 | q_.push_back(std::move(item)); 79 | push_cv_.notify_one(); 80 | } 81 | 82 | // enqueue immediately. overrun oldest message in the queue if no room left. 83 | void enqueue_nowait(T &&item) 84 | { 85 | std::unique_lock lock(queue_mutex_); 86 | q_.push_back(std::move(item)); 87 | push_cv_.notify_one(); 88 | } 89 | 90 | // try to dequeue item. if no item found. wait upto timeout and try again 91 | // Return true, if succeeded dequeue item, false otherwise 92 | bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) 93 | { 94 | std::unique_lock lock(queue_mutex_); 95 | if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) 96 | { 97 | return false; 98 | } 99 | popped_item = std::move(q_.front()); 100 | q_.pop_front(); 101 | pop_cv_.notify_one(); 102 | return true; 103 | } 104 | 105 | #endif 106 | 107 | size_t overrun_counter() 108 | { 109 | std::unique_lock lock(queue_mutex_); 110 | return q_.overrun_counter(); 111 | } 112 | 113 | private: 114 | std::mutex queue_mutex_; 115 | std::condition_variable push_cv_; 116 | std::condition_variable pop_cv_; 117 | spdlog::details::circular_q q_; 118 | }; 119 | } // namespace details 120 | } // namespace spdlog 121 | -------------------------------------------------------------------------------- /src/spdlog/details/null_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | // null, no cost dummy "mutex" and dummy "atomic" int 9 | 10 | namespace spdlog { 11 | namespace details { 12 | struct null_mutex 13 | { 14 | void lock() const {} 15 | void unlock() const {} 16 | bool try_lock() const 17 | { 18 | return true; 19 | } 20 | }; 21 | 22 | struct null_atomic_int 23 | { 24 | int value; 25 | null_atomic_int() = default; 26 | 27 | explicit null_atomic_int(int new_value) 28 | : value(new_value) 29 | {} 30 | 31 | int load(std::memory_order = std::memory_order_relaxed) const 32 | { 33 | return value; 34 | } 35 | 36 | void store(int new_value, std::memory_order = std::memory_order_relaxed) 37 | { 38 | value = new_value; 39 | } 40 | 41 | int exchange(int new_value, std::memory_order = std::memory_order_relaxed) 42 | { 43 | std::swap(new_value, value); 44 | return new_value; // return value before the call 45 | } 46 | }; 47 | 48 | } // namespace details 49 | } // namespace spdlog 50 | -------------------------------------------------------------------------------- /src/spdlog/details/os.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include // std::time_t 8 | 9 | namespace spdlog { 10 | namespace details { 11 | namespace os { 12 | 13 | SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; 14 | 15 | SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; 16 | 17 | SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; 18 | 19 | SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; 20 | 21 | SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; 22 | 23 | // eol definition 24 | #if !defined(SPDLOG_EOL) 25 | #ifdef _WIN32 26 | #define SPDLOG_EOL "\r\n" 27 | #else 28 | #define SPDLOG_EOL "\n" 29 | #endif 30 | #endif 31 | 32 | SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; 33 | 34 | // folder separator 35 | #ifdef _WIN32 36 | static const char folder_sep = '\\'; 37 | #else 38 | SPDLOG_CONSTEXPR static const char folder_sep = '/'; 39 | #endif 40 | 41 | // fopen_s on non windows for writing 42 | SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); 43 | 44 | // Remove filename. return 0 on success 45 | SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; 46 | 47 | // Remove file if exists. return 0 on success 48 | // Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) 49 | SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; 50 | 51 | SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; 52 | 53 | // Return if file exists. 54 | SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; 55 | 56 | // Return file size according to open FILE* object 57 | SPDLOG_API size_t filesize(FILE *f); 58 | 59 | // Return utc offset in minutes or throw spdlog_ex on failure 60 | SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); 61 | 62 | // Return current thread id as size_t 63 | // It exists because the std::this_thread::get_id() is much slower(especially 64 | // under VS 2013) 65 | SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; 66 | 67 | // Return current thread id as size_t (from thread local storage) 68 | SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; 69 | 70 | // This is avoid msvc issue in sleep_for that happens if the clock changes. 71 | // See https://github.com/gabime/spdlog/issues/609 72 | SPDLOG_API void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT; 73 | 74 | SPDLOG_API std::string filename_to_str(const filename_t &filename); 75 | 76 | SPDLOG_API int pid() SPDLOG_NOEXCEPT; 77 | 78 | // Determine if the terminal supports colors 79 | // Source: https://github.com/agauniyal/rang/ 80 | SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; 81 | 82 | // Determine if the terminal attached 83 | // Source: https://github.com/agauniyal/rang/ 84 | SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; 85 | 86 | #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) 87 | SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); 88 | #endif 89 | 90 | // Return directory name from given path or empty string 91 | // "abc/file" => "abc" 92 | // "abc/" => "abc" 93 | // "abc" => "" 94 | // "abc///" => "abc//" 95 | SPDLOG_API filename_t dir_name(filename_t path); 96 | 97 | // Create a dir from the given path. 98 | // Return true if succeeded or if this dir already exists. 99 | SPDLOG_API bool create_dir(filename_t path); 100 | 101 | // non thread safe, cross platform getenv/getenv_s 102 | // return empty string if field not found 103 | SPDLOG_API std::string getenv(const char *field); 104 | 105 | } // namespace os 106 | } // namespace details 107 | } // namespace spdlog 108 | 109 | #ifdef SPDLOG_HEADER_ONLY 110 | #include "os-inl.h" 111 | #endif 112 | -------------------------------------------------------------------------------- /src/spdlog/details/periodic_worker-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE periodic_worker::periodic_worker(const std::function &callback_fun, std::chrono::seconds interval) 14 | { 15 | active_ = (interval > std::chrono::seconds::zero()); 16 | if (!active_) 17 | { 18 | return; 19 | } 20 | 21 | worker_thread_ = std::thread([this, callback_fun, interval]() { 22 | for (;;) 23 | { 24 | std::unique_lock lock(this->mutex_); 25 | if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) 26 | { 27 | return; // active_ == false, so exit this thread 28 | } 29 | callback_fun(); 30 | } 31 | }); 32 | } 33 | 34 | // stop the worker thread and join it 35 | SPDLOG_INLINE periodic_worker::~periodic_worker() 36 | { 37 | if (worker_thread_.joinable()) 38 | { 39 | { 40 | std::lock_guard lock(mutex_); 41 | active_ = false; 42 | } 43 | cv_.notify_one(); 44 | worker_thread_.join(); 45 | } 46 | } 47 | 48 | } // namespace details 49 | } // namespace spdlog 50 | -------------------------------------------------------------------------------- /src/spdlog/details/periodic_worker.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // periodic worker thread - periodically executes the given callback function. 7 | // 8 | // RAII over the owned thread: 9 | // creates the thread on construction. 10 | // stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | namespace spdlog { 18 | namespace details { 19 | 20 | class SPDLOG_API periodic_worker 21 | { 22 | public: 23 | periodic_worker(const std::function &callback_fun, std::chrono::seconds interval); 24 | periodic_worker(const periodic_worker &) = delete; 25 | periodic_worker &operator=(const periodic_worker &) = delete; 26 | // stop the worker thread and join it 27 | ~periodic_worker(); 28 | 29 | private: 30 | bool active_; 31 | std::thread worker_thread_; 32 | std::mutex mutex_; 33 | std::condition_variable cv_; 34 | }; 35 | } // namespace details 36 | } // namespace spdlog 37 | 38 | #ifdef SPDLOG_HEADER_ONLY 39 | #include "periodic_worker-inl.h" 40 | #endif 41 | -------------------------------------------------------------------------------- /src/spdlog/details/registry.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Loggers registry of unique name->logger pointer 7 | // An attempt to create a logger with an already existing name will result with spdlog_ex exception. 8 | // If user requests a non existing logger, nullptr will be returned 9 | // This class is thread safe 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace spdlog { 22 | class logger; 23 | 24 | namespace details { 25 | class thread_pool; 26 | class periodic_worker; 27 | 28 | class SPDLOG_API registry 29 | { 30 | public: 31 | registry(const registry &) = delete; 32 | registry &operator=(const registry &) = delete; 33 | 34 | void register_logger(std::shared_ptr new_logger); 35 | void initialize_logger(std::shared_ptr new_logger); 36 | std::shared_ptr get(const std::string &logger_name); 37 | std::shared_ptr default_logger(); 38 | 39 | // Return raw ptr to the default logger. 40 | // To be used directly by the spdlog default api (e.g. spdlog::info) 41 | // This make the default API faster, but cannot be used concurrently with set_default_logger(). 42 | // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. 43 | logger *get_default_raw(); 44 | 45 | // set default logger. 46 | // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. 47 | void set_default_logger(std::shared_ptr new_default_logger); 48 | 49 | void set_tp(std::shared_ptr tp); 50 | 51 | std::shared_ptr get_tp(); 52 | 53 | // Set global formatter. Each sink in each logger will get a clone of this object 54 | void set_formatter(std::unique_ptr formatter); 55 | 56 | void enable_backtrace(size_t n_messages); 57 | 58 | void disable_backtrace(); 59 | 60 | void set_level(level::level_enum log_level); 61 | 62 | void flush_on(level::level_enum log_level); 63 | 64 | void flush_every(std::chrono::seconds interval); 65 | 66 | void set_error_handler(void (*handler)(const std::string &msg)); 67 | 68 | void apply_all(const std::function)> &fun); 69 | 70 | void flush_all(); 71 | 72 | void drop(const std::string &logger_name); 73 | 74 | void drop_all(); 75 | 76 | // clean all resources and threads started by the registry 77 | void shutdown(); 78 | 79 | std::recursive_mutex &tp_mutex(); 80 | 81 | void set_automatic_registration(bool automatic_registration); 82 | 83 | void update_levels(cfg::log_levels levels); 84 | 85 | static registry &instance(); 86 | 87 | private: 88 | registry(); 89 | ~registry(); 90 | 91 | void throw_if_exists_(const std::string &logger_name); 92 | void register_logger_(std::shared_ptr new_logger); 93 | std::mutex logger_map_mutex_, flusher_mutex_; 94 | std::recursive_mutex tp_mutex_; 95 | std::unordered_map> loggers_; 96 | cfg::log_levels levels_; 97 | std::unique_ptr formatter_; 98 | level::level_enum flush_level_ = level::off; 99 | void (*err_handler_)(const std::string &msg); 100 | std::shared_ptr tp_; 101 | std::unique_ptr periodic_flusher_; 102 | std::shared_ptr default_logger_; 103 | bool automatic_registration_ = true; 104 | size_t backtrace_n_messages_ = 0; 105 | }; 106 | 107 | } // namespace details 108 | } // namespace spdlog 109 | 110 | #ifdef SPDLOG_HEADER_ONLY 111 | #include "registry-inl.h" 112 | #endif 113 | -------------------------------------------------------------------------------- /src/spdlog/details/synchronous_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "registry.h" 7 | 8 | namespace spdlog { 9 | 10 | // Default logger factory- creates synchronous loggers 11 | class logger; 12 | 13 | struct synchronous_factory 14 | { 15 | template 16 | static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) 17 | { 18 | auto sink = std::make_shared(std::forward(args)...); 19 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); 20 | details::registry::instance().initialize_logger(new_logger); 21 | return new_logger; 22 | } 23 | }; 24 | } // namespace spdlog -------------------------------------------------------------------------------- /src/spdlog/details/tcp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | #error include tcp_client-windows.h instead 8 | #endif 9 | 10 | // tcp client helper 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | namespace spdlog { 23 | namespace details { 24 | class tcp_client 25 | { 26 | int socket_ = -1; 27 | 28 | public: 29 | bool is_connected() const 30 | { 31 | return socket_ != -1; 32 | } 33 | 34 | void close() 35 | { 36 | if (is_connected()) 37 | { 38 | ::close(socket_); 39 | socket_ = -1; 40 | } 41 | } 42 | 43 | int fd() const 44 | { 45 | return socket_; 46 | } 47 | 48 | ~tcp_client() 49 | { 50 | close(); 51 | } 52 | 53 | // try to connect or throw on failure 54 | void connect(const std::string &host, int port) 55 | { 56 | close(); 57 | struct addrinfo hints 58 | {}; 59 | memset(&hints, 0, sizeof(struct addrinfo)); 60 | hints.ai_family = AF_INET; // IPv4 61 | hints.ai_socktype = SOCK_STREAM; // TCP 62 | hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value 63 | hints.ai_protocol = 0; 64 | 65 | auto port_str = std::to_string(port); 66 | struct addrinfo *addrinfo_result; 67 | auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); 68 | if (rv != 0) 69 | { 70 | auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv)); 71 | throw_spdlog_ex(msg); 72 | } 73 | 74 | // Try each address until we successfully connect(2). 75 | int last_errno = 0; 76 | for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) 77 | { 78 | int const flags = SOCK_CLOEXEC; 79 | socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); 80 | if (socket_ == -1) 81 | { 82 | last_errno = errno; 83 | continue; 84 | } 85 | rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); 86 | if (rv == 0) 87 | { 88 | break; 89 | } 90 | else 91 | { 92 | last_errno = errno; 93 | ::close(socket_); 94 | socket_ = -1; 95 | } 96 | } 97 | ::freeaddrinfo(addrinfo_result); 98 | if (socket_ == -1) 99 | { 100 | throw_spdlog_ex("::connect failed", last_errno); 101 | } 102 | 103 | // set TCP_NODELAY 104 | int enable_flag = 1; 105 | ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag)); 106 | 107 | // prevent sigpipe on systems where MSG_NOSIGNAL is not available 108 | #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 109 | ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, (char *)&enable_flag, sizeof(enable_flag)); 110 | #endif 111 | 112 | #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 113 | #error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" 114 | #endif 115 | } 116 | 117 | // Send exactly n_bytes of the given data. 118 | // On error close the connection and throw. 119 | void send(const char *data, size_t n_bytes) 120 | { 121 | size_t bytes_sent = 0; 122 | while (bytes_sent < n_bytes) 123 | { 124 | #if defined(MSG_NOSIGNAL) 125 | const int send_flags = MSG_NOSIGNAL; 126 | #else 127 | const int send_flags = 0; 128 | #endif 129 | auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); 130 | if (write_result < 0) 131 | { 132 | close(); 133 | throw_spdlog_ex("write(2) failed", errno); 134 | } 135 | 136 | if (write_result == 0) // (probably should not happen but in any case..) 137 | { 138 | break; 139 | } 140 | bytes_sent += static_cast(write_result); 141 | } 142 | } 143 | }; 144 | } // namespace details 145 | } // namespace spdlog 146 | -------------------------------------------------------------------------------- /src/spdlog/details/thread_pool-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace details { 15 | 16 | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) 17 | : q_(q_max_items) 18 | { 19 | if (threads_n == 0 || threads_n > 1000) 20 | { 21 | throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " 22 | "range is 1-1000)"); 23 | } 24 | for (size_t i = 0; i < threads_n; i++) 25 | { 26 | threads_.emplace_back([this, on_thread_start] { 27 | on_thread_start(); 28 | this->thread_pool::worker_loop_(); 29 | }); 30 | } 31 | } 32 | 33 | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) 34 | : thread_pool(q_max_items, threads_n, [] {}) 35 | {} 36 | 37 | // message all threads to terminate gracefully join them 38 | SPDLOG_INLINE thread_pool::~thread_pool() 39 | { 40 | SPDLOG_TRY 41 | { 42 | for (size_t i = 0; i < threads_.size(); i++) 43 | { 44 | post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); 45 | } 46 | 47 | for (auto &t : threads_) 48 | { 49 | t.join(); 50 | } 51 | } 52 | SPDLOG_CATCH_ALL() {} 53 | } 54 | 55 | void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) 56 | { 57 | async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); 58 | post_async_msg_(std::move(async_m), overflow_policy); 59 | } 60 | 61 | void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) 62 | { 63 | post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); 64 | } 65 | 66 | size_t SPDLOG_INLINE thread_pool::overrun_counter() 67 | { 68 | return q_.overrun_counter(); 69 | } 70 | 71 | void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) 72 | { 73 | if (overflow_policy == async_overflow_policy::block) 74 | { 75 | q_.enqueue(std::move(new_msg)); 76 | } 77 | else 78 | { 79 | q_.enqueue_nowait(std::move(new_msg)); 80 | } 81 | } 82 | 83 | void SPDLOG_INLINE thread_pool::worker_loop_() 84 | { 85 | while (process_next_msg_()) {} 86 | } 87 | 88 | // process next message in the queue 89 | // return true if this thread should still be active (while no terminate msg 90 | // was received) 91 | bool SPDLOG_INLINE thread_pool::process_next_msg_() 92 | { 93 | async_msg incoming_async_msg; 94 | bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); 95 | if (!dequeued) 96 | { 97 | return true; 98 | } 99 | 100 | switch (incoming_async_msg.msg_type) 101 | { 102 | case async_msg_type::log: { 103 | incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); 104 | return true; 105 | } 106 | case async_msg_type::flush: { 107 | incoming_async_msg.worker_ptr->backend_flush_(); 108 | return true; 109 | } 110 | 111 | case async_msg_type::terminate: { 112 | return false; 113 | } 114 | 115 | default: { 116 | assert(false); 117 | } 118 | } 119 | 120 | return true; 121 | } 122 | 123 | } // namespace details 124 | } // namespace spdlog 125 | -------------------------------------------------------------------------------- /src/spdlog/details/thread_pool.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | class async_logger; 18 | 19 | namespace details { 20 | 21 | using async_logger_ptr = std::shared_ptr; 22 | 23 | enum class async_msg_type 24 | { 25 | log, 26 | flush, 27 | terminate 28 | }; 29 | 30 | #include 31 | // Async msg to move to/from the queue 32 | // Movable only. should never be copied 33 | struct async_msg : log_msg_buffer 34 | { 35 | async_msg_type msg_type{async_msg_type::log}; 36 | async_logger_ptr worker_ptr; 37 | 38 | async_msg() = default; 39 | ~async_msg() = default; 40 | 41 | // should only be moved in or out of the queue.. 42 | async_msg(const async_msg &) = delete; 43 | 44 | // support for vs2013 move 45 | #if defined(_MSC_VER) && _MSC_VER <= 1800 46 | async_msg(async_msg &&other) 47 | : log_msg_buffer(std::move(other)) 48 | , msg_type(other.msg_type) 49 | , worker_ptr(std::move(other.worker_ptr)) 50 | {} 51 | 52 | async_msg &operator=(async_msg &&other) 53 | { 54 | *static_cast(this) = std::move(other); 55 | msg_type = other.msg_type; 56 | worker_ptr = std::move(other.worker_ptr); 57 | return *this; 58 | } 59 | #else // (_MSC_VER) && _MSC_VER <= 1800 60 | async_msg(async_msg &&) = default; 61 | async_msg &operator=(async_msg &&) = default; 62 | #endif 63 | 64 | // construct from log_msg with given type 65 | async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) 66 | : log_msg_buffer{m} 67 | , msg_type{the_type} 68 | , worker_ptr{std::move(worker)} 69 | {} 70 | 71 | async_msg(async_logger_ptr &&worker, async_msg_type the_type) 72 | : log_msg_buffer{} 73 | , msg_type{the_type} 74 | , worker_ptr{std::move(worker)} 75 | {} 76 | 77 | explicit async_msg(async_msg_type the_type) 78 | : async_msg{nullptr, the_type} 79 | {} 80 | }; 81 | 82 | class SPDLOG_API thread_pool 83 | { 84 | public: 85 | using item_type = async_msg; 86 | using q_type = details::mpmc_blocking_queue; 87 | 88 | thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); 89 | thread_pool(size_t q_max_items, size_t threads_n); 90 | 91 | // message all threads to terminate gracefully join them 92 | ~thread_pool(); 93 | 94 | thread_pool(const thread_pool &) = delete; 95 | thread_pool &operator=(thread_pool &&) = delete; 96 | 97 | void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy); 98 | void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); 99 | size_t overrun_counter(); 100 | 101 | private: 102 | q_type q_; 103 | 104 | std::vector threads_; 105 | 106 | void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); 107 | void worker_loop_(); 108 | 109 | // process next message in the queue 110 | // return true if this thread should still be active (while no terminate msg 111 | // was received) 112 | bool process_next_msg_(); 113 | }; 114 | 115 | } // namespace details 116 | } // namespace spdlog 117 | 118 | #ifdef SPDLOG_HEADER_ONLY 119 | #include "thread_pool-inl.h" 120 | #endif 121 | -------------------------------------------------------------------------------- /src/spdlog/details/windows_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | #define NOMINMAX // prevent windows redefining min/max 5 | #endif 6 | 7 | #ifndef WIN32_LEAN_AND_MEAN 8 | #define WIN32_LEAN_AND_MEAN 9 | #endif 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /src/spdlog/fmt/bundled/LICENSE.rst: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /src/spdlog/fmt/bundled/locale.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::locale support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_LOCALE_H_ 9 | #define FMT_LOCALE_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | FMT_BEGIN_NAMESPACE 16 | 17 | namespace internal { 18 | template 19 | typename buffer_context::iterator vformat_to( 20 | const std::locale& loc, buffer& buf, 21 | basic_string_view format_str, 22 | basic_format_args>> args) { 23 | using range = buffer_range; 24 | return vformat_to>(buf, to_string_view(format_str), args, 25 | internal::locale_ref(loc)); 26 | } 27 | 28 | template 29 | std::basic_string vformat( 30 | const std::locale& loc, basic_string_view format_str, 31 | basic_format_args>> args) { 32 | basic_memory_buffer buffer; 33 | internal::vformat_to(loc, buffer, format_str, args); 34 | return fmt::to_string(buffer); 35 | } 36 | } // namespace internal 37 | 38 | template > 39 | inline std::basic_string vformat( 40 | const std::locale& loc, const S& format_str, 41 | basic_format_args>> args) { 42 | return internal::vformat(loc, to_string_view(format_str), args); 43 | } 44 | 45 | template > 46 | inline std::basic_string format(const std::locale& loc, 47 | const S& format_str, Args&&... args) { 48 | return internal::vformat( 49 | loc, to_string_view(format_str), 50 | internal::make_args_checked(format_str, args...)); 51 | } 52 | 53 | template ::value, char_t>> 56 | inline OutputIt vformat_to( 57 | OutputIt out, const std::locale& loc, const S& format_str, 58 | format_args_t, Char> args) { 59 | using range = internal::output_range; 60 | return vformat_to>( 61 | range(out), to_string_view(format_str), args, internal::locale_ref(loc)); 62 | } 63 | 64 | template ::value&& 66 | internal::is_string::value)> 67 | inline OutputIt format_to(OutputIt out, const std::locale& loc, 68 | const S& format_str, Args&&... args) { 69 | internal::check_format_string(format_str); 70 | using context = format_context_t>; 71 | format_arg_store as{args...}; 72 | return vformat_to(out, loc, to_string_view(format_str), 73 | basic_format_args(as)); 74 | } 75 | 76 | FMT_END_NAMESPACE 77 | 78 | #endif // FMT_LOCALE_H_ 79 | -------------------------------------------------------------------------------- /src/spdlog/fmt/bundled/posix.h: -------------------------------------------------------------------------------- 1 | #include "os.h" 2 | #warning "fmt/posix.h is deprecated; use fmt/os.h instead" -------------------------------------------------------------------------------- /src/spdlog/fmt/fmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016-2018 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | // 9 | // Include a bundled header-only copy of fmtlib or an external one. 10 | // By default spdlog include its own copy. 11 | // 12 | 13 | #if !defined(SPDLOG_FMT_EXTERNAL) 14 | #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) 15 | #define FMT_HEADER_ONLY 16 | #endif 17 | #ifndef FMT_USE_WINDOWS_H 18 | #define FMT_USE_WINDOWS_H 0 19 | #endif 20 | #include 21 | #include 22 | #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib 23 | #include 24 | #include 25 | #endif -------------------------------------------------------------------------------- /src/spdlog/fmt/ostr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ostream support 9 | // 10 | 11 | #if !defined(SPDLOG_FMT_EXTERNAL) 12 | #ifdef SPDLOG_HEADER_ONLY 13 | #ifndef FMT_HEADER_ONLY 14 | #define FMT_HEADER_ONLY 15 | #endif 16 | #endif 17 | #include 18 | #else 19 | #include 20 | #endif 21 | -------------------------------------------------------------------------------- /src/spdlog/formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | class formatter 12 | { 13 | public: 14 | virtual ~formatter() = default; 15 | virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; 16 | virtual std::unique_ptr clone() const = 0; 17 | }; 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /src/spdlog/fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | namespace spdlog { 7 | class logger; 8 | class formatter; 9 | 10 | namespace sinks { 11 | class sink; 12 | } 13 | 14 | } // namespace spdlog 15 | -------------------------------------------------------------------------------- /src/spdlog/pattern_formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace details { 21 | 22 | // padding information. 23 | struct padding_info 24 | { 25 | enum pad_side 26 | { 27 | left, 28 | right, 29 | center 30 | }; 31 | 32 | padding_info() = default; 33 | padding_info(size_t width, padding_info::pad_side side, bool truncate) 34 | : width_(width) 35 | , side_(side) 36 | , truncate_(truncate) 37 | , enabled_(true) 38 | {} 39 | 40 | bool enabled() const 41 | { 42 | return enabled_; 43 | } 44 | size_t width_ = 0; 45 | pad_side side_ = left; 46 | bool truncate_ = false; 47 | bool enabled_ = false; 48 | }; 49 | 50 | class SPDLOG_API flag_formatter 51 | { 52 | public: 53 | explicit flag_formatter(padding_info padinfo) 54 | : padinfo_(padinfo) 55 | {} 56 | flag_formatter() = default; 57 | virtual ~flag_formatter() = default; 58 | virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; 59 | 60 | protected: 61 | padding_info padinfo_; 62 | }; 63 | 64 | } // namespace details 65 | 66 | class SPDLOG_API custom_flag_formatter : public details::flag_formatter 67 | { 68 | public: 69 | virtual std::unique_ptr clone() const = 0; 70 | 71 | void set_padding_info(details::padding_info padding) 72 | { 73 | flag_formatter::padinfo_ = padding; 74 | } 75 | }; 76 | 77 | class SPDLOG_API pattern_formatter final : public formatter 78 | { 79 | public: 80 | using custom_flags = std::unordered_map>; 81 | 82 | explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, 83 | std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags()); 84 | 85 | // use default pattern is not given 86 | explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); 87 | 88 | pattern_formatter(const pattern_formatter &other) = delete; 89 | pattern_formatter &operator=(const pattern_formatter &other) = delete; 90 | 91 | std::unique_ptr clone() const override; 92 | void format(const details::log_msg &msg, memory_buf_t &dest) override; 93 | 94 | template 95 | pattern_formatter &add_flag(char flag, const Args &... args) 96 | { 97 | custom_handlers_[flag] = details::make_unique(args...); 98 | return *this; 99 | } 100 | void set_pattern(std::string pattern); 101 | 102 | private: 103 | std::string pattern_; 104 | std::string eol_; 105 | pattern_time_type pattern_time_type_; 106 | std::tm cached_tm_; 107 | std::chrono::seconds last_log_secs_; 108 | std::vector> formatters_; 109 | custom_flags custom_handlers_; 110 | 111 | std::tm get_time_(const details::log_msg &msg); 112 | template 113 | void handle_flag_(char flag, details::padding_info padding); 114 | 115 | // Extract given pad spec (e.g. %8X) 116 | // Advance the given it pass the end of the padding spec found (if any) 117 | // Return padding. 118 | static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); 119 | 120 | void compile_pattern_(const std::string &pattern); 121 | }; 122 | } // namespace spdlog 123 | 124 | #ifdef SPDLOG_HEADER_ONLY 125 | #include "pattern_formatter-inl.h" 126 | #endif 127 | -------------------------------------------------------------------------------- /src/spdlog/sinks/android_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef __ANDROID__ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if !defined(SPDLOG_ANDROID_RETRIES) 21 | #define SPDLOG_ANDROID_RETRIES 2 22 | #endif 23 | 24 | namespace spdlog { 25 | namespace sinks { 26 | 27 | /* 28 | * Android sink (logging using __android_log_write) 29 | */ 30 | template 31 | class android_sink final : public base_sink 32 | { 33 | public: 34 | explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) 35 | : tag_(std::move(tag)) 36 | , use_raw_msg_(use_raw_msg) 37 | {} 38 | 39 | protected: 40 | void sink_it_(const details::log_msg &msg) override 41 | { 42 | const android_LogPriority priority = convert_to_android_(msg.level); 43 | memory_buf_t formatted; 44 | if (use_raw_msg_) 45 | { 46 | details::fmt_helper::append_string_view(msg.payload, formatted); 47 | } 48 | else 49 | { 50 | base_sink::formatter_->format(msg, formatted); 51 | } 52 | formatted.push_back('\0'); 53 | const char *msg_output = formatted.data(); 54 | 55 | // See system/core/liblog/logger_write.c for explanation of return value 56 | int ret = __android_log_write(priority, tag_.c_str(), msg_output); 57 | int retry_count = 0; 58 | while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) 59 | { 60 | details::os::sleep_for_millis(5); 61 | ret = __android_log_write(priority, tag_.c_str(), msg_output); 62 | retry_count++; 63 | } 64 | 65 | if (ret < 0) 66 | { 67 | throw_spdlog_ex("__android_log_write() failed", ret); 68 | } 69 | } 70 | 71 | void flush_() override {} 72 | 73 | private: 74 | static android_LogPriority convert_to_android_(spdlog::level::level_enum level) 75 | { 76 | switch (level) 77 | { 78 | case spdlog::level::trace: 79 | return ANDROID_LOG_VERBOSE; 80 | case spdlog::level::debug: 81 | return ANDROID_LOG_DEBUG; 82 | case spdlog::level::info: 83 | return ANDROID_LOG_INFO; 84 | case spdlog::level::warn: 85 | return ANDROID_LOG_WARN; 86 | case spdlog::level::err: 87 | return ANDROID_LOG_ERROR; 88 | case spdlog::level::critical: 89 | return ANDROID_LOG_FATAL; 90 | default: 91 | return ANDROID_LOG_DEFAULT; 92 | } 93 | } 94 | 95 | std::string tag_; 96 | bool use_raw_msg_; 97 | }; 98 | 99 | using android_sink_mt = android_sink; 100 | using android_sink_st = android_sink; 101 | } // namespace sinks 102 | 103 | // Create and register android syslog logger 104 | 105 | template 106 | inline std::shared_ptr android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") 107 | { 108 | return Factory::template create(logger_name, tag); 109 | } 110 | 111 | template 112 | inline std::shared_ptr android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") 113 | { 114 | return Factory::template create(logger_name, tag); 115 | } 116 | 117 | } // namespace spdlog 118 | 119 | #endif // __ANDROID__ -------------------------------------------------------------------------------- /src/spdlog/sinks/ansicolor_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | 17 | /** 18 | * This sink prefixes the output with an ANSI escape sequence color code 19 | * depending on the severity 20 | * of the message. 21 | * If no color terminal detected, omit the escape codes. 22 | */ 23 | 24 | template 25 | class ansicolor_sink : public sink 26 | { 27 | public: 28 | using mutex_t = typename ConsoleMutex::mutex_t; 29 | ansicolor_sink(FILE *target_file, color_mode mode); 30 | ~ansicolor_sink() override = default; 31 | 32 | ansicolor_sink(const ansicolor_sink &other) = delete; 33 | ansicolor_sink(ansicolor_sink &&other) = delete; 34 | 35 | ansicolor_sink &operator=(const ansicolor_sink &other) = delete; 36 | ansicolor_sink &operator=(ansicolor_sink &&other) = delete; 37 | 38 | void set_color(level::level_enum color_level, string_view_t color); 39 | void set_color_mode(color_mode mode); 40 | bool should_color(); 41 | 42 | void log(const details::log_msg &msg) override; 43 | void flush() override; 44 | void set_pattern(const std::string &pattern) final; 45 | void set_formatter(std::unique_ptr sink_formatter) override; 46 | 47 | // Formatting codes 48 | const string_view_t reset = "\033[m"; 49 | const string_view_t bold = "\033[1m"; 50 | const string_view_t dark = "\033[2m"; 51 | const string_view_t underline = "\033[4m"; 52 | const string_view_t blink = "\033[5m"; 53 | const string_view_t reverse = "\033[7m"; 54 | const string_view_t concealed = "\033[8m"; 55 | const string_view_t clear_line = "\033[K"; 56 | 57 | // Foreground colors 58 | const string_view_t black = "\033[30m"; 59 | const string_view_t red = "\033[31m"; 60 | const string_view_t green = "\033[32m"; 61 | const string_view_t yellow = "\033[33m"; 62 | const string_view_t blue = "\033[34m"; 63 | const string_view_t magenta = "\033[35m"; 64 | const string_view_t cyan = "\033[36m"; 65 | const string_view_t white = "\033[37m"; 66 | 67 | /// Background colors 68 | const string_view_t on_black = "\033[40m"; 69 | const string_view_t on_red = "\033[41m"; 70 | const string_view_t on_green = "\033[42m"; 71 | const string_view_t on_yellow = "\033[43m"; 72 | const string_view_t on_blue = "\033[44m"; 73 | const string_view_t on_magenta = "\033[45m"; 74 | const string_view_t on_cyan = "\033[46m"; 75 | const string_view_t on_white = "\033[47m"; 76 | 77 | /// Bold colors 78 | const string_view_t yellow_bold = "\033[33m\033[1m"; 79 | const string_view_t red_bold = "\033[31m\033[1m"; 80 | const string_view_t bold_on_red = "\033[1m\033[41m"; 81 | 82 | private: 83 | FILE *target_file_; 84 | mutex_t &mutex_; 85 | bool should_do_colors_; 86 | std::unique_ptr formatter_; 87 | std::array colors_; 88 | void print_ccode_(const string_view_t &color_code); 89 | void print_range_(const memory_buf_t &formatted, size_t start, size_t end); 90 | static std::string to_string_(const string_view_t &sv); 91 | }; 92 | 93 | template 94 | class ansicolor_stdout_sink : public ansicolor_sink 95 | { 96 | public: 97 | explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); 98 | }; 99 | 100 | template 101 | class ansicolor_stderr_sink : public ansicolor_sink 102 | { 103 | public: 104 | explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); 105 | }; 106 | 107 | using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; 108 | using ansicolor_stdout_sink_st = ansicolor_stdout_sink; 109 | 110 | using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; 111 | using ansicolor_stderr_sink_st = ansicolor_stderr_sink; 112 | 113 | } // namespace sinks 114 | } // namespace spdlog 115 | 116 | #ifdef SPDLOG_HEADER_ONLY 117 | #include "ansicolor_sink-inl.h" 118 | #endif 119 | -------------------------------------------------------------------------------- /src/spdlog/sinks/base_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | template 16 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() 17 | : formatter_{details::make_unique()} 18 | {} 19 | 20 | template 21 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink(std::unique_ptr formatter) 22 | : formatter_{std::move(formatter)} 23 | {} 24 | 25 | template 26 | void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) 27 | { 28 | std::lock_guard lock(mutex_); 29 | sink_it_(msg); 30 | } 31 | 32 | template 33 | void SPDLOG_INLINE spdlog::sinks::base_sink::flush() 34 | { 35 | std::lock_guard lock(mutex_); 36 | flush_(); 37 | } 38 | 39 | template 40 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) 41 | { 42 | std::lock_guard lock(mutex_); 43 | set_pattern_(pattern); 44 | } 45 | 46 | template 47 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) 48 | { 49 | std::lock_guard lock(mutex_); 50 | set_formatter_(std::move(sink_formatter)); 51 | } 52 | 53 | template 54 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) 55 | { 56 | set_formatter_(details::make_unique(pattern)); 57 | } 58 | 59 | template 60 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) 61 | { 62 | formatter_ = std::move(sink_formatter); 63 | } 64 | -------------------------------------------------------------------------------- /src/spdlog/sinks/base_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | // 6 | // base sink templated over a mutex (either dummy or real) 7 | // concrete implementation should override the sink_it_() and flush_() methods. 8 | // locking is taken care of in this class - no locking needed by the 9 | // implementers.. 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | template 19 | class base_sink : public sink 20 | { 21 | public: 22 | base_sink(); 23 | explicit base_sink(std::unique_ptr formatter); 24 | ~base_sink() override = default; 25 | 26 | base_sink(const base_sink &) = delete; 27 | base_sink(base_sink &&) = delete; 28 | 29 | base_sink &operator=(const base_sink &) = delete; 30 | base_sink &operator=(base_sink &&) = delete; 31 | 32 | void log(const details::log_msg &msg) final; 33 | void flush() final; 34 | void set_pattern(const std::string &pattern) final; 35 | void set_formatter(std::unique_ptr sink_formatter) final; 36 | 37 | protected: 38 | // sink formatter 39 | std::unique_ptr formatter_; 40 | Mutex mutex_; 41 | 42 | virtual void sink_it_(const details::log_msg &msg) = 0; 43 | virtual void flush_() = 0; 44 | virtual void set_pattern_(const std::string &pattern); 45 | virtual void set_formatter_(std::unique_ptr sink_formatter); 46 | }; 47 | } // namespace sinks 48 | } // namespace spdlog 49 | 50 | #ifdef SPDLOG_HEADER_ONLY 51 | #include "base_sink-inl.h" 52 | #endif 53 | -------------------------------------------------------------------------------- /src/spdlog/sinks/basic_file_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate) 18 | { 19 | file_helper_.open(filename, truncate); 20 | } 21 | 22 | template 23 | SPDLOG_INLINE const filename_t &basic_file_sink::filename() const 24 | { 25 | return file_helper_.filename(); 26 | } 27 | 28 | template 29 | SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) 30 | { 31 | memory_buf_t formatted; 32 | base_sink::formatter_->format(msg, formatted); 33 | file_helper_.write(formatted); 34 | } 35 | 36 | template 37 | SPDLOG_INLINE void basic_file_sink::flush_() 38 | { 39 | file_helper_.flush(); 40 | } 41 | 42 | } // namespace sinks 43 | } // namespace spdlog 44 | -------------------------------------------------------------------------------- /src/spdlog/sinks/basic_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /* 17 | * Trivial file sink with single file as target 18 | */ 19 | template 20 | class basic_file_sink final : public base_sink 21 | { 22 | public: 23 | explicit basic_file_sink(const filename_t &filename, bool truncate = false); 24 | const filename_t &filename() const; 25 | 26 | protected: 27 | void sink_it_(const details::log_msg &msg) override; 28 | void flush_() override; 29 | 30 | private: 31 | details::file_helper file_helper_; 32 | }; 33 | 34 | using basic_file_sink_mt = basic_file_sink; 35 | using basic_file_sink_st = basic_file_sink; 36 | 37 | } // namespace sinks 38 | 39 | // 40 | // factory functions 41 | // 42 | template 43 | inline std::shared_ptr basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false) 44 | { 45 | return Factory::template create(logger_name, filename, truncate); 46 | } 47 | 48 | template 49 | inline std::shared_ptr basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false) 50 | { 51 | return Factory::template create(logger_name, filename, truncate); 52 | } 53 | 54 | } // namespace spdlog 55 | 56 | #ifdef SPDLOG_HEADER_ONLY 57 | #include "basic_file_sink-inl.h" 58 | #endif -------------------------------------------------------------------------------- /src/spdlog/sinks/dist_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "base_sink.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Distribution sink (mux). Stores a vector of sinks which get called when log 17 | // is called 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | 22 | template 23 | class dist_sink : public base_sink 24 | { 25 | public: 26 | dist_sink() = default; 27 | explicit dist_sink(std::vector> sinks) 28 | : sinks_(sinks) 29 | {} 30 | 31 | dist_sink(const dist_sink &) = delete; 32 | dist_sink &operator=(const dist_sink &) = delete; 33 | 34 | void add_sink(std::shared_ptr sink) 35 | { 36 | std::lock_guard lock(base_sink::mutex_); 37 | sinks_.push_back(sink); 38 | } 39 | 40 | void remove_sink(std::shared_ptr sink) 41 | { 42 | std::lock_guard lock(base_sink::mutex_); 43 | sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); 44 | } 45 | 46 | void set_sinks(std::vector> sinks) 47 | { 48 | std::lock_guard lock(base_sink::mutex_); 49 | sinks_ = std::move(sinks); 50 | } 51 | 52 | std::vector> &sinks() 53 | { 54 | return sinks_; 55 | } 56 | 57 | protected: 58 | void sink_it_(const details::log_msg &msg) override 59 | { 60 | for (auto &sink : sinks_) 61 | { 62 | if (sink->should_log(msg.level)) 63 | { 64 | sink->log(msg); 65 | } 66 | } 67 | } 68 | 69 | void flush_() override 70 | { 71 | for (auto &sink : sinks_) 72 | { 73 | sink->flush(); 74 | } 75 | } 76 | 77 | void set_pattern_(const std::string &pattern) override 78 | { 79 | set_formatter_(details::make_unique(pattern)); 80 | } 81 | 82 | void set_formatter_(std::unique_ptr sink_formatter) override 83 | { 84 | base_sink::formatter_ = std::move(sink_formatter); 85 | for (auto &sink : sinks_) 86 | { 87 | sink->set_formatter(base_sink::formatter_->clone()); 88 | } 89 | } 90 | std::vector> sinks_; 91 | }; 92 | 93 | using dist_sink_mt = dist_sink; 94 | using dist_sink_st = dist_sink; 95 | 96 | } // namespace sinks 97 | } // namespace spdlog 98 | -------------------------------------------------------------------------------- /src/spdlog/sinks/dup_filter_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "dist_sink.h" 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // Duplicate message removal sink. 15 | // Skip the message if previous one is identical and less than "max_skip_duration" have passed 16 | // 17 | // Example: 18 | // 19 | // #include 20 | // 21 | // int main() { 22 | // auto dup_filter = std::make_shared(std::chrono::seconds(5)); 23 | // dup_filter->add_sink(std::make_shared()); 24 | // spdlog::logger l("logger", dup_filter); 25 | // l.info("Hello"); 26 | // l.info("Hello"); 27 | // l.info("Hello"); 28 | // l.info("Different Hello"); 29 | // } 30 | // 31 | // Will produce: 32 | // [2019-06-25 17:50:56.511] [logger] [info] Hello 33 | // [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. 34 | // [2019-06-25 17:50:56.512] [logger] [info] Different Hello 35 | 36 | namespace spdlog { 37 | namespace sinks { 38 | template 39 | class dup_filter_sink : public dist_sink 40 | { 41 | public: 42 | template 43 | explicit dup_filter_sink(std::chrono::duration max_skip_duration) 44 | : max_skip_duration_{max_skip_duration} 45 | {} 46 | 47 | protected: 48 | std::chrono::microseconds max_skip_duration_; 49 | log_clock::time_point last_msg_time_; 50 | std::string last_msg_payload_; 51 | size_t skip_counter_ = 0; 52 | 53 | void sink_it_(const details::log_msg &msg) override 54 | { 55 | bool filtered = filter_(msg); 56 | if (!filtered) 57 | { 58 | skip_counter_ += 1; 59 | return; 60 | } 61 | 62 | // log the "skipped.." message 63 | if (skip_counter_ > 0) 64 | { 65 | memory_buf_t buf; 66 | fmt::format_to(buf, "Skipped {} duplicate messages..", skip_counter_); 67 | details::log_msg skipped_msg{msg.logger_name, msg.level, string_view_t{buf.data(), buf.size()}}; 68 | dist_sink::sink_it_(skipped_msg); 69 | } 70 | 71 | // log current message 72 | dist_sink::sink_it_(msg); 73 | last_msg_time_ = msg.time; 74 | skip_counter_ = 0; 75 | last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); 76 | } 77 | 78 | // return whether the log msg should be displayed (true) or skipped (false) 79 | bool filter_(const details::log_msg &msg) 80 | { 81 | auto filter_duration = msg.time - last_msg_time_; 82 | return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); 83 | } 84 | }; 85 | 86 | using dup_filter_sink_mt = dup_filter_sink; 87 | using dup_filter_sink_st = dup_filter_sink; 88 | 89 | } // namespace sinks 90 | } // namespace spdlog 91 | -------------------------------------------------------------------------------- /src/spdlog/sinks/msvc_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2016 Alexander Dalshov. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #if defined(_WIN32) 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace spdlog { 18 | namespace sinks { 19 | /* 20 | * MSVC sink (logging using OutputDebugStringA) 21 | */ 22 | template 23 | class msvc_sink : public base_sink 24 | { 25 | public: 26 | explicit msvc_sink() {} 27 | 28 | protected: 29 | void sink_it_(const details::log_msg &msg) override 30 | { 31 | 32 | memory_buf_t formatted; 33 | base_sink::formatter_->format(msg, formatted); 34 | OutputDebugStringA(fmt::to_string(formatted).c_str()); 35 | } 36 | 37 | void flush_() override {} 38 | }; 39 | 40 | using msvc_sink_mt = msvc_sink; 41 | using msvc_sink_st = msvc_sink; 42 | 43 | using windebug_sink_mt = msvc_sink_mt; 44 | using windebug_sink_st = msvc_sink_st; 45 | 46 | } // namespace sinks 47 | } // namespace spdlog 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/spdlog/sinks/null_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | template 16 | class null_sink : public base_sink 17 | { 18 | protected: 19 | void sink_it_(const details::log_msg &) override {} 20 | void flush_() override {} 21 | }; 22 | 23 | using null_sink_mt = null_sink; 24 | using null_sink_st = null_sink; 25 | 26 | } // namespace sinks 27 | 28 | template 29 | inline std::shared_ptr null_logger_mt(const std::string &logger_name) 30 | { 31 | auto null_logger = Factory::template create(logger_name); 32 | null_logger->set_level(level::off); 33 | return null_logger; 34 | } 35 | 36 | template 37 | inline std::shared_ptr null_logger_st(const std::string &logger_name) 38 | { 39 | auto null_logger = Factory::template create(logger_name); 40 | null_logger->set_level(level::off); 41 | return null_logger; 42 | } 43 | 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /src/spdlog/sinks/ostream_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | template 15 | class ostream_sink final : public base_sink 16 | { 17 | public: 18 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 19 | : ostream_(os) 20 | , force_flush_(force_flush) 21 | {} 22 | ostream_sink(const ostream_sink &) = delete; 23 | ostream_sink &operator=(const ostream_sink &) = delete; 24 | 25 | protected: 26 | void sink_it_(const details::log_msg &msg) override 27 | { 28 | memory_buf_t formatted; 29 | base_sink::formatter_->format(msg, formatted); 30 | ostream_.write(formatted.data(), static_cast(formatted.size())); 31 | if (force_flush_) 32 | { 33 | ostream_.flush(); 34 | } 35 | } 36 | 37 | void flush_() override 38 | { 39 | ostream_.flush(); 40 | } 41 | 42 | std::ostream &ostream_; 43 | bool force_flush_; 44 | }; 45 | 46 | using ostream_sink_mt = ostream_sink; 47 | using ostream_sink_st = ostream_sink; 48 | 49 | } // namespace sinks 50 | } // namespace spdlog 51 | -------------------------------------------------------------------------------- /src/spdlog/sinks/ringbuffer_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "spdlog/sinks/base_sink.h" 7 | #include "spdlog/details/circular_q.h" 8 | #include "spdlog/details/log_msg_buffer.h" 9 | #include "spdlog/details/null_mutex.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | /* 18 | * Ring buffer sink 19 | */ 20 | template 21 | class ringbuffer_sink final : public base_sink 22 | { 23 | public: 24 | explicit ringbuffer_sink(size_t n_items) 25 | : q_{n_items} 26 | {} 27 | 28 | std::vector last_raw(size_t lim = 0) 29 | { 30 | std::lock_guard lock(base_sink::mutex_); 31 | auto items_available = q_.size(); 32 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 33 | std::vector ret; 34 | ret.reserve(n_items); 35 | for (size_t i = (items_available - n_items); i < items_available; i++) 36 | { 37 | ret.push_back(q_.at(i)); 38 | } 39 | return ret; 40 | } 41 | 42 | std::vector last_formatted(size_t lim = 0) 43 | { 44 | std::lock_guard lock(base_sink::mutex_); 45 | auto items_available = q_.size(); 46 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 47 | std::vector ret; 48 | ret.reserve(n_items); 49 | for (size_t i = (items_available - n_items); i < items_available; i++) 50 | { 51 | memory_buf_t formatted; 52 | base_sink::formatter_->format(q_.at(i), formatted); 53 | ret.push_back(fmt::to_string(formatted)); 54 | } 55 | return ret; 56 | } 57 | 58 | protected: 59 | void sink_it_(const details::log_msg &msg) override 60 | { 61 | q_.push_back(details::log_msg_buffer{msg}); 62 | } 63 | void flush_() override {} 64 | 65 | private: 66 | details::circular_q q_; 67 | }; 68 | 69 | using ringbuffer_sink_mt = ringbuffer_sink; 70 | using ringbuffer_sink_st = ringbuffer_sink; 71 | 72 | } // namespace sinks 73 | 74 | } // namespace spdlog 75 | -------------------------------------------------------------------------------- /src/spdlog/sinks/rotating_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | 18 | // 19 | // Rotating file sink based on size 20 | // 21 | template 22 | class rotating_file_sink final : public base_sink 23 | { 24 | public: 25 | rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false); 26 | static filename_t calc_filename(const filename_t &filename, std::size_t index); 27 | filename_t filename(); 28 | 29 | protected: 30 | void sink_it_(const details::log_msg &msg) override; 31 | void flush_() override; 32 | 33 | private: 34 | // Rotate files: 35 | // log.txt -> log.1.txt 36 | // log.1.txt -> log.2.txt 37 | // log.2.txt -> log.3.txt 38 | // log.3.txt -> delete 39 | void rotate_(); 40 | 41 | // delete the target if exists, and rename the src file to target 42 | // return true on success, false otherwise. 43 | bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); 44 | 45 | filename_t base_filename_; 46 | std::size_t max_size_; 47 | std::size_t max_files_; 48 | std::size_t current_size_; 49 | details::file_helper file_helper_; 50 | }; 51 | 52 | using rotating_file_sink_mt = rotating_file_sink; 53 | using rotating_file_sink_st = rotating_file_sink; 54 | 55 | } // namespace sinks 56 | 57 | // 58 | // factory functions 59 | // 60 | 61 | template 62 | inline std::shared_ptr rotating_logger_mt( 63 | const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) 64 | { 65 | return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); 66 | } 67 | 68 | template 69 | inline std::shared_ptr rotating_logger_st( 70 | const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) 71 | { 72 | return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); 73 | } 74 | } // namespace spdlog 75 | 76 | #ifdef SPDLOG_HEADER_ONLY 77 | #include "rotating_file_sink-inl.h" 78 | #endif 79 | -------------------------------------------------------------------------------- /src/spdlog/sinks/sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const 13 | { 14 | return msg_level >= level_.load(std::memory_order_relaxed); 15 | } 16 | 17 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) 18 | { 19 | level_.store(log_level, std::memory_order_relaxed); 20 | } 21 | 22 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const 23 | { 24 | return static_cast(level_.load(std::memory_order_relaxed)); 25 | } 26 | -------------------------------------------------------------------------------- /src/spdlog/sinks/sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | namespace sinks { 12 | class SPDLOG_API sink 13 | { 14 | public: 15 | virtual ~sink() = default; 16 | virtual void log(const details::log_msg &msg) = 0; 17 | virtual void flush() = 0; 18 | virtual void set_pattern(const std::string &pattern) = 0; 19 | virtual void set_formatter(std::unique_ptr sink_formatter) = 0; 20 | 21 | void set_level(level::level_enum log_level); 22 | level::level_enum level() const; 23 | bool should_log(level::level_enum msg_level) const; 24 | 25 | protected: 26 | // sink log level - default is all 27 | level_t level_{level::trace}; 28 | }; 29 | 30 | } // namespace sinks 31 | } // namespace spdlog 32 | 33 | #ifdef SPDLOG_HEADER_ONLY 34 | #include "sink-inl.h" 35 | #endif 36 | -------------------------------------------------------------------------------- /src/spdlog/sinks/stdout_color_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | template 16 | SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode) 17 | { 18 | return Factory::template create(logger_name, mode); 19 | } 20 | 21 | template 22 | SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode) 23 | { 24 | return Factory::template create(logger_name, mode); 25 | } 26 | 27 | template 28 | SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode) 29 | { 30 | return Factory::template create(logger_name, mode); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode) 35 | { 36 | return Factory::template create(logger_name, mode); 37 | } 38 | } // namespace spdlog -------------------------------------------------------------------------------- /src/spdlog/sinks/stdout_color_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | #ifdef _WIN32 17 | using stdout_color_sink_mt = wincolor_stdout_sink_mt; 18 | using stdout_color_sink_st = wincolor_stdout_sink_st; 19 | using stderr_color_sink_mt = wincolor_stderr_sink_mt; 20 | using stderr_color_sink_st = wincolor_stderr_sink_st; 21 | #else 22 | using stdout_color_sink_mt = ansicolor_stdout_sink_mt; 23 | using stdout_color_sink_st = ansicolor_stdout_sink_st; 24 | using stderr_color_sink_mt = ansicolor_stderr_sink_mt; 25 | using stderr_color_sink_st = ansicolor_stderr_sink_st; 26 | #endif 27 | } // namespace sinks 28 | 29 | template 30 | std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 31 | 32 | template 33 | std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 34 | 35 | template 36 | std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 37 | 38 | template 39 | std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 40 | 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | #include "stdout_color_sinks-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /src/spdlog/sinks/stdout_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | 16 | namespace sinks { 17 | 18 | template 19 | SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) 20 | : mutex_(ConsoleMutex::mutex()) 21 | , file_(file) 22 | , formatter_(details::make_unique()) 23 | {} 24 | 25 | template 26 | SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) 27 | { 28 | std::lock_guard lock(mutex_); 29 | memory_buf_t formatted; 30 | formatter_->format(msg, formatted); 31 | fwrite(formatted.data(), sizeof(char), formatted.size(), file_); 32 | fflush(file_); // flush every line to terminal 33 | } 34 | 35 | template 36 | SPDLOG_INLINE void stdout_sink_base::flush() 37 | { 38 | std::lock_guard lock(mutex_); 39 | fflush(file_); 40 | } 41 | 42 | template 43 | SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) 44 | { 45 | std::lock_guard lock(mutex_); 46 | formatter_ = std::unique_ptr(new pattern_formatter(pattern)); 47 | } 48 | 49 | template 50 | SPDLOG_INLINE void stdout_sink_base::set_formatter(std::unique_ptr sink_formatter) 51 | { 52 | std::lock_guard lock(mutex_); 53 | formatter_ = std::move(sink_formatter); 54 | } 55 | 56 | // stdout sink 57 | template 58 | SPDLOG_INLINE stdout_sink::stdout_sink() 59 | : stdout_sink_base(stdout) 60 | {} 61 | 62 | // stderr sink 63 | template 64 | SPDLOG_INLINE stderr_sink::stderr_sink() 65 | : stdout_sink_base(stderr) 66 | {} 67 | 68 | } // namespace sinks 69 | 70 | // factory methods 71 | template 72 | SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) 73 | { 74 | return Factory::template create(logger_name); 75 | } 76 | 77 | template 78 | SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) 79 | { 80 | return Factory::template create(logger_name); 81 | } 82 | 83 | template 84 | SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) 85 | { 86 | return Factory::template create(logger_name); 87 | } 88 | 89 | template 90 | SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) 91 | { 92 | return Factory::template create(logger_name); 93 | } 94 | } // namespace spdlog 95 | -------------------------------------------------------------------------------- /src/spdlog/sinks/stdout_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace spdlog { 12 | 13 | namespace sinks { 14 | 15 | template 16 | class stdout_sink_base : public sink 17 | { 18 | public: 19 | using mutex_t = typename ConsoleMutex::mutex_t; 20 | explicit stdout_sink_base(FILE *file); 21 | ~stdout_sink_base() override = default; 22 | 23 | stdout_sink_base(const stdout_sink_base &other) = delete; 24 | stdout_sink_base(stdout_sink_base &&other) = delete; 25 | 26 | stdout_sink_base &operator=(const stdout_sink_base &other) = delete; 27 | stdout_sink_base &operator=(stdout_sink_base &&other) = delete; 28 | 29 | void log(const details::log_msg &msg) override; 30 | void flush() override; 31 | void set_pattern(const std::string &pattern) override; 32 | 33 | void set_formatter(std::unique_ptr sink_formatter) override; 34 | 35 | protected: 36 | mutex_t &mutex_; 37 | FILE *file_; 38 | std::unique_ptr formatter_; 39 | }; 40 | 41 | template 42 | class stdout_sink : public stdout_sink_base 43 | { 44 | public: 45 | stdout_sink(); 46 | }; 47 | 48 | template 49 | class stderr_sink : public stdout_sink_base 50 | { 51 | public: 52 | stderr_sink(); 53 | }; 54 | 55 | using stdout_sink_mt = stdout_sink; 56 | using stdout_sink_st = stdout_sink; 57 | 58 | using stderr_sink_mt = stderr_sink; 59 | using stderr_sink_st = stderr_sink; 60 | 61 | } // namespace sinks 62 | 63 | // factory methods 64 | template 65 | std::shared_ptr stdout_logger_mt(const std::string &logger_name); 66 | 67 | template 68 | std::shared_ptr stdout_logger_st(const std::string &logger_name); 69 | 70 | template 71 | std::shared_ptr stderr_logger_mt(const std::string &logger_name); 72 | 73 | template 74 | std::shared_ptr stderr_logger_st(const std::string &logger_name); 75 | 76 | } // namespace spdlog 77 | 78 | #ifdef SPDLOG_HEADER_ONLY 79 | #include "stdout_sinks-inl.h" 80 | #endif 81 | -------------------------------------------------------------------------------- /src/spdlog/sinks/syslog_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /** 17 | * Sink that write to syslog using the `syscall()` library call. 18 | */ 19 | template 20 | class syslog_sink : public base_sink 21 | { 22 | 23 | public: 24 | syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) 25 | : enable_formatting_{enable_formatting} 26 | , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, 27 | /* spdlog::level::debug */ LOG_DEBUG, 28 | /* spdlog::level::info */ LOG_INFO, 29 | /* spdlog::level::warn */ LOG_WARNING, 30 | /* spdlog::level::err */ LOG_ERR, 31 | /* spdlog::level::critical */ LOG_CRIT, 32 | /* spdlog::level::off */ LOG_INFO}} 33 | , ident_{std::move(ident)} 34 | { 35 | // set ident to be program name if empty 36 | ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); 37 | } 38 | 39 | ~syslog_sink() override 40 | { 41 | ::closelog(); 42 | } 43 | 44 | syslog_sink(const syslog_sink &) = delete; 45 | syslog_sink &operator=(const syslog_sink &) = delete; 46 | 47 | protected: 48 | void sink_it_(const details::log_msg &msg) override 49 | { 50 | string_view_t payload; 51 | memory_buf_t formatted; 52 | if (enable_formatting_) 53 | { 54 | base_sink::formatter_->format(msg, formatted); 55 | payload = string_view_t(formatted.data(), formatted.size()); 56 | } 57 | else 58 | { 59 | payload = msg.payload; 60 | } 61 | 62 | size_t length = payload.size(); 63 | // limit to max int 64 | if (length > static_cast(std::numeric_limits::max())) 65 | { 66 | length = static_cast(std::numeric_limits::max()); 67 | } 68 | 69 | ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast(length), payload.data()); 70 | } 71 | 72 | void flush_() override {} 73 | bool enable_formatting_ = false; 74 | 75 | private: 76 | using levels_array = std::array; 77 | levels_array syslog_levels_; 78 | // must store the ident because the man says openlog might use the pointer as 79 | // is and not a string copy 80 | const std::string ident_; 81 | 82 | // 83 | // Simply maps spdlog's log level to syslog priority level. 84 | // 85 | int syslog_prio_from_level(const details::log_msg &msg) const 86 | { 87 | return syslog_levels_.at(static_cast(msg.level)); 88 | } 89 | }; 90 | 91 | using syslog_sink_mt = syslog_sink; 92 | using syslog_sink_st = syslog_sink; 93 | } // namespace sinks 94 | 95 | // Create and register a syslog logger 96 | template 97 | inline std::shared_ptr syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, 98 | int syslog_facility = LOG_USER, bool enable_formatting = false) 99 | { 100 | return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); 101 | } 102 | 103 | template 104 | inline std::shared_ptr syslog_logger_st(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, 105 | int syslog_facility = LOG_USER, bool enable_formatting = false) 106 | { 107 | return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); 108 | } 109 | } // namespace spdlog 110 | -------------------------------------------------------------------------------- /src/spdlog/sinks/systemd_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #ifndef SD_JOURNAL_SUPPRESS_LOCATION 12 | #define SD_JOURNAL_SUPPRESS_LOCATION 13 | #endif 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | 19 | /** 20 | * Sink that write to systemd journal using the `sd_journal_send()` library call. 21 | * 22 | * Locking is not needed, as `sd_journal_send()` itself is thread-safe. 23 | */ 24 | template 25 | class systemd_sink : public base_sink 26 | { 27 | public: 28 | // 29 | systemd_sink() 30 | : syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, 31 | /* spdlog::level::debug */ LOG_DEBUG, 32 | /* spdlog::level::info */ LOG_INFO, 33 | /* spdlog::level::warn */ LOG_WARNING, 34 | /* spdlog::level::err */ LOG_ERR, 35 | /* spdlog::level::critical */ LOG_CRIT, 36 | /* spdlog::level::off */ LOG_INFO}} 37 | {} 38 | 39 | ~systemd_sink() override {} 40 | 41 | systemd_sink(const systemd_sink &) = delete; 42 | systemd_sink &operator=(const systemd_sink &) = delete; 43 | 44 | protected: 45 | using levels_array = std::array; 46 | levels_array syslog_levels_; 47 | 48 | void sink_it_(const details::log_msg &msg) override 49 | { 50 | int err; 51 | 52 | size_t length = msg.payload.size(); 53 | // limit to max int 54 | if (length > static_cast(std::numeric_limits::max())) 55 | { 56 | length = static_cast(std::numeric_limits::max()); 57 | } 58 | 59 | // Do not send source location if not available 60 | if (msg.source.empty()) 61 | { 62 | // Note: function call inside '()' to avoid macro expansion 63 | err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), 64 | "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), nullptr); 65 | } 66 | else 67 | { 68 | err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), 69 | "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), "CODE_FILE=%s", 70 | msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); 71 | } 72 | 73 | if (err) 74 | { 75 | throw_spdlog_ex("Failed writing to systemd", errno); 76 | } 77 | } 78 | 79 | int syslog_level(level::level_enum l) 80 | { 81 | return syslog_levels_.at(static_cast(l)); 82 | } 83 | 84 | void flush_() override {} 85 | }; 86 | 87 | using systemd_sink_mt = systemd_sink; 88 | using systemd_sink_st = systemd_sink; 89 | } // namespace sinks 90 | 91 | // Create and register a syslog logger 92 | template 93 | inline std::shared_ptr systemd_logger_mt(const std::string &logger_name) 94 | { 95 | return Factory::template create(logger_name); 96 | } 97 | 98 | template 99 | inline std::shared_ptr systemd_logger_st(const std::string &logger_name) 100 | { 101 | return Factory::template create(logger_name); 102 | } 103 | } // namespace spdlog 104 | -------------------------------------------------------------------------------- /src/spdlog/sinks/tcp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #pragma once 21 | 22 | // Simple tcp client sink 23 | // Connects to remote address and send the formatted log. 24 | // Will attempt to reconnect if connection drops. 25 | // If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. 26 | 27 | namespace spdlog { 28 | namespace sinks { 29 | 30 | struct tcp_sink_config 31 | { 32 | std::string server_host; 33 | int server_port; 34 | bool lazy_connect = false; // if true connect on first log call instead of on construction 35 | 36 | tcp_sink_config(std::string host, int port) 37 | : server_host{std::move(host)} 38 | , server_port{port} 39 | {} 40 | }; 41 | 42 | template 43 | class tcp_sink : public spdlog::sinks::base_sink 44 | { 45 | public: 46 | // connect to tcp host/port or throw if failed 47 | // host can be hostname or ip address 48 | 49 | explicit tcp_sink(tcp_sink_config sink_config) 50 | : config_{std::move(sink_config)} 51 | { 52 | if (!config_.lazy_connect) 53 | { 54 | this->client_.connect(config_.server_host, config_.server_port); 55 | } 56 | } 57 | 58 | ~tcp_sink() override = default; 59 | 60 | protected: 61 | void sink_it_(const spdlog::details::log_msg &msg) override 62 | { 63 | spdlog::memory_buf_t formatted; 64 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 65 | if (!client_.is_connected()) 66 | { 67 | client_.connect(config_.server_host, config_.server_port); 68 | } 69 | client_.send(formatted.data(), formatted.size()); 70 | } 71 | 72 | void flush_() override {} 73 | tcp_sink_config config_; 74 | details::tcp_client client_; 75 | }; 76 | 77 | using tcp_sink_mt = tcp_sink; 78 | using tcp_sink_st = tcp_sink; 79 | 80 | } // namespace sinks 81 | } // namespace spdlog 82 | -------------------------------------------------------------------------------- /src/spdlog/sinks/wincolor_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | /* 22 | * Windows color console sink. Uses WriteConsoleA to write to the console with 23 | * colors 24 | */ 25 | template 26 | class wincolor_sink : public sink 27 | { 28 | public: 29 | const WORD BOLD = FOREGROUND_INTENSITY; 30 | const WORD RED = FOREGROUND_RED; 31 | const WORD GREEN = FOREGROUND_GREEN; 32 | const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; 33 | const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 34 | const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; 35 | 36 | wincolor_sink(HANDLE out_handle, color_mode mode); 37 | ~wincolor_sink() override; 38 | 39 | wincolor_sink(const wincolor_sink &other) = delete; 40 | wincolor_sink &operator=(const wincolor_sink &other) = delete; 41 | 42 | // change the color for the given level 43 | void set_color(level::level_enum level, WORD color); 44 | void log(const details::log_msg &msg) final override; 45 | void flush() final override; 46 | void set_pattern(const std::string &pattern) override final; 47 | void set_formatter(std::unique_ptr sink_formatter) override final; 48 | void set_color_mode(color_mode mode); 49 | 50 | protected: 51 | using mutex_t = typename ConsoleMutex::mutex_t; 52 | HANDLE out_handle_; 53 | mutex_t &mutex_; 54 | bool in_console_; 55 | bool should_do_colors_; 56 | std::unique_ptr formatter_; 57 | std::array colors_; 58 | 59 | // set foreground color and return the orig console attributes (for resetting later) 60 | WORD set_foreground_color_(WORD attribs); 61 | 62 | // print a range of formatted message to console 63 | void print_range_(const memory_buf_t &formatted, size_t start, size_t end); 64 | 65 | // in case we are redirected to file (not in console mode) 66 | void write_to_file_(const memory_buf_t &formatted); 67 | }; 68 | 69 | template 70 | class wincolor_stdout_sink : public wincolor_sink 71 | { 72 | public: 73 | explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); 74 | }; 75 | 76 | template 77 | class wincolor_stderr_sink : public wincolor_sink 78 | { 79 | public: 80 | explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); 81 | }; 82 | 83 | using wincolor_stdout_sink_mt = wincolor_stdout_sink; 84 | using wincolor_stdout_sink_st = wincolor_stdout_sink; 85 | 86 | using wincolor_stderr_sink_mt = wincolor_stderr_sink; 87 | using wincolor_stderr_sink_st = wincolor_stderr_sink; 88 | 89 | } // namespace sinks 90 | } // namespace spdlog 91 | 92 | #ifdef SPDLOG_HEADER_ONLY 93 | #include "wincolor_sink-inl.h" 94 | #endif 95 | -------------------------------------------------------------------------------- /src/spdlog/spdlog-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) 16 | { 17 | details::registry::instance().initialize_logger(std::move(logger)); 18 | } 19 | 20 | SPDLOG_INLINE std::shared_ptr get(const std::string &name) 21 | { 22 | return details::registry::instance().get(name); 23 | } 24 | 25 | SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) 26 | { 27 | details::registry::instance().set_formatter(std::move(formatter)); 28 | } 29 | 30 | SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) 31 | { 32 | set_formatter(std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); 33 | } 34 | 35 | SPDLOG_INLINE void enable_backtrace(size_t n_messages) 36 | { 37 | details::registry::instance().enable_backtrace(n_messages); 38 | } 39 | 40 | SPDLOG_INLINE void disable_backtrace() 41 | { 42 | details::registry::instance().disable_backtrace(); 43 | } 44 | 45 | SPDLOG_INLINE void dump_backtrace() 46 | { 47 | default_logger_raw()->dump_backtrace(); 48 | } 49 | 50 | SPDLOG_INLINE void set_level(level::level_enum log_level) 51 | { 52 | details::registry::instance().set_level(log_level); 53 | } 54 | 55 | SPDLOG_INLINE void flush_on(level::level_enum log_level) 56 | { 57 | details::registry::instance().flush_on(log_level); 58 | } 59 | 60 | SPDLOG_INLINE void flush_every(std::chrono::seconds interval) 61 | { 62 | details::registry::instance().flush_every(interval); 63 | } 64 | 65 | SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) 66 | { 67 | details::registry::instance().set_error_handler(handler); 68 | } 69 | 70 | SPDLOG_INLINE void register_logger(std::shared_ptr logger) 71 | { 72 | details::registry::instance().register_logger(std::move(logger)); 73 | } 74 | 75 | SPDLOG_INLINE void apply_all(const std::function)> &fun) 76 | { 77 | details::registry::instance().apply_all(fun); 78 | } 79 | 80 | SPDLOG_INLINE void drop(const std::string &name) 81 | { 82 | details::registry::instance().drop(name); 83 | } 84 | 85 | SPDLOG_INLINE void drop_all() 86 | { 87 | details::registry::instance().drop_all(); 88 | } 89 | 90 | SPDLOG_INLINE void shutdown() 91 | { 92 | details::registry::instance().shutdown(); 93 | } 94 | 95 | SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) 96 | { 97 | details::registry::instance().set_automatic_registration(automatic_registration); 98 | } 99 | 100 | SPDLOG_INLINE std::shared_ptr default_logger() 101 | { 102 | return details::registry::instance().default_logger(); 103 | } 104 | 105 | SPDLOG_INLINE spdlog::logger *default_logger_raw() 106 | { 107 | return details::registry::instance().get_default_raw(); 108 | } 109 | 110 | SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) 111 | { 112 | details::registry::instance().set_default_logger(std::move(default_logger)); 113 | } 114 | 115 | } // namespace spdlog -------------------------------------------------------------------------------- /src/spdlog/version.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define SPDLOG_VER_MAJOR 1 7 | #define SPDLOG_VER_MINOR 7 8 | #define SPDLOG_VER_PATCH 0 9 | 10 | #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) 11 | -------------------------------------------------------------------------------- /src/wav.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define WAV_SIGNATURE "RIFF" 6 | #define WAV_TYPE "WAVE" 7 | #define WAV_FORMAT_MARK "fmt " 8 | #define WAV_DATA_MARK "data" 9 | #define WAV_SAMPLE_TYPE_PCM 1 10 | 11 | class WavWriter { 12 | public: 13 | WavWriter(std::string path, uint16_t bitDepth, uint16_t channelCount, uint32_t sampleRate) { 14 | file = std::ofstream(path.c_str(), std::ios::binary); 15 | memcpy(hdr.signature, WAV_SIGNATURE, 4); 16 | memcpy(hdr.fileType, WAV_TYPE, 4); 17 | memcpy(hdr.formatMarker, WAV_FORMAT_MARK, 4); 18 | memcpy(hdr.dataMarker, WAV_DATA_MARK, 4); 19 | hdr.formatHeaderLength = 16; 20 | hdr.sampleType = WAV_SAMPLE_TYPE_PCM; 21 | hdr.channelCount = channelCount; 22 | hdr.sampleRate = sampleRate; 23 | hdr.bytesPerSecond = (bitDepth / 8) * channelCount * sampleRate; 24 | hdr.bytesPerSample = (bitDepth / 8) * channelCount; 25 | hdr.bitDepth = bitDepth; 26 | file.write((char*)&hdr, sizeof(WavHeader_t)); 27 | } 28 | 29 | void writeSamples(void* data, size_t size) { 30 | file.write((char*)data, size); 31 | bytesWritten += size; 32 | } 33 | 34 | void close() { 35 | hdr.fileSize = bytesWritten + sizeof(WavHeader_t) - 8; 36 | hdr.dataSize = bytesWritten; 37 | file.seekp(0); 38 | file.write((char*)&hdr, sizeof(WavHeader_t)); 39 | file.close(); 40 | } 41 | 42 | private: 43 | struct WavHeader_t { 44 | char signature[4]; // "RIFF" 45 | uint32_t fileSize; // data bytes + sizeof(WavHeader_t) - 8 46 | char fileType[4]; // "WAVE" 47 | char formatMarker[4]; // "fmt " 48 | uint32_t formatHeaderLength; // Always 16 49 | uint16_t sampleType; // PCM (1) 50 | uint16_t channelCount; 51 | uint32_t sampleRate; 52 | uint32_t bytesPerSecond; 53 | uint16_t bytesPerSample; 54 | uint16_t bitDepth; 55 | char dataMarker[4]; // "data" 56 | uint32_t dataSize; 57 | }; 58 | 59 | std::ofstream file; 60 | size_t bytesWritten = 0; 61 | WavHeader_t hdr; 62 | }; -------------------------------------------------------------------------------- /src/wavreader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | 8 | #define WAV_SIGNATURE "RIFF" 9 | #define WAV_TYPE "WAVE" 10 | #define WAV_FORMAT_MARK "fmt " 11 | #define WAV_DATA_MARK "data" 12 | #define WAV_SAMPLE_TYPE_PCM 1 13 | 14 | class WavReader { 15 | public: 16 | WavReader(std::string path) { 17 | file = std::ifstream(path.c_str(), std::ios::binary); 18 | file.read((char*)&hdr, sizeof(WavHeader_t)); 19 | valid = false; 20 | if (memcmp(hdr.signature, "RIFF", 4) != 0) { return; } 21 | if (memcmp(hdr.fileType, "WAVE", 4) != 0) { return; } 22 | valid = true; 23 | } 24 | 25 | uint16_t getBitDepth() { 26 | return hdr.bitDepth; 27 | } 28 | 29 | uint16_t getChannelCount() { 30 | return hdr.channelCount; 31 | } 32 | 33 | uint32_t getSampleRate() { 34 | return hdr.sampleRate; 35 | } 36 | 37 | bool isValid() { 38 | return valid; 39 | } 40 | 41 | void readSamples(void* data, size_t size) { 42 | char* _data = (char*)data; 43 | file.read(_data, size); 44 | int read = file.gcount(); 45 | if (read < size) { 46 | file.seekg(sizeof(WavHeader_t)); 47 | file.read(&_data[read], size - read); 48 | } 49 | bytesRead += size; 50 | } 51 | 52 | void rewind() { 53 | file.seekg(sizeof(WavHeader_t)); 54 | } 55 | 56 | void close() { 57 | file.close(); 58 | } 59 | 60 | struct WavHeader_t { 61 | char signature[4]; // "RIFF" 62 | uint32_t fileSize; // data bytes + sizeof(WavHeader_t) - 8 63 | char fileType[4]; // "WAVE" 64 | char formatMarker[4]; // "fmt " 65 | uint32_t formatHeaderLength; // Always 16 66 | uint16_t sampleType; // PCM (1) 67 | uint16_t channelCount; 68 | uint32_t sampleRate; 69 | uint32_t bytesPerSecond; 70 | uint16_t bytesPerSample; 71 | uint16_t bitDepth; 72 | char dataMarker[4]; // "data" 73 | uint32_t dataSize; 74 | }; 75 | 76 | WavHeader_t hdr; 77 | 78 | private: 79 | 80 | 81 | bool valid = false; 82 | std::ifstream file; 83 | size_t bytesRead = 0; 84 | 85 | }; --------------------------------------------------------------------------------