diff options
| author | rimio <vasi.vilvoiu@gmail.com> | 2019-02-16 01:38:15 +0200 |
|---|---|---|
| committer | rimio <vasi.vilvoiu@gmail.com> | 2019-02-16 01:38:15 +0200 |
| commit | 7f387fe2a1b9758defeb82bcba58b4c9554a8a7f (patch) | |
| tree | 36ae77f3aa36320ac362eaeabde76d2576c5e7f1 | |
| parent | d7972c361d6fbad81a9a7c4dbe180515dfca7f02 (diff) | |
Robot color modes
| -rw-r--r-- | src/encoder.c | 253 | ||||
| -rw-r--r-- | src/sstv.c | 39 | ||||
| -rw-r--r-- | src/sstv.h | 16 |
3 files changed, 305 insertions, 3 deletions
diff --git a/src/encoder.c b/src/encoder.c index 2824ab6..f8a378d 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -44,9 +44,18 @@ typedef enum { SSTV_ENCODER_STATE_SYNC, SSTV_ENCODER_STATE_SYNC_FIRST, SSTV_ENCODER_STATE_PORCH, + SSTV_ENCODER_STATE_PORCH2, SSTV_ENCODER_STATE_PORCH_R, SSTV_ENCODER_STATE_PORCH_G, SSTV_ENCODER_STATE_PORCH_B, + SSTV_ENCODER_STATE_PORCH_BY, + SSTV_ENCODER_STATE_PORCH_RY, + + /* separator */ + SSTV_ENCODER_STATE_SEPARATOR, + SSTV_ENCODER_STATE_SEPARATOR2, + SSTV_ENCODER_STATE_SEPARATOR_BY, + SSTV_ENCODER_STATE_SEPARATOR_RY, /* scan */ SSTV_ENCODER_STATE_Y_SCAN, @@ -215,12 +224,246 @@ sstv_delete_encoder(void *ctx) } static sstv_error_t -sstv_encode_robot_state_change(sstv_encoder_context_t *context) +sstv_encode_robot_bw_state_change(sstv_encoder_context_t *context) { return SSTV_OK; } static sstv_error_t +sstv_encode_robot_cfull_state_change(sstv_encoder_context_t *context) +{ + /* start communication */ + if (context->state == SSTV_ENCODER_STATE_VIS_STOP_BIT) { + context->state = SSTV_ENCODER_STATE_SYNC; + context->extra.scan.curr_line = 0; + FSK(context, context->descriptor.sync.time, context->descriptor.sync.freq); + return SSTV_OK; + } + + /* sync->porch */ + if (context->state == SSTV_ENCODER_STATE_SYNC) { + context->state = SSTV_ENCODER_STATE_PORCH; + FSK(context, context->descriptor.porch.time, context->descriptor.porch.freq); + return SSTV_OK; + } + + /* porch->y or y->y */ + if ((context->state == SSTV_ENCODER_STATE_PORCH) + || (context->state == SSTV_ENCODER_STATE_Y_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH) { + context->extra.scan.curr_col = 0; + } + + context->state = SSTV_ENCODER_STATE_Y_SCAN; + + uint32_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint8_t y = context->image.buffer[pix_offset * 3]; + FSK_PIXEL(context, context->descriptor.pixel.time, y); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* y->separator */ + if (context->state == SSTV_ENCODER_STATE_Y_SCAN) { + context->state = SSTV_ENCODER_STATE_SEPARATOR_RY; + FSK(context, context->descriptor.separator.time, context->descriptor.separator.freq); + return SSTV_OK; + } + + /* separator -> porch_ry */ + if (context->state == SSTV_ENCODER_STATE_SEPARATOR_RY) + { + context->state = SSTV_ENCODER_STATE_PORCH_RY; + FSK(context, context->descriptor.porch2.time, context->descriptor.porch2.freq); + return SSTV_OK; + } + + /* porch_ry->ry_scan or ry->ry */ + if ((context->state == SSTV_ENCODER_STATE_PORCH_RY) + || (context->state == SSTV_ENCODER_STATE_RY_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH_RY) { + context->extra.scan.curr_col = 0; + } + context->state = SSTV_ENCODER_STATE_RY_SCAN; + + uint32_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint8_t ry = context->image.buffer[pix_offset * 3 + 2]; + FSK_PIXEL(context, context->descriptor.pixel.time2, ry); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* ry_scan->separator2 */ + if (context->state == SSTV_ENCODER_STATE_RY_SCAN) { + context->state = SSTV_ENCODER_STATE_SEPARATOR_BY; + FSK(context, context->descriptor.separator2.time, context->descriptor.separator2.freq); + return SSTV_OK; + } + + /* separator2 -> porch_by */ + if (context->state == SSTV_ENCODER_STATE_SEPARATOR_BY) + { + context->state = SSTV_ENCODER_STATE_PORCH_BY; + FSK(context, context->descriptor.porch2.time, context->descriptor.porch2.freq); + return SSTV_OK; + } + + /* porch_by->by_scan or by->by */ + if ((context->state == SSTV_ENCODER_STATE_PORCH_BY) + || (context->state == SSTV_ENCODER_STATE_BY_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH_BY) { + context->extra.scan.curr_col = 0; + } + context->state = SSTV_ENCODER_STATE_BY_SCAN; + + uint32_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint8_t by = context->image.buffer[pix_offset * 3 + 1]; + FSK_PIXEL(context, context->descriptor.pixel.time2, by); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* advance line (by->sync) */ + if ((context->state == SSTV_ENCODER_STATE_BY_SCAN) + && (context->extra.scan.curr_line < context->image.height-1)) + { + context->state = SSTV_ENCODER_STATE_SYNC; + context->extra.scan.curr_line ++; + FSK(context, context->descriptor.sync.time, context->descriptor.sync.freq); + return SSTV_OK; + } + + /* no more state changes, done */ + context->state = SSTV_ENCODER_STATE_END; + return SSTV_OK; +} + +static sstv_error_t +sstv_encode_robot_chalf_state_change(sstv_encoder_context_t *context) +{ + /* start communication */ + if (context->state == SSTV_ENCODER_STATE_VIS_STOP_BIT) { + context->state = SSTV_ENCODER_STATE_SYNC; + context->extra.scan.curr_line = 0; + FSK(context, context->descriptor.sync.time, context->descriptor.sync.freq); + return SSTV_OK; + } + + /* sync->porch */ + if (context->state == SSTV_ENCODER_STATE_SYNC) { + context->state = SSTV_ENCODER_STATE_PORCH; + FSK(context, context->descriptor.porch.time, context->descriptor.porch.freq); + return SSTV_OK; + } + + /* porch->y or y->y */ + if ((context->state == SSTV_ENCODER_STATE_PORCH) + || (context->state == SSTV_ENCODER_STATE_Y_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH) { + context->extra.scan.curr_col = 0; + } + + context->state = SSTV_ENCODER_STATE_Y_SCAN; + + uint32_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint8_t y = context->image.buffer[pix_offset * 3]; + FSK_PIXEL(context, context->descriptor.pixel.time, y); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* y->separator/separator2 */ + if (context->state == SSTV_ENCODER_STATE_Y_SCAN) { + if (context->extra.scan.curr_line % 2 == 0) { + context->state = SSTV_ENCODER_STATE_SEPARATOR; + FSK(context, context->descriptor.separator.time, context->descriptor.separator.freq); + } else { + context->state = SSTV_ENCODER_STATE_SEPARATOR2; + FSK(context, context->descriptor.separator2.time, context->descriptor.separator2.freq); + } + + return SSTV_OK; + } + + /* separator/separator2 -> porch2 */ + if (context->state == SSTV_ENCODER_STATE_SEPARATOR + || context->state == SSTV_ENCODER_STATE_SEPARATOR2) + { + context->state = SSTV_ENCODER_STATE_PORCH2; + FSK(context, context->descriptor.porch2.time, context->descriptor.porch2.freq); + return SSTV_OK; + } + + /* porch2->ry_scan or ry->ry */ + if ((context->state == SSTV_ENCODER_STATE_PORCH2 && context->extra.scan.curr_line % 2 == 0) + || (context->state == SSTV_ENCODER_STATE_RY_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH2) { + context->extra.scan.curr_col = 0; + } + context->state = SSTV_ENCODER_STATE_RY_SCAN; + + uint32_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint32_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col; + uint8_t r1 = context->image.buffer[pix_offset_l0 * 3 + 2]; + uint8_t r2 = context->image.buffer[pix_offset_l1 * 3 + 2]; + uint8_t r = (r1 + r2) / 2; + FSK_PIXEL(context, context->descriptor.pixel.time2, r); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* porch2->by_scan or by->by */ + if ((context->state == SSTV_ENCODER_STATE_PORCH2 && context->extra.scan.curr_line % 2 == 1) + || (context->state == SSTV_ENCODER_STATE_BY_SCAN + && context->extra.scan.curr_col < context->image.width)) + { + if (context->state == SSTV_ENCODER_STATE_PORCH2) { + context->extra.scan.curr_col = 0; + } + context->state = SSTV_ENCODER_STATE_BY_SCAN; + + uint32_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col; + uint32_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line - 1) + context->extra.scan.curr_col; + uint8_t b1 = context->image.buffer[pix_offset_l0 * 3 + 1]; + uint8_t b2 = context->image.buffer[pix_offset_l1 * 3 + 1]; + uint8_t b = (b1 + b2) / 2; + FSK_PIXEL(context, context->descriptor.pixel.time2, b); + + context->extra.scan.curr_col ++; + return SSTV_OK; + } + + /* advance line (ry/by->sync) */ + if ((context->state == SSTV_ENCODER_STATE_RY_SCAN || context->state == SSTV_ENCODER_STATE_BY_SCAN) + && (context->extra.scan.curr_line < context->image.height-1)) + { + context->state = SSTV_ENCODER_STATE_SYNC; + context->extra.scan.curr_line ++; + FSK(context, context->descriptor.sync.time, context->descriptor.sync.freq); + return SSTV_OK; + } + + /* no more state changes, done */ + context->state = SSTV_ENCODER_STATE_END; + return SSTV_OK; +} + +static sstv_error_t sstv_encode_scottie_state_change(sstv_encoder_context_t *context) { /* start communication */ @@ -641,11 +884,15 @@ sstv_encode_state_change(sstv_encoder_context_t *context) case SSTV_MODE_ROBOT_BW36_R: case SSTV_MODE_ROBOT_BW36_G: case SSTV_MODE_ROBOT_BW36_B: + return sstv_encode_robot_bw_state_change(context); + case SSTV_MODE_ROBOT_C12: - case SSTV_MODE_ROBOT_C24: case SSTV_MODE_ROBOT_C36: + return sstv_encode_robot_chalf_state_change(context); + + case SSTV_MODE_ROBOT_C24: case SSTV_MODE_ROBOT_C72: - return sstv_encode_robot_state_change(context); + return sstv_encode_robot_cfull_state_change(context); /* Scottie modes */ case SSTV_MODE_SCOTTIE_S1: @@ -496,6 +496,9 @@ sstv_get_mode_descriptor(sstv_mode_t mode, uint32_t sample_rate, sstv_mode_descr case SSTV_MODE_ROBOT_C72: desc->sync.freq = FREQ_DESC_INIT(1200, sample_rate); desc->porch.freq = FREQ_DESC_INIT(1500, sample_rate); + desc->porch2.freq = FREQ_DESC_INIT(1900, sample_rate); + desc->separator.freq = FREQ_DESC_INIT(1500, sample_rate); + desc->separator2.freq = FREQ_DESC_INIT(2300, sample_rate); desc->pixel.low_freq = FREQ_DESC_INIT(1500, sample_rate); desc->pixel.bandwidth = FREQ_DESC_INIT(800, sample_rate); break; @@ -567,10 +570,46 @@ sstv_get_mode_descriptor(sstv_mode_t mode, uint32_t sample_rate, sstv_mode_descr case SSTV_MODE_ROBOT_BW36_R: case SSTV_MODE_ROBOT_BW36_G: case SSTV_MODE_ROBOT_BW36_B: + break; + case SSTV_MODE_ROBOT_C12: + desc->sync.time = TIME_DESC_INIT(9000, sample_rate); + desc->porch.time = TIME_DESC_INIT(3000, sample_rate); + desc->porch2.time = TIME_DESC_INIT(1500, sample_rate); + desc->separator.time = TIME_DESC_INIT(4500, sample_rate); + desc->separator2.time = TIME_DESC_INIT(4500, sample_rate); + desc->pixel.time = TIME_DESC_INIT(375, sample_rate); + desc->pixel.time2 = TIME_DESC_INIT(187, sample_rate); + break; + case SSTV_MODE_ROBOT_C24: + desc->sync.time = TIME_DESC_INIT(9000, sample_rate); + desc->porch.time = TIME_DESC_INIT(3000, sample_rate); + desc->porch2.time = TIME_DESC_INIT(1500, sample_rate); + desc->separator.time = TIME_DESC_INIT(4500, sample_rate); + desc->separator2.time = TIME_DESC_INIT(4500, sample_rate); + desc->pixel.time = TIME_DESC_INIT(275, sample_rate); + desc->pixel.time2 = TIME_DESC_INIT(137, sample_rate); + break; + case SSTV_MODE_ROBOT_C36: + desc->sync.time = TIME_DESC_INIT(9000, sample_rate); + desc->porch.time = TIME_DESC_INIT(3000, sample_rate); + desc->porch2.time = TIME_DESC_INIT(1500, sample_rate); + desc->separator.time = TIME_DESC_INIT(4500, sample_rate); + desc->separator2.time = TIME_DESC_INIT(4500, sample_rate); + desc->pixel.time = TIME_DESC_INIT(275, sample_rate); + desc->pixel.time2 = TIME_DESC_INIT(137, sample_rate); + break; + case SSTV_MODE_ROBOT_C72: + desc->sync.time = TIME_DESC_INIT(9000, sample_rate); + desc->porch.time = TIME_DESC_INIT(3000, sample_rate); + desc->porch2.time = TIME_DESC_INIT(1500, sample_rate); + desc->separator.time = TIME_DESC_INIT(4500, sample_rate); + desc->separator2.time = TIME_DESC_INIT(4500, sample_rate); + desc->pixel.time = TIME_DESC_INIT(431, sample_rate); + desc->pixel.time2 = TIME_DESC_INIT(216, sample_rate); break; /* @@ -55,6 +55,22 @@ typedef struct { struct { sstv_timing_desc_t time; + sstv_freq_desc_t freq; + } porch2; + + struct { + sstv_timing_desc_t time; + sstv_freq_desc_t freq; + } separator; + + struct { + sstv_timing_desc_t time; + sstv_freq_desc_t freq; + } separator2; + + struct { + sstv_timing_desc_t time; + sstv_timing_desc_t time2; sstv_freq_desc_t low_freq; sstv_freq_desc_t bandwidth; |
