TEMPEST HDMI泄漏接收 2

我后来找到了gr-tempest包,它基于gnuradio重置了tempestsdr,由于是gnuradio,比较方便我本地安装,因此我跑了一下,结果没跑出实际效果,可能因为它默认用usrp,我这用的是hackrf+重采样,硬件不太一样导致的。但是它里面还有个simulate的流图,可以导入图片再重新解出来。这个我玩成功了,通过调试,我发现在不同sample correction时,会出现类似第一篇文章的样子,也会出现比较像样的画面。所以我的信心大增。

后来我还是决定在我以前的c++/hackrf实现的模拟视频解调程序里试试。果然试成了,主要秘诀在于要去掉模拟视频解调里的各种同步,去掉隔行扫描,然后再耐心调整行宽,最后为了效果好一些,不乱跳,建议再人为限制刷新间隔。

下面就是我的代码:

#include <iostream>
#include <signal.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <libhackrf/hackrf.h>
#include <pthread.h>
#include <unistd.h>
#include <string>
#include <sstream>

using namespace std;
using namespace cv;

int decimate_rate = 1;
//#define original_width_x_height 65100

static volatile bool do_exit = false;
int result;
static hackrf_device* device = NULL;
double sample_rate_hz = 6e6/decimate_rate * 1.951047  ;
double baseband_filter_bw_hz =  1e6 ;
double freq_hz = 395.991*1000000;

Mat frame;
int x = 0;
int y = 0;
int correctX = 0;
int correctY = 0;
int autoCorrectX = 0;
int autoCorrectY = 0;

int width = 2081; //multiple of 347 like 2081 or 1387
int height = 800;

int original_width = width / decimate_rate;
int original_width_x_height = original_width * height;
int inverseVideo = 1;

double maxSignalLevel = 0;
double blackLevel = 0;
double coeff = 0;
double agcSignalLevel = 0;
int pixelCounter = 0;
double contrast = 40;
double bright = 40;

int delay_count = 0;

bool bufferIsFull = false;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

//double grayScaleValues[original_width_x_height];
double grayScaleValues[2000000];

void sigint_callback_handler(int signum) 
{
	cout << "Caught signal" << endl;
	do_exit = true;
}

void draw_pixel(double mag)
{
    if (x >= original_width)
    {
        y += 1;
        x = 0;
    }
    if (y >= height)
    {
        y = 0;
        delay_count++;
        if (delay_count > 3)
        {
            bufferIsFull = true;
            delay_count = 0;
        }
    }

    double num2 = (blackLevel - mag) * coeff * contrast;
    num2 += bright;
    if (num2 > 255)
    {
        num2 = 255;
    }
    if (num2 < 0)
    {
        num2 = 0;
    }
    
    int num = y % height * original_width + x % original_width;
    grayScaleValues[num] = num2;

    x = x + 1;
}
int rx_callback(hackrf_transfer* transfer)
{
    double im, re, mag;
    double num = 0;
    double num2 = 0;
    
    double compare_re;
    for( uint32_t i = 0; i <  transfer->valid_length; i += 2)
    {
        // int8_t(transfer->buffer[i]) -128~127
        
        im = (int8_t(transfer->buffer[i]))/128.0;
        re = (int8_t(transfer->buffer[i + 1]))/128.0;

        compare_re = abs(int8_t(transfer->buffer[i+1])) ;
        if (compare_re > num) 
        {
            num = compare_re;
        }
        
        double mag = sqrt( im * im + re * re);  //mag 0~1.414

        if (mag > num2)
        {
            num2 = mag;
        }
        if (inverseVideo)
        {
            mag = maxSignalLevel - mag;
        }

        pthread_mutex_lock(&mtx);
        draw_pixel(mag);
        pthread_mutex_unlock(&mtx);
        //grey of opencv is 0~255
        //0 is black 255 is white
    } 
    
    maxSignalLevel = maxSignalLevel * 0.9 + num2 * 0.1;
    blackLevel = maxSignalLevel * 0.4;
    coeff = 255 / blackLevel;
    agcSignalLevel = num;

    return 0;
}

void *receiving_function(void *arg)
{ 
    while (do_exit == false)
    {
        sleep(1);
    }
    cout << "Thread Exiting..." << endl;
    pthread_exit(NULL);
}

int main()
{
    pthread_t recv_th;

    signal(SIGINT, &sigint_callback_handler);

    frame = Mat::zeros(height, width, CV_8UC1);

    result = hackrf_init();
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_init() failed" << endl;
        return EXIT_FAILURE;
    }
    result = hackrf_open(&device);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_open() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_sample_rate(device, sample_rate_hz);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_sample_rate() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz);
    if( result != HACKRF_SUCCESS )
    {
        cout << "hackrf_baseband_filter_bandwidth_set() failed" << endl;
        return EXIT_FAILURE;
    }
    
    result = hackrf_set_freq(device, freq_hz);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_freq() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_lna_gain(device, 40);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_lna_gain() failed" << endl;
        return EXIT_FAILURE;
    }

    result = hackrf_set_vga_gain(device, 26);
    if( result != HACKRF_SUCCESS ) 
    {
        cout << "hackrf_set_vga_gain() failed" << endl;
        return EXIT_FAILURE;
    }
    
    int err = pthread_create(&recv_th, NULL, receiving_function, NULL);
    if (err != 0)
    {
        cout << "Create thread failed" << endl;
    }
    
    result = hackrf_start_rx(device, rx_callback, NULL); 

    while( (hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false) ) 
    {
        if (bufferIsFull)
        {
            pthread_mutex_lock(&mtx);
            for (int counter = 0; counter < original_width_x_height; counter++)
            {
                int new_x = counter % original_width;
                int new_y = counter / original_width;
                 

                for (int c = 0; c < decimate_rate; c++)
                {
                    frame.at<uchar>(new_y, new_x*decimate_rate + c) =  grayScaleValues[counter];
                }
                grayScaleValues[counter] = 0;
            }   
        
            bufferIsFull = false;
            pthread_mutex_unlock(&mtx);
        }
        imshow("frame", frame);

        if (waitKey(5) == 'q')
        {
            do_exit = true;
            break;
        }
    }

    if (do_exit)
    {
	cout << "Exiting..." << endl;
    }

    result = hackrf_close(device);
    if(result != HACKRF_SUCCESS)
    {
        cout << "hackrf_close() failed" << endl;
    } 
    else 
    {
        cout << "hackrf_close() done" << endl;
    }

    hackrf_exit();
    cout << "hackrf_exit() done" << endl;
    
    pthread_join(recv_th,NULL);
    return 0;
}

下面是编译用的命令:

g++ hackrf_tv_hdmi.cpp -o hackrf_tv_hdmi `pkg-config --cflags --libs opencv` -lhackrf -pthread

感兴趣的朋友可以试一下,我的显示器设置为1920x1080 60Hz。你的可能频点和我不一样。

目前这个c++版本代码肯定比tempestsdr简单好多,但是仍然不是最简化的,里面有不少我做模拟视频解调时的冗余代码。等我有时间再整理为python版本。

实测效果:

SDR接收HDMI泄露信号2 程序优化和泄漏源查找_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1sr4y1G7oL

猜你喜欢

转载自blog.csdn.net/shukebeta008/article/details/125438189