mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 10:31:38 +08:00
🍉 Sync 2026-06-04 16:44:02
This commit is contained in:
parent
c2f5e11633
commit
0bb17b828a
137
fusiontunx/Makefile
Normal file
137
fusiontunx/Makefile
Normal file
@ -0,0 +1,137 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=fusiontunx
|
||||
PKG_VERSION:=1.0.3-4
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=BobbyUnknown
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/bobbyunknown/FusionTunX.git
|
||||
PKG_SOURCE_VERSION:=dd3605dcb3ad75933c4c27ac28f2276ea2af85aa
|
||||
PKG_HASH:=skip
|
||||
#PKG_MIRROR_HASH:=f37155115e9e96661b5c5d41f7c33d0af6babaebe66dbe9017858292d6cb4589
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
|
||||
PKG_BUILD_DEPENDS:=node/host golang/host
|
||||
|
||||
MIHOMO_VERSION:=v1.19.18
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
GO_PKG:=github.com/bobbyunknown/FusionTunX
|
||||
|
||||
# Determine Mihomo arch suffix
|
||||
MIHOMO_ARCH:=$(GO_ARCH)
|
||||
ifeq ($(GO_ARCH),arm)
|
||||
MIHOMO_ARCH:=armv$(or $(GO_ARM),7)
|
||||
else ifeq ($(findstring mips,$(GO_ARCH)),mips)
|
||||
MIHOMO_ARCH:=$(GO_ARCH)-$(or $(GO_MIPS),softfloat)
|
||||
else ifeq ($(GO_ARCH),aarch64)
|
||||
MIHOMO_ARCH:=arm64
|
||||
endif
|
||||
|
||||
define Package/fusiontunx
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=FusionTunX Core + Mihomo
|
||||
URL:=https://github.com/bobbyunknown/FusionTunX
|
||||
DEPENDS:=+ca-bundle +ip-full +kmod-tun +kmod-nft-core +kmod-nft-nat +kmod-nft-tproxy +kmod-nft-socket
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/description
|
||||
FusionTunX + Mihomo Core Binary
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
@echo "Building Vite dashboard..."
|
||||
cd $(PKG_BUILD_DIR)/src/dash && \
|
||||
npm install && \
|
||||
npm run build
|
||||
|
||||
@echo "Preparing static files..."
|
||||
rm -rf $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
cp -r $(PKG_BUILD_DIR)/src/dash/dist $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
chmod -R 755 $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
|
||||
@echo "Installing dependencies and generating Swagger..."
|
||||
cd $(PKG_BUILD_DIR)/src && \
|
||||
go mod tidy && \
|
||||
go install github.com/swaggo/swag/cmd/swag@latest && \
|
||||
$(HOME)/go/bin/swag init -g cmd/server/main.go -o docs
|
||||
|
||||
@echo "Compiling FusionTunX Go binary..."
|
||||
cd $(PKG_BUILD_DIR)/src && \
|
||||
GOOS=linux \
|
||||
GOARCH=$(GO_ARCH) \
|
||||
$(if $(findstring arm,$(GO_ARCH)),GOARM=$(or $(GO_ARM),7)) \
|
||||
$(if $(findstring mips,$(GO_ARCH)),GOMIPS=$(or $(GO_MIPS),softfloat)) \
|
||||
CGO_ENABLED=0 \
|
||||
go build -v -trimpath -ldflags="-s -w" -o $(PKG_BUILD_DIR)/fusiontunx ./cmd/server
|
||||
|
||||
@echo "Downloading Mihomo $(MIHOMO_VERSION)..."
|
||||
wget -q -O $(PKG_BUILD_DIR)/mihomo.gz "https://github.com/MetaCubeX/mihomo/releases/download/$(MIHOMO_VERSION)/mihomo-linux-$(MIHOMO_ARCH)-$(MIHOMO_VERSION).gz"
|
||||
gunzip -f $(PKG_BUILD_DIR)/mihomo.gz
|
||||
chmod +x $(PKG_BUILD_DIR)/mihomo
|
||||
|
||||
@echo "Downloading GeoIP assets..."
|
||||
wget -q -O $(PKG_BUILD_DIR)/country.mmdb https://github.com/rtaserver/meta-rules-dat/releases/latest/download/country.mmdb
|
||||
wget -q -O $(PKG_BUILD_DIR)/geoip.dat https://github.com/rtaserver/meta-rules-dat/releases/latest/download/geoip.dat
|
||||
wget -q -O $(PKG_BUILD_DIR)/geosite.dat https://github.com/rtaserver/meta-rules-dat/releases/latest/download/geosite.dat
|
||||
wget -q -O $(PKG_BUILD_DIR)/geoip.metadb https://github.com/rtaserver/meta-rules-dat/releases/download/latest/geoip.metadb
|
||||
|
||||
@echo "Downloading Zashboard..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/zashboard.zip "https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip"
|
||||
mkdir -p $(PKG_BUILD_DIR)/ui/zashboard
|
||||
unzip -q $(PKG_BUILD_DIR)/zashboard.zip -d $(PKG_BUILD_DIR)/temp_zashboard
|
||||
mv $(PKG_BUILD_DIR)/temp_zashboard/dist/* $(PKG_BUILD_DIR)/ui/zashboard/
|
||||
rm -rf $(PKG_BUILD_DIR)/temp_zashboard $(PKG_BUILD_DIR)/zashboard.zip
|
||||
|
||||
@echo "Downloading MetaCubeXD..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/metacubexd.tgz "https://github.com/MetaCubeX/metacubexd/releases/latest/download/compressed-dist.tgz"
|
||||
mkdir -p $(PKG_BUILD_DIR)/ui/metacubexd
|
||||
tar -xzf $(PKG_BUILD_DIR)/metacubexd.tgz -C $(PKG_BUILD_DIR)/ui/metacubexd
|
||||
rm $(PKG_BUILD_DIR)/metacubexd.tgz
|
||||
|
||||
@echo "Downloading Yacd..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/yacd.zip "https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip"
|
||||
unzip -q $(PKG_BUILD_DIR)/yacd.zip -d $(PKG_BUILD_DIR)/temp_yacd
|
||||
mv $(PKG_BUILD_DIR)/temp_yacd/Yacd-meta-gh-pages $(PKG_BUILD_DIR)/ui/yacd
|
||||
rm -rf $(PKG_BUILD_DIR)/temp_yacd $(PKG_BUILD_DIR)/yacd.zip
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_DIR) $(1)/usr/share/fusiontunx
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/configs
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/proxy_providers
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/rule_providers
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/ui
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/fusiontunx $(1)/usr/share/fusiontunx/fusiontunx
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mihomo $(1)/usr/bin/mihomo
|
||||
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/app.yaml $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/country.mmdb $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geoip.dat $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geosite.dat $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geoip.metadb $(1)/etc/fusiontunx/
|
||||
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/configs/* $(1)/etc/fusiontunx/configs/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/proxy_providers/* $(1)/etc/fusiontunx/proxy_providers/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/rule_providers/* $(1)/etc/fusiontunx/rule_providers/
|
||||
|
||||
$(CP) -r $(PKG_BUILD_DIR)/ui/* $(1)/etc/fusiontunx/ui/
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/conffiles
|
||||
/etc/fusiontunx/app.yaml
|
||||
/etc/fusiontunx/configs/config.yaml
|
||||
/etc/fusiontunx/proxy_providers/proxy.yaml
|
||||
/etc/fusiontunx/rule_providers/rule.yaml
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,fusiontunx))
|
||||
132
fusiontunx/Makefile.backup
Normal file
132
fusiontunx/Makefile.backup
Normal file
@ -0,0 +1,132 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=fusiontunx
|
||||
PKG_VERSION:=1.0.3
|
||||
PKG_RELEASE:=4
|
||||
|
||||
PKG_MAINTAINER:=BobbyUnknown
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
# Direct download configuration - change GIT_BRANCH to switch branches
|
||||
GIT_BRANCH:=dev
|
||||
|
||||
# Direct download method (no git)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/bobbyunknown/FusionTunX/archive/refs/heads/$(GIT_BRANCH).tar.gz?
|
||||
PKG_HASH:=skip
|
||||
|
||||
PKG_BUILD_DEPENDS:=node/host golang/host
|
||||
|
||||
MIHOMO_VERSION:=v1.19.17
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
GO_PKG:=github.com/bobbyunknown/FusionTunX
|
||||
|
||||
define Package/fusiontunx
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=FusionTunX Core + Mihomo
|
||||
URL:=https://github.com/bobbyunknown/FusionTunX
|
||||
DEPENDS:=+ca-bundle +ip-full +kmod-tun +kmod-nft-core +kmod-nft-nat +kmod-nft-tproxy +kmod-nft-socket
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/description
|
||||
FusionTunX + Mihomo Core Binary
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(HOST_TAR) -C $(PKG_BUILD_DIR) --strip-components=1 -xzf $(DL_DIR)/$(PKG_SOURCE)
|
||||
$(Build/Patch)
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
@echo "Building Vite dashboard..."
|
||||
cd $(PKG_BUILD_DIR)/src/dash && \
|
||||
npm install && \
|
||||
npm run build
|
||||
|
||||
@echo "Preparing static files..."
|
||||
rm -rf $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
cp -r $(PKG_BUILD_DIR)/src/dash/dist $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
chmod -R 755 $(PKG_BUILD_DIR)/src/internal/ui/dist
|
||||
|
||||
@echo "Installing dependencies and generating Swagger..."
|
||||
cd $(PKG_BUILD_DIR)/src && \
|
||||
go mod tidy && \
|
||||
go install github.com/swaggo/swag/cmd/swag@latest && \
|
||||
$(HOME)/go/bin/swag init -g cmd/server/main.go -o docs
|
||||
|
||||
@echo "Compiling FusionTunX Go binary..."
|
||||
cd $(PKG_BUILD_DIR)/src && \
|
||||
GOOS=linux GOARCH=$(GO_ARCH) CGO_ENABLED=1 \
|
||||
CC=$(TARGET_CC) CXX=$(TARGET_CXX) \
|
||||
CGO_CFLAGS="$(TARGET_CFLAGS)" \
|
||||
CGO_LDFLAGS="$(TARGET_LDFLAGS)" \
|
||||
go build -v -trimpath -ldflags="-s -w" -o $(PKG_BUILD_DIR)/fusiontunx ./cmd/server
|
||||
|
||||
@echo "Downloading Mihomo $(MIHOMO_VERSION)..."
|
||||
wget -q -O $(PKG_BUILD_DIR)/mihomo.gz "https://github.com/MetaCubeX/mihomo/releases/download/$(MIHOMO_VERSION)/mihomo-linux-$(GO_ARCH)-$(MIHOMO_VERSION).gz"
|
||||
gunzip -f $(PKG_BUILD_DIR)/mihomo.gz
|
||||
chmod +x $(PKG_BUILD_DIR)/mihomo
|
||||
|
||||
@echo "Downloading GeoIP assets..."
|
||||
wget -q -O $(PKG_BUILD_DIR)/country.mmdb https://github.com/rtaserver/meta-rules-dat/releases/latest/download/country.mmdb
|
||||
wget -q -O $(PKG_BUILD_DIR)/geoip.dat https://github.com/rtaserver/meta-rules-dat/releases/latest/download/geoip.dat
|
||||
wget -q -O $(PKG_BUILD_DIR)/geosite.dat https://github.com/rtaserver/meta-rules-dat/releases/latest/download/geosite.dat
|
||||
wget -q -O $(PKG_BUILD_DIR)/geoip.metadb https://github.com/rtaserver/meta-rules-dat/releases/download/latest/geoip.metadb
|
||||
|
||||
@echo "Downloading Zashboard..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/zashboard.zip "https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip"
|
||||
mkdir -p $(PKG_BUILD_DIR)/ui/zashboard
|
||||
unzip -q $(PKG_BUILD_DIR)/zashboard.zip -d $(PKG_BUILD_DIR)/temp_zashboard
|
||||
mv $(PKG_BUILD_DIR)/temp_zashboard/dist/* $(PKG_BUILD_DIR)/ui/zashboard/
|
||||
rm -rf $(PKG_BUILD_DIR)/temp_zashboard $(PKG_BUILD_DIR)/zashboard.zip
|
||||
|
||||
@echo "Downloading MetaCubeXD..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/metacubexd.tgz "https://github.com/MetaCubeX/metacubexd/releases/latest/download/compressed-dist.tgz"
|
||||
mkdir -p $(PKG_BUILD_DIR)/ui/metacubexd
|
||||
tar -xzf $(PKG_BUILD_DIR)/metacubexd.tgz -C $(PKG_BUILD_DIR)/ui/metacubexd
|
||||
rm $(PKG_BUILD_DIR)/metacubexd.tgz
|
||||
|
||||
@echo "Downloading Yacd..."
|
||||
curl -sL -o $(PKG_BUILD_DIR)/yacd.zip "https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip"
|
||||
unzip -q $(PKG_BUILD_DIR)/yacd.zip -d $(PKG_BUILD_DIR)/temp_yacd
|
||||
mv $(PKG_BUILD_DIR)/temp_yacd/Yacd-meta-gh-pages $(PKG_BUILD_DIR)/ui/yacd
|
||||
rm -rf $(PKG_BUILD_DIR)/temp_yacd $(PKG_BUILD_DIR)/yacd.zip
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_DIR) $(1)/usr/share/fusiontunx
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/configs
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/proxy_providers
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/rule_providers
|
||||
$(INSTALL_DIR) $(1)/etc/fusiontunx/ui
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/fusiontunx $(1)/usr/share/fusiontunx/fusiontunx
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mihomo $(1)/usr/bin/mihomo
|
||||
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/app.yaml $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/country.mmdb $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geoip.dat $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geosite.dat $(1)/etc/fusiontunx/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/geoip.metadb $(1)/etc/fusiontunx/
|
||||
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/configs/* $(1)/etc/fusiontunx/configs/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/proxy_providers/* $(1)/etc/fusiontunx/proxy_providers/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/rule_providers/* $(1)/etc/fusiontunx/rule_providers/
|
||||
|
||||
$(CP) -r $(PKG_BUILD_DIR)/ui/* $(1)/etc/fusiontunx/ui/
|
||||
endef
|
||||
|
||||
define Package/fusiontunx/conffiles
|
||||
/etc/fusiontunx/app.yaml
|
||||
/etc/fusiontunx/configs/config.yaml
|
||||
/etc/fusiontunx/proxy_providers/proxy.yaml
|
||||
/etc/fusiontunx/rule_providers/rule.yaml
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,fusiontunx))
|
||||
96
luci-app-fusiontunx/Makefile
Normal file
96
luci-app-fusiontunx/Makefile
Normal file
@ -0,0 +1,96 @@
|
||||
# - Copyright 2024
|
||||
# - bobbyunknown <https://github.com/bobbyunknown>
|
||||
#
|
||||
# https://opensource.org/license/mit
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-fusiontunx
|
||||
PKG_VERSION:=1.0.3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=BobbyUnknown <bobbyun.known88@gmail.com>
|
||||
|
||||
LUCI_TITLE:=Luci Simple Tunnel Client for Mihomo
|
||||
LUCI_DEPENDS:=+fusiontunx
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
RUN_DIR=/etc/fusiontunx
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
CATEGORY:=LuCI
|
||||
SUBMENU:=3. Applications
|
||||
TITLE:=$(LUCI_TITLE)
|
||||
PKGARCH:=$(LUCI_PKGARCH)
|
||||
DEPENDS:=$(LUCI_DEPENDS)
|
||||
MAINTAINER:=$(PKG_MAINTAINER)
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
Luci Simple Tunnel Client for Mihomo (Clash Meta Core). Provides transparent proxy with TUN/TPROXY mode.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
# 1. Install Init Script
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./root/etc/init.d/fusiontunx $(1)/etc/init.d/fusiontunx
|
||||
|
||||
# 2. Install LuCI Files
|
||||
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
|
||||
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/* $(1)/usr/share/luci/menu.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/* $(1)/usr/share/rpcd/acl.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/fusiontunx
|
||||
$(INSTALL_DATA) ./root/www/luci-static/resources/view/fusiontunx/* $(1)/www/luci-static/resources/view/fusiontunx/
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$$IPKG_INSTROOT" ] || {
|
||||
/etc/init.d/fusiontunx enable
|
||||
/etc/init.d/fusiontunx start
|
||||
}
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/prerm
|
||||
#!/bin/sh
|
||||
[ -n "$$IPKG_INSTROOT" ] || {
|
||||
/etc/init.d/fusiontunx stop
|
||||
/etc/init.d/fusiontunx disable
|
||||
}
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
|
||||
23
luci-app-fusiontunx/root/etc/init.d/fusiontunx
Executable file
23
luci-app-fusiontunx/root/etc/init.d/fusiontunx
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=15
|
||||
USE_PROCD=1
|
||||
|
||||
BIN_PATH="/usr/share/fusiontunx/fusiontunx"
|
||||
CONFIG_FILE="/etc/fusiontunx/app.yaml"
|
||||
|
||||
start_service() {
|
||||
procd_open_instance fusiontunx
|
||||
procd_set_param command "$BIN_PATH" -c "$CONFIG_FILE"
|
||||
procd_set_param term_timeout 15
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "fusiontunx"
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
{
|
||||
"admin/services/fusiontunx": {
|
||||
"title": "FusionTunX",
|
||||
"order": 50,
|
||||
"action": {
|
||||
"type": "alias",
|
||||
"path": "admin/services/fusiontunx/dashboard"
|
||||
}
|
||||
},
|
||||
"admin/services/fusiontunx/dashboard": {
|
||||
"title": "Dashboard",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "fusiontunx/fusiontunx"
|
||||
}
|
||||
},
|
||||
"admin/services/fusiontunx/server": {
|
||||
"title": "Server",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "fusiontunx/server"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
{
|
||||
"luci-app-fusiontunx": {
|
||||
"description": "Grant access to FusionTunX status and control",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"service": [
|
||||
"list"
|
||||
]
|
||||
},
|
||||
"file": {
|
||||
"/etc/init.d/fusiontunx": [
|
||||
"read"
|
||||
]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/etc/init.d/fusiontunx": [
|
||||
"exec"
|
||||
]
|
||||
},
|
||||
"ubus": {
|
||||
"service": [
|
||||
"start",
|
||||
"stop",
|
||||
"delete"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
|
||||
var callServiceList = rpc.declare({
|
||||
object: 'service',
|
||||
method: 'list',
|
||||
params: ['name'],
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function () {
|
||||
return fs.read('/etc/fusiontunx/app.yaml').then(function (content) {
|
||||
var port = '8080';
|
||||
if (content) {
|
||||
var match = content.match(/port:\s*["']?(\d+)["']?/);
|
||||
if (match) port = match[1];
|
||||
}
|
||||
return port;
|
||||
}).catch(function () { return '8080'; });
|
||||
},
|
||||
|
||||
render: function (port) {
|
||||
var url = 'http://' + window.location.hostname + ':' + port;
|
||||
|
||||
var iframe = E('iframe', {
|
||||
'src': url,
|
||||
'style': 'width: 100%; min-height: 85vh; border: none; display: none;',
|
||||
'title': 'FusionTunX Dashboard'
|
||||
});
|
||||
|
||||
var warning = E('div', {
|
||||
'class': 'cbi-section',
|
||||
'style': 'display: none; text-align: center; margin-top: 50px; padding: 30px;'
|
||||
}, [
|
||||
E('h3', { 'style': 'color: #d9534f;' }, _('Service is Not Running')),
|
||||
E('p', { 'style': 'margin: 15px 0 25px;' }, _('The FusionTunX backend service is currently stopped. Please start the service to access the dashboard.')),
|
||||
E('div', {}, [
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'click': function () {
|
||||
window.location.href = L.url('admin', 'services', 'fusiontunx', 'server');
|
||||
}
|
||||
}, _('Go to Server Control'))
|
||||
])
|
||||
]);
|
||||
|
||||
var container = E('div', {}, [warning, iframe]);
|
||||
|
||||
var updateStatus = function () {
|
||||
return callServiceList('fusiontunx').then(function (res) {
|
||||
var running = false;
|
||||
try {
|
||||
var instances = res.fusiontunx.instances;
|
||||
for (var i in instances) {
|
||||
if (instances[i].running) {
|
||||
running = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
if (running) {
|
||||
if (iframe.style.display === 'none') {
|
||||
warning.style.display = 'none';
|
||||
iframe.style.display = 'block';
|
||||
iframe.src = iframe.src;
|
||||
}
|
||||
} else {
|
||||
if (warning.style.display === 'none') {
|
||||
iframe.style.display = 'none';
|
||||
warning.style.display = 'block';
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
updateStatus();
|
||||
|
||||
poll.add(updateStatus, 3);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -0,0 +1,142 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
|
||||
var callServiceList = rpc.declare({
|
||||
object: 'service',
|
||||
method: 'list',
|
||||
params: ['name'],
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function () {
|
||||
return fs.read('/etc/fusiontunx/app.yaml').then(function (content) {
|
||||
var port = '8080';
|
||||
if (content) {
|
||||
var match = content.match(/port:\s*["']?(\d+)["']?/);
|
||||
if (match) port = match[1];
|
||||
}
|
||||
return port;
|
||||
}).catch(function () { return '8080'; });
|
||||
},
|
||||
|
||||
render: function (port) {
|
||||
var statusEl = E('span', { 'class': 'label' }, _('Checking...'));
|
||||
|
||||
var btnStart = E('button', {
|
||||
'class': 'cbi-button cbi-button-apply',
|
||||
'disabled': true
|
||||
}, _('Start'));
|
||||
|
||||
var btnRestart = E('button', {
|
||||
'class': 'cbi-button cbi-button-save',
|
||||
'disabled': true
|
||||
}, _('Restart'));
|
||||
|
||||
var btnStop = E('button', {
|
||||
'class': 'cbi-button cbi-button-reset',
|
||||
'disabled': true
|
||||
}, _('Stop'));
|
||||
|
||||
var btnOpen = E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'disabled': true,
|
||||
'click': function () {
|
||||
var url = 'http://' + window.location.hostname + ':' + port;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}, _('Open Dashboard'));
|
||||
|
||||
|
||||
|
||||
var handleAction = function (action) {
|
||||
return fs.exec('/etc/init.d/fusiontunx', [action]).then(function (res) {
|
||||
if (res.code !== 0) {
|
||||
ui.addNotification(null, E('p', _('Command failed: %s').format(res.stderr || res.stdout)), 'error');
|
||||
throw new Error(res.stderr || res.stdout);
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var handleStart = function () {
|
||||
return fs.exec('/etc/init.d/fusiontunx', ['enable']).then(function () {
|
||||
return handleAction('start');
|
||||
});
|
||||
};
|
||||
|
||||
var handleStop = function () {
|
||||
return handleAction('stop').then(function () {
|
||||
return fs.exec('/etc/init.d/fusiontunx', ['disable']);
|
||||
});
|
||||
};
|
||||
|
||||
btnStart.onclick = ui.createHandlerFn(this, handleStart);
|
||||
btnRestart.onclick = ui.createHandlerFn(this, function () { return handleAction('restart'); });
|
||||
btnStop.onclick = ui.createHandlerFn(this, handleStop);
|
||||
|
||||
var updateStatus = function () {
|
||||
return callServiceList('fusiontunx').then(function (res) {
|
||||
var running = false;
|
||||
try {
|
||||
var instances = res.fusiontunx.instances;
|
||||
for (var i in instances) {
|
||||
if (instances[i].running) {
|
||||
running = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
if (running) {
|
||||
statusEl.textContent = _('Running');
|
||||
statusEl.className = 'label success';
|
||||
|
||||
btnStart.setAttribute('disabled', 'disabled');
|
||||
btnRestart.removeAttribute('disabled');
|
||||
btnStop.removeAttribute('disabled');
|
||||
btnOpen.removeAttribute('disabled');
|
||||
} else {
|
||||
statusEl.textContent = _('Stopped');
|
||||
statusEl.className = 'label important';
|
||||
|
||||
btnStart.removeAttribute('disabled');
|
||||
btnRestart.setAttribute('disabled', 'disabled');
|
||||
btnStop.setAttribute('disabled', 'disabled');
|
||||
btnOpen.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}).catch(function () {
|
||||
statusEl.textContent = _('Error');
|
||||
statusEl.className = 'label warning';
|
||||
});
|
||||
};
|
||||
|
||||
updateStatus();
|
||||
|
||||
poll.add(updateStatus, 3);
|
||||
|
||||
return E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', _('FusionTunX Control')),
|
||||
E('div', { 'class': 'cbi-section' }, [
|
||||
E('div', { 'class': 'cbi-value' }, [
|
||||
E('label', { 'class': 'cbi-value-title' }, _('Service Status')),
|
||||
E('div', { 'class': 'cbi-value-field' }, statusEl)
|
||||
]),
|
||||
|
||||
E('div', { 'class': 'cbi-section-descr' }, _('Control the FusionTunX backend service.')),
|
||||
|
||||
E('div', { 'class': 'cbi-page-actions' }, [
|
||||
btnStart, btnRestart, btnStop, btnOpen
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -1,34 +1,28 @@
|
||||
include $(TOPDIR)/rules.mk#将openwrt顶层目录下的rules.mk文件中的内容导入进来
|
||||
|
||||
PKG_NAME:=sendat#软件包名
|
||||
PKG_VERSION:=6.8.2#软件包版本
|
||||
PKG_RELEASE:=2
|
||||
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)#真正编译当前软件包的目录
|
||||
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk#将$(TOPDIR)/include目录下的package.mk文件中的内容导入进来
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sendat
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/ouyangzq/sendat.git
|
||||
PKG_SOURCE_DATE:=2024-01-22
|
||||
PKG_SOURCE_VERSION:=624c58f6331e5be3eac6d144ed985b4a4af94b10
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/sendat
|
||||
SECTION:=wrtnode#软件包类型
|
||||
CATEGORY:=Daocaoren#menuconfig中软件包所属的一级目录
|
||||
SUBMENU :=CPE#menuconfig中软件包所属的二级目录
|
||||
TITLE:=Sendat AT#软件包标题
|
||||
DEPENDS:=+libpthread#运行本软件依赖的其他包
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=WWAN
|
||||
TITLE:=Send AT commands to serial
|
||||
endef
|
||||
|
||||
define Package/sendat/description #软件包描述
|
||||
A sample for sendat test
|
||||
|
||||
MAKE_PATH:=src
|
||||
|
||||
define Package/sendat/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/sendat $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
define Build/Prepare #编译之前的准备动作
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
|
||||
define Package/sendat/install #软件包的安装方法,主要就是将一系列编译好的文件、启动脚本、UCI配置文件等拷贝到指定位置
|
||||
$(INSTALL_DIR) $(1)/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/sendat $(1)/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,sendat))
|
||||
|
||||
$(eval $(call BuildPackage,sendat))
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
# sendat
|
||||
AT 命令工具
|
||||
1简化使用AT命令请求方式
|
||||
使用命令说明
|
||||
sendat 2 'ATI' 2表示 /dev/ttyUSB2 'ATI' 为at命令
|
||||
@ -1,9 +0,0 @@
|
||||
all:sendat
|
||||
|
||||
OBJS = sendat.o
|
||||
|
||||
sendat:$(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) -lpthread
|
||||
|
||||
clean:
|
||||
rm -f sendat *.o
|
||||
420
sendat/src/pdu.c
420
sendat/src/pdu.c
@ -1,420 +0,0 @@
|
||||
/*
|
||||
* 2017 - 2021 Cezary Jackiewicz <cezary@eko.one.pl>
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
*/
|
||||
// Copyright 2011 The Avalon Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// SMS encoding/decoding functions, which are based on examples from:
|
||||
// http://www.dreamfabric.com/sms/
|
||||
|
||||
#include "pdu.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
enum {
|
||||
BITMASK_7BITS = 0x7F,
|
||||
BITMASK_8BITS = 0xFF,
|
||||
BITMASK_HIGH_4BITS = 0xF0,
|
||||
BITMASK_LOW_4BITS = 0x0F,
|
||||
|
||||
TYPE_OF_ADDRESS_UNKNOWN = 0x81,
|
||||
TYPE_OF_ADDRESS_INTERNATIONAL_PHONE = 0x91,
|
||||
TYPE_OF_ADDRESS_NATIONAL_SUBSCRIBER = 0xC8,
|
||||
TYPE_OF_ADDRESS_ALPHANUMERIC = 0xD0,
|
||||
|
||||
SMS_DELIVER_ONE_MESSAGE = 0x04,
|
||||
SMS_SUBMIT = 0x11,
|
||||
|
||||
SMS_MAX_7BIT_TEXT_LENGTH = 160,
|
||||
};
|
||||
|
||||
// Swap decimal digits of a number (e.g. 12 -> 21).
|
||||
static unsigned char
|
||||
SwapDecimalNibble(const unsigned char x)
|
||||
{
|
||||
return (x / 16) + ((x % 16) * 10);
|
||||
}
|
||||
|
||||
// Encode/Decode PDU: Translate ASCII 7bit characters to 8bit buffer.
|
||||
// SMS encoding example from: http://www.dreamfabric.com/sms/.
|
||||
//
|
||||
// 7-bit ASCII: "hellohello"
|
||||
// [0]:h [1]:e [2]:l [3]:l [4]:o [5]:h [6]:e [7]:l [8]:l [9]:o
|
||||
// 1101000 1100101 1101100 1101100 1101111 1101000 1100101 1101100 1101100 1101111
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// /-------------/ ///-------/// /////-///// \------------\ ||||||| \\\\\\ .
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// input buffer position
|
||||
// 10000000 22111111 33322222 44443333 55555333 66666655 77777776 98888888 --999999
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// 8bit encoded buffer
|
||||
// 11101000 00110010 10011011 11111101 01000110 10010111 11011001 11101100 00110111
|
||||
// E8 32 9B FD 46 97 D9 EC 37
|
||||
|
||||
|
||||
// Encode PDU message by merging 7 bit ASCII characters into 8 bit octets.
|
||||
int
|
||||
EncodePDUMessage(const char* sms_text, int sms_text_length, unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
// Check if output buffer is big enough.
|
||||
if ((sms_text_length * 7 + 7) / 8 > buffer_size)
|
||||
return -1;
|
||||
|
||||
int output_buffer_length = 0;
|
||||
int carry_on_bits = 1;
|
||||
int i = 0;
|
||||
|
||||
for (; i < sms_text_length - 1; ++i) {
|
||||
output_buffer[output_buffer_length++] =
|
||||
((sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1)) |
|
||||
((sms_text[i + 1] & BITMASK_7BITS) << (8 - carry_on_bits));
|
||||
carry_on_bits++;
|
||||
if (carry_on_bits == 8) {
|
||||
carry_on_bits = 1;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (i <= sms_text_length)
|
||||
output_buffer[output_buffer_length++] = (sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1);
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
// Decode PDU message by splitting 8 bit encoded buffer into 7 bit ASCII
|
||||
// characters.
|
||||
int
|
||||
DecodePDUMessage_GSM_7bit(const unsigned char* buffer, int buffer_length, char* output_sms_text, int sms_text_length)
|
||||
{
|
||||
int output_text_length = 0;
|
||||
if (buffer_length > 0)
|
||||
output_sms_text[output_text_length++] = BITMASK_7BITS & buffer[0];
|
||||
|
||||
if (sms_text_length > 1) {
|
||||
int carry_on_bits = 1;
|
||||
int i = 1;
|
||||
for (; i < buffer_length; ++i) {
|
||||
|
||||
output_sms_text[output_text_length++] = BITMASK_7BITS & ((buffer[i] << carry_on_bits) | (buffer[i - 1] >> (8 - carry_on_bits)));
|
||||
|
||||
if (output_text_length == sms_text_length) break;
|
||||
|
||||
carry_on_bits++;
|
||||
|
||||
if (carry_on_bits == 8) {
|
||||
carry_on_bits = 1;
|
||||
output_sms_text[output_text_length++] = buffer[i] & BITMASK_7BITS;
|
||||
if (output_text_length == sms_text_length) break;
|
||||
}
|
||||
|
||||
}
|
||||
if (output_text_length < sms_text_length) // Add last remainder.
|
||||
output_sms_text[output_text_length++] = buffer[i - 1] >> (8 - carry_on_bits);
|
||||
}
|
||||
|
||||
return output_text_length;
|
||||
}
|
||||
|
||||
#define GSM_7BITS_ESCAPE 0x1b
|
||||
|
||||
static const unsigned char gsm7bits_to_latin1[128] = {
|
||||
'@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
|
||||
0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0xe6, 0xdf, 0xc9,
|
||||
' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
|
||||
0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0,
|
||||
};
|
||||
|
||||
static const unsigned char gsm7bits_extend_to_latin1[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\',
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0,
|
||||
'|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static int
|
||||
G7bitToAscii(char* buffer, int buffer_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i<buffer_length; i++) {
|
||||
if (buffer[i] < 128) {
|
||||
if (buffer[i] == GSM_7BITS_ESCAPE) {
|
||||
buffer[i] = gsm7bits_extend_to_latin1[buffer[i + 1]];
|
||||
memmove(&buffer[i + 1], &buffer[i + 2], buffer_length - i - 1);
|
||||
buffer_length--;
|
||||
} else {
|
||||
buffer[i] = gsm7bits_to_latin1[buffer[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer_length;
|
||||
}
|
||||
|
||||
#define NPC '?'
|
||||
|
||||
static const int latin1_to_gsm7bits[256] = {
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, 0x0a, NPC,-0x0a, 0x0d, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,-0x3c,-0x2f,-0x3e,-0x14, 0x11,
|
||||
NPC, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,-0x28,-0x40,-0x29,-0x3d, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, 0x40, NPC, 0x01, 0x24, 0x03, NPC, 0x5f, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, 0x60,
|
||||
NPC, NPC, NPC, NPC, 0x5b, 0x0e, 0x1c, 0x09, NPC, 0x1f, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, 0x5d, NPC, NPC, NPC, NPC, 0x5c, NPC, 0x0b, NPC, NPC, NPC, 0x5e, NPC, NPC, 0x1e,
|
||||
0x7f, NPC, NPC, NPC, 0x7b, 0x0f, 0x1d, NPC, 0x04, 0x05, NPC, NPC, 0x07, NPC, NPC, NPC,
|
||||
NPC, 0x7d, 0x08, NPC, NPC, NPC, 0x7c, NPC, 0x0c, 0x06, NPC, NPC, 0x7e, NPC, NPC, NPC,
|
||||
};
|
||||
|
||||
static int
|
||||
AsciiToG7bit(const char* buffer, int buffer_length, unsigned char* output_buffer)
|
||||
{
|
||||
int i, j, val;
|
||||
|
||||
j=0;
|
||||
for (i = 0; i < buffer_length; i++) {
|
||||
val = latin1_to_gsm7bits[buffer[i] & 0xFF];
|
||||
if (val < 0) {
|
||||
output_buffer[j++] = GSM_7BITS_ESCAPE;
|
||||
output_buffer[j++] = -1*val;
|
||||
} else {
|
||||
if (((buffer[i] & 0xFF) & 0xE0) == 0xC0) { /* test for two byte utf8 char */
|
||||
val = NPC;
|
||||
i++;
|
||||
} else if (((buffer[i] & 0xFF) & 0xF0) == 0xE0) { /* test for three byte utf8 char */
|
||||
val = NPC;
|
||||
i++;
|
||||
i++;
|
||||
}
|
||||
output_buffer[j++] = val;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
// Encode a digit based phone number for SMS based format.
|
||||
static int
|
||||
EncodePhoneNumber(const char* phone_number, unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
int output_buffer_length = 0;
|
||||
const int phone_number_length = strlen(phone_number);
|
||||
|
||||
// Check if the output buffer is big enough.
|
||||
if ((phone_number_length + 1) / 2 > buffer_size)
|
||||
return -1;
|
||||
|
||||
int i = 0;
|
||||
for (; i < phone_number_length; ++i) {
|
||||
|
||||
if (phone_number[i] < '0' && phone_number[i] > '9')
|
||||
return -1;
|
||||
|
||||
if (i % 2 == 0) {
|
||||
output_buffer[output_buffer_length++] = BITMASK_HIGH_4BITS | (phone_number[i] - '0');
|
||||
} else {
|
||||
output_buffer[output_buffer_length - 1] =
|
||||
(output_buffer[output_buffer_length - 1] & BITMASK_LOW_4BITS) |
|
||||
((phone_number[i] - '0') << 4);
|
||||
}
|
||||
}
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
// Decode a digit based phone number for SMS based format.
|
||||
static int
|
||||
DecodePhoneNumber(const unsigned char* buffer, int phone_number_length, char* output_phone_number)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < phone_number_length; ++i) {
|
||||
if (i % 2 == 0)
|
||||
output_phone_number[i] = (buffer[i / 2] & BITMASK_LOW_4BITS) + '0';
|
||||
else
|
||||
output_phone_number[i] = ((buffer[i / 2] & BITMASK_HIGH_4BITS) >> 4) + '0';
|
||||
}
|
||||
output_phone_number[phone_number_length] = '\0'; // Terminate C string.
|
||||
return phone_number_length;
|
||||
}
|
||||
|
||||
// Encode a SMS message to PDU
|
||||
int
|
||||
pdu_encode(const char* service_center_number, const char* phone_number, const char* sms_text,
|
||||
unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
if (buffer_size < 2)
|
||||
return -1;
|
||||
|
||||
int output_buffer_length = 0;
|
||||
|
||||
// 1. Set SMS center number.
|
||||
int length = 0;
|
||||
if (service_center_number && strlen(service_center_number) > 0) {
|
||||
output_buffer[1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
|
||||
length = EncodePhoneNumber(service_center_number,
|
||||
output_buffer + 2, buffer_size - 2);
|
||||
if (length < 0 && length >= 254)
|
||||
return -1;
|
||||
length++; // Add type of address.
|
||||
}
|
||||
output_buffer[0] = length;
|
||||
output_buffer_length = length + 1;
|
||||
if (output_buffer_length + 4 > buffer_size)
|
||||
return -1; // Check if it has space for four more bytes.
|
||||
|
||||
// 2. Set type of message.
|
||||
output_buffer[output_buffer_length++] = SMS_SUBMIT;
|
||||
output_buffer[output_buffer_length++] = 0x00; // Message reference.
|
||||
|
||||
// 3. Set phone number.
|
||||
output_buffer[output_buffer_length] = strlen(phone_number);
|
||||
|
||||
if (strlen(phone_number) < 6) {
|
||||
output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_UNKNOWN;
|
||||
} else {
|
||||
output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
|
||||
}
|
||||
|
||||
length = EncodePhoneNumber(phone_number,
|
||||
output_buffer + output_buffer_length + 2,
|
||||
buffer_size - output_buffer_length - 2);
|
||||
output_buffer_length += length + 2;
|
||||
if (output_buffer_length + 4 > buffer_size)
|
||||
return -1; // Check if it has space for four more bytes.
|
||||
|
||||
|
||||
// 4. Protocol identifiers.
|
||||
output_buffer[output_buffer_length++] = 0x00; // TP-PID: Protocol identifier.
|
||||
output_buffer[output_buffer_length++] = 0x00; // TP-DCS: Data coding scheme.
|
||||
output_buffer[output_buffer_length++] = 0xB0; // TP-VP: Validity: 10 days
|
||||
|
||||
// 5. SMS message.
|
||||
int sms_text_length = strlen(sms_text);
|
||||
char sms_text_7bit[2*SMS_MAX_7BIT_TEXT_LENGTH];
|
||||
sms_text_length = AsciiToG7bit(sms_text, sms_text_length, sms_text_7bit);
|
||||
if (sms_text_length > SMS_MAX_7BIT_TEXT_LENGTH)
|
||||
return -1;
|
||||
output_buffer[output_buffer_length++] = sms_text_length;
|
||||
length = EncodePDUMessage(sms_text_7bit, sms_text_length,
|
||||
output_buffer + output_buffer_length,
|
||||
buffer_size - output_buffer_length);
|
||||
if (length < 0)
|
||||
return -1;
|
||||
output_buffer_length += length;
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
int pdu_decode(const unsigned char* buffer, int buffer_length,
|
||||
time_t* output_sms_time,
|
||||
char* output_sender_phone_number, int sender_phone_number_size,
|
||||
char* output_sms_text, int sms_text_size,
|
||||
int* tp_dcs,
|
||||
int* ref_number,
|
||||
int* total_parts,
|
||||
int* part_number,
|
||||
int* skip_bytes)
|
||||
{
|
||||
|
||||
if (buffer_length <= 0)
|
||||
return -1;
|
||||
|
||||
const int sms_deliver_start = 1 + buffer[0];
|
||||
if (sms_deliver_start + 1 > buffer_length)
|
||||
return -2;
|
||||
|
||||
const int user_data_header_length = (buffer[sms_deliver_start]>>4);
|
||||
|
||||
const int sender_number_length = buffer[sms_deliver_start + 1];
|
||||
if (sender_number_length + 1 > sender_phone_number_size)
|
||||
return -3; // Buffer too small to hold decoded phone number.
|
||||
|
||||
const int sender_type_of_address = buffer[sms_deliver_start + 2];
|
||||
if (sender_type_of_address == TYPE_OF_ADDRESS_ALPHANUMERIC) {
|
||||
DecodePDUMessage_GSM_7bit(buffer + sms_deliver_start + 3, (sender_number_length + 1) / 2, output_sender_phone_number, sender_number_length);
|
||||
} else {
|
||||
DecodePhoneNumber(buffer + sms_deliver_start + 3, sender_number_length, output_sender_phone_number);
|
||||
}
|
||||
|
||||
const int sms_pid_start = sms_deliver_start + 3 + (buffer[sms_deliver_start + 1] + 1) / 2;
|
||||
|
||||
// Decode timestamp.
|
||||
struct tm sms_broken_time;
|
||||
sms_broken_time.tm_year = 100 + SwapDecimalNibble(buffer[sms_pid_start + 2]);
|
||||
sms_broken_time.tm_mon = SwapDecimalNibble(buffer[sms_pid_start + 3]) - 1;
|
||||
sms_broken_time.tm_mday = SwapDecimalNibble(buffer[sms_pid_start + 4]);
|
||||
sms_broken_time.tm_hour = SwapDecimalNibble(buffer[sms_pid_start + 5]);
|
||||
sms_broken_time.tm_min = SwapDecimalNibble(buffer[sms_pid_start + 6]);
|
||||
sms_broken_time.tm_sec = SwapDecimalNibble(buffer[sms_pid_start + 7]);
|
||||
(*output_sms_time) = timegm(&sms_broken_time);
|
||||
|
||||
const int sms_start = sms_pid_start + 2 + 7;
|
||||
if (sms_start + 1 > buffer_length) return -1; // Invalid input buffer.
|
||||
|
||||
int tmp;
|
||||
if((user_data_header_length&0x04)==0x04) {
|
||||
tmp = buffer[sms_start + 1] + 1;
|
||||
*skip_bytes = tmp;
|
||||
*ref_number = 0x000000FF&buffer[sms_start + tmp - 2];
|
||||
*total_parts = 0x000000FF&buffer[sms_start + tmp - 1];
|
||||
*part_number = 0x000000FF&buffer[sms_start + tmp];
|
||||
} else {
|
||||
tmp = 0;
|
||||
*skip_bytes = tmp;
|
||||
*ref_number = tmp;
|
||||
*total_parts = tmp;
|
||||
*part_number = tmp;
|
||||
}
|
||||
|
||||
int output_sms_text_length = buffer[sms_start];
|
||||
if (sms_text_size < output_sms_text_length) return -1; // Cannot hold decoded buffer.
|
||||
|
||||
const int sms_tp_dcs_start = sms_pid_start + 1;
|
||||
*tp_dcs = buffer[sms_tp_dcs_start];
|
||||
|
||||
switch((*tp_dcs / 4) % 4)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// GSM 7 bit
|
||||
int decoded_sms_text_size = DecodePDUMessage_GSM_7bit(buffer + sms_start + 1, buffer_length - (sms_start + 1),
|
||||
output_sms_text, output_sms_text_length);
|
||||
if (decoded_sms_text_size != output_sms_text_length) return -1; // Decoder length is not as expected.
|
||||
output_sms_text_length = G7bitToAscii(output_sms_text, output_sms_text_length);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// UCS2
|
||||
memcpy(output_sms_text, buffer + sms_start + 1, output_sms_text_length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add a C string end.
|
||||
if (output_sms_text_length < sms_text_size)
|
||||
output_sms_text[output_sms_text_length] = 0;
|
||||
else
|
||||
output_sms_text[sms_text_size-1] = 0;
|
||||
|
||||
return output_sms_text_length;
|
||||
}
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 2017 - 2021 Cezary Jackiewicz <cezary@eko.one.pl>
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
*/
|
||||
// Copyright 2011 The Avalon Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
#ifndef SMS_PDU_H_
|
||||
#define SMS_PDU_H_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
enum { SMS_MAX_PDU_LENGTH = 256 };
|
||||
|
||||
/*
|
||||
* Encode an SMS message. Output the encoded message into output pdu buffer.
|
||||
* Returns the length of the SMS encoded message in the output buffer or
|
||||
* a negative number in case encoding failed (for example provided output buffer
|
||||
* does not have enough space).
|
||||
*/
|
||||
int pdu_encode(const char* service_center_number, const char* phone_number, const char* text,
|
||||
unsigned char* pdu, int pdu_size);
|
||||
|
||||
/*
|
||||
* Decode an SMS message. Output the decoded message into the sms text buffer.
|
||||
* Returns the length of the SMS dencoded message or a negative number in
|
||||
* case encoding failed (for example provided output buffer has not enough
|
||||
* space).
|
||||
*/
|
||||
int pdu_decode(const unsigned char* pdu, int pdu_len,
|
||||
time_t* sms_time,
|
||||
char* phone_number, int phone_number_size,
|
||||
char* text, int text_size,
|
||||
int* tp_dcs,
|
||||
int* ref_number,
|
||||
int* total_parts,
|
||||
int* part_number,
|
||||
int* skip_bytes);
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8);
|
||||
|
||||
int DecodePDUMessage_GSM_7bit(const unsigned char* buffer,
|
||||
int buffer_length,
|
||||
char* output_sms_text,
|
||||
int sms_text_length);
|
||||
|
||||
int EncodePDUMessage(const char* sms_text,
|
||||
int sms_text_length,
|
||||
unsigned char* output_buffer,
|
||||
int buffer_size);
|
||||
|
||||
#endif // SMS_SMS_H_
|
||||
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
* SMS PDU Decoder
|
||||
*/
|
||||
#include "pdu.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8);
|
||||
|
||||
int sms_decode()
|
||||
{
|
||||
char buffer[2*SMS_MAX_PDU_LENGTH+4];
|
||||
char *p = buffer;
|
||||
char t[2];
|
||||
int d;
|
||||
do
|
||||
{
|
||||
t[0] = getchar();
|
||||
if(t[0]=='\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
t[1] = getchar();
|
||||
if(t[1]=='\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
*p = strtol(t,NULL,16);
|
||||
p++;
|
||||
}while(1);
|
||||
|
||||
time_t sms_time;
|
||||
char sms_phone[40];
|
||||
char sms_text[161];
|
||||
int tp_dcs_type;
|
||||
int ref_number;
|
||||
int total_parts;
|
||||
int part_number;
|
||||
int skip_bytes;
|
||||
|
||||
int sms_text_length = pdu_decode((const unsigned char*)buffer,
|
||||
sizeof(buffer),
|
||||
&sms_time,
|
||||
sms_phone, sizeof(sms_phone),
|
||||
sms_text, sizeof(sms_text),
|
||||
&tp_dcs_type,
|
||||
&ref_number,
|
||||
&total_parts,
|
||||
&part_number,
|
||||
&skip_bytes);
|
||||
|
||||
printf("From:%s\n",sms_phone);
|
||||
printf("Textlen=%d\n",sms_text_length);
|
||||
char time_data_str[64];
|
||||
strftime(time_data_str,64,"%D %T", localtime(&sms_time));
|
||||
printf("Date/Time:%s\n",time_data_str);
|
||||
|
||||
if (total_parts > 0) {
|
||||
printf("Reference number: %d\n", ref_number);
|
||||
printf("SMS segment %d of %d\n", part_number, total_parts);
|
||||
}
|
||||
|
||||
switch((tp_dcs_type / 4) % 4)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// GSM7 bit
|
||||
int i = skip_bytes;
|
||||
if(skip_bytes > 0) i = (skip_bytes*8+6)/7;
|
||||
for(;i<sms_text_length;i++)
|
||||
{
|
||||
printf("%c", sms_text[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// UCS2
|
||||
for(int i = skip_bytes;i<sms_text_length;i+=2)
|
||||
{
|
||||
int ucs2_char = 0x000000FF&sms_text[i+1];
|
||||
ucs2_char|=(0x0000FF00&(sms_text[i]<<8));
|
||||
unsigned char utf8_char[5];
|
||||
int len = ucs2_to_utf8(ucs2_char,utf8_char);
|
||||
int j;
|
||||
for(j=0;j<len;j++)
|
||||
{
|
||||
printf("%c",utf8_char[j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,450 +0,0 @@
|
||||
/*
|
||||
** Soft:Daocaoren Name:马上有房 qq:168620188
|
||||
*/
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/select.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
// #include "pdu.h"
|
||||
|
||||
|
||||
#define MAX_PORTS 4
|
||||
/*this array hold information about each port we have opened */
|
||||
struct PortInfo {
|
||||
char name[16];
|
||||
int port_fd;
|
||||
};
|
||||
int serial_init(int port, int spd, int databits, int parity, \
|
||||
int stopbits, int RTSCTS, int need_line_input);
|
||||
int serial_write(int fd, void *src, int len);
|
||||
int serial_read(int fd, char *buf, int len);
|
||||
int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout);
|
||||
//串口常用初始化接口
|
||||
#define serial_com_init(port, spd, databits, parity, stopbits)\
|
||||
serial_init(port, spd, databits, parity, stopbits, 0, 0)
|
||||
//串口默认初始化接口
|
||||
#define serial_def_init(port, spd) serial_init(port, spd, 8, 'n', 1, 0, 1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** File: uart.c
|
||||
**
|
||||
** Description:
|
||||
** Provides an RS-232 interface that is very similar to the CVI provided
|
||||
** interface library
|
||||
*/
|
||||
/*this array hold information about each port we have opened */
|
||||
struct PortInfo ports[13] =
|
||||
{
|
||||
{"/dev/ttyUSB0", 0},
|
||||
{"/dev/ttyUSB1", 0},
|
||||
{"/dev/ttyUSB2", 0},
|
||||
{"/dev/ttyUSB3", 0},
|
||||
{"/dev/ttyUSB4", 0},
|
||||
{"/dev/ttyUSB5", 0},
|
||||
{"/dev/ttyUSB6", 0},
|
||||
{"/dev/ttyUSB7", 0},
|
||||
{"/dev/ttyUSB8", 0},
|
||||
{"/dev/ttyUSB9", 0},
|
||||
{"/dev/ttyUSB10", 0},
|
||||
{"/dev/ttyUSB11", 0},
|
||||
{"/dev/ttyUSB12", 0},
|
||||
};
|
||||
FILE* pf;
|
||||
FILE* pfi;
|
||||
int spd_arr[] = {B2000000, B1500000, B576000, B500000, B460800, B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400};
|
||||
int name_arr[] = { 2000000, 1500000, 576000, 500000, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400 };
|
||||
/**
|
||||
*@brief 设置串口通信速率
|
||||
*@param fd 类型 int 打开串口的文件句柄
|
||||
*@param speed 类型 int 串口速度
|
||||
*@return void
|
||||
*/
|
||||
int set_speed(int fd, int speed)
|
||||
{
|
||||
int i;
|
||||
int status;
|
||||
struct termios Opt;
|
||||
tcgetattr(fd, &Opt);
|
||||
for ( i= 0; i < sizeof(spd_arr) / sizeof(int); i++) {
|
||||
if(speed == name_arr[i]) {
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
cfsetispeed(&Opt, spd_arr[i]);
|
||||
cfsetospeed(&Opt, spd_arr[i]);
|
||||
status = tcsetattr(fd, TCSANOW, &Opt);
|
||||
if (status != 0) {
|
||||
printf("tcsetattr failed");
|
||||
return 1;
|
||||
}
|
||||
tcflush(fd,TCIOFLUSH);
|
||||
}
|
||||
}
|
||||
// printf("set_speed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief 设置串口数据位,停止位和效验位
|
||||
*@param fd 类型 int 打开的串口文件句柄
|
||||
*@param databits 类型 int 数据位 取值为 7 或者8
|
||||
*@param stopbits 类型 int 停止位 取值为 1 或者2
|
||||
*@param parity 类型 int 效验类型 取值为N,E,O,,S
|
||||
*/
|
||||
int set_Parity(int fd, int databits, int parity, int stopbits, int RTSCTS)
|
||||
{
|
||||
struct termios options;
|
||||
if ( tcgetattr( fd,&options) != 0) {
|
||||
perror("SetupSerial 1");
|
||||
return -1;
|
||||
}
|
||||
options.c_cflag &= ~CSIZE;
|
||||
switch (databits) /*设置数据位数*/
|
||||
{
|
||||
case 7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
case 8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unsupported data size\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
options.c_iflag |= INPCK;
|
||||
cfmakeraw(&options);
|
||||
//options.c_lflag |= (ICANON | ECHO | ECHOE);
|
||||
//options.c_lflag &= ~(ICANON | ECHO | ECHOE);
|
||||
//options.c_iflag &= ~(IXON | IXOFF);
|
||||
switch (parity)
|
||||
{
|
||||
case 'n':
|
||||
case 'N':
|
||||
options.c_cflag &= ~PARENB; /* Clear parity enable */
|
||||
options.c_iflag &= ~INPCK; /* Enable parity checking */
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
options.c_cflag |= PARENB; /* Enable parity */
|
||||
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
|
||||
break;
|
||||
case 'S':
|
||||
case 's': /*as no parity*/
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unsupported parity\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 设置停止位*/
|
||||
switch (stopbits)
|
||||
{
|
||||
case 1:
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
break;
|
||||
case 2:
|
||||
options.c_cflag |= CSTOPB;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unsupported stop bits\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set rts/cts */
|
||||
if (RTSCTS)
|
||||
{
|
||||
printf("Set rts/cts");
|
||||
options.c_cflag |= CRTSCTS;
|
||||
}
|
||||
|
||||
tcflush(fd,TCIFLUSH);
|
||||
options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
|
||||
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
|
||||
if (tcsetattr(fd,TCSANOW,&options) != 0)
|
||||
{
|
||||
printf("SetupSerial failed");
|
||||
return -1;
|
||||
}
|
||||
// printf("set_Parity\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//接收消息结尾加换行符
|
||||
int serial_set_line_input(int fd)
|
||||
{
|
||||
struct termios options;
|
||||
if ( tcgetattr( fd,&options) != 0) {
|
||||
perror("SetupSerial 1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
options.c_lflag |= ICANON;
|
||||
|
||||
tcflush(fd,TCIFLUSH);
|
||||
options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
|
||||
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
|
||||
if (tcsetattr(fd,TCSANOW,&options) != 0)
|
||||
{
|
||||
perror("SetupSerial 3");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief
|
||||
*@param port 串口端口号
|
||||
*@param spd 串口速度
|
||||
*@param databits,parity,stopbits,RTSCTS,分别为数据位,校验位,停止位,rtscts位
|
||||
*@param need_line_input接收数据结尾是否加换行符?
|
||||
*/
|
||||
int serial_init(int port, int spd, int databits, int parity, int stopbits, int RTSCTS, int need_line_input)
|
||||
{
|
||||
int fd;
|
||||
if(port < 13)
|
||||
{
|
||||
// printf("open port:%d\n", port);
|
||||
}
|
||||
else {
|
||||
printf("error: port:%d > MAX_PORTS\n", port);
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
fd = open(ports[port].name, O_RDWR|O_NOCTTY);//O_NONBLOCK 非阻塞, O_WRONLY 只读写, O_RDONLY 只读, O_RDWR 读写,O_NOCTTY 阻塞
|
||||
|
||||
if (-1 == fd) {
|
||||
printf("init %s failed\n", ports[port].name);
|
||||
return -1;
|
||||
}
|
||||
pf = fdopen(port, "w");
|
||||
pfi = fdopen(port, "r");
|
||||
if (!pf || ! pfi)
|
||||
fprintf(stderr,"open port failed\n");
|
||||
|
||||
|
||||
|
||||
set_speed(fd, spd);
|
||||
|
||||
set_Parity(fd, databits, parity, stopbits, RTSCTS);
|
||||
|
||||
if (need_line_input) {
|
||||
serial_set_line_input(fd);
|
||||
}
|
||||
|
||||
ports[port].port_fd = fd;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief
|
||||
*@param fd 串口端口号文件描述符
|
||||
*@param src 需要通过串口发送的数据
|
||||
*@param len 需要发送的数据长度
|
||||
*@param 成功返回0, 否则返回-1
|
||||
*/
|
||||
int serial_write(int fd, void *src, int len)
|
||||
{
|
||||
int ret = write(fd, src, len);
|
||||
if (len != ret) {
|
||||
perror("oh, write serial failed!");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*@brief
|
||||
*@param fd 串口端口号文件描述符
|
||||
*@param src 串口接收数据的指针
|
||||
*@param len 需要接收的数据长度
|
||||
*@param 成功返回0, 否则返回-1
|
||||
*/
|
||||
int serial_read(int fd, char *buf, int len)
|
||||
{
|
||||
int ret = read(fd, buf, len-1);
|
||||
if (-1 == ret) {
|
||||
perror("oh, read serial failed!");
|
||||
return -1;
|
||||
}
|
||||
buf[ret] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout)
|
||||
{
|
||||
int retval;
|
||||
fd_set rset;
|
||||
struct timeval time_out;
|
||||
if(!rbuf || rbuf_len <= 0)
|
||||
{
|
||||
// printf("serial_recv Invalid parameter.\n");
|
||||
return -1;
|
||||
}
|
||||
if(timeout) //指定延时等待
|
||||
{
|
||||
time_out.tv_sec = (time_t)(timeout / 1000);
|
||||
time_out.tv_usec = 0;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(fd,&rset);
|
||||
|
||||
retval = select(fd,&rset,NULL,NULL,&time_out);
|
||||
if(retval < 0)
|
||||
{
|
||||
// printf("%s,Select failed:%s\n",strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
else if(0 == retval)
|
||||
{
|
||||
// printf("Time Out.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
// usleep(1000);
|
||||
retval = read(fd, rbuf, rbuf_len);
|
||||
if( retval <= 0)
|
||||
{
|
||||
// printf("Read failed:%s\n",strerror(errno));
|
||||
return -3;
|
||||
}
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void timeout()
|
||||
{
|
||||
fprintf(stderr,"No response from modem.\n");
|
||||
exit(2);
|
||||
}
|
||||
/*字符包含判断*/
|
||||
static int starts_with(const char* prefix, const char* str)
|
||||
{
|
||||
while(*prefix)
|
||||
{
|
||||
if (*prefix++ != *str++)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*判断是否存在*/
|
||||
int FileExist(const char* filename)
|
||||
{
|
||||
if (filename && access(filename, F_OK) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*字符转小写*/
|
||||
char* str_tolower(const char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *lower = calloc(len+1, sizeof(char));
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
lower[i] = tolower((unsigned char)str[i]);
|
||||
}
|
||||
/*free(upper);*/
|
||||
return lower;
|
||||
}
|
||||
/*字符转大写*/
|
||||
char* str_toupper(const char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *upper = calloc(len+1, sizeof(char));
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
upper[i] = toupper((unsigned char)str[i]);
|
||||
}
|
||||
/*free(upper);*/
|
||||
return upper;
|
||||
}
|
||||
/*char*转char[]*/
|
||||
char strx_tostrarr(const char* str)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc<3)
|
||||
{
|
||||
printf("ERROR demo: sendat 2 'ATI'\n");
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
int debug = 1;
|
||||
int port= 0;
|
||||
sscanf(argv[1], "%d", &port);
|
||||
if(FileExist(ports[port].name)==0)
|
||||
{
|
||||
printf("AT ERROR absent.\n");
|
||||
return 0;
|
||||
}
|
||||
char *message= argv[2];
|
||||
char *nty= "\r\n";
|
||||
char buff[1024];
|
||||
signal(SIGALRM,timeout);
|
||||
alarm(2);
|
||||
/*信号超时3秒自动退出*/
|
||||
int fd = serial_def_init(port, 1500000);
|
||||
if(fd < 0) return 0;
|
||||
char *send= strcat(message,nty);
|
||||
serial_write(fd,send, strlen(send));
|
||||
while(1) {
|
||||
int read = serial_read(fd, buff, sizeof(buff));
|
||||
if(starts_with("OK", buff)) {
|
||||
if (debug == 1)
|
||||
printf("%s", buff);
|
||||
close(fd);//关闭串口
|
||||
exit(0);
|
||||
}
|
||||
if(starts_with("ERROR", buff)) {
|
||||
if (debug == 1)
|
||||
printf("%s", buff);
|
||||
close(fd);//关闭串口
|
||||
exit(1);
|
||||
}
|
||||
if(starts_with("COMMAND NOT SUPPORT", buff)) {
|
||||
if (debug == 1)
|
||||
printf("%s", buff);
|
||||
close(fd);//关闭串口
|
||||
exit(1);
|
||||
}
|
||||
if(starts_with("+CME ERROR", buff)) {
|
||||
if (debug == 1)
|
||||
printf("%s", buff);
|
||||
close(fd);//关闭串口
|
||||
exit(1);
|
||||
}
|
||||
printf("%s", buff);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
* from http://www.lemoda.net/c/ucs2-to-utf8/ucs2-to-utf8.c
|
||||
*/
|
||||
/* Input: a Unicode code point, "ucs2".
|
||||
|
||||
Output: UTF-8 characters in buffer "utf8".
|
||||
|
||||
Return value: the number of bytes written into "utf8", or -1 if
|
||||
there was an error.
|
||||
|
||||
This adds a zero byte to the end of the string. It assumes that the
|
||||
buffer "utf8" has at least four bytes of space to write to. */
|
||||
|
||||
#define UNICODE_SURROGATE_PAIR -2
|
||||
#define UNICODE_BAD_INPUT -1
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8)
|
||||
{
|
||||
if (ucs2 < 0x80) {
|
||||
utf8[0] = ucs2;
|
||||
utf8[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
if (ucs2 >= 0x80 && ucs2 < 0x800) {
|
||||
utf8[0] = (ucs2 >> 6) | 0xC0;
|
||||
utf8[1] = (ucs2 & 0x3F) | 0x80;
|
||||
utf8[2] = '\0';
|
||||
return 2;
|
||||
}
|
||||
if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
|
||||
if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) {
|
||||
/* Ill-formed. */
|
||||
return UNICODE_SURROGATE_PAIR;
|
||||
}
|
||||
utf8[0] = ((ucs2 >> 12) ) | 0xE0;
|
||||
utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
|
||||
utf8[2] = ((ucs2 ) & 0x3F) | 0x80;
|
||||
utf8[3] = '\0';
|
||||
return 3;
|
||||
}
|
||||
if (ucs2 >= 0x10000 && ucs2 < 0x10FFFF) {
|
||||
/* http://tidy.sourceforge.net/cgi-bin/lxr/source/src/utf8.c#L380 */
|
||||
utf8[0] = 0xF0 | (ucs2 >> 18);
|
||||
utf8[1] = 0x80 | ((ucs2 >> 12) & 0x3F);
|
||||
utf8[2] = 0x80 | ((ucs2 >> 6) & 0x3F);
|
||||
utf8[3] = 0x80 | ((ucs2 & 0x3F));
|
||||
utf8[4] = '\0';
|
||||
return 4;
|
||||
}
|
||||
return UNICODE_BAD_INPUT;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user