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 = "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;
|
||||
for (Device device : deviceList) {
|
||||
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) {
|
||||
//if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
|
||||
continue;
|
||||
|
||||
@ -148,19 +148,27 @@ public class VersionController extends BasicController{
|
||||
@PostMapping("/sys/ver_mgr/upgrade")
|
||||
@ResponseBody
|
||||
public HttpResult upgradeApp(@RequestParam String firmware, @RequestParam String id_list) throws Exception {
|
||||
|
||||
HttpResp rsp;
|
||||
if(firmware!=null && !firmware.equals("undefined")) {
|
||||
//请求版本服务升级
|
||||
try {
|
||||
HttpResp<HashMap<String, Object>> rsp = versionClient.upgrade(id_list, firmware);
|
||||
rsp = versionClient.upgrade(id_list, firmware);
|
||||
System.out.println(id_list);
|
||||
}
|
||||
catch (Exception e){
|
||||
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){
|
||||
@ -196,4 +204,11 @@ public class VersionController extends BasicController{
|
||||
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 {
|
||||
super.channelActive(ctx);
|
||||
Channel channel = ctx.channel();
|
||||
VerManager.INSTANCE.onChannelActive(channel);
|
||||
UpgradeManager.INSTANCE.onChannelActive(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -33,14 +33,14 @@ public class VersionHandler extends ChannelInboundHandlerAdapter {
|
||||
public void channelRead(ChannelHandlerContext ctx,
|
||||
Object msg) throws Exception{
|
||||
Channel channel = ctx.channel();
|
||||
VerManager.INSTANCE.procMsg(channel, (byte[]) msg);
|
||||
UpgradeManager.INSTANCE.onRxData(channel, (byte[]) msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx)
|
||||
throws Exception {
|
||||
Channel channel = ctx.channel();
|
||||
VerManager.INSTANCE.onChannelInactive(channel);
|
||||
UpgradeManager.INSTANCE.onChannelInactive(channel);
|
||||
}
|
||||
|
||||
@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