# Conflicts:
#	rtss_simulation
This commit is contained in:
tiger_zhou 2023-10-23 11:12:40 +08:00
commit 0adc9b2a16
71 changed files with 5586 additions and 2041 deletions

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitAuthRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -49,13 +50,9 @@ func InitAuthRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware)
func pageQueryRole(c *gin.Context) {
req := dto.PageQueryDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,请求参数异常", err))
}
page, err := service.PageAuthRoleQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageAuthRoleQuery(&req))
}
// 查询角色列表
@ -74,8 +71,7 @@ func pageQueryRole(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/auth/role/list [get]
func listQueryRole(c *gin.Context) {
page := service.ListAuthRoleQuery()
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.ListAuthRoleQuery())
}
// 创建角色
@ -97,7 +93,7 @@ func listQueryRole(c *gin.Context) {
func createRole(c *gin.Context) {
req := dto.AuthRoleReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,请求参数异常", err))
}
slog.Debug("保存数据", req)
c.JSON(http.StatusOK, service.CreateAuthRole(&req))
@ -122,7 +118,7 @@ func createRole(c *gin.Context) {
func queryRoleInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -149,12 +145,12 @@ func queryRoleInfo(c *gin.Context) {
func updateRoleInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
req := dto.AuthRoleReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新角色信息出错,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
rid := int32(int64Id)
@ -184,9 +180,8 @@ func updateRoleInfo(c *gin.Context) {
func deleteRoleInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("删除失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
rid := int32(int64Id)
result := service.DeleteAuthRole(rid)
@ -215,13 +210,9 @@ func deleteRoleInfo(c *gin.Context) {
func pageQueryApiPath(c *gin.Context) {
req := dto.AuthApiPathPageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
page, err := service.PageAuthApiPathQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageAuthApiPathQuery(&req))
}
// 查询接口路径列表
@ -262,7 +253,7 @@ func listQueryApiPath(c *gin.Context) {
func createApiPath(c *gin.Context) {
req := dto.AuthApiPathReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,参数格式错误", err))
}
slog.Debug("保存数据", req)
c.JSON(http.StatusOK, service.CreateAuthApiPath(&req))
@ -287,7 +278,7 @@ func createApiPath(c *gin.Context) {
func queryApiPathInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -314,11 +305,11 @@ func queryApiPathInfo(c *gin.Context) {
func updateApiPathInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少id"))
}
req := dto.AuthApiPathReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.UpdateAuthApiPath(int32(int64Id), &req))
@ -343,7 +334,7 @@ func updateApiPathInfo(c *gin.Context) {
func deleteApiPathInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("删除失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -369,7 +360,7 @@ func deleteApiPathInfo(c *gin.Context) {
func assignRoleToUser(c *gin.Context) {
req := dto.AuthRoleUserReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("关联失败,参数格式错误", err))
}
result := service.UserLinkRole(&req)
if result {

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitCategoryRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -39,18 +40,12 @@ func InitCategoryRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddlewa
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/category/paging [get]
func pageQueryCategory(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("分页查询厂家", user)
req := dto.PageCategoryReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("分页查厂家参数", req)
page, err := service.PageCategoryQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageCategoryQuery(&req))
}
// 查询厂家信息列表
@ -72,14 +67,10 @@ func pageQueryCategory(c *gin.Context) {
func listQueryCategory(c *gin.Context) {
req := dto.CategoryReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("查厂家参数", req)
page, err := service.ListCategoryQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.ListCategoryQuery(&req))
}
// 创建厂家信息
@ -101,14 +92,10 @@ func listQueryCategory(c *gin.Context) {
func createCategory(c *gin.Context) {
req := dto.CategoryDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "传入参数错误"})
panic(sys_error.New("保存失败,参数格式错误", err))
}
slog.Debug("保存数据", req)
data, err := service.CreateCategory(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateCategory(&req))
}
// 查询厂家信息
@ -130,9 +117,8 @@ func createCategory(c *gin.Context) {
func queryCategoryInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryCategory(int32(int64Id)))
}
@ -157,19 +143,15 @@ func queryCategoryInfo(c *gin.Context) {
func updateCategoryInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
req := dto.CategoryDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateCategory(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存参数出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateCategory(int32(int64Id), &req))
}
// 删除厂家信息
@ -189,14 +171,11 @@ func updateCategoryInfo(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/category/{id} [delete]
func deleteCategory(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("id删除草稿的图形数据", user)
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,主键格式错误", err))
}
slog.Debug("id查询草稿的图形数据", id)
service.DeleteCategoryById(id)
c.JSON(http.StatusOK, true)
}

View File

@ -1,7 +1,6 @@
package api
import (
"log/slog"
"net/http"
"strconv"
@ -14,6 +13,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitDraftingRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -45,18 +45,11 @@ func InitDraftingRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddlewa
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/drafting/paging [get]
func pageQueryDrafting(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("分页查询草稿", user)
req := dto.PageDraftingReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("分页查草稿参数", req)
page, err := service.PageDraftingQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageDraftingQuery(&req))
}
// 列表查询草稿
@ -74,20 +67,13 @@ func pageQueryDrafting(c *gin.Context) {
// @Failure 401 {object} dto.ErrorDto
// @Failure 404 {object} dto.ErrorDto
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/drafting/paging [get]
// @Router /api/v1/drafting/list [get]
func listQueryDrafting(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("列表查询草稿", user)
req := dto.ListDraftingReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("列表查草稿参数", req)
list, err := service.ListDraftingQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, list)
c.JSON(http.StatusOK, service.ListDraftingQuery(&req))
}
// 创建草稿
@ -111,14 +97,9 @@ func createDrafting(c *gin.Context) {
createId := user.(*model.User).ID
req := dto.DraftingDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,参数格式错误", err))
}
slog.Debug("保存数据", req)
data, err := service.CreateDrafting(createId, &req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateDrafting(createId, &req))
}
// 草稿另存为
@ -141,21 +122,16 @@ func createDrafting(c *gin.Context) {
func saveAsDrafting(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("另存为失败,缺少主键"))
}
slog.Debug("传入参数id为" + id)
user, _ := c.Get(middleware.IdentityKey)
createrId := user.(*model.User).ID
req := dto.DraftingDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("另存为失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
newData, err := service.SaveAsDrafting(createrId, int32(int64Id), &req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, newData)
c.JSON(http.StatusOK, service.SaveAsDrafting(createrId, int32(int64Id), &req))
}
// 查询草稿详情
@ -177,9 +153,8 @@ func saveAsDrafting(c *gin.Context) {
func queryDraftingInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少主键"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryDrafting(int32(int64Id)))
}
@ -204,19 +179,14 @@ func queryDraftingInfo(c *gin.Context) {
func updateDraftingInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少主键"))
}
slog.Debug("传入参数id为" + id)
req := dto.DraftingDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateDrafting(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateDrafting(int32(int64Id), &req))
}
// 删除草稿数据
@ -236,14 +206,11 @@ func updateDraftingInfo(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/drafting/{id} [delete]
func deleteDrafting(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("id删除草稿的图形数据", user)
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,主键格式错误", err))
}
slog.Debug("id查询草稿的图形数据", id)
service.DeleteDraftingById(id)
c.JSON(http.StatusOK, true)
}
@ -267,7 +234,7 @@ func deleteDrafting(c *gin.Context) {
func generateCalculateLinkData(c *gin.Context) {
req := dto.DraftingMapDataDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("link生成失败参数格式错误", err))
}
gd := &graphicData.RtssGraphicStorage{}
proto.Unmarshal(req.Proto, gd)

View File

@ -1,7 +1,6 @@
package api
import (
"log/slog"
"net/http"
"strconv"
@ -10,6 +9,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitProjectRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -41,14 +41,9 @@ func InitProjectRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddlewar
func pageQueryProject(c *gin.Context) {
req := dto.PageProjectReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("分页查项目参数", req)
page, err := service.PageProjectQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageProjectQuery(&req))
}
// 查询项目信息列表
@ -70,14 +65,9 @@ func pageQueryProject(c *gin.Context) {
func listQueryProject(c *gin.Context) {
req := dto.ProjectReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
slog.Debug("查项目参数", req)
page, err := service.ListProjectQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.ListProjectQuery(&req))
}
// 创建项目信息
@ -99,14 +89,9 @@ func listQueryProject(c *gin.Context) {
func createProject(c *gin.Context) {
req := dto.ProjectDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,参数格式错误", err))
}
slog.Debug("保存数据", req)
data, err := service.CreateProject(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateProject(&req))
}
// 查询项目信息
@ -128,9 +113,8 @@ func createProject(c *gin.Context) {
func queryProjectInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少主键"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryProject(int32(int64Id)))
}
@ -155,18 +139,14 @@ func queryProjectInfo(c *gin.Context) {
func updateProjectInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少主键"))
}
req := dto.ProjectDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateProject(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateProject(int32(int64Id), &req))
}
// 删除项目信息
@ -189,9 +169,8 @@ func deleteProject(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,缺少主键"))
}
slog.Debug("id查询草稿的图形数据", id)
service.DeleteProjectById(id)
c.JSON(http.StatusOK, true)
}

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitProjectLinkRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -39,7 +40,7 @@ func InitProjectLinkRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
func queryProjectLinkInfo(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -65,7 +66,7 @@ func queryProjectLinkInfo(c *gin.Context) {
func queryTrainSizeByMapId(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -91,7 +92,7 @@ func queryTrainSizeByMapId(c *gin.Context) {
func queryTrainSizeByPId(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少id"))
}
slog.Debug("传入参数id为" + id)
int64Id, _ := strconv.ParseInt(id, 10, 64)
@ -118,7 +119,7 @@ func queryTrainSizeByPId(c *gin.Context) {
func saveProjectLinkInfo(c *gin.Context) {
req := dto.ProjectLinkReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("保持失败,参数格式化错误", err))
}
service.UpdateProjectLink(&req)
c.JSON(http.StatusOK, true)

View File

@ -8,10 +8,10 @@ import (
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin"
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dto/publishedGi"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitPublishedGiRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -41,13 +41,10 @@ func InitPublishedGiRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/publishedGi/paging [get]
func pageQueryPublishedGi(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("分页查询发布的图形数据", user)
req := publishedGi.PublishedGiReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,查询参数格式错误", err))
}
slog.Debug("分页查询发布的图形数据", req)
page := service.PageQueryPublishedGi(&req)
c.JSON(http.StatusOK, page)
}
@ -68,13 +65,10 @@ func pageQueryPublishedGi(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/publishedGi/list [get]
func listQueryPublishedGi(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("列表查询发布的图形数据", user)
req := publishedGi.PublishedGiListReqDto{}
if err := c.ShouldBindQuery(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,查询参数格式错误", err))
}
slog.Debug("列表查询发布的图形数据", req)
list := service.ListQueryPublishedGi(&req)
c.JSON(http.StatusOK, list)
}
@ -95,18 +89,12 @@ func listQueryPublishedGi(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/publishedGi/{id} [get]
func getPublishedGiById(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("id查询发布的图形数据", user)
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
}
slog.Debug("id查询发布的图形数据", id)
entity, err := service.GetPublishedGiById(id)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
panic(sys_error.New("查询失败,传入参数格式错误", err))
}
entity := service.GetPublishedGiById(id)
c.JSON(http.StatusOK, entity)
}
@ -130,10 +118,8 @@ func publishFromDraft(c *gin.Context) {
slog.Debug("发布图形数据", user)
req := publishedGi.PublishReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("发布失败,参数格式错误", err))
}
//todo
slog.Debug("发布图形数据请求参数", req)
service.PublishFormDraft(&req, user.(*model.User))
}
@ -153,14 +139,11 @@ func publishFromDraft(c *gin.Context) {
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/publishedGi/{id} [delete]
func deletePublishedGiById(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("id删除发布的图形数据", user)
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,传入参数格式错误", err))
}
slog.Debug("id查询发布的图形数据", id)
service.DeletePublishedGiById(id)
}
@ -186,11 +169,11 @@ func saveAsDraftingFromPublish(c *gin.Context) {
slog.Debug("用户拉取发布图形数据", "userId", user, "发布图数据id", idStr)
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("另存为草稿失败,传入参数格式错误", err))
}
req := publishedGi.PublishReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("另存为草稿失败,传入参数格式错误", err))
}
service.SaveAsDraftingFromPublish(int32(id), user.(*model.User), req.Name)
}
@ -205,20 +188,17 @@ func saveAsDraftingFromPublish(c *gin.Context) {
// @Tags 发布的图形数据Api
// @Accept json
// @Produce json
// @Param publishedGiListReqDto query publishedGi.PublishedGiListReqDto true "查询参数"
// @Param PublishedGiSingleQueryDto query publishedGi.PublishedGiSingleQueryDto true "查询参数"
// @Success 200 {object} []model.PublishedGi
// @Failure 401 {object} dto.ErrorDto
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/publishedGi/list [get]
// @Router /api/v1/publishedGi/name [get]
func getPublishedGiByName(c *gin.Context) {
user, _ := c.Get(middleware.IdentityKey)
slog.Debug("name查询发布的图形数据", user)
param := &publishedGi.PublishedGiSingleQueryDto{}
err := c.ShouldBind(param)
slog.Debug("name查询发布的图形数据", param.Name)
entity, err := service.GetPublishedGiByName(param)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
if err := c.ShouldBind(param); err != nil {
panic(sys_error.New("查询失败,查询参数格式错误", err))
}
slog.Debug("name查询发布的图形数据", param.Name)
entity := service.GetPublishedGiByName(param)
c.JSON(http.StatusOK, entity)
}

View File

@ -20,6 +20,7 @@ import (
apiproto "joylink.club/bj-rtsts-server/grpcproto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitSimulationRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -34,11 +35,19 @@ func InitSimulationRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddle
authed.GET("/getDataChannelName", getDataChannelName)
authed.POST("/relay/operation", relayOperation)
authed.POST("/signal/operation", signalOperation)
authed.POST("/esbBtn/operation", esbBtnOperation)
authed.POST("/ibp/btn/operation", ibpBtnOperation)
authed.POST("/ibp/key/operation", ibpKeyOperation)
authed.GET("/:id/getMapKilometerRange", getMapKilometerRange)
authed.POST("/psl/operation", pslBtnOperation)
// 初始化地图信息
initPublishMapInfo()
apiproto.RegisterMsgServer(&apiproto.SimulationServer{})
apiproto.RegisterMsgServer(&apiproto.MemoryChangeServer{SimulationMap: make(map[string]*state.SimulationStatus)})
apiproto.InitClient()
apiproto.Register(&apiproto.SimulationServer{})
apiproto.Register(&apiproto.SimulationIBPServer{})
apiproto.Register(&apiproto.SimulationPSLServer{})
apiproto.Register(&apiproto.MemoryChangeServer{SimulationMap: make(map[string]*state.SimulationStatus)})
}
func initPublishMapInfo() {
@ -70,18 +79,22 @@ func initPublishMapInfo() {
func createByProjectId(c *gin.Context) {
req := dto.SimulationCreateReqDto{}
if err := c.ShouldBind(&req); nil != err {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("测试启动失败,请求参数异常", err))
}
mapInfos := service.QueryProjectPublishedGi(req.ProjectId)
if len(mapInfos) == 0 {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: "项目未关联地图"})
panic(sys_error.New("测试启动失败,项目未关联发布图"))
}
mapIds := make([]int32, len(mapInfos))
for i, mapInfo := range mapInfos {
mapIds[i] = mapInfo.ID
}
rsp := dto.SimulationCreateRspDto{ProjectId: req.ProjectId, MapId: mapIds[0], MapIds: mapIds}
rsp.SimulationId = simulation.CreateSimulation(req.ProjectId, mapIds)
simulationId, err := simulation.CreateSimulation(req.ProjectId, mapIds)
if err != nil {
panic(sys_error.New("测试启动失败", err))
}
rsp.SimulationId = simulationId
c.JSON(http.StatusOK, &rsp)
}
@ -144,12 +157,11 @@ func findAllSimulations(c *gin.Context) {
func checkSimMapData(c *gin.Context) {
rt := &dto.CheckMapDataReqDto{}
if err := c.ShouldBind(&rt); nil != err {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("请求参数异常", err))
}
err := proto.Unmarshal(rt.Data, &graphicData.RtssGraphicStorage{})
if err != nil {
c.JSON(http.StatusInternalServerError, "参数错误")
return
panic(sys_error.New("非平面布置图数据"))
}
c.JSON(http.StatusOK, &dto.CheckMapDataRspDto{Success: true})
}
@ -172,13 +184,12 @@ func checkSimMapData(c *gin.Context) {
func addTrain(c *gin.Context) {
req := dto.AddTrainReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("添加列车失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
id := getAddTrainPrimaryKey(simulation)
if id == -1 {
c.JSON(http.StatusBadRequest, "已存在在线列车")
return
panic(sys_error.New("添加列车失败,已有列车在运行"))
}
rsp := &state.TrainState{
Id: strconv.Itoa(id),
@ -211,7 +222,7 @@ func addTrain(c *gin.Context) {
func removeTrain(c *gin.Context) {
rt := &dto.RemoveTrainDto{}
if err := c.ShouldBind(&rt); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("移除列车失败,请求参数异常", err))
}
slog.Debug("ATS测试仿真-移除列车,请求:", rt)
simulation := checkDeviceDataAndReturn(rt.SimulationId)
@ -239,16 +250,11 @@ func removeTrain(c *gin.Context) {
func switchOperation(c *gin.Context) {
req := &request_proto.TurnoutOperationReq{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("道岔操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
slog.Info("传入状态参数", "request", req)
memory.HandleTurnoutOperation(simulation, req)
// memory.ChangeTurnoutState(simulation, &state.SwitchState{
// Id: req.DeviceId,
// Normal: req.TurnNormal,
// Reverse: req.TurnReverse,
// }, req.MapId)
c.JSON(http.StatusOK, "ok")
}
@ -275,7 +281,115 @@ func signalOperation(c *gin.Context) {
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeSignalState(simulation, req.MapId, req.DeviceId, req.Aspect)
memory.ChangeSignalState(simulation, req)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-ESB按钮操作
//
// @Summary ATS测试-ESB按钮操作
//
// @Security JwtAuth
//
// @Description ATS测试-ESB按钮操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param EsbButtonOperationReqDto body dto.EsbButtonOperationReqDto true "ATS测试仿真-ESB按钮操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/esbBtn/operation [post]
func esbBtnOperation(c *gin.Context) {
req := &dto.EsbButtonOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("紧急关闭按钮操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeEsbButtonState(simulation, req.MapId, req.Id, req.Down)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-IBP按钮操作
//
// @Summary ATS测试-IBP按钮操作
//
// @Security JwtAuth
//
// @Description ATS测试-IBP按钮操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param IBPButtonOperationReqDto body dto.IBPButtonOperationReqDto true "ATS测试仿真-IBP按钮操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/btn/operation [post]
func ibpBtnOperation(c *gin.Context) {
req := &dto.IBPButtonOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("IBP按钮操作失败请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeIBPButtonState(simulation, req.MapId, req.StationId, req.ButtonCode, req.Down)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-IBP钥匙操作
//
// @Summary ATS测试-IBP钥匙操作
//
// @Security JwtAuth
//
// @Description ATS测试-IBP钥匙操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param KeyOperationReqDto body dto.KeyOperationReqDto true "ATS测试仿真-IBP钥匙操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/key/operation [post]
func ibpKeyOperation(c *gin.Context) {
req := &dto.KeyOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("IBP开关操作失败请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeIBPKeyState(simulation, req.MapId, req.StationId, req.KeyCode, req.Gear)
c.JSON(http.StatusOK, "ok")
}
// PSL操作
//
// @Summary PSL操作
//
// @Security JwtAuth
//
// @Description PSL操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param PslOperationReqDto body dto.PslOperationReqDto true "PSL操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/operation [post]
func pslBtnOperation(c *gin.Context) {
req := &dto.PslOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangePSLButtonState(simulation, req.MapId, req.GateBoxId, req.ButtonCode, req.Down)
c.JSON(http.StatusOK, "ok")
}
@ -298,6 +412,30 @@ func getDataChannelName(c *gin.Context) {
c.JSON(http.StatusOK, config.SimulationId_prefix+apiproto.MemoryChangeServerSuffix)
}
// 获取仿真地图的公里标范围
//
// @Summary 获取仿真地图的公里标范围
//
// @Security JwtAuth
//
// @Description 获取仿真地图的公里标范围
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/:id/getMapKilometerRange [get]
func getMapKilometerRange(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(sys_error.New("缺少仿真编号"))
}
simulation := checkDeviceDataAndReturn(id)
c.JSON(http.StatusOK, simulation.Repo.GetCoordinateInfo())
}
// 获取ATS测试-操作继电器
//
// @Summary 获取ATS测试-操作继电器
@ -317,7 +455,7 @@ func getDataChannelName(c *gin.Context) {
func relayOperation(c *gin.Context) {
req := &dto.RelayOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("继电器操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
@ -329,7 +467,7 @@ func relayOperation(c *gin.Context) {
func checkDeviceDataAndReturn(simId string) *memory.VerifySimulation {
deviceMemory := simulation.FindSimulation(simId)
if deviceMemory == nil {
panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("仿真[%s]不存在", simId)})
panic(sys_error.New(fmt.Sprintf("仿真[%s]不存在", simId)))
}
return deviceMemory
}
@ -340,15 +478,10 @@ func getAddTrainPrimaryKey(simulation *memory.VerifySimulation) int {
// 获取列车ID
i := 1
for {
t, ok := trainMap.Load(strconv.Itoa(i))
_, ok := trainMap.Load(strconv.Itoa(i))
if !ok {
break
}
ts := t.(*state.TrainState)
if ts.Show {
i = -1
break
}
i++
}
return i

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitTrainManageRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -53,13 +54,9 @@ func InitTrainManageRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
func pageQueryTrainModel(c *gin.Context) {
req := dto.PageTrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
page, err := service.PageTrainModelQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageTrainModelQuery(&req))
}
// 创建列车型号
@ -81,13 +78,9 @@ func pageQueryTrainModel(c *gin.Context) {
func createTrainModel(c *gin.Context) {
req := dto.TrainModelDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("保存失败,参数格式错误", err))
}
data, err := service.CreateTrainModel(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateTrainModel(&req))
}
// 查询列车型号详情
@ -109,7 +102,7 @@ func createTrainModel(c *gin.Context) {
func queryTrainModel(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少主键"))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryTrainModel(int32(int64Id)))
@ -135,18 +128,14 @@ func queryTrainModel(c *gin.Context) {
func updateTrainModel(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少主键"))
}
req := dto.TrainModelDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateTrainModel(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存参数出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateTrainModel(int32(int64Id), &req))
}
// 删除列车型号数据
@ -169,7 +158,7 @@ func deleteTrainModel(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,缺少主键"))
}
service.DeleteTrainModelById(id)
c.JSON(http.StatusOK, true)
@ -194,13 +183,9 @@ func deleteTrainModel(c *gin.Context) {
func queryTrainModelList(c *gin.Context) {
req := dto.TrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
models, err := service.ListTrainModelQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, models)
c.JSON(http.StatusOK, service.ListTrainModelQuery(&req))
}
// 分页查询列车尺寸列表
@ -222,13 +207,9 @@ func queryTrainModelList(c *gin.Context) {
func pageQueryTrainSize(c *gin.Context) {
req := dto.PageTrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
page, err := service.PageTrainSizeQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageTrainSizeQuery(&req))
}
// 查询列车尺寸列表
@ -250,13 +231,9 @@ func pageQueryTrainSize(c *gin.Context) {
func queryTrainSizeList(c *gin.Context) {
req := dto.TrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
sizeList, err := service.ListTrainSizeQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, sizeList)
c.JSON(http.StatusOK, service.ListTrainSizeQuery(&req))
}
// 创建列车尺寸
@ -278,13 +255,9 @@ func queryTrainSizeList(c *gin.Context) {
func createTrainSize(c *gin.Context) {
req := dto.TrainSizeDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,参数格式错误", err))
}
data, err := service.CreateTrainSize(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateTrainSize(&req))
}
// 查询列车尺寸详情
@ -306,7 +279,7 @@ func createTrainSize(c *gin.Context) {
func queryTrainSize(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少查询主键"))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryTrainSize(int32(int64Id)))
@ -332,18 +305,14 @@ func queryTrainSize(c *gin.Context) {
func updateTrainSize(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少查询主键"))
}
req := dto.TrainSizeDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("更新失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateTrainSize(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateTrainSize(int32(int64Id), &req))
}
// 删除列车尺寸数据
@ -366,7 +335,7 @@ func deleteTrainSize(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("删除失败,主键格式错误", err))
}
service.DeleteTrainSizeById(id)
c.JSON(http.StatusOK, true)
@ -391,13 +360,9 @@ func deleteTrainSize(c *gin.Context) {
func pageQueryTrainWheelDiameter(c *gin.Context) {
req := dto.PageTrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
page, err := service.PageTrainWheelDiameterQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, page)
c.JSON(http.StatusOK, service.PageTrainWheelDiameterQuery(&req))
}
// 查询列车轮径列表
@ -419,13 +384,9 @@ func pageQueryTrainWheelDiameter(c *gin.Context) {
func queryTrainWheelDiameterList(c *gin.Context) {
req := dto.TrainManageReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
wheels, err := service.ListTrainWheelDiameterQuery(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, wheels)
c.JSON(http.StatusOK, service.ListTrainWheelDiameterQuery(&req))
}
// 创建列车轮径
@ -447,13 +408,9 @@ func queryTrainWheelDiameterList(c *gin.Context) {
func createTrainWheelDiameter(c *gin.Context) {
req := dto.TrainWheelDiameterDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("创建失败,参数格式错误", err))
}
data, err := service.CreateTrainWheelDiameter(&req)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
c.JSON(http.StatusOK, data)
c.JSON(http.StatusOK, service.CreateTrainWheelDiameter(&req))
}
// 查询列车轮径详情
@ -475,7 +432,7 @@ func createTrainWheelDiameter(c *gin.Context) {
func queryTrainWheelDiameter(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("查询失败,缺少查询主键"))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
c.JSON(http.StatusOK, service.QueryTrainWheelDiameter(int32(int64Id)))
@ -501,18 +458,14 @@ func queryTrainWheelDiameter(c *gin.Context) {
func updateTrainWheelDiameter(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("更新失败,缺少查询主键"))
}
req := dto.TrainWheelDiameterDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("查询失败,参数格式错误", err))
}
int64Id, _ := strconv.ParseInt(id, 10, 64)
result := service.UpdateTrainWheelDiameter(int32(int64Id), &req)
if !result {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: "保存出错"})
}
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, service.UpdateTrainWheelDiameter(int32(int64Id), &req))
}
// 删除列车轮径数据
@ -535,7 +488,7 @@ func deleteTrainWheelDiameter(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.Atoi(idStr)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: "必要参数id不存在"})
panic(sys_error.New("删除失败,缺少主键"))
}
service.DeleteTrainWheelDiameterById(id)
c.JSON(http.StatusOK, true)

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitUserRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -37,9 +38,12 @@ func register(c *gin.Context) {
user := &dto.RegisterUser{}
err := c.BindJSON(user)
if err != nil {
slog.Warn("用户注册失败", err)
panic(sys_error.New("注册失败,参数错误", err))
}
err = service.Register(user)
if err != nil {
panic(sys_error.New("注册失败", err))
}
service.Register(user)
c.JSON(http.StatusOK, "ok")
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc-gen-go v1.28.1
// protoc v4.23.1
// source: ibpGraphics.proto
@ -239,7 +239,8 @@ type IBPButton struct {
Common *CommonInfo `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"`
Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"`
Color IBPButton_IbpButtonColor `protobuf:"varint,3,opt,name=color,proto3,enum=ibpGraphicData.IBPButton_IbpButtonColor" json:"color,omitempty"`
IsSelfReset bool `protobuf:"varint,4,opt,name=isSelfReset,proto3" json:"isSelfReset,omitempty"`
IsSelfReset bool `protobuf:"varint,4,opt,name=isSelfReset,proto3" json:"isSelfReset,omitempty"` //是否自复位
HasLight bool `protobuf:"varint,5,opt,name=hasLight,proto3" json:"hasLight,omitempty"` //是否带灯
}
func (x *IBPButton) Reset() {
@ -302,6 +303,13 @@ func (x *IBPButton) GetIsSelfReset() bool {
return false
}
func (x *IBPButton) GetHasLight() bool {
if x != nil {
return x.HasLight
}
return false
}
type IBPText struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -701,7 +709,7 @@ var file_ibpGraphics_proto_rawDesc = []byte{
0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x69, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68,
0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x62, 0x70, 0x47, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67,
0x68, 0x74, 0x52, 0x09, 0x69, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x22, 0xf8, 0x01,
0x68, 0x74, 0x52, 0x09, 0x69, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x22, 0x94, 0x02,
0x0a, 0x09, 0x49, 0x42, 0x50, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
@ -713,60 +721,62 @@ var file_ibpGraphics_proto_rawDesc = []byte{
0x74, 0x74, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x73, 0x65, 0x74, 0x18,
0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x73,
0x65, 0x74, 0x22, 0x44, 0x0a, 0x0e, 0x49, 0x62, 0x70, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x43,
0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x08, 0x0a, 0x04, 0x67, 0x72, 0x61, 0x79, 0x10, 0x00, 0x12, 0x07,
0x0a, 0x03, 0x72, 0x65, 0x64, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72, 0x65, 0x65, 0x6e,
0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06,
0x79, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x10, 0x04, 0x22, 0x9a, 0x01, 0x0a, 0x07, 0x49, 0x42, 0x50,
0x54, 0x65, 0x78, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61,
0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e,
0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x6f, 0x6e,
0x74, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x6f, 0x6e,
0x74, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x4f, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x41, 0x6c, 0x61, 0x72,
0x6d, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x4d, 0x0a, 0x06, 0x49, 0x62, 0x70, 0x4b, 0x65, 0x79,
0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05,
0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x68, 0x61, 0x73, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x22, 0x44,
0x0a, 0x0e, 0x49, 0x62, 0x70, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
0x12, 0x08, 0x0a, 0x04, 0x67, 0x72, 0x61, 0x79, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x72, 0x65,
0x64, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x10, 0x02, 0x12, 0x08,
0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x79, 0x65, 0x6c, 0x6c,
0x6f, 0x77, 0x10, 0x04, 0x22, 0x9a, 0x01, 0x0a, 0x07, 0x49, 0x42, 0x50, 0x54, 0x65, 0x78, 0x74,
0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x7b, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x41, 0x72, 0x72, 0x6f,
0x77, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x44, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x73, 0x22, 0xc7, 0x01, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x12,
0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x12, 0x3c, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x26, 0x2e, 0x69, 0x62, 0x70, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61,
0x2e, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67,
0x68, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x22, 0x38, 0x0a, 0x0d, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f,
0x6c, 0x6f, 0x72, 0x12, 0x09, 0x0a, 0x05, 0x77, 0x68, 0x69, 0x74, 0x65, 0x10, 0x00, 0x12, 0x07,
0x0a, 0x03, 0x72, 0x65, 0x64, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72, 0x65, 0x65, 0x6e,
0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x03, 0x22, 0x62, 0x0a, 0x10,
0x49, 0x62, 0x70, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x12, 0x4e, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43,
0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x52, 0x10,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a,
0x65, 0x22, 0x4f, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x41, 0x6c, 0x61, 0x72, 0x6d, 0x12, 0x2f, 0x0a,
0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x22, 0x4d, 0x0a, 0x06, 0x49, 0x62, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x06,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67,
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64,
0x65, 0x22, 0x7b, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x2f, 0x0a,
0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61,
0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xc7,
0x01, 0x0a, 0x08, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x05,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x69, 0x62,
0x70, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x49, 0x62, 0x70,
0x4c, 0x69, 0x67, 0x68, 0x74, 0x2e, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f,
0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x38,
0x0a, 0x0d, 0x49, 0x62, 0x70, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12,
0x09, 0x0a, 0x05, 0x77, 0x68, 0x69, 0x74, 0x65, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x72, 0x65,
0x64, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x10, 0x02, 0x12, 0x08,
0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x03, 0x22, 0x62, 0x0a, 0x10, 0x49, 0x62, 0x70, 0x52,
0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x10,
0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x73,
0x42, 0x21, 0x5a, 0x1f, 0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44,
0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x62, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x62,
0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x42, 0x21, 0x5a, 0x1f,
0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc-gen-go v1.28.1
// protoc v4.23.1
// source: picture.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc-gen-go v1.28.1
// protoc v4.23.1
// source: pslGraphics.proto
@ -231,6 +231,7 @@ type PslButton struct {
Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"`
// string topAnnotation = 3;
ButtonColor PslElementColor `protobuf:"varint,4,opt,name=buttonColor,proto3,enum=pslGraphicData.PslElementColor" json:"buttonColor,omitempty"`
IsSelfReset bool `protobuf:"varint,5,opt,name=isSelfReset,proto3" json:"isSelfReset,omitempty"`
}
func (x *PslButton) Reset() {
@ -286,6 +287,13 @@ func (x *PslButton) GetButtonColor() PslElementColor {
return PslElementColor_red
}
func (x *PslButton) GetIsSelfReset() bool {
if x != nil {
return x.IsSelfReset
}
return false
}
// * PSL钥匙
type PslKey struct {
state protoimpl.MessageState
@ -461,7 +469,7 @@ var file_pslGraphics_proto_rawDesc = []byte{
0x68, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e,
0x70, 0x73, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x50,
0x73, 0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x0a,
0x6c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x93, 0x01, 0x0a, 0x09, 0x50,
0x6c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0xb5, 0x01, 0x0a, 0x09, 0x50,
0x73, 0x6c, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68,
0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49, 0x6e, 0x66,
@ -471,27 +479,29 @@ var file_pslGraphics_proto_rawDesc = []byte{
0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x70, 0x73, 0x6c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44,
0x61, 0x74, 0x61, 0x2e, 0x50, 0x73, 0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f,
0x6c, 0x6f, 0x72, 0x52, 0x0b, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
0x22, 0x4d, 0x0a, 0x06, 0x50, 0x73, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x63,
0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22,
0x9a, 0x01, 0x0a, 0x07, 0x50, 0x73, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04,
0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,
0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f,
0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x12, 0x1a, 0x0a, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01,
0x28, 0x05, 0x52, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x2f, 0x0a, 0x0f,
0x50, 0x73, 0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12,
0x07, 0x0a, 0x03, 0x72, 0x65, 0x64, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72, 0x65, 0x65,
0x6e, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x02, 0x42, 0x21, 0x5a,
0x1f, 0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x73, 0x65, 0x74, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x65, 0x73,
0x65, 0x74, 0x22, 0x4d, 0x0a, 0x06, 0x50, 0x73, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x06,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67,
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64,
0x65, 0x22, 0x9a, 0x01, 0x0a, 0x07, 0x50, 0x73, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x12, 0x2f, 0x0a,
0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f,
0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x05,
0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x6f, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x2f,
0x0a, 0x0f, 0x50, 0x73, 0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f,
0x72, 0x12, 0x07, 0x0a, 0x03, 0x72, 0x65, 0x64, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x67, 0x72,
0x65, 0x65, 0x6e, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x62, 0x6c, 0x75, 0x65, 0x10, 0x02, 0x42,
0x21, 0x5a, 0x1f, 0x2e, 0x2f, 0x61, 0x74, 0x73, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x44, 0x61,
0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc-gen-go v1.28.1
// protoc v4.23.1
// source: relayCabinetLayoutGraphics.proto

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +1,18 @@
package simulation
import (
"encoding/binary"
"log/slog"
"math"
"time"
"joylink.club/rtsssimulation/repository/model/proto"
"fmt"
"net/http"
"strconv"
"sync"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/dynamics"
"joylink.club/bj-rtsts-server/vobc"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
"joylink.club/bj-rtsts-server/dto"
)
func init() {
// vobc 发来的列车信息
vobc.RegisterTrainInfoHandler(func(info []byte) {
memory.UdpUpdateTime.VobcTime = time.Now().UnixMilli()
for _, simulation := range GetSimulationArr() {
simulation.Memory.Status.TrainStateMap.Range(func(_, value any) bool {
train := value.(*state.TrainState)
if !train.Show { // 下线列车
return false
}
// 拼接列车ID
trainId, err := strconv.Atoi(train.Id)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
}
trainInfo := decoderVobcTrainState(info)
d := append(info, uint8(trainId))
// 发送给动力学
dynamics.SendDynamicsTrainMsg(d)
// 存放至列车中
train.VobcState = trainInfo
return true
})
}
})
dynamics.RegisterTrainInfoHandler(func(info *dynamics.TrainInfo) {
slog.Info("发送到vobc的列车编号为", info.Number)
memory.UdpUpdateTime.DynamicsTime = time.Now().UnixMilli()
for _, simulation := range GetSimulationArr() {
sta, ok := simulation.Memory.Status.TrainStateMap.Load(strconv.Itoa(int(info.Number)))
if !ok {
continue
}
trainState := sta.(*state.TrainState)
// 给半实物仿真发送速度
vobc.SendTrainSpeedTask(convertVobc(info))
// 更新列车状态
memory.UpdateTrainState(simulation, convert(info, trainState, simulation))
}
})
}
// 仿真存储集合
var simulationMap sync.Map
@ -78,28 +27,39 @@ func IsExistSimulation() bool {
}
// 创建仿真对象
func CreateSimulation(projectId int32, mapIds []int32) string {
func CreateSimulation(projectId int32, mapIds []int32) (string, error) {
simulationId := createSimulationId(projectId)
_, e := simulationMap.Load(simulationId)
if !e && IsExistSimulation() {
panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"})
// panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"})
return "", sys_error.New("一套环境同时只能运行一个仿真")
}
if !e {
verifySimulation, err := memory.CreateSimulation(projectId, mapIds)
if err != nil {
panic(fmt.Sprintf("创建仿真失败:%s", err.Error()))
return "", err
// panic(fmt.Sprintf("创建仿真失败:%s", err.Error()))
}
verifySimulation.SimulationId = simulationId
//通知动力学
lineBaseInfo := buildLineBaseInfo(verifySimulation)
httpCode, _, err := dynamics.SendSimulationStartReq(lineBaseInfo)
if httpCode != http.StatusOK || err != nil {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
if config.Config.Dynamics.Open {
// 动力学接口调用
lineBaseInfo := verifySimulation.BuildLineBaseInfo()
err := dynamics.Default().RequestStartSimulation(lineBaseInfo)
if err != nil {
return "", err
// panic(dto.ErrorDto{Code: dto.DynamicsError, Message: err.Error()})
}
dynamics.Default().Start(verifySimulation)
}
if config.Config.Vobc.Open {
// 半实物系统接口功能启动
semi_physical_train.Default().Start(verifySimulation)
}
simulationMap.Store(simulationId, verifySimulation)
dynamicsRun(verifySimulation)
// 全部成功,启动仿真
verifySimulation.World.StartUp()
}
return simulationId
return simulationId, nil
}
// 删除仿真对象
@ -112,13 +72,10 @@ func DestroySimulation(simulationId string) {
simulationMap.Delete(simulationId)
// 停止ecs world
simulationInfo.World.Close()
//ecsSimulation.DestroySimulation(simulationInfo.WorldId)
//移除道岔状态发送
dynamics.Stop()
//通知动力学
httpCode, _, err := dynamics.SendSimulationEndReq()
if httpCode != http.StatusOK {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
if config.Config.Dynamics.Open {
// 停止动力学接口功能
dynamics.Default().Stop()
dynamics.Default().RequestStopSimulation()
}
}
@ -161,191 +118,3 @@ func GetSimulationArr() []*memory.VerifySimulation {
})
return result
}
func convert(info *dynamics.TrainInfo, sta *state.TrainState, simulation *memory.VerifySimulation) *state.TrainState {
slog.Debug("收到动力学原始消息", "Number", info.Number, "Link", info.Link, "LinkOffset", info.LinkOffset)
id, port, offset, runDirection, pointTo, kilometer := memory.QueryDeviceByCalcLink(simulation.Repo, strconv.Itoa(int(info.Link)), int64(info.LinkOffset), info.Up)
slog.Debug("处理动力学转换后的消息", "number", info.Number,
"车头位置", id, "偏移", offset, "是否上行", runDirection, "是否ab", pointTo)
sta.HeadDeviceId = simulation.GetComIdByUid(id)
sta.DevicePort = port
sta.HeadOffset = offset
sta.PointTo = pointTo
sta.TrainKilometer = kilometer
sta.RunDirection = runDirection
//判定车头方向
sta.HeadDirection = runDirection
if sta.VobcState != nil {
if sta.VobcState.DirectionForward {
sta.HeadDirection = runDirection
} else if sta.VobcState.DirectionBackward {
sta.HeadDirection = !runDirection
}
}
if info.Speed < 0 {
sta.RunDirection = !sta.RunDirection
}
// 赋值动力学信息
sta.DynamicState.Heartbeat = int32(info.LifeSignal)
sta.DynamicState.HeadLinkId = strconv.Itoa(int(info.Link))
sta.DynamicState.HeadLinkOffset = int64(info.LinkOffset)
sta.DynamicState.Slope = int32(info.Slope)
sta.DynamicState.Upslope = info.UpSlope
sta.DynamicState.RunningUp = info.Up
sta.DynamicState.RunningResistanceSum = float32(info.TotalResistance) / 1000
sta.DynamicState.AirResistance = float32(info.AirResistance) / 1000
sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000
sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000
sta.DynamicState.Speed = speedParse(info.Speed)
sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1)
sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2)
sta.DynamicState.TailSensorSpeed1 = speedParse(info.TailSpeed1)
sta.DynamicState.TailSensorSpeed2 = speedParse(info.TailSpeed2)
sta.DynamicState.HeadRadarSpeed = speedParse(info.HeadRadarSpeed)
sta.DynamicState.TailRadarSpeed = speedParse(info.TailRadarSpeed)
sta.DynamicState.Acceleration = info.Acceleration
return sta
}
// 转换成Vobc发送参数
func convertVobc(info *dynamics.TrainInfo) *vobc.SendTrainInfo {
param := &vobc.SendTrainInfo{
Speed: uint16(math.Abs(float64(info.Speed * 36))),
Upslope: info.UpSlope,
Slope: uint16(info.Slope),
TotalResistance: uint32(math.Abs(float64(info.TotalResistance / 10))),
AirResistance: uint32(info.AirResistance / 10),
SlopeResistance: uint32(math.Abs(float64(info.SlopeResistance / 10))),
CurveResistance: uint32(info.CurveResistance / 10),
}
d := math.Abs(float64(info.Acceleration * 100))
if info.Acceleration > 0 {
param.Acceleration = uint8(d)
} else {
param.Deceleration = uint8(d)
}
return param
}
func dynamicsRun(verifySimulation *memory.VerifySimulation) {
_ = dynamics.Run(func() []*dynamics.TurnoutInfo {
stateSlice := memory.GetAllTurnoutState(verifySimulation)
var turnoutInfoSlice []*dynamics.TurnoutInfo
for _, sta := range stateSlice {
code64, err := strconv.ParseUint(sta.Id, 10, 16)
if err != nil {
slog.Error("id转uint16报错", err)
}
info := dynamics.TurnoutInfo{
Code: uint16(code64),
NPosition: sta.Dw,
RPosition: sta.Fw,
}
turnoutInfoSlice = append(turnoutInfoSlice, &info)
}
return turnoutInfoSlice
})
}
func buildLineBaseInfo(sim *memory.VerifySimulation) *dynamics.LineBaseInfo {
info := &dynamics.LineBaseInfo{}
for _, model := range sim.Repo.LinkList() {
id, _ := strconv.Atoi(model.Id())
link := &dynamics.Link{
ID: int32(id),
Len: int32(model.Length()),
}
info.LinkList = append(info.LinkList, link)
if model.ARelation() != nil {
turnoutId, _ := strconv.Atoi(sim.GetComIdByUid(model.ARelation().Device().Id()))
link.ARelTurnoutId = int32(turnoutId)
switch model.ARelation().Port() {
case proto.Port_A:
link.ARelTurnoutPoint = "A"
case proto.Port_B:
link.ARelTurnoutPoint = "B"
case proto.Port_C:
link.ARelTurnoutPoint = "C"
}
}
if model.BRelation() != nil {
turnoutId, _ := strconv.Atoi(sim.GetComIdByUid(model.BRelation().Device().Id()))
link.BRelTurnoutId = int32(turnoutId)
switch model.BRelation().Port() {
case proto.Port_A:
link.BRelTurnoutPoint = "A"
case proto.Port_B:
link.BRelTurnoutPoint = "B"
case proto.Port_C:
link.BRelTurnoutPoint = "C"
}
}
}
for _, model := range sim.Repo.SlopeList() {
id, _ := strconv.Atoi(sim.GetComIdByUid(model.Id()))
slope := &dynamics.Slope{
ID: int32(id),
StartLinkOffset: int32(model.StartLinkPosition().Offset()),
EndLinkOffset: int32(model.EndLinkPosition().Offset()),
DegreeTrig: model.Degree(),
}
info.SlopeList = append(info.SlopeList, slope)
startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id())
slope.StartLinkId = int32(startLinkId)
endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id())
slope.EndLinkId = int32(endLinkId)
}
for _, model := range sim.Repo.SectionalCurvatureList() {
id, _ := strconv.Atoi(sim.GetComIdByUid(model.Id()))
curve := &dynamics.Curve{
ID: int32(id),
StartLinkOffset: int32(model.StartLinkPosition().Offset()),
EndLinkOffset: int32(model.EndLinkPosition().Offset()),
Curvature: model.Radius(),
}
info.CurveList = append(info.CurveList, curve)
startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id())
curve.StartLinkId = int32(startLinkId)
endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id())
curve.EndLinkId = int32(endLinkId)
}
return info
}
// 解析VOBC列车信息
func decoderVobcTrainState(buf []byte) *state.TrainVobcState {
trainVobcInfo := &state.TrainVobcState{}
trainVobcInfo.LifeSignal = int32(binary.BigEndian.Uint16(buf[0:2]))
b2 := buf[2]
trainVobcInfo.Tc1Active = (b2 & 1) != 0
trainVobcInfo.Tc2Active = (b2 & (1 << 1)) != 0
trainVobcInfo.DirectionForward = (b2 & (1 << 2)) != 0
trainVobcInfo.DirectionBackward = (b2 & (1 << 3)) != 0
trainVobcInfo.TractionStatus = (b2 & (1 << 4)) != 0
trainVobcInfo.BrakingStatus = (b2 & (1 << 5)) != 0
trainVobcInfo.EmergencyBrakingStatus = (b2 & (1 << 6)) != 0
trainVobcInfo.TurnbackStatus = (b2 & 7) != 0
b3 := buf[3]
trainVobcInfo.JumpStatus = (b3 & 1) != 0
trainVobcInfo.Ato = (b3 & (1 << 1)) != 0
trainVobcInfo.Fam = (b3 & (1 << 2)) != 0
trainVobcInfo.Cam = (b3 & (1 << 3)) != 0
trainVobcInfo.TractionSafetyCircuit = (b3 & (1 << 4)) != 0
trainVobcInfo.ParkingBrakeStatus = (b3 & (1 << 5)) != 0
trainVobcInfo.MaintainBrakeStatus = (b3 & (1 << 6)) != 0
trainVobcInfo.TractionForce = int64(binary.BigEndian.Uint16(buf[4:6]))
trainVobcInfo.BrakeForce = int64(binary.BigEndian.Uint16(buf[6:8]))
trainVobcInfo.TrainLoad = int64(binary.BigEndian.Uint16(buf[8:10]))
b4 := buf[15]
trainVobcInfo.LeftDoorOpenCommand = (b4 & 1) != 0
trainVobcInfo.RightDoorOpenCommand = (b4 & (1 << 1)) != 0
trainVobcInfo.LeftDoorCloseCommand = (b4 & (1 << 2)) != 0
trainVobcInfo.RightDoorCloseCommand = (b4 & (1 << 3)) != 0
trainVobcInfo.AllDoorClose = (b4 & (1 << 4)) != 0
return trainVobcInfo
}
// 发送给前端的速度格式化
func speedParse(speed float32) int32 {
return int32(math.Abs(float64(speed * 3.6 * 100)))
}

View File

@ -0,0 +1,97 @@
package memory
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/ecs"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/entity"
"joylink.club/rtsssimulation/fi"
)
// 操作IBP按钮
func ChangeIBPButtonState(sim *VerifySimulation, mapId int32, stationId, btnCode string, pressDown bool) {
stationUid := QueryUidByMidAndComId(mapId, stationId, &graphicData.Station{})
if pressDown {
fi.PressDownButton(sim.World, stationUid+"_button_"+btnCode)
} else {
fi.PressUpButton(sim.World, stationUid+"_button_"+btnCode)
}
}
// 操作IBP按钮
func ChangeIBPKeyState(sim *VerifySimulation, mapId int32, stationId, keyCode string, gear int32) {
stationUid := QueryUidByMidAndComId(mapId, stationId, &graphicData.Station{})
fi.SwitchKeyGear(sim.World, stationUid+"_key_"+keyCode, gear)
}
// 获取仿真车站按钮状态,前端推送
func GetMapAllIBPState(sim *VerifySimulation, mapId int32, stationId, ibpMapCode string) *state.AllDevicesStatus {
status := &state.AllDevicesStatus{
ButtonState: []*state.ButtonState{},
LightState: []*state.LightState{},
AlarmState: []*state.AlarmState{},
KeyState: []*state.KeyState{},
}
stationUid := QueryUidByMidAndComId(mapId, stationId, &graphicData.Station{})
ibpStorage := getStorageIBPMapData(ibpMapCode)
for _, data := range ibpStorage.IbpButtons { // 按钮
entry, ok := entity.GetEntityByUid(sim.World, stationUid+"_button_"+data.Code)
if !ok {
continue
}
if entry.HasComponent(component.ButtonTag) {
status.ButtonState = append(status.ButtonState, getIBPButtonState(data.Common.Id, entry))
}
}
for _, data := range ibpStorage.IbpAlarms { // 报警器
entry, ok := entity.GetEntityByUid(sim.World, stationUid+"_alarm_"+data.Code)
if !ok {
continue
}
if entry.HasComponent(component.AlarmTag) {
status.AlarmState = append(status.AlarmState, &state.AlarmState{
Id: data.Common.Id,
Active: component.BitStateType.Get(entry).Val,
})
}
}
for _, data := range ibpStorage.IbpLights { // 指示灯
entry, ok := entity.GetEntityByUid(sim.World, stationUid+"_light_"+data.Code)
if !ok {
continue
}
if entry.HasComponent(component.LightTag) {
status.LightState = append(status.LightState, &state.LightState{
Id: data.Common.Id,
Active: component.BitStateType.Get(entry).Val,
})
}
}
for _, data := range ibpStorage.IbpKeys { // 钥匙
entry, ok := entity.GetEntityByUid(sim.World, stationUid+"_key_"+data.Code)
if !ok {
continue
}
if entry.HasComponent(component.KeyTag) {
status.KeyState = append(status.KeyState, &state.KeyState{
Id: data.Common.Id,
Gear: component.GearStateType.Get(entry).Val,
})
}
}
return status
}
// 获取IBP盘按钮状态
func getIBPButtonState(id string, entry *ecs.Entry) *state.ButtonState {
status := &state.ButtonState{Id: id}
bit := component.BitStateType.Get(entry)
status.Down = bit.Val
// 如果按钮包含灯
if entry.HasComponent(component.SingleLightType) {
lightComponent := component.SingleLightType.Get(entry)
status.Active = component.BitStateType.Get(lightComponent.Light).Val
}
return status
}

View File

@ -13,6 +13,7 @@ import (
"google.golang.org/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
)
@ -73,8 +74,13 @@ func DeleteMapVerifyStructure(mapId int32) {
func QueryGiType(mapId int32) graphicData.PictureType {
value, ok := giTypeMap.Load(mapId)
if !ok {
graphic, err := dbquery.PublishedGi.Debug().Where(dbquery.PublishedGi.ID.Eq(mapId)).First() // 当缓存缺失新地图时,查询一次
if err != nil {
panic(&dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("[mapId:%d]类型映射错误 :%v", mapId, value)})
}
PublishMapVerifyStructure(graphic)
return graphicData.PictureType(graphic.Type)
}
return value.(graphicData.PictureType)
}
@ -83,6 +89,11 @@ func QueryGiData[T proto.Message](mapId int32) T {
return value.(T)
}
func QueryGiId(name string) int32 {
value, _ := giNameMap.Load(name)
return value.(int32)
}
// 根据区段道岔偏移量返回linkID和link相对偏移量
func QueryEcsLinkByDeviceInfo(repo *repository.Repository, mapId int32, id string, devicePort string, offset int64, runDirection bool) (int32, int64, bool, bool, int64) {
if devicePort == "" {
@ -117,19 +128,20 @@ func sectionMapToEcsLink(repo *repository.Repository, id string, offset int64, r
panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("地图不存在uid:%s缓存", id)})
}
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
// 是否从A到B
ak, bk := section.AKilometer().Value, section.BKilometer().Value
// 是否从A到B统一坐标
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
akv, bkv := ak.Value, bk.Value
// 上行
var up, abDirection bool
if runDirection {
abDirection = ak < bk
abDirection = akv < bkv
if abDirection {
up = ao < bo
} else {
up = ao > bo
}
} else {
abDirection = ak > bk
abDirection = akv > bkv
if abDirection {
up = ao < bo
} else {
@ -137,7 +149,7 @@ func sectionMapToEcsLink(repo *repository.Repository, id string, offset int64, r
}
}
linkId, _ := strconv.Atoi(section.ALinkPosition().Link().Identity.Id())
trainKilometer := concertTrainKilometer(ak, offset, up)
trainKilometer := concertTrainKilometer(akv, offset, up)
if ao < bo {
return int32(linkId), ao + offset, up, abDirection, trainKilometer
} else {
@ -168,7 +180,10 @@ func turnoutMapToEcsLink(repo *repository.Repository, id string, port string, of
}
// 岔心公里标
crossKm = turnout.GetTurnoutKm(proto2.Port_None)
portKm = repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
portKm, err := repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
if err != nil {
panic(err)
}
// 关联link
link := portPosition.Link()
isStart := link.ARelation().Device().Id() == id
@ -204,7 +219,7 @@ func QueryDeviceByCalcLink(repo *repository.Repository, id string, offset int64,
if onTurnout {
return ecsLinkMapToTurnout(repo, isA, offset, up, link)
} else {
return ecsLinkMapToSection(offset, up, link)
return ecsLinkMapToSection(repo, offset, up, link)
}
}
@ -236,7 +251,10 @@ func ecsLinkMapToTurnout(repo *repository.Repository, isA bool, offset int64, up
deviceId = tp.Turnout().Id()
tpOffset := tp.Turnout().FindLinkPositionByPort(tp.Port()).Offset()
crossKmInfo, portKmInfo := tp.Turnout().GetTurnoutKm(proto2.Port_None), tp.Turnout().GetTurnoutKm(tp.Port())
portKmInfo = repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
portKmInfo, err := repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
if err != nil {
panic(err)
}
crossKm, portKm := crossKmInfo.Value, portKmInfo.Value
if isA {
deviceOffset = tpOffset - (tpOffset - offset)
@ -272,12 +290,12 @@ func ecsLinkMapToTurnout(repo *repository.Repository, isA bool, offset int64, up
}
// 处理在道岔上link映射
func ecsLinkMapToSection(offset int64, up bool, link *repository.Link) (
func ecsLinkMapToSection(repo *repository.Repository, offset int64, up bool, link *repository.Link) (
deviceId, port string, deviceOffset int64, runDirection, pointTo bool, km int64) {
var section *repository.PhysicalSection
for _, s := range link.PhysicalSections() {
ao, bo := s.ALinkPosition().Offset(), s.BLinkPosition().Offset()
if (ao <= offset && offset < bo) || (bo <= offset && offset < ao) {
if (ao < offset && offset <= bo) || (bo < offset && offset <= ao) {
section = s
break
}
@ -289,21 +307,22 @@ func ecsLinkMapToSection(offset int64, up bool, link *repository.Link) (
deviceId = section.Id()
// link偏移变大方向
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
ak, bk := section.AKilometer().Value, section.BKilometer().Value
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
akv, bkv := ak.Value, bk.Value
if up {
if ao < bo {
runDirection = ak < bk
runDirection = akv < bkv
} else {
runDirection = ak > bk
runDirection = akv > bkv
}
} else {
if ao > bo {
runDirection = ak < bk
runDirection = akv < bkv
} else {
runDirection = ak > bk
runDirection = akv > bkv
}
}
pointTo = runDirection == (ak < bk)
pointTo = runDirection == (akv < bkv)
// a点偏移 大于 b点偏移
if ao > bo {
deviceOffset = ao - offset
@ -311,10 +330,10 @@ func ecsLinkMapToSection(offset int64, up bool, link *repository.Link) (
deviceOffset = offset - ao
}
// a点公里标 大于 b点公里标
if ak > bk {
km = ak - deviceOffset
if akv > bkv {
km = akv - deviceOffset
} else {
km = ak + deviceOffset
km = akv + deviceOffset
}
return
}
@ -327,3 +346,12 @@ func concertTrainKilometer(kilometer, offset int64, tendTo bool) int64 {
return kilometer + offset
}
}
// 转换成统一坐标公里标
func convertRepoBaseKm(r *repository.Repository, km *proto2.Kilometer) *proto2.Kilometer {
k, err := r.ConvertKilometer(km, r.GetCoordinateInfo().Coordinate)
if err != nil {
panic(err)
}
return k
}

View File

@ -18,7 +18,7 @@ type elementIdStructure struct {
Uid string
}
// 数组为Index为 common.Id, index, uid
// 数组为Index为 common.ButtonCode, index, uid
type stationUidStructure struct {
AxlePointIds map[string]*elementIdStructure
TurnoutIds map[string]*elementIdStructure
@ -29,7 +29,9 @@ type stationUidStructure struct {
CurvatureIds map[string]*elementIdStructure
ButtonIds map[string]*elementIdStructure
StationIds map[string]*elementIdStructure
IBPIds map[string]map[string]*elementIdStructure
PlatformIds map[string]*elementIdStructure
PsdIds map[string]*elementIdStructure
GateBoxIds map[string]*elementIdStructure
}
type relayUidStructure struct {
@ -74,7 +76,9 @@ func initStationUid(data *graphicData.RtssGraphicStorage) *stationUidStructure {
CurvatureIds: make(map[string]*elementIdStructure, len(data.Curvatures)),
ButtonIds: make(map[string]*elementIdStructure, len(data.EsbButtons)),
StationIds: make(map[string]*elementIdStructure, len(data.Stations)),
IBPIds: make(map[string]map[string]*elementIdStructure, len(data.Stations)),
PlatformIds: make(map[string]*elementIdStructure, len(data.Platforms)),
PsdIds: make(map[string]*elementIdStructure, len(data.ScreenDoors)),
GateBoxIds: make(map[string]*elementIdStructure, len(data.GateBoxs)),
}
city, lineId, _ := getUIdPrefix(data.UniqueIdPrefix)
// 初始化计轴信息
@ -150,74 +154,52 @@ func initStationUid(data *graphicData.RtssGraphicStorage) *stationUidStructure {
}
gus.ButtonIds[b.Common.Id] = &elementIdStructure{
CommonId: b.Common.Id,
Code: b.Code,
Uid: GenerateElementUid(city, lineId, nil, code),
}
}
// 处理车站信息
stationMap := make(map[string]*graphicData.Station)
for _, s := range data.Stations {
stationMap[s.Common.Id] = s
gus.StationIds[s.Common.Id] = &elementIdStructure{
CommonId: s.Common.Id,
Uid: GenerateElementUid(city, lineId, nil, s.Code),
Uid: GenerateElementUid(city, lineId, nil, s.StationName),
}
}
// 站台
platformMap := make(map[string]*graphicData.Platform)
for _, platform := range data.Platforms {
platformMap[platform.Common.Id] = platform
gus.PlatformIds[platform.Common.Id] = &elementIdStructure{
CommonId: platform.Common.Id,
Uid: GenerateElementUid(city, lineId, nil, platform.Code),
}
}
// 屏蔽门
psd_station_map := make(map[string]string)
for _, door := range data.ScreenDoors {
station := stationMap[platformMap[door.RefPlatformId].GetRefStationId()]
if station == nil { //线路数据有问题
continue
}
psd_station_map[door.Common.Id] = station.Common.Id
gus.PsdIds[door.Common.Id] = &elementIdStructure{
CommonId: door.Common.Id,
Uid: GenerateElementUid(city, lineId, []string{station.Common.Id}, door.Code),
}
}
// 门控箱
for _, box := range data.GateBoxs {
stationId := psd_station_map[box.RefScreenDoor]
gus.GateBoxIds[box.Common.Id] = &elementIdStructure{
CommonId: box.Common.Id,
Uid: GenerateElementUid(city, lineId, []string{stationId}, box.Code),
}
// 处理关联的IBP盘信息
initIBPUid(gus, city, lineId, s, getStorageIBPMapData(s.RefIbpMapCode))
}
return gus
}
// 处理IBP盘信息
func initIBPUid(gus *stationUidStructure, city, lineId string, station *graphicData.Station, data *graphicData.IBPGraphicStorage) {
if data == nil {
return
}
// 设备所属组合
refMap := make(map[string]string)
for _, r := range data.IbpRelatedDevices {
for _, c := range r.Combinationtypes {
for _, i := range c.RefDevices {
refMap[i] = c.Code
}
}
}
getCode := func(id, code string) string {
p := refMap[id]
if p == "" {
return code
}
return p + "_" + code
}
uidMap := make(map[string]*elementIdStructure, len(data.IbpButtons)+len(data.IbpKeys)+len(data.IbpAlarms)+len(data.IbpLights))
for _, d := range data.IbpButtons { // ibp按钮
uidMap[d.Common.Id] = &elementIdStructure{
CommonId: d.Common.Id,
Code: d.Code,
Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)),
}
}
for _, d := range data.IbpKeys { // ibp钥匙
uidMap[d.Common.Id] = &elementIdStructure{
CommonId: d.Common.Id,
Code: d.Code,
Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)),
}
}
for _, d := range data.IbpAlarms { // ibp报警器
uidMap[d.Common.Id] = &elementIdStructure{
CommonId: d.Common.Id,
Code: d.Code,
Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)),
}
}
for _, d := range data.IbpLights { // ibp指示灯
uidMap[d.Common.Id] = &elementIdStructure{
CommonId: d.Common.Id,
Code: d.Code,
Uid: GenerateElementUid(city, lineId, []string{station.Code}, getCode(d.Common.Id, d.Code)),
}
}
gus.IBPIds[station.Code] = uidMap
}
// 初始化继电器柜 UID
func initRelayCabinetUid(data *graphicData.RelayCabinetGraphicStorage) *relayUidStructure {
rus := &relayUidStructure{
@ -280,7 +262,7 @@ func initRelayCabinetUid(data *graphicData.RelayCabinetGraphicStorage) *relayUid
return rus
}
// 构建仿真内所有地图UID映射信号布置图ID
// 构建仿真内所有地图UID映射信号布置图ID,这里为了解决多地图时根据UID反向寻找避免多次循环地图直接获取平面布置图元素
func buildRepositoryAllUidsMap(mapIds []int32, repo *repository.Repository) map[string]*elementIdStructure {
mapLen := len(repo.CheckPointList()) + len(repo.PhysicalSectionList()) + len(repo.SignalList()) +
len(repo.TurnoutList()) + len(repo.ResponderList()) + len(repo.SlopeList()) + len(repo.SectionalCurvatureList())
@ -305,9 +287,6 @@ func buildRepositoryAllUidsMap(mapIds []int32, repo *repository.Repository) map[
saveToAllUidMap(u.SlopeIds)
saveToAllUidMap(u.CurvatureIds)
saveToAllUidMap(u.ButtonIds)
for _, ids := range u.IBPIds {
saveToAllUidMap(ids)
}
continue
}
}
@ -346,6 +325,8 @@ func getUidMapByType(uidData any, m interface{}) map[string]*elementIdStructure
return (uidData.(*relayUidStructure)).RelayIds
case *graphicData.EsbButton:
return (uidData.(*stationUidStructure)).ButtonIds
case *graphicData.Station:
return (uidData.(*stationUidStructure)).StationIds
default:
panic(&dto.ErrorDto{Code: dto.ArgumentParseError, Message: "类型未映射字段"})
}
@ -368,27 +349,3 @@ func QueryUidByMidAndComId(mapId int32, comId string, m interface{}) string {
}
panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("地图【id:%d】不存在【comId:%s】缓存", mapId, comId)})
}
// 根据地图、车站CODE、设备类型获取UID集合
func QueryIBPUidMapByType(mapId int32, stationCode string, m interface{}) map[string]*elementIdStructure {
uidData, ok := giUidMap.Load(mapId)
if !ok {
panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("地图【id:%d】不存在uid缓存", mapId)})
}
switch m.(type) {
// Ibp相关
case *graphicData.IBPButton, *graphicData.IbpAlarm, *graphicData.IbpKey, *graphicData.IbpLight:
return (uidData.(*stationUidStructure)).IBPIds[stationCode]
default:
panic(&dto.ErrorDto{Code: dto.ArgumentParseError, Message: "类型未映射字段"})
}
}
// 根据地图的comId获取UID
func QueryIBPUidByMidAndComId(mapId int32, comId, stationCode string, m interface{}) string {
uidMap := QueryIBPUidMapByType(mapId, stationCode, m)
if uidMap[comId] != nil {
return uidMap[comId].Uid
}
panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("地图【id:%d】不存在【comId:%s】缓存", mapId, comId)})
}

View File

@ -0,0 +1,50 @@
package memory
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/entity"
)
// 获取所有的列车信息
func GetMapAllPsdState(vs *VerifySimulation, mapId int32) []*state.PsdState {
world := vs.GetSimulationWorld()
uidStructure := queryUidStructure[*stationUidStructure](mapId)
data := QueryGiData[*graphicData.RtssGraphicStorage](mapId)
var psdStateArr []*state.PsdState
for _, door := range data.ScreenDoors {
uid := uidStructure.PsdIds[door.Common.Id].Uid
psdEntry, ok := entity.GetEntityByUid(world, uid)
if ok {
var amount int32
psdState := component.PsdStateType.Get(psdEntry)
if psdState.Km8 {
amount = 8
} else if psdState.Km4 {
amount = 4
} else {
amount = 0
}
start, end := getStartEndCodeByGroup(door, amount)
var openSubDoor []int32
for i := start; i <= end; i++ {
openSubDoor = append(openSubDoor, i)
}
psdStateArr = append(psdStateArr, &state.PsdState{
Id: door.Common.Id,
OpenDoorCodes: openSubDoor,
})
}
}
return psdStateArr
}
func getStartEndCodeByGroup(door *graphicData.ScreenDoor, groupAmount int32) (int32, int32) {
for _, group := range door.ScreenDoorGroupList {
if group.TrainGroupAmount == groupAmount {
return group.StartSmallDoor, group.EndSmallDoor
}
}
return 0, -1
}

View File

@ -0,0 +1,16 @@
package memory
import (
"joylink.club/rtsssimulation/fi"
)
// 操作IBP按钮
func ChangePSLButtonState(sim *VerifySimulation, mapId int32, gateBoxId, btnCode string, pressDown bool) {
uid := queryUidStructure[*stationUidStructure](mapId)
gateBoxUid := uid.GateBoxIds[gateBoxId].Uid
if pressDown {
fi.PressDownButton(sim.World, gateBoxUid+"_"+btnCode)
} else {
fi.PressUpButton(sim.World, gateBoxUid+"_"+btnCode)
}
}

View File

@ -2,45 +2,124 @@ package memory
import (
"fmt"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/entity"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dto/request_proto"
"joylink.club/ecs"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/component/component_proto"
"joylink.club/rtsssimulation/consts"
"joylink.club/rtsssimulation/entity"
"joylink.club/rtsssimulation/fi"
"joylink.club/rtsssimulation/repository"
"joylink.club/rtsssimulation/repository/model/proto"
"log/slog"
)
func ChangeSignalState(simulation *VerifySimulation, mapId int32, signalDeviceId string, toAspect state.Signal_Aspect) {
signalUid := QueryUidByMidAndComId(mapId, signalDeviceId, &graphicData.Signal{})
func ChangeSignalState(simulation *VerifySimulation, req *dto.SignalOperationReqDto) {
signalUid := QueryUidByMidAndComId(req.MapId, req.DeviceId, &graphicData.Signal{})
signalModel, err := simulation.Repo.FindModel(signalUid, proto.DeviceType_DeviceType_Signal)
if err != nil {
panic(fmt.Sprintf("信号机[%s]模型不存在", signalUid))
}
signalGroupCode := signalModel.(*repository.Signal).Code()
slog.Info("信号机操作", "uid", signalUid, "组合类型码", signalGroupCode)
switch req.Operation {
case request_proto.Signal_Display: //信号机显示信号设置
{
switch signalGroupCode {
case consts.SIGNAL_2XH1:
changeSignal2XH1State(simulation.World, signalUid, toAspect)
changeSignal2XH1State(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_3XH1:
changeSignal3XH1State(simulation.World, signalUid, toAspect)
changeSignal3XH1State(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_3XH2:
changeSignal3XH2State(simulation.World, signalUid, toAspect)
changeSignal3XH2State(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_3XH3:
changeSignal3XH3State(simulation.World, signalUid, toAspect)
changeSignal3XH3State(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_3XH4:
changeSignal3XH4State(simulation.World, signalUid, toAspect)
changeSignal3XH4State(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_DCXH:
changeSignalDCXHState(simulation.World, signalUid, toAspect)
changeSignalDCXHState(simulation.World, signalUid, req.Aspect)
case consts.SIGNAL_JCKXH:
changeSignalJCKXHState(simulation.World, signalUid, toAspect)
changeSignalJCKXHState(simulation.World, signalUid, req.Aspect)
default:
panic(dto.ErrorDto{Code: dto.OperationOfSignalNotSupported, Message: fmt.Sprintf("操作[%s]的信号机,无法识别组合类型[%s]", signalUid, signalGroupCode)})
}
}
case request_proto.Signal_LightHFaultDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_H, component_proto.Signal_DS, true)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightHCancelDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_H, component_proto.Signal_DS, false)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightLFaultDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_L, component_proto.Signal_DS, true)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightLCancelDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_L, component_proto.Signal_DS, false)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightUFaultDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_U, component_proto.Signal_DS, true)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightUCancelDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_U, component_proto.Signal_DS, false)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightAFaultDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_A, component_proto.Signal_DS, true)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightACancelDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_A, component_proto.Signal_DS, false)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightBFaultDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_B, component_proto.Signal_DS, true)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
case request_proto.Signal_LightBCancelDs:
{
e := fi.UpdateSignalLightFault(simulation.World, signalUid, component_proto.Light_B, component_proto.Signal_DS, false)
if e != nil {
panic(dto.ErrorDto{Code: dto.OperationOfSignalError, Message: dto.ErrorTipMap[dto.OperationOfSignalError]})
}
}
}
}
func changeSignalJCKXHState(w ecs.World, signalUid string, toAspect state.Signal_Aspect) {
switch toAspect {
case state.Signal_U:

View File

@ -0,0 +1,37 @@
package memory
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/entity"
"joylink.club/rtsssimulation/fi"
)
// 操作IBP按钮
func ChangeEsbButtonState(sim *VerifySimulation, mapId int32, btnId string, pressDown bool) {
uid := QueryUidByMidAndComId(mapId, btnId, &graphicData.EsbButton{})
if pressDown {
fi.PressDownButton(sim.World, uid)
} else {
fi.PressUpButton(sim.World, uid)
}
}
// 获取仿真车站按钮状态,前端推送
func GetMapAllStationButtonState(sim *VerifySimulation, mapId int32) []*state.ButtonState {
// 获取地图上的按钮状态
var btnStateArr []*state.ButtonState
uidMap := QueryMapUidMapByType(mapId, &graphicData.EsbButton{})
for _, u := range uidMap {
entry, ok := entity.GetEntityByUid(sim.World, u.Uid)
if !ok {
continue
}
if entry.HasComponent(component.ButtonTag) { // 按钮
bit := component.BitStateType.Get(entry)
btnStateArr = append(btnStateArr, &state.ButtonState{Id: u.CommonId, Down: bit.Val})
}
}
return btnStateArr
}

View File

@ -4,24 +4,16 @@ import (
"fmt"
"log/slog"
"math"
"net/http"
"strconv"
"sync"
"time"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dynamics"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/message"
"google.golang.org/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
)
// 仿真列车UDP更新时间
var UdpUpdateTime = struct {
DynamicsTime int64
VobcTime int64
}{}
// 增加列车状态
func AddTrainState(vs *VerifySimulation, status *state.TrainState, mapId int32) {
allTrainMap := &vs.Memory.Status.TrainStateMap
@ -38,7 +30,7 @@ func AddTrainState(vs *VerifySimulation, status *state.TrainState, mapId int32)
status.Up = up
status.PointTo = pointTo
status.TrainKilometer = kilometer
httpCode, _, err := dynamics.SendInitTrainReq(&dynamics.InitTrainInfo{
err := dynamics.Default().RequestAddTrain(&message.InitTrainInfo{
TrainIndex: uint16(trainIndex),
LinkIndex: uint16(linkId),
LinkOffset: uint32(loffset),
@ -48,11 +40,12 @@ func AddTrainState(vs *VerifySimulation, status *state.TrainState, mapId int32)
})
slog.Debug("添加列车", "trainIndex", trainIndex, "HeadDeviceId", status.HeadDeviceId, "HeadOffset", status.HeadOffset)
slog.Debug("列车初始化", "trainIndex", trainIndex, "linkId", linkId, "loffset", loffset)
if err != nil || httpCode != http.StatusOK {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
if err != nil {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: err.Error()})
}
// 调用成功后初始化列车的动力学
status.DynamicState = &state.TrainDynamicState{}
status.VobcState = &state.TrainVobcState{}
// 将信息合并到当前设备状态中
allTrainMap.Store(status.Id, status)
// 将变更信息放入变更状态队列中
@ -84,11 +77,14 @@ func RemoveTrainState(vs *VerifySimulation, id string) {
if ok {
t := d.(*state.TrainState)
trainIndex, _ := strconv.ParseUint(id, 10, 16)
httpCode, _, err := dynamics.SendRemoveTrainReq(&dynamics.InitTrainInfo{
err := dynamics.Default().RequestRemoveTrain(&message.RemoveTrainReq{
TrainIndex: uint16(trainIndex),
})
if err != nil || httpCode != http.StatusOK {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
// httpCode, _, err := dynamics.SendRemoveTrainReq(&dynamics.InitTrainInfo{
// TrainIndex: uint16(trainIndex),
// })
if err != nil {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: err.Error()})
}
// 从仿真内存中移除列车
t.Show = false
@ -104,44 +100,13 @@ func RemoveTrainState(vs *VerifySimulation, id string) {
func GetAllTrainState(vs *VerifySimulation) []*state.TrainState {
allTrainMap := &vs.Memory.Status.TrainStateMap
var trainArr []*state.TrainState
dus, vus := judgeUdpInterruption()
allTrainMap.Range(func(_, v any) bool {
train := v.(*state.TrainState)
if train.DynamicState != nil {
train.DynamicState.UdpInterruption = dus
}
if train.VobcState != nil {
train.VobcState.UdpInterruption = vus
}
trainArr = append(trainArr, train)
trainArr = append(trainArr, v.(*state.TrainState))
return true
})
return trainArr
}
// 获取变更列车状态并清空
func GetUpdatedTrainState(vs *VerifySimulation) []*state.TrainState {
changeTrainMap := &vs.Memory.ChangeStatus.TrainStateMap
var trainArr []*state.TrainState
dus, vus := judgeUdpInterruption()
changeTrainMap.Range(func(_, v any) bool {
d := v.(*state.TrainState)
if d.DynamicState != nil {
d.DynamicState.UdpInterruption = dus
}
if d.VobcState != nil {
d.VobcState.UdpInterruption = vus
}
trainArr = append(trainArr, d)
return true
})
if len(trainArr) > 0 {
// 清空变更信息
vs.Memory.ChangeStatus.TrainStateMap = sync.Map{}
}
return trainArr
}
// 获取移除列车ID并清空
func GetRemovedTrainId(vs *VerifySimulation) []string {
ids := vs.Memory.ChangeStatus.RemoveTrainId
@ -156,16 +121,3 @@ func GetRemovedTrainId(vs *VerifySimulation) []string {
}
return []string{}
}
// 判断UDP是否终端
func judgeUdpInterruption() (bool, bool) {
dynamicsUdpStatus, vobcUdpStatus := false, false
curTime := time.Now().UnixMilli()
if UdpUpdateTime.DynamicsTime != 0 {
dynamicsUdpStatus = (curTime - UdpUpdateTime.DynamicsTime) > 100
}
if UdpUpdateTime.VobcTime != 0 {
vobcUdpStatus = (curTime - UdpUpdateTime.VobcTime) > 100
}
return dynamicsUdpStatus, vobcUdpStatus
}

View File

@ -14,16 +14,6 @@ import (
"joylink.club/bj-rtsts-server/dto/request_proto"
)
// 道岔相关道岔操作方法
func ChangeTurnoutState(simulation *VerifySimulation, status *state.SwitchState, mapId int32) {
uid := QueryUidByMidAndComId(mapId, status.Id, &graphicData.Turnout{})
if status.Normal {
fi.DriveTurnoutDCOn(simulation.World, uid)
} else if status.Reverse {
fi.DriveTurnoutFCOn(simulation.World, uid)
}
}
// 处理道岔操作
func HandleTurnoutOperation(simulation *VerifySimulation, req *request_proto.TurnoutOperationReq) {
uid := QueryUidByMidAndComId(req.MapId, req.DeviceId, &graphicData.Turnout{})

View File

@ -3,16 +3,26 @@ package memory
import (
"fmt"
"log/slog"
"math"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"time"
"joylink.club/rtsssimulation/component"
"joylink.club/rtsssimulation/entity"
rtss_simulation "joylink.club/rtsssimulation"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
"joylink.club/ecs"
"joylink.club/rtsssimulation/repository"
"joylink.club/rtsssimulation/repository/model/proto"
@ -96,40 +106,55 @@ func CreateSimulation(projectId int32, mapIds []int32) (*VerifySimulation, error
if repo == nil {
protoRepo, err := buildProtoRepository(mapIds)
if err != nil {
return nil, err
return nil, sys_error.New("数据错误", err)
}
protoRepo.Id, protoRepo.Version = repoId, repoVersion
newRepo, err := repository.BuildRepository(protoRepo)
if err != nil {
return nil, err
return nil, sys_error.New("数据错误", err)
}
repo = newRepo
}
// 目前用本地构建状态
worldMemory := NewWaysideMemory()
initWorldDeviceState(worldMemory.Status, repo)
// 构建所有UID映射关系
allUidMap := buildRepositoryAllUidsMap(mapIds, repo)
//创建仿真
// worldId := world.CreateSimulation(repo)
w := rtss_simulation.NewSimulation(repo)
w.StartUp()
w, err := rtss_simulation.NewSimulation(repo)
if err != nil {
return nil, sys_error.New("仿真创建失败", err)
}
verifySimulation := &VerifySimulation{
MapIds: mapIds,
ProjectId: projectId,
Memory: worldMemory,
Memory: NewWaysideMemory(),
Repo: repo,
World: w,
WorldId: w.Id(),
uidMap: allUidMap,
}
// 保证World关闭
runtime.SetFinalizer(verifySimulation, func(verifySimulation *VerifySimulation) {
slog.Info("---关闭仿真World---")
verifySimulation.World.Close()
})
return verifySimulation, nil
}
// 获取全量状态
func (s *VerifySimulation) GetAllState(mapId int32) *state.PushedDevicesStatus {
giType := QueryGiType(mapId)
if giType != graphicData.PictureType_StationLayout {
switch giType {
case graphicData.PictureType_StationLayout:
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
SwitchState: GetMapAllTurnoutState(s, mapId),
TrainState: GetAllTrainState(s),
SignalState: GetMapAllSignalState(s, mapId),
ButtonState: GetMapAllStationButtonState(s, mapId),
PsdState: GetMapAllPsdState(s, mapId),
},
}
case graphicData.PictureType_RelayCabinetLayout:
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
@ -137,16 +162,48 @@ func (s *VerifySimulation) GetAllState(mapId int32) *state.PushedDevicesStatus {
},
}
}
return &state.PushedDevicesStatus{}
}
// 获取门控箱状态
func (s *VerifySimulation) GetAllPSLState(mapId int32, boxId string) *state.PushedDevicesStatus {
world := s.GetSimulationWorld()
uidStructure := queryUidStructure[*stationUidStructure](mapId)
boxUid := uidStructure.GateBoxIds[boxId].Uid
mkxEntry, ok := entity.GetEntityByUid(world, boxUid)
var buttonStateArr []*state.ButtonState
if ok {
mkxCircuit := component.MkxCircuitType.Get(mkxEntry)
var boxArr []*ecs.Entry
boxArr = append(boxArr, mkxCircuit.PcbList...)
boxArr = append(boxArr, mkxCircuit.PobList...)
boxArr = append(boxArr, mkxCircuit.PabList...)
for _, mkxBoxEntry := range boxArr {
mkxBox := component.MkxBoxType.Get(mkxBoxEntry)
uid := component.UidType.Get(mkxBox.Btn).Id
down := component.BitStateType.Get(mkxBox.Btn).Val
buttonStateArr = append(buttonStateArr, &state.ButtonState{
Id: uid,
Down: down,
})
}
}
return &state.PushedDevicesStatus{
All: true,
AllStatus: &state.AllDevicesStatus{
SwitchState: GetMapAllTurnoutState(s, mapId),
TrainState: GetAllTrainState(s),
SignalState: GetMapAllSignalState(s, mapId),
ButtonState: buttonStateArr,
},
}
}
// 获取车站IBP状态
func (s *VerifySimulation) GetAllIBPState(mapId int32, stationId string, ibpMapCode string) *state.PushedDevicesStatus {
return &state.PushedDevicesStatus{
All: true,
AllStatus: GetMapAllIBPState(s, mapId, stationId, ibpMapCode),
}
}
// 获取仿真世界信息
func (s *VerifySimulation) GetSimulationWorld() ecs.World {
return s.World
@ -164,6 +221,175 @@ func (s *VerifySimulation) GetComIdByUid(uid string) string {
return es[uid].CommonId
}
func (sim *VerifySimulation) BuildLineBaseInfo() *message.LineBaseInfo {
info := &message.LineBaseInfo{}
for _, model := range sim.Repo.LinkList() {
id, _ := strconv.Atoi(model.Id())
link := &message.Link{
ID: int32(id),
Len: int32(model.Length()),
}
info.LinkList = append(info.LinkList, link)
if model.ARelation() != nil {
turnoutId, _ := strconv.Atoi(sim.GetComIdByUid(model.ARelation().Device().Id()))
link.ARelTurnoutId = int32(turnoutId)
switch model.ARelation().Port() {
case proto.Port_A:
link.ARelTurnoutPoint = "A"
case proto.Port_B:
link.ARelTurnoutPoint = "B"
case proto.Port_C:
link.ARelTurnoutPoint = "C"
}
}
if model.BRelation() != nil {
turnoutId, _ := strconv.Atoi(sim.GetComIdByUid(model.BRelation().Device().Id()))
link.BRelTurnoutId = int32(turnoutId)
switch model.BRelation().Port() {
case proto.Port_A:
link.BRelTurnoutPoint = "A"
case proto.Port_B:
link.BRelTurnoutPoint = "B"
case proto.Port_C:
link.BRelTurnoutPoint = "C"
}
}
}
for _, model := range sim.Repo.SlopeList() {
id, _ := strconv.Atoi(sim.GetComIdByUid(model.Id()))
slope := &message.Slope{
ID: int32(id),
StartLinkOffset: int32(model.StartLinkPosition().Offset()),
EndLinkOffset: int32(model.EndLinkPosition().Offset()),
DegreeTrig: model.Degree(),
}
info.SlopeList = append(info.SlopeList, slope)
startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id())
slope.StartLinkId = int32(startLinkId)
endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id())
slope.EndLinkId = int32(endLinkId)
}
for _, model := range sim.Repo.SectionalCurvatureList() {
id, _ := strconv.Atoi(sim.GetComIdByUid(model.Id()))
curve := &message.Curve{
ID: int32(id),
StartLinkOffset: int32(model.StartLinkPosition().Offset()),
EndLinkOffset: int32(model.EndLinkPosition().Offset()),
Curvature: model.Radius(),
}
info.CurveList = append(info.CurveList, curve)
startLinkId, _ := strconv.Atoi(model.StartLinkPosition().Link().Id())
curve.StartLinkId = int32(startLinkId)
endLinkId, _ := strconv.Atoi(model.EndLinkPosition().Link().Id())
curve.EndLinkId = int32(endLinkId)
}
return info
}
// 采集动力学道岔状态
func (s *VerifySimulation) CollectDynamicsTurnoutInfo() []*message.DynamicsTurnoutInfo {
stateSlice := GetAllTurnoutState(s)
var turnoutStates []*message.DynamicsTurnoutInfo
for _, sta := range stateSlice {
code64, err := strconv.ParseUint(sta.Id, 10, 16)
if err != nil {
slog.Error("id转uint16报错", err)
}
info := message.DynamicsTurnoutInfo{
Code: uint16(code64),
NPosition: sta.Dw,
RPosition: sta.Fw,
}
turnoutStates = append(turnoutStates, &info)
}
return turnoutStates
}
// 处理动力学列车速度消息
func (s *VerifySimulation) HandleDynamicsTrainInfo(info *message.DynamicsTrainInfo) {
sta, ok := s.Memory.Status.TrainStateMap.Load(strconv.Itoa(int(info.Number)))
if !ok {
return
}
// 给半实物仿真发送速度
semi_physical_train.Default().SendTrainControlMessage(info)
// 更新列车状态
UpdateTrainState(s, convert(info, sta.(*state.TrainState), s))
}
func convert(info *message.DynamicsTrainInfo, sta *state.TrainState, simulation *VerifySimulation) *state.TrainState {
delayTime := time.Now().UnixMilli() - sta.VobcState.UpdateTime
sta.ControlDelayTime = (int64(sta.VobcState.LifeSignal)-int64(info.VobcLifeSignal))*20 + delayTime
slog.Debug("收到动力学原始消息", "Number", info.Number, "Link", info.Link, "LinkOffset", info.LinkOffset)
id, port, offset, runDirection, pointTo, kilometer := QueryDeviceByCalcLink(simulation.Repo, strconv.Itoa(int(info.Link)), int64(info.LinkOffset), info.Up)
slog.Debug("处理动力学转换后的消息", "number", info.Number, "车头位置", id, "偏移", offset, "是否上行", runDirection, "是否ab", pointTo)
sta.HeadDeviceId = simulation.GetComIdByUid(id)
sta.DevicePort = port
sta.HeadOffset = offset
sta.PointTo = pointTo
sta.TrainKilometer = kilometer
sta.RunDirection = runDirection
//判定车头方向
sta.HeadDirection = runDirection
if sta.VobcState != nil {
if sta.VobcState.DirectionForward {
sta.HeadDirection = runDirection
} else if sta.VobcState.DirectionBackward {
sta.HeadDirection = !runDirection
}
}
if info.Speed < 0 {
sta.RunDirection = !sta.RunDirection
}
// 赋值动力学信息
sta.DynamicState.Heartbeat = int32(info.LifeSignal)
sta.DynamicState.HeadLinkId = strconv.Itoa(int(info.Link))
sta.DynamicState.HeadLinkOffset = int64(info.LinkOffset)
sta.DynamicState.Slope = int32(info.Slope)
sta.DynamicState.Upslope = info.UpSlope
sta.DynamicState.RunningUp = info.Up
sta.DynamicState.RunningResistanceSum = float32(info.TotalResistance) / 1000
sta.DynamicState.AirResistance = float32(info.AirResistance) / 1000
sta.DynamicState.RampResistance = float32(info.SlopeResistance) / 1000
sta.DynamicState.CurveResistance = float32(info.CurveResistance) / 1000
sta.DynamicState.Speed = speedParse(info.Speed)
sta.DynamicState.HeadSensorSpeed1 = speedParse(info.HeadSpeed1)
sta.DynamicState.HeadSensorSpeed2 = speedParse(info.HeadSpeed2)
sta.DynamicState.TailSensorSpeed1 = speedParse(info.TailSpeed1)
sta.DynamicState.TailSensorSpeed2 = speedParse(info.TailSpeed2)
sta.DynamicState.HeadRadarSpeed = speedParse(info.HeadRadarSpeed)
sta.DynamicState.TailRadarSpeed = speedParse(info.TailRadarSpeed)
sta.DynamicState.Acceleration = info.Acceleration
return sta
}
// 发送给前端的速度格式化
func speedParse(speed float32) int32 {
return int32(math.Abs(float64(speed * 3.6 * 100)))
}
// 处理半实物仿真列车控制消息
func (s *VerifySimulation) HandleSemiPhysicalTrainControlMsg(b []byte) {
s.Memory.Status.TrainStateMap.Range(func(_, value any) bool {
train := value.(*state.TrainState)
if !train.Show { // 下线列车
return false
}
trainId, err := strconv.Atoi(train.Id)
if err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
}
d := append(b, uint8(trainId))
// 发送给动力学
dynamics.Default().SendTrainControlMessage(d)
// 存放至列车中
controlMessage := &message.TrainControlMsg{}
controlMessage.Decode(b)
train.VobcState = controlMessage.ControlInfo
return true
})
}
func buildProtoRepository(mapIds []int32) (*proto.Repository, error) {
repo := &proto.Repository{}
var exceptStationGiMapIds []int32
@ -193,12 +419,15 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicD
city := relayGi.UniqueIdPrefix.City
lineId := relayGi.UniqueIdPrefix.LineId
station := relayGi.UniqueIdPrefix.BelongsConcentrationStation
relayMap := make(map[string]*proto.Relay)
for _, relay := range relayGi.Relays {
repo.Relays = append(repo.Relays, &proto.Relay{
repoRelay := &proto.Relay{
Id: uidsMap.RelayIds[relay.Common.Id].Uid,
Code: relay.Code,
Model: convertRelayModel(relay.NewModel),
})
}
repo.Relays = append(repo.Relays, repoRelay)
relayMap[repoRelay.Id] = repoRelay
}
for _, pfp := range relayGi.PhaseFailureProtectors {
repo.PhaseFailureProtectors = append(repo.PhaseFailureProtectors, &proto.PhaseFailureProtector{
@ -218,6 +447,14 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicD
for _, station := range repo.Stations {
stationMap[station.Id] = station
}
psdMap := make(map[string]*proto.Psd)
for _, psd := range repo.Psds {
psdMap[psd.Id] = psd
}
platformMap := make(map[string]*proto.Platform)
for _, platform := range repo.Platforms {
platformMap[platform.Id] = platform
}
for _, relationship := range relayGi.DeviceRelateRelayList {
switch relationship.DeviceType {
case graphicData.RelatedRef_Turnout:
@ -280,6 +517,53 @@ func buildAndRelateElectronicComponent(repo *proto.Repository, relayGi *graphicD
}
station.ElectronicGroup = append(station.ElectronicGroup, d)
}
case graphicData.RelatedRef_ScreenDoor:
psd, ok := psdMap[GenerateElementUid(city, lineId, nil, relationship.Code)]
if !ok {
continue
}
for _, group := range relationship.Combinationtypes {
var componentIds []string
for _, relayId := range group.RefRelays {
if uidsMap.RelayIds[relayId] == nil {
continue
}
componentIds = append(componentIds, uidsMap.RelayIds[relayId].Uid)
}
psd.ElectronicComponentGroups = append(psd.ElectronicComponentGroups,
&proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
}
}
}
//门控箱
for _, mkx := range repo.Mkxs {
platform := platformMap[psdMap[mkx.PsdId].GetPlatformId()]
station := stationMap[platform.GetStationId()]
var s string
if strings.Contains(platform.GetCode(), "上行") {
s = "S"
} else if strings.Contains(platform.GetCode(), "下行") {
s = "X"
} else {
continue
}
for _, group := range station.ElectronicGroup {
if group.Code == "MKX" {
var componentIds []string
for _, component := range group.Components {
relay := relayMap[component.Id]
if strings.Contains(relay.GetCode(), s) {
componentIds = append(componentIds, relay.Id)
}
}
mkx.ElectronicComponentGroups = append(mkx.ElectronicComponentGroups, &proto.ElectronicComponentGroup{
Code: group.Code,
ComponentIds: componentIds,
})
}
}
}
}
@ -310,6 +594,7 @@ func convertRelayModel(modelType graphicData.Relay_ModelType) proto.Relay_Model
}
func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphicStorage, mapId int32) {
repo.MainCoordinateSystem = storage.UniqueIdPrefix.MainCoordinateSystem
axleCountingMap := make(map[string]*graphicData.AxleCounting)
uidsMap := queryUidStructure[*stationUidStructure](mapId)
for _, data := range storage.AxleCountings {
@ -378,7 +663,7 @@ func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphi
Km: convertKm(data.KilometerSystem),
SectionId: sectionId,
TurnoutPort: turnoutPort,
//Code: data.,
Model: convertToProtoSignalModel(data.Mt),
}
repo.Signals = append(repo.Signals, converSignalUid(signal, uidsMap))
}
@ -455,7 +740,7 @@ func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphi
for _, data := range storage.Stations {
station := &proto.Station{
Id: uidsMap.StationIds[data.Common.Id].Uid,
Code: data.Code,
Code: data.StationName,
}
// 关联车站的设备
refs, ok := relateMap[data.Code]
@ -478,93 +763,152 @@ func fillProtoRepository(repo *proto.Repository, storage *graphicData.RtssGraphi
}
}
// 处理车站关联IBP的设备
handlerIBPDeviceToStation(uidsMap, station, repo, data.RefIbpMapCode)
handlerIBPDeviceToStation(station, repo, data.RefIbpMapCode)
repo.Stations = append(repo.Stations, station)
}
//门控箱
gateBoxMap := make(map[string]*proto.Mkx)
for _, data := range storage.GateBoxs {
mkx, ok := gateBoxMap[data.RefScreenDoor]
if !ok {
mkx = &proto.Mkx{
Id: uidsMap.GateBoxIds[data.Common.Id].Uid,
PsdId: uidsMap.PsdIds[data.RefScreenDoor].Uid,
}
repo.Mkxs = append(repo.Mkxs, mkx)
gateBoxMap[data.RefScreenDoor] = mkx
}
pslMapId := QueryGiId(data.RefGatedBoxMapCode)
pslStorage := QueryGiData[*graphicData.PslGraphicStorage](pslMapId)
for _, button := range pslStorage.PslButtons {
repoButton := &proto.Button{
Id: uidsMap.GateBoxIds[data.Common.Id].Uid + "_" + button.Code,
Code: button.Code,
ButtonType: proto.Button_Reset_Press,
HasLight: true,
}
repo.Buttons = append(repo.Buttons, repoButton)
switch button.Code {
case "PCB":
mkx.PcbButtonIds = append(mkx.PcbButtonIds, repoButton.Id)
case "POB":
mkx.PobButtonIds = append(mkx.PobButtonIds, repoButton.Id)
case "PAB":
mkx.PabButtonIds = append(mkx.PabButtonIds, repoButton.Id)
}
}
}
//站台
platformMap := make(map[string]*graphicData.Platform)
for _, data := range storage.Platforms {
platformMap[data.Common.Id] = data
platform := &proto.Platform{
Id: uidsMap.PlatformIds[data.Common.Id].Uid,
Code: data.Code,
}
repo.Platforms = append(repo.Platforms, platform)
platform.StationId = uidsMap.StationIds[data.RefStationId].Uid
platform.PhysicalSectionId = uidsMap.PhysicalSectionIds[data.RefSectionId].Uid
}
//屏蔽门
for _, data := range storage.ScreenDoors {
psd := &proto.Psd{
Id: uidsMap.PsdIds[data.Common.Id].Uid,
PlatformId: uidsMap.PlatformIds[data.RefPlatformId].Uid,
}
repo.Psds = append(repo.Psds, psd)
}
}
// 将IBP的设备关联到车站中
func handlerIBPDeviceToStation(uidsMap *stationUidStructure, station *proto.Station, repo *proto.Repository, ibpMap string) {
func handlerIBPDeviceToStation(station *proto.Station, repo *proto.Repository, ibpMap string) {
storage := getStorageIBPMapData(ibpMap)
if storage == nil {
return
}
ibpIdMap := uidsMap.IBPIds[station.Code] // 车站对应的UID集合
typeMap := make(map[string]proto.DeviceType) // 对应的设备类型
deviceMap := make(map[string]*proto.ElectronicComponent) // 对应的设备类型
for _, data := range storage.IbpButtons { // 处理按钮
buttonType := proto.Button_NO_Reset_Press
if data.IsSelfReset {
buttonType = proto.Button_Reset_Press
}
b := &proto.Button{
Id: ibpIdMap[data.Common.Id].Uid,
Id: station.Id + "_button_" + data.Code,
Code: data.Code,
ButtonType: buttonType,
HasLight: data.HasLight,
}
deviceMap[data.Common.Id] = &proto.ElectronicComponent{
Id: b.Id,
DeviceType: proto.DeviceType_DeviceType_Button,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Button
repo.Buttons = append(repo.Buttons, b)
}
for _, data := range storage.IbpKeys { // 钥匙
b := &proto.Button{
Id: ibpIdMap[data.Common.Id].Uid,
b := &proto.Key{
Id: station.Id + "_key_" + data.Code,
Code: data.Code,
ButtonType: proto.Button_Key_Knob,
Gear: 2,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Button
repo.Buttons = append(repo.Buttons, b)
deviceMap[data.Common.Id] = &proto.ElectronicComponent{
Id: b.Id,
DeviceType: proto.DeviceType_DeviceType_Key,
}
repo.Keys = append(repo.Keys, b)
}
for _, data := range storage.IbpAlarms { // 报警器
b := &proto.Alarm{
Id: ibpIdMap[data.Common.Id].Uid,
Id: station.Id + "_alarm_" + data.Code,
Code: data.Code,
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Alarm
deviceMap[data.Common.Id] = &proto.ElectronicComponent{
Id: b.Id,
DeviceType: proto.DeviceType_DeviceType_Alarm,
}
repo.Alarms = append(repo.Alarms, b)
}
for _, data := range storage.IbpLights { // 指示灯
empGroup := &proto.ElectronicGroup{Code: "EMP"}
spksGroup := &proto.ElectronicGroup{Code: "SPKS"}
for _, data := range storage.IbpLights { // 指示灯,
b := &proto.Light{
Id: ibpIdMap[data.Common.Id].Uid,
Id: station.Id + "_light_" + data.Code,
Code: data.Code,
Aspect: converIbpLightAspect(data.Color),
}
typeMap[data.Common.Id] = proto.DeviceType_DeviceType_Light
repo.Lights = append(repo.Lights, b)
// 存入组合类型的
c := &proto.ElectronicComponent{
Id: b.Id,
DeviceType: proto.DeviceType_DeviceType_Light,
}
// 组信息
for _, data := range storage.IbpRelatedDevices {
switch data.Code {
case "X紧急关闭", "S紧急关闭":
empGroup.Components = append(empGroup.Components, c)
case "启用状态_SPKS1", "启用状态_SPKS3", "启用状态_SPKS2", "启用状态_SPKS4":
spksGroup.Components = append(spksGroup.Components, c)
}
}
for _, data := range storage.IbpRelatedDevices { // 组信息
for _, c := range data.Combinationtypes {
group := &proto.ElectronicGroup{Code: c.Code}
var group *proto.ElectronicGroup
switch c.Code {
case "EMP":
group = empGroup
case "SPKS":
group = spksGroup
default:
continue
}
for _, d := range c.RefDevices {
deviceType, ok := typeMap[d]
deviceType, ok := deviceMap[d]
if !ok {
slog.Debug("IBP组合类型类型不确定id:%s", d)
continue
}
group.Components = append(group.Components, &proto.ElectronicComponent{
Id: ibpIdMap[d].Uid,
DeviceType: deviceType,
})
}
station.ElectronicGroup = append(station.ElectronicGroup, group)
group.Components = append(group.Components, deviceType)
}
}
}
// 将IBP的灯颜色转换成repo灯颜色
func converIbpLightAspect(color graphicData.IbpLight_IbpLightColor) proto.Light_LightAspect {
switch color {
case graphicData.IbpLight_white:
return proto.Light_B
case graphicData.IbpLight_red:
return proto.Light_H
case graphicData.IbpLight_green:
return proto.Light_L
case graphicData.IbpLight_blue:
return proto.Light_A
default:
panic(&dto.ErrorDto{Code: dto.ArgumentParseError, Message: "未知的灯颜色类型" + color.String()})
}
station.ElectronicGroup = append(station.ElectronicGroup, empGroup, spksGroup)
}
func converCheckPointUid(data *proto.CheckPoint, uidsMap *stationUidStructure) *proto.CheckPoint {
@ -738,23 +1082,21 @@ func findTurnoutIds(axleCountingMap map[string]*graphicData.AxleCounting, axleId
return turnoutIds
}
func initWorldDeviceState(status *VerifyStatus, repo *repository.Repository) {
initWorldTurnoutState(status, repo)
initWorldPhysicalSectionState(status, repo)
}
// 初始化道岔状态
func initWorldTurnoutState(status *VerifyStatus, repo *repository.Repository) {
for _, turnout := range repo.TurnoutList() {
id := turnout.Identity.Id()
status.SwitchStateMap.Store(id, &state.SwitchState{Id: id, Normal: true, Reverse: false})
}
}
// 初始化物理区段状态
func initWorldPhysicalSectionState(status *VerifyStatus, repo *repository.Repository) {
for _, section := range repo.PhysicalSectionList() {
id := section.Identity.Id()
status.PhysicalSectionStateMap.Store(id, &state.SectionState{Id: id, Occupied: false, Type: state.SectionType_Physic})
func convertToProtoSignalModel(gSmt graphicData.Signal_Model) proto.Signal_Model {
switch gSmt {
case graphicData.Signal_HLU:
return proto.Signal_HLU
case graphicData.Signal_HL:
return proto.Signal_HL
case graphicData.Signal_HLU_FU:
return proto.Signal_HLU_FU
case graphicData.Signal_HLU_FL:
return proto.Signal_HLU_FL
case graphicData.Signal_AB:
return proto.Signal_AB
case graphicData.Signal_HBU:
return proto.Signal_HBU
default:
panic(fmt.Sprintf("graphicData.Signal_Model[%d]无法映射到proto.Signal_Model", gSmt))
}
}

@ -1 +1 @@
Subproject commit 7a105e7c0ee7ddf8e9803d31343fafac697a4872
Subproject commit 9b1c6d78012eff4f9d300412ad41c8175751767d

View File

@ -1328,7 +1328,7 @@ const docTemplate = `{
}
}
},
"/api/v1/drafting/paging": {
"/api/v1/drafting/list": {
"get": {
"security": [
{
@ -1381,6 +1381,75 @@ const docTemplate = `{
}
}
},
"/api/v1/drafting/paging": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "可以通过草稿名称过滤,分页查询草稿",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"草稿Api"
],
"summary": "分页查询草稿",
"parameters": [
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "integer",
"example": 1,
"description": "页码",
"name": "current",
"in": "query",
"required": true
},
{
"type": "integer",
"example": 10,
"description": "页面行数",
"name": "size",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.PageDto"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/drafting/{id}": {
"get": {
"security": [
@ -2333,6 +2402,61 @@ const docTemplate = `{
}
}
},
"/api/v1/publishedGi/name": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "可以通过名称过滤",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"发布的图形数据Api"
],
"summary": "根据Code查询发布地图数据",
"parameters": [
{
"type": "boolean",
"name": "detail",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PublishedGi"
}
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/publishedGi/paging": {
"get": {
"security": [
@ -2612,6 +2736,49 @@ const docTemplate = `{
}
}
},
"/api/v1/simulation/:id/getMapKilometerRange": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "获取仿真地图的公里标范围",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "获取仿真地图的公里标范围",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/check/data": {
"post": {
"security": [
@ -2766,6 +2933,58 @@ const docTemplate = `{
}
}
},
"/api/v1/simulation/esbBtn/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-ESB按钮操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-ESB按钮操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-ESB按钮操作",
"name": "EsbButtonOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.EsbButtonOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/getDataChannelName": {
"get": {
"security": [
@ -2809,6 +3028,162 @@ const docTemplate = `{
}
}
},
"/api/v1/simulation/ibp/btn/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-IBP按钮操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-IBP按钮操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-IBP按钮操作",
"name": "IBPButtonOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.IBPButtonOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/ibp/key/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-IBP钥匙操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-IBP钥匙操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-IBP钥匙操作",
"name": "KeyOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.KeyOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/ibp/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "PSL操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "PSL操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "PSL操作",
"name": "PslOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PslOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/list": {
"get": {
"security": [
@ -4545,6 +4920,79 @@ const docTemplate = `{
}
}
},
"dto.EsbButtonOperationReqDto": {
"type": "object",
"required": [
"id",
"mapId",
"simulationId"
],
"properties": {
"down": {
"type": "boolean"
},
"id": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
}
}
},
"dto.IBPButtonOperationReqDto": {
"type": "object",
"required": [
"buttonCode",
"mapId",
"simulationId",
"stationId"
],
"properties": {
"buttonCode": {
"type": "string"
},
"down": {
"type": "boolean"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
},
"stationId": {
"type": "string"
}
}
},
"dto.KeyOperationReqDto": {
"type": "object",
"required": [
"mapId",
"simulationId",
"stationId"
],
"properties": {
"gear": {
"type": "integer"
},
"keyCode": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
},
"stationId": {
"type": "string"
}
}
},
"dto.LoginDto": {
"type": "object",
"required": [
@ -4631,6 +5079,31 @@ const docTemplate = `{
}
}
},
"dto.PslOperationReqDto": {
"type": "object",
"required": [
"buttonCode",
"mapId",
"simulationId"
],
"properties": {
"buttonCode": {
"type": "string"
},
"down": {
"type": "boolean"
},
"gateBoxId": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
}
}
},
"dto.PublishedGiLinkDto": {
"type": "object",
"properties": {
@ -4717,11 +5190,17 @@ const docTemplate = `{
"aspect",
"id",
"mapId",
"operation",
"simulationId"
],
"properties": {
"aspect": {
"description": "当操作为Operation.Display时有效表示显示的信号",
"allOf": [
{
"$ref": "#/definitions/state.Signal_Aspect"
}
]
},
"id": {
"type": "string"
@ -4729,6 +5208,14 @@ const docTemplate = `{
"mapId": {
"type": "integer"
},
"operation": {
"description": "信号机操作类型",
"allOf": [
{
"$ref": "#/definitions/request_proto.Signal_Operation"
}
]
},
"simulationId": {
"type": "string"
}
@ -5110,6 +5597,51 @@ const docTemplate = `{
}
}
},
"request_proto.Signal_Operation": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11
],
"x-enum-comments": {
"Signal_Display": "显示操作,如设置绿色、设置红黄色",
"Signal_LightACancelDs": "取消蓝灯断丝故障",
"Signal_LightAFaultDs": "设置蓝灯断丝故障",
"Signal_LightBCancelDs": "取消白灯断丝故障",
"Signal_LightBFaultDs": "设置白灯断丝故障",
"Signal_LightHCancelDs": "取消红灯断丝故障",
"Signal_LightHFaultDs": "设置红灯断丝故障",
"Signal_LightLCancelDs": "取消绿灯断丝故障",
"Signal_LightLFaultDs": "设置绿灯断丝故障",
"Signal_LightUCancelDs": "取消黄灯断丝故障",
"Signal_LightUFaultDs": "设置黄灯断丝故障",
"Signal_Undefined": "未定义"
},
"x-enum-varnames": [
"Signal_Undefined",
"Signal_Display",
"Signal_LightHFaultDs",
"Signal_LightUFaultDs",
"Signal_LightLFaultDs",
"Signal_LightAFaultDs",
"Signal_LightBFaultDs",
"Signal_LightHCancelDs",
"Signal_LightUCancelDs",
"Signal_LightLCancelDs",
"Signal_LightACancelDs",
"Signal_LightBCancelDs"
]
},
"request_proto.TurnoutOperationReq": {
"type": "object",
"properties": {
@ -5184,8 +5716,8 @@ const docTemplate = `{
7
],
"x-enum-varnames": [
"Signal_Non",
"Signal_OFF",
"Signal_ON",
"Signal_L",
"Signal_H",
"Signal_U",

View File

@ -1321,7 +1321,7 @@
}
}
},
"/api/v1/drafting/paging": {
"/api/v1/drafting/list": {
"get": {
"security": [
{
@ -1374,6 +1374,75 @@
}
}
},
"/api/v1/drafting/paging": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "可以通过草稿名称过滤,分页查询草稿",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"草稿Api"
],
"summary": "分页查询草稿",
"parameters": [
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "integer",
"example": 1,
"description": "页码",
"name": "current",
"in": "query",
"required": true
},
{
"type": "integer",
"example": 10,
"description": "页面行数",
"name": "size",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.PageDto"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/drafting/{id}": {
"get": {
"security": [
@ -2326,6 +2395,61 @@
}
}
},
"/api/v1/publishedGi/name": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "可以通过名称过滤",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"发布的图形数据Api"
],
"summary": "根据Code查询发布地图数据",
"parameters": [
{
"type": "boolean",
"name": "detail",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PublishedGi"
}
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/publishedGi/paging": {
"get": {
"security": [
@ -2605,6 +2729,49 @@
}
}
},
"/api/v1/simulation/:id/getMapKilometerRange": {
"get": {
"security": [
{
"JwtAuth": []
}
],
"description": "获取仿真地图的公里标范围",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "获取仿真地图的公里标范围",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/check/data": {
"post": {
"security": [
@ -2759,6 +2926,58 @@
}
}
},
"/api/v1/simulation/esbBtn/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-ESB按钮操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-ESB按钮操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-ESB按钮操作",
"name": "EsbButtonOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.EsbButtonOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/getDataChannelName": {
"get": {
"security": [
@ -2802,6 +3021,162 @@
}
}
},
"/api/v1/simulation/ibp/btn/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-IBP按钮操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-IBP按钮操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-IBP按钮操作",
"name": "IBPButtonOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.IBPButtonOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/ibp/key/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "ATS测试-IBP钥匙操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "ATS测试-IBP钥匙操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "ATS测试仿真-IBP钥匙操作",
"name": "KeyOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.KeyOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/ibp/operation": {
"post": {
"security": [
{
"JwtAuth": []
}
],
"description": "PSL操作",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"ATS测试仿真Api"
],
"summary": "PSL操作",
"parameters": [
{
"type": "string",
"description": "JWT Token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "PSL操作",
"name": "PslOperationReqDto",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PslOperationReqDto"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/dto.ErrorDto"
}
}
}
}
},
"/api/v1/simulation/list": {
"get": {
"security": [
@ -4538,6 +4913,79 @@
}
}
},
"dto.EsbButtonOperationReqDto": {
"type": "object",
"required": [
"id",
"mapId",
"simulationId"
],
"properties": {
"down": {
"type": "boolean"
},
"id": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
}
}
},
"dto.IBPButtonOperationReqDto": {
"type": "object",
"required": [
"buttonCode",
"mapId",
"simulationId",
"stationId"
],
"properties": {
"buttonCode": {
"type": "string"
},
"down": {
"type": "boolean"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
},
"stationId": {
"type": "string"
}
}
},
"dto.KeyOperationReqDto": {
"type": "object",
"required": [
"mapId",
"simulationId",
"stationId"
],
"properties": {
"gear": {
"type": "integer"
},
"keyCode": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
},
"stationId": {
"type": "string"
}
}
},
"dto.LoginDto": {
"type": "object",
"required": [
@ -4624,6 +5072,31 @@
}
}
},
"dto.PslOperationReqDto": {
"type": "object",
"required": [
"buttonCode",
"mapId",
"simulationId"
],
"properties": {
"buttonCode": {
"type": "string"
},
"down": {
"type": "boolean"
},
"gateBoxId": {
"type": "string"
},
"mapId": {
"type": "integer"
},
"simulationId": {
"type": "string"
}
}
},
"dto.PublishedGiLinkDto": {
"type": "object",
"properties": {
@ -4710,11 +5183,17 @@
"aspect",
"id",
"mapId",
"operation",
"simulationId"
],
"properties": {
"aspect": {
"description": "当操作为Operation.Display时有效表示显示的信号",
"allOf": [
{
"$ref": "#/definitions/state.Signal_Aspect"
}
]
},
"id": {
"type": "string"
@ -4722,6 +5201,14 @@
"mapId": {
"type": "integer"
},
"operation": {
"description": "信号机操作类型",
"allOf": [
{
"$ref": "#/definitions/request_proto.Signal_Operation"
}
]
},
"simulationId": {
"type": "string"
}
@ -5103,6 +5590,51 @@
}
}
},
"request_proto.Signal_Operation": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11
],
"x-enum-comments": {
"Signal_Display": "显示操作,如设置绿色、设置红黄色",
"Signal_LightACancelDs": "取消蓝灯断丝故障",
"Signal_LightAFaultDs": "设置蓝灯断丝故障",
"Signal_LightBCancelDs": "取消白灯断丝故障",
"Signal_LightBFaultDs": "设置白灯断丝故障",
"Signal_LightHCancelDs": "取消红灯断丝故障",
"Signal_LightHFaultDs": "设置红灯断丝故障",
"Signal_LightLCancelDs": "取消绿灯断丝故障",
"Signal_LightLFaultDs": "设置绿灯断丝故障",
"Signal_LightUCancelDs": "取消黄灯断丝故障",
"Signal_LightUFaultDs": "设置黄灯断丝故障",
"Signal_Undefined": "未定义"
},
"x-enum-varnames": [
"Signal_Undefined",
"Signal_Display",
"Signal_LightHFaultDs",
"Signal_LightUFaultDs",
"Signal_LightLFaultDs",
"Signal_LightAFaultDs",
"Signal_LightBFaultDs",
"Signal_LightHCancelDs",
"Signal_LightUCancelDs",
"Signal_LightLCancelDs",
"Signal_LightACancelDs",
"Signal_LightBCancelDs"
]
},
"request_proto.TurnoutOperationReq": {
"type": "object",
"properties": {
@ -5177,8 +5709,8 @@
7
],
"x-enum-varnames": [
"Signal_Non",
"Signal_OFF",
"Signal_ON",
"Signal_L",
"Signal_H",
"Signal_U",

View File

@ -87,6 +87,56 @@ definitions:
title:
type: string
type: object
dto.EsbButtonOperationReqDto:
properties:
down:
type: boolean
id:
type: string
mapId:
type: integer
simulationId:
type: string
required:
- id
- mapId
- simulationId
type: object
dto.IBPButtonOperationReqDto:
properties:
buttonCode:
type: string
down:
type: boolean
mapId:
type: integer
simulationId:
type: string
stationId:
type: string
required:
- buttonCode
- mapId
- simulationId
- stationId
type: object
dto.KeyOperationReqDto:
properties:
gear:
type: integer
keyCode:
type: string
mapId:
type: integer
simulationId:
type: string
stationId:
type: string
required:
- mapId
- simulationId
- stationId
type: object
dto.LoginDto:
properties:
account:
@ -147,6 +197,23 @@ definitions:
$ref: '#/definitions/dto.TrainSizeDto'
type: array
type: object
dto.PslOperationReqDto:
properties:
buttonCode:
type: string
down:
type: boolean
gateBoxId:
type: string
mapId:
type: integer
simulationId:
type: string
required:
- buttonCode
- mapId
- simulationId
type: object
dto.PublishedGiLinkDto:
properties:
category:
@ -205,17 +272,24 @@ definitions:
dto.SignalOperationReqDto:
properties:
aspect:
$ref: '#/definitions/state.Signal_Aspect'
allOf:
- $ref: '#/definitions/state.Signal_Aspect'
description: 当操作为Operation.Display时有效表示显示的信号
id:
type: string
mapId:
type: integer
operation:
allOf:
- $ref: '#/definitions/request_proto.Signal_Operation'
description: 信号机操作类型
simulationId:
type: string
required:
- aspect
- id
- mapId
- operation
- simulationId
type: object
dto.SimulationCreateReqDto:
@ -485,6 +559,47 @@ definitions:
description: 名称
type: string
type: object
request_proto.Signal_Operation:
enum:
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
type: integer
x-enum-comments:
Signal_Display: 显示操作,如设置绿色、设置红黄色
Signal_LightACancelDs: 取消蓝灯断丝故障
Signal_LightAFaultDs: 设置蓝灯断丝故障
Signal_LightBCancelDs: 取消白灯断丝故障
Signal_LightBFaultDs: 设置白灯断丝故障
Signal_LightHCancelDs: 取消红灯断丝故障
Signal_LightHFaultDs: 设置红灯断丝故障
Signal_LightLCancelDs: 取消绿灯断丝故障
Signal_LightLFaultDs: 设置绿灯断丝故障
Signal_LightUCancelDs: 取消黄灯断丝故障
Signal_LightUFaultDs: 设置黄灯断丝故障
Signal_Undefined: 未定义
x-enum-varnames:
- Signal_Undefined
- Signal_Display
- Signal_LightHFaultDs
- Signal_LightUFaultDs
- Signal_LightLFaultDs
- Signal_LightAFaultDs
- Signal_LightBFaultDs
- Signal_LightHCancelDs
- Signal_LightUCancelDs
- Signal_LightLCancelDs
- Signal_LightACancelDs
- Signal_LightBCancelDs
request_proto.Turnout_Operation:
enum:
- 0
@ -545,8 +660,8 @@ definitions:
- 7
type: integer
x-enum-varnames:
- Signal_Non
- Signal_OFF
- Signal_ON
- Signal_L
- Signal_H
- Signal_U
@ -1583,7 +1698,7 @@ paths:
summary: 根据地图数据新生成计算的link信息
tags:
- 草稿Api
/api/v1/drafting/paging:
/api/v1/drafting/list:
get:
consumes:
- application/json
@ -1616,6 +1731,51 @@ paths:
summary: 列表查询草稿
tags:
- 草稿Api
/api/v1/drafting/paging:
get:
consumes:
- application/json
description: 可以通过草稿名称过滤,分页查询草稿
parameters:
- in: query
name: name
type: string
- description: 页码
example: 1
in: query
name: current
required: true
type: integer
- description: 页面行数
example: 10
in: query
name: size
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dto.PageDto'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/dto.ErrorDto'
"404":
description: Not Found
schema:
$ref: '#/definitions/dto.ErrorDto'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: 分页查询草稿
tags:
- 草稿Api
/api/v1/project:
post:
consumes:
@ -2094,6 +2254,40 @@ paths:
summary: 列表查询发布的图形数据
tags:
- 发布的图形数据Api
/api/v1/publishedGi/name:
get:
consumes:
- application/json
description: 可以通过名称过滤
parameters:
- in: query
name: detail
type: boolean
- in: query
name: name
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/model.PublishedGi'
type: array
"401":
description: Unauthorized
schema:
$ref: '#/definitions/dto.ErrorDto'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: 根据Code查询发布地图数据
tags:
- 发布的图形数据Api
/api/v1/publishedGi/paging:
get:
consumes:
@ -2212,6 +2406,33 @@ paths:
summary: 从发布数据拉取信息到草稿
tags:
- 发布的图形数据Api
/api/v1/simulation/:id/getMapKilometerRange:
get:
consumes:
- application/json
description: 获取仿真地图的公里标范围
parameters:
- description: JWT Token
in: header
name: Authorization
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: 获取仿真地图的公里标范围
tags:
- ATS测试仿真Api
/api/v1/simulation/check/data:
post:
consumes:
@ -2310,6 +2531,39 @@ paths:
summary: ATS仿真销毁
tags:
- ATS测试仿真Api
/api/v1/simulation/esbBtn/operation:
post:
consumes:
- application/json
description: ATS测试-ESB按钮操作
parameters:
- description: JWT Token
in: header
name: Authorization
required: true
type: string
- description: ATS测试仿真-ESB按钮操作
in: body
name: EsbButtonOperationReqDto
required: true
schema:
$ref: '#/definitions/dto.EsbButtonOperationReqDto'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: ATS测试-ESB按钮操作
tags:
- ATS测试仿真Api
/api/v1/simulation/getDataChannelName:
get:
consumes:
@ -2337,6 +2591,105 @@ paths:
summary: 获取仿真信息更新通道名称
tags:
- ATS测试仿真Api
/api/v1/simulation/ibp/btn/operation:
post:
consumes:
- application/json
description: ATS测试-IBP按钮操作
parameters:
- description: JWT Token
in: header
name: Authorization
required: true
type: string
- description: ATS测试仿真-IBP按钮操作
in: body
name: IBPButtonOperationReqDto
required: true
schema:
$ref: '#/definitions/dto.IBPButtonOperationReqDto'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: ATS测试-IBP按钮操作
tags:
- ATS测试仿真Api
/api/v1/simulation/ibp/key/operation:
post:
consumes:
- application/json
description: ATS测试-IBP钥匙操作
parameters:
- description: JWT Token
in: header
name: Authorization
required: true
type: string
- description: ATS测试仿真-IBP钥匙操作
in: body
name: KeyOperationReqDto
required: true
schema:
$ref: '#/definitions/dto.KeyOperationReqDto'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: ATS测试-IBP钥匙操作
tags:
- ATS测试仿真Api
/api/v1/simulation/ibp/operation:
post:
consumes:
- application/json
description: PSL操作
parameters:
- description: JWT Token
in: header
name: Authorization
required: true
type: string
- description: PSL操作
in: body
name: PslOperationReqDto
required: true
schema:
$ref: '#/definitions/dto.PslOperationReqDto'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/dto.ErrorDto'
security:
- JwtAuth: []
summary: PSL操作
tags:
- ATS测试仿真Api
/api/v1/simulation/list:
get:
consumes:

View File

@ -19,6 +19,7 @@ const (
QueryDBError = 5000
OperationOfSignalNotSupported = 6000
OperationOfSignalError = 6001
)
var ErrorTipMap = map[int]string{
@ -31,4 +32,5 @@ var ErrorTipMap = map[int]string{
NoAuthOperationError: "无权限操作",
QueryDBError: "数据库操作错误",
OperationOfSignalNotSupported: "信号机不支持该操作",
OperationOfSignalError: "信号机操作异常",
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc-gen-go v1.28.1
// protoc v4.23.1
// source: request.proto
@ -88,6 +88,83 @@ func (Turnout_Operation) EnumDescriptor() ([]byte, []int) {
return file_request_proto_rawDescGZIP(), []int{0, 0}
}
// 信号机操作
type Signal_Operation int32
const (
Signal_Undefined Signal_Operation = 0 // 未定义
Signal_Display Signal_Operation = 1 //显示操作,如设置绿色、设置红黄色
Signal_LightHFaultDs Signal_Operation = 2 //设置红灯断丝故障
Signal_LightUFaultDs Signal_Operation = 3 //设置黄灯断丝故障
Signal_LightLFaultDs Signal_Operation = 4 //设置绿灯断丝故障
Signal_LightAFaultDs Signal_Operation = 5 //设置蓝灯断丝故障
Signal_LightBFaultDs Signal_Operation = 6 //设置白灯断丝故障
Signal_LightHCancelDs Signal_Operation = 7 //取消红灯断丝故障
Signal_LightUCancelDs Signal_Operation = 8 //取消黄灯断丝故障
Signal_LightLCancelDs Signal_Operation = 9 //取消绿灯断丝故障
Signal_LightACancelDs Signal_Operation = 10 //取消蓝灯断丝故障
Signal_LightBCancelDs Signal_Operation = 11 //取消白灯断丝故障
)
// Enum value maps for Signal_Operation.
var (
Signal_Operation_name = map[int32]string{
0: "Undefined",
1: "Display",
2: "LightHFaultDs",
3: "LightUFaultDs",
4: "LightLFaultDs",
5: "LightAFaultDs",
6: "LightBFaultDs",
7: "LightHCancelDs",
8: "LightUCancelDs",
9: "LightLCancelDs",
10: "LightACancelDs",
11: "LightBCancelDs",
}
Signal_Operation_value = map[string]int32{
"Undefined": 0,
"Display": 1,
"LightHFaultDs": 2,
"LightUFaultDs": 3,
"LightLFaultDs": 4,
"LightAFaultDs": 5,
"LightBFaultDs": 6,
"LightHCancelDs": 7,
"LightUCancelDs": 8,
"LightLCancelDs": 9,
"LightACancelDs": 10,
"LightBCancelDs": 11,
}
)
func (x Signal_Operation) Enum() *Signal_Operation {
p := new(Signal_Operation)
*p = x
return p
}
func (x Signal_Operation) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Signal_Operation) Descriptor() protoreflect.EnumDescriptor {
return file_request_proto_enumTypes[1].Descriptor()
}
func (Signal_Operation) Type() protoreflect.EnumType {
return &file_request_proto_enumTypes[1]
}
func (x Signal_Operation) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Signal_Operation.Descriptor instead.
func (Signal_Operation) EnumDescriptor() ([]byte, []int) {
return file_request_proto_rawDescGZIP(), []int{2, 0}
}
// 道岔
type Turnout struct {
state protoimpl.MessageState
@ -199,6 +276,45 @@ func (x *TurnoutOperationReq) GetOperation() Turnout_Operation {
return Turnout_Undefined
}
// 信号机
type Signal struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Signal) Reset() {
*x = Signal{}
if protoimpl.UnsafeEnabled {
mi := &file_request_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Signal) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Signal) ProtoMessage() {}
func (x *Signal) ProtoReflect() protoreflect.Message {
mi := &file_request_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Signal.ProtoReflect.Descriptor instead.
func (*Signal) Descriptor() ([]byte, []int) {
return file_request_proto_rawDescGZIP(), []int{2}
}
var File_request_proto protoreflect.FileDescriptor
var file_request_proto_rawDesc = []byte{
@ -222,9 +338,24 @@ var file_request_proto_rawDesc = []byte{
0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x1a, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x75, 0x72, 0x6e, 0x6f, 0x75,
0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x15, 0x5a, 0x13, 0x2e, 0x2f, 0x64, 0x74, 0x6f, 0x2f,
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xf5, 0x01, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x6c, 0x22, 0xea, 0x01, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x0d, 0x0a, 0x09, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0b,
0x0a, 0x07, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x4c,
0x69, 0x67, 0x68, 0x74, 0x48, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x73, 0x10, 0x02, 0x12, 0x11,
0x0a, 0x0d, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x55, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x73, 0x10,
0x03, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x46, 0x61, 0x75, 0x6c, 0x74,
0x44, 0x73, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x41, 0x46, 0x61,
0x75, 0x6c, 0x74, 0x44, 0x73, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x69, 0x67, 0x68, 0x74,
0x42, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x73, 0x10, 0x06, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x69,
0x67, 0x68, 0x74, 0x48, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x44, 0x73, 0x10, 0x07, 0x12, 0x12,
0x0a, 0x0e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x55, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x44, 0x73,
0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x43, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x44, 0x73, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x41,
0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x44, 0x73, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x69,
0x67, 0x68, 0x74, 0x42, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x44, 0x73, 0x10, 0x0b, 0x42, 0x15,
0x5a, 0x13, 0x2e, 0x2f, 0x64, 0x74, 0x6f, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -239,12 +370,14 @@ func file_request_proto_rawDescGZIP() []byte {
return file_request_proto_rawDescData
}
var file_request_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_request_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_request_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_request_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_request_proto_goTypes = []interface{}{
(Turnout_Operation)(0), // 0: request.Turnout.Operation
(*Turnout)(nil), // 1: request.Turnout
(*TurnoutOperationReq)(nil), // 2: request.TurnoutOperationReq
(Signal_Operation)(0), // 1: request.Signal.Operation
(*Turnout)(nil), // 2: request.Turnout
(*TurnoutOperationReq)(nil), // 3: request.TurnoutOperationReq
(*Signal)(nil), // 4: request.Signal
}
var file_request_proto_depIdxs = []int32{
0, // 0: request.TurnoutOperationReq.operation:type_name -> request.Turnout.Operation
@ -285,14 +418,26 @@ func file_request_proto_init() {
return nil
}
}
file_request_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Signal); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_request_proto_rawDesc,
NumEnums: 1,
NumMessages: 2,
NumEnums: 2,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -1,6 +1,9 @@
package dto
import "joylink.club/bj-rtsts-server/ats/verify/protos/state"
import (
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/dto/request_proto"
)
// 创建仿真请求
type SimulationCreateReqDto struct {
@ -74,7 +77,39 @@ type SignalOperationReqDto struct {
SimulationId string `form:"simulationId" json:"simulationId" binding:"required"`
MapId int32 `json:"mapId" from:"mapId" binding:"required"`
DeviceId string `form:"id" json:"id" binding:"required"`
Aspect state.Signal_Aspect `form:"aspect" json:"aspect" binding:"required"`
Operation request_proto.Signal_Operation `form:"operation" json:"operation" binding:"required"` //信号机操作类型
Aspect state.Signal_Aspect `form:"aspect" json:"aspect" binding:"required"` // 当操作为Operation.Display时有效表示显示的信号
}
type EsbButtonOperationReqDto struct {
SimulationId string `form:"simulationId" json:"simulationId" binding:"required"`
MapId int32 `json:"mapId" from:"mapId" binding:"required"`
Id string `form:"id" json:"id" binding:"required"`
Down bool `form:"down" json:"down"`
}
type IBPButtonOperationReqDto struct {
SimulationId string `form:"simulationId" json:"simulationId" binding:"required"`
MapId int32 `json:"mapId" from:"mapId" binding:"required"`
StationId string `form:"stationId" json:"stationId" binding:"required"`
ButtonCode string `form:"buttonCode" json:"buttonCode" binding:"required"`
Down bool `form:"down" json:"down"`
}
type PslOperationReqDto struct {
SimulationId string `form:"simulationId" json:"simulationId" binding:"required"`
MapId int32 `json:"mapId" from:"mapId" binding:"required"`
GateBoxId string `form:"gateBoxId" json:"gateBoxId"`
ButtonCode string `form:"buttonCode" json:"buttonCode" binding:"required"`
Down bool `form:"down" json:"down"`
}
type KeyOperationReqDto struct {
SimulationId string `form:"simulationId" json:"simulationId" binding:"required"`
MapId int32 `json:"mapId" from:"mapId" binding:"required"`
StationId string `form:"stationId" json:"stationId" binding:"required"`
KeyCode string `form:"keyCode" json:"keyCode"`
Gear int32 `form:"gear" json:"gear"`
}
/////////////////////////////////////////////////////////////////////////////////

View File

@ -26,22 +26,6 @@ func (t *MemoryChangeServer) getInterval() time.Duration {
return 1 * time.Second
}
// 返回所有数据
func (t *MemoryChangeServer) allMsgData(params map[string]string) []byte {
arr := make([]*state.SimulationStatus, len(t.SimulationMap))
i := 0
for _, v := range t.SimulationMap {
arr[i] = v
i++
}
msg := &state.MemoryDataStatus{AllSimulations: arr}
data, err := proto.Marshal(msg)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
return data
}
// 定时发送数据
func (t *MemoryChangeServer) onTick() []TopicMsg {
simArr := simulation.GetSimulationArr()

View File

@ -1,7 +1,9 @@
package apiproto
import (
context "context"
"log/slog"
"runtime/debug"
"time"
)
@ -13,9 +15,6 @@ type IMsgServer interface {
// 发送消息间隔时间,单位ms
getInterval() time.Duration
// 全量信息
allMsgData(params map[string]string) []byte
// 定时发送的消息
onTick() []TopicMsg
}
@ -29,69 +28,126 @@ type TopicMsg struct {
data []byte
}
// 消息类型服务集合
var serverMap = make(map[string]*IMsgServer)
// 消息服务退出通道
var serverExitChannelMap = make(map[string]chan bool)
// 服务运行
func doServerRun(tick *time.Ticker, server IMsgServer, exitChannel chan bool) {
// 循环推送信息
for {
<-tick.C
topicMsgs := server.onTick()
if len(topicMsgs) == 0 {
continue
}
for _, msg := range topicMsgs {
PublishMsg(msg.channalName, msg.data)
}
select {
case <-exitChannel:
return
default:
}
}
type MsgServer struct {
IMsgServer
ctx context.Context
cancelFn context.CancelFunc
}
// 注册服务
func RegisterMsgServer(server IMsgServer) {
if client == nil {
InitClient()
}
serverMap[server.getChannelName()] = &server
if server.getInterval() > 0 {
exitChannel := make(chan bool)
serverExitChannelMap[server.getChannelName()] = exitChannel
tick := time.NewTicker(server.getInterval())
go func() {
defer func() {
if r := recover(); r != nil {
slog.Debug("定时器发生错误,%v\n", r)
}
// 重新启动,防止服务卡死
doServerRun(tick, server, exitChannel)
}()
// 循环推送信息
doServerRun(tick, server, exitChannel)
}()
// 消息服务管理map
var servers map[string]*MsgServer = make(map[string]*MsgServer)
// 注册消息服务
func Register(server IMsgServer) *MsgServer {
ms := &MsgServer{
IMsgServer: server,
}
ctx, cancelFn := context.WithCancel(context.Background())
ms.ctx = ctx
ms.cancelFn = cancelFn
go run(ms)
servers[server.getChannelName()] = ms
return ms
}
// 注销消息服务
func UnRegisterMsgServer(key string) {
channel := serverExitChannelMap[key]
if channel != nil {
// 定时任务取消
channel <- false
delete(serverExitChannelMap, key)
// 删除集合信息
delete(serverMap, key)
func Unregister(key string) {
server := servers[key]
if server == nil {
return
}
server.cancelFn()
delete(servers, key)
}
// 消息服务运行
func run(server *MsgServer) {
defer func() {
if err := recover(); err != nil {
slog.Error("消息服务运行异常", "serverChannelName", server.getChannelName(), "error", err, "stack", string(debug.Stack()))
debug.PrintStack()
}
}()
for {
select {
case <-server.ctx.Done():
slog.Info("消息服务退出", "serverChannelName", server.getChannelName())
return
default:
}
topicMsgs := server.onTick()
if len(topicMsgs) > 0 {
for _, msg := range topicMsgs {
PublishMsg(msg.channalName, msg.data)
}
}
time.Sleep(server.getInterval())
}
}
// 获取消息服务
func GetMsgServer(key string) *IMsgServer {
return serverMap[key]
}
// // 消息类型服务集合
// var serverMap = make(map[string]*IMsgServer)
// // 消息服务退出通道
// var serverExitChannelMap = make(map[string]chan bool)
// // 服务运行
// func doServerRun(tick *time.Ticker, server IMsgServer, exitChannel chan bool) {
// // 循环推送信息
// for {
// <-tick.C
// topicMsgs := server.onTick()
// if len(topicMsgs) == 0 {
// continue
// }
// for _, msg := range topicMsgs {
// PublishMsg(msg.channalName, msg.data)
// }
// select {
// case <-exitChannel:
// return
// default:
// }
// }
// }
// // 注册服务
// func RegisterMsgServer(server IMsgServer) {
// if client == nil {
// InitClient()
// }
// serverMap[server.getChannelName()] = &server
// if server.getInterval() > 0 {
// exitChannel := make(chan bool)
// serverExitChannelMap[server.getChannelName()] = exitChannel
// tick := time.NewTicker(server.getInterval())
// go func() {
// defer func() {
// if r := recover(); r != nil {
// slog.Debug("定时器发生错误,%v\n", r)
// }
// // 重新启动,防止服务卡死
// doServerRun(tick, server, exitChannel)
// }()
// // 循环推送信息
// doServerRun(tick, server, exitChannel)
// }()
// }
// }
// // 注销消息服务
// func UnRegisterMsgServer(key string) {
// channel := serverExitChannelMap[key]
// if channel != nil {
// // 定时任务取消
// channel <- false
// delete(serverExitChannelMap, key)
// // 删除集合信息
// delete(serverMap, key)
// }
// }
// // 获取消息服务
// func GetMsgServer(key string) *IMsgServer {
// return serverMap[key]
// }

View File

@ -0,0 +1,59 @@
package apiproto
import (
"strconv"
"strings"
"time"
"google.golang.org/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/simulation"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/dto"
)
type SimulationIBPServer struct{}
// 返回通道格式
func (t *SimulationIBPServer) getChannelName() string {
return "simulation-ibp-{sid}_{mid}_{station}-status"
}
// 消息运行间隔
func (t *SimulationIBPServer) getInterval() time.Duration {
return 200 * time.Millisecond
}
// 定时发送数据
func (t *SimulationIBPServer) onTick() []TopicMsg {
simArr := simulation.GetSimulationArr()
var msgArr []TopicMsg
for _, v := range simArr {
for _, mapId := range v.MapIds {
mapType := memory.QueryGiType(mapId)
if mapType != graphicData.PictureType_StationLayout {
continue
}
mapData := memory.QueryGiData[*graphicData.RtssGraphicStorage](mapId)
idStr := strconv.Itoa(int(mapId))
for _, station := range mapData.Stations {
channelName := handlerIBPChannelName(v.SimulationId, idStr, station.Common.Id, t.getChannelName())
b, err := proto.Marshal(v.GetAllIBPState(mapId, station.Common.Id, station.RefIbpMapCode))
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
msgArr = append(msgArr, TopicMsg{channalName: channelName, data: b})
}
}
}
return msgArr
}
// 处理订阅通道名称
func handlerIBPChannelName(sid, mapId, station string, format string) string {
var channelName string
channelName = strings.Replace(format, "{sid}", sid, 1)
channelName = strings.Replace(channelName, "{mid}", mapId, 1)
channelName = strings.Replace(channelName, "{station}", station, 1)
return channelName
}

View File

@ -0,0 +1,59 @@
package apiproto
import (
"strconv"
"strings"
"time"
"google.golang.org/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/simulation"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/dto"
)
type SimulationPSLServer struct{}
// 返回通道格式
func (t *SimulationPSLServer) getChannelName() string {
return "simulation-psl-{sid}_{mid}_{psl}-status"
}
// 消息运行间隔
func (t *SimulationPSLServer) getInterval() time.Duration {
return 200 * time.Millisecond
}
// 定时发送数据
func (t *SimulationPSLServer) onTick() []TopicMsg {
simArr := simulation.GetSimulationArr()
var msgArr []TopicMsg
for _, v := range simArr {
for _, mapId := range v.MapIds {
mapType := memory.QueryGiType(mapId)
if mapType != graphicData.PictureType_StationLayout {
continue
}
mapData := memory.QueryGiData[*graphicData.RtssGraphicStorage](mapId)
idStr := strconv.Itoa(int(mapId))
for _, box := range mapData.GateBoxs {
channelName := handlerPSLChannelName(v.SimulationId, idStr, box.Common.Id, t.getChannelName())
b, err := proto.Marshal(v.GetAllPSLState(mapId, box.Common.Id))
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
msgArr = append(msgArr, TopicMsg{channalName: channelName, data: b})
}
}
}
return msgArr
}
// 处理订阅通道名称
func handlerPSLChannelName(sid, mapId, psl string, format string) string {
var channelName string
channelName = strings.Replace(format, "{sid}", sid, 1)
channelName = strings.Replace(channelName, "{mid}", mapId, 1)
channelName = strings.Replace(channelName, "{psl}", psl, 1)
return channelName
}

View File

@ -22,28 +22,6 @@ func (t *SimulationServer) getInterval() time.Duration {
return 200 * time.Millisecond
}
// 返回所有数据
func (t *SimulationServer) allMsgData(params map[string]string) []byte {
simId := params["SID"]
if simId == "" {
return nil
}
mId := params["MID"]
if mId == "" {
return nil
}
simulation := simulation.FindSimulation(simId)
if simulation == nil {
return nil
}
mapId, _ := strconv.Atoi(mId)
data, err := proto.Marshal(simulation.GetAllState(int32(mapId)))
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
return data
}
// 定时发送数据
func (t *SimulationServer) onTick() []TopicMsg {
simArr := simulation.GetSimulationArr()

27
init.go
View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"log/slog"
"net"
"net/http"
@ -13,6 +14,7 @@ import (
"go.uber.org/zap"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
@ -45,19 +47,19 @@ func InitServer() *gin.Engine {
engine.Use(cors.New(conf))
// gin panic 异常处理,默认处理为
engine.Use(CustomRecoveryWithSlog(slog.Default(), true, func(c *gin.Context, e interface{}) {
switch e := e.(type) {
case error:
c.JSON(http.StatusInternalServerError, &dto.ErrorDto{
Code: dto.LogicError,
Tip: dto.ErrorTipMap[dto.LogicError],
Message: e.Error(),
})
case dto.ErrorDto:
e.Tip = dto.ErrorTipMap[e.Code]
c.JSON(http.StatusInternalServerError, e)
default:
c.JSON(http.StatusInternalServerError, e)
be, ok := e.(*sys_error.BusinessError)
if !ok {
e, ok := e.(error)
if ok {
be = sys_error.New("未知错误", e)
} else {
be = sys_error.New("未知错误", fmt.Errorf("%v", e))
}
}
c.JSON(http.StatusInternalServerError, &dto.ErrorDto{
Tip: be.UserMsg,
Message: be.Error(),
})
c.Writer.WriteHeaderNow()
c.Abort()
}))
@ -98,6 +100,7 @@ func CustomRecoveryWithSlog(logger *slog.Logger, stack bool, recovery gin.Recove
zap.String("request", string(httpRequest)),
zap.String("stack", string(debug.Stack())),
)
debug.PrintStack()
} else {
logger.Error("[Recovery from panic]",
zap.Time("time", time.Now()),

View File

@ -8,9 +8,9 @@ import (
"joylink.club/bj-rtsts-server/api"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/docs"
"joylink.club/bj-rtsts-server/dynamics"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/vobc"
"joylink.club/bj-rtsts-server/third_party"
)
// @title CBTC测试系统API
@ -26,6 +26,7 @@ import (
func main() {
engine := InitServer()
third_party.Init()
authMiddleware := middleware.InitGinJwtMiddleware()
router := engine.Group("/api")
api.InitUserRouter(router, authMiddleware)
@ -40,9 +41,6 @@ func main() {
docs.SwaggerInfo.Title = "CBTC测试系统API"
engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
go dynamics.RunUdpServer()
go vobc.RunUdpServer()
serverConfig := config.Config.Server
if serverConfig.Port == 0 {
serverConfig.Port = 8080

View File

@ -9,6 +9,7 @@ import (
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
// 用户权限缓存
@ -40,7 +41,7 @@ func permissionMiddleware() gin.HandlerFunc {
return
}
slog.Error("无权限操作请求路径", "path", path, "method", method)
panic(dto.ErrorDto{Code: dto.NoAuthOperationError, Message: "无权限操作"})
panic(sys_error.New("权限不足"))
}
}

@ -1 +1 @@
Subproject commit 7eefa31437020d42b9b363fc1083030292294f0a
Subproject commit 5231948d595afc3f1e36e9ff5119f6d07c7989d3

View File

@ -10,13 +10,13 @@ import (
)
// 查询权限角色信息列表
func PageAuthRoleQuery(query *dto.PageQueryDto) (*dto.PageDto, error) {
func PageAuthRoleQuery(query *dto.PageQueryDto) *dto.PageDto {
d := dbquery.AuthRole
records, total, err := d.Debug().Select(d.ID, d.Name).Order(d.CreateTime).FindByPage(query.Offset(), query.Size)
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: *query, Records: dto.ConvertFromAuthRole(records)}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: *query, Records: dto.ConvertFromAuthRole(records)}
}
// 获取角色列表
@ -142,7 +142,7 @@ func DeleteAuthRole(rid int32) bool {
}
// 查询接口路径信息列表
func PageAuthApiPathQuery(query *dto.AuthApiPathPageReqDto) (*dto.PageDto, error) {
func PageAuthApiPathQuery(query *dto.AuthApiPathPageReqDto) *dto.PageDto {
d := dbquery.AuthAPIPath
dq := d.Where()
if query.Name != "" {
@ -152,7 +152,7 @@ func PageAuthApiPathQuery(query *dto.AuthApiPathPageReqDto) (*dto.PageDto, error
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询接口路径信息列表

View File

@ -10,7 +10,7 @@ import (
)
// 查询草稿列表
func PageCategoryQuery(query *dto.PageCategoryReqDto) (*dto.PageDto, error) {
func PageCategoryQuery(query *dto.PageCategoryReqDto) *dto.PageDto {
d := dbquery.Category
dq := d.Where()
if query.Name != "" {
@ -20,11 +20,11 @@ func PageCategoryQuery(query *dto.PageCategoryReqDto) (*dto.PageDto, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询草稿列表
func ListCategoryQuery(query *dto.CategoryReqDto) ([]*model.Category, error) {
func ListCategoryQuery(query *dto.CategoryReqDto) []*model.Category {
d := dbquery.Category
dq := d.Where()
if query.Name != "" {
@ -34,11 +34,11 @@ func ListCategoryQuery(query *dto.CategoryReqDto) ([]*model.Category, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建草稿
func CreateCategory(cd *dto.CategoryDto) (*model.Category, error) {
func CreateCategory(cd *dto.CategoryDto) *model.Category {
if err := checkCategoryInfo(cd.Name, cd.Code, 0); err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
@ -53,7 +53,11 @@ func CreateCategory(cd *dto.CategoryDto) (*model.Category, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dbquery.Category.Where(dbquery.Category.Name.Eq(cd.Name)).Order(dbquery.Category.CreatedAt).Debug().First()
data, err := dbquery.Category.Where(dbquery.Category.Name.Eq(cd.Name)).Order(dbquery.Category.CreatedAt).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
func QueryCategory(id int32) *model.Category {

View File

@ -10,7 +10,7 @@ import (
)
// 查询草稿列表
func PageDraftingQuery(query *dto.PageDraftingReqDto) (*dto.PageDto, error) {
func PageDraftingQuery(query *dto.PageDraftingReqDto) *dto.PageDto {
d := dbquery.Drafting
dq := d.Where()
if query.Name != "" {
@ -20,10 +20,10 @@ func PageDraftingQuery(query *dto.PageDraftingReqDto) (*dto.PageDto, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
func ListDraftingQuery(query *dto.ListDraftingReqDto) ([]*model.Drafting, error) {
func ListDraftingQuery(query *dto.ListDraftingReqDto) []*model.Drafting {
d := dbquery.Drafting
dq := d.Where()
if query.Type != 0 {
@ -33,11 +33,11 @@ func ListDraftingQuery(query *dto.ListDraftingReqDto) ([]*model.Drafting, error)
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建草稿
func CreateDrafting(createId int32, dd *dto.DraftingDto) (*model.Drafting, error) {
func CreateDrafting(createId int32, dd *dto.DraftingDto) *model.Drafting {
if err := checkDraftingInfo(dd.Name); err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
@ -54,16 +54,20 @@ func CreateDrafting(createId int32, dd *dto.DraftingDto) (*model.Drafting, error
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dbquery.Drafting.Where(
data, err := dbquery.Drafting.Where(
dbquery.Drafting.Name.Eq(dd.Name),
dbquery.Drafting.CreatorID.Eq(createId),
).Order(dbquery.Drafting.CreatedAt).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
// 另存为
func SaveAsDrafting(createId int32, oldId int32, dd *dto.DraftingDto) (*model.Drafting, error) {
func SaveAsDrafting(createId int32, oldId int32, dd *dto.DraftingDto) *model.Drafting {
if err := checkDraftingInfo(dd.Name); err != nil {
return nil, err
return nil
}
oldD, err := dbquery.Drafting.Where(dbquery.Drafting.ID.Eq(oldId)).Debug().First()
if oldD == nil || err != nil {
@ -81,10 +85,14 @@ func SaveAsDrafting(createId int32, oldId int32, dd *dto.DraftingDto) (*model.Dr
if err = dbquery.Drafting.Save(&newD); err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dbquery.Drafting.Where(
data, err := dbquery.Drafting.Where(
dbquery.Drafting.Name.Eq(dd.Name),
dbquery.Drafting.CreatorID.Eq(createId),
).Order(dbquery.Drafting.CreatedAt).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
func QueryDrafting(id int32) *model.Drafting {

View File

@ -10,7 +10,7 @@ import (
)
// 查询项目列表
func PageProjectQuery(query *dto.PageProjectReqDto) (*dto.PageDto, error) {
func PageProjectQuery(query *dto.PageProjectReqDto) *dto.PageDto {
d := dbquery.Project
dq := d.Where()
if query.Name != "" {
@ -23,11 +23,11 @@ func PageProjectQuery(query *dto.PageProjectReqDto) (*dto.PageDto, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询项目列表
func ListProjectQuery(query *dto.ProjectReqDto) ([]*model.Project, error) {
func ListProjectQuery(query *dto.ProjectReqDto) []*model.Project {
d := dbquery.Project
dq := d.Where()
if query.Name != "" {
@ -40,11 +40,11 @@ func ListProjectQuery(query *dto.ProjectReqDto) ([]*model.Project, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建草稿
func CreateProject(pd *dto.ProjectDto) (*model.Project, error) {
func CreateProject(pd *dto.ProjectDto) *model.Project {
if err := checkProjectInfo(pd.Code, 0); err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
@ -59,7 +59,11 @@ func CreateProject(pd *dto.ProjectDto) (*model.Project, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return p.Where(p.Name.Eq(pd.Name)).Order(p.CreatedAt).Debug().First()
data, err := p.Where(p.Name.Eq(pd.Name)).Order(p.CreatedAt).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
func QueryProject(id int32) *model.Project {

View File

@ -2,6 +2,7 @@ package service
import (
"fmt"
"sync"
"time"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
@ -11,6 +12,8 @@ import (
"joylink.club/bj-rtsts-server/dto/publishedGi"
)
var publishMapMutex sync.Mutex
func PageQueryPublishedGi(req *publishedGi.PublishedGiReqDto) *dto.PageDto {
dp := dbquery.PublishedGi
where := dp.Where(dp.Status.Eq(1))
@ -50,11 +53,17 @@ func ListAllPublishedGi() ([]*model.PublishedGi, error) {
return dbquery.PublishedGi.Debug().Where(dbquery.PublishedGi.Status.Eq(1)).Find()
}
func GetPublishedGiById(id int) (*model.PublishedGi, error) {
return dbquery.PublishedGi.Where(dbquery.PublishedGi.ID.Eq(int32(id))).Debug().First()
func GetPublishedGiById(id int) *model.PublishedGi {
data, err := dbquery.PublishedGi.Where(dbquery.PublishedGi.ID.Eq(int32(id))).Debug().First()
if err != nil {
panic(err)
}
return data
}
func PublishFormDraft(req *publishedGi.PublishReqDto, user *model.User) {
publishMapMutex.Lock()
defer publishMapMutex.Unlock()
draft := QueryDrafting(req.DraftId)
if draft.Proto == nil || len(draft.Proto) == 0 {
panic(fmt.Sprintf("草稿[%v]绘图数据信息为空", req.DraftId))
@ -146,12 +155,16 @@ func QueryProjectPublishedGi(id int32) []*model.PublishedGi {
return publishedGis
}
func GetPublishedGiByName(param *publishedGi.PublishedGiSingleQueryDto) (*model.PublishedGi, error) {
func GetPublishedGiByName(param *publishedGi.PublishedGiSingleQueryDto) *model.PublishedGi {
where := dbquery.PublishedGi.
Where(dbquery.PublishedGi.Name.Eq(param.Name)).
Where(dbquery.PublishedGi.Status.Eq(1))
if !param.Detail {
where = where.Omit(dbquery.PublishedGi.Proto)
}
return where.Debug().First()
data, err := where.Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.DataOperationError, Message: err.Error()})
}
return data
}

View File

@ -1,18 +0,0 @@
package service
import (
"google.golang.org/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/dto"
)
// 查询地图数据
func QueryRtssGraphicStorage(mapId int32) *graphicData.RtssGraphicStorage {
publishdata, err := GetPublishedGiById(int(mapId))
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
graphicStorage := &graphicData.RtssGraphicStorage{}
proto.Unmarshal(publishdata.Proto, graphicStorage)
return graphicStorage
}

View File

@ -10,7 +10,7 @@ import (
)
// 查询列车型号信息列表
func PageTrainModelQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto, error) {
func PageTrainModelQuery(query *dto.PageTrainManageReqDto) *dto.PageDto {
d := dbquery.TrainModel
dq := d.Where()
if query.Name != "" {
@ -20,11 +20,11 @@ func PageTrainModelQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto, error)
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询列车型号信息列表
func ListTrainModelQuery(query *dto.TrainManageReqDto) ([]*model.TrainModel, error) {
func ListTrainModelQuery(query *dto.TrainManageReqDto) []*model.TrainModel {
d := dbquery.TrainModel
dq := d.Where()
if query.Name != "" {
@ -34,11 +34,11 @@ func ListTrainModelQuery(query *dto.TrainManageReqDto) ([]*model.TrainModel, err
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建列车型号信息
func CreateTrainModel(td *dto.TrainModelDto) (*model.TrainModel, error) {
func CreateTrainModel(td *dto.TrainModelDto) *model.TrainModel {
if err := checkTrainModel(td.Name, 0); err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
@ -52,7 +52,11 @@ func CreateTrainModel(td *dto.TrainModelDto) (*model.TrainModel, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dt.Where(dt.Name.Eq(td.Name)).Order(dt.CreatedAt).Debug().First()
data, err2 := dt.Where(dt.Name.Eq(td.Name)).Order(dt.CreatedAt).Debug().First()
if err2 != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err2.Error()})
}
return data
}
// 查询列车型号信息
@ -90,7 +94,7 @@ func DeleteTrainModelById(id int) {
}
// 查询列车尺寸信息列表
func PageTrainSizeQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto, error) {
func PageTrainSizeQuery(query *dto.PageTrainManageReqDto) *dto.PageDto {
d := dbquery.TrainSize
dq := d.Where()
if query.Name != "" {
@ -100,11 +104,11 @@ func PageTrainSizeQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto, error)
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询列车尺寸信息列表
func ListTrainSizeQuery(query *dto.TrainManageReqDto) ([]*model.TrainSize, error) {
func ListTrainSizeQuery(query *dto.TrainManageReqDto) []*model.TrainSize {
d := dbquery.TrainSize
dq := d.Where()
if query.Name != "" {
@ -114,11 +118,11 @@ func ListTrainSizeQuery(query *dto.TrainManageReqDto) ([]*model.TrainSize, error
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建列车尺寸信息
func CreateTrainSize(td *dto.TrainSizeDto) (*model.TrainSize, error) {
func CreateTrainSize(td *dto.TrainSizeDto) *model.TrainSize {
d := model.TrainSize{
Name: td.Name,
CarriageLength: td.CarriageLength,
@ -130,7 +134,11 @@ func CreateTrainSize(td *dto.TrainSizeDto) (*model.TrainSize, error) {
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dt.Where(dt.Name.Eq(td.Name)).Order(dt.Name).Debug().First()
data, err := dt.Where(dt.Name.Eq(td.Name)).Order(dt.Name).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
// 查询列车尺寸信息
@ -185,7 +193,7 @@ func QueryProjectTrainSize(id int32) []*model.TrainSize {
}
// 查询列车轮径信息列表
func PageTrainWheelDiameterQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto, error) {
func PageTrainWheelDiameterQuery(query *dto.PageTrainManageReqDto) *dto.PageDto {
d := dbquery.TrainWheelDiameter
dq := d.Where()
if query.Name != "" {
@ -195,11 +203,11 @@ func PageTrainWheelDiameterQuery(query *dto.PageTrainManageReqDto) (*dto.PageDto
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}, nil
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: records}
}
// 查询列车轮径信息列表
func ListTrainWheelDiameterQuery(query *dto.TrainManageReqDto) ([]*model.TrainWheelDiameter, error) {
func ListTrainWheelDiameterQuery(query *dto.TrainManageReqDto) []*model.TrainWheelDiameter {
d := dbquery.TrainWheelDiameter
dq := d.Where()
if query.Name != "" {
@ -209,11 +217,11 @@ func ListTrainWheelDiameterQuery(query *dto.TrainManageReqDto) ([]*model.TrainWh
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return records, nil
return records
}
// 创建列车轮径信息
func CreateTrainWheelDiameter(twd *dto.TrainWheelDiameterDto) (*model.TrainWheelDiameter, error) {
func CreateTrainWheelDiameter(twd *dto.TrainWheelDiameterDto) *model.TrainWheelDiameter {
d := model.TrainWheelDiameter{
Name: twd.Name,
Diameter: twd.Diameter,
@ -227,7 +235,11 @@ func CreateTrainWheelDiameter(twd *dto.TrainWheelDiameterDto) (*model.TrainWheel
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return dt.Where(dt.Name.Eq(twd.Name)).Order(dt.Name).Debug().First()
data, err := dt.Where(dt.Name.Eq(twd.Name)).Order(dt.Name).Debug().First()
if err != nil {
panic(dto.ErrorDto{Code: dto.QueryDBError, Message: err.Error()})
}
return data
}
// 查询列车轮径信息

View File

@ -2,13 +2,13 @@ package service
import (
"fmt"
"log/slog"
"sort"
"time"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
)
// 分页查询用户列表
@ -28,23 +28,23 @@ func PagingQueryUser(query *dto.PageUserReqDto) (*dto.PageDto, error) {
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: linkUserRole(records)}, err
}
func Register(user *dto.RegisterUser) {
defer func() {
err := recover()
if err != nil {
slog.Warn("用户注册失败", err)
panic(err)
}
}()
func Register(user *dto.RegisterUser) error {
u := dbquery.User
uq := u.Where()
uq = uq.Where(u.Mobile.Eq(user.Mobile))
findCounter, _ := uq.Count()
findCounter, err := uq.Count()
if err != nil {
return sys_error.New("数据服务异常", err)
}
if findCounter > 0 {
panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "重复的手机号"})
return sys_error.New("手机号已存在")
}
user.RegisterTime = time.Now()
u.Save(user)
err = u.Save(user)
if err != nil {
return sys_error.New("数据服务异常", err)
}
return nil
}
func FindUserInfo(userId int32) *dto.UserRspDto {

61
sys_error/error.go Normal file
View File

@ -0,0 +1,61 @@
package sys_error
import (
"fmt"
"strings"
)
// 业务错误定义
type BusinessError struct {
// 用户提示信息
UserMsg string
// 错误信息传递(用于开发回溯定位,不给用户展示)
Errors []string
}
// 新建业务错误
// 如果errs为空,则返回一个只包含用户提示信息的业务错误
// 如果errs不为空,如果errs是一个业务错误,则附加错误信息,否则返回一个包含用户提示信息和错误信息的业务错误
func New(userMsg string, errs ...error) *BusinessError {
if len(errs) == 1 {
be, ok := errs[0].(*BusinessError)
if ok {
be.prependUserMsg(userMsg)
return be
} else {
return &BusinessError{
UserMsg: userMsg,
Errors: []string{errs[0].Error()},
}
}
}
return &BusinessError{
UserMsg: userMsg,
// Errors: convert(errs),
}
}
func IsBusinessError(err error) bool {
_, ok := err.(*BusinessError)
return ok
}
func (e *BusinessError) prependUserMsg(userMsg string) {
e.UserMsg = fmt.Sprintf("%s,%s", userMsg, e.UserMsg)
}
// func convert(err []error) []string {
// s := []string{}
// for _, e := range err {
// s = append(s, e.Error())
// }
// return s
// }
func (e *BusinessError) Append(err error) {
e.Errors = append(e.Errors, err.Error())
}
func (e *BusinessError) Error() string {
return strings.Join(e.Errors, ", ")
}

View File

@ -10,6 +10,11 @@ type InitTrainInfo struct {
TrainLength uint16 `json:"trainLength"`
}
// 移除列车请求参数
type RemoveTrainReq struct {
TrainIndex uint16 `json:"trainIndex"`
}
// LineBaseInfo 线路基础信息,提供给动力学作为计算依据
type LineBaseInfo struct {
LinkList []*Link `json:"linkList"`

View File

@ -249,6 +249,7 @@ func decoderDynamicsTrainInfo(buf []byte) *TrainInfo {
trainInfo.HeadRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[50:54]))
trainInfo.TailRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[54:58]))
trainInfo.Acceleration = math.Float32frombits(binary.BigEndian.Uint32(buf[58:62]))
trainInfo.VobcLifeSignal = binary.BigEndian.Uint16(buf[62:64])
return trainInfo
}

View File

@ -48,4 +48,6 @@ type TrainInfo struct {
TailRadarSpeed float32
//加速度(m/s^2)
Acceleration float32
// 对应动力学生命周期值
VobcLifeSignal uint16
}

View File

@ -113,13 +113,16 @@ func RunUdpServer() {
}
// 发送列车速度到VOBC
func SendTrainSpeedTask(trainInfo *SendTrainInfo) error {
func SendTrainSpeedTask(speed float64) error {
if running {
return nil
}
mutex.Lock()
defer mutex.Unlock()
trainInfo.LifeSignal = sendTrainLifeSignal
trainInfo := &SendTrainInfo{
LifeSignal: sendTrainLifeSignal,
Speed: uint16(speed),
}
err := sendVobcMsg(encoderVobcTrainInfo(trainInfo))
if err != nil {
slog.Error("发送Vobc信息失败", err)
@ -161,7 +164,6 @@ func sendVobcMsg(buf []byte) error {
// 将道岔转为动力学的消息
func encoderVobcTrainInfo(info *SendTrainInfo) []byte {
slog.Info("收到的动力学传输的信息:", info)
var data []byte
data = binary.BigEndian.AppendUint16(data, info.LifeSignal)
data = binary.BigEndian.AppendUint16(data, info.Speed)
@ -179,6 +181,5 @@ func encoderVobcTrainInfo(info *SendTrainInfo) []byte {
data = binary.BigEndian.AppendUint32(data, info.SlopeResistance) // 坡道阻力 100 = 1KN
data = binary.BigEndian.AppendUint32(data, info.CurveResistance) // 曲线阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, info.Slope) // 坡度值 1= 1‰
slog.Info("收到的动力转换后的信息:", data)
return data
}

243
third_party/dynamics/dynamics.go vendored Normal file
View File

@ -0,0 +1,243 @@
package dynamics
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"runtime/debug"
"time"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
)
type DynamicsMessageManager interface {
CollectDynamicsTurnoutInfo() []*message.DynamicsTurnoutInfo
HandleDynamicsTrainInfo(info *message.DynamicsTrainInfo)
}
// 动力学接口
type Dynamics interface {
// 请求启动仿真
RequestStartSimulation(base *message.LineBaseInfo) error
// 请求停止仿真
RequestStopSimulation() error
// 请求添加列车
RequestAddTrain(info *message.InitTrainInfo) error
// 请求移除列车
RequestRemoveTrain(req *message.RemoveTrainReq) error
// 启动动力学消息功能
Start(manager DynamicsMessageManager)
// 停止动力学消息功能
Stop()
// 发送列车控制消息
SendTrainControlMessage(b []byte)
}
var _default Dynamics
func Default() Dynamics {
if !config.Config.Dynamics.Open {
panic("动力学接口模块未开启")
}
return _default
}
func Init() {
if !config.Config.Dynamics.Open {
return
}
slog.Info("初始化动力学接口模块")
_default = newDynamics()
}
type dynamics struct {
trainInfoUdpServer udp.UdpServer
turnoutStateUdpClient udp.UdpClient
trainControlUdpClient udp.UdpClient
baseUrl string
httpClient *http.Client
manager DynamicsMessageManager
turnoutTaskCancel context.CancelFunc
}
func newDynamics() Dynamics {
d := &dynamics{
turnoutStateUdpClient: udp.NewClient(fmt.Sprintf("%v:%v", config.Config.Dynamics.Ip, config.Config.Dynamics.UdpRemotePort)),
trainControlUdpClient: udp.NewClient(fmt.Sprintf("%v:%v", config.Config.Dynamics.Ip, config.Config.Dynamics.UdpRemoteTrainPort)),
baseUrl: getUrlBase(),
httpClient: &http.Client{
Timeout: time.Second * 5,
},
}
d.trainInfoUdpServer = udp.NewServer(fmt.Sprintf(":%d", config.Config.Dynamics.UdpLocalPort), d.handleDynamicsTrainInfo)
d.trainInfoUdpServer.Listen()
return d
}
// 解码列车信息并处理
func (d *dynamics) handleDynamicsTrainInfo(b []byte) {
trainInfo := &message.DynamicsTrainInfo{}
err := trainInfo.Decode(b)
if err != nil {
panic(err)
}
handler := d.manager
if handler != nil {
handler.HandleDynamicsTrainInfo(trainInfo)
}
}
func getUrlBase() string {
ip := config.Config.Dynamics.Ip
var port string
if config.Config.Dynamics.HttpPort != 0 {
port = fmt.Sprintf(":%d", config.Config.Dynamics.HttpPort)
}
urlBase := "http://" + ip + port
return urlBase
}
func (d *dynamics) buildUrl(uri string) string {
return d.baseUrl + uri
}
func (d *dynamics) RequestStartSimulation(base *message.LineBaseInfo) error {
if !config.Config.Dynamics.Open {
return nil
}
url := d.buildUrl("/api/start/")
data, _ := json.Marshal(base)
resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
return sys_error.New("动力学开始仿真请求发送错误", err)
}
defer resp.Body.Close()
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return sys_error.New("动力学开始仿真请求响应错误", err)
}
return nil
}
func (d *dynamics) RequestStopSimulation() error {
if !config.Config.Dynamics.Open {
return nil
}
url := d.buildUrl("/api/end/")
resp, err := d.httpClient.Post(url, "application/json", nil)
if err != nil {
return fmt.Errorf("停止仿真请求异常: %v", err)
}
defer resp.Body.Close()
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return fmt.Errorf("停止仿真响应读取异常: %v", err)
}
return nil
}
func (d *dynamics) RequestAddTrain(info *message.InitTrainInfo) error {
if !config.Config.Dynamics.Open {
return nil
}
url := d.buildUrl("/api/aerodynamics/init/train/")
data, _ := json.Marshal(info)
resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("动力学添加列车请求异常: %v", err)
}
defer resp.Body.Close()
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return fmt.Errorf("动力学添加列车响应读取异常: %v", err)
}
return nil
}
func (d *dynamics) RequestRemoveTrain(req *message.RemoveTrainReq) error {
if !config.Config.Dynamics.Open {
return nil
}
url := d.buildUrl("/api/aerodynamics/remove/train/")
data, _ := json.Marshal(req)
resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("动力学移除列车请求异常: %v", err)
}
defer resp.Body.Close()
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return fmt.Errorf("动力学移除列车响应读取异常: %v", err)
}
return nil
}
func (d *dynamics) Start(manager DynamicsMessageManager) {
if manager == nil {
panic("启动动力学消息服务错误: DynamicsMessageManager不能为nil")
}
if d.manager != nil {
panic("启动动力学消息服务错误: 存在正在运行的任务")
}
d.manager = manager
ctx, cancle := context.WithCancel(context.Background())
go d.sendTurnoutStateTask(ctx)
d.turnoutTaskCancel = cancle
}
func (d *dynamics) Stop() {
if d.turnoutTaskCancel != nil {
d.turnoutTaskCancel()
d.manager = nil
}
}
const (
// 道岔消息发送间隔,单位ms
TurnoutMessageSendInterval = 50
)
var turnoutStateLifeSignal uint16 //道岔消息生命信号
// 定时发送道岔状态任务
func (d *dynamics) sendTurnoutStateTask(ctx context.Context) {
defer func() {
if err := recover(); err != nil {
slog.Error("定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack()))
debug.PrintStack()
}
}()
for {
select {
case <-ctx.Done():
return
default:
}
turnoutStates := d.manager.CollectDynamicsTurnoutInfo()
// slog.Debug("发送道岔状态", "count", len(turnoutStates))
for _, state := range turnoutStates {
turnoutStateLifeSignal++
state.LifeSignal = turnoutStateLifeSignal
d.turnoutStateUdpClient.SendMsg(state)
}
time.Sleep(time.Millisecond * TurnoutMessageSendInterval)
}
}
func (d *dynamics) SendTrainControlMessage(b []byte) {
d.trainControlUdpClient.Send(b)
}

43
third_party/example/main.go vendored Normal file
View File

@ -0,0 +1,43 @@
package main
import (
"log/slog"
"time"
"joylink.club/bj-rtsts-server/third_party/udp"
)
type TestMsg struct {
Msg string
Port int
}
func (t *TestMsg) Encode() []byte {
b := []byte(t.Msg)
// binary.BigEndian.PutUint16(b, uint16(t.Port))
return b
}
func (t *TestMsg) Decode(data []byte) error {
t.Msg = string(data)
// t.Port = int(binary.BigEndian.Uint16(data))
return nil
}
func handleUdpMsg(b []byte) {
slog.Info("udp server handle", "msg", string(b))
}
func main() {
udp.NewServer("127.0.0.1:6666", handleUdpMsg).Listen()
// client := udp.NewClient("127.0.0.1:7777")
// for i := 0; i < 1000; i++ {
// time.Sleep(time.Millisecond * 500)
// client.Send(&TestMsg{
// Msg: "test, port = 7777",
// })
// }
time.Sleep(time.Second * 60)
}

100
third_party/message/dynamics.go vendored Normal file
View File

@ -0,0 +1,100 @@
package message
import (
"encoding/binary"
"math"
)
type DynamicsTurnoutInfo struct {
LifeSignal uint16
Code uint16
NPosition bool
RPosition bool
}
func (t *DynamicsTurnoutInfo) Encode() []byte {
var data []byte
data = binary.BigEndian.AppendUint16(data, t.LifeSignal)
data = binary.BigEndian.AppendUint16(data, t.Code)
var b byte
if t.NPosition {
b |= 1 << 7
}
if t.RPosition {
b |= 1 << 6
}
data = append(data, b)
return data
}
type DynamicsTrainInfo struct {
//生命信号
LifeSignal uint16
//列车号(车辆)
Number uint8
//列车长度 cm
Len uint16
//列车所在轨道link
Link uint8
//列车所在link偏移量mm
LinkOffset uint32
//列车所在位置坡度值(‰)
Slope uint16
//列车所在位置坡度走势(上/下坡)
UpSlope bool
//列车当前运行方向(偏移量增大/减小方向)
Up bool
//实际运行阻力N
TotalResistance int32
//阻力1空气阻力N
AirResistance int32
//阻力2坡道阻力N
SlopeResistance int32
//阻力3曲线阻力N
CurveResistance int32
//列车运行速度m/s
Speed float32
//头车速传1速度值m/s
HeadSpeed1 float32
//头车速度2速度值m/s
HeadSpeed2 float32
//尾车速传1速度值m/s
TailSpeed1 float32
//尾车速度2速度值m/s
TailSpeed2 float32
//头车雷达速度值m/s
HeadRadarSpeed float32
//尾车雷达速度值m/s
TailRadarSpeed float32
//加速度(m/s^2)
Acceleration float32
// 对应动力学生命周期值
VobcLifeSignal uint16
}
// 解析动力学的列车信息
func (t *DynamicsTrainInfo) Decode(buf []byte) error {
t.LifeSignal = binary.BigEndian.Uint16(buf[0:2])
t.Number = buf[2]
t.Len = binary.BigEndian.Uint16(buf[3:5])
t.Link = buf[5]
t.LinkOffset = binary.BigEndian.Uint32(buf[6:10])
t.Slope = binary.BigEndian.Uint16(buf[10:12])
b := buf[12]
t.UpSlope = (b & (1 << 7)) != 0
t.Up = (b & (1 << 6)) != 0
t.TotalResistance = int32(binary.BigEndian.Uint32(buf[14:18]))
t.AirResistance = int32(binary.BigEndian.Uint32(buf[18:22]))
t.SlopeResistance = int32(binary.BigEndian.Uint32(buf[22:26]))
t.CurveResistance = int32(binary.BigEndian.Uint32(buf[26:30]))
t.Speed = math.Float32frombits(binary.BigEndian.Uint32(buf[30:34]))
t.HeadSpeed1 = math.Float32frombits(binary.BigEndian.Uint32(buf[34:38]))
t.HeadSpeed2 = math.Float32frombits(binary.BigEndian.Uint32(buf[38:42]))
t.TailSpeed1 = math.Float32frombits(binary.BigEndian.Uint32(buf[42:46]))
t.TailSpeed2 = math.Float32frombits(binary.BigEndian.Uint32(buf[46:50]))
t.HeadRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[50:54]))
t.TailRadarSpeed = math.Float32frombits(binary.BigEndian.Uint32(buf[54:58]))
t.Acceleration = math.Float32frombits(binary.BigEndian.Uint32(buf[58:62]))
t.VobcLifeSignal = binary.BigEndian.Uint16(buf[62:64])
return nil
}

52
third_party/message/dynamics_http.go vendored Normal file
View File

@ -0,0 +1,52 @@
package message
type InitTrainInfo struct {
TrainIndex uint16 `json:"trainIndex"`
LinkIndex uint16 `json:"linkIndex"`
LinkOffset uint32 `json:"linkOffset"`
//单位0.1km/h
Speed uint16 `json:"speed"`
Up bool `json:"up"`
TrainLength uint16 `json:"trainLength"`
}
// 移除列车请求参数
type RemoveTrainReq struct {
TrainIndex uint16 `json:"trainIndex"`
}
// LineBaseInfo 线路基础信息,提供给动力学作为计算依据
type LineBaseInfo struct {
LinkList []*Link `json:"linkList"`
SlopeList []*Slope `json:"slopeList"`
CurveList []*Curve `json:"curveList"`
}
type Link struct {
ID int32 `json:"id"`
//长度 mm
Len int32 `json:"len"`
ARelTurnoutId int32 `json:"ARelTurnoutId"`
ARelTurnoutPoint string `json:"ARelTurnoutPoint"`
BRelTurnoutId int32 `json:"BRelTurnoutId"`
BRelTurnoutPoint string `json:"BRelTurnoutPoint"`
}
type Slope struct {
ID int32 `json:"id"`
StartLinkId int32 `json:"startLinkId"`
StartLinkOffset int32 `json:"startLinkOffset"`
EndLinkId int32 `json:"endLinkId"`
EndLinkOffset int32 `json:"endLinkOffset"`
//坡度的三角函数(猜是sin)值的*1000
DegreeTrig int32 `json:"degreeTrig"`
}
type Curve struct {
ID int32 `json:"id"`
StartLinkId int32 `json:"startLinkId"`
StartLinkOffset int32 `json:"startLinkOffset"`
EndLinkId int32 `json:"endLinkId"`
EndLinkOffset int32 `json:"endLinkOffset"`
Curvature int32 `json:"curvature"`
}

111
third_party/message/train_control.go vendored Normal file
View File

@ -0,0 +1,111 @@
package message
import (
"encoding/binary"
"math"
"time"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
)
// 接收到的列车控制信息
type TrainControlMsg struct {
ControlInfo *state.TrainVobcState
}
// 解析VOBC列车信息
func (r *TrainControlMsg) Decode(buf []byte) error {
t := &state.TrainVobcState{}
t.LifeSignal = int32(binary.BigEndian.Uint16(buf[0:2]))
b2 := buf[2]
t.Tc1Active = (b2 & 1) != 0
t.Tc2Active = (b2 & (1 << 1)) != 0
t.DirectionForward = (b2 & (1 << 2)) != 0
t.DirectionBackward = (b2 & (1 << 3)) != 0
t.TractionStatus = (b2 & (1 << 4)) != 0
t.BrakingStatus = (b2 & (1 << 5)) != 0
t.EmergencyBrakingStatus = (b2 & (1 << 6)) != 0
t.TurnbackStatus = (b2 & 7) != 0
b3 := buf[3]
t.JumpStatus = (b3 & 1) != 0
t.Ato = (b3 & (1 << 1)) != 0
t.Fam = (b3 & (1 << 2)) != 0
t.Cam = (b3 & (1 << 3)) != 0
t.TractionSafetyCircuit = (b3 & (1 << 4)) != 0
t.ParkingBrakeStatus = (b3 & (1 << 5)) != 0
t.MaintainBrakeStatus = (b3 & (1 << 6)) != 0
t.TractionForce = int64(binary.BigEndian.Uint16(buf[4:6]))
t.BrakeForce = int64(binary.BigEndian.Uint16(buf[6:8]))
t.TrainLoad = int64(binary.BigEndian.Uint16(buf[8:10]))
b4 := buf[15]
t.LeftDoorOpenCommand = (b4 & 1) != 0
t.RightDoorOpenCommand = (b4 & (1 << 1)) != 0
t.LeftDoorCloseCommand = (b4 & (1 << 2)) != 0
t.RightDoorCloseCommand = (b4 & (1 << 3)) != 0
t.AllDoorClose = (b4 & (1 << 4)) != 0
t.UpdateTime = time.Now().UnixMilli()
r.ControlInfo = t
return nil
}
// 发送列车信息
type TrainSpeedMsg struct {
// 生命信号 每个周期+1
lifeSignal uint16
// 列车速度 10=1km/h
speed uint16
// 上坡
upslope bool
// 坡度值 1= 1‰
slope uint16
// 加速度 100 = 1 m/s*s
acceleration uint8
// 减速度 100 = 1 m/s*s
deceleration uint8
// 实际运行阻力 100 = 1KN
totalResistance uint32
// 空气阻力 100 = 1KN
airResistance uint32
// 坡道阻力 100 = 1KN
slopeResistance uint32
// 曲线阻力 100 = 1KN
curveResistance uint32
}
func (t *TrainSpeedMsg) DynamicsDecode(info *DynamicsTrainInfo) {
t.lifeSignal = info.LifeSignal
t.speed = uint16(math.Abs(float64(info.Speed * 36)))
t.upslope = info.UpSlope
t.slope = uint16(info.Slope)
t.totalResistance = uint32(math.Abs(float64(info.TotalResistance / 10)))
t.airResistance = uint32(info.AirResistance / 10)
t.slopeResistance = uint32(math.Abs(float64(info.SlopeResistance / 10)))
t.curveResistance = uint32(info.CurveResistance / 10)
d := math.Abs(float64(info.Acceleration * 100))
if info.Acceleration > 0 {
t.acceleration = uint8(d)
} else {
t.deceleration = uint8(d)
}
}
func (t *TrainSpeedMsg) Encode() []byte {
var data []byte
data = binary.BigEndian.AppendUint16(data, t.lifeSignal)
data = binary.BigEndian.AppendUint16(data, t.speed)
if t.upslope {
data = append(data, 1)
} else {
data = append(data, 0)
}
// 中间预留一位
data = append(data, 0)
data = append(data, t.acceleration) // 加速度 100 = 1 m/s*s
data = append(data, t.deceleration) // 减速度 100 = 1 m/s*s
data = binary.BigEndian.AppendUint32(data, t.totalResistance) // 实际运行阻力 100 = 1KN
data = binary.BigEndian.AppendUint32(data, t.airResistance) // 空气阻力 100 = 1KN
data = binary.BigEndian.AppendUint32(data, t.slopeResistance) // 坡道阻力 100 = 1KN
data = binary.BigEndian.AppendUint32(data, t.curveResistance) // 曲线阻力 100 = 1KN
data = binary.BigEndian.AppendUint16(data, t.slope) // 坡度值 1= 1‰
return data
}

View File

@ -0,0 +1,77 @@
package semi_physical_train
import (
"fmt"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
)
// 半实物仿真列车通信接口
type SemiPhysicalTrain interface {
// 启动半实物仿真消息处理
Start(manager SemiPhysicalMessageManager)
// 停止半实物仿真消息处理
Stop()
// 发送列车控制消息
SendTrainControlMessage(info *message.DynamicsTrainInfo)
}
type SemiPhysicalMessageManager interface {
// 处理半实物仿真列车控制消息
HandleSemiPhysicalTrainControlMsg(b []byte)
}
type semiPhysicalTrainImpl struct {
trainControlUdpServer udp.UdpServer
trainSpeedInfoUdpClient udp.UdpClient
manager SemiPhysicalMessageManager
}
func (s *semiPhysicalTrainImpl) handleTrainControlMsg(b []byte) {
handler := s.manager
if handler != nil {
handler.HandleSemiPhysicalTrainControlMsg(b)
}
}
func (s *semiPhysicalTrainImpl) Start(manager SemiPhysicalMessageManager) {
s.manager = manager
}
func (s *semiPhysicalTrainImpl) Stop() {
s.manager = nil
}
func (s *semiPhysicalTrainImpl) SendTrainControlMessage(info *message.DynamicsTrainInfo) {
sendMsg := &message.TrainSpeedMsg{}
sendMsg.DynamicsDecode(info)
s.trainSpeedInfoUdpClient.Send(sendMsg.Encode())
}
func newSemiPhysicalTrain() SemiPhysicalTrain {
s := &semiPhysicalTrainImpl{
trainSpeedInfoUdpClient: udp.NewClient(fmt.Sprintf("%v:%v", config.Config.Vobc.Ip, config.Config.Vobc.RemotePort)),
}
s.trainControlUdpServer = udp.NewServer(fmt.Sprintf(":%d", config.Config.Vobc.LocalPort), s.handleTrainControlMsg)
s.trainControlUdpServer.Listen()
return s
}
var _default SemiPhysicalTrain
func Default() SemiPhysicalTrain {
if !config.Config.Vobc.Open {
panic("半实物仿真接口模块未开启")
}
return _default
}
func Init() {
if !config.Config.Vobc.Open {
return
}
_default = newSemiPhysicalTrain()
}

11
third_party/third_party.go vendored Normal file
View File

@ -0,0 +1,11 @@
package third_party
import (
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
)
func Init() {
dynamics.Init()
semi_physical_train.Init()
}

79
third_party/udp/udp_client.go vendored Normal file
View File

@ -0,0 +1,79 @@
package udp
import (
"log/slog"
"net"
)
type UdpClient interface {
SendMsg(msg UdpMessageEncoder)
Send(b []byte)
}
type client struct {
laddr *net.UDPAddr
raddr *net.UDPAddr
conn *net.UDPConn
}
// 新建UDP客户端
// remoteAddr - 远端地址, 如 127.0.0.1:7777
func NewClient(remoteAddr string) UdpClient {
addr, err := net.ResolveUDPAddr("udp", remoteAddr)
if err != nil {
panic(err)
}
var laddr *net.UDPAddr = nil
conn, err := net.DialUDP("udp", laddr, addr)
if err != nil {
panic(err)
}
c := &client{
laddr: laddr,
raddr: addr,
conn: conn,
}
return c
}
// 新建UDP客户端
// remoteAddr - 远端地址, 如 127.0.0.1:7777
// localAddr - 本地地址, 如 :9999
func NewClientWithLocalAddr(remoteAddr string, localAddr string) UdpClient {
addr, err := net.ResolveUDPAddr("udp", remoteAddr)
if err != nil {
panic(err)
}
laddr, err := net.ResolveUDPAddr("udp", localAddr)
if err != nil {
slog.Info("UDP客户端使用随机端口")
laddr = nil
}
conn, err := net.DialUDP("udp", laddr, addr)
if err != nil {
panic(err)
}
c := &client{
laddr: laddr,
raddr: addr,
conn: conn,
}
return c
}
func (c *client) SendMsg(msg UdpMessageEncoder) {
b := msg.Encode()
_, err := c.conn.Write(b)
if err != nil {
slog.Error("udp client send error", "error", err)
}
// slog.Debug("udp client send", "size", n)
}
func (c *client) Send(b []byte) {
_, err := c.conn.Write(b)
if err != nil {
slog.Error("udp client send error", "error", err)
}
// slog.Debug("udp client send", "size", n)
}

14
third_party/udp/udp_message.go vendored Normal file
View File

@ -0,0 +1,14 @@
package udp
type UdpMessageCodec interface {
UdpMessageEncoder
UdpMessageDecoder
}
type UdpMessageEncoder interface {
Encode() []byte
}
type UdpMessageDecoder interface {
Decode(data []byte) error
}

64
third_party/udp/udp_server.go vendored Normal file
View File

@ -0,0 +1,64 @@
package udp
import (
"log/slog"
"net"
"runtime/debug"
)
type UdpServer interface {
Listen()
}
type UdpMsgHandler func(b []byte)
type server struct {
addr string
conn *net.UDPConn
handler UdpMsgHandler
}
// NewServer creates a new instance of UdpServer.
func NewServer(addr string, handler UdpMsgHandler) UdpServer {
return &server{addr: addr, handler: handler}
}
func (s *server) Listen() {
udpAddr, err := net.ResolveUDPAddr("udp", s.addr)
if err != nil {
panic(err)
}
conn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
panic(err)
}
s.conn = conn
// 启动监听处理
go s.listenAndHandle()
}
func (s *server) listenAndHandle() {
defer s.conn.Close()
for {
b := make([]byte, 1024)
n, err := s.conn.Read(b)
if err != nil {
slog.Error("udp server read error", err)
return
}
if n > 0 {
go s.handle(b[0:n])
}
}
}
func (s *server) handle(b []byte) {
defer func() {
if err := recover(); err != nil {
slog.Error("udp server handle error", "error", err, "stack", string(debug.Stack()))
debug.PrintStack()
}
}()
// slog.Info("udp server handle", "msg", string(b))
s.handler(b)
}

38
third_party/udp/udp_server_test.go vendored Normal file
View File

@ -0,0 +1,38 @@
package udp_test
import (
"log/slog"
"testing"
"joylink.club/bj-rtsts-server/third_party/udp"
)
type TestMsg struct {
Msg string
Port int
}
func (t *TestMsg) Encode() []byte {
b := []byte(t.Msg)
// binary.BigEndian.PutUint16(b, uint16(t.Port))
return b
}
func (t *TestMsg) Decode(data []byte) error {
t.Msg = string(data)
// t.Port = int(binary.BigEndian.Uint16(data))
return nil
}
func handleUdpMsg(b []byte) {
slog.Info("udp server handle", "msg", string(b))
}
func TestUdpServer(t *testing.T) {
udp.NewServer("127.0.0.1:7777", handleUdpMsg).Listen()
client := udp.NewClient("127.0.0.1:7777")
client.SendMsg(&TestMsg{
Msg: "test, port = 7777",
})
}