Merge branch 'test' into master-huawei

This commit is contained in:
thesai 2021-11-13 20:48:03 +08:00
commit 65572dd3b0
63 changed files with 1205 additions and 628 deletions

View File

@ -42,6 +42,8 @@ public enum Project {
RICHOR_JOINT,
/** 上饶沙盘 */
SR_SANDBOX,
/** 江西工贸 */
JXGM,
;
public static boolean isDefault(Project project) {

View File

@ -34,6 +34,8 @@ public enum ProjectDeviceType {
UDP_LOW,
/** UDP客户端 */
UDP_CLIENT,
/** 列车 */
TRAIN,
/* -----------plc device end---------- */
/* -----------client device start---------- */
@ -79,6 +81,7 @@ public enum ProjectDeviceType {
SIGNAL,
DCU,
UDP_LOW,
UDP_CLIENT);
UDP_CLIENT,
TRAIN);
}
}

View File

@ -189,6 +189,14 @@ public class DeviceController {
this.deviceService.updateIlwConfig(id, configVO);
}
/**
* 修改配置以json的形式
*/
@PutMapping("/config/updateConfig")
public void updateConfig(@RequestBody ProjectDeviceVO projectDeviceVO) {
this.deviceService.updateConfig(projectDeviceVO);
}
/**
*删除设备
*/

View File

@ -44,6 +44,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
@ -109,7 +110,11 @@ public class CompetitionPracticalService implements ICompetitionPracticalService
@Override
public PageVO<CompetitionVO> pagedQueryCompetition(CompetitionPagedQueryVO queryVO) {
PageHelper.startPage(queryVO.getPageNum(), queryVO.getPageSize());
Page<Competition> page = (Page<Competition>) this.competitionDAO.selectByExample(null);
CompetitionExample competitionExample = new CompetitionExample();
if (StringUtils.hasText(queryVO.getName())) {
competitionExample.createCriteria().andNameLike(String.format("%%%s%%", queryVO.getName()));
}
Page<Competition> page = (Page<Competition>) this.competitionDAO.selectByExample(competitionExample);
List<CompetitionVO> list = page.getResult().stream().map(CompetitionVO::new).collect(Collectors.toList());
return PageVO.convert(page, list);
}

View File

