1、增加版本管理
2、只有固定解大于100个时,才允许间隔推送
This commit is contained in:
parent
705b004d62
commit
66f283a8a4
@ -41,4 +41,10 @@ public interface BeidouClient {
|
|||||||
@RequestParam(name = "tenantId") Integer tenantId,
|
@RequestParam(name = "tenantId") Integer tenantId,
|
||||||
@RequestParam(name = "uploadTime") LocalDateTime uploadTime);
|
@RequestParam(name = "uploadTime") LocalDateTime uploadTime);
|
||||||
|
|
||||||
|
@PostMapping("/upgrade_progress")
|
||||||
|
String onUpgradeProgress(@RequestParam(name = "deviceId") String deviceId,
|
||||||
|
@RequestParam(name = "msg") String msg);
|
||||||
|
|
||||||
|
@PostMapping("/upgrade_complete")
|
||||||
|
String onUpgradeComplete();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.imdroid.secapi.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UpgradeState {
|
||||||
|
static final public byte STATE_DISCONNECTED = 0;
|
||||||
|
static final public byte STATE_INFO_ACQUIRING = 1;
|
||||||
|
static final public byte STATE_UPGRADING = 2;
|
||||||
|
static final public byte STATE_UPGRADED = 3;
|
||||||
|
String deviceId;
|
||||||
|
byte progress=0;
|
||||||
|
byte state=STATE_DISCONNECTED; //0:未连接;1:获取信息;2:升级中;3:升级完成
|
||||||
|
byte code=0;
|
||||||
|
}
|
||||||
@ -66,7 +66,7 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
|||||||
DeviceChannel deviceChannel = null;
|
DeviceChannel deviceChannel = null;
|
||||||
for (Device device : deviceList) {
|
for (Device device : deviceList) {
|
||||||
if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
|
if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
|
||||||
if (device.getFixedNum()>0 && device.getGnssSampleRate()>1
|
if (device.getFixedNum()>100 && device.getGnssSampleRate()>1
|
||||||
&& (deviceBs.getD3xxCount()%device.getGnssSampleRate()) != 0) {
|
&& (deviceBs.getD3xxCount()%device.getGnssSampleRate()) != 0) {
|
||||||
//if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
|
//if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -148,19 +148,27 @@ public class VersionController extends BasicController{
|
|||||||
@PostMapping("/sys/ver_mgr/upgrade")
|
@PostMapping("/sys/ver_mgr/upgrade")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public HttpResult upgradeApp(@RequestParam String firmware, @RequestParam String id_list) throws Exception {
|
public HttpResult upgradeApp(@RequestParam String firmware, @RequestParam String id_list) throws Exception {
|
||||||
|
HttpResp rsp;
|
||||||
if(firmware!=null && !firmware.equals("undefined")) {
|
if(firmware!=null && !firmware.equals("undefined")) {
|
||||||
//请求版本服务升级
|
//请求版本服务升级
|
||||||
try {
|
try {
|
||||||
HttpResp<HashMap<String, Object>> rsp = versionClient.upgrade(id_list, firmware);
|
rsp = versionClient.upgrade(id_list, firmware);
|
||||||
System.out.println(id_list);
|
System.out.println(id_list);
|
||||||
}
|
}
|
||||||
catch (Exception e){
|
catch (Exception e){
|
||||||
return HttpResult.fail("版本服务未启动");
|
return HttpResult.fail("版本服务未启动");
|
||||||
}
|
}
|
||||||
|
if(rsp.getCode() == HttpResp.HTTP_RSP_OK){
|
||||||
|
//设置设备的使用状态为升级,下发连接版本服务器指令
|
||||||
|
|
||||||
|
return HttpResult.success("开始升级");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return HttpResult.fail(rsp.getResponseMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResult.success("OK");
|
return HttpResult.fail("非法固件");
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFirmwareList(int page, int limit, List firmwareInfo){
|
int getFirmwareList(int page, int limit, List firmwareInfo){
|
||||||
@ -196,4 +204,11 @@ public class VersionController extends BasicController{
|
|||||||
return files.length;
|
return files.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void startUpgrade(String id_list){
|
||||||
|
String[] deviceList = id_list.split(",");
|
||||||
|
for(String deviceId:deviceList){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,290 @@
|
|||||||
|
package com.imdroid.vermgr.service;
|
||||||
|
|
||||||
|
import com.imdroid.secapi.client.BeidouClient;
|
||||||
|
import com.imdroid.secapi.client.HttpResp;
|
||||||
|
import com.imdroid.vermgr.entity.DeviceApp;
|
||||||
|
import com.imdroid.vermgr.utils.CRC16;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.util.AttributeKey;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* 批量升级终端版本
|
||||||
|
* 单例,要求线程安全
|
||||||
|
* 状态机:Idle---收到UpgradeDeviceList--->Upgrading
|
||||||
|
* ^ |
|
||||||
|
* | |
|
||||||
|
* +------Timerout or Complete <-----+
|
||||||
|
*
|
||||||
|
* 流程:
|
||||||
|
* 1)收到待升级的设备列表UpgradeDeviceList。如果当前处于升级完毕状态,则更新待升级列表。回应答:开始升级/升级未结束
|
||||||
|
* 2)TCP通道激活 ---> 获取版本信息 ---> 关联TCP通道和待升级的设备
|
||||||
|
* 3)启动升级会话 ---> 实时更新会话
|
||||||
|
* 数据结构:deviceId,cur_ver,upgrade_firmware,TCP_channel,upgrade_session
|
||||||
|
* ****************************************************/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
public class UpgradeManager {
|
||||||
|
// 版本管理协议
|
||||||
|
public static final byte GET_APP_INFO = (byte) 0xA0;
|
||||||
|
public static final byte APP_INFO_IND = (byte) 0xA1;
|
||||||
|
public static final byte UPGRADE_IND = (byte) 0xA2;
|
||||||
|
public static final byte NOT_UPGRADE_IND = (byte) 0xA3;
|
||||||
|
public static final byte UPGRADE_ACK = (byte) 0xA4;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
static public UpgradeManager INSTANCE;
|
||||||
|
@Autowired
|
||||||
|
BeidouClient beidouClient;
|
||||||
|
|
||||||
|
Map<Long, DeviceApp> upgradeDeviceList = new ConcurrentHashMap<>();
|
||||||
|
Map<Long, UpgradeSession> upgradeSessionMap = new ConcurrentHashMap<>();
|
||||||
|
boolean isIdleState = true;
|
||||||
|
TimerTask operationTimerTask = null;
|
||||||
|
TimerTask txProgressTimerTask = null;
|
||||||
|
Timer timer; //30s定时器
|
||||||
|
|
||||||
|
@PostMapping("/upgrade_cmd")
|
||||||
|
HttpResp upgrade(@RequestParam(name = "deviceList") String deviceList, @RequestParam(name = "verFile") String verFile){
|
||||||
|
HttpResp resp = new HttpResp();
|
||||||
|
if(onRxUpgradeDeviceList(deviceList.split(","),verFile)){
|
||||||
|
resp.setCode(HttpResp.HTTP_RSP_OK);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
resp.setCode(HttpResp.HTTP_RSP_FAILED);
|
||||||
|
resp.setResponseMessage("正在升级中");
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onRxUpgradeDeviceList(String[] deviceList, String firmware){
|
||||||
|
if(isIdleState){
|
||||||
|
isIdleState = false;
|
||||||
|
//清空状态信息和升级会话
|
||||||
|
upgradeDeviceList.clear();
|
||||||
|
upgradeSessionMap.clear();
|
||||||
|
//创建新的状态信息
|
||||||
|
for(String deviceId:deviceList){
|
||||||
|
Long deviceSn = Long.valueOf(deviceId);
|
||||||
|
if(deviceSn!=null) {
|
||||||
|
DeviceApp deviceApp = new DeviceApp();
|
||||||
|
deviceApp.setDevice_sn(deviceSn);
|
||||||
|
deviceApp.setFirmware(firmware);
|
||||||
|
upgradeDeviceList.put(deviceSn, deviceApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//启动20s定时器,如果这期间没有收到任何数据,则超时失败
|
||||||
|
startTimer();
|
||||||
|
startTxProgressTimerTask();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onChannelActive(Channel channel){
|
||||||
|
// get app info
|
||||||
|
Long deviceId = (Long) channel.attr(AttributeKey.valueOf("deviceId")).get();
|
||||||
|
if(deviceId == null){
|
||||||
|
getVerInfo(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void onChannelInactive(Channel channel){
|
||||||
|
// 更新状态为”未连接“
|
||||||
|
long sn = (long) channel.attr(AttributeKey.valueOf("sn")).get();
|
||||||
|
if(sn > 0){
|
||||||
|
DeviceApp deviceApp = upgradeDeviceList.get(sn);
|
||||||
|
if (deviceApp != null) {
|
||||||
|
deviceApp.setUpgrade_state(DeviceApp.STATE_DISCONNECTED);
|
||||||
|
}
|
||||||
|
upgradeSessionMap.remove(sn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void onRxData(Channel channel, byte[] rx_data){
|
||||||
|
if(isIdleState){
|
||||||
|
// 临时,空闲状态下,如果连续3次收到C,则认为有终端主动请求升级
|
||||||
|
if(rx_data[0]==UpgradeSession.CC && rx_data.length<=4){
|
||||||
|
//onUpgradeRequest(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (rx_data[0] == APP_INFO_IND && rx_data.length > 2) {
|
||||||
|
onVerInfoReceived(channel, rx_data);
|
||||||
|
restartTimer();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Long sn = (Long) channel.attr(AttributeKey.valueOf("deviceId")).get();
|
||||||
|
if(sn==null) return;
|
||||||
|
UpgradeSession session = upgradeSessionMap.get(sn);
|
||||||
|
if (session == null) return;
|
||||||
|
|
||||||
|
boolean session_done = false;
|
||||||
|
|
||||||
|
if (rx_data[0] == UPGRADE_ACK) {
|
||||||
|
log.info("upgrade ack");
|
||||||
|
//outputHex(rx_data);
|
||||||
|
if (rx_data[5] != 0) {
|
||||||
|
//终端拒绝升级,原因是产品序列号不对
|
||||||
|
session.reject();
|
||||||
|
session_done = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
session_done = session.procYmodem(channel, rx_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_done) {
|
||||||
|
if (isAllUpgraded()) {
|
||||||
|
//全部发完,等待新版本启动回应答
|
||||||
|
stopTimer();
|
||||||
|
onUpgradeComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUpgradeComplete(){
|
||||||
|
isIdleState = true;
|
||||||
|
stopTxProgressTimerTask();
|
||||||
|
refreshTxProgress();
|
||||||
|
beidouClient.onUpgradeComplete();
|
||||||
|
}
|
||||||
|
/***************************************************
|
||||||
|
* 定时器处理
|
||||||
|
****************************************************/
|
||||||
|
void startTimer(){
|
||||||
|
if(operationTimerTask == null) {
|
||||||
|
operationTimerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
onTimerout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
timer.schedule(operationTimerTask,15000);
|
||||||
|
}
|
||||||
|
void restartTimer(){
|
||||||
|
stopTimer();
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
void stopTimer(){
|
||||||
|
if(operationTimerTask != null){
|
||||||
|
operationTimerTask.cancel();
|
||||||
|
operationTimerTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTimerout(){
|
||||||
|
// 超时处理
|
||||||
|
for(UpgradeSession session:upgradeSessionMap.values()){
|
||||||
|
if(session.getState() == DeviceApp.STATE_UPGRADING) {
|
||||||
|
session.onTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
onUpgradeComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
void startTxProgressTimerTask(){
|
||||||
|
if(txProgressTimerTask==null){
|
||||||
|
txProgressTimerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
refreshTxProgress();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
timer.schedule(txProgressTimerTask,1000,1000);
|
||||||
|
}
|
||||||
|
void stopTxProgressTimerTask(){
|
||||||
|
if(txProgressTimerTask != null){
|
||||||
|
txProgressTimerTask.cancel();
|
||||||
|
txProgressTimerTask = null;
|
||||||
|
log.info("stopTxProgressTimerTask");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/***************************************************
|
||||||
|
* 获取终端信息
|
||||||
|
****************************************************/
|
||||||
|
public void getVerInfo(Channel channel){
|
||||||
|
// 向所有连接终端发读取版本请求
|
||||||
|
byte get_app_info[] = {GET_APP_INFO,0};
|
||||||
|
byte tailer_buff[] = {0,0};
|
||||||
|
int crc = CRC16.calculate(get_app_info);
|
||||||
|
tailer_buff[0] = (byte) (crc>>8);
|
||||||
|
tailer_buff[1] = (byte) crc;
|
||||||
|
channel.write(get_app_info);
|
||||||
|
channel.writeAndFlush(tailer_buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onVerInfoReceived(Channel channel, byte[] rx_data){
|
||||||
|
log.info(channel.remoteAddress()+": received app info");
|
||||||
|
// 记录获取到的版本信息
|
||||||
|
if(rx_data.length<9) return;
|
||||||
|
int crc = CRC16.calculate(rx_data, 7);
|
||||||
|
int crc0 = (((short)rx_data[7]&0xFF)<<8) | ((short)rx_data[8]&0xFF);
|
||||||
|
if(crc != crc0) {
|
||||||
|
log.info(channel.remoteAddress()+": crc error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i=1;
|
||||||
|
long sn = 0;
|
||||||
|
for(i=1;i<=4;i++){
|
||||||
|
sn = (sn<<8) | ((short)rx_data[i]&0xFF);
|
||||||
|
}
|
||||||
|
String cur_ver = ((short)rx_data[i++]&0xFF) + "." + ((short)rx_data[i++]&0xFF);
|
||||||
|
|
||||||
|
// 更新APP记录并检查此终端是否需要升级
|
||||||
|
DeviceApp deviceApp = upgradeDeviceList.get(sn);
|
||||||
|
|
||||||
|
if (deviceApp == null) return;
|
||||||
|
|
||||||
|
deviceApp.setVersion(cur_ver);
|
||||||
|
//记录这个channel是有应答的
|
||||||
|
channel.attr(AttributeKey.valueOf("deviceId")).set(sn);
|
||||||
|
// 如果原来是未连接状态,则改为连接;如果是其他状态则保持不变
|
||||||
|
if(deviceApp.getUpgrade_state() == DeviceApp.STATE_DISCONNECTED) {
|
||||||
|
deviceApp.setUpgrade_state(DeviceApp.STATE_CONNECTED);
|
||||||
|
}
|
||||||
|
//启动升级
|
||||||
|
UpgradeSession session = new UpgradeSession(deviceApp);
|
||||||
|
upgradeSessionMap.put(sn, session);
|
||||||
|
session.start(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************
|
||||||
|
* 升级
|
||||||
|
****************************************************/
|
||||||
|
synchronized public boolean isAllUpgraded(){
|
||||||
|
for(DeviceApp deviceApp:upgradeDeviceList.values()){
|
||||||
|
if(deviceApp.getUpgrade_state() != DeviceApp.STATE_TX_COMPLETED &&
|
||||||
|
deviceApp.getUpgrade_state() != DeviceApp.STATE_TX_FAILED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshTxProgress(){
|
||||||
|
for(UpgradeSession session:upgradeSessionMap.values()){
|
||||||
|
if(session.getState() == DeviceApp.STATE_UPGRADING) {
|
||||||
|
beidouClient.onUpgradeProgress(Long.toString(session.getSN()), session.getTxPercentage() + "%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(DeviceApp deviceApp:upgradeDeviceList.values()){
|
||||||
|
if(deviceApp.getUpgrade_state()!=DeviceApp.STATE_UPGRADING){
|
||||||
|
beidouClient.onUpgradeProgress(Long.toString(deviceApp.getDevice_sn()),deviceApp.getStrState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,376 +0,0 @@
|
|||||||
package com.imdroid.vermgr.service;
|
|
||||||
|
|
||||||
import com.imdroid.vermgr.entity.DeviceApp;
|
|
||||||
import com.imdroid.vermgr.utils.CRC16;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.util.AttributeKey;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/******************************************************
|
|
||||||
* 批量升级终端版本
|
|
||||||
* 单例,要求线程安全
|
|
||||||
* 流程:
|
|
||||||
* 1)收到待升级的设备列表UpgradeDeviceList。如果当前处于升级完毕状态,则更新待升级列表。回应答
|
|
||||||
* 2)TCP通道激活 ---> 获取版本信息 ---> 关联TCP通道和待升级的设备
|
|
||||||
* 3)启动升级会话 ---> 实时更新会话
|
|
||||||
* 数据结构:deviceId,cur_ver,upgrade_firmware,TCP_channel,upgrade_session
|
|
||||||
* ****************************************************/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class VerManager {
|
|
||||||
public static final byte GET_APP_INFO = (byte) 0xA0;
|
|
||||||
public static final byte APP_INFO_IND = (byte) 0xA1;
|
|
||||||
public static final byte UPGRADE_IND = (byte) 0xA2;
|
|
||||||
public static final byte NOT_UPGRADE_IND = (byte) 0xA3;
|
|
||||||
public static final byte UPGRADE_ACK = (byte) 0xA4;
|
|
||||||
|
|
||||||
public static final int NOT_APP_INFO = 0;
|
|
||||||
public static final int UPGRADING = 1;
|
|
||||||
public static final int UPGRADE_DONE= 2;
|
|
||||||
|
|
||||||
public static final int STATE_IDLE = 0;
|
|
||||||
public static final int STATE_VER_GETTING = 1;
|
|
||||||
public static final int STATE_UPGRADING = 2;
|
|
||||||
|
|
||||||
int mgr_state;
|
|
||||||
int ack_expected;
|
|
||||||
int ack_num;
|
|
||||||
|
|
||||||
// thread safety set and map
|
|
||||||
Map<Long, DeviceApp> upgradeDeviceList;
|
|
||||||
Map<Channel, UpgradeSession> sessionChannelMap;
|
|
||||||
|
|
||||||
@Data //加这个注解才能用JSON转换
|
|
||||||
class WebSocketMsg {
|
|
||||||
byte state = STATE_IDLE;
|
|
||||||
byte state_changed = 0;
|
|
||||||
long sn = 0;
|
|
||||||
String msg;
|
|
||||||
}
|
|
||||||
TimerTask operationTimerTask = null;
|
|
||||||
TimerTask txProgressTimerTask = null;
|
|
||||||
|
|
||||||
Timer timer; //获取app info操作、升级操作的定时器
|
|
||||||
|
|
||||||
public static final VerManager INSTANCE = new VerManager();
|
|
||||||
|
|
||||||
private VerManager(){
|
|
||||||
mgr_state = STATE_IDLE;
|
|
||||||
upgradeDeviceList = new ConcurrentHashMap<Long, DeviceApp>();
|
|
||||||
sessionChannelMap = new ConcurrentHashMap<Channel, UpgradeSession>();
|
|
||||||
timer = new Timer();
|
|
||||||
operationTimerTask = null;
|
|
||||||
txProgressTimerTask = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized public int getState(){
|
|
||||||
return mgr_state;
|
|
||||||
}
|
|
||||||
synchronized public boolean addAckNum(){
|
|
||||||
if(ack_num<ack_expected) ack_num++;
|
|
||||||
return (ack_num==ack_expected);
|
|
||||||
}
|
|
||||||
synchronized public boolean isAllUpgraded(){
|
|
||||||
for(UpgradeSession session:sessionChannelMap.values()){
|
|
||||||
if(session.getState() == DeviceApp.STATE_UPGRADING) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void startOperationTimerTask(int delay){
|
|
||||||
if(operationTimerTask == null) {
|
|
||||||
operationTimerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onOperationTimeout();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
timer.schedule(operationTimerTask,delay);
|
|
||||||
}
|
|
||||||
void stopOperationTimerTask(){
|
|
||||||
if(operationTimerTask != null){
|
|
||||||
operationTimerTask.cancel();
|
|
||||||
operationTimerTask = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void startTxProgressTimerTask(){
|
|
||||||
if(txProgressTimerTask==null){
|
|
||||||
txProgressTimerTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onRefreshTxProgress();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
timer.schedule(txProgressTimerTask,1000,1000);
|
|
||||||
}
|
|
||||||
void stopTxProgressTimerTask(){
|
|
||||||
if(txProgressTimerTask != null){
|
|
||||||
txProgressTimerTask.cancel();
|
|
||||||
txProgressTimerTask = null;
|
|
||||||
log.info("stopTxProgressTimerTask");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void onOperationTimeout(){
|
|
||||||
log.info("operation timeout!");
|
|
||||||
// 检查session状态
|
|
||||||
if(mgr_state == STATE_UPGRADING){
|
|
||||||
for(UpgradeSession session:sessionChannelMap.values()){
|
|
||||||
if(session.getState() == DeviceApp.STATE_UPGRADING) {
|
|
||||||
session.onTimeout();
|
|
||||||
deviceAppMapper.setUpgrade(session.getDeviceApp());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changeState(STATE_IDLE);
|
|
||||||
}
|
|
||||||
void onRefreshTxProgress(){
|
|
||||||
WebSocketMsg webSocketMsg = new WebSocketMsg();
|
|
||||||
webSocketMsg.state = (byte) mgr_state;
|
|
||||||
webSocketMsg.state_changed = 0;
|
|
||||||
for(UpgradeSession session:sessionChannelMap.values()){
|
|
||||||
if(session.getState() == DeviceApp.STATE_UPGRADING) {
|
|
||||||
webSocketMsg.sn = session.getSN();
|
|
||||||
webSocketMsg.msg = session.getTxPercentage() + "%";
|
|
||||||
WebSocketServer.sendMessageToAll(JSON.toJSONString(webSocketMsg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void changeState(int new_state){
|
|
||||||
mgr_state = new_state;
|
|
||||||
log.info("transfer to state "+new_state);
|
|
||||||
// 通知UI
|
|
||||||
WebSocketMsg webSocketMsg = new WebSocketMsg();
|
|
||||||
webSocketMsg.state = (byte) mgr_state;
|
|
||||||
webSocketMsg.state_changed = 1;
|
|
||||||
WebSocketServer.sendMessageToAll(JSON.toJSONString(webSocketMsg));
|
|
||||||
|
|
||||||
switch(mgr_state){
|
|
||||||
case STATE_IDLE:
|
|
||||||
stopOperationTimerTask();
|
|
||||||
stopTxProgressTimerTask();
|
|
||||||
break;
|
|
||||||
case STATE_VER_GETTING:
|
|
||||||
startOperationTimerTask(5000);
|
|
||||||
break;
|
|
||||||
case STATE_UPGRADING:
|
|
||||||
startOperationTimerTask(60000);
|
|
||||||
startTxProgressTimerTask();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSessionChanged(UpgradeSession session){
|
|
||||||
// 通知UI
|
|
||||||
WebSocketMsg webSocketMsg = new WebSocketMsg();
|
|
||||||
webSocketMsg.state = (byte) mgr_state;
|
|
||||||
webSocketMsg.sn = session.getSN();
|
|
||||||
|
|
||||||
switch (session.getState()){
|
|
||||||
case DeviceApp.STATE_UPGRADING:
|
|
||||||
webSocketMsg.msg = "升级中";
|
|
||||||
break;
|
|
||||||
case DeviceApp.STATE_TX_COMPLETED:
|
|
||||||
webSocketMsg.msg = "传输完成";
|
|
||||||
break;
|
|
||||||
case DeviceApp.STATE_TX_FAILED:
|
|
||||||
webSocketMsg.msg = "传输失败";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebSocketServer.sendMessageToAll(JSON.toJSONString(webSocketMsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onChannelActive(Channel channel){
|
|
||||||
// get app info
|
|
||||||
Long deviceId = (Long) channel.attr(AttributeKey.valueOf("deviceId")).get();
|
|
||||||
if(deviceId == null){
|
|
||||||
getVerInfo(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onChannelInactive(Channel channel){
|
|
||||||
// 更新状态为”未连接“
|
|
||||||
setDeviceAppState(channel, DeviceApp.STATE_DISCONNECTED);
|
|
||||||
channelSet.remove(channel);
|
|
||||||
sessionChannelMap.remove(channel);
|
|
||||||
log.info("channel inactive. total channel num: "+channelSet.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDeviceAppState(Channel channel, short state){
|
|
||||||
long sn = (long) channel.attr(AttributeKey.valueOf("sn")).get();
|
|
||||||
if(sn > 0){
|
|
||||||
DeviceApp deviceApp = deviceAppMapper.queryById(sn);
|
|
||||||
if (deviceApp != null) {
|
|
||||||
deviceApp.setUpgrade_state(state);
|
|
||||||
deviceAppMapper.setUpgrade(deviceApp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** 获取终端版本信息 ****
|
|
||||||
* 这个函数是controller调用,为避免多个用户同时操作,要避免多线程同时调用
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void getVerInfo(Channel channel){
|
|
||||||
// 向所有连接终端发读取版本请求
|
|
||||||
byte get_app_info[] = {GET_APP_INFO,0};
|
|
||||||
byte tailer_buff[] = {0,0};
|
|
||||||
int crc = CRC16.calculate(get_app_info);
|
|
||||||
tailer_buff[0] = (byte) (crc>>8);
|
|
||||||
tailer_buff[1] = (byte) crc;
|
|
||||||
channel.write(get_app_info);
|
|
||||||
channel.writeAndFlush(tailer_buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onVerInfoReceived(Channel channel, byte[] rx_data){
|
|
||||||
log.info(channel.remoteAddress()+": received app info");
|
|
||||||
// 记录获取到的版本信息
|
|
||||||
if(rx_data.length<9) return;
|
|
||||||
int crc = CRC16.calculate(rx_data, 7);
|
|
||||||
int crc0 = (((short)rx_data[7]&0xFF)<<8) | ((short)rx_data[8]&0xFF);
|
|
||||||
if(crc != crc0) {
|
|
||||||
log.info(channel.remoteAddress()+": crc error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int i=1;
|
|
||||||
long sn = 0;
|
|
||||||
for(i=1;i<=4;i++){
|
|
||||||
sn = (sn<<8) | ((short)rx_data[i]&0xFF);
|
|
||||||
}
|
|
||||||
String cur_ver = ((short)rx_data[i++]&0xFF) + "." + ((short)rx_data[i++]&0xFF);
|
|
||||||
|
|
||||||
// 更新APP记录并检查此终端是否需要升级
|
|
||||||
DeviceApp deviceApp = upgradeDeviceList.get(sn);
|
|
||||||
|
|
||||||
if (deviceApp == null) return;
|
|
||||||
|
|
||||||
deviceApp.setVersion(cur_ver);
|
|
||||||
//记录这个channel是有应答的
|
|
||||||
channel.attr(AttributeKey.valueOf("deviceId")).set(sn);
|
|
||||||
// 如果原来是未连接状态,则改为连接;如果是其他状态则保持不变
|
|
||||||
if(deviceApp.getUpgrade_state() == DeviceApp.STATE_DISCONNECTED) {
|
|
||||||
deviceApp.setUpgrade_state(DeviceApp.STATE_CONNECTED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** 批量升级 ****/
|
|
||||||
Channel getChannelBySn(long sn){
|
|
||||||
for(Channel channel: channelSet){
|
|
||||||
long id = (long) channel.attr(AttributeKey.valueOf("sn")).get();
|
|
||||||
boolean acked = (boolean) channel.attr(AttributeKey.valueOf("acked")).get();
|
|
||||||
if(acked && (id == sn)){
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized public boolean upgradeBatch(String firmware, ArrayList<Long> id_list){
|
|
||||||
if(mgr_state != STATE_IDLE) return false;
|
|
||||||
changeState(STATE_UPGRADING);
|
|
||||||
|
|
||||||
// 清除上次的session
|
|
||||||
for(UpgradeSession session : sessionChannelMap.values()){
|
|
||||||
session.reset();
|
|
||||||
}
|
|
||||||
sessionChannelMap.clear();
|
|
||||||
|
|
||||||
// 创建升级session
|
|
||||||
int upgrade_expected = 0;
|
|
||||||
for(long sn:id_list){
|
|
||||||
DeviceApp deviceApp = deviceAppMapper.queryById(sn);
|
|
||||||
Channel channel = getChannelBySn(sn);
|
|
||||||
if(deviceApp!=null && channel!=null){
|
|
||||||
deviceApp.setFirmware(firmware);
|
|
||||||
UpgradeSession session = new UpgradeSession(deviceApp);
|
|
||||||
sessionChannelMap.put(channel,session);
|
|
||||||
|
|
||||||
// 启动升级会话,这里边会改变deviceApp的状态
|
|
||||||
if(session.start(channel)) {
|
|
||||||
upgrade_expected++;
|
|
||||||
}
|
|
||||||
deviceAppMapper.setUpgrade(deviceApp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(upgrade_expected == 0) changeState(STATE_IDLE);
|
|
||||||
ack_expected = upgrade_expected;
|
|
||||||
ack_num = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** 消息处理 ****
|
|
||||||
* 允许多线程操作
|
|
||||||
*/
|
|
||||||
void outputHex(byte[] rx_data)
|
|
||||||
{
|
|
||||||
byte[] hex = new byte[rx_data.length*3];
|
|
||||||
int pos = 0;
|
|
||||||
for(int i=0; i<rx_data.length; i++){
|
|
||||||
hex[pos] = (byte) (((short)rx_data[i]&0xFF)>>4);
|
|
||||||
if(hex[pos]<=9) hex[pos]+='0';
|
|
||||||
else hex[pos] = (byte) (hex[pos] - 0xA + 'A');
|
|
||||||
pos++;
|
|
||||||
hex[pos] = (byte) (rx_data[i]&0x0F);
|
|
||||||
if(hex[pos]<=9) hex[pos]+='0';
|
|
||||||
else hex[pos] = (byte) (hex[pos] - 0xA + 'A');
|
|
||||||
pos++;
|
|
||||||
hex[pos++] = ' ';
|
|
||||||
}
|
|
||||||
log.info(new String(hex));
|
|
||||||
}
|
|
||||||
public void procMsg(Channel channel, byte[] rx_data) {
|
|
||||||
//outputHex(rx_data);
|
|
||||||
if(mgr_state == STATE_IDLE){
|
|
||||||
// 临时,空闲状态下,如果连续3次收到C,则认为有终端主动请求升级
|
|
||||||
if(rx_data[0]==UpgradeSession.CC && rx_data.length<=4){
|
|
||||||
//onUpgradeRequest(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(mgr_state == STATE_UPGRADING){
|
|
||||||
UpgradeSession session = sessionChannelMap.get(channel);
|
|
||||||
if(session == null) return;
|
|
||||||
|
|
||||||
boolean session_done = false;
|
|
||||||
|
|
||||||
if(rx_data[0]==UPGRADE_ACK){
|
|
||||||
log.info("upgrade ack");
|
|
||||||
//outputHex(rx_data);
|
|
||||||
if(rx_data[5]!=0) {
|
|
||||||
//终端拒绝升级,原因是产品序列号不对
|
|
||||||
session.reject();
|
|
||||||
session_done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
session_done = session.procYmodem(channel, rx_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(session_done){
|
|
||||||
deviceAppMapper.setUpgrade(session.getDeviceApp());
|
|
||||||
if(isAllUpgraded()){
|
|
||||||
//全部发完,等待新版本启动回应答
|
|
||||||
stopTxProgressTimerTask();
|
|
||||||
}
|
|
||||||
onSessionChanged(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询状态或升级状态下都会收到这个指示
|
|
||||||
if(rx_data[0]==APP_INFO_IND && rx_data.length>2) {
|
|
||||||
onVerInfoReceived(channel, rx_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -13,7 +13,7 @@ public class VersionHandler extends ChannelInboundHandlerAdapter {
|
|||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
Channel channel = ctx.channel();
|
Channel channel = ctx.channel();
|
||||||
VerManager.INSTANCE.onChannelActive(channel);
|
UpgradeManager.INSTANCE.onChannelActive(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -33,14 +33,14 @@ public class VersionHandler extends ChannelInboundHandlerAdapter {
|
|||||||
public void channelRead(ChannelHandlerContext ctx,
|
public void channelRead(ChannelHandlerContext ctx,
|
||||||
Object msg) throws Exception{
|
Object msg) throws Exception{
|
||||||
Channel channel = ctx.channel();
|
Channel channel = ctx.channel();
|
||||||
VerManager.INSTANCE.procMsg(channel, (byte[]) msg);
|
UpgradeManager.INSTANCE.onRxData(channel, (byte[]) msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx)
|
public void channelInactive(ChannelHandlerContext ctx)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Channel channel = ctx.channel();
|
Channel channel = ctx.channel();
|
||||||
VerManager.INSTANCE.onChannelInactive(channel);
|
UpgradeManager.INSTANCE.onChannelInactive(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
10
sec-vermgr/src/main/resources/application.properties
Normal file
10
sec-vermgr/src/main/resources/application.properties
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
server.port=9914
|
||||||
|
server.servlet.context-path=/
|
||||||
|
|
||||||
|
spring.application.name=vermgr
|
||||||
|
spring.application.build=20250519
|
||||||
|
|
||||||
|
version_server_port = 9916
|
||||||
|
|
||||||
|
#version manage
|
||||||
|
version.path = firmware
|
||||||
Loading…
x
Reference in New Issue
Block a user