泰国沙盘调试改动

This commit is contained in:
joylink_zhangsai 2023-06-04 17:23:46 +08:00
parent f3ec423779
commit 74b9ab80da
38 changed files with 4404 additions and 3282 deletions

View File

@ -0,0 +1,8 @@
package club.joylink.rtss.constants;
public interface ProjectCode {
String THAILAND_SANDBOX = "THAILAND_SANDBOX";
String SR_SANDBOX = "SR_SANDBOX";
}

View File

@ -7,12 +7,32 @@ import club.joylink.rtss.services.project.DeviceService;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.project.*;
import club.joylink.rtss.vo.client.project.IbpConfigVO;
import club.joylink.rtss.vo.client.project.LswConfigVO;
import club.joylink.rtss.vo.client.project.LwConfigVO;
import club.joylink.rtss.vo.client.project.PlcGatewayConfigVO;
import club.joylink.rtss.vo.client.project.ProjectDevicePageQueryVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.PscConfigVO;
import club.joylink.rtss.vo.client.project.PsdConfigVO;
import club.joylink.rtss.vo.client.project.PslConfigVO;
import club.joylink.rtss.vo.client.project.RelationLoginConfigVO;
import club.joylink.rtss.vo.client.project.SignalConfigVO;
import club.joylink.rtss.vo.client.project.SwitchConfigVO;
import club.joylink.rtss.vo.client.project.VrIbpConfigVO;
import club.joylink.rtss.vo.client.project.VrpsdConfigVO;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 项目设备管理接口()
@ -258,4 +278,10 @@ public class DeviceController {
AccountVO accountVO) {
this.deviceService.addOrUpdateSayDeviceConfig(accountVO);
}
@PostMapping("/thailand/addOrUpdate/{mapId}")
public void addOrUpdateThailandDeviceConfig(@RequestAttribute(name = AuthenticateInterceptor.LOGIN_USER_KEY)
AccountVO accountVO, @PathVariable Long mapId) {
this.deviceService.addOrUpdateThailandDeviceConfig(accountVO, mapId);
}
}

View File

