view ater/tx_func.c @ 52:626180a15857 default tip

ater play-d144: emit E-data frames manually, osmo_trau_frame_encode() is currently broken for this frame type
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 25 Sep 2024 06:40:43 +0000
parents db39e8855f3d
children
line wrap: on
line source

/*
 * Here we are going to implement Tx on Ater toward the TRAU.
 */

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <osmocom/core/bits.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/isdn/i460_mux.h>
#include <osmocom/trau/trau_frame.h>

#include "globals.h"
#include "submux.h"
#include "out_frame.h"

/*
 * The following hard-coded frame is based on TS 48.060 section 5.3.1.
 * 0-based octet numbers in the comments are as in the spec.
 */
static const ubit_t d144_sync_frame[320] = {
	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 0 */
	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 1 */
	1, 1, 0, 1, 0, 0, 1, 1,		/* octet 2 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 3 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 4 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 5 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 6 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 7 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 8 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 9 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 10 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 11 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 12 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 13 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 14 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 15 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 16 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 17 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 18 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 19 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 20 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 21 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 22 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 23 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 24 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 25 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 26 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 27 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 28 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 29 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 30 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 31 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 32 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 33 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 34 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 35 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 36 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 37 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 38 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 39 */
};

/*
 * The following hard-coded frame is based on TS 48.060 section 5.3.2.
 * 0-based octet numbers in the comments are as in the spec.
 */
static const ubit_t d144_idle_edata[320] = {
	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 0 */
	0, 0, 0, 0, 0, 0, 0, 0,		/* octet 1 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 2 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 3 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 4 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 5 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 6 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 7 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 8 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 9 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 10 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 11 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 12 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 13 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 14 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 15 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 16 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 17 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 18 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 19 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 20 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 21 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 22 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 23 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 24 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 25 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 26 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 27 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 28 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 29 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 30 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 31 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 32 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 33 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 34 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 35 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 36 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 37 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 38 */
	1, 1, 1, 1, 1, 1, 1, 1,		/* octet 39 */
};

void init_trau_ul_frame(int nr)
{
	struct ater_subslot *at = &subslots[nr];
	struct osmo_trau_frame *fr = &at->ul_frame;

	fr->type = at->is_efr ? OSMO_TRAU16_FT_EFR : OSMO_TRAU16_FT_FR;
	fr->dir = OSMO_TRAU_DIR_UL;
	memset(fr->c_bits + 5, 0, 6);
	memset(fr->c_bits + 15, 1, 6);
	memset(fr->t_bits, 1, 4);
}

void init_trau_ul_frame_csd(int nr, bool ir_16k)
{
	struct ater_subslot *at = &subslots[nr];
	struct osmo_trau_frame *fr = &at->ul_frame;

	fr->type = OSMO_TRAU16_FT_DATA;
	fr->dir = OSMO_TRAU_DIR_UL;
	fr->c_bits[5] = ir_16k;
	memset(fr->c_bits + 6, 1, 9);
	memset(fr->d_bits, 1, 63 * 4);
}

static void d144_play_frame(ubit_t *out, const uint8_t *filerec)
{
	memset(out, 0, 16);
	memset(out + 16, 1, 6);
	out[22] = 0;
	memset(out + 23, 1, 7);
	out[30] = (filerec[1] & 2) >> 1;
	out[31] = filerec[1] & 1;
	osmo_pbit2ubit(out + 32, filerec + 2, 288);
}

static void d144_fill_frame(struct ater_subslot *at, ubit_t *out)
{
	if (at->play_buffer) {
		d144_play_frame(out, at->play_buffer + at->play_buf_ptr * 38);
		at->play_buf_ptr++;
		if (at->play_buf_ptr < at->play_buf_total)
			return;
		free(at->play_buffer);
		at->play_buffer = NULL;
		printf("file play finished\n");
		return;
	}
	memcpy(out, at->d144_edata ? d144_idle_edata : d144_sync_frame, 320);
}

static void handle_d144(int nr)
{
	struct ater_subslot *at = &subslots[nr];
	struct msgb *msg;

	msg = msgb_alloc_c(g_ctx, 320, "TRAU-UL-frame");
	if (!msg)
		return;
	d144_fill_frame(at, msg->tail);
	msgb_put(msg, 320);
	osmo_i460_mux_enqueue(at->schan, msg);
}

static void handle_play(struct ater_subslot *at)
{
	if (at->play_wait_align) {
		if (at->mfrm_count)
			return;
		at->play_wait_align = false;
	}
	trau_frame_from_record(at->play_buffer + at->play_buf_ptr * 34,
				at->is_efr, &at->ul_frame);
	at->play_buf_ptr++;
	if (at->play_buf_ptr < at->play_buf_total)
		return;
	free(at->play_buffer);
	at->play_buffer = NULL;
	printf("file play finished\n");
}

static void tx_service_subslot(int nr)
{
	struct ater_subslot *at = &subslots[nr];
	struct osmo_trau_frame *fr = &at->ul_frame;
	struct msgb *msg;
	int len;

	if (!at->is_active)
		return;
	if (at->is_data_144) {
		handle_d144(nr);
		return;
	}
	if (at->play_buffer)
		handle_play(at);
	if (!at->is_data) {
		at->mfrm_count++;
		if (at->mfrm_count >= 24) {
			at->mfrm_count = 0;
			fr->c_bits[14] = 1;
		} else {
			fr->c_bits[14] = 0;
		}
	}
	msg = msgb_alloc_c(g_ctx, 640, "TRAU-UL-frame");
	if (!msg)
		return;
	len = osmo_trau_frame_encode(msg->tail, msgb_tailroom(msg), fr);
	if (len <= 0) {
		msgb_free(msg);
		return;
	}
	/*
	 * A very ugly/hacky way of setting C5 for HR data,
	 * working around libosmotrau API that is not designed
	 * for such hacking.
	 */
	if (at->is_data && at->is_hr_data)
		msg->tail[21] = 1;
	msgb_put(msg, len);
	osmo_i460_mux_enqueue(at->schan, msg);
}

void transmit_e1_ts(void)
{
	uint8_t buf[160];
	int nr;

	for (nr = 0; nr < ATER_SUBSLOTS; nr++)
		tx_service_subslot(nr);
	osmo_i460_mux_out(&i460_ts, buf, 160);
	write(ts_fd, buf, 160);
}