Jump to content

iOS DCC app


chadbag

Recommended Posts

I've had a goal to write an iOS DCC app and decided to start on it this weekend.  Eventually it will be multi-loco throttle, programmer (generic DCC and as specific as I can get for each command station), loco library, and eventually way in the distant future automated train control.   Should run on iPhone, iPad, and macOS (through the Catalyst feature -- in fact, while I have an iPhone hooked up. I've actually been using the Mac app version through Catalyst to debug instead of the iPhone)

 

I hope to support Z21 and Loconet as a minimum.

 

I have a Digikeijs DR5000-ADJ command station, which supports both Z21 and Loconet.  I am going down the Z21 path first.   I started a test app to flesh out communication with the command station and have been able to send simple commands (get version, get status, get serial number) and have the command station reply and be able to get the reply.   That is all that it does now but I hope to get this bit all worked out at the low network level in my test app and then start the actual App itself.  The first goal is to have a simple full fledged throttle, with Loco library, etc. and then expand it to multi-throttle (ie, you can have multiple throttles running at once -- either paged on an iPhone or panes on an iPad or Mac).   But first I need to work out moer of the low level networking.  I have a way of defining a command (using the X21 protocol docs) and am working out translating the results back into some sort of structured format (right now I am just printing the byte string in hex format to my debug console).

 

 

  • Like 6
  • Thanks 2
Link to comment

I got more work done on defining the return values from X-Bus calls over Z21 network so that the return values are useful 🙂   Also got a few more X-Bus commands defined.   

 

I am using my test app as a test harness to exercise the low level networking etc.  I had hoped to finish enough to be able to turn track power off and on and tell a train to move (throttle) using the test harness but am still working on the return value stuff.  Today I need to work on the day job to catch up as our 2-week "sprint" period ends tomorrow and I have one story left, so I won't get anything done today.

 

  • Like 1
Link to comment
Martijn Meerts

I started on something similar a long time ago, although for MacOS. I had the connection to the ECoS working fine, but had some issues with the Lenz Digital Plus interface. It would randomly send commands twice and chop commands up into multiple bytestreams.. It was really annoying. 

 

Of course, once I finally got the hang of Objective-C, Apple decided to announce Swift. Sure, Objective-C still worked, but all the new stuff would all be optimised for Swift, so I kinda gave up. I had started on drawing a switchboard as well, that was quite challenging performance wise 🙂

 

  • Like 1
Link to comment

The Objective-C part would not have been a problem on my side 🙂  Been doing Objective-C since 1996.   But I am using Swift for everything in this project.  As you implied, it is the future.  The nice thing with this Catalyst business is that I can get a macOS app "for free" from the efforts.  We'll see how that works, and obviously the UI will need to be optimized for each of iPhone, iPad, and Mac.

 

Right now I only have the DR5000 so am using the Z21 mode it provides for X-Bus.  When we get closer to actual release I'll get a real Z21, and some other command stations to test against.  Also, after I add in WiThrottle/Loconet support I'll have to get a Digitrax command station.  I do have an LNWI interface already.

 

I plan on this being a commercial product, but forum members who actively help with testing, and debug, etc. will gladly get a full-functionality coupon for the app.  There will be a free version that will allow basic throttle use etc. in any case.

 

  • Like 2
Link to comment
Martijn Meerts

Yeah, I was planning on making a computer control program for non-computer people really. I wanted it to be user friendly, and also have various features to make it possible for kids to operate trains at shows. For example, if they or their father had a smartphone, you could assign a specific train to that phone, and set some limitations (max speed mainly). They'd then also see the signals on the smartphone screen, so while they'd be able to drive trains, they would have to keep signals in mind. And of course the program would take over if they ran a red light etc.

 

I decided I don't have time for all that though, so I'll stick to the model train database for now (which might be possible to integrate in a control software, so model settings and images could be picked up from the database)

 

  • Like 3
Link to comment

Actually the Kiosk mode is an interesting idea.  Once we get past the throttle and programming but into the train control well have to see about slave clients in a Kiosk mode.  

Link to comment

So yesterday evening and  today I worked on this some more.  I re-worked my data structures to represent XBUS commands and Replies and also Z21 raw commands.

 