@ -4,8 +4,20 @@ import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.project.*;
import club.joylink.rtss.vo.client.project.IbpConfigVO;
import club.joylink.rtss.vo.client.project.LswConfigVO;
import club.joylink.rtss.vo.client.project.LwConfigVO;
import club.joylink.rtss.vo.client.project.PlcGatewayConfigVO;
import club.joylink.rtss.vo.client.project.ProjectDevicePageQueryVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.PscConfigVO;
import club.joylink.rtss.vo.client.project.PsdConfigVO;
import club.joylink.rtss.vo.client.project.PslConfigVO;
import club.joylink.rtss.vo.client.project.RelationLoginConfigVO;
import club.joylink.rtss.vo.client.project.SignalConfigVO;
import club.joylink.rtss.vo.client.project.SwitchConfigVO;
import club.joylink.rtss.vo.client.project.VrIbpConfigVO;
import club.joylink.rtss.vo.client.project.VrpsdConfigVO;
import java.util.List;
public interface DeviceService {
@ -216,4 +228,6 @@ public interface DeviceService {
void addOrUpdateHhcjDeviceConfig(AccountVO accountVO);
void addOrUpdateSayDeviceConfig(AccountVO accountVO);
void addOrUpdateThailandDeviceConfig(AccountVO accountVO, Long mapId);
}

View File

@ -1,17 +1,35 @@
package club.joylink.rtss.services.project;
import club.joylink.rtss.constants.Project;
import club.joylink.rtss.constants.ProjectCode;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.dao.ProjectDeviceDAO;
import club.joylink.rtss.entity.ProjectDevice;
import club.joylink.rtss.entity.ProjectDeviceExample;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.IMapService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service.ThailandSignalServiceImpl;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service.ThailandSwitchServiceImpl;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.project.*;
import club.joylink.rtss.vo.client.project.IbpConfigVO;
import club.joylink.rtss.vo.client.project.LswConfigVO;
import club.joylink.rtss.vo.client.project.LwConfigVO;
import club.joylink.rtss.vo.client.project.PlcGatewayConfigVO;
import club.joylink.rtss.vo.client.project.ProjectDevicePageQueryVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.PscConfigVO;
import club.joylink.rtss.vo.client.project.PsdConfigVO;
import club.joylink.rtss.vo.client.project.PslConfigVO;
import club.joylink.rtss.vo.client.project.RelationLoginConfigVO;
import club.joylink.rtss.vo.client.project.SignalConfigVO;
import club.joylink.rtss.vo.client.project.SwitchConfigVO;
import club.joylink.rtss.vo.client.project.UDPClientConfigVO;
import club.joylink.rtss.vo.client.project.UDPLowConfigVO;
import club.joylink.rtss.vo.client.project.VrIbpConfigVO;
import club.joylink.rtss.vo.client.project.VrpsdConfigVO;
import club.joylink.rtss.vo.client.project.gzb.GzbSignalConfigVO;
import club.joylink.rtss.vo.client.project.gzb.GzbSwitchConfigVO;
import club.joylink.rtss.vo.client.project.hhcj.HhcjIbpConfigVO;
@ -19,13 +37,20 @@ import club.joylink.rtss.vo.client.project.hhcj.HhcjPsdConfigVO;
import club.joylink.rtss.vo.client.project.richor.ZjdIbpConfigVO;
import club.joylink.rtss.vo.client.project.richor.ZjdPsdConfigVO;
import club.joylink.rtss.vo.client.project.richor.ZjdPslConfigVO;
import club.joylink.rtss.vo.client.project.say.*;
import club.joylink.rtss.vo.client.project.say.SayIbpConfigVO;
import club.joylink.rtss.vo.client.project.say.SayPsdConfigVO;
import club.joylink.rtss.vo.client.project.say.SaySectionConfigVO;
import club.joylink.rtss.vo.client.project.say.SaySignalConfigVO;
import club.joylink.rtss.vo.client.project.say.SaySwitchConfigVO;
import club.joylink.rtss.vo.client.project.sdy.SdyPsdConfigVO;
import club.joylink.rtss.vo.client.project.sdy.SdyPslConfigVO;
import club.joylink.rtss.vo.client.project.sr.SrSectionConfigVO;
import club.joylink.rtss.vo.client.project.sr.SrSignalConfigVO;
import club.joylink.rtss.vo.client.project.sr.SrSwitchConfigVO;
import club.joylink.rtss.vo.client.project.sr.SrTrainConfigVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandSectionConfigVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandSwitchConfigVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandTrainConfigVO;
import club.joylink.rtss.vo.client.project.xty.XtyPsdConfigVO;
import club.joylink.rtss.vo.map.MapGraphDataNewVO;
import club.joylink.rtss.vo.map.MapVO;
@ -33,19 +58,17 @@ import club.joylink.rtss.vo.map.graph.MapSectionNewVO;
import club.joylink.rtss.vo.map.graph.MapSignalNewVO;
import club.joylink.rtss.vo.map.graph.MapSwitchVO;
import club.joylink.rtss.vo.map.graph.MapTrainVO;
import club.joylink.rtss.vo.project.ProjectVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@Service
public class DeviceServiceImpl implements DeviceService {
@ -71,8 +94,10 @@ public class DeviceServiceImpl implements DeviceService {
criteria.andTypeEqualTo(queryVO.getType().name());
}
PageHelper.startPage(queryVO.getPageNum(), queryVO.getPageSize());
Page<ProjectDevice> projectDevices = (Page<ProjectDevice>) this.projectDeviceDAO.selectByExample(example);
List<ProjectDeviceVO> projectDeviceVOS = ProjectDeviceVO.convert2VOList(projectDevices.getResult());
Page<ProjectDevice> projectDevices = (Page<ProjectDevice>) this.projectDeviceDAO.selectByExample(
example);
List<ProjectDeviceVO> projectDeviceVOS = ProjectDeviceVO.convert2VOList(
projectDevices.getResult());
return PageVO.convert(projectDevices, projectDeviceVOS);
}
@ -281,9 +306,12 @@ public class DeviceServiceImpl implements DeviceService {
}
private void check(ProjectDevice entity, ProjectDeviceVO projectDeviceVO) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getProjectCode(), projectDeviceVO.getProject());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getCode(), projectDeviceVO.getCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getType(), projectDeviceVO.getType().name());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getProjectCode(),
projectDeviceVO.getProject());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getCode(),
projectDeviceVO.getCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getType(),
projectDeviceVO.getType().name());
}
@Override
@ -293,7 +321,8 @@ public class DeviceServiceImpl implements DeviceService {
@Override
public List<ProjectDeviceVO> queryByType(ProjectDeviceType type, String project) {
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotEquals(project, Project.DEFAULT.name(),
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotEquals(project,
Project.DEFAULT.name(),
String.format("项目[%s]没有权限", project));
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria().andProjectCodeEqualTo(project).andTypeEqualTo(type.name());
@ -304,7 +333,8 @@ public class DeviceServiceImpl implements DeviceService {
@Override
public ProjectDeviceVO getDeviceDetailInfoById(Long id) {
ProjectDevice projectDevice = this.projectDeviceDAO.selectByPrimaryKey(id);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(projectDevice, String.format("id为[%s]的设备不存在", id));
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertNotNull(projectDevice,
String.format("id为[%s]的设备不存在", id));
return new ProjectDeviceVO(projectDevice);
}
@ -322,7 +352,8 @@ public class DeviceServiceImpl implements DeviceService {
}
@Override
public List<ProjectDeviceVO> queryDetailByTypes(List<ProjectDeviceType> typeList, String project) {
public List<ProjectDeviceVO> queryDetailByTypes(List<ProjectDeviceType> typeList,
String project) {
if (CollectionUtils.isEmpty(typeList)) {
throw new IllegalArgumentException("ProjectDeviceType list cannot empty");
}
@ -340,7 +371,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.XTY.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildXtyProjectDevices(accountVO);
@ -381,7 +413,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.GZB.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildGzbProjectDevices(accountVO);
@ -396,7 +429,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.SDY.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildSdyProjectDevices(accountVO);
@ -411,7 +445,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.RICHOR_JOINT.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildZjdProjectDevices(accountVO);
@ -426,7 +461,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.SR_SANDBOX.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildSrProjectDevices(accountVO, mapId);
@ -441,7 +477,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.RICHOR_HHCJ.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildHhcjProjectDevices(accountVO);
@ -456,7 +493,8 @@ public class DeviceServiceImpl implements DeviceService {
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(Project.SAY.name())
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name).collect(Collectors.toList()));
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildSayProjectDevices(accountVO);
@ -465,6 +503,22 @@ public class DeviceServiceImpl implements DeviceService {
}
}
@Override
public void addOrUpdateThailandDeviceConfig(AccountVO accountVO, Long mapId) {
// 删除旧配置
ProjectDeviceExample example = new ProjectDeviceExample();
example.createCriteria()
.andProjectCodeEqualTo(ProjectCode.THAILAND_SANDBOX)
.andTypeIn(ProjectDeviceType.PlcDeviceList().stream().map(Enum::name)
.collect(Collectors.toList()));
this.projectDeviceDAO.deleteByExample(example);
// 保存新配置
List<ProjectDevice> list = this.buildThailandProjectDevices(accountVO, mapId);
for (ProjectDevice projectDevice : list) {
this.projectDeviceDAO.insert(projectDevice);
}
}
private List<ProjectDevice> buildSayProjectDevices(AccountVO accountVO) {
LocalDateTime now = LocalDateTime.now();
List<ProjectDevice> list = new ArrayList<>();
@ -603,7 +657,8 @@ public class DeviceServiceImpl implements DeviceService {
signal.setType(ProjectDeviceType.SIGNAL.name());
signal.setCreator(accountVO.getId());
signal.setCreateTime(now);
SrSignalConfigVO configVO = new SrSignalConfigVO(mapSignalNewVO.getCode(), mapSignalNewVO.getSrCode());
SrSignalConfigVO configVO = new SrSignalConfigVO(mapSignalNewVO.getCode(),
mapSignalNewVO.getSrCode());
signal.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(signal);
}
@ -617,7 +672,8 @@ public class DeviceServiceImpl implements DeviceService {
aSwitch.setType(ProjectDeviceType.SWITCH.name());
aSwitch.setCreator(accountVO.getId());
aSwitch.setCreateTime(now);
SrSwitchConfigVO configVO = new SrSwitchConfigVO(mapSwitchVO.getCode(), mapSwitchVO.getSrCode());
SrSwitchConfigVO configVO = new SrSwitchConfigVO(mapSwitchVO.getCode(),
mapSwitchVO.getSrCode());
aSwitch.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(aSwitch);
}
@ -631,8 +687,9 @@ public class DeviceServiceImpl implements DeviceService {
section.setType(ProjectDeviceType.SECTION.name());
section.setCreator(accountVO.getId());
section.setCreateTime(now);
SrSectionConfigVO configVO = new SrSectionConfigVO(mapSectionNewVO.getCode(), mapSectionNewVO.getSrCode());
fillTime(configVO, mapSectionNewVO);
SrSectionConfigVO configVO = new SrSectionConfigVO(mapSectionNewVO.getCode(),
mapSectionNewVO.getSrCode());
srFillTime(configVO, mapSectionNewVO);
section.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(section);
}
@ -646,7 +703,8 @@ public class DeviceServiceImpl implements DeviceService {
train.setType(ProjectDeviceType.TRAIN.name());
train.setCreator(accountVO.getId());
train.setCreateTime(now);
SrTrainConfigVO configVO = new SrTrainConfigVO(mapTrainVO.getGroupNumber(), String.valueOf(Integer.parseInt(mapTrainVO.getGroupNumber())));
SrTrainConfigVO configVO = new SrTrainConfigVO(mapTrainVO.getGroupNumber(),
String.valueOf(Integer.parseInt(mapTrainVO.getGroupNumber())));
train.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(train);
}
@ -654,9 +712,9 @@ public class DeviceServiceImpl implements DeviceService {
}
/**
* 填充区段延时停车时间
* 填充区段延时停车时间上饶沙盘项目
*/
private void fillTime(SrSectionConfigVO configVO, MapSectionNewVO section) {
private void srFillTime(SrSectionConfigVO configVO, MapSectionNewVO section) {
Float headDelayTime = null;
Float tailDelayTime = null;
switch (section.getCode()) {
@ -792,16 +850,6 @@ public class DeviceServiceImpl implements DeviceService {
return list;
}
private ProjectDevice buildIm(ProjectVO projectVO, Long creatorId) {
ProjectDevice im = new ProjectDevice();
im.setProjectCode(projectVO.name());
im.setCode(projectVO.name().toLowerCase() + "-" + "im");
im.setType(ProjectDeviceType.IM.name());
im.setCreator(creatorId);
im.setCreateTime(LocalDateTime.now());
return im;
}
private List<ProjectDevice> buildGzbProjectDevices(AccountVO accountVO) {
LocalDateTime now = LocalDateTime.now();
List<ProjectDevice> list = new ArrayList<>();
@ -837,4 +885,152 @@ public class DeviceServiceImpl implements DeviceService {
list.add(signal);
return list;
}
private List<ProjectDevice> buildThailandProjectDevices(AccountVO accountVO, long mapId) {
LocalDateTime now = LocalDateTime.now();
List<ProjectDevice> list = new ArrayList<>();
String projectCode = ProjectCode.THAILAND_SANDBOX;
//道岔和列车数据发送端口
ProjectDevice switchTrainUdpLow = new ProjectDevice();
switchTrainUdpLow.setProjectCode(projectCode);
switchTrainUdpLow.setCode("udp-sender-1");
switchTrainUdpLow.setType(ProjectDeviceType.UDP_LOW.name());
switchTrainUdpLow.setCreator(accountVO.getId());
switchTrainUdpLow.setCreateTime(now);
switchTrainUdpLow.setConfig(
new UDPLowConfigVO(ThailandSwitchServiceImpl.NAME, "192.168.0.10", 44449).toJson());
list.add(switchTrainUdpLow);
//信号机数据发送端口
ProjectDevice signalUdpLow = new ProjectDevice();
signalUdpLow.setProjectCode(projectCode);
signalUdpLow.setCode("udp-sender-2");
signalUdpLow.setType(ProjectDeviceType.UDP_LOW.name());
signalUdpLow.setCreator(accountVO.getId());
signalUdpLow.setCreateTime(now);
signalUdpLow.setConfig(
new UDPLowConfigVO(ThailandSignalServiceImpl.NAME, "192.168.0.10", 44445).toJson());
list.add(signalUdpLow);
//UDP数据接收
ProjectDevice udpClient = new ProjectDevice();
udpClient.setProjectCode(projectCode);
udpClient.setCode("udp-receiver");
udpClient.setType(ProjectDeviceType.UDP_CLIENT.name());
udpClient.setCreator(accountVO.getId());
udpClient.setCreateTime(now);
UDPClientConfigVO udpClientConfigVO = new UDPClientConfigVO("192.168.0.10", 44449);
udpClient.setConfig(JsonUtils.writeValueAsString(udpClientConfigVO));
list.add(udpClient);
/*-------------------- 地图设备 --------------------*/
MapVO map = iMapService.getMapDetail(mapId);
MapGraphDataNewVO graphDataNew = map.getGraphDataNew();
//信号机
for (MapSignalNewVO mapSignalNewVO : graphDataNew.getSignalList()) {
if (StringUtils.hasText(mapSignalNewVO.getSrCode())) {
ProjectDevice signal = new ProjectDevice();
signal.setProjectCode(projectCode);
signal.setCode("signal-" + mapSignalNewVO.getCode());
signal.setType(ProjectDeviceType.SIGNAL.name());
signal.setCreator(accountVO.getId());
signal.setCreateTime(now);
SrSignalConfigVO configVO = new SrSignalConfigVO(mapSignalNewVO.getCode(),
mapSignalNewVO.getSrCode());
signal.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(signal);
}
}
//道岔
for (MapSwitchVO mapSwitchVO : graphDataNew.getSwitchList()) {
if (StringUtils.hasText(mapSwitchVO.getSrCode())) {
ProjectDevice aSwitch = new ProjectDevice();
aSwitch.setProjectCode(projectCode);
aSwitch.setCode("switch-" + mapSwitchVO.getCode());
aSwitch.setType(ProjectDeviceType.SWITCH.name());
aSwitch.setCreator(accountVO.getId());
aSwitch.setCreateTime(now);
ThailandSwitchConfigVO configVO = new ThailandSwitchConfigVO(mapSwitchVO.getCode(),
mapSwitchVO.getSrCode());
aSwitch.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(aSwitch);
}
}
//区段
for (MapSectionNewVO mapSectionNewVO : graphDataNew.getSectionList()) {
if (StringUtils.hasText(mapSectionNewVO.getSrCode())) {
ProjectDevice section = new ProjectDevice();
section.setProjectCode(projectCode);
section.setCode("section-" + mapSectionNewVO.getCode());
section.setType(ProjectDeviceType.SECTION.name());
section.setCreator(accountVO.getId());
section.setCreateTime(now);
ThailandSectionConfigVO configVO = new ThailandSectionConfigVO(mapSectionNewVO.getCode(),
mapSectionNewVO.getSrCode());
thailandFillTime(configVO, mapSectionNewVO);
section.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(section);
}
}
//列车
List<MapTrainVO> trainList = graphDataNew.getTrainList();
for (MapTrainVO mapTrainVO : trainList) {
ProjectDevice train = new ProjectDevice();
train.setProjectCode(projectCode);
train.setCode("train-" + mapTrainVO.getGroupNumber());
train.setType(ProjectDeviceType.TRAIN.name());
train.setCreator(accountVO.getId());
train.setCreateTime(now);
ThailandTrainConfigVO configVO = new ThailandTrainConfigVO(mapTrainVO.getGroupNumber(),
String.valueOf(Integer.parseInt(mapTrainVO.getGroupNumber())));
train.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(train);
}
return list;
}
private void thailandFillTime(ThailandSectionConfigVO configVO, MapSectionNewVO section) {
Float headDelayTime = null;
Float tailDelayTime = null;
if (section.isStandTrack()) { //站台轨默认为车尾出清立即停车
headDelayTime = 5f;
}
switch (section.getCode()) {
case "T233": //X302G
headDelayTime = 7f;
break;
case "T232": //X303G
headDelayTime = 7f;
break;
case "T231": //X304G
headDelayTime = 5.5f;
break;
case "T175": //4站-IIG
headDelayTime = 5.5f;
break;
case "T121": //4站-IIG
headDelayTime = 5.2f;
break;
case "T77": //4站-IIG
headDelayTime = 6f;
break;
case "T145": //QX04
tailDelayTime = 0f;
break;
case "T146": //QS04
tailDelayTime = 0f;
break;
case "T104": //QX03
tailDelayTime = 0f;
break;
case "T105": //QS03
tailDelayTime = 0f;
break;
case "T62": //QX02
tailDelayTime = 0f;
break;
case "T63": //QS02
tailDelayTime = 0f;
break;
}
configVO.setHeadDelayTime(headDelayTime);
configVO.setTailDelayTime(tailDelayTime);
}
}

View File

@ -1,6 +1,5 @@
package club.joylink.rtss.simulation.cbtc.CI.device;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SignalAspect;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
@ -62,9 +61,9 @@ public class CiSignalControlService {
} else {
this.virtualRealityDeviceService.control(simulation, vrSignal, SignalAspect.No);
}
} else { // 模式开放室外信号
} else { // 模式开放室外信号
if(signal.getSignalModel().getDefaultAspect().equals(aspect) ||
(signal.getSignalModel().getGuideAspect().equals(aspect) && signal.isHigherThanGuideLevel()) ||
(aspect.equals(signal.getSignalModel().getGuideAspect()) && signal.isHigherThanGuideLevel()) ||
(signal.isAtpLevel() || signal.isMainLevel())) {
this.virtualRealityDeviceService.control(simulation, vrSignal, aspect);
}

View File

@ -7,21 +7,6 @@ import club.joylink.rtss.vo.project.ProjectVO;
* 项目综合演练仿真服务
*/
public interface ProjectJointSimulationService {
/**
* 实训室教员机登录创建仿真
*
* @param loginUserInfo
* @return
*/
Simulation createSimulation(LoginUserInfoVO loginUserInfo);
/**
* 获取实训室仿真
*
* @param project
* @return
*/
Simulation getProjectSimulation(String project);
/**
* 通过项目设置的mapID与功能ID获取仿真

View File

@ -1,35 +1,21 @@
package club.joylink.rtss.simulation.cbtc;
import club.joylink.rtss.constants.MapPrdTypeEnum;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.IMapService;
import club.joylink.rtss.services.auth.ProjectDeviceLogoutEvent;
import club.joylink.rtss.services.auth.UserLogoutEvent;
import club.joylink.rtss.services.project.DeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.SimulationRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.event.SimulationUserEnterEvent;
import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.member.SimulationUser;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.map.MapVO;
import club.joylink.rtss.vo.project.ProjectVO;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Slf4j
@Service
@ -40,169 +26,17 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
@Autowired
private ApplicationContext applicationContext;
@Autowired
private IMapService iMapService;
@Autowired
private DeviceService deviceService;
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private MemberManager memberManager;
@Autowired
private SimulationRealDeviceThread simulationRealDeviceThread;
@Autowired
private UDPRealDeviceThread udpRealDeviceThread;
@Autowired
private SimulationService simulationService;
@Override
public Simulation createSimulation(LoginUserInfoVO loginUserInfo) {
String project = loginUserInfo.getProject();
Simulation oldSimulation = projectSimulationMap.get(project);
// 之前的仿真销毁
if (Objects.nonNull(oldSimulation)) {
this.handleLogout(oldSimulation.getBuildParams().getLoginUserInfo());
}
// 权限判断
AccountVO accountVO = loginUserInfo.getAccountVO();
// 查询用户综合演练配置
// 查询项目地图默认取第一个暂时这样处理后面考虑配置实训室-地图对应
List<MapVO> mapList = this.iMapService.findOnlineMapByProjectCode(project);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertCollectionNotEmpty(mapList,
String.format("项目[%s]无地图", project));
// 查询项目设备
List<ProjectDeviceVO> projectDeviceList = this.deviceService
.queryDetailByTypes(ProjectDeviceType.PlcDeviceList(), project);
List<RealDeviceConfig> realDeviceList = ProjectDeviceVO.convert2RealDeviceList(projectDeviceList);
log.info(String.format("load project device list: [%s]",
String.join(",", realDeviceList.stream().map(realDevice -> realDevice.toString()).collect(Collectors.toList()))));
// 构建仿真
Long mapId = mapList.get(0).getId();
Simulation simulation = this.groupSimulationService.create(loginUserInfo, mapId,
MapPrdTypeEnum.JOINT, Simulation.FunctionalType.SIMULATION);
this.loadRealDevices(simulation, realDeviceList);
projectSimulationMap.put(project, simulation);
return simulation;
}
private void loadRealDevices(Simulation simulation, List<RealDeviceConfig> realDeviceList) {
try {
simulation.setRealDeviceList(realDeviceList);
if (!CollectionUtils.isEmpty(realDeviceList)) {
simulationRealDeviceThread.addJobs(simulation);
udpRealDeviceThread.addJobs(simulation);
}
for (RealDeviceConfig realDevice : realDeviceList) {
if (ProjectDeviceType.PLC_GATEWAY.equals(realDevice.getDeviceType())) {
continue;
}
String deviceCode = this.queryDeviceCodeFromConfig(realDevice);
if (Objects.nonNull(deviceCode)) {
this.groupSimulationService.connectDevice(simulation.getId(),
deviceCode, realDevice.getProjectDevice().getId());
}
}
} catch (Exception e) {
log.error("仿真加载真实设备异常", e);
// 清理仿真
this.groupSimulationService.clearSimulation(simulation.getId(), simulation.getCreator());
throw BusinessExceptionAssertEnum.TRAINING_ROOM_SIMULATION_LOAD_DEVICE_ERROR.exception(e);
}
}
private String queryDeviceCodeFromConfig(RealDeviceConfig config) {
return config.findDeviceCode();
// switch (config.getProject()) {
// case "HEB": {
// switch (config.getDeviceType()) {
// case IBP:
// return ((Heb1IbpConfig) config).getConfig().getStationCode();
// case PSL:
// return ((Heb1PslConfig) config).getConfig().getPsdCode();
// case PSC:
// return ((Heb1PscConfig) config).getConfig().getPsdCode();
// }
// break;
// }
// case "XTY": {
// switch (config.getDeviceType()) {
// case PSD:
// return ((XtyPsdConfig) config).getConfig().getPsdCode();
// }
// break;
// }
// case "RICHOR_JOINT": {
// switch (config.getDeviceType()) {
// case IBP:
// return ((ZjdIbpConfig) config).getConfigVO().getIbpCode();
// case PSL:
// return ((ZjdPslConfig) config).getConfigVO().getPslCode();
// }
// break;
// }
// case "SR_SANDBOX": {
// switch (config.getDeviceType()) {
// case SIGNAL:
// return ((SrSignalConfig) config).getConfigVO().getVrCode();
// case SECTION:
// return ((SrSectionConfig) config).getConfigVO().getVrCode();
// case SWITCH:
// return ((SrSwitchConfig) config).getConfigVO().getVrCode();
// case TRAIN:
// return ((SrTrainConfig) config).getConfigVO().getVrCode();
// }
// break;
// }
// case "RICHOR_HHCJ": {
// switch (config.getDeviceType()) {
// case IBP:
// return ((HhcjIbpConfig) config).getConfigVO().getIbpCode();
// case PSD:
// return ((HhcjPsdConfig) config).getConfigVO().getPsdCode();
// }
// break;
// }
// case "SAY": {
// return config.findDeviceCode();
// switch (config.getDeviceType()) {
// case IBP:
// return ((SayIbpConfig) config).getConfigVO().getIbpCode();
// case PSD:
// return ((SayPsdConfig) config).getConfigVO().getPsdCode();
// case SIGNAL:
// return ((SaySignalConfig) config).getConfigVO().getSignalCode();
// case SWITCH:
// return ((SaySwitchConfig) config).getConfigVO().getSwitchCode();
// case SECTION:
// return config.findDeviceCode();
// }
// break;
// }
// }
// return null;
}
private Simulation queryProjectSimulation(String project) {
Simulation simulation = projectSimulationMap.get(project);
return simulation;
}
@Override
public Simulation getProjectSimulation(String project) {
Simulation simulation = projectSimulationMap.get(project);
BusinessExceptionAssertEnum.TRAINING_ROOM_SIMULATION_NOT_EXIST
.assertNotNull(simulation, String.format("项目[%s]实训室仿真不存在", project));
return simulation;
}
@Override
public Simulation getSimulationByProject(ProjectVO project) {
Simulation simulation = simulationService.querySimulation(project.getMapId(), project.getFunctionId());
@ -219,52 +53,6 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
simulation.addSimulationUser(simulationUser);
SimulationUserEnterEvent userEnterEvent = new SimulationUserEnterEvent(this, simulation, simulationUser);
this.applicationContext.publishEvent(userEnterEvent);
// switch (deviceVO.getType()) {
// case LW: {
// // 暂时默认先按配置的车站创建成员
// LwConfigVO lwConfigVO = deviceVO.buildLwConfig();
// Station station = simulation.getRepository().getByCode(lwConfigVO.getStationCode(), Station.class);
// SimulationMember member = simulation.getSimulationMember(station, SimulationMember.Type.STATION_SUPERVISOR);
// this.memberManager.playRole(simulation, loginUserInfo.getAccountVO().getId(), member.getId());
// // 现地工作站
// break;
// }
// case CW: {
// // 行调工作站
// List<SimulationMember> dispatcherList = simulation.querySimulationMembersOfRole(SimulationMember.Type.DISPATCHER);
// SimulationMember dispatcher = null;
// for (SimulationMember member : dispatcherList) {
// if (member.isRobot()) {
// dispatcher = member;
// break;
// }
// }
// if (Objects.isNull(dispatcher)) {
// // 行调都被占用添加新的行调
// dispatcher = this.memberManager.addRole(simulation, SimulationMember.Type.DISPATCHER);
// }
// this.memberManager.playRole(simulation, loginUserInfo.getAccountVO().getId(), dispatcher.getId());
// break;
// }
// case DEPOT: {
// List<SimulationMember> depoterList = simulation.querySimulationMembersOfRole(SimulationMember.Type.DEPOT_DISPATCHER);
// SimulationMember depoter = null;
// for (SimulationMember member : depoterList) {
// if (member.isRobot()) {
// depoter = member;
// break;
// }
// }
// if (Objects.isNull(depoter)) {
// depoter = this.memberManager.addRole(simulation, SimulationMember.Type.DEPOT_DISPATCHER);
// }
// this.memberManager.playRole(simulation, loginUserInfo.getAccountVO().getId(), depoter.getId());
// break;
// }
// case SCHEDULING: {
//
// }
// }
loginUserInfo.setGroup(simulation.getId());
}

View File

@ -10,12 +10,17 @@ import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.simulation.cbtc.training2.ecm.anno.ExpConditionMaterialAnno;
import club.joylink.rtss.simulation.cbtc.training2.ecm.anno.ExpConditionMaterialSrcAnno;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* 区段
*/
@ -288,10 +293,7 @@ public class Section extends DelayUnlockDevice {
private List<ShuntingType> shuntingTypeList;
/**
* 停稳倒计时
* 0 表示初始状态
* -1 表示准备开始计时
* 非负数表示当前计时
* 停稳倒计时 0 表示初始状态 -1 表示准备开始计时 非负数表示当前计时
*/
private int stopCountDown;
@ -361,7 +363,8 @@ public class Section extends DelayUnlockDevice {
* @return
*/
public boolean isFree() {
return !this.blockade && !this.routeLock && !this.overlapLock && !this.ctOccupied && !this.nctOccupied;
return !this.blockade && !this.routeLock && !this.overlapLock && !this.ctOccupied
&& !this.nctOccupied;
}
public void addLogicSection(Section logic) {
@ -397,7 +400,14 @@ public class Section extends DelayUnlockDevice {
}
public Collection<Signal> getSignals() {
return Arrays.asList(getSignalToLeft(), getSignalToRight());
List<Signal> list = new ArrayList<>(2);
if (signalToLeft != null) {
list.add(signalToLeft);
}
if (signalToRight != null) {
list.add(signalToRight);
}
return list;
}
public float getStopPointByDirection(boolean right) {
@ -465,6 +475,7 @@ public class Section extends DelayUnlockDevice {
}
return null;
}
public Section findBackRunningSectionBaseRealSwitch(boolean right) {
if (right && Objects.nonNull(this.leftSection)) {
return this.leftSection;
@ -475,6 +486,7 @@ public class Section extends DelayUnlockDevice {
}
return null;
}
/**
* 获取左/右向关联的区段
*
@ -487,8 +499,12 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Section section = (Section) o;
return getCode().equals(section.getCode());
}
@ -913,7 +929,8 @@ public class Section extends DelayUnlockDevice {
*/
private void nctOccupiedBySwitchPosition(Simulation simulation) {
List<Switch> relSwitchList = this.getRelSwitchList();
if (relSwitchList.size() == 2 && simulation.getRepository().getConfig().isSwitchSingleHandle()) {
if (relSwitchList.size() == 2 && simulation.getRepository().getConfig()
.isSwitchSingleHandle()) {
// 道岔计轴区段两个道岔有一个反位
if (!relSwitchList.stream().allMatch(Switch::isPosN)) {
for (Switch aSwitch : relSwitchList) {
@ -952,13 +969,16 @@ public class Section extends DelayUnlockDevice {
* 岔心判断占用
*/
private void crossJudgeOccupied() {
if (!this.cross)
if (!this.cross) {
return;
}
this.logicList.forEach(logic -> {
Section leftSection = logic.getLeftSection();
boolean leftSectionNctOccupied = leftSection.isNctOccupied() && leftSection.getParent().equals(this.parent);
boolean leftSectionNctOccupied =
leftSection.isNctOccupied() && leftSection.getParent().equals(this.parent);
Section rightSection = logic.getRightSection();
boolean rightSectionNctOccupied = rightSection.isNctOccupied() && rightSection.getParent().equals(this.parent);
boolean rightSectionNctOccupied =
rightSection.isNctOccupied() && rightSection.getParent().equals(this.parent);
if (leftSectionNctOccupied || rightSectionNctOccupied) {
logic.setNctOccupied(true);
setNctOccupied(true);
@ -1083,8 +1103,9 @@ public class Section extends DelayUnlockDevice {
private boolean isLogicStandTrack() {
Section parent = this.getParent();
if (parent == null || !parent.isStandTrack())
if (parent == null || !parent.isStandTrack()) {
return false;
}
float left = parent.getStopPointByDirection(false);
float right = parent.getStopPointByDirection(true);
return this.minOffset <= right && this.maxOffset >= left;
@ -1185,12 +1206,14 @@ public class Section extends DelayUnlockDevice {
public boolean isAheadOf(SimulationDataRepository repository, Section other, boolean right) {
List<RoutePath> routePaths = repository.queryRoutePathsByEndAndContainsSection(this, other);
if (CollectionUtils.isEmpty(routePaths))
if (CollectionUtils.isEmpty(routePaths)) {
return false;
}
for (RoutePath routePath : routePaths) {
if (routePath.isRight() == right)
if (routePath.isRight() == right) {
return true;
}
}
return false;
}
@ -1266,7 +1289,8 @@ public class Section extends DelayUnlockDevice {
if (this.isOccupied() &&
this.getVirtualAxleCounter() != null &&
this.getFault() != null &&
(AxleFault.FAULT.equals(this.getFault()) || AxleFault.CBTC_OCCUPIED_FAULT.equals(this.getFault()))) {
(AxleFault.FAULT.equals(this.getFault()) || AxleFault.CBTC_OCCUPIED_FAULT.equals(
this.getFault()))) {
return true;
} else if (this.getParent() != null) {
return this.getParent().isFaultOccupied();
@ -1290,8 +1314,9 @@ public class Section extends DelayUnlockDevice {
* 获取道岔计轴区段被道岔连接起来的区段
*/
public List<Section> findConnectedSections() {
if (!isSwitchAxleCounterSection())
if (!isSwitchAxleCounterSection()) {
return Collections.emptyList();
}
Switch relSwitch = getLogicList().get(0).getRelSwitch();
List<Section> sections = new ArrayList<>();
sections.add(relSwitch.getA());
@ -1304,10 +1329,12 @@ public class Section extends DelayUnlockDevice {
}
public Section findPhysicalSection() {
if (this.isPhysical())
if (this.isPhysical()) {
return this;
if (this.parent != null)
}
if (this.parent != null) {
return this.parent.findPhysicalSection();
}
return null;
}
@ -1384,8 +1411,9 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Section axleSection = ((Section) device).getAxleCounterSection();
if (Objects.equals(this, axleSection.getFault()))
if (Objects.equals(this, axleSection.getFault())) {
return false;
}
VirtualRealitySectionAxleCounter virtualAxleCounter = axleSection.getVirtualAxleCounter();
VirtualRealitySectionAxleCounter.Fault.FAULT.apply(virtualAxleCounter);
axleSection.setFault(this);
@ -1409,8 +1437,9 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Section axleSection = ((Section) device).getAxleCounterSection();
if (this.equals(axleSection.getFault()))
if (this.equals(axleSection.getFault())) {
return false;
}
axleSection.setFault(this);
axleSection.loseStatus();
return true;
@ -1430,10 +1459,12 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Section section = (Section) device;
if (!CollectionUtils.isEmpty(section.getLogicList()))
if (!CollectionUtils.isEmpty(section.getLogicList())) {
return false;
if (this.equals(section.getFault()))
}
if (this.equals(section.getFault())) {
return false;
}
Section axleSection = section.getAxleCounterSection();
section.setFault(this);
VirtualRealitySectionAxleCounter.Fault.FAULT.apply(axleSection.getVirtualAxleCounter());
@ -1448,7 +1479,8 @@ public class Section extends DelayUnlockDevice {
section.setFault(null);
section.setCtOccupied(false);
if (section.isSwitchTrack()) {
section.getRelSwitch().getAllSections().forEach(section1 -> section1.setCtOccupied(false));
section.getRelSwitch().getAllSections()
.forEach(section1 -> section1.setCtOccupied(false));
}
Section axleSection = section.getAxleCounterSection();
VirtualRealitySectionAxleCounter.Fault.FAULT.fix(axleSection.getVirtualAxleCounter());
@ -1460,8 +1492,9 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Section axleSection = ((Section) device).getAxleCounterSection();
if (this.equals(axleSection.getFault()))
if (this.equals(axleSection.getFault())) {
return false;
}
VirtualRealitySectionAxleCounter.Fault.FAULT.apply(axleSection.getVirtualAxleCounter());
axleSection.setFault(this);
return true;
@ -1481,8 +1514,9 @@ public class Section extends DelayUnlockDevice {
@Override
public boolean apply(MayOutOfOrderDevice device) {
Section section = (Section) device;
if (this.equals(section.getFault()))
if (this.equals(section.getFault())) {
return false;
}
section.setFault(this);
section.setFaultLock(true);
return true;

View File

@ -6,7 +6,11 @@ import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.TrainTBControl;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
@ -14,15 +18,14 @@ import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.vo.client.operation.DriveParamVO;
import club.joylink.rtss.vo.ws.TrainPosition;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
/**
* 虚拟真实列车
@ -1188,6 +1191,10 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
return robotDriveParam.needStop();
}
public boolean isRobotStopControl() {
return robotDriveParam.isStopControl();
}
@Getter
@Setter
public static class Door extends ControllableVrDevice<Door.Operation> {

View File

@ -1,16 +1,15 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Getter
@Setter
@NoArgsConstructor
public class SrTrainControlParam {
public class SandTableTrainControlParam {
@NotBlank(message = "车组号不能为空")
private String groupNumber;

View File

@ -0,0 +1,70 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp;
import club.joylink.rtss.constants.ProjectCode;
import club.joylink.rtss.dao.MapDataDAO;
import club.joylink.rtss.entity.MapDataExample;
import club.joylink.rtss.entity.MapDataWithBLOBs;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service.SrTrainServiceImpl;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service.ThailandTrainServiceImpl;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.map.MapLogicDataNewVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/sandTable")
public class SandTableTrainController {
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private ThailandTrainServiceImpl thailandTrainService;
@Autowired
private SrTrainServiceImpl srTrainService;
@PutMapping("/{simulationId}/control")
public void control(@PathVariable String simulationId, String groupNumber, boolean right,
int speed) {
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
switch (simulation.getProject()) {
case ProjectCode.THAILAND_SANDBOX:
thailandTrainService.controlTrain(simulationId, groupNumber, right, speed);
break;
case ProjectCode.SR_SANDBOX:
srTrainService.controlTrain(simulationId, groupNumber, right, speed);
break;
default:
}
}
@Autowired
private MapDataDAO mapDataDAO;
@PutMapping("/handle")
public void handle() {
MapDataExample example = new MapDataExample();
example.setOrderByClause("id desc");
example.setLimit(1);
MapDataWithBLOBs data = mapDataDAO.selectByExampleWithBLOBs(example).get(0);
MapLogicDataNewVO logicDataNewVO = JsonUtils.read(data.getLogicData(), MapLogicDataNewVO.class);
logicDataNewVO.getRouteList().stream()
.filter(route -> route.getStartSignalCode().equals("X542") || route.getStartSignalCode()
.equals("X11357")
|| route.getStartSignalCode().equals("X47820") || route.getStartSignalCode()
.equals("X4371")
|| route.getStartSignalCode().equals("X21134") || route.getStartSignalCode()
.equals("X99402")
|| route.getStartSignalCode().equals("X2670") || route.getStartSignalCode()
.equals("X49087"))
.forEach(route -> {
route.setSignalAspect(3);
});
data.setLogicData(JsonUtils.writeValueAsString(logicDataNewVO));
mapDataDAO.updateByPrimaryKeyWithBLOBs(data);
}
}

View File

@ -10,6 +10,9 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.InetSocketAddress;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,14 +21,10 @@ import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentLinkedQueue;
@Component
@Slf4j
public class UDPClient implements ApplicationRunner {
@Autowired
private UDPConfig udpConfig;
@ -59,14 +58,18 @@ public class UDPClient implements ApplicationRunner {
}
public void write(InetSocketAddress addr, byte[] msg) {
if (msg != null) {
msgQueue.add(new Msg(addr, msg));
System.out.println(LocalDateTime.now());
}
}
@Scheduled(fixedRate = 10)
public void send() {
Msg msg = msgQueue.poll();
if (msg == null)
if (msg == null) {
return;
}
InetSocketAddress addr = msg.getAddr();
byte[] data = msg.getData();
if (channel != null && channel.isWritable() && addr != null && data != null) {
@ -78,6 +81,7 @@ public class UDPClient implements ApplicationRunner {
@Getter
class Msg {
private InetSocketAddress addr;
private byte[] data;

View File

@ -5,12 +5,11 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDevice
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.UDPLowConfigVO;
import lombok.Getter;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import lombok.Getter;
import org.springframework.util.StringUtils;
public class UDPLowConfig extends RealDeviceConfig {
@Getter
@ -53,4 +52,8 @@ public class UDPLowConfig extends RealDeviceConfig {
public String findDeviceCode() {
return null;
}
public String getName() {
return configVO == null ? null : configVO.getName();
}
}

View File

@ -5,6 +5,10 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDevice
import io.netty.buffer.ByteBuf;
public interface UDPRealDeviceService {
default boolean isMatch(UDPLowConfig udpLowConfig) {
return true;
}
boolean isMatch(RealDeviceConfig realDevice);
void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice);

View File

@ -3,23 +3,28 @@ package club.joylink.rtss.simulation.cbtc.device.real.udp;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.PlcGateway;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.event.SimulationResetEvent;
import io.netty.buffer.ByteBuf;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
public class UDPRealDeviceThread {
/**
* 真是设备逻辑执行频率
* <p>
* 因沙盘对延迟要求较高所以将频率提高
*/
public static final int RATE = 100;
@Autowired
private UDPRealDeviceServiceManager udpRealDeviceServiceManager;
@ -30,11 +35,14 @@ public class UDPRealDeviceThread {
public void simulationReset(SimulationResetEvent event) {
Simulation simulation = event.getSimulation();
List<RealDeviceConfig> realDeviceList = simulation.getRealDeviceList();
if (CollectionUtils.isEmpty(realDeviceList))
if (CollectionUtils.isEmpty(realDeviceList)) {
return;
UDPLowConfig udpConfig = (UDPLowConfig) simulation.queryOneRealDevice(ProjectDeviceType.UDP_LOW);
if (udpConfig == null)
}
UDPLowConfig udpConfig = (UDPLowConfig) simulation.queryOneRealDevice(
ProjectDeviceType.UDP_LOW);
if (udpConfig == null) {
return;
}
for (RealDeviceConfig realDevice : realDeviceList) {
if (realDevice instanceof PlcGateway) {
continue;
@ -49,36 +57,40 @@ public class UDPRealDeviceThread {
public void run(Simulation simulation) {
List<RealDeviceConfig> realDeviceList = simulation.getRealDeviceList();
if (CollectionUtils.isEmpty(realDeviceList))
if (CollectionUtils.isEmpty(realDeviceList)) {
return;
}
List<UDPRealDeviceService> serviceList = udpRealDeviceServiceManager.getServiceList();
if (CollectionUtils.isEmpty(serviceList))
if (CollectionUtils.isEmpty(serviceList)) {
return;
UDPLowConfig udpLowConfig = null;
for (RealDeviceConfig realDeviceConfig : realDeviceList) {
if (ProjectDeviceType.UDP_LOW.equals(realDeviceConfig.getDeviceType())) {
udpLowConfig = (UDPLowConfig) realDeviceConfig;
break;
}
}
realDeviceList.stream()
.filter(
realDeviceConfig -> ProjectDeviceType.UDP_LOW.equals(realDeviceConfig.getDeviceType()))
.map(realDeviceConfig -> (UDPLowConfig) realDeviceConfig)
.forEach(udpLowConfig -> {
for (RealDeviceConfig config : realDeviceList) {
for (UDPRealDeviceService service : serviceList) {
if (service.isMatch(config) && config.getMapElement() != null) {
if (service.isMatch(udpLowConfig) && service.isMatch(config)
&& config.getMapElement() != null) {
service.run(simulation, udpLowConfig, config);
}
}
}
});
}
public void handleData(String ip, int port, ByteBuf data) {
List<Simulation> simulations = groupSimulationService.querySimulations();
for (Simulation simulation : simulations) {
List<RealDeviceConfig> realDeviceList = simulation.getRealDeviceList();
if (CollectionUtils.isEmpty(realDeviceList))
if (CollectionUtils.isEmpty(realDeviceList)) {
continue;
UDPClientConfig udpClientConfig = (UDPClientConfig) simulation.queryOneRealDevice(ProjectDeviceType.UDP_CLIENT);
if (udpClientConfig != null && Objects.equals(ip, udpClientConfig.getConfigVO().getIp())
&& Objects.equals(port, udpClientConfig.getConfigVO().getPort())) {
}
UDPClientConfig udpClientConfig = (UDPClientConfig) simulation.queryOneRealDevice(
ProjectDeviceType.UDP_CLIENT);
if (udpClientConfig != null /*&& Objects.equals(ip, udpClientConfig.getConfigVO().getIp())
&& Objects.equals(port, udpClientConfig.getConfigVO().getPort())*/) {
for (UDPRealDeviceService udpRealDeviceService : this.udpRealDeviceServiceManager.getServiceList()) {
if (udpRealDeviceService.isMatch(udpClientConfig)) {
udpRealDeviceService.handle(simulation, data);
@ -89,7 +101,6 @@ public class UDPRealDeviceThread {
}
public void addJobs(Simulation simulation) {
simulation.addFixedRateJob(Simulation.JobName.udpRealDevice,
() -> this.run(simulation), SimulationConstants.VRD_LOOP_RATE);
simulation.addFixedRateJob(Simulation.JobName.udpRealDevice, () -> this.run(simulation), RATE);
}
}

View File

@ -1,22 +0,0 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service.SrTrainServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/sr")
public class SrTrainController {
@Autowired
private SrTrainServiceImpl srTrainService;
// @PutMapping("/{simulationId}/control")
// public void control(@PathVariable String simulationId, @RequestBody @Validated SrTrainControlParam controlParam) {
// srTrainService.control(simulationId, controlParam.getGroupNumber(), controlParam.getRight(), controlParam.getSpeed());
// }
@PutMapping("/{simulationId}/control")
public void control(@PathVariable String simulationId, String groupNumber, boolean right, int speed) {
srTrainService.controlTrain(simulationId, groupNumber, right, speed);
}
}

View File

@ -15,10 +15,6 @@ import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrTrainConfig;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
@ -26,19 +22,23 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class SrSectionServiceImpl implements UDPRealDeviceService {
@Autowired
private SrTrainServiceImpl srTrainService;
public static final String PROJECT_CODE = "SR_SANDBOX";
@Autowired
private MaService maService;
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof UDPClientConfig;
return realDevice instanceof UDPClientConfig && PROJECT_CODE
.equals(realDevice.getProject());
}
@Override
@ -54,22 +54,26 @@ public class SrSectionServiceImpl implements UDPRealDeviceService {
public void handle(Simulation simulation, ByteBuf msg) {
//检查数据
byte[] data = new byte[msg.readableBytes()];
if (data.length < 4)
if (data.length < 4) {
return;
}
msg.readBytes(data);
if (Byte.toUnsignedInt(data[1]) != 137) {
return;
}
//处理数据
Map<String, SrSectionConfig> configMap = simulation.queryAllRealDevice(ProjectDeviceType.SECTION).stream()
Map<String, SrSectionConfig> configMap = simulation.queryAllRealDevice(
ProjectDeviceType.SECTION).stream()
.map(config -> (SrSectionConfig) config)
.collect(Collectors.toMap(config -> config.getConfigVO().getSandboxCode(), Function.identity()));
.collect(
Collectors.toMap(config -> config.getConfigVO().getSandboxCode(), Function.identity()));
for (int i = 3, dataLength = data.length; i < dataLength; i += 2) {
int code = Byte.toUnsignedInt(data[i - 1]);
String key = String.valueOf(code);
SrSectionConfig config = configMap.get(key);
if (config == null)
if (config == null) {
continue;
}
VirtualRealitySectionAxleCounter axle = (VirtualRealitySectionAxleCounter) config.getMapElement();
if (axle != null) {
int n = Byte.toUnsignedInt(data[i]);
@ -98,14 +102,20 @@ public class SrSectionServiceImpl implements UDPRealDeviceService {
Section headSection = train.getHeadPosition().getSection();
SrTrainConfig config = (SrTrainConfig) train.getRealDevice();
if (!Objects.equals(headSection, config.getHeadSection())) //列车无需在该站台停车
{
continue;
}
if (config.getTimeOfStop() != null) //已经设置过停车时间
{
continue;
if (!headSection.isFunctionTrack())
}
if (!headSection.isFunctionTrack()) {
continue;
}
VirtualRealitySectionAxleCounter headAxle = headSection.findAxle();
if (headAxle == null)
if (headAxle == null) {
continue;
}
SrSectionConfig sectionConfig = (SrSectionConfig) headAxle.getRealDevice();
//设置延时停车时间
long m = 1000000000;
@ -118,11 +128,13 @@ public class SrSectionServiceImpl implements UDPRealDeviceService {
//以前一个区段无占用作为停车标志的区段
boolean right = train.isRight();
Section behindSection = headSection.getNextRunningSectionOf(!right);
if (behindSection == null)
if (behindSection == null) {
continue;
}
VirtualRealitySectionAxleCounter behindAxle = behindSection.findAxle();
if (behindAxle == null)
if (behindAxle == null) {
continue;
}
if (!behindAxle.isOccupy()) { //车头后方区段所属计轴无占用状态
nanos = 0;
if (sectionConfig.getConfigVO().getTailDelayTime() != null) {
@ -159,7 +171,8 @@ public class SrSectionServiceImpl implements UDPRealDeviceService {
/**
* 检查是否有right向的列车可以更新车头位置
*/
private void check4UpdateHeadPosition(Simulation simulation, Section occupiedSection, boolean right) {
private void check4UpdateHeadPosition(Simulation simulation, Section occupiedSection,
boolean right) {
Section section = occupiedSection.getNextRunningSectionOf(!right); //找反向的区段
if (section != null) {
for (VirtualRealityTrain train : simulation.getRepository().getOnlineTrainList()) {
@ -175,10 +188,13 @@ public class SrSectionServiceImpl implements UDPRealDeviceService {
SectionPosition stopPointPosition;
if (occupiedSection.isFunctionTrack()) {
stopPointPosition = occupiedSection.buildStopPointPosition(right);
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition, !right, 1, true);
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition,
!right, 1, true);
} else {
stopPointPosition = new SectionPosition(occupiedSection, occupiedSection.getEndOffsetByDirection(right));
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition, !right, 3, true);
stopPointPosition = new SectionPosition(occupiedSection,
occupiedSection.getEndOffsetByDirection(right));
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition,
!right, 3, true);
}
train.setHeadPosition(headPosition); //更新位置
if (occupiedSection.isFunctionTrack()) { //功能轨可能需要停车

View File

@ -0,0 +1,32 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandSectionConfigVO;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
@Getter
public class ThailandSectionConfig extends RealDeviceConfig {
private ThailandSectionConfigVO configVO;
/**
* 连续无占用次数
*/
@Setter
private int timesOfRelease;
public ThailandSectionConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {
this.configVO = JsonUtils.read(projectDevice.getConfig(), ThailandSectionConfigVO.class);
}
}
@Override
public String findDeviceCode() {
return configVO.findDeviceCode();
}
}

View File

@ -0,0 +1,30 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config;
import club.joylink.rtss.simulation.cbtc.constant.SignalAspect;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandSignalConfigVO;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
@Getter
public class ThailandSignalConfig extends RealDeviceConfig {
private ThailandSignalConfigVO configVO;
@Setter
private SignalAspect aspect;
public ThailandSignalConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {
this.configVO = JsonUtils.read(projectDevice.getConfig(), ThailandSignalConfigVO.class);
}
}
@Override
public String findDeviceCode() {
return configVO.findDeviceCode();
}
}

View File

@ -0,0 +1,29 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config;
import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandSwitchConfigVO;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
@Getter
public class ThailandSwitchConfig extends RealDeviceConfig {
private ThailandSwitchConfigVO configVO;
@Setter
private SwitchIndication p;
public ThailandSwitchConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {
this.configVO = JsonUtils.read(projectDevice.getConfig(), ThailandSwitchConfigVO.class);
}
}
@Override
public String findDeviceCode() {
return configVO.findDeviceCode();
}
}

View File

@ -0,0 +1,58 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.project.thailand.ThailandTrainConfigVO;
import java.time.LocalDateTime;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
@Getter
public class ThailandTrainConfig extends RealDeviceConfig {
private ThailandTrainConfigVO configVO;
@Setter
private Integer gear;
/**
* 列车需要在这个轨道停车
*/
private Section headSection;
/**
* 列车抵达停车点的时间
* <p>
* 当走到这个时间时需要将列车的车头位置更新至当前区段的停车点
* <p>
* 上述停车点指代一切可能需要停车的位置比如站台轨的停车点信号机2m前轨道尽头10m前
*/
@Setter
private LocalDateTime timeOfArriveStopPoint;
/**
* 人为驾驶的档位
*/
@Setter
private Integer manualGear;
public void updateHeadSection(Section headSection) {
this.headSection = headSection;
this.timeOfArriveStopPoint = null;
}
public ThailandTrainConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {
this.configVO = JsonUtils.read(projectDevice.getConfig(), ThailandTrainConfigVO.class);
}
}
@Override
public String findDeviceCode() {
return configVO.findDeviceCode();
}
}

View File

@ -0,0 +1,85 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service;
import club.joylink.rtss.constants.ProjectCode;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPClientConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSectionConfig;
import io.netty.buffer.ByteBuf;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ThailandSectionServiceImpl implements UDPRealDeviceService {
@Autowired
private MaService maService;
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof UDPClientConfig && ProjectCode.THAILAND_SANDBOX
.equals(realDevice.getProject());
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
//沙盘不需要停太长时间
simulation.getRepository().getStandList().forEach(stand -> stand.setParkingTime(15));
}
@Override
public void handle(Simulation simulation, ByteBuf msg) {
//检查数据
byte[] data = new byte[msg.readableBytes()];
if (data.length < 4) {
return;
}
msg.readBytes(data);
if (Byte.toUnsignedInt(data[1]) != 137) {
return;
}
//处理数据
Map<String, ThailandSectionConfig> configMap = simulation.queryAllRealDevice(
ProjectDeviceType.SECTION).stream()
.map(config -> (ThailandSectionConfig) config)
.collect(
Collectors.toMap(config -> config.getConfigVO().getSandboxCode(), Function.identity()));
for (int i = 3, dataLength = data.length; i < dataLength; i += 2) {
int code = Byte.toUnsignedInt(data[i - 1]);
String key = String.valueOf(code);
ThailandSectionConfig config = configMap.get(key);
if (config == null) {
continue;
}
VirtualRealitySectionAxleCounter axle = (VirtualRealitySectionAxleCounter) config.getMapElement();
if (axle != null) {
int n = Byte.toUnsignedInt(data[i]);
if (n == 170) {
config.setTimesOfRelease(0);
axle.setOccupy(true);
} else if (n == 85) {
config.setTimesOfRelease(config.getTimesOfRelease() + 1);
if (config.getTimesOfRelease() > 2) { //连续3次该计轴都是无占用状态才视为确实无占用
config.setTimesOfRelease(0);
axle.clear();
}
}
}
}
}
}

View File

@ -0,0 +1,136 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SignalAspect;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPClient;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSignalConfig;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ThailandSignalServiceImpl implements UDPRealDeviceService {
public static final String NAME = "SIGNAL";
@Autowired
private UDPClient udpClient;
@Override
public boolean isMatch(UDPLowConfig udpLowConfig) {
return NAME.equals(udpLowConfig.getName());
}
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof ThailandSignalConfig;
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
ThailandSignalConfig config = (ThailandSignalConfig) realDevice;
//控制vr设备
VirtualRealitySignal vrSignal = (VirtualRealitySignal) realDevice.getMapElement();
SignalAspect aspect = vrSignal.getAspect();
SignalAspect command = vrSignal.getCommand();
if (Objects.equals(aspect, command)) {
return;
}
if (vrSignal.isTurning()) {
vrSignal.turning(SimulationConstants.VRD_LOOP_RATE);
}
//控制沙盘设备
aspect = vrSignal.getAspect();
if (aspect == null || udpLowConfig == null || Objects.equals(aspect, config.getAspect())) {
return;
}
byte[] data = buildData(aspect, config);
if (data == null)
return;
udpClient.write(udpLowConfig.getAddr(), data);
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@Override
public void handle(Simulation simulation, ByteBuf msg) {
}
private byte[] buildData(SignalAspect aspect, ThailandSignalConfig config) {
if (aspect == null)
return null;
config.setAspect(aspect);
byte[] data = new byte[5];
data[1] = (byte) 203;
data[2] = (byte) Integer.parseInt(config.getConfigVO().getSandboxCode());
switch (aspect) {
case No:
case R:
case RF:
data[3] = (byte) 0;
break;
case G:
case GF:
data[3] = (byte) 1;
break;
case Y:
case YF:
data[3] = (byte) 2;
break;
case W:
case WF:
data[3] = (byte) 6;
break;
case B:
data[3] = (byte) 7;
break;
case GG:
data[3] = (byte) 5;
break;
case GY:
data[3] = (byte) 4;
break;
case YY:
data[3] = (byte) 3;
break;
case RY:
case RW:
return null;
default:
return null;
}
switch (aspect) {
case No:
case R:
case G:
case Y:
case W:
case B:
case RY:
case RW:
case GG:
case GY:
case YY:
data[4] = (byte) 0;
break;
case RF:
case YF:
case GF:
case WF:
data[4] = (byte) 1;
break;
default:
throw new IllegalStateException("Unexpected value: " + aspect);
}
return data;
}
}

View File

@ -0,0 +1,85 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SwitchIndication;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPClient;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSwitchConfig;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ThailandSwitchServiceImpl implements UDPRealDeviceService {
public static final String NAME = "SWITCH-TRAIN";
@Autowired
private UDPClient udpClient;
@Override
public boolean isMatch(UDPLowConfig udpLowConfig) {
return NAME.equals(udpLowConfig.getName());
}
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof ThailandSwitchConfig;
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
ThailandSwitchConfig config = (ThailandSwitchConfig) realDevice;
//控制vr设备
VirtualRealitySwitch vrSwitch = (VirtualRealitySwitch) realDevice.getMapElement();
if (vrSwitch.isTurning()) {
vrSwitch.turning(SimulationConstants.VRD_LOOP_RATE);
}
//控制沙盘设备
SwitchIndication p = vrSwitch.getP();
if (p == null || udpLowConfig == null || Objects.equals(p, config.getP())) {
return;
}
byte[] data = buildData(p, config);
if (data == null)
return;
udpClient.write(udpLowConfig.getAddr(), data);
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@Override
public void handle(Simulation simulation, ByteBuf msg) {
}
private byte[] buildData(SwitchIndication p, ThailandSwitchConfig config) {
if (p == null)
return null;
config.setP(p);
byte[] data = new byte[4];
data[1] = (byte) 208;
data[2] = (byte) Integer.parseInt(config.getConfigVO().getSandboxCode());
switch (p) {
case N:
data[3] = (byte) 0;
break;
case R:
data[3] = (byte) 1;
break;
case NO:
case EX:
return null;
default:
throw new IllegalStateException("Unexpected value: " + p);
}
return data;
}
}

View File

@ -0,0 +1,303 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.service;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainLoadService;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySectionAxleCounter;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPClient;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceService;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandTrainConfig;
import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService;
import club.joylink.rtss.vo.client.project.thailand.ThailandSectionConfigVO;
import club.joylink.rtss.vo.map.graph.MapSectionNewVO;
import io.netty.buffer.ByteBuf;
import java.time.LocalDateTime;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ThailandTrainServiceImpl implements UDPRealDeviceService {
public static final String NAME = ThailandSwitchServiceImpl.NAME;
@Autowired
private UDPClient udpClient;
@Autowired
private ATPService atpService;
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private AtsTrainLoadService atsTrainLoadService;
@Override
public boolean isMatch(UDPLowConfig udpLowConfig) {
return NAME.equals(udpLowConfig.getName());
}
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof ThailandTrainConfig;
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
ThailandTrainConfig config = (ThailandTrainConfig) realDevice;
//控制vr设备
VirtualRealityTrain train = (VirtualRealityTrain) config.getMapElement();
SimulationDataRepository repository = simulation.getRepository();
String groupNumber = train.getGroupNumber();
if (repository.isVrTrainOnline(groupNumber)) {
removeVrTrainIfNotSupervised(repository, groupNumber);
if (!train.isRobotStopControl() && config.getManualGear() != null) {
config.setManualGear(null);
config.setGear(null);
}
updateTrainPosition(simulation, train, config);
updateTrainSpeed(simulation, train, config);
//减少关门后的延迟发车时间
if (train.getDelayTime() > 3000) {
train.setDelayTime(3000);
}
//控制沙盘设备
byte[] data = buildData(train, config);
udpClient.write(udpLowConfig.getAddr(), data);
} else {
addVrTrainIfSupervised(simulation, repository, groupNumber);
}
}
/**
* 更新列车位置
* <p>
* 1.如果列车占压新的区段则先将列车车头位置更新至该区段的停车点之前保证列车可以继续运行 2.根据区段的配置信息决定列车何时将车头位置更新至停车点
* 3.根据上一步设置的停车时间判断执行更新车头位置至停车点逻辑触发列车停车逻辑
*/
private void updateTrainPosition(Simulation simulation, VirtualRealityTrain train,
ThailandTrainConfig config) {
//判断列车是否到达新区段
boolean right = train.isRight(); //车头方向
Section headSection = train.getHeadPosition().getSection(); //车头区段
Section previousSection = null; //车头方向的上一个区段
Section nextSection = headSection.getNextRunningSectionOf(right); //车头方向的下一个区段
ThailandSectionConfig sectionConfig = (ThailandSectionConfig) headSection.findAxle()
.getRealDevice(); //车头区段的配置
if (nextSection != null) {
VirtualRealitySectionAxleCounter nextAxle = nextSection.findAxle();
if (nextAxle.isOccupy()) {
train.setHeadPosition(
new SectionPosition(nextSection, right ? 0 : nextSection.getMaxOffset()));
config.setTimeOfArriveStopPoint(null);
sectionConfig = (ThailandSectionConfig) nextAxle.getRealDevice();
//更新变量
previousSection = headSection;
headSection = train.getHeadPosition().getSection();
nextSection = null;
}
}
//根据区段的配置信息设置车头位置更新至停车点的时间
// fill(headSection, sectionConfig.getConfigVO()); 仅用于调试
LocalDateTime now = LocalDateTime.now();
if (config.getTimeOfArriveStopPoint() == null) {
int rate = 1000000000; //秒到纳秒的换算比例
Long delayOfNano = null; //延迟时间的纳秒表示
if (sectionConfig.getConfigVO().getHeadDelayTime() != null) { //车头占压延时停车
delayOfNano = (long) (sectionConfig.getConfigVO().getHeadDelayTime() * rate);
} else if (sectionConfig.getConfigVO().getTailDelayTime() != null) { //车尾出清延时停车
if (previousSection == null) {
previousSection = headSection.getNextRunningSectionOf(!right);
}
if (previousSection != null && !previousSection.isOccupied()) {
delayOfNano = (long) (sectionConfig.getConfigVO().getTailDelayTime() * rate);
}
} else { //未设置则认为车头占压即刻停车
delayOfNano = 0L;
}
if (delayOfNano != null) {
config.setTimeOfArriveStopPoint(now.plusNanos(delayOfNano));
}
}
//根据当前时间判断更新车头位置至停车点
LocalDateTime timeOfArriveStopPoint = config.getTimeOfArriveStopPoint();
if (timeOfArriveStopPoint != null && !now.isBefore(timeOfArriveStopPoint)) {
SectionPosition stopPosition = train.getRobotDriveParam().getStopPosition();
if (stopPosition != null && stopPosition.getSection().equals(headSection)) {
train.setHeadPosition(stopPosition);
} else if (stopPosition == null || !stopPosition.getSection().equals(headSection)) {
float offset = right ? headSection.getMaxOffset() : 0;
train.setHeadPosition(new SectionPosition(headSection, offset));
}
}
}
/**
* 如果有监控添加一个vrTrain
*/
private void addVrTrainIfSupervised(Simulation simulation, SimulationDataRepository repository,
String groupNumber) {
TrainInfo trainInfo = repository.findSupervisedTrainByGroup(groupNumber);
if (trainInfo != null) {
Section section = repository.getByCode(trainInfo.getSection(), Section.class);
if (section.isSwitchAxleCounterSection()) {
section = section.getLogicList().get(0).getRelSwitch().getA();
}
atsTrainLoadService.loadSpareTrain(simulation, groupNumber, section.getCode(), false);
}
}
/**
* 移除vrTrain如果没有被监控
*/
private void removeVrTrainIfNotSupervised(SimulationDataRepository repository,
String groupNumber) {
TrainInfo trainInfo = repository.findSupervisedTrainByGroup(groupNumber);
if (trainInfo == null) {
repository.deleteOnlineTrain(groupNumber);
}
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
ThailandTrainConfig config = (ThailandTrainConfig) realDevice;
//控制vr设备
VirtualRealityTrain train = (VirtualRealityTrain) config.getMapElement();
//控制沙盘设备
byte[] data = buildData(train, config);
udpClient.write(udpLowConfig.getAddr(), data);
//清除状态
config.updateHeadSection(null);
}
@Override
public void handle(Simulation simulation, ByteBuf msg) {
}
private void updateTrainSpeed(Simulation simulation, VirtualRealityTrain train,
ThailandTrainConfig config) {
//更新速度
if (config.getManualGear() != null) {
return;
}
if (train.getFk() > train.getFb()) {
train.setSpeed(10 / 3.6f);
} else if (train.getFb() > train.getFk()) {
train.setSpeed(0);
}
}
private byte[] buildData(VirtualRealityTrain train, ThailandTrainConfig config) {
int gear;
if (train.isStop()) {
gear = 0;
} else {
float speedKmPh = train.getSpeedKmPh();
if (train.isStop()) {
gear = 0;
} else {
gear = (int) Math.ceil(speedKmPh / 10);
gear = Math.max(1, gear);
}
if (train.isRight()) { //档位1-5是正向6-10是反向
gear += 5;
}
}
if (Objects.equals(config.getGear(), gear)) {
return null;
}
config.setGear(gear);
byte[] data = new byte[4];
data[1] = (byte) 1;
data[2] = (byte) Integer.parseInt(config.getConfigVO().getSandboxCode());
data[3] = (byte) gear;
return data;
}
/**
* 此方法用于调试调试完成后方法内的数据请保存到项目设备配置{@link club.joylink.rtss.services.project.DeviceServiceImpl#thailandFillTime(ThailandSectionConfigVO, MapSectionNewVO)}
*/
public void fill(Section section, ThailandSectionConfigVO configVO) {
Float headDelayTime = null;
Float tailDelayTime = null;
if (section.isStandTrack()) { //站台轨默认为车尾出清立即停车
headDelayTime = 5f;
}
switch (section.getCode()) {
case "T233": //X302G
headDelayTime = 7f;
break;
case "T232": //X303G
headDelayTime = 7f;
break;
case "T231": //X304G
headDelayTime = 5.5f;
break;
case "T175": //4站-IIG
headDelayTime = 5.5f;
break;
case "T121": //4站-IIG
headDelayTime = 5.2f;
break;
case "T77": //4站-IIG
headDelayTime = 6f;
break;
case "T145": //QX04
tailDelayTime = 0f;
break;
case "T146": //QS04
tailDelayTime = 0f;
break;
case "T104": //QX03
tailDelayTime = 0f;
break;
case "T105": //QS03
tailDelayTime = 0f;
break;
case "T62": //QX02
tailDelayTime = 0f;
break;
case "T63": //QS02
tailDelayTime = 0f;
break;
}
configVO.setHeadDelayTime(headDelayTime);
configVO.setTailDelayTime(tailDelayTime);
}
public void controlTrain(String simulationId, String groupNumber, boolean right, int speed) {
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber);
ThailandTrainConfig config = (ThailandTrainConfig) train.getRealDevice();
if (right != train.isRight()) { //调头
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertTrue(train.getSpeed() == 0, "换端需先停车");
atpService.turnDirectionImmediately(train);
}
train.setRobotTargetPosition(null); //终止机器人司机驾驶
//加减速
if (train.isEB()) {
return;
}
atpService.changeGear(train, VirtualRealityTrain.Handwheel.MANUAL);
int manualGear = speed / 10;
config.setManualGear(manualGear);
train.setSpeed(speed / 3.6f);
train.getRobotDriveParam().stopControl();
byte[] data = buildData(train, config);
UDPLowConfig udpLowConfig = (UDPLowConfig) simulation.queryOneRealDevice(
ProjectDeviceType.UDP_LOW);
udpClient.write(udpLowConfig.getAddr(), data);
}
}

View File

@ -9,14 +9,18 @@ import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* 目标速度-距离曲线
*/
@ -315,75 +319,6 @@ public class SpeedCurve {
return speedCurve;
}
// public static SpeedCurve buildTargetSpeedCurve(SectionPosition headPosition,
// SectionPosition tailPosition, boolean right,
// float totalLen, float v0, float recommendedSpeedMax) {
// if (totalLen <= 0) {
// return SpeedCurve.ZERO;
// }
// Section base = tailPosition.getSection();
// Section headSection = headPosition.getSection();
// float limitSpeed = recommendedSpeedMax;
// boolean limit = false;
// if (Objects.nonNull(tailPosition.getSection().getNeedLimitSpeed())) {
// limitSpeed = Math.min(limitSpeed, tailPosition.getSection().getNeedLimitSpeed() * 0.9f);
// limit = true;
// } else if (Objects.nonNull(headPosition.getSection().getNeedLimitSpeed())) {
// limitSpeed = Math.min(limitSpeed, headPosition.getSection().getNeedLimitSpeed() * 0.9f);
// limit = true;
// }
// SectionPosition endPosition = null;
// boolean ahead = false;
// float vt = 0;
// int count = 0;
// if (!limit) {
// // 无限速找前方限速
// while (Objects.nonNull(base) && count < 20) {
// ++count;
// Float limitSpeed1 = base.getNeedLimitSpeed();
// if (limitSpeed1 == null && !CollectionUtils.isEmpty(base.getLogicList())) { //兼容逻辑区段设置限速
// float distanceBetweenLogicAndPhysical = 0; //逻辑区段距物理区段端点的距离同向端点
// for (Section section : base.getLogicList()) {
// limitSpeed1 = section.getNeedLimitSpeed();
// if (limitSpeed1 != null) {
// float offsetOfLogicSectionOnPhysicalSection = distanceBetweenLogicAndPhysical + (right ? section.getLen() : 0); //逻辑区段的端点在物理区段上的偏移量
// SectionPosition logicSectionPosition = new SectionPosition(base, offsetOfLogicSectionOnPhysicalSection);
// if (logicSectionPosition.isAheadOf(tailPosition, right)) {
// break;
// }
// }
// distanceBetweenLogicAndPhysical += section.getLen();
// }
// }
// if (Objects.nonNull(limitSpeed1)) {
// if (ahead) {
// // 车头前方
// vt = Math.min(limitSpeed, limitSpeed1 * 0.9f);
// endPosition = new SectionPosition(base, right ? 0 : base.getLen());
// break;
// } else {
// limitSpeed = Math.min(limitSpeed, limitSpeed1 * 0.9f);
// }
// }
// if (Objects.equals(base, headSection)) {
// ahead = true;
// }
// base = base.getNextRunningSectionOf(right);
// }
// }
// SpeedCurve normalSpeedCurve = buildTargetSpeedCurve(totalLen, v0, 0, limitSpeed);
// if (endPosition != null) {
// Float distance = CalculateService.calculateDistance(headPosition, endPosition, right);
// if (distance != null && distance < totalLen) {
// SpeedCurve limitSpeedCurve = buildTargetSpeedCurve(distance, v0, vt, limitSpeed);
// float normalStartSpeed = normalSpeedCurve.getSpeedOf(normalSpeedCurve.getTotalDistance());
// float limitStartSpeed = limitSpeedCurve.getSpeedOf(limitSpeedCurve.getTotalDistance());
// return normalStartSpeed < limitStartSpeed ? normalSpeedCurve : limitSpeedCurve;
// }
// }
// return normalSpeedCurve;
// }
/**
* 构建目标速度曲线
*

View File

@ -1,5 +1,7 @@
package club.joylink.rtss.simulation.cbtc.robot;
import static club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain.ConfirmationMessage.Confirm_Release_Speed;
import club.joylink.rtss.services.psl.IVirtualRealityPslService;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.ATS.operation.AtsOperationDispatcher;
@ -15,32 +17,46 @@ import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.map.PSD;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.vo.ControlTransferReplyVO;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.*;
import club.joylink.rtss.simulation.cbtc.data.vr.StandParkedTrainActivity;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityPsl;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityScreenDoor;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.service.ATOService;
import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService;
import club.joylink.rtss.simulation.cbtc.training2.Training2;
import club.joylink.rtss.vo.client.operation.DriveParamVO;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
import static club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain.ConfirmationMessage.Confirm_Release_Speed;
/**
* 仿真机器人逻辑循环
*/
@Component
public class SimulationRobotService {
@Autowired
private AtsStationService atsStationService;
@ -117,8 +133,9 @@ public class SimulationRobotService {
if (!CollectionUtils.isEmpty(standList)) {
for (Stand stand : standList) {
PSD psd = stand.getPsd();
if (psd == null)
if (psd == null) {
continue;
}
VirtualRealityScreenDoor vrPsd = psd.getVirtualScreenDoor();
if (open) {
if (!vrPsd.isClose() || vrPsd.isSettingOpen()) {
@ -153,7 +170,8 @@ public class SimulationRobotService {
* 机器人司机逻辑循环
*/
private void robotDriverLogicLoop(Simulation simulation) {
List<SimulationMember> drivers = simulation.querySimulationMembersOfRole(SimulationMember.Type.DRIVER);
List<SimulationMember> drivers = simulation.querySimulationMembersOfRole(
SimulationMember.Type.DRIVER);
for (SimulationMember driver : drivers) {
// if (!driver.isRobot())
// continue;
@ -170,13 +188,17 @@ public class SimulationRobotService {
train.getRobotDriveParam().setStop(false);
} else {
if (!train.isInTheGear(VirtualRealityTrain.Handwheel.MANUAL)) { //确保当前在手动档位
CommandBO.Step step = CommandBO.buildGearChangeStep(train.getGroupNumber(), VirtualRealityTrain.Handwheel.MANUAL);
atsOperationDispatcher.execute(simulation, driver, step.getOperationType().name(), step.getOperationParams());
CommandBO.Step step = CommandBO.buildGearChangeStep(train.getGroupNumber(),
VirtualRealityTrain.Handwheel.MANUAL);
atsOperationDispatcher.execute(simulation, driver, step.getOperationType().name(),
step.getOperationParams());
}
doBreakMax(simulation, train);
}
} else if (train.isRobotNeedRun() && (train.isRMMode() || train.isNRMMode())) { //CM应当根据推荐速度驾驶待实现
Optional<SectionPosition> targetPositionOptional = calculateTargetPosition(simulation, train);
} else if (train.isRobotNeedRun() && (train.isRMMode()
|| train.isNRMMode())) { //CM应当根据推荐速度驾驶待实现
Optional<SectionPosition> targetPositionOptional = calculateTargetPosition(simulation,
train);
targetPositionOptional.ifPresent(tp -> robotDrive(simulation, driver, train, tp));
}
}
@ -185,7 +207,8 @@ public class SimulationRobotService {
/**
* 计算目标位置
*/
private Optional<SectionPosition> calculateTargetPosition(Simulation simulation, VirtualRealityTrain train) {
private Optional<SectionPosition> calculateTargetPosition(Simulation simulation,
VirtualRealityTrain train) {
DriveParamVO robotDriveParam = train.getRobotDriveParam();
if (train.isEB()) {
if (!robotDriveParam.isReleaseEB()) { //列车EB了且没有要求解除EB
@ -202,7 +225,8 @@ public class SimulationRobotService {
if (repository.getConfig().isRailway()) { //如果是大铁线路计划根据运行日志确定要停车的区段
TrainInfo trainInfo = repository.getSupervisedTrainByGroup(train.getGroupNumber());
CtcRepository ctcRepository = simulation.getCtcRepository();
Collection<CtcStationRunPlanLog> runPlans = ctcRepository.findRunPlans(trainInfo.getTripNumber());
Collection<CtcStationRunPlanLog> runPlans = ctcRepository.findRunPlans(
trainInfo.getTripNumber());
if (!CollectionUtils.isEmpty(runPlans)) {
for (CtcStationRunPlanLog runPlan : runPlans) {
CtcStationRunPlanLog.RunPlanItem arriveRunPlan = runPlan.getArriveRunPlan();
@ -226,7 +250,8 @@ public class SimulationRobotService {
Signal throughSignal = robotDriveParam.getThroughSignal();
SignalAspect throughAspect = robotDriveParam.getThroughSignalAspect();
Section section = headPosition.getSection();
if (throughSignal != null && !Objects.equals(section, throughSignal.getSection())) { //当车头与要越过的信号机不在同一区段
if (throughSignal != null && !Objects.equals(section,
throughSignal.getSection())) { //当车头与要越过的信号机不在同一区段
throughSignal = null;
throughAspect = null;
robotDriveParam.setThrough(DriveParamVO.NO);
@ -235,10 +260,12 @@ public class SimulationRobotService {
SectionPosition targetPosition = null;
for (int i = 0; i < 10; i++) {
if (section.isNormalStandTrack() && !section.equals(train.getParkSection())) { //正常站台轨且未在此处停过车
if (CollectionUtils.isEmpty(plannedParkingSections) || plannedParkingSections.contains(section)) {
if (CollectionUtils.isEmpty(plannedParkingSections) || plannedParkingSections.contains(
section)) {
SectionPosition stopPosition = section.buildStopPointPosition(right);
if (targetPosition == null || stopPosition.isAheadOf(targetPosition, right)) {
if (headPosition.getOffset() < (section.getStopPointByDirection(right) + SimulationConstants.PARK_POINT_MAX_OFFSET)) { //防止意外开过站后无法发车
if (headPosition.getOffset() < (section.getStopPointByDirection(right)
+ SimulationConstants.PARK_POINT_MAX_OFFSET)) { //防止意外开过站后无法发车
targetPosition = stopPosition;
}
}
@ -249,10 +276,12 @@ public class SimulationRobotService {
if (signal != null && !signal.isShunting()) {
VirtualRealitySignal vrSignal = signal.getVirtualSignal();
SectionPosition signalPosition = signal.getPosition();
if (vrSignal != null && (i != 0 || signalPosition.isAheadOf(headPosition, right))) { //有实体信号机且列车未越过信号机
if (vrSignal != null && (i != 0 || signalPosition.isAheadOf(headPosition,
right))) { //有实体信号机且列车未越过信号机
if (Objects.equals(vrSignal.getAspect(), signal.getDefaultAspect()) //禁止信号
|| Objects.equals(vrSignal.getAspect(), signal.getGuideAspect())) { //引导信号
if (!Objects.equals(signal, throughSignal) || !Objects.equals(vrSignal.getAspect(), throughAspect)) {
if (!Objects.equals(signal, throughSignal) || !Objects.equals(vrSignal.getAspect(),
throughAspect)) {
SectionPosition noPassPosition = CalculateService
.calculateNextPositionByStartAndLen(signalPosition, !right, 2, true);
if (targetPosition == null || noPassPosition.isAheadOf(targetPosition, right)) {
@ -264,7 +293,8 @@ public class SimulationRobotService {
}
if (targetPosition == null) {
if (selectedPosition != null && section.equals(selectedPosition.getSection())) { //不会有比选定位置更靠前的停车点了
if (selectedPosition != null && section.equals(
selectedPosition.getSection())) { //不会有比选定位置更靠前的停车点了
targetPosition = selectedPosition;
} else {
Section tempSection = section.findNextRunningSectionBaseRealSwitch(right);
@ -289,7 +319,8 @@ public class SimulationRobotService {
return Optional.ofNullable(targetPosition);
}
private void releaseEB(Simulation simulation, SimulationMember driver, VirtualRealityTrain train) {
private void releaseEB(Simulation simulation, SimulationMember driver,
VirtualRealityTrain train) {
Operation.Type operationType = null;
Map<String, Object> param = null;
if (train.isSignalEB()) {
@ -312,7 +343,9 @@ public class SimulationRobotService {
/**
* 机器人驾驶
*/
private void robotDrive(Simulation simulation, SimulationMember driver, VirtualRealityTrain train, SectionPosition targetPosition) {
private void robotDrive(Simulation simulation, SimulationMember driver, VirtualRealityTrain train,
SectionPosition targetPosition) {
train.getRobotDriveParam().setStopPosition(targetPosition);
if (!train.isInTheGear(VirtualRealityTrain.Handwheel.MANUAL)) { //确保当前在手动档位
return;
// CommandBO.Step step = CommandBO.buildGearChangeStep(train.getGroupNumber(), VirtualRealityTrain.Handwheel.MANUAL);
@ -353,12 +386,14 @@ public class SimulationRobotService {
* end 2022-08-15
*/
Float distance = CalculateService.calculateDistance(headPosition, targetPosition, right, true);
if (distance == null || distance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //如果列车已经抵达或越过目标位置
if (distance == null
|| distance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //如果列车已经抵达或越过目标位置
atoService.doBreakMax(train);
return;
}
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), true);
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition,
!right, train.getLen(), true);
SpeedCurve speedCurve = null;
switch (train.getDriveMode()) {
case AM: //AM模式下不需要司机驾驶
@ -371,11 +406,13 @@ public class SimulationRobotService {
break;
case RM:
speedCurve = SpeedCurve.buildTargetSpeedCurve(headPosition, tailPosition, right,
distance, speed, Math.min(repository.getConfig().getRmAtpSpeed(), train.getSpeedLimitInMs()) * 0.9f);
distance, speed,
Math.min(repository.getConfig().getRmAtpSpeed(), train.getSpeedLimitInMs()) * 0.9f);
break;
case NRM:
speedCurve = SpeedCurve.buildTargetSpeedCurve(headPosition, tailPosition, right,
distance, speed, Math.min(repository.getConfig().getUrmAtpSpeed(), train.getSpeedLimitInMs()) * 0.9f);
distance, speed,
Math.min(repository.getConfig().getUrmAtpSpeed(), train.getSpeedLimitInMs()) * 0.9f);
break;
default:
return;
@ -396,33 +433,42 @@ public class SimulationRobotService {
}
// 实训场景模式已设置背景处于编制状态的实训不做自动转换处理
Training2 training2 = simulation.getTraining2();
if (training2 != null && training2.isScene() && StringUtils.hasText(training2.getBgSceneJson()) && !training2.isRunning()) {
if (training2 != null && training2.isScene() && StringUtils.hasText(training2.getBgSceneJson())
&& !training2.isRunning()) {
return;
}
Map<SimulationMember, List<Station>> collect = simulation.getRepository().getStationList().stream()
.filter(station -> station.getApplicant() != null).collect(Collectors.groupingBy(Station::getApplicant));
Map<SimulationMember, List<Station>> collect = simulation.getRepository().getStationList()
.stream()
.filter(station -> station.getApplicant() != null)
.collect(Collectors.groupingBy(Station::getApplicant));
for (Map.Entry<SimulationMember, List<Station>> entry : collect.entrySet()) {
if (entry.getValue().get(0).getValidDuration() > SimulationConstants.CONTROL_TRANSFER_VALID_DURATION - 2 * 1000) { //延时通过申请
if (entry.getValue().get(0).getValidDuration()
> SimulationConstants.CONTROL_TRANSFER_VALID_DURATION - 2 * 1000) { //延时通过申请
continue;
}
if (SimulationMember.Type.DISPATCHER.equals(entry.getKey().getType())) { //如果申请者是行调
for (Station station : entry.getValue()) {
List<SimulationMember> supervisors = simulation.getSimulationMembersByDevice(station);
if (supervisors.stream().allMatch(SimulationMember::isRobot)) {
List<ControlTransferReplyVO> replyVOList = Collections.singletonList(new ControlTransferReplyVO(station.getCode(), true));
this.robotReplyControlTransferApplication(simulation, replyVOList, station.getApply2TheControlMode());
List<ControlTransferReplyVO> replyVOList = Collections.singletonList(
new ControlTransferReplyVO(station.getCode(), true));
this.robotReplyControlTransferApplication(simulation, replyVOList,
station.getApply2TheControlMode());
}
}
}
if (SimulationMember.Type.STATION_SUPERVISOR.equals(entry.getKey().getType())) { //如果申请者是行值
List<SimulationMember> dispatchers = simulation.getMemberListByType(SimulationMember.Type.DISPATCHER);
List<SimulationMember> dispatchers = simulation.getMemberListByType(
SimulationMember.Type.DISPATCHER);
if (dispatchers.stream().anyMatch(dispatcher -> !dispatcher.isRobot())) { //有任何一个行调不是机器人
continue;
}
List<ControlTransferReplyVO> replyVOList = entry.getValue()
.stream().map(station -> new ControlTransferReplyVO(station.getCode(), true)).collect(Collectors.toList());
this.robotReplyControlTransferApplication(simulation, replyVOList, entry.getValue().get(0).getApply2TheControlMode());
.stream().map(station -> new ControlTransferReplyVO(station.getCode(), true))
.collect(Collectors.toList());
this.robotReplyControlTransferApplication(simulation, replyVOList,
entry.getValue().get(0).getApply2TheControlMode());
}
}
}
@ -434,11 +480,15 @@ public class SimulationRobotService {
if (simulation.getScript() != null && simulation.getScript().isBgSet()) {
return;
}
Map<SimulationMember, List<Station>> robotControlStations = simulation.getRepository().getStationList().stream()
.filter(station -> Objects.nonNull(station.getController()) && station.getController().isRobot() && Objects.nonNull(station.getControlApplicant()))
Map<SimulationMember, List<Station>> robotControlStations = simulation.getRepository()
.getStationList().stream()
.filter(
station -> Objects.nonNull(station.getController()) && station.getController().isRobot()
&& Objects.nonNull(station.getControlApplicant()))
.collect(Collectors.groupingBy(Station::getController));
robotControlStations.forEach((controler, stations) -> {
atsStationService.transferControl(simulation, stations.stream().map(Station::getCode).collect(Collectors.toList()), true, controler);
atsStationService.transferControl(simulation,
stations.stream().map(Station::getCode).collect(Collectors.toList()), true, controler);
});
}
@ -447,7 +497,8 @@ public class SimulationRobotService {
*
* @param controlMode 申请转到该控制模式
*/
private void robotReplyControlTransferApplication(Simulation simulation, List<ControlTransferReplyVO> replyVOList, Station.ControlMode controlMode) {
private void robotReplyControlTransferApplication(Simulation simulation,
List<ControlTransferReplyVO> replyVOList, Station.ControlMode controlMode) {
switch (controlMode) {
case Center:
atsStationService.replyForCenterControl(simulation, replyVOList);
@ -468,7 +519,8 @@ public class SimulationRobotService {
}
// 实训场景模式已设置背景处于编制状态的实训不做自动转换处理
Training2 training2 = simulation.getTraining2();
if (training2 != null && training2.isScene() && StringUtils.hasText(training2.getBgSceneJson()) && !training2.isRunning()) {
if (training2 != null && training2.isScene() && StringUtils.hasText(training2.getBgSceneJson())
&& !training2.isRunning()) {
return;
}
// 非单岗位一直等待角色同意
@ -477,17 +529,20 @@ public class SimulationRobotService {
}
simulation.getRepository().getStationList().stream()
// 申请不为空审批人全部为机器人
.filter(station -> station.getOperationModeApplication() != null && station.getOperationModeApplication().isRobotApproval())
.filter(station -> station.getOperationModeApplication() != null
&& station.getOperationModeApplication().isRobotApproval())
.forEach(station -> atsStationService.doOperationModeSwitch(station));
}
private void doControlBySpeedCurve(Simulation simulation, VirtualRealityTrain train, SpeedCurve speedCurve, float remainDistance) {
private void doControlBySpeedCurve(Simulation simulation, VirtualRealityTrain train,
SpeedCurve speedCurve, float remainDistance) {
if (speedCurve.equals(SpeedCurve.ZERO)) {
this.doBreakMax(simulation, train);
return;
}
SpeedCurve.SpeedCalculator calculator = speedCurve.getCalculatorOf(remainDistance);
if (calculator.getVt() == 0 && remainDistance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //末速度为0且当前距终点距离在停车误差内
if (calculator.getVt() == 0
&& remainDistance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //末速度为0且当前距终点距离在停车误差内
this.doBreakMax(simulation, train);
return;
}
@ -557,7 +612,8 @@ public class SimulationRobotService {
float fk = a * train.getMass();
float fkMax = train.getCurrentFkMax();
fk = Math.min(fk, fkMax);
driverOperateHandler.changeTrainForce(simulation, train.getGroupNumber(), Math.min(fk / fkMax, 1));
driverOperateHandler.changeTrainForce(simulation, train.getGroupNumber(),
Math.min(fk / fkMax, 1));
}
private void doBreakMax(Simulation simulation, VirtualRealityTrain train) {
@ -571,20 +627,24 @@ public class SimulationRobotService {
a = -Math.abs(a);
float fb = train.getMass() * a;
float fbMax = train.getCurrentFbMax();
driverOperateHandler.changeTrainForce(simulation, train.getGroupNumber(), Math.max(fb / fbMax, -1));
driverOperateHandler.changeTrainForce(simulation, train.getGroupNumber(),
Math.max(fb / fbMax, -1));
}
public void addJobs(Simulation simulation) {
simulation.addJob(SimulationModule.ROBOT.name(), () -> this.run(simulation), SimulationConstants.ROBOT_LOGIC_LOOP_RATE);
simulation.addJob(SimulationModule.ROBOT.name(), () -> this.run(simulation),
SimulationConstants.ROBOT_LOGIC_LOOP_RATE);
}
public void stopTrain(Simulation simulation, SimulationMember simulationMember, String groupNumber, Boolean eb) {
public void stopTrain(Simulation simulation, SimulationMember simulationMember,
String groupNumber, Boolean eb) {
SimulationDataRepository repository = simulation.getRepository();
VirtualRealityTrain train = repository.getOnlineTrainBy(groupNumber);
if (Objects.equals(true, eb)) {
Map<String, Object> param = new HashMap<>();
param.put("groupNumber", train.getGroupNumber());
atsOperationDispatcher.execute(simulation, simulationMember, Operation.Type.Driver_EB.name(), param);
atsOperationDispatcher.execute(simulation, simulationMember, Operation.Type.Driver_EB.name(),
param);
} else {
train.getRobotDriveParam().setStop(true);
}

View File

@ -1,9 +1,12 @@
package club.joylink.rtss.simulation.cbtc.work;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.entity.Ibp;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.*;
import club.joylink.rtss.services.ICommandService;
import club.joylink.rtss.services.ILoadPlanService;
import club.joylink.rtss.services.IMapService;
import club.joylink.rtss.services.IRunPlanTemplateService;
import club.joylink.rtss.services.IVirtualRealityIbpService;
import club.joylink.rtss.services.iscs.IscsDeviceService;
import club.joylink.rtss.services.iscs.IscsSystemResourcesService;
import club.joylink.rtss.services.project.DeviceService;
@ -15,12 +18,16 @@ import club.joylink.rtss.services.simulation.SchedulingService;
import club.joylink.rtss.services.training.ITrainingV1Service;
import club.joylink.rtss.simulation.cbtc.ATS.ATSLogicLoop;
import club.joylink.rtss.simulation.cbtc.ATS.ATSMessageCollectAndDispatcher;
import club.joylink.rtss.simulation.cbtc.ATS.service.alarm.NccAlarmService;
import club.joylink.rtss.simulation.cbtc.ATS.ATSTrainMessageDiagram;
import club.joylink.rtss.simulation.cbtc.ATS.service.alarm.NccAlarmService;
import club.joylink.rtss.simulation.cbtc.CI.CiLogic;
import club.joylink.rtss.simulation.cbtc.*;
import club.joylink.rtss.simulation.cbtc.DeviceStatusService;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.ISCS.IscsLogicLoop;
import club.joylink.rtss.simulation.cbtc.ISCS.IscsMessageCollectAndDispatcher;
import club.joylink.rtss.simulation.cbtc.PowerSupplyService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.SimulationLifeCycleService;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuildParams;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuilder;
import club.joylink.rtss.simulation.cbtc.build.UserConfigDataBuilder;
@ -28,7 +35,6 @@ import club.joylink.rtss.simulation.cbtc.communication.Joylink3DMessageService;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.depot.DepotService;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.SimulationRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.device.virtual.VRDeviceLogicLoop;
import club.joylink.rtss.simulation.cbtc.device.virtual.VRTrainRunningService;
@ -48,7 +54,6 @@ import club.joylink.rtss.vo.client.CommandDefinitionVO;
import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesQueryVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.client.runplan.RunPlanLoadVO;
import club.joylink.rtss.vo.client.runplan.RunPlanVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanParkingTimeVO;
@ -56,18 +61,16 @@ import club.joylink.rtss.vo.client.runplan.user.RunPlanRunlevelVO;
import club.joylink.rtss.vo.client.schedulingNew.SchedulingPlanNewVO;
import club.joylink.rtss.vo.client.simulationv1.RunAsPlanParam;
import club.joylink.rtss.vo.map.MapVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@Slf4j
@Service
@ -190,12 +193,7 @@ public class MetroSimulationWorkServiceImpl implements SimulationWorkService {
simulationWorkServiceManager.buildMember(simulation);
// 添加项目设备
if (buildParams.getWorkParamVO().containsRealDeviceItem()) {
List<ProjectDeviceVO> projectDeviceList = this.deviceService
.queryDetailByTypes(ProjectDeviceType.PlcDeviceList(), buildParams.getMap().getProjectCode());
List<RealDeviceConfig> realDeviceList = ProjectDeviceVO.convert2RealDeviceList(projectDeviceList);
log.info(String.format("load project device list: [%s]",
realDeviceList.stream().map(Object::toString).collect(Collectors.joining(","))));
this.loadRealDevices(simulation, realDeviceList);
simulationWorkServiceManager.loadRealDevices(simulation);
}
}
@ -491,29 +489,4 @@ public class MetroSimulationWorkServiceImpl implements SimulationWorkService {
}
});
}
private void loadRealDevices(Simulation simulation, List<RealDeviceConfig> realDeviceList) {
try {
simulation.setRealDeviceList(realDeviceList);
if (!CollectionUtils.isEmpty(realDeviceList)) {
simulationRealDeviceThread.addJobs(simulation);
udpRealDeviceThread.addJobs(simulation);
}
for (RealDeviceConfig realDevice : realDeviceList) {
if (ProjectDeviceType.PLC_GATEWAY.equals(realDevice.getDeviceType())) {
continue;
}
String deviceCode = realDevice.findDeviceCode();
if (Objects.nonNull(deviceCode)) {
this.groupSimulationService.connectDevice(simulation.getId(),
deviceCode, realDevice.getProjectDevice().getId());
}
}
} catch (Exception e) {
log.error("仿真加载真实设备异常", e);
// 清理仿真
this.groupSimulationService.clearSimulation(simulation.getId(), simulation.getCreator());
throw BusinessExceptionAssertEnum.TRAINING_ROOM_SIMULATION_LOAD_DEVICE_ERROR.exception(e);
}
}
}

View File

@ -33,17 +33,16 @@ import club.joylink.rtss.vo.map.MapGraphDataNewVO;
import club.joylink.rtss.vo.map.MapLogicDataNewVO;
import club.joylink.rtss.vo.map.MapVO;
import club.joylink.rtss.websocket.StompMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@Slf4j
@Service
@ -101,16 +100,20 @@ public class RailwaySimulationWorkServiceImpl implements SimulationWorkService {
@Override
public void loadData(Simulation simulation) {
SimulationBuildParams params = simulation.getBuildParams();
SimulationBuildParams buildParams = simulation.getBuildParams();
// 加载地图数据
loadMapData(simulation);
// // 车辆段
// depotService.loadDepotTrain(simulation);
// 添加仿真用户
SimulationUser creator = SimulationUser.buildCreator(simulation, params.getLoginUserInfo());
SimulationUser creator = SimulationUser.buildCreator(simulation, buildParams.getLoginUserInfo());
simulation.addSimulationUser(creator);
// 添加仿真成员
simulationWorkServiceManager.buildMember(simulation);
// 添加项目设备
if (buildParams.getWorkParamVO().containsRealDeviceItem()) {
simulationWorkServiceManager.loadRealDevices(simulation);
}
}
@Override

View File

@ -1,13 +1,26 @@
package club.joylink.rtss.simulation.cbtc.work;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.project.DeviceService;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuildParams;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.SimulationRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDeviceConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.event.SimulationUserEnterEvent;
import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.member.SimulationUser;
import club.joylink.rtss.vo.client.project.ProjectDeviceVO;
import club.joylink.rtss.vo.map.graph.MapMemberVO;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
@ -18,11 +31,11 @@ import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 仿真工作服务管理
* 1.管理仿真工作服务的实现类
* 2.各种仿真的公共方法
*/
@Slf4j
@Component
public class SimulationWorkServiceManager implements ApplicationContextAware {
@ -30,6 +43,14 @@ public class SimulationWorkServiceManager implements ApplicationContextAware {
private MemberManager memberManager;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private DeviceService deviceService;
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private SimulationRealDeviceThread simulationRealDeviceThread;
@Autowired
private UDPRealDeviceThread udpRealDeviceThread;
private Map<Simulation.Type, SimulationWorkService> map;
@ -95,4 +116,39 @@ public class SimulationWorkServiceManager implements ApplicationContextAware {
SimulationUserEnterEvent userEnterEvent = new SimulationUserEnterEvent(this, simulation, simulationUser);
this.applicationContext.publishEvent(userEnterEvent);
}
public void loadRealDevices(Simulation simulation) {
SimulationBuildParams buildParams = simulation.getBuildParams();
List<ProjectDeviceVO> projectDeviceList = this.deviceService
.queryDetailByTypes(ProjectDeviceType.PlcDeviceList(), buildParams.getMap().getProjectCode());
List<RealDeviceConfig> realDeviceList = ProjectDeviceVO.convert2RealDeviceList(projectDeviceList);
log.info(String.format("load project device list: [%s]",
realDeviceList.stream().map(Object::toString).collect(Collectors.joining(","))));
this.loadRealDevices(simulation, realDeviceList);
}
private void loadRealDevices(Simulation simulation, List<RealDeviceConfig> realDeviceList) {
try {
simulation.setRealDeviceList(realDeviceList);
if (!CollectionUtils.isEmpty(realDeviceList)) {
simulationRealDeviceThread.addJobs(simulation);
udpRealDeviceThread.addJobs(simulation);
}
for (RealDeviceConfig realDevice : realDeviceList) {
if (ProjectDeviceType.PLC_GATEWAY.equals(realDevice.getDeviceType())) {
continue;
}
String deviceCode = realDevice.findDeviceCode();
if (Objects.nonNull(deviceCode)) {
this.groupSimulationService.connectDevice(simulation.getId(),
deviceCode, realDevice.getProjectDevice().getId());
}
}
} catch (Exception e) {
log.error("仿真加载真实设备异常", e);
// 清理仿真
this.groupSimulationService.clearSimulation(simulation.getId(), simulation.getCreator());
throw BusinessExceptionAssertEnum.TRAINING_ROOM_SIMULATION_LOAD_DEVICE_ERROR.exception(e);
}
}
}

View File

@ -16,6 +16,7 @@ import lombok.Setter;
@Setter
@NoArgsConstructor
public class DriveParamVO {
/**
* 限速值km/h
*/
@ -56,6 +57,12 @@ public class DriveParamVO {
*/
private int through;
/**
* 这个停车位置是机器人驾驶逻辑计算出来的这个字段仅供泰国沙盘的列车逻辑使用
*/
@JsonIgnore
private SectionPosition stopPosition;
public static final int NO = 0;
public static final int RED_SIGNAL = 1;
public static final int GUIDE_SIGNAL = 2;
@ -84,6 +91,19 @@ public class DriveParamVO {
this.speedLimitInMs = speedLimit == null ? Float.MAX_VALUE : speedLimit / 3.6f;
}
/**
* 让机器人驾驶逻辑停止控制该列车
*/
public void stopControl() {
stop = false;
run = false;
}
@JsonIgnore
public boolean isStopControl() {
return !stop && !run;
}
public boolean needStop() {
return stop;
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.vo.client.project;
import club.joylink.rtss.constants.ProjectCode;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.entity.ProjectDevice;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
@ -9,10 +10,18 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.gxsd.GxsdSignalCo
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.gxsd.GxsdSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.gzb.GzbSignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.gzb.GzbSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.*;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1IbpConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1PscConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1PslConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1SignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1SwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.hhcj.HhcjIbpConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.hhcj.HhcjPsdConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.*;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.SayIbpConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.SayPsdConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.SaySectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.SaySignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.say.SaySwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.sdy.SdyPsdConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.sdy.SdyPslConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.xty.XtyPsdConfig;
@ -25,8 +34,17 @@ import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSectionConf
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrTrainConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.thailand.config.ThailandTrainConfig;
import club.joylink.rtss.util.JsonUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -34,12 +52,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 项目设备对象
*/
@ -104,8 +116,7 @@ public class ProjectDeviceVO {
List<RealDeviceConfig> list = new ArrayList<>();
if (!CollectionUtils.isEmpty(voList)) {
String project = voList.get(0).getProject();
String projectCode = StringUtils.hasText(project) ? project.toUpperCase() : "";
switch (projectCode) {
switch (project) {
case "XTY": {
return xtyDeviceConfigConvert(voList);
}
@ -121,7 +132,7 @@ public class ProjectDeviceVO {
case "RICHOR_JOINT": {
return zjdDeviceConfigConvert(voList);
}
case "SR_SANDBOX": {
case ProjectCode.SR_SANDBOX: {
return srSandboxDeviceConfigConvert(voList);
}
case "RICHOR_HHCJ": {
@ -130,6 +141,9 @@ public class ProjectDeviceVO {
case "SAY": {
return sayDeviceConfigConvert(voList);
}
case ProjectCode.THAILAND_SANDBOX: {
return thailandSandboxDeviceConfigConvert(voList);
}
case "GXSD": {
return gxsdDeviceConfigConvert(voList);
}
@ -139,6 +153,34 @@ public class ProjectDeviceVO {
return list;
}
private static List<RealDeviceConfig> thailandSandboxDeviceConfigConvert(
List<ProjectDeviceVO> voList) {
List<RealDeviceConfig> list = new ArrayList<>();
for (ProjectDeviceVO deviceVO : voList) {
switch (deviceVO.getType()) {
case UDP_LOW:
list.add(new UDPLowConfig(deviceVO));
break;
case UDP_CLIENT:
list.add(new UDPClientConfig(deviceVO));
break;
case SIGNAL:
list.add(new ThailandSignalConfig(deviceVO));
break;
case SECTION:
list.add(new ThailandSectionConfig(deviceVO));
break;
case SWITCH:
list.add(new ThailandSwitchConfig(deviceVO));
break;
case TRAIN:
list.add(new ThailandTrainConfig(deviceVO));
break;
}
}
return list;
}
private static List<RealDeviceConfig> gxsdDeviceConfigConvert(List<ProjectDeviceVO> voList) {
List<RealDeviceConfig> list = new ArrayList<>();
for (ProjectDeviceVO deviceVO : voList) {

View File

@ -12,6 +12,12 @@ import lombok.Setter;
@Setter
@NoArgsConstructor
public class UDPLowConfigVO {
/**
* 名称
* 泰国沙盘下位机有两个接收数据的端口一个用于接收信号机控制指令一个用于接收道岔和区段控制指令
*/
private String name;
private String ip;
private Integer port;
@ -21,6 +27,11 @@ public class UDPLowConfigVO {
this.port = port;
}
public UDPLowConfigVO(String name, String ip, Integer port) {
this(ip, port);
this.name = name;
}
public String toJson() {
return JsonUtils.writeValueAsString(this);
}

View File

@ -0,0 +1,38 @@
package club.joylink.rtss.vo.client.project.thailand;
import club.joylink.rtss.vo.client.project.RealConfigVO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ThailandSectionConfigVO extends RealConfigVO {
private String vrCode;
private String sandboxCode;
/**
* 车头到达区段延迟停车时间/s
*/
private Float headDelayTime;
/**
* 车尾解除占用延迟停车时间/s
*/
private Float tailDelayTime;
public ThailandSectionConfigVO() {
super(null, null);
}
public ThailandSectionConfigVO(String vrCode, String sandboxCode) {
this();
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;
}
@Override
public String findDeviceCode() {
return vrCode;
}
}

View File

@ -0,0 +1,28 @@
package club.joylink.rtss.vo.client.project.thailand;
import club.joylink.rtss.vo.client.project.RealConfigVO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ThailandSignalConfigVO extends RealConfigVO {
private String vrCode;
private String sandboxCode;
public ThailandSignalConfigVO() {
super(null, null);
}
public ThailandSignalConfigVO(String vrCode, String sandboxCode) {
this();
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;
}
@Override
public String findDeviceCode() {
return vrCode;
}
}

View File

@ -0,0 +1,28 @@
package club.joylink.rtss.vo.client.project.thailand;
import club.joylink.rtss.vo.client.project.RealConfigVO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ThailandSwitchConfigVO extends RealConfigVO {
private String vrCode;
private String sandboxCode;
public ThailandSwitchConfigVO() {
super(null, null);
}
public ThailandSwitchConfigVO(String vrCode, String sandboxCode) {
this();
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;
}
@Override
public String findDeviceCode() {
return vrCode;
}
}

View File

@ -0,0 +1,28 @@
package club.joylink.rtss.vo.client.project.thailand;
import club.joylink.rtss.vo.client.project.RealConfigVO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ThailandTrainConfigVO extends RealConfigVO {
private String vrCode;
private String sandboxCode;
public ThailandTrainConfigVO() {
super(null, null);
}
public ThailandTrainConfigVO(String vrCode, String sandboxCode) {
this();
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;
}
@Override
public String findDeviceCode() {
return vrCode;
}
}

View File

@ -215,7 +215,7 @@ common:
spring:
profiles: local
datasource:
url: jdbc:mysql://192.168.1.254:3306/joylink?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
url: jdbc:mysql://192.168.53.12:3306/joylink?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: localdb