Skip to content

Instantly share code, notes, and snippets.

@bbaranoff
Last active April 8, 2026 10:03
Show Gist options
  • Select an option

  • Save bbaranoff/4c0e54dc1404a207387ad9d8c977b35a to your computer and use it in GitHub Desktop.

Select an option

Save bbaranoff/4c0e54dc1404a207387ad9d8c977b35a to your computer and use it in GitHub Desktop.
● Oui exactement — l1ctl_sock_init(&s->uart_modem, ...) est le lien direct entre QEMU et le L23 mobile, sans passer par sercomm/PTY/bridge pour cette voie. Voici l'état actuel des liens inter-layers après les merges qu'on vient de pousser :
┌────────────┐ L1CTL direct (socket UNIX /tmp/osmocom_l2_1)
│ mobile L23 │ ◄──────────────────────────────────────────┐
└────────────┘ │
▲ │
│ sercomm DLCI 5 (PTY) │
│ │
▼ │
┌──────────────┐ sercomm_gate_feed() ┌────────────────┴───┐
│ bridge.py │ ─────────────────────────►│ l1ctl_sock.c │
│ (PTY ↔ UDP) │◄──── calypso_uart.c ──────│ (socket owner) │
└──────────────┘ └─────────┬──────────┘
▲ │
│ UDP TRXD :6702 (DL+UL) │ uart_inject_raw
│ ▼
│ ┌──────────────────┐
▼ │ calypso_uart.c │
┌──────────────┐ │ (modem RX FIFO) │
│ calypso_bsp │ ──c54x_interrupt_ex(21,5)─┐└────────┬─────────┘
│ (UDP socket │ ──bsp_udp_dl_cb───────┐ │ │
│ + BRINT0) │ │ │ ▼
└──────────────┘ ▼ │ ┌──────────────────┐
▲ ┌────┴───┴─┤ ARM L1S firmware │
│ calypso_bsp_tx_burst │ c54x DSP │ (sercomm parser │
│ │ (api_ram │ + L1CTL handler)│
┌──────┴──────┐ │ shared) │ │
│ c54x DSP │ ──api_write_cb───►└─────┬─────┘──────────────────┘
│ (DARAM 0x900│ ↕ IRQ_API │
│ UL bits) │ │ TINT0 timer
└─────────────┘ ▼
┌──────────────┐
│ calypso_tint0│ ── frame_irq + SINT17
└──────────────┘ (TPU sticky)
Les deux nouveautés clés post-merge :
1. l1ctl_sock direct sur l'UART modem — voie courte mobile↔QEMU sans passer par bridge.py pour le L1CTL (bridge.py ne garde que la PTY/sercomm pour le data path UART historique + UDP TRXD pour les bursts)
2. BRINT0 fire dans calypso_bsp_rx_burst — chaque burst UDP entrant de osmo-bts-trx réveille le DSP via vec 21 / IMR bit 5 (en plus du wake SINT17 sur TPU frame)
Mais le binaire actuel régresse : DSP boucle sur SP=0 — soit mon fix TPU sticky soit le BRINT0 wake fire pendant l'init DSP. Tant qu'on ne conditionne pas ces deux wakes sur dsp_init_done, on ne pourra pas tester le pipeline live. Tu veux que je
fasse ce fix conditionnel (et que je vérifie aussi si bridge.py bind encore /tmp/osmocom_l2_1) ?
✻ Cogitated for 46s
❯ pour toutes les layer avec le flow osmo
● Voici le diagramme complet avec l'intégralité du flow osmocom, des layers applicatives mobile L3 jusqu'à la BTS et le core network, en passant par notre QEMU baseband émulé.
╔══════════════════════════════════════════════════════════════════════════╗
║ STACK COMPLÈTE QEMU + OSMOCOM ║
║ (mobile ←→ baseband ←→ BTS ←→ core) ║
╚══════════════════════════════════════════════════════════════════════════╝
┌─────────── MOBILE SIDE (process `mobile`, osmocom-bb layer23) ──────────┐
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ L3 GSM 04.08 (CC, MM, RR) gsm48_* │ │
│ │ app_mobile.c → mobile_main_loop │ │
│ └────────────────────────────┬─────────────────────────────────────┘ │
│ │ rsl_rll_* │
│ ┌────────────────────────────▼─────────────────────────────────────┐ │
│ │ L2 LAPDm rslms_recvmsg / lapdm_phsap_dequeue_prim │ │
│ └────────────────────────────┬─────────────────────────────────────┘ │
│ │ ph-data.{req,ind} │
│ ┌────────────────────────────▼─────────────────────────────────────┐ │
│ │ L1A layer23/src/common/l1ctl.c │ │
│ │ l1ctl_tx_fbsb_req / l1ctl_rx_fbsb_conf / l1ctl_tx_dm_est_req │ │
│ └────────────────────────────┬─────────────────────────────────────┘ │
└────────────────────────────────│─────────────────────────────────────────┘
│ L1CTL msg (mt + payload)
│ unix socket SOCK_STREAM
│ /tmp/osmocom_l2_1
╔══════════════════════════════════════════════════════════════════════════╗
║ QEMU baseband emulation (process qemu-system-arm -M calypso) ║
╠══════════════════════════════════════════════════════════════════════════╣
║ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ l1ctl_sock.c l1ctl_sock_init(uart_modem, "/tmp/osmocom_l2_1") │ ║
║ │ • accept() l1ctl_sock_accept() │ ║
║ │ • RX→fw l1ctl_sock_read() → sercomm-wrap → uart_inject_raw │ ║
║ │ • TX←fw l1ctl_sock_uart_tx_byte() (hooked in calypso_uart) │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ ║
║ │ sercomm DLCI 5 frames (HDLC 0x7E flag, CRC) ║
║ ▼ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ calypso_uart.c modem UART RX FIFO + IRQ_UART_MODEM │ ║
║ │ • calypso_uart_inject_raw() (push bytes into firmware FIFO) │ ║
║ │ • RX path: chardev → sercomm_gate_feed() → fifo │ ║
║ │ • TX path: firmware MMIO write → l1ctl_sock_uart_tx_byte hook │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ ║
║ │ ARM7 reads DR + sercomm decoder (firmware side) ║
║ ▼ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ ARM firmware (osmocom-bb target/firmware/layer1) │ ║
║ │ sercomm.c → l23_api.c::l1a_l23_handler() │ ║
║ │ l1ctl_rx_fbsb_req() → l1s_fbsb_req() → tdma_schedule_set() │ ║
║ │ │ ║
║ │ sync.c::l1_sync() ←── IRQ_TPU_FRAME (frame_irq) │ ║
║ │ tdma_sched_execute() │ ║
║ │ prim_fbsb.c::l1s_fbdet_cmd() │ ║
║ │ → dsp_api.db_w->d_task_md = FB_DSP_TASK (=5) │ ║
║ │ → l1s_rx_win_ctrl() programme TPU │ ║
║ │ │ ║
║ │ prim_fbsb.c::l1s_fbdet_resp() ← TPU+4 frames │ ║
║ │ poll dsp_api.ndb->d_fb_det │ ║
║ │ read a_sync_demod[] (TOA, PM, ANGLE, SNR) │ ║
║ │ l1s_compl_sched(L1_COMPL_FB) │ ║
║ │ l1a_fb_compl() → l1ctl_fbsb_resp(0) │ ║
║ │ l1_queue_for_l2() → sercomm DLCI 5 → calypso_uart TX → l1ctl_sock │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ ║
║ │ ARM MMIO 0xFFD00000 (API RAM, page d_dsp_page) ║
║ ▼ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ calypso_trx.c DSP API RAM mailbox + TPU + IRQ routing │ ║
║ │ • calypso_dsp_read/write ARM ↔ shared dsp_ram[] │ ║
║ │ • calypso_tpu_write(TPU_CTRL_EN) → arm tpu_run + sticky wake DSP │ ║
║ │ • calypso_tint0_do_tick(fn) (frame tick from TINT0): │ ║
║ │ - DMA wp[] → DSP DARAM 0x0586.. │ ║
║ │ - c54x_interrupt_ex(dsp, INT_FRAME, bit) ← SINT17 wake │ ║
║ │ - run dsp until idle (budget) │ ║
║ │ - qemu_irq_raise(IRQ_TPU_FRAME) → ARM frame_irq │ ║
║ │ • trx_dsp_api_write_cb → qemu_irq_pulse(IRQ_API) DSP→ARM │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ ║
║ │ shared C54x api_ram + DARAM (0x0800 base) ║
║ ▼ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ calypso_c54x.c TMS320C54x emulator │ ║
║ │ • c54x_run(insn budget) │ ║
║ │ • c54x_interrupt_ex(vec, imr_bit) → push PC, vector to ISR │ ║
║ │ • IDLE instruction → s->idle = true (waits for IRQ) │ ║
║ │ • DSP firmware (real Calypso DSP ROM .txt): │ ║
║ │ - PROM0 boot, SINT17 ISR, TINT0 ISR, BRINT0 ISR │ ║
║ │ - FB correlator → write d_fb_det + a_sync_demod[] │ ║
║ │ - SB decoder → write a_sch[] │ ║
║ │ - Burst codec/encoder for DL/UL frames │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ ║
║ │ DARAM samples (BSP DMA target window) ║
║ ▼ ║
║ ┌────────────────────────────────────────────────────────────────────┐ ║
║ │ calypso_bsp.c BSP serial + DMA (radio sample DMA emulation) │ ║
║ │ • bsp_udp_dl_cb() ← UDP :6702 from bridge │ ║
║ │ - parse TRXDv0 wire (TN, FN, RSSI, TOA256, soft bits) │ ║
║ │ - calypso_trx_on_dl_burst(tn, fn, samples, n) │ ║
║ │ - calypso_bsp_rx_burst() → DMA into DARAM 0x3f80.. │ ║
║ │ - c54x_interrupt_ex(dsp, 21, 5) ← BRINT0 wake DSP │ ║
║ │ • calypso_bsp_tx_burst(tn, fn, bits) │ ║
║ │ - read 148 bits from DSP DARAM 0x0900.. │ ║
║ │ - bsp_udp_ul_send() → UDP :6802 → bridge │ ║
║ └─────────────────┬──────────────────────────────────────────────────┘ ║
║ │ UDP TRXDv0 127.0.0.1:6702 (DL recv) ║
║ │ UDP TRXDv0 127.0.0.1:6802 (UL send) ║
╚════════════════════│═══════════════════════════════════════════════════════╝
┌─────────────────── BRIDGE (Python user-space) ─────────────────────────┐
│ bridge.py │
│ • PTY /dev/pts/0 ↔ UART modem (firmware sercomm trace, debug) │
│ • UDP TRXC :5701 (control: SETSLOT, POWERON, etc.) ← osmo-bts-trx │
│ • UDP TRXD :6700 ↔ :6702 (DL bursts BTS→QEMU) │
│ • UDP TRXD :6802 ↔ :6800 (UL bursts QEMU→BTS) │
│ • CLK :5700 (1 IND/frame, drives BTS scheduler) │
└──────────────────────────────┬─────────────────────────────────────────┘
│ TRXD wire (osmo-bts-trx <-> trx)
┌─────────────────── osmo-bts-trx (process `osmo-bts-trx`) ───────────────┐
│ scheduler_trx.c GSM clock (TINT-driven) │
│ l1sap.c PH-DATA / PH-RACH primitive layer │
│ gsm_data_shared logical channel mapping (BCCH/CCCH/SDCCH/TCH) │
│ bts_model.c SI broadcast, SACCH, paging │
│ ↕ Abis/IP │
└─────────────────────────────┬───────────────────────────────────────────┘
│ IPA mux IPAC (TCP 3002/3003)
┌─────────────────── osmo-bsc (process `osmo-bsc`) ───────────────────────┐
│ abis_rsl.c RSL handling (paging, channel activation) │
│ bsc_subscr_conn subscriber connection tracking │
│ handover_* intra/inter BSC handover │
│ ↕ A/IP (M3UA SCCP) │
└─────────────────────────────┬───────────────────────────────────────────┘
│ A interface, BSSAP
┌─────────────────── osmo-msc / hlr / sgsn ───────────────────────────────┐
│ osmo-msc mobility management, call control, SMS, USSD │
│ osmo-hlr subscriber DB, auth (Milenage) │
│ osmo-mgw media gateway (RTP) │
│ osmo-sgsn GPRS session mgmt (data side) │
└─────────────────────────────────────────────────────────────────────────┘
Vue radial inverse (UL — mobile → core) :
mobile L3 (CM/MM) → osmo-msc CC handler
↓ rslms_data_req ↑ BSSAP/SCCP
mobile LAPDm → osmo-bsc RSL DATA IND
↓ ph_data_req ↑ Abis RSL
mobile l1ctl_tx_data_req → osmo-bts-trx l1sap PH-DATA.ind
↓ /tmp/osmocom_l2_1 ↑ scheduler_trx
QEMU l1ctl_sock RX → bridge.py UDP :6800 ← QEMU UL
↓ uart_inject_raw ↑ bsp_udp_ul_send
ARM firmware sercomm parse → calypso_bsp_tx_burst()
↓ l1ctl_rx_data_req ↑ DSP DARAM 0x0900..
prim_data.c::l1s_tx_* ← C54x DSP burst encoder
↓ d_task_u write ↑ ARM ISR + DSP run
calypso_dsp_write API → calypso_trx_send_ul_burst (poll)
↓ TPU prog. UL win. ↑ TINT0 sticky wake
TPU TX trigger ← c54x_interrupt_ex(SINT17)
Le 3 wakes DSP qui composent le pipeline (rappel) :
┌─────────────────┬─────────────────────────────────────┬────────────────────┬────────────────────┬─────────────────────────────────────────┐
│ Wake │ Source │ Vec │ Bit │ Quand │
├─────────────────┼─────────────────────────────────────┼────────────────────┼────────────────────┼─────────────────────────────────────────┤
│ SINT17 (frame) │ calypso_trx.c calypso_tint0_do_tick │ C54X_INT_FRAME_VEC │ C54X_INT_FRAME_BIT │ chaque tick TINT0 quand TPU_CTRL_EN set │
├─────────────────┼─────────────────────────────────────┼────────────────────┼────────────────────┼─────────────────────────────────────────┤
│ BRINT0 (BSP rx) │ calypso_bsp.c calypso_bsp_rx_burst │ 21 │ 5 │ chaque burst UDP DL reçu │
├─────────────────┼─────────────────────────────────────┼────────────────────┼────────────────────┼─────────────────────────────────────────┤
│ TINT0 (timer) │ masqué côté DSP (IMR bit 4 = 0) │ 20 │ 4 │ inactif — firmware n'arme pas │
└─────────────────┴─────────────────────────────────────┴────────────────────┴────────────────────┴─────────────────────────────────────────┘
Verrou actuel : les deux wakes (SINT17 sticky + BRINT0) tirent avant que dsp_init_done soit posé, ce qui interrompt l'init DSP au mauvais moment et fout SP=0 — d'où la régression PC=0x010a qu'on a vu. Le fix : conditionner les deux sur if
(s->dsp_init_done).
C'est ça que tu veux que je code maintenant ?
● Build OK. qemu-system-arm linked successfully with tous les changes (calypso_orch, l1ctl_sock_steal, hooks calypso_trx_on_l1ctl_fw, etc.).
Listed 1 directory (ctrl+o to expand)
● Binaire neuf daté 12:01, contient tous les nouveaux symboles. Tu peux lancer ./run.sh maintenant.
Pour l'UML que tu demandes — voici le diagramme de séquence du flow actuel après build :
@startuml
actor "mobile L23" as L23
participant "l1ctl_sock\n(/tmp/osmocom_l2_1)" as SOCK
participant "calypso_uart\n(FIFO+IRQ)" as UART
participant "ARM L1S\n(firmware)" as ARM
participant "calypso_trx\n(orchestrator)" as TRX
participant "c54x DSP" as DSP
participant "calypso_bsp\n(6702/6802)" as BSP
participant "calypso_orch\n(UDP 6920)" as ORCH
participant "bridge_orch_bursts\n(5702↔6702, 6802↔5802)" as BURSTS
participant "osmo-bts-trx" as BTS
== Boot ==
SOCK -> SOCK : listen /tmp/osmocom_l2_1
ORCH -> ORCH : listen UDP 6920
TRX -> TRX : calypso_orch_init + l1ctl_sock_steal_init(6921)
== Mobile connects ==
L23 -> SOCK : connect + L1CTL RESET_REQ (BE16 len+payload)
SOCK -> UART : sercomm_wrap DLCI5 → inject_raw
UART -> ARM : IRQ_UART_MODEM
ARM -> SOCK : RESET_CONF via l1ctl_sock_uart_tx_byte
SOCK -> L23 : len+payload
SOCK -> TRX : calypso_trx_on_l1ctl_fw(0x0e)
SOCK -> ORCH : calypso_orch_publish(L1CTL, RESET_CONF)
== PM scan ==
L23 -> SOCK -> UART -> ARM : PM_REQ
ARM -> DSP : d_task_md=1 (PM)
TRX -> TRX : dsp_ram_write hook → publish D_TASK
DSP --> ARM : a_pm[] filled
ARM -> SOCK -> L23 : PM_CONF
SOCK -> TRX : calypso_trx_on_l1ctl_fw(0x09) → IRQ_API pulse
== FBSB cycle ==
L23 -> ARM : FBSB_REQ
ARM -> DSP : d_task_md=5 (FB)
BTS -> BURSTS : DL burst UDP 5702
BURSTS -> BSP : UDP 6702
BSP -> DSP : DMA + BRINT0 (gated dsp_init_done)
DSP -> TRX : api_write_cb → publish DSP_API + pulse IRQ_API
DSP --> ARM : d_fb_det=1, a_sync_demod[]
ARM -> SOCK -> L23 : FBSB_CONF
== UL burst ==
DSP -> BSP : calypso_bsp_tx_burst
BSP -> TRX : calypso_trx_on_ul_burst_raw
BSP -> BURSTS : UDP 6802
BURSTS -> BTS : UDP 5802
BSP -> ORCH : publish UL_BURST
@enduml
Bindings :
- /tmp/osmocom_l2_1 → l1ctl_sock.c
- UDP 6920 (orch bus) → calypso_orch.c
- UDP 6921 (L1CTL steal) → l1ctl_sock_steal_init
- UDP 6702/6802 → calypso_bsp.c
- UDP 5700 → bridge_clk.py → BTS
- UDP 5701 → bridge_trxc.py → stub + 6701/5801 RSP
- UDP 5702↔6702 + 6802↔5802 → bridge_orch_bursts.py
- UDP orch sub (éphémère) → bridge_orch_pty.py, bridge_orch_bursts.py
Méthodes publiques côté C (dans calypso_orch.h) :
- calypso_orch_init(), calypso_orch_publish(layer, type, payload, len)
- l1ctl_sock_steal_init(port), l1ctl_sock_inject_dlci(dlci, pl, len), l1ctl_sock_send_to_mobile_synth(pl, len)
- calypso_trx_dsp_init_done(), calypso_trx_on_l1ctl_fw(mt, pl, len), calypso_trx_on_ul_burst_raw(tn, fn, pkt, len), calypso_trx_redirect_ul_to_bsp(pkt, len)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment