Add user manuals for tom-modem and QModem in English and Chinese - Created tom-modem user manual in English and Chinese (zh-cn). - Added comprehensive user guide for QModem in English and Chinese (zh-cn), covering installation, features, configuration options, and troubleshooting steps.
15 KiB
QModem Developer Guide
This document provides a guide for developers looking to understand, extend, or adapt the luci-app-qmodem application.
1. Project Structure
The luci-app-qmodem is the core LuCI application for modem management. Its structure follows the standard LuCI MVC pattern.
luci-app-qmodem/
├── Makefile # Build instructions for the package
├── htdocs/
│ └── luci-static/ # Static web assets (JS, CSS, images)
│ └── resources/
│ └── qmodem/
│ ├── modem.js # Main JavaScript for frontend logic
│ └── ... # Other JS files
├── luasrc/
│ ├── controller/
│ │ └── qmodem.lua # Main controller, handles API requests and page rendering
│ ├── model/
│ │ └── cbi/
│ │ └── qmodem/ # CBI models for configuration pages
│ │ ├── dial_config.lua
│ │ ├── modem_cfg.lua
│ │ └── ...
│ └── view/
│ └── qmodem/ # HTML templates for the views
│ ├── modem_status.htm
│ └── ...
└── root/
└── etc/
├── config/
│ └── qmodem # Default configuration file
└── uci-defaults/
└── luci-qmodem # Script to set up default configs
controller/qmodem.lua: The heart of the application. It defines the menu structure and handles all the API calls from the frontend.model/cbi/qmodem/: Contains the CBI (Configuration Binding Interface) files that generate the forms in the LuCI web interface for configuring the modem.htdocs/luci-static/resources/qmodem/: Contains JavaScript files that provide dynamic functionality to the web interface, such as polling for modem status.root/etc/config/qmodem: The UCI configuration file where all settings for the modem are stored.
2. API Endpoints and Parameters
The frontend communicates with the backend via API calls handled by controller/qmodem.lua. The primary endpoint is /cgi-bin/luci/admin/modem/qmodem. The action is determined by a json parameter in the request.
Here are some of the key API actions:
| Action | Description | Parameters |
|---|---|---|
get_modem_list |
Retrieves a list of detected modems. | - |
get_modem_info |
Gets detailed information for a specific modem. | slot: The slot ID of the modem. |
set_modem_info |
Sets configuration for a modem. | slot, key, value |
scan_modem |
Initiates a scan for new modems. | - |
get_dial_status |
Gets the current network connection status. | slot |
dial_up |
Starts the network connection. | slot |
dial_down |
Stops the network connection. | slot |
send_at_command |
Sends an AT command to the modem. | slot, cmd |
get_sms_list |
Retrieves a list of SMS messages. | slot |
send_sms |
Sends an SMS message. | slot, number, message |
3. Modem Scan Workflow
The modem scan process is crucial for detecting and initializing modems.
- User Trigger: The user clicks the "Scan Modems" button in the web interface.
- API Call: The frontend sends a
scan_modemrequest to the backend. - Backend Script: The
qmodem.luacontroller executes a shell script (/usr/share/qmodem/scan_modem.shor similar). - Device Detection: The script scans for devices that look like modems. This is typically done by:
- Checking
/sys/bus/usb/devicesfor USB devices with known vendor/product IDs. - Checking
/sys/bus/pci/devicesfor PCIe devices. - Looking for TTY devices (
/dev/ttyUSB*,/dev/ttyACM*, etc.) that respond to basic AT commands likeATI.
- Checking
- Information Gathering: For each detected modem, the script gathers basic information (Manufacturer, Model, IMEI, etc.) by sending a series of AT commands.
- UCI Update: The script updates the
qmodemUCI configuration file with the information about the detected modems, creating a new "slot" for each. - Response to Frontend: The API call returns, and the frontend calls
get_modem_listto refresh the list of modems displayed to the user.
4. How to Adapt for a New Modem
Adapting qmodem for a new, unsupported modem generally involves the following steps:
- Identify Device Ports: Connect the modem and identify which TTY port is used for AT commands, and which is used for data (e.g., QMI, NCM, MBIM). You can use
dmesgand look at/dev/to find these. - AT Command Set: Obtain the AT command manual for the new modem. While many commands are standard, some, especially for vendor-specific features, will be different.
- Update
tom_modemor other tools: If the modem requires special handling for AT commands (e.g., binary AT commands, unusual response formats), you may need to modify the underlying command-line tools liketom_modem. - Update Connection Scripts: The dialing scripts (e.g., those used by
quectel-cm) may need to be updated. This could involve:- Adding the modem's QMI/MBIM device path to the script.
- Modifying the AT commands used to put the modem into the correct mode for dialing.
- Update Scan Logic (if necessary): If the modem has a unique USB Vendor/Product ID that isn't recognized, you may need to add it to the detection scripts.
- Add to
support_list.md: Once the modem is working, add it to thesupport_list.mdfile to document its compatibility. - Custom AT Commands: For special features of the new modem (e.g., unique band locking commands), you can add custom AT command buttons to the LuCI interface by editing the CBI and controller files. This allows users to easily access these features.
By following these steps, you can integrate new modems into the qmodem ecosystem and take advantage of its management features.
5. Core Scripts in /usr/share/qmodem
The backend logic is heavily reliant on a set of shell scripts. Understanding these scripts is key to debugging and extending the application.
modem_scan.sh
- Purpose: This script is responsible for detecting, identifying, and configuring modem devices. It is the core of the hotplug and auto-detection system.
- Commands & Parameters:
scan [usb|pcie]: Scans for all modems. Can be limited to a specific bus type (usborpcie). It identifies devices, determines their model, and callsaddfor each one found.add <slot>: Adds or updates a modem configuration in UCI based on a bus slot ID (e.g.,1-1.2for USB,0000:01:00.0for PCIe). It gathers device info and creates theqmodem.<slot_name>configuration section.remove <slot>: Removes a modem's configuration from UCI.disable <slot>: Marks a modem's configuration as disabled.
- Functionality: It reads
modem_support.jsonandmodem_port_rule.jsonto identify supported modems and find their AT command ports.
modem_ctrl.sh
- Purpose: This is the main control script that acts as the backend for most API calls from the LuCI interface. It reads the modem's configuration, sources the correct vendor-specific script, and executes the requested function.
- Commands & Parameters:
modem_ctrl.sh <method> <config_section> [json_data]<method>: The function to call (e.g.,base_info,set_lockband,send_at).<config_section>: The UCI section name of the modem (e.g.,modem_usb_1_1_2).[json_data]: Optional JSON data for functions that require input (e.g., the bands to lock).
- Functionality: It uses the
manufacturerfrom the modem's UCI config to find the corresponding script file in thevendor/directory (viavendor/dynamic_load.json) and then calls the function within that script.
modem_util.sh
- Purpose: A library of common helper functions used by the other scripts.
- Key Functions:
at <device> <command>: Sends an AT command to the specified port usingtom_modem.fastat <device> <command>: Sends an AT command with a short timeout, used for quick checks during scanning.m_debug <message>: Writes a debug message to the system log.
vendor/ Directory
dynamic_load.json: A simple JSON file that maps a vendor name (e.g., "quectel") to its corresponding script file (e.g., "quectel.sh").<vendor_name>.sh: These scripts contain the specific AT command implementations for a particular brand of modem. For example,quectel.shknows how to get signal strength or set band locks using Quectel's specific AT commands.generic.sh: Provides a default set of functions. If a function is not implemented in a specific vendor script, the system falls back to the one ingeneric.sh.
6. Adapting for a New Modem (Advanced)
Adapting a new modem involves teaching qmodem about its characteristics and commands.
Case 1: New Model from an Existing Vendor
If the modem is from a vendor that is already supported (e.g., a new Quectel model), the process is simpler.
- Identify Model Name: Use
tom_modemor another tool to sendAT+CGMMto the modem's AT port and get its model name. - Update
modem_support.json: Add a new entry for your model. You can copy an existing one from the same vendor and platform.- Specify its
manufacturer,platform, supportedmodes(qmi, mbim, etc.), and available frequency bands.
- Specify its
- Test: Run
modem_scan.sh scanand see if the modem is detected and configured correctly. If some functions (like band locking) use different AT commands than other models from that vendor, you will need to modify the vendor's script invendor/<vendor_name>.sh, adding conditional logic based on the$modem_nameor$platformvariable.
Case 2: New Vendor
If the modem is from a completely new vendor, you need to create a new vendor integration.
- Create Vendor Script:
- Create a new file:
/usr/share/qmodem/vendor/<new_vendor>.sh. - The best practice is to copy
/usr/share/qmodem/vendor/generic.shas a template. This ensures you have all the required function stubs.
- Create a new file:
- Update
dynamic_load.json:- Add an entry to map your new vendor name to the script file you just created.
"<new_vendor>": "<new_vendor>.sh"
- Implement Vendor Functions:
- Edit your new
<new_vendor>.shfile. You must implement the functions to get information and control the modem. Refer to the vendor's AT command manual. - Key functions to implement:
get_imeiget_mode/set_modeget_network_prefer/set_network_preferget_lockband/set_lockbandbase_info(gathers basic info like firmware, manufacturer)sim_info(gathers SIM status, IMSI, ICCID)network_info(gathers network type, signal strength)cell_info(gathers detailed cell tower information)get_neighborcell/set_neighborcell(for cell locking)
- Edit your new
- Update
modem_support.json: Add an entry for the new modem model, referencing your newmanufacturername.
How to Disable Unsupported Features
If a modem does not support a specific feature (e.g., it cannot report temperature, or it has no cell locking capability), you can disable its corresponding UI element. This is controlled by adding logic to the vendor_get_disabled_features function within the vendor's script file (/usr/share/qmodem/vendor/<vendor_name>.sh).
The modem_ctrl.sh script calls this function, and the frontend JavaScript reads the returned list of disabled features to hide the corresponding tabs or UI elements.
Available Features to Disable
The features that can be disabled correspond to the tabs in the "Modem Debug" page. Disabling a feature will remove its tab from the UI. Here is the list of controllable UI components and their configuration names:
| Feature Name (UI Tab) | Config Name | Description |
|---|---|---|
| Dial Mode | DialMode |
Disables the "Dial Mode" selection tab. |
| Rat Prefer | RatPrefer |
Disables the "Rat Prefer" selection tab. |
| Set IMEI | IMEI |
Disables the "Set IMEI" tab. |
| Neighbor Cell | NeighborCell |
Disables the "Neighbor Cell" tab. |
| Lock Band | LockBand |
Disables the "Lock Band" tab. |
| Reboot Modem | RebootModem |
Disables the "Reboot Modem" tab. |
| AT Debug | AtDebug |
Disables the "AT Debug" tab. |
Disabling Strategies and Examples
You can implement logic to disable features at different granularities.
1. Disable for an Entire Vendor
To disable a feature for all modems from a specific vendor, simply add the feature's config name to the vendor_get_disabled_features function.
Example: Disable SMS and Voltage for all "ExampleVendor" modems.
# In /usr/share/qmodem/vendor/example_vendor.sh
vendor_get_disabled_features() {
json_add_string "" "sms"
json_add_string "" "voltage"
}
2. Disable for a Specific Platform
If only a certain platform (e.g., qualcomm, unisoc) from a vendor lacks a feature, you can add conditional logic based on the $platform variable.
Example: Disable the "Neighbor Cell" feature for all Quectel modems on the unisoc platform.
# In /usr/share/qmodem/vendor/quectel.sh
vendor_get_disabled_features() {
if [ "$platform" = "unisoc" ]; then
json_add_string "" "NeighborCell"
fi
}
3. Disable for a Specific Model
To target a single modem model, use the $modem_name variable.
Example: Disable band locking for the "RM500U-CN" model.
# In /usr/share/qmodem/vendor/quectel.sh
vendor_get_disabled_features() {
if [ "$modem_name" = "rm500u-cn" ]; then
json_add_string "" "LockBand"
fi
# You can combine conditions
if [ "$platform" = "unisoc" ]; then
json_add_string "" "NeighborCell"
fi
}