@ -148,6 +148,11 @@ public interface DeviceService {
*/
void updateIlwConfig(Long id, RelationLoginConfigVO configVO);
/**
* 更新以json直接更新
*/
void updateConfig(ProjectDeviceVO projectDeviceVO);
/**
* 删除设备
* @param id

View File

@ -7,6 +7,7 @@ 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.data.map.Section;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO;
@ -22,12 +23,14 @@ 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.xty.XtyPsdConfigVO;
import club.joylink.rtss.vo.map.MapGraphDataNewVO;
import club.joylink.rtss.vo.map.MapVO;
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 com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
@ -269,6 +272,24 @@ public class DeviceServiceImpl implements DeviceService {
this.projectDeviceDAO.updateByPrimaryKeySelective(device);
}
@Override
public void updateConfig(ProjectDeviceVO projectDeviceVO) {
ProjectDevice entity = getEntityById(projectDeviceVO.getId());
check(entity, projectDeviceVO);
entity.setConfig(projectDeviceVO.getConfig());
projectDeviceDAO.updateByPrimaryKeyWithBLOBs(entity);
}
private ProjectDevice getEntityById(long id) {
return projectDeviceDAO.selectByPrimaryKey(id);
}
private void check(ProjectDevice entity, ProjectDeviceVO projectDeviceVO) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getProjectCode(), projectDeviceVO.getProject().name());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getCode(), projectDeviceVO.getCode());
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertEquals(entity.getType(), projectDeviceVO.getType().name());
}
@Override
public void delete(Long id) {
this.projectDeviceDAO.deleteByPrimaryKey(id);
@ -436,7 +457,7 @@ public class DeviceServiceImpl implements DeviceService {
udp.setType(ProjectDeviceType.UDP_LOW.name());
udp.setCreator(accountVO.getId());
udp.setCreateTime(now);
UDPLowConfigVO udpConfigVO = new UDPLowConfigVO("", 10086);
UDPLowConfigVO udpConfigVO = new UDPLowConfigVO("192.168.0.110", 44449);
udp.setConfig(udpConfigVO.toJson());
list.add(udp);
//UDP客户端
@ -446,7 +467,7 @@ public class DeviceServiceImpl implements DeviceService {
udpClient.setType(ProjectDeviceType.UDP_CLIENT.name());
udpClient.setCreator(accountVO.getId());
udpClient.setCreateTime(now);
UDPClientConfigVO udpClientConfigVO = new UDPClientConfigVO("192.168.8.109", 10000);
UDPClientConfigVO udpClientConfigVO = new UDPClientConfigVO("192.168.0.110", 44449);
udpClient.setConfig(JsonUtils.writeValueAsString(udpClientConfigVO));
list.add(udpClient);
/*-------------------- 地图设备 --------------------*/
@ -490,13 +511,82 @@ public class DeviceServiceImpl implements DeviceService {
section.setCreator(accountVO.getId());
section.setCreateTime(now);
SrSectionConfigVO configVO = new SrSectionConfigVO(mapSectionNewVO.getCode(), mapSectionNewVO.getSrCode());
fillTime(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(Project.SR_SANDBOX.name());
train.setCode("sr-train-" + mapTrainVO.getGroupNumber());
train.setType(ProjectDeviceType.TRAIN.name());
train.setCreator(accountVO.getId());
train.setCreateTime(now);
SrTrainConfigVO configVO = new SrTrainConfigVO(mapTrainVO.getGroupNumber(), String.valueOf(Integer.parseInt(mapTrainVO.getGroupNumber())));
train.setConfig(JsonUtils.writeValueAsString(configVO));
list.add(train);
}
return list;
}
/**
* 填充区段延时停车时间
*/
private void fillTime(SrSectionConfigVO configVO, MapSectionNewVO section) {
Float headDelayTime = null;
Float tailDelayTime = null;
switch (section.getCode()) {
//以车头到目标位置作为停车标志的区段
case "T141": //49G
case "T142":
headDelayTime = 1.0f;
break;
case "T1": //1G
headDelayTime = 3.7f;
break;
case "T11":
headDelayTime = 3.7f;
break;
case "T73":
case "T75":
headDelayTime = 3.4f;
break;
//以车尾解除占用作为停车标志的区段
case "T5": //1x
break;
case "T7": //2x
break;
case "T45": //3x
break;
case "T53": //4x
break;
case "T61": //5x
break;
case "T67": //6x
break;
case "T33": //1s
tailDelayTime = 2.0f;
break;
case "T35": //2s
tailDelayTime = 2.5f;
break;
case "T46": //3s
break;
case "T54": //4s
break;
case "T62": //5s
break;
case "T68": //6s
tailDelayTime = 2.0f;
break;
}
configVO.setHeadDelayTime(headDelayTime);
configVO.setTailDelayTime(tailDelayTime);
}
private List<ProjectDevice> buildZjdProjectDevices(AccountVO accountVO) {
LocalDateTime now = LocalDateTime.now();
List<ProjectDevice> list = new ArrayList<>();
@ -584,7 +674,7 @@ public class DeviceServiceImpl implements DeviceService {
private ProjectDevice buildIm(Project project, Long creatorId) {
ProjectDevice im = new ProjectDevice();
im.setProjectCode(project.name());
im.setCode(project.name().toLowerCase() + "-" +"im");
im.setCode(project.name().toLowerCase() + "-" + "im");
im.setType(ProjectDeviceType.IM.name());
im.setCreator(creatorId);
im.setCreateTime(LocalDateTime.now());

View File

@ -239,7 +239,7 @@ public class RunPlanGenerator {
List<RunPlanRoutingSection> inSectionList = inRouting.getParkSectionCodeList();
RunPlanRoutingSection inSection = inSectionList.get(inSectionList.size() - 2);
return Objects.equals(parkSection.getSectionCode(), inSection.getSectionCode());
}).sorted(Comparator.comparing(routingVO -> runLevelMap.get(parkSection.getSectionCode() + "-" + routingVO.getEndSectionCode()))).findFirst().orElse(null);
}).min(Comparator.comparing(routingVO -> runLevelMap.get(parkSection.getSectionCode() + "-" + routingVO.getEndSectionCode()))).orElse(null);
if (Objects.nonNull(inboundRouting)) {
r = runningRouting.getStartTbFront() ? i + 1 : i;
break t;

View File

@ -84,7 +84,7 @@ public class AtpSectionService {
if (train.isCommunicable()) { // 通信车占用
// 车尾位置追加不确定性距离(速度*2)m
SectionPosition trainTailPosition = CalculateService
.calculateNextPositionByStartAndLen(trainHeadPosition, !right, train.getLen() + train.getSpeed() * 2);
.calculateNextPositionByStartAndLen(trainHeadPosition, !right, train.getLen() + train.getSpeed() * 2, false);
atpSectionList = CalculateService.getAtpSections(trainHeadPosition, trainTailPosition,
right, switchSingleHandle);
List<Section> removes = new ArrayList<>();
@ -171,11 +171,11 @@ public class AtpSectionService {
SectionPosition headPosition = train.getHeadPosition();
float offset = 50;
SectionPosition head = CalculateService
.calculateNextPositionByStartAndLen(headPosition, right, offset);
.calculateNextPositionByStartAndLen(headPosition, right, offset, false);
// 考虑列车最大可能占用区间用于判断ARB区段
SectionPosition tail = CalculateService
.calculateNextPositionByStartAndLen(headPosition,
!right, train.getLen() + offset);
!right, train.getLen() + offset, false);
List<Section> sectionList = CalculateService.getTrainOccupyAxleSection(head, tail, right);
if (!CollectionUtils.isEmpty(sectionList)) {
for (Section section : sectionList) {
@ -209,26 +209,4 @@ public class AtpSectionService {
});
}
/**
* 如果有非通信车接近故障区段将故障区段设为非通信车占用
*/
public void judgeFaultSectionAsNctOccupied(Map<VirtualRealityTrain, Signal> nctApproachSignalMap) {
if (CollectionUtils.isEmpty(nctApproachSignalMap)) {
return;
}
nctApproachSignalMap.forEach((k, v) -> {
v.getRouteList().forEach(route -> {
if (v.equals(route.getStart())) { //如果该信号机是某进路的始端信号机
route.getSectionList().forEach(section -> {
if (section.isFault()) {
section.setNctOccupied(true); //设为非通信车占用
if (section.isInvalid()) {
section.setInvalid(false); //去掉ARB状态
}
}
});
}
});
});
}
}

View File

@ -134,7 +134,7 @@ public class MaService {
end = signal.getSection().buildStopPointPosition(right);
} else {
SectionPosition sectionPosition = new SectionPosition(signal.getSection(), signal.getOffset());
end = CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 5);
end = CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 5, false);
}
Float distance = CalculateService.calculateDistance(this.train.getHeadPosition(), end, right);
if (distance == null) {
@ -165,7 +165,7 @@ public class MaService {
} else {
eoa = frontTrain.getHeadPosition();
}
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10);
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10, false);
break;
}
case Axle_Occupy_Section:{
@ -202,7 +202,7 @@ public class MaService {
Section section = (Section) this.device;
float offset = section.getStopPointByDirection(right);
offset = right ? offset - train.getLen() - 20 : offset + train.getLen() + 20;
eoa = CalculateService.getAvailableSectionPositionOf(new SectionPosition(section, offset));
eoa = CalculateService.getAvailableSectionPositionOf(new SectionPosition(section, offset), false);
break;
}
case ITC_Signal:{
@ -222,7 +222,7 @@ public class MaService {
physicalSection = physicalSection.getParent();
}
eoa = new SectionPosition(physicalSection, right ? section.getMinOffset() : section.getMaxOffset());
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10);
eoa = CalculateService.calculateNextPositionByStartAndLen(eoa, !right, 10, false);
break;
}
default:
@ -550,7 +550,7 @@ public class MaService {
SwitchElement switchElement = route.getRouteSwitchElement(routeSection.getRelSwitch());
Switch aSwitch = switchElement.getASwitch();
handledSwitchSet.add(aSwitch.getCode());
if (route.equals(aSwitch.getRoute())) {
if (aSwitch.getRoutes().contains(route)) {
if (aSwitch.isLoss()) {
switchFault = true;
break;

View File

@ -67,6 +67,12 @@ public class DriverOperateHandler {
}
}
/**
* 修改工况手轮档位
* @param simulation
* @param groupNumber
* @param gear
*/
@OperateHandlerMapping(type = Operation.Type.Driver_Gear_Change)
public void changeTrainGear(Simulation simulation, String groupNumber, VirtualRealityTrain.Handwheel gear) {
Objects.requireNonNull(gear);

View File

@ -615,7 +615,7 @@ public class AtsTrainLoadService {
// 与上一辆车距离一个安全距离
SectionPosition headPosition = CalculateService
.calculateNextPositionByStartAndLen(frontTrain.getHeadPosition(),
!train.isRight(), frontTrain.getLen() + 2 * SimulationConstants.TRAIN_SAFE_DISTANCE);
!train.isRight(), frontTrain.getLen() + 2 * SimulationConstants.TRAIN_SAFE_DISTANCE, false);
train.setHeadPosition(headPosition);
}
}
@ -664,7 +664,7 @@ public class AtsTrainLoadService {
for (VirtualRealityTrain train : loadedList) {
Section headSection = train.getHeadPosition().getSection();
boolean right = train.isRight();
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(train.getHeadPosition(), !right, train.getLen());
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(train.getHeadPosition(), !right, train.getLen(), false);
TripPlan tripPlan = repository.getTripPlan(train.getServiceNumber(), train.getTripNumber());
// 取进路所有经过的区段
List<Section> viaSectionList = tripPlan.getAllViaStoppedSectionList();
@ -850,7 +850,7 @@ public class AtsTrainLoadService {
"列车需加载到物理区段上");
//重叠检测
SectionPosition headPosition = new SectionPosition(section, section.getStopPointByDirection(right));
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen());
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), false);
boolean willOverlap = vrTrainRunningService.willOverlap(simulation, headPosition, tailPosition);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertNotTrue(willOverlap, "列车重叠");
// 列车上线并构建ATS监控列车信息
@ -861,8 +861,19 @@ public class AtsTrainLoadService {
* 人工车上线并监控
*/
private void manualTrainOnlineAndSupervise(Simulation simulation, VirtualRealityTrain train, SectionPosition headPosition, boolean right) {
train.initManualTrain(headPosition, right); //暂时默认向左
train.initManualTrain(headPosition, right);
SimulationDataRepository repository = simulation.getRepository();
//设置列车预选模式驾驶模式运行级别
if (!headPosition.getSection().anyZcWorking()) {
train.initAsRM();
} else {
MapConfig config = repository.getConfig();
if (RunLevel.ITC.equals(config.getRunMode())) {
train.initAsAM_I();
} else if (RunLevel.IL.equals(config.getRunMode())) {
train.initAsRM();
}
}
TrainInfo trainInfo = TrainInfo.constructManualTrain(train);
trainInfo.tracking(train);
repository.addOnlineTrain(train);

View File

@ -8,8 +8,6 @@ import club.joylink.rtss.simulation.cbtc.ATS.service.stage.AtsHeadTrainStageServ
import club.joylink.rtss.simulation.cbtc.ATS.service.stage.AtsPlanTrainStageService;
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
import club.joylink.rtss.simulation.cbtc.constant.TrainType;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
@ -18,7 +16,6 @@ import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.RoutePath;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
@ -63,6 +60,9 @@ public class AtsTrainService {
@Autowired
private AtsHeadTrainStageService atsHeadTrainStageService;
@Autowired
private AtsTrainService atsTrainService;
/**
* 添加列车追踪
*
@ -100,6 +100,8 @@ public class AtsTrainService {
BusinessExceptionAssertEnum.OPERATION_FAIL.assertNotTrue(tripRepeat, "车次计划已在运行");
ti = new TrainInfo(groupNumber, TrainType.PLAN);
ti.init(section, tripPlan, dn, cn);
} else if (StringUtils.hasText(dn)) {
ti = new TrainInfo(groupNumber, TrainType.HEAD);
} else {
ti = new TrainInfo(groupNumber, TrainType.MANUAL);
}
@ -360,355 +362,6 @@ public class AtsTrainService {
onboardAtpApiService.resetAtoSpeedMax(simulation, groupNumber);
}
/**
* 头码车和人工车运行逻辑
*
* @param simulation
* @param train
*/
public void runContinue(Simulation simulation, TrainInfo train) {
if (train.isPlanTrain() || !train.hasPositionAndDirection()) {
return;
}
SimulationDataRepository repository = simulation.getRepository();
if (train.isInbound()) { // 准备回库列车
int deleteRemain = train.getDeleteRemain();
deleteRemain -= SimulationModule.ATS.getRateMs();
if (deleteRemain <= 0) { // 删除列车
repository.deleteOnlineTrain(train.getGroupNumber());
repository.deleteSuperviseTrain(train.getGroupNumber());
} else {
train.updateDeleteRemain(deleteRemain);
}
return;
}
Long mapId = simulation.getBuildParams().getMap().getId();
LocalTime systemTime = simulation.getSystemTime().toLocalTime();
Section headSection = repository.getByCode(train.getPhysicalSection(), Section.class);
Station headStation = headSection.getStation();
float offset = train.getOffsetp() * headSection.getLen();
SectionPosition headPosition = new SectionPosition(headSection, offset);
Boolean trainRight = train.getRight();
TrainType type = train.getType();
String estimatedArriveStandTrack = train.getEstimatedArriveStandTrack();
Section targetSection = null;
Station targetStation = null;
if (estimatedArriveStandTrack != null) {
targetSection = repository.getByCode(estimatedArriveStandTrack, Section.class);
targetStation = targetSection.getStation();
}
boolean stop = train.isStop();
Section nextTarget = null;
long runningTime = 0;
switch (type) {
case MANUAL: {
Section base = headSection;
boolean right = trainRight;
if (!CollectionUtils.isEmpty(headSection.getStandList())) {
Optional<Stand> onStand = headSection.getStandList().stream().filter(stand -> Objects.equals(stand.isRight(), train.getRight())).findFirst();
if (onStand.isPresent()) {
runningTime = onStand.get().getRunLevelTime();
}
}
if (train.isParking()) {
if (train.getSpeed() > 0) { // 列车出发了
// 站台停站状态取消
this.atsStandService.trainLeaveStand(headSection);
// 更新列车实际离开信息
train.updateLeaveInfo(headSection, systemTime);
}
// 站台停靠
Signal tdSignal = headSection.getSignalOf(trainRight); // 列车方向信号机
if (Objects.nonNull(tdSignal) && tdSignal.isMainAspect()) {
base = headSection.getNextRunningSectionOf(trainRight);
} else {
Signal trdSignal = headSection.getSignalOf(!trainRight);
if (Objects.nonNull(trdSignal) && trdSignal.isMainAspect()) {
right = !trainRight;
base = headSection.getNextRunningSectionOf(right);
}
}
} else if (stop) {
// 列车停车中
Signal trdSignal = headSection.getSignalOf(!trainRight);
if (Objects.nonNull(trdSignal) && trdSignal.isMainAspect()) {
right = !trainRight;
}
if (headSection.isNormalStandTrack() || headSection.isTransferTrack()) {
float stopPointOffset = headSection.getStopPointByDirection(right);
SectionPosition standPosition = new SectionPosition(headSection, stopPointOffset);
if (headPosition.isAheadOf(standPosition, right)) {
base = headSection.getNextRunningSectionOf(right);
}
}
}
int count = 0;
while (Objects.nonNull(base)) {
if ((base.isNormalStandTrack() || base.isTransferTrack())) {
nextTarget = base;
break;
}
Signal signal = base.getSignalOf(right);
if (Objects.nonNull(signal) && !signal.isMainAspect()) {
nextTarget = base;
break;
}
Section section = base.getNextRunningSectionOf(right);
if (Objects.isNull(section)) {
nextTarget = base;
break;
} else {
base = section;
}
if (count > 20) {
log.warn(String.format("人工列车[%s]前方20个区段都通畅", train.getGroupNumber()));
break;
}
++count;
}
break;
}
case HEAD: {
String destinationCode = train.getDestinationCode();
if (!stop) {
if (train.isParking()) {
// 站台停站状态取消
this.atsStandService.trainLeaveStand(headSection);
// 更新列车实际离开信息
train.updateLeaveInfo(headSection, systemTime);
}
} else {
/* 判断是否需要更新下一目标区段 */
if (trainRight == null)
return;
Map<String, DestinationCodeDefinition> destinationMap = repository.getDestinationMap();
if (CollectionUtils.isEmpty(destinationMap))
return;
DestinationCodeDefinition destDefinition = destinationMap.get(destinationCode);
if (destDefinition == null) {
log.error("地图[{}}]目的地码[{}]不存在", simulation.getBuildParams().getMap().getName(), destinationCode);
return;
}
Section destSection = destDefinition.getSection();
if (headSection.equals(destSection)) { //列车已到达目的地区段
VirtualRealityTrain vrTrain = repository.getOnlineTrainBy(train.getGroupNumber());
if (vrTrain.isStopAtThePosition(new SectionPosition(destSection, destSection.getStopPointByDirection(trainRight)))) {
if (repository.getConfig().isSetManualWhenHeadTrainArriveTarget()) {
setManualTrain(simulation, vrTrain.getGroupNumber());
}
return;
}
}
if (targetSection != null) {
SectionPosition targetPosition = new SectionPosition(targetSection, targetSection.getStopPointByDirection(trainRight));
// TODO: 2021/5/28 这里列车越过目标停车点的判断逻辑不严谨如果开过头并换端了以此逻辑判断并不正确
SectionPosition minStopPosition = CalculateService
.calculateNextPositionByStartAndLen(targetPosition, !trainRight, SimulationConstants.PARK_POINT_MAX_OFFSET);
if (!headPosition.isAheadOf(minStopPosition, trainRight)) //没有越过最小停车位置
return;
}
/* 寻找下一目标区段 */
nextTarget = findNextTarget4HeadTrain(simulation, train, repository, headSection, headStation, destDefinition);
/* 判断换端并更新目标 */
if (nextTarget != null) {
if (nextTarget.getCode().equals(estimatedArriveStandTrack)) {
return;
}
boolean isPark = true;
if (repository.getConfig().isNoParkingServiceNumber(train.getServiceNumber())) {
isPark = false;
}
if (!nextTarget.isAheadOf(repository, headSection, trainRight)) //下一目标区段不在当前车头方向的前方
atpService.turnDirectionImmediately(repository.getOnlineTrainBy(train.getGroupNumber())); //调头
SectionPosition stopPosition = new SectionPosition(nextTarget, nextTarget.getStopPointByDirection(trainRight));
Float distance = CalculateService.calculateDistance(headPosition, stopPosition, trainRight);
if (distance == null) {
distance = CalculateService.calculateDistance(headPosition, stopPosition, !trainRight);
}
if (distance != null) {
runningTime = (int) (distance / (45 / 3.6));
}
train.updateEstimatedArriveInfo(nextTarget, simulation.getSystemTime().plusSeconds(runningTime).toLocalTime());
this.onboardAtpApiService.updateNextStation(simulation, train.getGroupNumber(),
nextTarget.getStation().getCode(), nextTarget.getCode(), runningTime, isPark);
}
}
break;
}
}
if (Objects.nonNull(nextTarget)) {
//非计划车跟踪目标轨
train.setPlanStandTrack(nextTarget.getCode());
String standTrackCode = null;
if (train.isParking()) {
standTrackCode = train.getActualArriveStandTrack();
}
if (!stop) {
standTrackCode = estimatedArriveStandTrack;
}
if (standTrackCode == null) {
return;
}
boolean jump = this.atsStandService.isJump(repository.getByCode(standTrackCode, Section.class),
train.getGroupNumber());
boolean hold = this.atsStandService.isHoldTrain(repository.getByCode(standTrackCode, Section.class));
// 更新跳停状态
if (!Objects.equals(train.isJump(), jump)) {
if (jump) {
this.onboardAtpApiService.setJump(simulation, train.getGroupNumber());
} else {
this.onboardAtpApiService.cancelJump(simulation, train.getGroupNumber());
}
}
// 更新扣车状态
if (!Objects.equals(train.isHold(), hold)) {
if (hold) {
this.onboardAtpApiService.standHoldTrain(simulation, train.getGroupNumber());
} else {
this.onboardAtpApiService.standCancelHoldTrain(simulation, train.getGroupNumber());
}
}
}
}
/**
* 寻找头码车的下一个目标区段
*/
public static Section findNextTarget4HeadTrain(Simulation simulation, TrainInfo train, SimulationDataRepository repository, Section headSection,
Station headStation, DestinationCodeDefinition destinationCodeDefinition) {
Section nextTarget = null;
Boolean destinationRight = destinationCodeDefinition.getRight();
switch (destinationCodeDefinition.getType()) {
case NORMAL_OPERATION: {
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget != null) {
break;
}
Station leftStation = destinationCodeDefinition.getLeftStation();
Station rightStation = destinationCodeDefinition.getRightStation();
if (destinationCodeDefinition.isBorder(headStation)) { //到达边界车站
boolean rightEnd = headStation.equals(rightStation); //是否右端车站
if (headSection.isNormalStandTrack()) {
boolean standRight = headStation.isStandOfSectionRight(headSection); //是否是右行站台
if (rightEnd == standRight && !destinationCodeDefinition.isFrontTurnBack(headStation)) { //需要站后折返
//查询目的地码定义指定的折返轨
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isTurnBackTrack() && !section.isStandTrack() && section.getStation().equals(headStation))
.findAny().orElse(null);
//查询车站指定的折返轨
if (nextTarget == null) {
if (!CollectionUtils.isEmpty(headStation.getTbStrategyMap()) && headStation.getTbStrategyId() != null) {
StationTurnBackStrategyOption strategy = headStation.getCurrentTurnBackStrategy();
Section tbSection = strategy.getSectionList().get(0);
switch (strategy.getType()) {
case FIRST:
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, tbSection, standRight, 10);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = tbSection;
}
break;
case ONLY:
nextTarget = tbSection;
break;
}
}
}
//随意选择能用的折返轨
if (nextTarget == null) {
for (Section section : headStation.getTurnBackList()) {
if (section.isNormalStandTrack()) {
continue;
}
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, section, standRight, 10);
if (routePaths.stream().anyMatch(path -> !path.isOccupied())) {
nextTarget = section;
break;
}
}
}
} else { //站前折返或已到站后折返轨
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, !rightEnd);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(adjacentStation,
String.format("%s的%s侧相邻车站不存在", headStation.debugStr(), rightEnd ? "" : ""));
nextTarget = adjacentStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else if (headSection.isTurnBackTrack()) { //认为是站后折返轨
nextTarget = headStation.getNormalStand(!rightEnd).get(0).getSection();
}
} else { //不在边界车站
if (!headSection.isNormalStandTrack()) { //认为此时列车一定在站台轨如果是在折返轨不好处理故略过
break;
}
boolean standRight = headStation.isStandOfSectionRight(headSection);
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, standRight);
if (destinationCodeDefinition.isBorder(adjacentStation)) {
if (destinationCodeDefinition.isFrontTurnBack(adjacentStation)) {
nextTarget = destinationCodeDefinition.getNecessarySections().stream()
.filter(section -> section.isStandTrack() && adjacentStation.equals(section.getStation()))
.limit(1).findAny().orElse(null);
if (nextTarget != null) {
break;
}
nextTarget = adjacentStation.getNormalStand(!standRight).get(0).getSection();
if (CollectionUtils.isEmpty(CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, standRight, 10))) {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
} else {
nextTarget = adjacentStation.getNormalStand(standRight).get(0).getSection();
}
}
break;
}
case LAST_OPERATION:
case NON_OPERATION:
case LAST_NON_OPERATION:
nextTarget = destinationCodeDefinition.queryNextTargetSection(headSection);
if (nextTarget == null) {
nextTarget = headStation.getNormalStand(destinationRight).get(0).getSection();
if (!headSection.equals(nextTarget)) {
List<RoutePath> routePaths = CalculateService.queryRoutePathsOnDirection(headSection, nextTarget, destinationRight, 10);
if (!CollectionUtils.isEmpty(routePaths)) {
break;
}
}
Station adjacentStation = simulation.getRepository().findAdjacentStation(headStation, destinationRight);
nextTarget = adjacentStation.getNormalStand(destinationRight).get(0).getSection();
}
break;
case OTHER:
List<Section> path = train.getHctPath().getSections();
if (path != null) {
int index = path.indexOf(headSection);
if (index == -1) {
break;
}
for (int i = index + 1; i < path.size(); i++) {
Section section = path.get(i);
if (section.isSpecialSection()) {
List<RoutePath> routePaths = repository.queryRoutePathsByEnd(section);
if (routePaths.stream().anyMatch(rp -> rp.containsSection(headSection))) {
nextTarget = section;
break;
}
}
}
if (nextTarget == null) {
nextTarget = path.get(path.size() - 1);
}
}
break;
}
return nextTarget;
}
/**
* 扣车
*/
@ -772,7 +425,7 @@ public class AtsTrainService {
if (distance == null) {
throw new SimulationException(SimulationExceptionType.Illegal_Argument, "无法到达的位置");
}
targetPosition = CalculateService.calculateNextPositionByStartAndLen(train.getHeadPosition(), right, distance);
targetPosition = CalculateService.calculateNextPositionByStartAndLen(train.getHeadPosition(), right, distance, false);
} else {
targetPosition = new SectionPosition(section, section.getStopPointByDirection(right));
}
@ -783,7 +436,7 @@ public class AtsTrainService {
VirtualRealityTrain targetTrain = repository.getVRByCode(targetDeviceCode, VirtualRealityTrain.class);
SectionPosition targetTrainTailPosition = targetTrain.calculateTailPosition();
boolean targetIsRight = targetTrain.isRight();
targetPosition = CalculateService.calculateNextPositionByStartAndLen(targetTrainTailPosition, !targetIsRight, 2);
targetPosition = CalculateService.calculateNextPositionByStartAndLen(targetTrainTailPosition, !targetIsRight, 2, false);
}
SectionPosition physicalPosition = targetPosition.convert2PhysicalSectionPosition();
train.setRobotTargetPosition(physicalPosition);

