# Fibocom FM350-GL 5G Modem Configuration Guide

Complete reference for configuring the Fibocom FM350-GL modem on Alpine Linux.

## Working Configuration

| Setting | Value |
|---------|-------|
| **Modem** | Fibocom FM350-GL |
| **USB ID** | 0e8d:7126 (Mode 40) |
| **AT Port** | /dev/ttyUSB1 |
| **Network Interface** | eth1 (RNDIS) |
| **APN** | internet (CYTA Cyprus) |

## AT Command Reference

### Sending AT Commands

The FM350-GL doesn't need `stty` configuration. Send commands directly:

```bash
# Pattern for sending AT commands
cat /dev/ttyUSB1 & CAT_PID=$!
sleep 0.3
echo -e 'YOUR_COMMAND\r' > /dev/ttyUSB1
sleep 2
kill $CAT_PID 2>/dev/null
```

### Essential Commands

| Command | Purpose | Example Response |
|---------|---------|------------------|
| `AT` | Test communication | `OK` |
| `AT+CGMI` | Manufacturer | `Fibocom Wireless Inc.` |
| `AT+CGMM` | Model | `FM350-GL` |
| `AT+CSQ` | Signal strength | `+CSQ: 7, 99` (7 = moderate) |
| `AT+CREG?` | Network registration | `+CREG: 0,1` (1 = registered) |
| `AT+CEREG?` | LTE/5G registration | `+CEREG: 0,1` |
| `AT+CCID` | SIM card ID | `+CCID: 893570...` |

### APN Configuration

```bash
# Set APN (CYTA Cyprus uses "internet")
echo -e 'AT+CGDCONT=1,"IP","internet"\r' > /dev/ttyUSB1

# Verify APN is set
echo -e 'AT+CGDCONT?\r' > /dev/ttyUSB1
# Response: +CGDCONT: 1,"IP","internet",""...
```

### Connection Management

```bash
# Activate PDP context (start data connection)
echo -e 'AT+CGACT=1,1\r' > /dev/ttyUSB1
# Response: +CGEV: ME PDN ACT 1, OK

# Get assigned IP address
echo -e 'AT+CGPADDR=1\r' > /dev/ttyUSB1
# Response: +CGPADDR: 1,"10.156.167.104",""

# Get full connection details (DNS, MTU)
echo -e 'AT+CGCONTRDP=1\r' > /dev/ttyUSB1
# Response includes DNS servers
```

### USB Mode Control

```bash
# Check current USB mode
echo -e 'AT+GTUSBMODE?\r' > /dev/ttyUSB1
# Response: +GTUSBMODE: 40

# Available modes
echo -e 'AT+GTUSBMODE=?\r' > /dev/ttyUSB1
# Response: +GTUSBMODE: (40,41)

# Switch modes (requires modem reset)
echo -e 'AT+GTUSBMODE=40\r' > /dev/ttyUSB1

# Reset modem
echo -e 'AT+CFUN=1,1\r' > /dev/ttyUSB1
```

## USB Modes

| Mode | USB Product ID | Description | AT Commands |
|------|----------------|-------------|-------------|
| 40 | 0e8d:7126 | RNDIS mode | ✅ Work on ttyUSB1 |
| 41 | 0e8d:7127 | Extended mode | ❌ Don't work |

**Important:** Stay in Mode 40 for reliable AT command access.

## Network Interface Configuration

### Why DHCP Doesn't Work

The RNDIS interface (`eth1`) does **not** provide DHCP. The modem does not assign an IP to the host via DHCP. You must:

1. Get the IP from the modem via **`AT+CGPADDR=1`**
2. Optionally get DNS via **`AT+CGCONTRDP=1`** (connection dynamic parameters)
3. Configure the interface and `/etc/resolv.conf` manually

The **connect-5g.sh** script does exactly this: it uses AT commands only (no DHCP on eth1), then sets `ip addr` and default route on eth1, and DNS from modem or from config.

### Manual Configuration

```bash
# Get IP from modem (replace with actual value)
MODEM_IP="10.156.167.104"

# Configure interface
ip link set eth1 up
ip addr flush dev eth1
ip addr add $MODEM_IP/32 dev eth1
ip route add default dev eth1 metric 50

# Test
ping -c 3 8.8.8.8
```

## CYTA Cyprus Settings