I think I mentioned above, that for now I am focussing on the XBUS protocol running on Z21 data packets.  There are a fews commands at the Z21 layer (get CC serial number and "logoff" the CC are the ones I've seen so far)  and but most are XBUS commands in the data section of the Z21 data packet.  

 

I have not yet defined all the possible XBUS protocol commands (requests) and replies/responses, but I have gotten several done.  I wanted to get a train running so I skipped ahead in the list of commands in the protocol and defined the LAN_X_SET_LOCODRIVE command which is how you set things like throttle etc.  I wired up a slider and some buttons and they all work.  I was able to drive my EF66 around my temporary layout loop.  The only thing not working yet on the test harness as seen below is the "Track Power" button.  Which should turn off/on the track power.  I've defined the XBUS protocol commands but have not yet finished the system state flag response processing so I can't yet determine what the current track power state is and I want it to actually reflect the current state before I go turning it off and on.  

 

I also don't process the loco state info stuff I get back so I am not updating the UI to reflect reality  if someone else changes the locomotive state, nor am I initializing the UI to the state of the locomotive. I assume a forwards direction at speed 0 and then react to the inputs. 

 

The change direction and emergency stop buttons both work (emergency stop uses the emergency stop "speed" which ignores any of the realistic decelerations you may have programmed in the decoder).

 

Z21TestHarness-initial-shot.thumb.png.6b3f36c73bc57a7b7ad4017d5251dacf.png

  • Like 5
Link to comment
On 9/7/2020 at 3:04 PM, Martijn Meerts said:

I started on something similar a long time ago, although for MacOS. I had the connection to the ECoS working fine, but had some issues with the Lenz Digital Plus interface. It would randomly send commands twice and chop commands up into multiple bytestreams.. It was really annoying. 

 

 

I actually, when I first tested the throttle slider tonight, had a crash because a UDP "message" was received that was 27 bytes long and had a 21 byte long Z21 packet and then the start of another 21 byte long Z21 packet.  So now I just throw away stuff where the length field says it should be X long and in reality it is less than X in the buffer.  And I also throw away stuff I don't recognize so if for some reason a half a packet comes by itself, and it is the back half, I won't recognize it and just throw it away.

 

Link to comment
Martijn Meerts

Throwing data away isn't the best idea though. In case of the Lenz system, it could cut a single command in multiple chunks, and you have to combine those chunks on the application end. You basically need a constant input stream, look for the init bytes (which also contains the package length), and then start buffering that command until you've parse all the bytes and arrive at the end of the package.

 

It's rather critical for things like occupancy detection, since you only get the command once. For just a throttle app it doesn't matter much really, but for automated control you really want all the data 🙂

 

  • Like 1
Link to comment
6 hours ago, Martijn Meerts said:

Throwing data away isn't the best idea though. In case of the Lenz system, it could cut a single command in multiple chunks, and you have to combine those chunks on the application end. You basically need a constant input stream, look for the init bytes (which also contains the package length), and then start buffering that command until you've parse all the bytes and arrive at the end of the package.

 

It's rather critical for things like occupancy detection, since you only get the command once. For just a throttle app it doesn't matter much really, but for automated control you really want all the data 🙂

 

 

yeah, I will worry about it some day.   Swift and its Network framework allow you to define your own protocol it lays over the network which may "solve" this problem.  I need to read up on how that part works.   The Z21 frame format is supposed to be constrained to a single UDP packet so you should not get things split (but obviously bugs exist or mistakes are made or the network messes with things that you need to account or).   I've put logging in to see how often I am seeing this sort of thing.

 

These guys are using UDP so they should design their protocols to be more robust since UDP does not guarantee delivery of packets.  (Famous last words -- at the day job we have a bug with the setup of a video or audio stream that is losing packets on a certain VPN network in certain circumstances)

 

 

Link to comment

This weekend I got the track power on and off working (though I see something in my logging I need to look into).  I also got the "loco info" response parsed and a handler in to allow it to be acted upon (but I did not tie anything in the test harness UI to it yet).  This is the response when you change the speed, or a myriad of other things about the locomotive and it returns speed, direction, F-keys activated, etc.

 

I did not get as much done as I had hoped as I was busy furzing around with a KATO DE10 and a TCS decoder, without success.

  • Like 1
Link to comment
Martijn Meerts

Once you get to the point where you want to try different digital interfaces, I'd be happy to test / help.. I have several digital stations with various protocols and ports.

 

ESU ECoS colour - uses XML over a TCP connection I believe

Lenz Digital Plus -  byte stream over serial port

Marklin Digital - probably also byte stream over serial port

Selectrix (Rautenhaus) - again, probably also byte stream over serial port

 

I played around with the ECoS and the Lens system when I was working on my own software using Objective C, both system have some weirdness really 🙂

 

Link to comment

All the systems have weirdness -- that is the conclusion of my research over the last 3 weeks.

 

I'll eventually call for testers.  I am trying to make sure the abstraction is good enough to plug in concrete low level stuff for each different one.  The XML one will be the easiest :).   I am only doing ones that support WiFi or ethernet (maybe through 3rd party add one like NCE) since that is the target market -- iPhone and iPad.  The Mac support is "free" with Catalyst.

 

Z21/WLANmaus is UDP frames with a byte stream or more per frame.  Others seem to use TCP.

Link to comment
Martijn Meerts

Looks like with most systems the computer interface was just an afterthought really 🙂

 

Well, maybe not the ECoS, since the XML is really quite nice. I'm guessing the Marklin Central Station will also be XML, considering ESU made the first one for them.

 

Link to comment
4 hours ago, Martijn Meerts said:

Looks like with most systems the computer interface was just an afterthought really


this was my experience with a lot of av and automation gear (go figure). I would bang my head on the wall not getting clear communication or all the data parsing properly, or dropped connections and think I was a total looser until I would finally break down and call the company and work my way to talking to an engineer and they would after a few minutes of seeing how bloody I was start to admit that it was the piece of equipment being flaky not me... usually the communications stuff was the last bit added as getting the playback output and features working beautifully was their main pressure from marketing and 98% of the time the control communication interface was only used by their canned control software so it was engineered and debugged just well enough for their software to work (and it turned out with a lot of undocumented work arounds not with the documented protocols many times) and as soon as out of the door none of the communications stuff still left partially undone was finalized, debugged and fully tested, as they were pushed onto the next project... So I learned the communications “feature” was never meant, designed, or built for anyone else to use really and the nice published documents with all the things you could do were usually a pile of well that may work but thus you will need to do a totally different way not mentioned at all...

 

On a few machines there were three rounds of models recycling regurgitated messes like this until they had to stop and redo it all as it had gotten into such a tangled mess even for their software.

 

You would assume that the more stable and well known products would have less of this but it turned out with high end a/v gear it was the opposite. While the new half prototype units had spottier documentation there was usually more engineers trying to get the first version all functional and working and actually functioned as presented most of the time and if you found an issue they would actually listen and at times patch for you.

 

use to make my head hurt.

 

jeff

  • Like 1
Link to comment

I did get a little done this past weekend.  Added a field to the test harness to be able enter the loco address directly (instead of compiled in like earlier) and fixed a couple dumb things and then converted some of the UI to be RxCocoa driven.   I am working on improving RxSwift knowledge and skill as we are adapting it at the day job, and we want to use RxCocoa as well so I had to catch up on my personal work goals due to end of quarter.  So I spent most of my weekend working through some training but tried applying it in the train app as the actual real app will be written using RxSwift and family.

 

I also cleaned up my desk and around the train area, and put a lot of train stuff away instead of having it on my desk.  Also "found" my KATO ET425 EMU of DB and used that as a test subject while testing the app.

 

Edited by chadbag
Link to comment

I haven't worked on this for a long while dueto the house project (which is currently in a holding pattern waiting for the bank to reauthorize or extend the loan as we didn't finish in time due to many reasons, including market conditions, labor not showing up and so having to do it much slower myself, etc).

 

