diff --git a/src/acquire.c b/src/acquire.c index ea4f65d..ab0e16d 100644 --- a/src/acquire.c +++ b/src/acquire.c @@ -204,7 +204,7 @@ void acquire_process(acquire_t *st) if (st->input->sync_state != SYNC_STATE_FINE) { - for (j = CENTER_AM - PIDS_2_INDEX_AM; j <= CENTER_AM + PIDS_2_INDEX_AM; j++) + for (j = CENTER_AM - PIDS_OUTER_INDEX_AM; j <= CENTER_AM + PIDS_OUTER_INDEX_AM; j++) { mag_sums[j] += cabsf(st->fftout[j]); } @@ -215,7 +215,7 @@ void acquire_process(acquire_t *st) { float max_mag = -1.0f; int max_index = -1; - for (j = CENTER_AM - PIDS_2_INDEX_AM; j <= CENTER_AM + PIDS_2_INDEX_AM; j++) + for (j = CENTER_AM - PIDS_OUTER_INDEX_AM; j <= CENTER_AM + PIDS_OUTER_INDEX_AM; j++) { if (mag_sums[j] > max_mag) { diff --git a/src/decode.c b/src/decode.c index ac76408..6b705c2 100644 --- a/src/decode.c +++ b/src/decode.c @@ -65,19 +65,48 @@ static void interleaver_ma1(decode_t *st) p = 3 + (n % 3); st->mu[DIVERSITY_DELAY_AM + n] = bit_map(st->buffer_pu, b, k, p); } - for (int n = 0; n < 12000; n++) + + if (st->input->sync.psmi != SERVICE_MODE_MA3) { - b = (3*n + n/3000) % 8; - k = (n + (n/6000)) % 750; - p = n % 2; - st->el[n] = bit_map(st->buffer_t, b, k, p); + for (int n = 0; n < 12000; n++) + { + b = (3*n + n/3000) % 8; + k = (n + (n/6000)) % 750; + p = n % 2; + st->el[n] = bit_map(st->buffer_t, b, k, p); + } + for (int n = 0; n < 24000; n++) + { + b = (3*n + n/3000 + 2*(n/12000)) % 8; + k = (n + (n/6000)) % 750; + p = n % 4; + st->eu[n] = bit_map(st->buffer_s, b, k, p); + } } - for (int n = 0; n < 24000; n++) + else { - b = (3*n + n/3000 + 2*(n/12000)) % 8; - k = (n + (n/6000)) % 750; - p = n % 4; - st->eu[n] = bit_map(st->buffer_s, b, k, p); + for (int n = 0; n < 18000; n++) + { + b = (3*n + 3) % 8; + k = (n + n/3000 + 3) % 750; + p = n % 3; + st->ebl[n] = bit_map(st->buffer_t, b, k, p); + + b = (3*n + 3) % 8; + k = (n + n/3000 + 3) % 750; + p = 3 + (n % 3); + st->eml[DIVERSITY_DELAY_AM + n] = bit_map(st->buffer_t, b, k, p); + + b = (3*n) % 8; + k = (n + n/3000 + 2) % 750; + p = n % 3; + st->ebu[n] = bit_map(st->buffer_s, b, k, p); + + b = (3*n) % 8; + k = (n + n/3000 + 2) % 750; + p = 3 + (n % 3); + st->emu[DIVERSITY_DELAY_AM + n] = bit_map(st->buffer_s, b, k, p); + } } for (int i = 0; i < 6000; i++) @@ -89,18 +118,36 @@ static void interleaver_ma1(decode_t *st) st->p1_am[i*12 + bu_delay[j]] = st->bu[i*3 + j]; st->p1_am[i*12 + mu_delay[j]] = st->mu[i*3 + j]; } - for (int j = 0; j < 2; j++) + if (st->input->sync.psmi != SERVICE_MODE_MA3) { - st->p3_am[i*6 + el_delay[j]] = st->el[i*2 + j]; + for (int j = 0; j < 2; j++) + { + st->p3_am[i*6 + el_delay[j]] = st->el[i*2 + j]; + } + for (int j = 0; j < 4; j++) + { + st->p3_am[i*6 + eu_delay[j]] = st->eu[i*4 + j]; + } } - for (int j = 0; j < 4; j++) + else { - st->p3_am[i*6 + eu_delay[j]] = st->eu[i*4 + j]; + for (int j = 0; j < 3; j++) + { + st->p3_am[i*12 + bl_delay[j]] = st->ebl[i*3 + j]; + st->p3_am[i*12 + ml_delay[j]] = st->eml[i*3 + j]; + st->p3_am[i*12 + bu_delay[j]] = st->ebu[i*3 + j]; + st->p3_am[i*12 + mu_delay[j]] = st->emu[i*3 + j]; + } } } memmove(st->ml, st->ml + 18000, DIVERSITY_DELAY_AM); memmove(st->mu, st->mu + 18000, DIVERSITY_DELAY_AM); + if (st->input->sync.psmi == SERVICE_MODE_MA3) + { + memmove(st->eml, st->eml + 18000, DIVERSITY_DELAY_AM); + memmove(st->emu, st->emu + 18000, DIVERSITY_DELAY_AM); + } int offset = 0; for (int i = 0; i < 8 * P1_FRAME_LEN_AM * 3; i++) @@ -118,17 +165,36 @@ static void interleaver_ma1(decode_t *st) } offset = 0; - for (int i = 0; i < P3_FRAME_LEN_AM * 3; i++) + if (st->input->sync.psmi != SERVICE_MODE_MA3) { - switch (i % 6) + for (int i = 0; i < P3_FRAME_LEN_MA1 * 3; i++) { - case 1: - case 4: - case 5: - st->viterbi_p3_am[i] = 0; - break; - default: - st->viterbi_p3_am[i] = st->p3_am[offset++] ? 1 : -1; + switch (i % 6) + { + case 1: + case 4: + case 5: + st->viterbi_p3_am[i] = 0; + break; + default: + st->viterbi_p3_am[i] = st->p3_am[offset++] ? 1 : -1; + } + } + } + else + { + for (int i = 0; i < P3_FRAME_LEN_MA3 * 3; i++) + { + switch (i % 15) + { + case 1: + case 4: + case 7: + st->viterbi_p3_am[i] = 0; + break; + default: + st->viterbi_p3_am[i] = st->p3_am[offset++] ? 1 : -1; + } } } } @@ -173,10 +239,16 @@ static int bit_errors_p1_am(int8_t *coded, uint8_t *decoded) return bit_errors(coded, decoded, 9, P1_FRAME_LEN_AM, 0561, 0657, 0711, puncture, 15); } -static int bit_errors_p3_am(int8_t *coded, uint8_t *decoded) +static int bit_errors_p3_ma1(int8_t *coded, uint8_t *decoded) { uint8_t puncture[] = {1, 0, 1, 1, 0, 0}; - return bit_errors(coded, decoded, 9, P3_FRAME_LEN_AM, 0561, 0753, 0711, puncture, 6); + return bit_errors(coded, decoded, 9, P3_FRAME_LEN_MA1, 0561, 0753, 0711, puncture, 6); +} + +static int bit_errors_p3_ma3(int8_t *coded, uint8_t *decoded) +{ + uint8_t puncture[] = {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1}; + return bit_errors(coded, decoded, 9, P3_FRAME_LEN_MA3, 0561, 0657, 0711, puncture, 15); } static void descramble(uint8_t *buf, unsigned int length) @@ -336,12 +408,25 @@ void decode_process_p1_p3_am(decode_t *st) descramble(st->scrambler_p1_am, P1_FRAME_LEN_AM); frame_push(&st->input->frame, st->scrambler_p1_am, P1_FRAME_LEN_AM, P1_LOGICAL_CHANNEL); } - nrsc5_conv_decode_e2(st->viterbi_p3_am, st->scrambler_p3_am, P3_FRAME_LEN_AM); - total_errors += bit_errors_p3_am(st->viterbi_p3_am, st->scrambler_p3_am); - descramble(st->scrambler_p3_am, P3_FRAME_LEN_AM); - frame_push(&st->input->frame, st->scrambler_p3_am, P3_FRAME_LEN_AM, P3_LOGICAL_CHANNEL); - nrsc5_report_ber(st->input->radio, (float) total_errors / (8 * P1_FRAME_LEN_ENCODED_AM + P3_FRAME_LEN_ENCODED_AM)); + if (st->input->sync.psmi != SERVICE_MODE_MA3) + { + nrsc5_conv_decode_e2(st->viterbi_p3_am, st->scrambler_p3_am, P3_FRAME_LEN_MA1); + total_errors += bit_errors_p3_ma1(st->viterbi_p3_am, st->scrambler_p3_am); + descramble(st->scrambler_p3_am, P3_FRAME_LEN_MA1); + frame_push(&st->input->frame, st->scrambler_p3_am, P3_FRAME_LEN_MA1, P3_LOGICAL_CHANNEL); + + nrsc5_report_ber(st->input->radio, (float) total_errors / (8 * P1_FRAME_LEN_ENCODED_AM + P3_FRAME_LEN_ENCODED_MA1)); + } + else + { + nrsc5_conv_decode_e1(st->viterbi_p3_am, st->scrambler_p3_am, P3_FRAME_LEN_MA3); + total_errors += bit_errors_p3_ma3(st->viterbi_p3_am, st->scrambler_p3_am); + descramble(st->scrambler_p3_am, P3_FRAME_LEN_MA3); + frame_push(&st->input->frame, st->scrambler_p3_am, P3_FRAME_LEN_MA3, P3_LOGICAL_CHANNEL); + + nrsc5_report_ber(st->input->radio, (float) total_errors / (8 * P1_FRAME_LEN_ENCODED_AM + P3_FRAME_LEN_ENCODED_MA3)); + } } static void interleaver_iv_reset(interleaver_iv_t *interleaver) diff --git a/src/decode.h b/src/decode.h index 9289e96..917b8f5 100644 --- a/src/decode.h +++ b/src/decode.h @@ -36,6 +36,10 @@ typedef struct uint8_t mu[18000 + DIVERSITY_DELAY_AM]; uint8_t el[12000]; uint8_t eu[24000]; + uint8_t ebl[18000]; + uint8_t ebu[18000]; + uint8_t eml[18000 + DIVERSITY_DELAY_AM]; + uint8_t emu[18000 + DIVERSITY_DELAY_AM]; int8_t viterbi_p1[P1_FRAME_LEN_FM * 3]; uint8_t scrambler_p1[P1_FRAME_LEN_FM]; @@ -51,9 +55,9 @@ typedef struct uint8_t p1_am[8 * P1_FRAME_LEN_ENCODED_AM]; int8_t viterbi_p1_am[8 * P1_FRAME_LEN_AM * 3]; uint8_t scrambler_p1_am[P1_FRAME_LEN_AM]; - uint8_t p3_am[P3_FRAME_LEN_ENCODED_AM]; - int8_t viterbi_p3_am[P3_FRAME_LEN_AM * 3]; - uint8_t scrambler_p3_am[P3_FRAME_LEN_AM]; + uint8_t p3_am[P3_FRAME_LEN_ENCODED_MA3]; + int8_t viterbi_p3_am[P3_FRAME_LEN_MA3 * 3]; + uint8_t scrambler_p3_am[P3_FRAME_LEN_MA3]; pids_t pids; } decode_t; diff --git a/src/defines.h b/src/defines.h index 1acdaf5..3fbb4d9 100644 --- a/src/defines.h +++ b/src/defines.h @@ -30,12 +30,15 @@ #define CENTER_AM (FFT_AM / 2) // indexes of AM subcarriers #define REF_INDEX_AM 1 -#define PIDS_1_INDEX_AM 27 -#define PIDS_2_INDEX_AM 53 -#define TERTIARY_INDEX_AM 2 -#define SECONDARY_INDEX_AM 28 -#define PRIMARY_INDEX_AM 57 +#define PIDS_INNER_INDEX_AM 27 +#define PIDS_OUTER_INDEX_AM 53 +#define INNER_PARTITION_START_AM 2 +#define MIDDLE_PARTITION_START_AM 28 +#define OUTER_PARTITION_START_AM 57 #define MAX_INDEX_AM 81 +// AM service modes +#define SERVICE_MODE_MA1 1 +#define SERVICE_MODE_MA3 2 // bits per P1 frame #define P1_FRAME_LEN_FM 146176 #define P1_FRAME_LEN_AM 3750 @@ -49,10 +52,12 @@ #define PIDS_FRAME_LEN_ENCODED_AM (PIDS_FRAME_LEN * 3) // bits per P3 frame #define P3_FRAME_LEN_FM 4608 -#define P3_FRAME_LEN_AM 24000 +#define P3_FRAME_LEN_MA1 24000 +#define P3_FRAME_LEN_MA3 30000 // bits per encoded P3 frame #define P3_FRAME_LEN_ENCODED_FM (P3_FRAME_LEN_FM * 2) -#define P3_FRAME_LEN_ENCODED_AM (P3_FRAME_LEN_AM * 3 / 2) +#define P3_FRAME_LEN_ENCODED_MA1 (P3_FRAME_LEN_MA1 * 3 / 2) +#define P3_FRAME_LEN_ENCODED_MA3 (P3_FRAME_LEN_MA3 * 12 / 5) // bits per L2 PCI #define PCI_LEN 24 // bytes per L2 PDU (max) diff --git a/src/frame.c b/src/frame.c index 29995da..2b45024 100644 --- a/src/frame.c +++ b/src/frame.c @@ -614,11 +614,16 @@ void frame_push(frame_t *st, uint8_t *bits, size_t length, logical_channel_t lc) offset = 160; pci_len = 22; break; - case P3_FRAME_LEN_AM: + case P3_FRAME_LEN_MA1: start = 120; offset = 992; pci_len = 24; break; + case P3_FRAME_LEN_MA3: + start = 120; + offset = 1240; + pci_len = 24; + break; default: log_error("Unknown frame length: %u", (unsigned int)length); return; diff --git a/src/sync.c b/src/sync.c index e368d74..4c17e41 100644 --- a/src/sync.c +++ b/src/sync.c @@ -196,6 +196,7 @@ static int find_block_am(sync_t *st, unsigned int ref) 0, 1, 1, 0, 0, 1, 0, -1, -1, 1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; unsigned char data[BLKSZ]; + int bc; for (int n = 0; n < BLKSZ; n++) { @@ -209,7 +210,10 @@ static int find_block_am(sync_t *st, unsigned int ref) if (data[15] ^ data[16] ^ data[17] ^ data[18] ^ data[19] ^ data[20]) return -1; if (data[23] ^ data[24] ^ data[25] ^ data[26] ^ data[27] ^ data[28] ^ data[29] ^ data[30] ^ data[31]) return -1; - return (data[17] << 2) | (data[18] << 1) | data[19]; + bc = (data[17] << 2) | (data[18] << 1) | data[19]; + if (bc == 0) + st->psmi = (data[26] << 4) | (data[27] << 3) | (data[28] << 2) | (data[29] << 1) | data[30]; + return bc; } static int find_ref_am(sync_t *st, unsigned int ref) @@ -539,19 +543,22 @@ void sync_process_am(sync_t *st) { int offset; - for (int i = REF_INDEX_AM; i <= PIDS_2_INDEX_AM; i++) + for (int i = REF_INDEX_AM; i <= MAX_INDEX_AM; i++) { for (int n = 0; n < BLKSZ; n++) { - st->buffer[CENTER_AM + i][n] -= conjf(st->buffer[CENTER_AM - i][n]); + st->buffer[CENTER_AM - i][n] = -conjf(st->buffer[CENTER_AM - i][n]); } } - for (int i = PRIMARY_INDEX_AM; i <= MAX_INDEX_AM; i++) + if (st->psmi != SERVICE_MODE_MA3) { - for (int n = 0; n < BLKSZ; n++) + for (int i = REF_INDEX_AM; i <= PIDS_OUTER_INDEX_AM; i++) { - st->buffer[CENTER_AM - i][n] = -conjf(st->buffer[CENTER_AM - i][n]); + for (int n = 0; n < BLKSZ; n++) + { + st->buffer[CENTER_AM + i][n] += st->buffer[CENTER_AM - i][n]; + } } } @@ -591,16 +598,19 @@ void sync_process_am(sync_t *st) if (st->input->sync_state == SYNC_STATE_FINE) { - float complex pids1_mult = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + PIDS_1_INDEX_AM][8] + st->buffer[CENTER_AM + PIDS_1_INDEX_AM][24]); - float complex pids2_mult = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + PIDS_2_INDEX_AM][8] + st->buffer[CENTER_AM + PIDS_2_INDEX_AM][24]); + int pids_0_index = (st->psmi != SERVICE_MODE_MA3) ? PIDS_INNER_INDEX_AM : -PIDS_INNER_INDEX_AM; + int pids_1_index = (st->psmi != SERVICE_MODE_MA3) ? PIDS_OUTER_INDEX_AM : PIDS_INNER_INDEX_AM; + + float complex pids1_mult = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + pids_0_index][8] + st->buffer[CENTER_AM + pids_0_index][24]); + float complex pids2_mult = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + pids_1_index][8] + st->buffer[CENTER_AM + pids_1_index][24]); for (int n = 0; n < BLKSZ; n++) { - st->buffer[CENTER_AM + PIDS_1_INDEX_AM][n] *= pids1_mult; - decode_push_pids(&st->input->decode, qam16(st->buffer[CENTER_AM + PIDS_1_INDEX_AM][n])); + st->buffer[CENTER_AM + pids_0_index][n] *= pids1_mult; + decode_push_pids(&st->input->decode, qam16(st->buffer[CENTER_AM + pids_0_index][n])); - st->buffer[CENTER_AM + PIDS_2_INDEX_AM][n] *= pids2_mult; - decode_push_pids(&st->input->decode, qam16(st->buffer[CENTER_AM + PIDS_2_INDEX_AM][n])); + st->buffer[CENTER_AM + pids_1_index][n] *= pids2_mult; + decode_push_pids(&st->input->decode, qam16(st->buffer[CENTER_AM + pids_1_index][n])); } float complex pl_mult[PARTITION_WIDTH_AM]; @@ -608,16 +618,28 @@ void sync_process_am(sync_t *st) float complex s_mult[PARTITION_WIDTH_AM]; float complex t_mult[PARTITION_WIDTH_AM]; + int primary_index = (st->psmi != SERVICE_MODE_MA3) ? OUTER_PARTITION_START_AM : INNER_PARTITION_START_AM; + int secondary_index = MIDDLE_PARTITION_START_AM; + int tertiary_index = (st->psmi != SERVICE_MODE_MA3) ? INNER_PARTITION_START_AM : MIDDLE_PARTITION_START_AM; + float samperr = 0; for (int col = 0; col < PARTITION_WIDTH_AM; col++) { int train1 = (5 + 11*col) % 32; int train2 = (21 + 11*col) % 32; - pl_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM - PRIMARY_INDEX_AM - col][train1] + st->buffer[CENTER_AM - PRIMARY_INDEX_AM - col][train2]); - pu_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM + PRIMARY_INDEX_AM + col][train1] + st->buffer[CENTER_AM + PRIMARY_INDEX_AM + col][train2]); - s_mult[col] = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + SECONDARY_INDEX_AM + col][train1] + st->buffer[CENTER_AM + SECONDARY_INDEX_AM + col][train2]); - t_mult[col] = 2 * CMPLXF(-0.5, 0.5) / (st->buffer[CENTER_AM + TERTIARY_INDEX_AM + col][train1] + st->buffer[CENTER_AM + TERTIARY_INDEX_AM + col][train2]); + pl_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM - primary_index - col][train1] + st->buffer[CENTER_AM - primary_index - col][train2]); + pu_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM + primary_index + col][train1] + st->buffer[CENTER_AM + primary_index + col][train2]); + if (st->psmi != SERVICE_MODE_MA3) + { + s_mult[col] = 2 * CMPLXF(1.5, -0.5) / (st->buffer[CENTER_AM + secondary_index + col][train1] + st->buffer[CENTER_AM + secondary_index + col][train2]); + t_mult[col] = 2 * CMPLXF(-0.5, 0.5) / (st->buffer[CENTER_AM + tertiary_index + col][train1] + st->buffer[CENTER_AM + tertiary_index + col][train2]); + } + else + { + s_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM + secondary_index + col][train1] + st->buffer[CENTER_AM + secondary_index + col][train2]); + t_mult[col] = 2 * CMPLXF(2.5, -2.5) / (st->buffer[CENTER_AM - tertiary_index - col][train1] + st->buffer[CENTER_AM - tertiary_index - col][train2]); + } if (col > 0) { @@ -632,18 +654,34 @@ void sync_process_am(sync_t *st) { for (int col = 0; col < PARTITION_WIDTH_AM; col++) { - st->buffer[CENTER_AM - PRIMARY_INDEX_AM - col][n] *= pl_mult[col]; - st->buffer[CENTER_AM + PRIMARY_INDEX_AM + col][n] *= pu_mult[col]; - st->buffer[CENTER_AM + SECONDARY_INDEX_AM + col][n] *= s_mult[col]; - st->buffer[CENTER_AM + TERTIARY_INDEX_AM + col][n] *= t_mult[col]; - - decode_push_pl_pu_s_t( - &st->input->decode, - qam64(st->buffer[CENTER_AM - PRIMARY_INDEX_AM - col][n]), - qam64(st->buffer[CENTER_AM + PRIMARY_INDEX_AM + col][n]), - qam16(st->buffer[CENTER_AM + SECONDARY_INDEX_AM + col][n]), - qpsk(st->buffer[CENTER_AM + TERTIARY_INDEX_AM + col][n]) - ); + st->buffer[CENTER_AM - primary_index - col][n] *= pl_mult[col]; + st->buffer[CENTER_AM + primary_index + col][n] *= pu_mult[col]; + st->buffer[CENTER_AM + secondary_index + col][n] *= s_mult[col]; + if (st->psmi != SERVICE_MODE_MA3) + st->buffer[CENTER_AM + tertiary_index + col][n] *= t_mult[col]; + else + st->buffer[CENTER_AM - tertiary_index - col][n] *= t_mult[col]; + + if (st->psmi != SERVICE_MODE_MA3) + { + decode_push_pl_pu_s_t( + &st->input->decode, + qam64(st->buffer[CENTER_AM - primary_index - col][n]), + qam64(st->buffer[CENTER_AM + primary_index + col][n]), + qam16(st->buffer[CENTER_AM + secondary_index + col][n]), + qpsk(st->buffer[CENTER_AM + tertiary_index + col][n]) + ); + } + else + { + decode_push_pl_pu_s_t( + &st->input->decode, + qam64(st->buffer[CENTER_AM - primary_index - col][n]), + qam64(st->buffer[CENTER_AM + primary_index + col][n]), + qam64(st->buffer[CENTER_AM + secondary_index + col][n]), + qam64(st->buffer[CENTER_AM - tertiary_index - col][n]) + ); + } } } }