| Setting | Value |
|---------|-------|
| APN | `internet` |
| DNS Primary | 195.14.130.220 |
| DNS Secondary | 195.14.154.100 |
| Network Name | Vodafone |

## Complete Connection Sequence

```bash
#!/bin/sh
# Full connection sequence for FM350-GL with CYTA SIM

AT_PORT="/dev/ttyUSB1"
APN="internet"

# 1. Configure APN
cat $AT_PORT & PID=$!; sleep 0.3
echo -e "AT+CGDCONT=1,\"IP\",\"$APN\"\r" > $AT_PORT
sleep 2; kill $PID 2>/dev/null

# 2. Activate connection
cat $AT_PORT & PID=$!; sleep 0.3
echo -e "AT+CGACT=1,1\r" > $AT_PORT
sleep 3; kill $PID 2>/dev/null

# 3. Get IP address
MODEM_IP=$(timeout 5 sh -c "
    cat $AT_PORT & PID=\$!
    sleep 0.3
    echo -e 'AT+CGPADDR=1\r' > $AT_PORT
    sleep 2
    kill \$PID 2>/dev/null
" 2>&1 | grep CGPADDR | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)

echo "Modem IP: $MODEM_IP"

# 4. Configure interface
ip link set eth1 up
ip addr flush dev eth1
ip addr add $MODEM_IP/32 dev eth1
ip route add default dev eth1 metric 50

# 5. Test
ping -c 3 8.8.8.8
```

## Troubleshooting

### Run full diagnostic (modem not responding after reboot)

**When the modem does not respond** after a reboot, run the full troubleshoot script on the device to collect all logs and checks:

```bash
# On the device (SSH or console)
/usr/local/bin/troubleshoot-5g.sh
```

If the script is not installed yet, deploy first (`./scripts/deploy.sh` or `./scripts/install.sh` on the device), or run from the repo:

```bash
./scripts/troubleshoot-5g.sh
```

The script prints:

- **dmesg** (last 40 lines) – kernel messages about USB/tty
- **lsusb** – modem present and Mode 40 (7126) vs Mode 41 (7127)
- **/dev/ttyUSB*** – whether each port is a character device or a broken regular file
- **AT test** on the configured port (with 3s wait, like connect-5g.sh)
- **AT probe** on each ttyUSB port – which port returns OK
- **5g-router service** status
- **WAN interface** and default route
- **Last 60 lines** of `/var/log/5g-router.log`
- **Processes using the AT port** (lsof) – see if ModemManager or another process is holding the port
- **modem-status-at.sh** output (registration, signal) if installed

Copy the full output and use it to see: wrong AT port, broken ttyUSB node, modem in Mode 41, another process holding the port, or service/APN issues. Then apply the fixes listed at the end of the script or in the sections below.

### AT Commands Not Responding / "AT not OK"

**Symptoms:** No response to AT commands, or connect script logs "AT not OK".

**Solutions:**
1. **Wait longer** – The modem can take 2–4 seconds to respond. The script now waits 3 s for the initial AT. If you still see "AT not OK", increase the wait in `get_at_response` or in config.
2. Check modem is in Mode 40: `lsusb | grep 7126`
3. If in Mode 41 (7127), AT commands won't work - need physical access to switch back
4. **Try different ports** – On FM350-GL the AT port is often ttyUSB1, but it can be ttyUSB0 or another. Test manually:
   ```bash
   ( timeout 5 cat /dev/ttyUSB1 & ); sleep 0.5; echo -e 'AT\r' > /dev/ttyUSB1; sleep 3; kill %1 2>/dev/null
   ```
   If you see `OK` in the output, that port works. Set `AT_PORT="/dev/ttyUSB1"` (or the working port) in `/etc/5g-router.conf`.
5. **Ensure no other process is holding the port** (e.g. ModemManager, a stuck `cat`, or the Web GUI polling modem-status-at.sh). Run `lsof /dev/ttyUSB1` to see who has it open. Stop ModemManager if present: `rc-service ModemManager stop`. If the 5g-router service is stuck with an open `cat`, restart it: `service 5g-router restart`.

### ttyUSB port shows as regular file (AT not responding)

**Symptoms:** `ls -la /dev/ttyUSB1` shows `-rw-rw----` (regular file) instead of `crw-rw----` (character device). AT commands get no reply or garbage.

