首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASCII图形波形发生器

ASCII图形波形发生器
EN

Code Review用户
提问于 2015-04-27 16:13:35
回答 2查看 2.3K关注 0票数 10

最近在编写一些文档时,我需要将许多异步串行波形转换为ASCII图形字符。我决定写一个程序来帮我画,而不是用手画。我对代码回顾感兴趣,尤其是如果有更聪明/更短的方法来编写类的话。

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <string>
#include <bitset>

class waveform
{
public:
    waveform(std::string &s) : data_(s) {}
    std::vector<bool> to_bits() const
    {
        std::vector<bool> bits;
        bits.reserve(data_.size() * 10);
        for (auto &ch : data_) {
            bits.push_back(0); // start bit
            for (int mask=1u; mask != 0x100; mask <<= 1) {
                bits.push_back(ch & mask);
            }
            bits.push_back(1); // stop bit
        }
        return bits;
    }
    friend std::ostream& operator<<(std::ostream& out, const waveform& w) {
        auto bits = w.to_bits();
        bool last = 1;
        for (const auto &b : bits) {
            out << (b ? "+---" : (last ? "+   " : "    "));
            last = b;
        }
        out << '\n';
        last = 1;
        for (const auto &b : bits) {
            out << (b != last ? "|   " : "    ");
            last = b;
        }
        out << '\n';
        last = 1;
        for (const auto &b : bits) {
            out << (b ? (last ? "    " : "+   ") : "+---");
            last = b;
        }
        out << '\n';
        int special = 0x201;
        for (const auto &b : bits) {
            if (special & 1) {
                out << (b ? "  P " : "  S ");
            } else {
                out << (b ? "  1 " : "  0 ");
            }
            special >>= 1;
            if (special == 0)
                special = 0x201;
        }
        out << '\n';
        return out;
    }
private:
    std::string data_;
};

示例驱动程序

代码语言:javascript
复制
int main()
{
    std::string msg{"ST"};
    std::cout << waveform(msg) << std::endl;
}

样本输出

代码语言:javascript
复制
+   +---+---+       +---+   +---+   +---+           +---+   +---+   +---+   +---
|   |       |       |   |   |   |   |   |           |   |   |   |   |   |   |   
+---+       +---+---+   +---+   +---+   +---+---+---+   +---+   +---+   +---+   
  S   1   1   0   0   1   0   1   0   P   S   0   0   1   0   1   0   1   0   P 

注意,在这个图中,S代表一个开始位,P代表一个停止位,而8个数据位首先被发送到最不重要的位。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-04-28 03:46:41

OOP的设计似乎对你没有多大帮助。感觉就像你只需要一个函数就能得到基本相同的效果。另一方面,operator<<方法基本上是一个状态机,它看起来比需要的要麻烦一些。这里有复制和粘贴代码,各地都有ASCII的一些艺术,还有一台使用神奇数字0x201的迷你图灵机。

假设to_bits()助手函数对您不重要(我假设它并不那么重要,因为您编写了#include <bitset>然后改变了主意),您可以通过定义一个过滤输出流来做得更好。下面是我试图实现这样一件事的尝试:

代码语言:javascript
复制
#include <climits>
#include <iostream>
#include <sstream>
#include <streambuf>
#include <string>

class waveform_ostream : public std::streambuf
{
public:
    explicit waveform_ostream(std::ostream &sink) : sink(sink) {}

protected:
    // Accept a byte of data
    virtual std::streambuf::int_type overflow(std::streambuf::int_type c) {
        output_bit(0, 'S');             // Start bit
        for (int i = 0; i < CHAR_BIT; ++i) {
            output_bit((c >> i) & 1);   // Data bits, LSB first
        }
        output_bit(1, 'P');             // Stop bit
        return c;
    }

    // Flush
    int sync() {
        for (int row = 0; row < 4; ++row) {
            std::string s = lines[row]->str();
            sink << s << '\n';
            lines[row]->str("");
        }
        sink << std::flush;
        return 0;   // success
    }

private:
    bool state = 1;
    std::ostream &sink;
    std::stringstream level[2], risefall, captions;
    std::stringstream *const lines[4] = {
        &level[1],
        &risefall,
        &level[0],
        &captions
    };

    void output_bit(bool b, char caption='\0') {
        level[!b] << ((b == state) ? "    " : "+   ");
        risefall  << ((b == state) ? "    " : "|   ");
        level[ b] <<                          "+---";
        captions  << "  " << (char)(caption ? caption : b ? '1' : '0') << ' ';
        state = b;
    }
};

int main()
{
    waveform_ostream wout(std::cout);
    std::ostream out(&wout);
    out << std::string("ST") << std::flush;
}
票数 4
EN

Code Review用户

发布于 2015-04-28 14:38:23

我不太喜欢原来的,所以我改变了一些东西,并制作了这个新版本。它允许可变数量的数据位和停止位,并且结构更好。每一行分别生成,图像使用两位查找表进行选择.

波形h

代码语言:javascript
复制
#ifndef WAVEFORM_H
#define WAVEFORM_H

#include <iostream>
#include <iomanip>
#include <vector>
#include <string>

namespace WAVE {
class Waveform
{
public:
    Waveform(std::string &s, int bits=8, int stopbits=1);
    std::size_t bits_per_char() const { return 1 + bits_ + stop_; }
    std::vector<bool> to_bits() const;
    void graphics_line(std::ostream& out, const std::vector<bool>& bits, int linenum) const;
    void bitlabel_line(std::ostream& out, const std::vector<bool>& bits) const;
    friend std::ostream& operator<<(std::ostream& out, const Waveform& w) {
        auto bits = w.to_bits();
        for (int i=0; i < 3; ++i)
            w.graphics_line(out, bits, i);
        w.bitlabel_line(out, bits);
        for (const auto &ch: w.data_) {
            out 
                << std::setw(2*w.bits_per_char()) << "0x" << std::hex 
                << static_cast<unsigned>(ch & 0xff)
                << std::setw(2*w.bits_per_char()-2) << ' ';
        }
        return out;
    }
private:
    std::string data_;
    int bits_;
    int stop_;
};
}
#endif //WAVEFORM_H

Waveform.cpp

代码语言:javascript
复制
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include "Waveform.h"

namespace WAVE {
Waveform::Waveform(std::string &s, int bits, int stopbits) 
    : data_(s), bits_(bits), stop_(stopbits) 
{
}

std::vector<bool> Waveform::to_bits() const
{
    std::vector<bool> bits;
    bits.reserve(data_.size() * bits_per_char());
    for (auto &ch : data_) {
        bits.push_back(0); // start bit
        for (int i=bits_, c=ch; i; --i) {
            bits.push_back(c & 1);
            c >>= 1;
        }
        for (int i=stop_; i; --i) {
            bits.push_back(1); // stop bit
        }
    }
    return bits;
}

void Waveform::graphics_line(std::ostream& out, const std::vector<bool>& bits, int linenum) const 
{
    static const char* graphic[3][4]{
        // 00      01      10      11
        {"    ", "+---", "+   ", "+---"}, 
        {"    ", "|   ", "|   ", "    "},
        {"+---", "+   ", "+---", "    "}
    };
    int last = 2;   // assume previous bit was 1
    for (const auto &b : bits) {
        last |= b;
        out << graphic[linenum][last];
        last = (last << 1) & 0x3;
    }
    out << '\n';
}

void Waveform::bitlabel_line(std::ostream& out, const std::vector<bool>& bits) const 
{
    enum states { START, DATA, STOP } state = START;
    int bitcount = bits_;
    for (unsigned i=0; i < bits.size(); ++i) {
        switch (state) {
            case START:
                out << (bits[i] ? " SE " : "  S ");
                state = DATA;
                break;
            case DATA:
                out << (bits[i] ? "  1 " : "  0 ");
                if (--bitcount == 0) {
                    bitcount = stop_;
                    state = STOP;
                }
                break;
            case STOP:
                out << (bits[i] ? "  P " : " EP ");
                if (--bitcount == 0) {
                    bitcount = bits_;
                    state = START;
                }
                break;
        }
    }
    out << '\n';
}
}

test.cpp

代码语言:javascript
复制
#include <iostream>
#include "Waveform.h"
using namespace std;

int main()
{
    string msg{"ST"};
    WAVE::Waveform wave = WAVE::Waveform(msg);
    WAVE::Waveform wave2{wave};
    cout << wave << endl;
    cout << WAVE::Waveform(msg,7,1) << endl;
    cout << WAVE::Waveform(msg,7,2) << endl;
    auto bits = wave2.to_bits();
    for (bool b : bits)
        cout << b;
    cout << endl;
}

输出

代码语言:javascript
复制
+   +---+---+       +---+   +---+   +---+           +---+   +---+   +---+   +---
|   |       |       |   |   |   |   |   |           |   |   |   |   |   |   |   
+---+       +---+---+   +---+   +---+   +---+---+---+   +---+   +---+   +---+   
  S   1   1   0   0   1   0   1   0   P   S   0   0   1   0   1   0   1   0   P 
                  0x53                                      0x54                    
+   +---+---+       +---+   +---+---+           +---+   +---+   +---+---
|   |       |       |   |   |       |           |   |   |   |   |       
+---+       +---+---+   +---+       +---+---+---+   +---+   +---+       
  S   1   1   0   0   1   0   1   P   S   0   0   1   0   1   0   1   P 
                0x53                                  0x54                  
+   +---+---+       +---+   +---+---+---+           +---+   +---+   +---+---+---
|   |       |       |   |   |           |           |   |   |   |   |           
+---+       +---+---+   +---+           +---+---+---+   +---+   +---+           
  S   1   1   0   0   1   0   1   P   P   S   0   0   1   0   1   0   1   P   P 
                  0x53                                      0x54                    
01100101010001010101
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/88148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档