Portapack应用开发教程(十四) SSTV发射机增加robot8

前两天我成功用电脑上的gnuradio流图发射了robot8格式的信号,并且用portapack解调出了图片,但是这样还是不太方便,我在想用Portapack发射robot8的格式,用另一个来收。

但是目前portapack的sstv发射不支持robot8制式。

所以我想到基于它修改,分为2步,先是要确保portapack能从tf卡上读到黑白的bmp图片。

第一步很容易搞定,只要让它不要读3个数字作为一个像素点RGB,而是每个值都是一个像素点亮度就行。只要改firmware/application/app/ui_sstvtx.cpp就行。

void SSTVTXView::paint(Painter&) {
	ui::Color line_buffer[240];
	Coord line;
	uint32_t data_idx, bmp_px, pixel_idx;
	
	data_idx = bmp_header.image_data;
	for (line = 0; line < 140; line++) {
		// Buffer a whole line
		for (bmp_px = 0; bmp_px < 160; bmp_px++) {
			line_buffer[bmp_px] = Color(0,0,0);
		}
		portapack::display.render_line({ 16, 95 + 128 - line }, 160, line_buffer);
	}

	if (options_grey.value() == 0) {
		for (line = 0; line < (256 / 2); line++) {
		
			// Buffer a whole line
			read_boundary(pixels_buffer, data_idx, sizeof(pixels_buffer));
		
			for (bmp_px = 0; bmp_px < 160; bmp_px++) {
				pixel_idx = bmp_px * 3 * 2;
				line_buffer[bmp_px] = Color(pixels_buffer[pixel_idx + 2],
										pixels_buffer[pixel_idx + 1],
										pixels_buffer[pixel_idx + 0]);
			}
			portapack::display.render_line({ 16, 95 + 128 - line }, 160, line_buffer);
			data_idx += sizeof(pixels_buffer) * 2;
		}
	}
	else if (options_grey.value() == 1){
		for (line = 0; line < 140; line=line+2) {
		
			// Buffer a whole line
			read_boundary(pixels_buffer_grey, data_idx, sizeof(pixels_buffer_grey));
		
			for (bmp_px = 0; bmp_px < 140; bmp_px++) {
				pixel_idx = bmp_px * 2; //both *1 or *2 would work
				line_buffer[bmp_px] = spectrum_rgb4_lut[pixels_buffer_grey[pixel_idx]];
			}
			portapack::display.render_line({ 16, 95 + 128 - line }, 140, line_buffer);
			portapack::display.render_line({ 16, 95 + 127 - line }, 140, line_buffer);
			data_idx += sizeof(pixels_buffer_grey) * 2; //both *1 or *2 would work
		}
	}
}

第二步,我又分为2小步。(firmware/application/app/ui_sstvtx.cpp firmware/baseband/proc_sstvtx.cpp firmware/common/sstv.hpp)

先是用martin m1发射彩色图片,我发现这时候portapack也能收到图像,把rgb中的一个颜色通道当作黑白值显示出来了。

接下来我慢慢把martin m1改为robot8的参数,每改动一步观察一下图像是否还能在portapack接收端成功解出来。

ui_sstvtx.cpp


