aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo_e1.h
blob: 4f5a18a6173e8f5b95736b3cb94df3d05deddcb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#pragma once

#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/isdnhdlc.h>

struct osmo_e1_tx_state {
	bool remote_alarm;
	bool crc4_error;
	/* lower 5 bits: Sa4..Sa8 */
	uint8_t sa4_sa8;
	/* frame number 0..15 */
	uint8_t frame_nr;
	uint8_t crc4_last_smf;
	uint8_t crc4;
};

struct osmo_e1_rx_state {
	uint8_t frame_nr;
	/* history of rceived TS0 octets */
	uint8_t ts0_history[16];
	uint8_t ts0_hist_len;
	/* was a remote alarm received? */
	bool remote_alarm;
	bool remote_crc4_error;
	/* number of TS0 bytes received since entering CRC mframe search */
	uint8_t num_ts0_in_mframe_search;
	struct osmo_fsm_inst *fi;
	/* computed CRC4 */
	uint8_t crc4_last_smf;
	uint8_t crc4;
};

enum osmo_e1_notify_event {
	E1_NTFY_EVT_ALIGN_FRAME,
	E1_NTFY_EVT_ALIGN_CRC_MFRAME,
	E1_NTFY_EVT_CRC_ERROR,
	E1_NTFY_EVT_REMOTE_CRC_ERROR,
	E1_NTFY_EVT_REMOTE_ALARM,
};

enum osmo_e1_ts_mode {
       OSMO_E1_TS_RAW,
       OSMO_E1_TS_HDLC_CRC,
};

struct osmo_e1_instance_ts;
struct osmo_e1_instance;
typedef void (*e1_data_cb)(struct osmo_e1_instance_ts *ts, struct msgb *msg);
typedef void (*e1_notify_cb)(struct osmo_e1_instance *e1i, enum osmo_e1_notify_event evt,
			     bool present, void *data);

struct osmo_e1_instance_ts {
	/* timeslot number */
	uint8_t ts_nr;
	/* mode in which we operate (RAW/HDLC) */
	enum osmo_e1_ts_mode mode;
	/* back-pointer to e1 instance */
	struct osmo_e1_instance *inst;
	struct {
		/* optional HDLC encoder state */
		struct osmo_isdnhdlc_vars hdlc;
		/* queue of pending to-be-transmitted messages */
		struct llist_head queue;
		unsigned long underruns;
	} tx;
	struct {
		/* optional HDLC decoder state */
		struct osmo_isdnhdlc_vars hdlc;
		bool enabled;
		/* how many bytes to buffer before calling call-back */
		unsigned int granularity;
		/* current receive buffer */
		struct msgb *msg;
		e1_data_cb data_cb;
		/* private data, relevant to user */
		void *priv;
	} rx;
};

struct osmo_e1_instance {
	/* list; currently not used yet */
	struct llist_head list;

	/* is CRC4 generation + parsing enabled? */
	bool crc4_enabled;
	/* notification call-back function */
	e1_notify_cb notify_cb;

	/* Rx + Tx related state */
	struct osmo_e1_tx_state tx;
	struct osmo_e1_rx_state rx;

	/* our 32 timeslots (only 1..32 are used) */
	struct osmo_e1_instance_ts ts[32];

	/* private data, relevant to user */
	void *priv;
};

extern const struct value_string osmo_e1_notifv_evt_names[];

static inline const char *osmo_e1_notify_event_name(enum osmo_e1_notify_event evt) {
	return get_value_string(osmo_e1_notifv_evt_names, evt);
}

int osmo_e1_init(void);
struct osmo_e1_instance_ts *osmo_e1_instance_ts(struct osmo_e1_instance *e1i, uint8_t ts_nr);
int osmo_e1_instance_init(struct osmo_e1_instance *e1i, const char *name, e1_notify_cb cb,
			  bool crc4_enabled, void *priv);
void osmo_e1_instance_reset(struct osmo_e1_instance *e1i);
int osmo_e1_ts_config(struct osmo_e1_instance_ts *e1t, e1_data_cb cb, unsigned int granularity,
		      bool enable, enum osmo_e1_ts_mode mode);
void osmo_e1_ts_reset(struct osmo_e1_instance_ts *e1t);


void osmo_e1_ts_enqueue(struct osmo_e1_instance_ts *e1t, struct msgb *msg);
int osmo_e1_pull_tx_frame(struct osmo_e1_instance *e1i, uint8_t *out_frame);
int osmo_e1_rx_frame(struct osmo_e1_instance *e1i, const uint8_t *in_frame);