summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrimio <vasi.vilvoiu@gmail.com>2019-02-16 01:38:15 +0200
committerrimio <vasi.vilvoiu@gmail.com>2019-02-16 01:38:15 +0200
commit7f387fe2a1b9758defeb82bcba58b4c9554a8a7f (patch)
tree36ae77f3aa36320ac362eaeabde76d2576c5e7f1
parentd7972c361d6fbad81a9a7c4dbe180515dfca7f02 (diff)
Robot color modes
-rw-r--r--src/encoder.c253
-rw-r--r--src/sstv.c39
-rw-r--r--src/sstv.h16
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:
diff --git a/src/sstv.c b/src/sstv.c
index bfe9319..b405c79 100644
--- a/src/sstv.c
+++ b/src/sstv.c
@@ -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;
/*
diff --git a/src/sstv.h b/src/sstv.h
index 6a8f819..f2542a5 100644
--- a/src/sstv.h
+++ b/src/sstv.h
@@ -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;