Anyway, I found this "external volume control" knob on amazon for like $25 or something.  I thought that would be interesting to see if I can interface it into my app as a throttle button or any other sort of button (set values etc).  I actually found a whole raft of them and bought two -- this one and another that had some other buttons on it as well.  The second one has not arrived yet.

 

I plugged it into my iPad and it does control the Music app without needing any driver or special app or setup.  Unfortunately on my iPhone it doesn't, when plugged in with a Lightning cable.  I have not tried it on the Mac yet but it is advertised as for PC/Mac so I assume that works.

 

I have not yet tried to access it programmatically on the iPad yet but will soon, just as  test.  I should be able to get values from it in any case, I think, through the audio or music player subsystem.  We'll see.

 

IMG_5806.thumb.jpeg.f9013d4a6f7ee8f60b2e17f52407546d.jpeg

  • Like 2
Link to comment

I got the other USB volume knob.  It functions basically the same.  The case is plastic instead of metal but the knob is metal.  It is smaller and has buttons.   Its knob also pushes but not sure what it does as it has buttons as well.  Probably mutes.  Pic below.

 

I have not found a way to directly deal with the device but did write some code tonight to capture the volume changes, convert them to generic down and up commands so that the consumer of the knob movement in the app can interpret the movement instead of the values.  I also wrote it so you can turn it infintely up and down instead of it "stopping" in value when the volume reaches 100% or 0%.  (I basically detect when it gets close to max or min and reset the volume at 50 percent and keep going).

 

Obviously you can't be using this knob to control something else if your app is making sound as it will be changing the actual device app volume.

 

IMG_5808.thumb.jpeg.fb630f82840ba09e069b8d121fe905ee.jpeg

  • Like 1
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...