View File

@ -86,6 +86,8 @@ public class AtsHeadTrainStageService implements AtsStageService {
* 处理列车到达目的地
*/
private void handleArriveDestination(Simulation simulation, TrainInfo trainInfo) {
// 先回库后设置为人工车
trainInfo.finishPlanPrepareInbound();
if (simulation.getRepository().getConfig().isSetManualWhenHeadTrainArriveTarget()) {
atsTrainService.setManualTrain(simulation, trainInfo.getGroupNumber());
}

View File

@ -41,11 +41,15 @@ public class AtsPlanTrainStageService implements AtsStageService {
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
List<RoutePath> routePathList = repository.queryRoutePathsByEnd(parkSection);
if (routePathList.get(0).isRight() == trainInfo.getRight()) { //准备回库
trainInfo.finishPlanPrepareInbound();
if (!parkSection.isTurnBackTrack()) { //针对上饶沙盘
trainInfo.finishPlanPrepareInbound();
}
} else if (tripPlan.getEndSection().equals(parkSection) ||
tripPlan.getEndSection().getStation().equals(parkSection.getStation())) {
// 列车到达计划终点准备回库
trainInfo.finishPlanPrepareInbound();
if (!parkSection.isTurnBackTrack()) { //针对上饶沙盘
trainInfo.finishPlanPrepareInbound();
}
} else if (tripPlan.getStartSection().equals(parkSection)) {
// 出库列车
if (trainInfo.getPlanStandTrack() != null) {

View File

@ -75,7 +75,9 @@ public class AtsTrainStageHandler {
this.onboardAtpApiService.departure(simulation, trainInfo.getGroupNumber());
}
} else { // 折返轨
stageService.handleTurnBackTrackParking(simulation, trainInfo, parkSection);
if (!(parkSection.getStation() != null && parkSection.getStation().isDepot())) { //上饶
stageService.handleTurnBackTrackParking(simulation, trainInfo, parkSection);
}
}
if (!trainInfo.isStop()) {
trainInfo.updateParking(false);

View File

@ -15,9 +15,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -246,21 +244,23 @@ public class CiApiServiceImpl2 implements CiApiService {
@Override
public void switchSectionFaultUnlock(Simulation simulation, String switchCode) {
Switch aSwitch = simulation.getRepository().getByCode(switchCode, Switch.class);
if (!aSwitch.isLocked() && aSwitch.getAllSections().stream().noneMatch(Section::isFaultLock))
if (!aSwitch.isLocked() && aSwitch.getAllSections().stream().noneMatch(Section::isLocked))
return;
List<Route> lockedRouteList = simulation.getRepository().queryAllLockedRoute();
Route lockedRoute = null;
Set<Route> lockSwitchRoutes = new HashSet<>();
if (aSwitch.isRouteLock()) {
lockedRoute = aSwitch.getRoute();
lockSwitchRoutes = aSwitch.getRoutes();
} else if (aSwitch.isOverlapLock()) {
for (Route route : lockedRouteList) {
if (route.overlapContainSwitch(aSwitch)) {
lockedRoute = route;
lockSwitchRoutes.add(route);
break;
}
}
}
this.routeService.switchFaultUnlock(simulation, aSwitch, lockedRoute);
for (Route lockedRoute : lockSwitchRoutes) {
this.routeService.switchFaultUnlock(simulation, aSwitch, lockedRoute);
}
}
@Override

View File

@ -44,7 +44,7 @@ public class CiRouteService {
}
}
// 进路中道岔没有被征用或锁定在相反位置
Route.CheckFailMessage failMessage = setSwitchCheck(route.getSwitchList());
Route.CheckFailMessage failMessage = setSwitchCheck(simulation, route.getSwitchList());
if (failMessage != null) {
return failMessage;
}
@ -110,7 +110,7 @@ public class CiRouteService {
RouteOverlap overlap = route.getOverlap();
if (Objects.nonNull(overlap)) {
SectionPath sectionPath = overlap.selectPath();
failMessage = setSwitchCheck(sectionPath.getSwitchList());
failMessage = setSwitchCheck(simulation, sectionPath.getSwitchList());
}
}
return failMessage;
@ -133,7 +133,7 @@ public class CiRouteService {
return null;
}
private static Route.CheckFailMessage setSwitchCheck(List<SwitchElement> switchList) {
private static Route.CheckFailMessage setSwitchCheck(Simulation simulation, List<SwitchElement> switchList) {
if (switchList != null) {
for (SwitchElement switchElement : switchList) {
Switch aSwitch = switchElement.getASwitch();
@ -147,6 +147,13 @@ public class CiRouteService {
if (aSwitch.isCiUseOnOppositePosition(switchElement.isNormal())) { // 道岔征用在相反位置
return new Route.CheckFailMessage(Route.CheckFailReason.SwitchCiUseOnOppositePosition, aSwitch);
}
// 非预先锁闭道岔相应位置失表则不排进路
if (!simulation.getRepository().getConfig().isLockFirst() && aSwitch.isLoss()) {
if ((Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault()) && switchElement.isNormal())
|| (Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault()) && !switchElement.isNormal())) {
return new Route.CheckFailMessage(Route.CheckFailReason.SwitchFault, aSwitch);
}
}
}
}
return null;
@ -310,12 +317,19 @@ public class CiRouteService {
return;
}
if (section.isSwitchTrack()) {
//解锁道岔
Switch relSwitch = section.getRelSwitch();
relSwitch.routeUnlock(route);
//解锁道岔侧防
RouteFls routeFls = route.queryRouteFlsOfSwitch(relSwitch);
if (routeFls != null) {
routeFls.unlock();
}
//解锁联动道岔
Switch linkedSwitch = relSwitch.queryLinkedSwitch();
if (linkedSwitch != null) {
linkedSwitch.routeUnlock(route);
}
} else {
section.routeUnlocking(route);
}

View File

@ -27,11 +27,23 @@ public class CiService {
if (overlap.getSection().isRouteLock()) {
SectionPath sectionPath = overlap.selectPath();
for (SwitchElement switchElement : sectionPath.getSwitchList()) {
if (switchElement.getASwitch().isLocked() && !switchElement.isOnPosition()) {
Switch aSwitch = switchElement.getASwitch();
if (aSwitch.isLocked() && !switchElement.isOnPosition()) {
log.debug("延续保护进路[{}]道岔[{}]锁闭在相反位置,不触发办理", overlap.debugStr(),
switchElement.getASwitch().debugStr());
aSwitch.debugStr());
return;
}
// 非预先锁闭道岔相应位置失表则不排延续保护
if (!simulation.getRepository().getConfig().isLockFirst() && aSwitch.isLoss()) {
if ((Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())
&& switchElement.isNormal())
|| (Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())
&& !switchElement.isNormal())) {
log.debug("延续保护进路[{}]道岔[{}]位置失表,不触发办理", overlap.debugStr(),
aSwitch.debugStr());
return;
}
}
}
overlap.startSetting(simulation.getSystemTime());
}

View File

@ -17,10 +17,11 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.heb.device.Heb1Ps
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.richor.ZjdIbpConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.richor.ZjdPslConfig;
import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.xty.XtyPsdConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSectionConfig;
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.UDPRealDeviceThread;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrTrainConfig;
import club.joylink.rtss.simulation.cbtc.event.SimulationUserEnterEvent;
import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
@ -161,6 +162,8 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
return ((SrSectionConfig) config).getConfigVO().getVrCode();
case SWITCH:
return ((SrSwitchConfig) config).getConfigVO().getVrCode();
case TRAIN:
return ((SrTrainConfig) config).getConfigVO().getVrCode();
}
}
}

View File

@ -1291,7 +1291,8 @@ public class MapDeviceBuilder {
}
elementMap.put(station.getCode(), station);
station.setCentralized(stationVO.isCentralized());
if (station.isCentralized()) {
station.setDepot(stationVO.isDepot());
if (station.isCentralized() && !station.isDepot()) {
ZC zc = (ZC) elementMap.get(stationVO.getZcCode());
if (Objects.isNull(zc)) {
errMsgList.add(String.format("车站[%s(%s)]未关联ZC或ZC不存在请在ZC设备处选择管理的集中站列表", station.getName(), station.getCode()));

View File

@ -516,6 +516,9 @@ public class CommandBO {
public Step execute(Simulation simulation, CommandBO command) {
SimulationMember driver = command.getTargetMember();
VirtualRealityTrain train = (VirtualRealityTrain) driver.getDevice();
if (!train.isAtpOn()) {
return buildDriverATPChangeOperationStep(train.getGroupNumber(), false);
}
if (train.isSignalEB()) {
return getStep4ReleaseEB(train);
}
@ -531,6 +534,27 @@ public class CommandBO {
}
return null;
}
},
/**
* 转NRM模式
*/
Apply_NRM(List.of(), SimulationMember.Type.DRIVER) {
@Override
public List<Step> buildStepList(Simulation simulation, SimulationMember targetMember, Map<String, Object> params) {
return Collections.emptyList();
}
@Override
public Step execute(Simulation simulation, CommandBO command) {
SimulationMember driver = command.getTargetMember();
VirtualRealityTrain train = (VirtualRealityTrain) driver.getDevice();
if (train.isNRMMode()) {
driver.setCommand(null);
return null;
}
return buildDriverATPChangeOperationStep(train.getGroupNumber(), true);
}
};
public enum ParamName {
@ -754,7 +778,7 @@ public class CommandBO {
} else {
return buildPreselectionModeDownOperationStep(groupNumber);
}
} else if (ConfirmationMessage.Confirm_Preselection.equals(train.findFirstMessage())) {
} else /*if (ConfirmationMessage.Confirm_Preselection.equals(train.findFirstMessage()))*/ {
return buildConfirmOperationStep(groupNumber);
}
}

View File

@ -17,7 +17,7 @@ import java.util.*;
@Slf4j
public class CalculateService {
public static SectionPosition getAvailableSectionPositionOf(SectionPosition sectionPosition) {
public static SectionPosition getAvailableSectionPositionOf(SectionPosition sectionPosition, boolean baseReal) {
if (!sectionPosition.isAvailable()) {
float offset = sectionPosition.getOffset();
Section baseSection = sectionPosition.getSection();
@ -25,7 +25,12 @@ public class CalculateService {
while (offset < 0 || offset > baseSection.getLen()) {
++count;
if (offset < 0) { // 向左
Section leftSection = baseSection.getNextRunningSectionOf(false);
Section leftSection;
if (baseReal) {
leftSection = baseSection.getNextRunningSectionBaseRealSwitch(false);
} else {
leftSection = baseSection.getNextRunningSectionOf(false);
}
if (Objects.nonNull(leftSection)) { // 左区段存在
offset = leftSection.getLen() + offset;
baseSection = leftSection;
@ -34,7 +39,12 @@ public class CalculateService {
offset = 0;
}
} else { // 向右
Section rightSection = baseSection.getNextRunningSectionOf(true);
Section rightSection;
if (baseReal) {
rightSection = baseSection.getNextRunningSectionBaseRealSwitch(true);
} else {
rightSection = baseSection.getNextRunningSectionOf(true);
}
if (Objects.nonNull(rightSection)) { // 右向区段存在
offset = offset - baseSection.getLen();
baseSection = rightSection;
@ -61,13 +71,13 @@ public class CalculateService {
* 根据开始位置方向距离计算到达的位置不会超出正线轨道范围不会冲过位置不合适道岔
*/
public static SectionPosition calculateNextPositionByStartAndLen(SectionPosition startPosition,
boolean right, float len) {
boolean right, float len, boolean baseReal) {
if (!right) {
len = -len;
}
float offset = startPosition.getOffset();
float offsetNew = offset + len;
return getAvailableSectionPositionOf(new SectionPosition(startPosition.getSection(), offsetNew));
return getAvailableSectionPositionOf(new SectionPosition(startPosition.getSection(), offsetNew), baseReal);
}
/**
@ -509,7 +519,7 @@ public class CalculateService {
Section section = source;
while (!section.getCode().equals(target.getCode()) && loop < 20) {
loop++;
Section temp = section.getNextRunningSectionOf(right);
Section temp = section.getNextRunningSectionBaseRealSwitch(right);
if (Objects.nonNull(temp)) { // 不为空
section = temp;
occupySectionList.add(section);
@ -1010,7 +1020,7 @@ public class CalculateService {
this.headPosition = train.getHeadPosition();
this.right = train.isRight();
this.tailPosition = CalculateService
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen());
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), false);
}
/**
@ -1020,7 +1030,7 @@ public class CalculateService {
this.headPosition = train.getHeadPosition();
this.right = train.isRight();
this.tailPosition = CalculateService
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen() + append);
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen() + append, false);
}
}

View File

@ -802,6 +802,22 @@ public class SimulationDataRepository {
return next;
}
public TripPlan findNextTripPlan(TripPlan tripPlan) {
Section endSection = tripPlan.getEndSection();
List<TripPlan> planList = this.endTripMap.get(endSection.getCode());
TripPlan next = null;
if (!CollectionUtils.isEmpty(planList)) {
for (TripPlan plan : planList) {
if (plan.isDeparture()) {
continue;
}
next = plan;
break;
}
}
return next;
}
/**
* 此方法只能用于计划车次号唯一的线路比如西门子风格的运行计划
* @param tripNumber

View File

@ -10,10 +10,7 @@ import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
/**
* 区段
@ -363,7 +360,7 @@ public class Section extends DelayUnlockDevice {
} else { // B或C
if (right && a.getLeftSection() != null) {
return this.rightSection;
} else if(!right && a.getRightSection() != null) {
} else if (!right && a.getRightSection() != null) {
return this.leftSection;
} else if ((relSwitch.isPosN() && relSwitch.isB(this)) ||
(relSwitch.isPosR() && relSwitch.isC(this))) {
@ -463,6 +460,9 @@ public class Section extends DelayUnlockDevice {
public void axleCounterOccupy(boolean right) {
this.trainRight = right;
this.setNctOccupied(true);
if (isSwitchAxleCounterSection()) {
nctOccupiedBySwitchPosition();
}
}
/**
@ -764,10 +764,19 @@ public class Section extends DelayUnlockDevice {
}
public void nonCommunicateTrainOccupy(boolean right) {
this.trainRight = right;
this.setNctOccupied(true);
// this.nctOccupied = true;
// setCtOccupied(false);
VirtualRealitySectionAxleCounter axle = findAxle();
if (axle != null && axle.isOccupy()) {
this.trainRight = right;
this.setNctOccupied(true);
}
}
public VirtualRealitySectionAxleCounter findAxle() {
VirtualRealitySectionAxleCounter axle = this.virtualAxleCounter;
if (axle == null && this.parent != null) {
return this.parent.findAxle();
}
return axle;
}
public boolean isOccupiedOn(boolean right) {
@ -813,24 +822,7 @@ public class Section extends DelayUnlockDevice {
}
this.setNctOccupied(true);
if (this.isSwitchAxleCounterSection()) { // 道岔计轴区段
List<Switch> relSwitchList = this.getRelSwitchList();
for (Switch aSwitch : relSwitchList) {
aSwitch.getA().setNctOccupied(true);
if (aSwitch.isPosN()) {
aSwitch.getB().setNctOccupied(true);
aSwitch.getC().setNctOccupied(false);
} else if (aSwitch.isPosR()) {
aSwitch.getC().setNctOccupied(true);
aSwitch.getB().setNctOccupied(false);
} else {
aSwitch.getB().setNctOccupied(true);
aSwitch.getC().setNctOccupied(true);
}
}
Section cross = queryCross();
if (cross != null) {
cross.crossJudgeInvalid();
}
nctOccupiedBySwitchPosition();
} else if (!CollectionUtils.isEmpty(this.logicList)) {
for (Section logic : this.logicList) {
logic.setNctOccupied(true);
@ -838,6 +830,30 @@ public class Section extends DelayUnlockDevice {
}
}
/**
* 根据道岔位置设置非通信车占用
*/
private void nctOccupiedBySwitchPosition() {
List<Switch> relSwitchList = this.getRelSwitchList();
for (Switch aSwitch : relSwitchList) {
aSwitch.getA().setNctOccupied(true);
if (aSwitch.isPosN()) {
aSwitch.getB().setNctOccupied(true);
aSwitch.getC().setNctOccupied(false);
} else if (aSwitch.isPosR()) {
aSwitch.getC().setNctOccupied(true);
aSwitch.getB().setNctOccupied(false);
} else {
aSwitch.getB().setNctOccupied(true);
aSwitch.getC().setNctOccupied(true);
}
}
Section cross = queryCross();
if (cross != null) {
cross.crossJudgeInvalid();
}
}
/**
* 岔心判断失效
*/
@ -1092,7 +1108,7 @@ public class Section extends DelayUnlockDevice {
if (!CollectionUtils.isEmpty(zcs)) {
return zcs.stream().anyMatch(zc -> !zc.isFault());
}
return true;
return false;
}
public void setInvalid(boolean invalid) {
@ -1168,6 +1184,31 @@ public class Section extends DelayUnlockDevice {
return false;
}
/**
* 获取道岔计轴区段被道岔连接起来的区段
*/
public List<Section> findConnectedSections() {
if (!isSwitchAxleCounterSection())
return Collections.emptyList();
Switch relSwitch = getLogicList().get(0).getRelSwitch();
List<Section> sections = new ArrayList<>();
sections.add(relSwitch.getA());
if (relSwitch.isPosN()) {
sections.add(relSwitch.getB());
} else if (relSwitch.isPosR()) {
sections.add(relSwitch.getC());
}
return sections;
}
public Section findPhysicalSection() {
if (this.isPhysical())
return this;
if (this.parent != null)
return this.parent.findPhysicalSection();
return null;
}
public enum SectionRoadType {
/**
* 左行线

View File

@ -440,6 +440,10 @@ public class Signal extends DelayUnlockDevice {
return SignalType.TRANSMISSION.equals(this.type);
}
public boolean isOutboundSignal() {
return SignalType.OUTBOUND.equals(this.type);
}
public boolean isDepotSameSignal(Signal signal) {
return this.type.equals(signal.getType())
|| (this.type.equals(SignalType.SHUNTING2) && signal.getType().equals(SignalType.SHUNTING));

View File

@ -5,9 +5,7 @@ import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch;
import lombok.Getter;
import lombok.Setter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -74,7 +72,7 @@ public class Switch extends DelayUnlockDevice {
/**
* 锁闭该道岔的进路
*/
private Route route;
private final Set<Route> routes = new HashSet<>();
/**
* 是否进路侧防锁闭
@ -141,7 +139,7 @@ public class Switch extends DelayUnlockDevice {
this.blockade = false;
this.usePosition = No_Use;
this.routeLock = false;
this.route = null;
this.routes.clear();
this.fpLock = false;
this.overlapLock = false;
this.masterGuideLock = false;
@ -207,22 +205,22 @@ public class Switch extends DelayUnlockDevice {
public void routeLock(Route route) {
this.routeLock = true;
this.route = route;
this.routes.add(route);
}
public void routeUnlock(Route route) {
if (this.isRouteLockBy(route)) {
this.a.routeUnlocking(this.route);
this.b.routeUnlocking(this.route);
this.c.routeUnlocking(this.route);
this.routeLock = false;
this.route = null;
this.a.routeUnlocking(route);
this.b.routeUnlocking(route);
this.c.routeUnlocking(route);
this.routes.remove(route);
this.routeLock = !this.routes.isEmpty();
this.checkAndResetUsePosition();
}
}
public boolean isRouteLockBy(Route route) {
return this.routeLock && this.route.equals(route);
return this.routeLock && this.routes.contains(route);
}
private void checkAndResetUsePosition() {
@ -393,7 +391,9 @@ public class Switch extends DelayUnlockDevice {
}
public void faultUnlock() {
this.routeUnlock(this.route);
for (Route route : routes) {
this.routeUnlock(route);
}
this.overlapUnLock();
this.fpUnlock();
}

View File

@ -1,6 +1,7 @@
package club.joylink.rtss.simulation.cbtc.data.storage;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.build.RunPlanBuilder;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan;
@ -18,6 +19,7 @@ import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -379,8 +381,12 @@ public class StorageSimulationDataRepository {
// 恢复服务-车次计划列表map
if (!CollectionUtils.isEmpty(this.serviceTripList)) {
List<TripPlan> plans = StorageTripPlan.convert2SimulationObjList(repository, this.serviceTripList);
Map<String, List<TripPlan>> tripPlanMap = plans.stream().collect(Collectors.groupingBy(TripPlan::getServiceNumber));
repository.setServiceTripsMap(tripPlanMap);
RunPlanBuilder.RunPlanBuildResult runPlanBuildResult = new RunPlanBuilder.RunPlanBuildResult();
plans.forEach(runPlanBuildResult::addTripPlan);
runPlanBuildResult.sort();
repository.setServiceTripsMap(runPlanBuildResult.getServerTripMap());
repository.setStandTripMap(runPlanBuildResult.getStandTripMap());
repository.setEndTripMap(runPlanBuildResult.getEndTripMap());
// for (StorageTripPlan storageTripPlan : this.serviceTripList) {
// TripPlan tripPlan = repository.getTripPlan(storageTripPlan.getServiceNumber(), storageTripPlan.getTripNumber());
// tripPlan.use();

View File

@ -14,6 +14,11 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Getter
@Setter
@ -43,6 +48,8 @@ public class StorageSwitch extends StorageDelayUnlockDevice {
private String route;
private Set<String> routes;
/**
* 是否进路侧防锁闭
*/
@ -95,10 +102,16 @@ public class StorageSwitch extends StorageDelayUnlockDevice {
change = true;
storageSwitch.setRouteLock(s.isRouteLock());
}
Route route = s.getRoute();
if (route != null) {
// Route route = s.getRoutes();
// if (route != null) {
// change = true;
// storageSwitch.setRoute(route.getCode());
// }
Set<Route> routes = s.getRoutes();
if (!CollectionUtils.isEmpty(routes)) {
change = true;
storageSwitch.setRoute(route.getCode());
Set<String> routeCodes = routes.stream().map(MapElement::getCode).collect(Collectors.toSet());
storageSwitch.setRoutes(routeCodes);
}
if (s.isFpLock()) {
change = true;
@ -141,7 +154,18 @@ public class StorageSwitch extends StorageDelayUnlockDevice {
s.setSingleLock(singleLock != null ? singleLock : false);
s.setBlockade(blockade != null ? blockade : false);
s.setRouteLock(routeLock != null ? routeLock : false);
s.setRoute(route == null ? null : repository.getByCode(route, Route.class));
if (route != null) {
Route route = repository.getByCode(this.route, Route.class);
s.getRoutes().add(route);
} else if (!CollectionUtils.isEmpty(routes)) {
for (String code : routes) {
Route route = repository.getByCode(code, Route.class);
s.getRoutes().add(route);
}
} else {
s.getRoutes().clear();
}
// s.setRoutes(route == null ? null : repository.getByCode(route, Route.class));
s.setOverlapLock(overlapLock != null ? overlapLock : false);
s.setMasterGuideLock(masterGuideLock != null ? masterGuideLock : false);
if (pos != null) {

View File

@ -11,9 +11,6 @@ import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
import lombok.Getter;
import lombok.Setter;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Objects;
/**
@ -99,7 +96,7 @@ public class MovementAuthority {
case CLOSED_STAND:{
Section section = baseSection;
SectionPosition stopPosition = new SectionPosition(section, section.getStopPointByDirection(right));
return CalculateService.calculateNextPositionByStartAndLen(stopPosition, !right, 180);
return CalculateService.calculateNextPositionByStartAndLen(stopPosition, !right, 180, false);
}
case CLOSED_SIGNAL: {
Signal signal = (Signal) this.device;
@ -117,10 +114,10 @@ public class MovementAuthority {
section = section.getParent();
SectionPosition sectionPosition = new SectionPosition(section, offset);
if (section.isStandTrack() && section.getStandList().get(0).isTrainParking()) {
return CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 10);
return CalculateService.calculateNextPositionByStartAndLen(sectionPosition, !right, 10, false);
} else {
return CalculateService.calculateNextPositionByStartAndLen(sectionPosition,
!right, 2 * SimulationConstants.TRAIN_SAFE_DISTANCE);
!right, 2 * SimulationConstants.TRAIN_SAFE_DISTANCE, false);
}
// VirtualRealityTrain train = (VirtualRealityTrain) this.device;
@ -154,7 +151,7 @@ public class MovementAuthority {
Section section = this.baseSection;
float offset = right ? section.getLen() : 0;
SectionPosition stopPosition = new SectionPosition(section, offset);
return CalculateService.calculateNextPositionByStartAndLen(stopPosition, !right, 100);
return CalculateService.calculateNextPositionByStartAndLen(stopPosition, !right, 100, false);
}
case UNLOCK_SECTION:
case FAULT_SECTION:
@ -197,7 +194,7 @@ public class MovementAuthority {
if (Objects.isNull(this.endPosition)) {
SectionPosition sectionPosition = this.computeEndPosition(right);
if (!sectionPosition.isAvailable()) {
sectionPosition = CalculateService.getAvailableSectionPositionOf(sectionPosition);
sectionPosition = CalculateService.getAvailableSectionPositionOf(sectionPosition, false);
}
this.endPosition = sectionPosition;
}

View File

@ -120,9 +120,9 @@ public class SectionPosition {
public boolean isWithinParkingRange(boolean right) {
SectionPosition targetPosition = new SectionPosition(this.section, this.section.getStopPointByDirection(right));
SectionPosition max = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
right, SimulationConstants.PARK_POINT_MAX_OFFSET);
right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
SectionPosition min = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
!right, SimulationConstants.PARK_POINT_MAX_OFFSET);
!right, SimulationConstants.PARK_POINT_MAX_OFFSET, false);
return this.isAheadOf(min, right) && max.isAheadOf(this, right);
}
}

View File

@ -365,6 +365,9 @@ public class TrainInfo extends MapElement {
public void init(Section section, String dn, String sn, String tn, String cn) {
this.section = section.getCode();
Section ps = section.findPhysicalSection();
if (ps != null)
this.physicalSection = ps.getCode();
this.destinationCode = dn;
this.serviceNumber = sn;
this.tripNumber = tn;
@ -426,6 +429,7 @@ public class TrainInfo extends MapElement {
public boolean isHeadCodeTrain() {
return Objects.equals(this.type, TrainType.HEAD);
}
public boolean isManualTrain() {
return TrainType.MANUAL.equals(this.type);
}

View File

@ -63,6 +63,24 @@ public class VirtualRealityScreenDoor extends ControllableVrDevice<VirtualRealit
this.fault = null;
}
@Override
protected boolean checkConditionBeforeControl(Operation command) {
//已是关门到位状态发送关门指令依然会进入转换中状态导致门又开启遂加此限制
switch (command) {
case K:{
if (this.isOpen2End())
return false;
break;
}
case G: {
if (this.isLockAndClose())
return false;
break;
}
}
return true;
}
@Override
protected void doTurn() {
this.setClose(false);

View File

@ -73,13 +73,6 @@ public class VirtualRealitySectionAxleCounter extends VirtualRealityDevice {
}
}
/**
* 判断计轴器的占用情况
*/
private void judgeOccupy() {
this.occupy = leftCount != 0 || rightCount != 0;
}
/**
* 列车车头进入该计轴区段
* @param trainRight 列车运行方向

View File

@ -377,7 +377,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
private boolean backUp;
/**
* 关门后的延迟发车时间单位s
* 关门后的延迟发车时间单位ms
*/
private int delayTime = 0;
@ -766,7 +766,7 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
}
public SectionPosition calculateTailPosition() {
this.tailPosition = CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen());
this.tailPosition = CalculateService.calculateNextPositionByStartAndLen(this.headPosition, !right, this.getLen(), true);
return this.tailPosition;
}
@ -825,9 +825,9 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
SectionPosition headPosition = this.headPosition;
boolean right = this.right;
SectionPosition max = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
right, SimulationConstants.PARK_POINT_MAX_OFFSET);
right, SimulationConstants.PARK_POINT_MAX_OFFSET, true);
SectionPosition min = CalculateService.calculateNextPositionByStartAndLen(targetPosition,
!right, SimulationConstants.PARK_POINT_MAX_OFFSET);
!right, SimulationConstants.PARK_POINT_MAX_OFFSET, true);
return headPosition.isAheadOf(min, right) && max.isAheadOf(headPosition, right);
}
@ -1132,6 +1132,23 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
return isCBTC() && VirtualRealityTrain.DoorMode.AA.equals(doorMode);
}
public void initAsAM_I() {
this.setCommunication(false);
this.setPreselectionMode(PreselectionMode.AM_I);
this.setTempPreselectionMode(this.preselectionMode);
this.setDriveMode(DriveMode.AM);
this.setRunLevel(RunLevel.ITC);
}
public void initAsRM() {
this.setCommunication(false);
this.setPreselectionMode(PreselectionMode.RM);
this.setTempPreselectionMode(this.preselectionMode);
this.setDriveMode(DriveMode.RM);
this.setRunLevel(RunLevel.IL);
this.setAtoOn(false);
}
@Getter
@Setter
public static class Door extends ControllableVrDevice<Door.Operation> {

View File

@ -36,7 +36,7 @@ public class SimulationRealDeviceConnectManager {
public void connectDevice(Simulation simulation, String deviceCode, Long projectDeviceId) {
RealDeviceConfig realDevice = simulation.getRealDeviceById(projectDeviceId);
MapElement mapElement = simulation.getRepository().getByCode(deviceCode);
MapElement mapElement = simulation.getRepository().findByCode(deviceCode);
boolean typeEqual = false;
switch (realDevice.getProjectDevice().getType()) {
case SWITCH:{
@ -102,6 +102,7 @@ public class SimulationRealDeviceConnectManager {
typeEqual = true;
realDevice.connect(vrDevice);
}
vrDevice.updateRealDevice(realDevice);
break;
}
case IBP:{
@ -111,7 +112,18 @@ public class SimulationRealDeviceConnectManager {
}
if (MapElement.DeviceType.IBP.equals(mapElement.getDeviceType())) {
typeEqual = true;
realDevice.connect((VirtualRealityIbp) mapElement);
VirtualRealityIbp vrIbp = (VirtualRealityIbp) mapElement;
realDevice.connect(vrIbp);
vrIbp.updateRealDevice(realDevice);
}
break;
}
case TRAIN:{
VirtualRealityDevice vrDevice = simulation.getRepository().getVRByCode(deviceCode);
if (MapElement.DeviceType.TRAIN.equals(vrDevice.getDeviceType())) {
typeEqual = true;
realDevice.connect(vrDevice);
vrDevice.updateRealDevice(realDevice);
}
break;
}

View File

@ -1,58 +0,0 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
import club.joylink.rtss.constants.ProjectDeviceType;
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 io.netty.buffer.ByteBuf;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class SrSectionServiceImpl implements UDPRealDeviceService {
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof UDPClientConfig;
}
@Override
public void control(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@Override
public void init(Simulation simulation, UDPLowConfig udpConfig, RealDeviceConfig realDevice) {
}
@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, VirtualRealitySectionAxleCounter> map = simulation.queryAllRealDevice(ProjectDeviceType.SECTION).stream()
.map(config -> (SrSectionConfig) config)
.collect(Collectors.toMap(config -> config.getConfigVO().getSandboxCode(),
config -> (VirtualRealitySectionAxleCounter) config.getMapElement()));
for (int i = 3, dataLength = data.length; i < dataLength; i+=2) {
int code = Byte.toUnsignedInt(data[i - 1]);
VirtualRealitySectionAxleCounter axle = map.get(String.valueOf(code));
if (axle != null) {
int n = Byte.toUnsignedInt(data[i]);
if (n == 170) {
axle.setOccupy(true);
} else if (n == 85) {
axle.setOccupy(false);
}
}
}
}
}

View File

@ -0,0 +1,22 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr;
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 {
@NotBlank(message = "车组号不能为空")
private String groupNumber;
@NotNull(message = "方向不能为null")
private Boolean right;
@NotNull(message = "速度不能为null")
private Integer speed;
}

View File

@ -0,0 +1,22 @@
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

@ -1,10 +1,11 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.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.sr.SrSectionConfigVO;
import lombok.Getter;
import lombok.Setter;
import java.util.Objects;
@ -12,6 +13,12 @@ import java.util.Objects;
public class SrSectionConfig extends RealDeviceConfig {
private SrSectionConfigVO configVO;
/**
* 连续无占用次数
*/
@Setter
private int timesOfRelease;
public SrSectionConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {

View File

@ -1,10 +1,13 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config;
import club.joylink.rtss.simulation.cbtc.constant.SignalAspect;
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
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.sr.SrSignalConfigVO;
import lombok.Getter;
import lombok.Setter;
import java.util.Objects;
@ -12,6 +15,9 @@ import java.util.Objects;
public class SrSignalConfig extends RealDeviceConfig {
private SrSignalConfigVO configVO;
@Setter
private SignalAspect aspect;
public SrSignalConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {

View File

@ -1,10 +1,12 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.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.sr.SrSwitchConfigVO;
import lombok.Getter;
import lombok.Setter;
import java.util.Objects;
@ -12,6 +14,8 @@ import java.util.Objects;
public class SrSwitchConfig extends RealDeviceConfig {
private SrSwitchConfigVO configVO;
@Setter
private SwitchIndication p;
public SrSwitchConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {

View File

@ -0,0 +1,51 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.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.sr.SrSwitchConfigVO;
import club.joylink.rtss.vo.client.project.sr.SrTrainConfigVO;
import lombok.Getter;
import lombok.Setter;
import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;
import java.util.Objects;
@Getter
public class SrTrainConfig extends RealDeviceConfig {
private SrTrainConfigVO configVO;
@Setter
private Integer gear;
/**
* 列车需要在这个轨道停车
*/
private Section headSection;
/**
* 列车在headSection停车的时间
*/
@Setter
private LocalDateTime timeOfStop;
/**
* 人为驾驶的档位
*/
@Setter
private Integer manualGear;
public void updateHeadSection(Section headSection) {
this.headSection = headSection;
this.timeOfStop = null;
}
public SrTrainConfig(ProjectDeviceVO projectDevice) {
super(projectDevice);
if (Objects.nonNull(projectDevice.getConfig())) {
this.configVO = JsonUtils.read(projectDevice.getConfig(), SrTrainConfigVO.class);
}
}
}

View File

@ -0,0 +1,192 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service;
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.CalculateService;
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.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.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.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;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
public class SrSectionServiceImpl implements UDPRealDeviceService {
@Autowired
private SrTrainServiceImpl srTrainService;
@Autowired
private MaService maService;
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof UDPClientConfig;
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
}
@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, SrSectionConfig> configMap = simulation.queryAllRealDevice(ProjectDeviceType.SECTION).stream()
.map(config -> (SrSectionConfig) 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);
SrSectionConfig 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) {
updateTrainPosition(simulation, axle);
config.setTimesOfRelease(0);
axle.setOccupy(true);
} else if (n == 85) {
config.setTimesOfRelease(config.getTimesOfRelease() + 1);
if (config.getTimesOfRelease() > 3) { //连续4次该计轴都是无占用状态才视为确实无占用
config.setTimesOfRelease(0);
axle.clear();
}
}
}
}
//设置停车信息
stop(simulation);
}
/**
* 列车到达特殊轨道设置延迟停车时间
*/
private void stop(Simulation simulation) {
for (VirtualRealityTrain train : simulation.getRepository().getOnlineTrainList()) {
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())
continue;
VirtualRealitySectionAxleCounter headAxle = headSection.findAxle();
if (headAxle == null)
continue;
SrSectionConfig sectionConfig = (SrSectionConfig) headAxle.getRealDevice();
//设置延时停车时间
long m = 1000000000;
long nanos;
if (sectionConfig.getConfigVO().getHeadDelayTime() != null) {
nanos = (long) (sectionConfig.getConfigVO().getHeadDelayTime() * m);
config.setTimeOfStop(LocalDateTime.now().plusNanos(nanos));
continue;
}
//以前一个区段无占用作为停车标志的区段
boolean right = train.isRight();
Section behindSection = headSection.getNextRunningSectionOf(!right);
if (behindSection == null)
continue;
VirtualRealitySectionAxleCounter behindAxle = behindSection.findAxle();
if (behindAxle == null)
continue;
if (!behindAxle.isOccupy()) { //车头后方区段所属计轴无占用状态
nanos = 0;
if (sectionConfig.getConfigVO().getTailDelayTime() != null) {
nanos = (long) (sectionConfig.getConfigVO().getTailDelayTime() * m);
}
if (nanos == 0) {
train.setHeadPosition(headSection.buildStopPointPosition(right));
} else {
config.setTimeOfStop(LocalDateTime.now().plusNanos(nanos));
}
}
}
}
private void updateTrainPosition(Simulation simulation, VirtualRealitySectionAxleCounter axle) {
for (Section section : simulation.getRepository().getAxleSectionList()) {
if (section.getVirtualAxleCounter().equals(axle)) {
List<Section> pSection;
if (section.isPhysical()) {
pSection = Collections.singletonList(section);
} else if (section.isSwitchAxleCounterSection()) {
pSection = section.findConnectedSections();
} else {
pSection = Collections.emptyList();
}
for (Section sec : pSection) {
check4UpdateHeadPosition(simulation, sec, false);
check4UpdateHeadPosition(simulation, sec, true);
}
}
}
}
/**
* 检查是否有right向的列车可以更新车头位置
*/
private void check4UpdateHeadPosition(Simulation simulation, Section occupiedSection, boolean right) {
Section section = occupiedSection.getNextRunningSectionOf(!right); //找反向的区段
if (section != null) {
for (VirtualRealityTrain train : simulation.getRepository().getOnlineTrainList()) {
Section headSection = train.getHeadPosition().getSection();
boolean trainRight = train.isRight();
if (trainRight == right && section.equals(headSection)) { //列车到达occupiedSection
//判断更新ITC ma
if (headSection.getSignalOf(trainRight) != null) {
maService.calculateAndUpdateItcMa(simulation, train);
}
//更新位置
SectionPosition headPosition;
SectionPosition stopPointPosition;
if (occupiedSection.isFunctionTrack()) {
stopPointPosition = occupiedSection.buildStopPointPosition(right);
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition, !right, 1, true);
} else {
stopPointPosition = new SectionPosition(occupiedSection, occupiedSection.getEndOffsetByDirection(right));
headPosition = CalculateService.calculateNextPositionByStartAndLen(stopPointPosition, !right, 3, true);
}
train.setHeadPosition(headPosition); //更新位置
if (occupiedSection.isFunctionTrack()) { //功能轨可能需要停车
SrTrainConfig config = (SrTrainConfig) train.getRealDevice();
config.updateHeadSection(occupiedSection);
}
}
}
}
}
}

View File

@ -1,4 +1,4 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SignalAspect;
@ -8,6 +8,7 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDevice
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.sr.config.SrSignalConfig;
import io.netty.buffer.ByteBuf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -25,7 +26,7 @@ public class SrSignalServiceImpl implements UDPRealDeviceService {
}
@Override
public void control(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
SrSignalConfig config = (SrSignalConfig) realDevice;
//控制vr设备
VirtualRealitySignal vrSignal = (VirtualRealitySignal) realDevice.getMapElement();
@ -34,12 +35,12 @@ public class SrSignalServiceImpl implements UDPRealDeviceService {
if (Objects.equals(aspect, command)) {
return;
}
if (vrSignal.getRemain() > 0) {
if (vrSignal.isTurning()) {
vrSignal.turning(SimulationConstants.VRD_LOOP_RATE);
}
//控制沙盘设备
aspect = vrSignal.getAspect();
if (aspect == null || udpLowConfig == null) {
if (aspect == null || udpLowConfig == null || Objects.equals(aspect, config.getAspect())) {
return;
}
byte[] data = buildData(aspect, config);
@ -49,11 +50,11 @@ public class SrSignalServiceImpl implements UDPRealDeviceService {
}
@Override
public void init(Simulation simulation, UDPLowConfig udpConfig, RealDeviceConfig realDevice) {
SrSignalConfig config = (SrSignalConfig) realDevice;
VirtualRealitySignal vrSignal = (VirtualRealitySignal) config.getMapElement();
byte[] data = buildData(vrSignal.getAspect(), config);
udpClient.write(udpConfig.getAddr(), data);
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
// SrSignalConfig config = (SrSignalConfig) realDevice;
// VirtualRealitySignal vrSignal = (VirtualRealitySignal) config.getMapElement();
// byte[] data = buildData(vrSignal.getAspect(), config);
// udpClient.write(udpLowConfig.getAddr(), data);
}
@Override
@ -64,6 +65,7 @@ public class SrSignalServiceImpl implements UDPRealDeviceService {
private byte[] buildData(SignalAspect aspect, SrSignalConfig 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());

View File

@ -1,4 +1,4 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.Sr;
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
@ -8,10 +8,13 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.device.RealDevice
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.sr.config.SrSwitchConfig;
import io.netty.buffer.ByteBuf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class SrSwitchServiceImpl implements UDPRealDeviceService {
@Autowired
@ -23,16 +26,16 @@ public class SrSwitchServiceImpl implements UDPRealDeviceService {
}
@Override
public void control(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
SrSwitchConfig config = (SrSwitchConfig) realDevice;
//控制vr设备
VirtualRealitySwitch vrSwitch = (VirtualRealitySwitch) realDevice.getMapElement();
if (vrSwitch.getRemain() > 0) {
if (vrSwitch.isTurning()) {
vrSwitch.turning(SimulationConstants.VRD_LOOP_RATE);
}
//控制沙盘设备
SwitchIndication p = vrSwitch.getP();
if (p == null || udpLowConfig == null) {
if (p == null || udpLowConfig == null || Objects.equals(p, config.getP())) {
return;
}
byte[] data = buildData(p, config);
@ -42,8 +45,20 @@ public class SrSwitchServiceImpl implements UDPRealDeviceService {
}
@Override
public void init(Simulation simulation, UDPLowConfig udpConfig, RealDeviceConfig realDevice) {
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
// SrSwitchConfig config = (SrSwitchConfig) realDevice;
// //控制vr设备
// VirtualRealitySwitch vrSwitch = (VirtualRealitySwitch) realDevice.getMapElement();
// if (vrSwitch.getRemain() > 0) {
// vrSwitch.turning(SimulationConstants.VRD_LOOP_RATE);
// }
// //控制沙盘设备
// SwitchIndication p = vrSwitch.getP();
// if (p == null || udpLowConfig == null) {
// return;
// }
// byte[] data = buildData(p, config);
// udpClient.write(udpLowConfig.getAddr(), data);
}
@Override
@ -54,6 +69,7 @@ public class SrSwitchServiceImpl implements UDPRealDeviceService {
private byte[] buildData(SwitchIndication p, SrSwitchConfig 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());

View File

@ -0,0 +1,296 @@
package club.joylink.rtss.simulation.cbtc.device.real.udp.sr.service;
import club.joylink.rtss.constants.ProjectDeviceType;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATS.operation.AtsOperationDispatcher;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
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.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
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.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.sr.config.SrTrainConfig;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.simulation.cbtc.onboard.ATO.SpeedCurve;
import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPService;
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.HashMap;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Service
public class SrTrainServiceImpl implements UDPRealDeviceService {
@Autowired
private UDPClient udpClient;
@Autowired
private ATPService atpService;
@Autowired
private AtsOperationDispatcher atsOperationDispatcher;
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private AtsTrainLoadService atsTrainLoadService;
@Override
public boolean isMatch(RealDeviceConfig realDevice) {
return realDevice instanceof SrTrainConfig;
}
@Override
public void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
SrTrainConfig config = (SrTrainConfig) realDevice;
//控制vr设备
VirtualRealityTrain train = (VirtualRealityTrain) config.getMapElement();
SimulationDataRepository repository = simulation.getRepository();
String groupNumber = train.getGroupNumber();
if (repository.isVrTrainOnline(groupNumber)) {
removeVrTrainIfNotSupervised(repository, groupNumber);
if (train.isEB()) {
train.setSpeed(0);
} else {
if (train.getRobotTargetPosition() != null || train.isAMMode()) {
config.setManualGear(null);
}
if (config.getManualGear() == null) {
change2RMWhenStopAtPlanEnd(simulation, train);
trainRunning(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);
}
}
/**
* 如果有监控添加一个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);
}
}
/**
* 当到达计划终点时将列车驾驶模式转为RM
*/
private void change2RMWhenStopAtPlanEnd(Simulation simulation, VirtualRealityTrain train) {
if (!train.isStop())
return;
if (!train.getHeadPosition().getSection().isTransferTrack()) //不是转换轨
return;
SimulationDataRepository repository = simulation.getRepository();
String groupNumber = train.getGroupNumber();
TrainInfo trainInfo = repository.getSupervisedTrainByGroup(groupNumber);
if (!trainInfo.isPlanTrain())
return;
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
if (!Objects.equals(train.getHeadPosition().getSection(), tripPlan.getEndSection())) //不是计划最后一个区段
return;
TripPlan nextTripPlan = repository.queryServiceNextTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
if (nextTripPlan != null)
return;
//无下一计划要回车辆段
VirtualRealityTrain.PreselectionMode preselectionMode = VirtualRealityTrain.PreselectionMode.RM;
VirtualRealityTrain.PreselectionMode trainMode = train.getPreselectionMode();
if (trainMode == preselectionMode) //已是RM
return;
VirtualRealityTrain.PreselectionMode tempMode = train.getTempPreselectionMode();
SimulationMember driver = simulation.getSimulationMembersByDevice(train).get(0);
Map<String, Object> params = new HashMap<>();
String operation;
params.put("groupNumber", groupNumber);
if (tempMode != preselectionMode) { //临时级别不对
if (preselectionMode.isHigherThan(tempMode)) {
operation = Operation.Type.Driver_Preselection_Mode_Up.name();
} else {
operation = Operation.Type.Driver_Preselection_Mode_Down.name();
}
} else {
operation = Operation.Type.Driver_Confirm.name();
}
atsOperationDispatcher.execute(simulation, driver, operation, params);
}
@Override
public void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice) {
SrTrainConfig config = (SrTrainConfig) 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 trainRunning(Simulation simulation, VirtualRealityTrain train, SrTrainConfig config) {
//判断到停车时间将列车位置更新到停车点
boolean right = train.isRight();
SectionPosition headPosition = train.getHeadPosition();
Section headSection = headPosition.getSection();
if (Objects.equals(headSection, config.getHeadSection())) {
LocalDateTime timeOfStop = config.getTimeOfStop();
if (timeOfStop != null && LocalDateTime.now().isAfter(timeOfStop)) {
headPosition = headSection.buildStopPointPosition(right);
train.setHeadPosition(headPosition);
config.updateHeadSection(null);
}
}
//更新速度
SimulationDataRepository repository = simulation.getRepository();
SectionPosition tailPosition = train.calculateTailPosition();
float speed = train.getSpeed();
float newSpeed;
if (train.isAMMode() || train.isCMMode()) {
newSpeed = train.getAtoSpeed();
} else {
SectionPosition targetPosition = train.getRobotTargetPosition();
if (targetPosition == null
|| (Objects.equals(headSection, targetPosition.getSection()) && !headSection.isFunctionTrack())) {
newSpeed = 0;
} else {
float recommendedSpeedMax;
if (train.isRMMode()) {
recommendedSpeedMax = Math.min(repository.getConfig().getRmAtpSpeed(), train.getSpeedLimit()) * 0.9f;
} else if (train.isNRMMode()) {
recommendedSpeedMax = Math.min(repository.getConfig().getUrmAtpSpeed(), train.getSpeedLimit()) * 0.9f;
} else {
recommendedSpeedMax = 0;
}
Float distance = CalculateService.calculateDistance(headPosition, targetPosition, right);
if (distance == null || distance <= SimulationConstants.PARK_POINT_MAX_OFFSET) { //如果列车已经抵达或越过目标位置
newSpeed = 0;
} else {
SpeedCurve speedCurve = SpeedCurve.buildTargetSpeedCurve(headPosition, tailPosition, right,
distance, speed, recommendedSpeedMax);
newSpeed = speedCurve.getSpeedOf(speedCurve.getTotalDistance());
}
}
}
if (newSpeed == 0) {
train.setSpeed(0);
} else {
newSpeed = 20f / 3.6f;
}
Float speedMax = null;
if (headSection.isStandTrack()) { //车头在站台轨
speedMax = 10f / 3.6f;
} else {
//车尾未离开站台轨
Section behindStandTrack = null;
Section behindSection = headSection;
for (int i = 0; i < 5; i++) {
behindSection = behindSection.getNextRunningSectionOf(!right);
if (behindSection == null)
break;
if (behindSection.isStandTrack()) {
behindStandTrack = behindSection;
break;
}
}
if (behindStandTrack != null && behindStandTrack.isOccupied()) {
speedMax = 10f / 3.6f;
}
}
if (speedMax != null) {
train.setSpeed(Math.min(newSpeed, speedMax));
} else {
train.setSpeed(newSpeed);
}
}
private byte[] buildData(VirtualRealityTrain train, SrTrainConfig 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()) {
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;
}
public void controlTrain(String simulationId, String groupNumber, boolean right, int speed) {
Simulation simulation = groupSimulationService.getSimulationByGroup(simulationId);
VirtualRealityTrain train = simulation.getRepository().getOnlineTrainBy(groupNumber);
SrTrainConfig config = (SrTrainConfig) 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);
byte[] data = buildData(train, config);
UDPLowConfig udpLowConfig = (UDPLowConfig) simulation.queryOneRealDevice(ProjectDeviceType.UDP_LOW);
udpClient.write(udpLowConfig.getAddr(), data);
}
}

View File

@ -10,15 +10,18 @@ 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 lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
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
@ -28,6 +31,8 @@ public class UDPClient implements ApplicationRunner {
private Channel channel;
private final ConcurrentLinkedQueue<Msg> msgQueue = new ConcurrentLinkedQueue<>();
@Override
public void run(ApplicationArguments args) throws Exception {
this.start();
@ -46,31 +51,40 @@ public class UDPClient implements ApplicationRunner {
ChannelFuture future = bootstrap.bind(udpConfig.getClientPort()).sync();
Channel channel = future.channel();
this.channel = channel;
if(future.isSuccess()) {
if (future.isSuccess()) {
log.info(String.format("udp client start on port [%s]", this.udpConfig.getClientPort()));
} else {
log.error("udp server start failed", future.cause());
}
}
public void write(byte[] ip, int port, byte[] msg) {
try {
if (channel != null && channel.isWritable()) {
InetAddress inetAddress = InetAddress.getByAddress(ip);
InetSocketAddress addr = new InetSocketAddress(inetAddress, port);
write(addr, msg);
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public void write(InetSocketAddress addr, byte[] msg) {
if (channel != null && channel.isWritable() && addr != null) {
ByteBuf byteBuf = Unpooled.copiedBuffer(msg);
DatagramPacket data = new DatagramPacket(byteBuf, addr);
channel.writeAndFlush(data);
msgQueue.add(new Msg(addr, msg));
}
@Scheduled(fixedRate = 10)
public void send() {
Msg msg = msgQueue.poll();
if (msg == null)
return;
InetSocketAddress addr = msg.getAddr();
byte[] data = msg.getData();
if (channel != null && channel.isWritable() && addr != null && data != null) {
ByteBuf byteBuf = Unpooled.copiedBuffer(data);
DatagramPacket datagramPacket = new DatagramPacket(byteBuf, addr);
channel.writeAndFlush(datagramPacket);
}
}
@Getter
class Msg {
private InetSocketAddress addr;
private byte[] data;
public Msg(InetSocketAddress addr, byte[] data) {
this.addr = addr;
this.data = data;
}
}
}

View File

@ -12,14 +12,15 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
@Getter
public class UDPLowConfig extends RealDeviceConfig {
@Getter
private UDPLowConfigVO configVO;
private byte[] ip;
private Integer port;
@Getter
private InetSocketAddress addr;
public UDPLowConfig(ProjectDeviceVO projectDevice) {

View File

@ -7,9 +7,9 @@ import io.netty.buffer.ByteBuf;
public interface UDPRealDeviceService {
boolean isMatch(RealDeviceConfig realDevice);
void control(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice);
void run(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice);
void init(Simulation simulation, UDPLowConfig udpConfig, RealDeviceConfig realDevice);
void init(Simulation simulation, UDPLowConfig udpLowConfig, RealDeviceConfig realDevice);
void handle(Simulation simulation, ByteBuf msg);
}

View File

@ -63,8 +63,8 @@ public class UDPRealDeviceThread {
}
for (RealDeviceConfig config : realDeviceList) {
for (UDPRealDeviceService service : serviceList) {
if (service.isMatch(config)) {
service.control(simulation, udpLowConfig, config);
if (service.isMatch(config) && config.getMapElement() != null) {
service.run(simulation, udpLowConfig, config);
}
}
}
@ -84,7 +84,6 @@ public class UDPRealDeviceThread {
udpRealDeviceService.handle(simulation, data);
}
}
break;
}
}
}

View File

@ -22,8 +22,5 @@ public class UDPMessageHandler extends SimpleChannelInboundHandler<DatagramPacke
int port = sender.getPort();
ByteBuf content = datagramPacket.content();
udpRealDeviceThread.handleData(ip, port, content);
// System.out.println("收到消息:" + datagramPacket.content().toString(StandardCharsets.UTF_8));
// ByteBuf byteBuf = Unpooled.copiedBuffer("hi".getBytes());
// ctx.writeAndFlush(new DatagramPacket(byteBuf, datagramPacket.sender()));
}
}

View File

@ -50,7 +50,7 @@ public class VRDeviceLogicLoop {
for (VirtualRealityTrain train : onlineTrainList) {
SectionPosition headPosition = train.getHeadPosition();
boolean right = train.isRight();
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen());
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), true);
List<Section> occupyAxleSectionList = CalculateService
.getTrainOccupyAxleSection(headPosition, tailPosition, right);
// 更新占用区段的占用状态

View File

@ -29,7 +29,11 @@ public class VRTrainRunningService {
public void trainRunning(Simulation simulation) {
List<VirtualRealityTrain> trainList = simulation.getRepository().getOnlineTrainList();
trainList.forEach(train -> this.trainRunning(simulation,train));
trainList.forEach(train -> {
if (!train.isConnectReal()) {
this.trainRunning(simulation, train);
}
});
}
/**
@ -57,8 +61,6 @@ public class VRTrainRunningService {
float fr = (float) (2.27 + 0.00156f * originSpeed * 3.6); // 基本阻力
float f = train.getFk() - train.getFb() - fr; // 合力
float a = f / train.getMass(); // f=ma, a = f/m
// System.out.println(String.format("fk-[%s], fb-[%s], fr-[%s], f-[%s], a[%s]",
// train.getFk(), train.getFb(), fr, f, a));
float time = SimulationModule.TR.getRateS();
float increment = a * time;
// 现在的速度
@ -66,14 +68,6 @@ public class VRTrainRunningService {
if (currentSpeed < 0) {
currentSpeed = 0;
}
// else if (currentSpeed > train.getSpeedMax()) {
// currentSpeed = train.getSpeedMax();
// }
// 更新列车速度
// System.out.println(String.format("当前车速:[%s]", currentSpeed));
// 根据速度计算并更新列车所在区段位置
// float s = (float) (currentSpeed * time - acceleration * Math.pow(time, 2) / 2);
float s;
if (VirtualRealityTrain.Handwheel.REVERSE.equals(train.getGear())) { // 倒车挡
currentSpeed = Math.min(train.getReverseSpeedMax(), currentSpeed);
@ -91,8 +85,7 @@ public class VRTrainRunningService {
}
boolean right = train.isRight();
SectionPosition headPosition = train.getHeadPosition();
SectionPosition headPositionNew = CalculateService.calculateNextPositionByStartAndLen(headPosition, right, s);
// todo 碰撞检测如果撞车不修改位置
SectionPosition headPositionNew = CalculateService.calculateNextPositionByStartAndLen(headPosition, right, s, true);
//更新车头区段不会碰撞才更新
boolean change = true;
for (VirtualRealityTrain aTrain : simulation.getRepository().getOnlineTrainList()) {
@ -102,7 +95,7 @@ public class VRTrainRunningService {
if (s > 0) { //向前行驶
checkPosition = headPositionNew;
} else { //向后行驶
checkPosition = CalculateService.calculateNextPositionByStartAndLen(headPositionNew, !right, train.getLen());
checkPosition = CalculateService.calculateNextPositionByStartAndLen(headPositionNew, !right, train.getLen(), true);
}
Section checkSection = checkPosition.getSection();
SectionPosition aTrainHeadPosition = aTrain.getHeadPosition();
@ -157,13 +150,13 @@ public class VRTrainRunningService {
}
}
//离开计轴区段判断
SectionPosition tailPositionOld = CalculateService.calculateNextPositionByStartAndLen(headPosition, !trainRight, train.getLen());
SectionPosition tailPositionOld = CalculateService.calculateNextPositionByStartAndLen(headPosition, !trainRight, train.getLen(), true);
Section tailAxleCounterSection = tailPositionOld.getSection();
if (!tailAxleCounterSection.isAxleCounter()) {
tailAxleCounterSection = tailAxleCounterSection.getParent();
}
if (tailAxleCounterSection != null && tailAxleCounterSection.isAxleCounter()) { //老的车尾区段是计轴区段
SectionPosition tailPositionNew = CalculateService.calculateNextPositionByStartAndLen(headPositionNew, !trainRight, train.getLen());
SectionPosition tailPositionNew = CalculateService.calculateNextPositionByStartAndLen(headPositionNew, !trainRight, train.getLen(), true);
Section tailSectionNew = tailPositionNew.getSection();
if (!tailAxleCounterSection.equals(tailSectionNew) && !tailAxleCounterSection.equals(tailSectionNew.getParent())) { //老车尾计轴区段和新车尾区段不一样
tailAxleCounterSection.getVirtualAxleCounter().trainOut(trainRight);

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.cbtc.onboard.ATP;
import club.joylink.rtss.constants.Project;
import club.joylink.rtss.simulation.cbtc.ATP.ground.MaService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.DriveMode;
@ -7,6 +8,7 @@ import club.joylink.rtss.simulation.cbtc.constant.RunLevel;
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.map.MapConfig;
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;
@ -66,10 +68,10 @@ public class ATPLogicLoop {
* 更新列车运行级别
*/
private void updateRunLevel(Simulation simulation, VirtualRealityTrain train, VirtualRealityTrain.PreselectionMode preselectionMode) {
// //如果当前级别高于预选降至IL
// if (!preselectionMode.isMatchTheRunLevel(train.getRunLevel())) {
// atpService.updateRunLevel(train, RunLevel.IL, preselectionMode);
// }
//如果当前级别高于预选降至IL
if (!preselectionMode.isMatchTheRunLevel(train.getRunLevel())) {
atpService.updateRunLevel(train, RunLevel.IL, preselectionMode);
}
RunLevel defaultRunLevel = simulation.getRepository().getConfig().getRunMode();
//更新移动授权丢失时长
@ -140,7 +142,7 @@ public class ATPLogicLoop {
// this.sendStopMessage2GroundAtp(simulation, train);
// // 检查列车是否在转换轨
// this.checkOnTransferAndSend2Ats(simulation, train, headPosition, tailPosition);
if (!train.isBreaking()) { // 制动状态
if (!train.isBreaking() && !train.isRMMode() && !train.isNRMMode()) { // 制动状态
// 施加常规制动防止倒溜
this.atoService.openBreaking(train);
}
@ -153,6 +155,10 @@ public class ATPLogicLoop {
if (train.isRMMode() && train.isLeverNotInTractionGear()) { //停车RM模式操纵杆非牵引位
atpService.cancelSignalEB(train);
}
// if (Project.SR_SANDBOX.name().equals(simulation.getBuildParams().getMap().getProjectCode())) {
// atpService.cancelSignalEB(train);
// atpService.openATO(train);
// }
}
if (this.checkConditionToMove2(simulation, train)) { // 可以启动
@ -268,13 +274,14 @@ public class ATPLogicLoop {
private void handlePreselectionMode(Simulation simulation, VirtualRealityTrain train) {
VirtualRealityTrain.PreselectionMode preselectionMode = train.getPreselectionMode();
MapConfig config = simulation.getRepository().getConfig();
switch (preselectionMode) {
case AM_C:
if (!train.isCBTC())
if (!train.isCBTC() && config.getRunMode().isNotLowerThan(RunLevel.CBTC))
train.setCommunication(true);
break;
case SM_C:
if (!train.isCBTC())
if (!train.isCBTC() && config.getRunMode().isNotLowerThan(RunLevel.CBTC))
train.setCommunication(true);
atpService.closeATO(train);
break;

View File

@ -175,6 +175,7 @@ public class ATPService {
if (train.isAtoOn()) {
closeATO(train);
}
train.initAsRM(); //简单粗暴
train.setAtpOn(false);
train.setSignalEB(false);
train.setDriveMode(DriveMode.NRM);
@ -185,6 +186,7 @@ public class ATPService {
*/
public void openAtp(VirtualRealityTrain train) {
train.setAtpOn(true);
train.setDriveMode(DriveMode.RM);
}
/**
@ -271,7 +273,7 @@ public class ATPService {
newHeadPosition = new SectionPosition(section, offset);
} else {
newHeadPosition = CalculateService
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen());
.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), false);
}
// 车尾变车头车头变车尾
train.setHeadPosition(newHeadPosition);

View File

@ -71,7 +71,7 @@ public class TrainTargetUpdateService {
if (!temp.getCode().equals(trainInfo.getActualArriveStandTrack())) { //列车未在该区段停车
SectionPosition maxStopPosition = CalculateService
.calculateNextPositionByStartAndLen(temp.buildStopPointPosition(right),
right, SimulationConstants.PARK_POINT_MAX_OFFSET); //最远停车点
right, SimulationConstants.PARK_POINT_MAX_OFFSET, false); //最远停车点
if (maxStopPosition.isAheadOf(headPosition, right)) { //该区段最远停车点在车头前方
newTarget = temp;
break;

View File

@ -192,7 +192,7 @@ public class RobotLogicLoop {
// operationParams.put("percent", 0);
// atsOperationDispatcher.execute(simulation, driver, Operation.Type.Driver_Force_Change.name(), operationParams);
// }
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen());
SectionPosition tailPosition = CalculateService.calculateNextPositionByStartAndLen(headPosition, !right, train.getLen(), true);
SpeedCurve speedCurve = null;
switch (train.getDriveMode()) {
case AM: //AM模式下不需要司机驾驶

View File

@ -1,9 +1,15 @@
package club.joylink.rtss.vo.client.competition;
import club.joylink.rtss.vo.client.PageQueryVO;
import lombok.Getter;
import lombok.Setter;
/**
* 竞赛分页查询
*/
@Getter
@Setter
public class CompetitionPagedQueryVO extends PageQueryVO {
private String name;
}

View File

@ -15,11 +15,12 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.richor.ZjdPslConf
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;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSectionConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSignalConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.Sr.SrSwitchConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrSectionConfig;
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.UDPClientConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.UDPLowConfig;
import club.joylink.rtss.simulation.cbtc.device.real.udp.sr.config.SrTrainConfig;
import club.joylink.rtss.util.JsonUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
@ -143,6 +144,9 @@ public class ProjectDeviceVO {
case SWITCH:
list.add(new SrSwitchConfig(deviceVO));
break;
case TRAIN:
list.add(new SrTrainConfig(deviceVO));
break;
}
}
return list;

View File

@ -12,6 +12,16 @@ public class SrSectionConfigVO {
private String sandboxCode;
/**
* 车头到达区段延迟停车时间/s
*/
private Float headDelayTime;
/**
* 车尾解除占用延迟停车时间/s
*/
private Float tailDelayTime;
public SrSectionConfigVO(String vrCode, String sandboxCode) {
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;

View File

@ -0,0 +1,19 @@
package club.joylink.rtss.vo.client.project.sr;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class SrTrainConfigVO {
private String vrCode;
private String sandboxCode;
public SrTrainConfigVO(String vrCode, String sandboxCode) {
this.vrCode = vrCode;
this.sandboxCode = sandboxCode;
}
}

View File

@ -123,8 +123,8 @@ public class RunPlanTripVO {
public RunPlanTripVO(RunPlanRoutingVO routingVO) {
this.right = routingVO.getRight();
this.isOutbound = routingVO.isInBoundRoute();
this.isInbound = routingVO.isOutBoundRoute();
this.isOutbound = routingVO.isOutBoundRoute();
this.isInbound = routingVO.isInBoundRoute();
this.destinationCode = Objects.isNull(routingVO.getDestinationCode()) ? "" : routingVO.getDestinationCode();
this.startSectionCode = routingVO.getStartSectionCode();
this.endSectionCode = routingVO.getEndSectionCode();

View File

@ -167,7 +167,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.0.254:3306/joylink?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: localdb