void SSTVTXView::prepare_scanline() {
	sstv_scanline scanline_buffer;
	uint32_t component, pixel_idx;
	uint8_t offset;
	
	if (options_grey.value() == 0) {
		if (scanline_counter >= (256 * 3)) {
			progressbar.set_value(0);
			transmitter_model.disable();
			options_bitmaps.set_focusable(true);
			tx_view.set_transmitting(false);
			return;
		}
	
		progressbar.set_value(scanline_counter);
		component = scanline_counter % 3;
	
		if ((!scanline_counter && tx_sstv_mode->sync_on_first) || (component == tx_sstv_mode->sync_index)) {
			// Sync
			scanline_buffer.start_tone.frequency = SSTV_F2D(1200);
			scanline_buffer.start_tone.duration = tx_sstv_mode->samples_per_sync;
			scanline_buffer.gap_tone.frequency = SSTV_F2D(1500);
			scanline_buffer.gap_tone.duration = tx_sstv_mode->samples_per_gap;
		} else {
			// Regular scanline
			scanline_buffer.start_tone.duration = 0;
			if (tx_sstv_mode->gaps) {
				scanline_buffer.gap_tone.frequency = SSTV_F2D(1500);
				scanline_buffer.gap_tone.duration = tx_sstv_mode->samples_per_gap;
			}
		}
	
		if (!component) {
			// Read a new line
			read_boundary(pixels_buffer,
						bmp_header.image_data + ((255 - (scanline_counter / 3)) * sizeof(pixels_buffer)),
						sizeof(pixels_buffer));
		}
	
		offset = component_map[component];
		for (uint32_t bmp_px = 0; bmp_px < 320; bmp_px++) {
			pixel_idx = bmp_px * 3;
			scanline_buffer.luma[bmp_px] = pixels_buffer[pixel_idx + offset];
		}
	
		baseband::set_fifo_data((int8_t *)&scanline_buffer);
	
		scanline_counter++;
	}
	else if (options_grey.value() == 1) 
	{
		if (scanline_counter >= 140) {
			progressbar.set_value(0);
			transmitter_model.disable();
			options_bitmaps.set_focusable(true);
			tx_view.set_transmitting(false);
			return;
		}
	
		progressbar.set_value(scanline_counter);
		component = scanline_counter % 1;
	
		if  (component == tx_sstv_mode->sync_index) {
			// Sync
			scanline_buffer.start_tone.frequency = SSTV_F2D(1200);
			scanline_buffer.start_tone.duration = tx_sstv_mode->samples_per_sync;
			scanline_buffer.gap_tone.frequency = SSTV_F2D(1500);
			scanline_buffer.gap_tone.duration = tx_sstv_mode->samples_per_gap;
		} else {
			// Regular scanline
			scanline_buffer.start_tone.duration = 0;
			if (tx_sstv_mode->gaps) {
				scanline_buffer.gap_tone.frequency = SSTV_F2D(1500);
				scanline_buffer.gap_tone.duration = tx_sstv_mode->samples_per_gap;
			}
		}
	
		if (!component) {
			// Read a new line
			read_boundary(pixels_buffer_grey,
						bmp_header.image_data + ((139 - (scanline_counter / 1)) * sizeof(pixels_buffer_grey)),
						sizeof(pixels_buffer_grey));
		}
	
		for (uint32_t bmp_px = 0; bmp_px < 140; bmp_px++) {
			pixel_idx = bmp_px * 2;
			scanline_buffer.luma[bmp_px] = pixels_buffer_grey[pixel_idx];
		}
	
		baseband::set_fifo_data((int8_t *)&scanline_buffer);
	
		scanline_counter++;
	}

}

proc_sstvtx.cpp

else if (state == STATE_PIXELS) {
				// Many times per scanline
				tone_delta = SSTV_F2D(1500 + ((current_scanline->luma[pixel_index] * 800) / 256));
				sample_count = pixel_duration;
				pixel_index++;
				//the problem is casued here, robot8 vis_code!=2!!!!!!!
				if (vis_code == sstv_parity(02)) {
					if (pixel_index >= 140) {
						// Scanline done, (dirty) state jump
						pixel_index = 0;
						state = STATE_VIS;
						substep = 10;
					}
				}
				else {
					if (pixel_index >= 320) {
						// Scanline done, (dirty) state jump
						pixel_index = 0;
						state = STATE_VIS;
						substep = 10;
					}
				}
			}

 sstv.hpp

{ "Robot 8",	sstv_parity(02),	false, SSTV_BW, 140, 140, SSTV_MS2S(0.4372),	false, 0, true, SSTV_MS2S(4.862), SSTV_MS2S(0.572) },

演示视频:

https://www.bilibili.com/video/BV1ZA411x7QN/

一般我们手头的都是彩色的jpg大图片,要自己制作图片步骤如下:

1.先用 office picture manager调整图片尺寸为140x140像素。

2.再用win下画图软件把图中内容剪切到左边2/3处,因为右边1/3到时会被忽略掉。

3.然后运行下面的程序,把彩色转为灰度图(不能用画图软件转为单色图)。

rgb_to_grey.py

import cv2


def main():
    img_src = cv2.imread("140140.jpg")

    img_grey = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)

    print("img_src:", img_src.shape)
    print("img_grey:", img_grey.shape)

    cv2.imshow("img_src", img_src)
    cv2.imshow("img_grey", img_grey)

    cv2.imwrite("140140grey.jpg",img_grey)
    cv2.waitKey()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

4.最后用ubuntu下默认的那个看图软件保存为bmp格式。

下面是我发射的图片例子。 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页