**Cause:** A **shell redirect** to `/dev/ttyUSB1` when the device **does not exist yet** (e.g. modem not bound, or device removed) **creates a regular file** at that path. That file then “steals” the name: when the kernel later creates the real modem port, it may get a different name (e.g. ttyUSB5). Typical causes:
- A script or cron job (e.g. Web GUI status poll, modem-status-at.sh) runs **before** the modem is ready and does `echo ... > /dev/ttyUSB1`.
- The 5g-router service runs at boot; between “port available” and sending AT, the modem briefly disappears (USB glitch) and the next write creates a file.
- ModemManager or another daemon opening the port when it doesn’t exist.

**Prevention:** All project scripts that write to the AT port now check `[ -c "$AT_PORT" ]` immediately before writing and skip/exit if it’s not a character device, so they never create a regular file. The connection script also removes a stray `/dev/ttyUSB` (no number) file at startup.

**Fix (one-time):**
```bash
# Replace N with the port number (0, 1, 2, …)
rm -f /dev/ttyUSB1
mknod /dev/ttyUSB1 c 188 1
chmod 660 /dev/ttyUSB1
chown root:dialout /dev/ttyUSB1
```

**Prevention:** `connect-5g.sh` now checks and fixes a broken AT port automatically before use (recreates the device node if it is a regular file). Scripts never write to the port unless it is currently a character device, so they don’t create the file in the first place.

### Stray /dev/ttyUSB file (no number)

**Symptoms:** Troubleshoot shows `/dev/ttyUSB` as a regular file (no digit). Real ports are ttyUSB0, ttyUSB1, etc.

**Fix:** Remove the stray file. The connection script now removes it automatically; you can also run: `rm -f /dev/ttyUSB`

### ttyUSB3 Shows as Regular File (legacy)

**Symptoms:** `ls -la /dev/ttyUSB3` shows `-rw-r--r--` instead of `crw-rw----`

**Fix:**
```bash
rm -f /dev/ttyUSB3
mknod /dev/ttyUSB3 c 188 3
chmod 660 /dev/ttyUSB3
chown root:dialout /dev/ttyUSB3
```

### stty Errors

**Symptoms:** `stty: /dev/ttyUSB1: cannot perform all requested operations`

**Solution:** Don't use `stty`. Send AT commands directly with `echo` and `cat`.

### No IP on eth1 / Could not get modem IP

**Symptoms:** `ip addr show eth1` shows no inet address; or connect script logs "Could not get modem IP".

**Solutions:**
1. RNDIS doesn't use DHCP. The script gets the IP from `AT+CGPADDR=1`; if the operator hasn't assigned one yet, it retries a few times. Wait and re-run the connection script.
2. Check registration and signal: run `AT+CEREG?` (expect `,1` or `,5` for registered) and `AT+CSQ` (signal strength). If not registered or no signal, fix antenna/SIM/location.
3. Ensure APN is correct for your operator (e.g. `internet` for CYTA).
4. Try activating PDP again: `AT+CGACT=1,1` then wait 5–10 s and `AT+CGPADDR=1`.

### ModemManager Not Detecting Modem

**Note:** ModemManager doesn't work well with this modem in RNDIS mode. Use AT commands directly instead.

### Signal Strength Interpretation

| CSQ Value | dBm | Quality |
|-----------|-----|---------|
| 0 | -113 or less | No signal |
| 1-9 | -111 to -95 | Poor |
| 10-14 | -93 to -85 | Fair |
| 15-19 | -83 to -75 | Good |
| 20-30 | -73 to -53 | Excellent |
| 31 | -51 or better | Excellent |
| 99 | Unknown | - |

## Kernel Modules

These modules should be loaded for MBIM/QMI support (optional):

```bash
modprobe cdc-wdm
modprobe cdc_mbim
modprobe qmi_wwan
modprobe cdc_ncm

# Verify
lsmod | grep -E '(cdc|qmi)'
```

## Files on Device

| Path | Purpose |
|------|---------|
| `/usr/local/bin/connect-5g.sh` | Auto-connection script |
| `/usr/local/bin/troubleshoot-5g.sh` | Full diagnostic (logs + AT/USB checks) |
| `/etc/init.d/5g-router` | OpenRC service |
| `/var/log/5g-router.log` | Connection log |
| `/etc/iptables/rules.v4` | Firewall/NAT rules |

## Service Management

```bash
# Check status
service 5g-router status

# Restart connection
service 5g-router restart

# View logs
tail -f /var/log/5g-router.log

# Check if enabled at boot
rc-update show | grep 5g-router
```
