You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(35) |
Nov
(5) |
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <Ai...@ec...> - 2004-01-02 15:15:37
|
I am creating project with Modbus in RS485 network. For this i am using Jmodbus class for java. Maybe, any work with modbus in RTU or ASCII mode. I am not understand how this mode work with Serial port. I am definating modbus(example RTU) and definating Searial port and open this. But i am not understand how organization send/receive date from modbus using Serial port. How i am understanding in TCP/IP this is socket, where organization date send/receive in Modbus language. Something need with Serial...? Ainars Bikshis EC Systems |
From: Wimberger D. <die...@td...> - 2001-12-31 14:24:44
|
Hi Kelvin, I did not receive any reply from you to my last post. I would like to = know how things will proceed. My modbus library is put to use in some projects over here now, and it = would be great to clear things up and have one source base. Probably you can contact me, I was also thinking of creating a project = on my own, focussing on=20 the TCP implementation only (ASCII does work, but requires javax.comm, = and RTU, well I did not=20 have the time to care about it). There is no need to "force" a merge, if = you feel uncomfortable with the shift in paradigms. Best regards, Dieter PS: Now that I missed wishing a merry christmas, I'll add a happy new = year to everybody on the edge of the old one. |
From: Wimberger D. <die...@td...> - 2001-11-06 11:20:21
|
Hi Kelvin, Well the code I send you was just an example. I know it does byte by byte, but to tune all of this should not be such an issue, as the two ends of the pipe are decoupled. I do not know if this approach works for RTU, but I understood that this is the way data should be read from a CommPort under javax.comm. Together with the design I had, this was actually the thing that came to my mind first. I have tested it under 115200, so far, but I will extend the test series, and see how it behaves. I do think that there is one piece of information missing to clarify what we are discussing. Basically I understood from the specification that in a serial network there is only one master, and that there is always a Request-Response Cycle. A broadcast is the only exception to this, but I am not exactly sure if a broadcast=20 could stipulate all slaves to answer. The processing speed is not as much of an issue, whatever the UART can grasp should not get lost, thus you should be able to pick it up, or not? In the light of above paragraph, a master would never listen if it did not send a request. The characters on the buffer or in the stream could easily be discarded to this point. The event handler could just skip bytes when it is set not to await anything. Regarding the LRC, well I have to check the VM Specs to verify the behaviour you describe for arithmetics :) I am not the low level freak, so I just came up with this because I did work on it before you committed your code. I see into some test matter, I have just read an article on how to profile under Platform 2 (formerly I messed around with the system's millis). As you said, if we find nothing better to do :) I for myself have to quest some of my other work, and I guess you will be=20 challenged with the RTU. The ObjectPool was just an idea to address the dynamic memory allocation issue you have mentioned. The way this is normally set up, an Interface is created and classes that are used to create instances to be recycled=20 are tagged with it. Candidates for the start are for sure the message classes, however, I have to see more into the matter to decide whether there are more that are worth to be recycled or not. In some cases it might just be an allocation ahead of use, not so much a recycling process..... Regarding the ThreadPool, well I think that the pros outweight the cons, as it efficiently allows a client to close and reopen connections in rapid sequence (as indicated in the specs, which also suggests a maximum of 1 second to leave a connection open at the client) and it prevents a denial of service attack (which might happen unintended). I think that TINI has just 8 of threads available, and I'd say it is much better to be in control of let's say three of those and observe them closely, or not? Regards, Dieter |
From: Proctor, K. <Kel...@al...> - 2001-11-06 08:40:55
|
> Well I have a design that works out with the javax.comm API ;) > The idea I had was to use a Pipe for "pumping" the incoming data through > on > the respective registered event: > > public void serialEvent(SerialPortEvent e) { > // Determine type of event. > switch (e.getEventType()) { > //pump data through the pipe > case SerialPortEvent.DATA_AVAILABLE: > try { > while (m_SerialIn.available()>0) { > try { > int b=m_SerialIn.read(); > //DEBUG: m_Pipe.write(m_SerialIn.read()); > m_Pipe.write(b); > //DEBUG: System.out.println("Piped byte "+b+"="+(char)b); > [Proctor, Kelvin] The section above would be better if you had an array as large as the largest message and used block reads and writes (only partially filling the array usually) here instead of doing everything a single byte at a time. > } catch (IOException ex) { > System.err.println(ex); > return; > } > } > } catch (Exception ex) { > //handle > > } > break; > > } > }//serialEvent > > Just to get the idea.... > [Proctor, Kelvin] I like the idea above. Have you tested that this actually works and can recognise frames that only have a 4ms break between them? (4ms for 9600 bps) I had a few ways that *should* have worked with the javax.comm API but I am having difficulty in getting them to detect the frame break, even on a PII, let alone a TINI where the processing speed will be much slower. You would also want to be careful when you react to serial port events, particularly on the master. A master should never react to unsolicited packets in any way. > I have also provided the infrastructure like for TCP, i.e. there is now > a ModbusSerialListener, and a SerialConnection, and a > ModbusSerialTransaction. > > > > I have also done a LRC, it would be good to have some results to test > > against..it is much simpler then the version you created, and it gives > > the same results but anyway, maybe there is some official way to test > > this. > > > > [Proctor, Kelvin] > > I'll be fascinated to see this, the version I came up with was > >pretty small already. With a function like this (and more importantly > for > >the CRC for RTU) getting a fast implementation is the most important > issue, > >even at he expense of 10 vs 5 lines of code. I have not had a serious > think > >out run time of my algorithm yet, I just hacked up something that > worked. > > I made a trial and error approach, and I realized that Java naturally > does the job: > > private final int getLRC(byte[] data,int tailskip) { > byte lrc=0; > for (int i = 0; i < data.length-tailskip; i++) { > lrc+=data[i]; > } > return (int)-lrc; > }//getLRC > > The tailskip is just to skip the LRC byte that is part of the byte[] > data (because that one represents the complete > frame without FRAME_START and FRAME_END). > > You see it is a one line algorithm, however, there is one thing I am not > exactly sure about and that is the > minus in the return. This way the result is exactly the same as coming > from your algorithm. > [Proctor, Kelvin] I would be interested to test the speed of the two implementations. While I agree yours looks nicer there is a problem in the way the JVM does maths. All byte and short values are converted to int values before any maths is done and then converted back to there original data types. While the difference will be very minimal if any at all it would be interesting to do a test to see how much difference there is. (Maybe I'll do that one day when I have nothing better to do :) > > >> [Wimberger, Dieter] > >> Another point I did not have the time to figure out are the > >> specifications for the serial communication. As each cycle is a > >> Transaction (Request by Master, Response by addressed Client) there > must > >> be some mechanism that repeats frames if there is no answer from any > >> client (timeout??) or to notify the master that a frame is corrupt > etc. > >> Any clue about this so far? > >> > > > [Proctor, Kelvin] > > You are correct here. The spec is a little vague about how all > of > >this should be handled. My original code does not handle any of this > at all > >really, only working out if a packet was sent correctly or not and > returning > >true or false. The method you have used in creating a Connection class > is a > >good solution to this. You can set it up to know how many times to > retry, > >set the timeouts etc.. and it can reference the transport. It adds > another > >layer but I think it is justified. > > Well this is a bit what I did, as I already mentioned above. It looks > pretty much the same as for TCP now, it > is just that a few of those mechanisms are not hooked up yet (i.e. the > exception handling etc.). > However, there must be a schema for reactions, as this is supposed to be > an industrial field bus. I will plunge into a research session, when I > find some time. We have resources here probably, as some guys are > teaching data transmission and industrial field bus lectures :) > > > > > [Proctor, Kelvin] > > This was always likely to be that hardest part of the design. > My > >design was written with the TINI in mind and written to be able to act > as a > >master or a slave. You code was written with the master only in mind > and > >designed to be run from a PC or similar. These two setups have very > >different requirements. > > Hmm yes. Well one thing is that it runs on TINI, and I am testing this, > however, to be optimized to > run there and to run there are two different things. I'll say with a bit > of work we get results that will > be fine for us. > > > Until we work out where we want to go with this I'll keep > plugging > >away with my transport code under my old architecture (as it's more > basic > >and hence a little simpler to integrate into). I'll have another go at > the > >serial stuff tonight and see where it gets me. > > Well that I agree, still it is nice to see that most of the > infrastructure as I put it up seems to work out > also for the serial transport flavors :) > I will try to put up the package as soon as possible, so that you can > take a look at things, and judge > were you want to go. I guess with the RTU it is going to be another > challenge, because I wonder how to > measure 3.5 character times etc. Without a Mechanism to ensure that a > message was received or not, > there is not much chance to get this going nicely from Java (with this > high level view of the system...) > [Proctor, Kelvin] Yes, this is a tricky one. I'm playing with some test code in a very basic app and I'm having trouble getting it to detect really sort breaks (like 4ms breaks) and I think it is time to get the digital scope out to see how long some of these breaks really are. I have the serial cable running through a break out box and I have a decent digital scope with 1 shot triggering so I'll probably use that to have a look at things soon. > > I'm interested in what you would intend to use the ObjectPool > for? > >I have usually seen this term used in the context of web servers where > a set > >of threads is created and then reset after a connection assigned to > them > >dies, as opposed to creating a new thread each time. If this is the > case > >I'm note sure it would really help this all that much. In my > experience of > >control type application this is not as much of a problem. In the case > of a > >web server you will have a lot of very short sessions open and closed > all > >the time, each dealing with only a single request. In the case of > ModbusTCP > >this is unlikely as most application will open a single connect and > keep it > >open send possibly millions of requests across a single connection. > > > If I have your definition of an ObjectPool wrong let me know. > > What you are describing is a so called thread pool. I have implemented > this for the TCPSlave, as it is perfectly > suited for multithreaded handling of Request-Response problems :) > Runs also nicely on Tini..... > An ObjectPool is to recycle instances at runtime. This would prevent the > code from constantly creating new instances and garbage collecting > unreferenced old ones. This is not the best practice for all cases, as > the trade off on present up to date computers with an up-to date JVM is > low compared to the additional cost on creating and garbage collecting. > At least this is what "Effective Java" author Joshua Bloch believes. > However, we are dealing with an embedded system, and probably the trade > off balance is better for the pool implementation. > This would clutter the code a little bit more, and needs care when > Recycling (to assert that the object is like newly created), > but maybe it is worth a try..... > [Proctor, Kelvin] I'm note sure which objects you wish to recycle. If this is for all the command objets etc... then this sounds like a good idea. I'm just note sure which objects you wish to add to the pool. As for the thread pool for the TCPSlave I'm still unsure of how useful this really is given the nature of the type of systems that are likely to be talking to this, as per my comparison with the web server examples from my last post. I'm not yet convinced that the benefit in run time justifies they increase in complexity given the relative infrequency with which new connections are likely to be created. In the case of a SCADA link to a TINI sitting in the field the connection might stay open for months. With a setup like this with only 1 new connection every 3 months (approx for example) it hardly justifies all the code and effort to create a thread pool. This is a *very* different scenario from a web server...... > Best regards, > Dieter > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Wimberger D. <die...@td...> - 2001-11-05 15:54:22
|
Hi Kelvin, > [Proctor, Kelvin] =20 > This is becoming vitally important for the RTU transport, there is >no way it could work without looking for whole frames. I was working on >that over the weekend and I'm having real trouble coming up with system for >doing this under the javax.comm API. Most implementations that are floating >around on the net (under any language) are Master devices and simply write a >frame, pause and then read until there is no more to read. This works fine >for the master only cause but I would like something that conforms to the >spec a little better and is more suitable for use in either a master or a >slave. The implementations that really do stick to the spec (such as PLC's) >have access to the UART in more primitive and powerful way usually. I'll >find some way to solve this but it might take some more work yet. Well I have a design that works out with the javax.comm API ;) The idea I had was to use a Pipe for "pumping" the incoming data through on the respective registered event: public void serialEvent(SerialPortEvent e) { // Determine type of event. switch (e.getEventType()) { //pump data through the pipe case SerialPortEvent.DATA_AVAILABLE: try { while (m_SerialIn.available()>0) { try { int b=3Dm_SerialIn.read(); //DEBUG: m_Pipe.write(m_SerialIn.read()); m_Pipe.write(b); //DEBUG: System.out.println("Piped byte "+b+"=3D"+(char)b); } catch (IOException ex) { System.err.println(ex); return; } } } catch (Exception ex) { //handle } break; } }//serialEvent Just to get the idea.... I have also provided the infrastructure like for TCP, i.e. there is now a ModbusSerialListener, and a SerialConnection, and a ModbusSerialTransaction. =20 =20 > I have also done a LRC, it would be good to have some results to test > against..it is much simpler then the version you created, and it gives > the same results but anyway, maybe there is some official way to test > this. >=20 > [Proctor, Kelvin] =20 > I'll be fascinated to see this, the version I came up with was >pretty small already. With a function like this (and more importantly for >the CRC for RTU) getting a fast implementation is the most important issue, >even at he expense of 10 vs 5 lines of code. I have not had a serious think >out run time of my algorithm yet, I just hacked up something that worked. I made a trial and error approach, and I realized that Java naturally does the job: private final int getLRC(byte[] data,int tailskip) { byte lrc=3D0; for (int i =3D 0; i < data.length-tailskip; i++) { lrc+=3Ddata[i]; } return (int)-lrc; }//getLRC The tailskip is just to skip the LRC byte that is part of the byte[] data (because that one represents the complete frame without FRAME_START and FRAME_END). You see it is a one line algorithm, however, there is one thing I am not exactly sure about and that is the=20 minus in the return. This way the result is exactly the same as coming from your algorithm. =20 >> [Wimberger, Dieter] >> Another point I did not have the time to figure out are the >> specifications for the serial communication. As each cycle is a >> Transaction (Request by Master, Response by addressed Client) there must >> be some mechanism that repeats frames if there is no answer from any >> client (timeout??) or to notify the master that a frame is corrupt etc.=20 >> Any clue about this so far? >>=20 > [Proctor, Kelvin] =20 > You are correct here. The spec is a little vague about how all of >this should be handled. My original code does not handle any of this at all >really, only working out if a packet was sent correctly or not and returning >true or false. The method you have used in creating a Connection class is a >good solution to this. You can set it up to know how many times to retry, >set the timeouts etc.. and it can reference the transport. It adds another >layer but I think it is justified. Well this is a bit what I did, as I already mentioned above. It looks pretty much the same as for TCP now, it is just that a few of those mechanisms are not hooked up yet (i.e. the exception handling etc.). However, there must be a schema for reactions, as this is supposed to be an industrial field bus. I will plunge into a research session, when I find some time. We have resources here probably, as some guys are teaching data transmission and industrial field bus lectures :) >=20 > [Proctor, Kelvin] =20 > This was always likely to be that hardest part of the design. My >design was written with the TINI in mind and written to be able to act as a >master or a slave. You code was written with the master only in mind and >designed to be run from a PC or similar. These two setups have very >different requirements. Hmm yes. Well one thing is that it runs on TINI, and I am testing this, however, to be optimized to run there and to run there are two different things. I'll say with a bit of work we get results that will be fine for us. > Until we work out where we want to go with this I'll keep plugging >away with my transport code under my old architecture (as it's more basic >and hence a little simpler to integrate into). I'll have another go at the >serial stuff tonight and see where it gets me.=20 Well that I agree, still it is nice to see that most of the infrastructure as I put it up seems to work out also for the serial transport flavors :) I will try to put up the package as soon as possible, so that you can take a look at things, and judge were you want to go. I guess with the RTU it is going to be another challenge, because I wonder how to=20 measure 3.5 character times etc. Without a Mechanism to ensure that a message was received or not, there is not much chance to get this going nicely from Java (with this high level view of the system...) > I'm interested in what you would intend to use the ObjectPool for? >I have usually seen this term used in the context of web servers where a set >of threads is created and then reset after a connection assigned to them >dies, as opposed to creating a new thread each time. If this is the case >I'm note sure it would really help this all that much. In my experience of >control type application this is not as much of a problem. In the case of a >web server you will have a lot of very short sessions open and closed all >the time, each dealing with only a single request. In the case of ModbusTCP >this is unlikely as most application will open a single connect and keep it >open send possibly millions of requests across a single connection. > If I have your definition of an ObjectPool wrong let me know. What you are describing is a so called thread pool. I have implemented this for the TCPSlave, as it is perfectly suited for multithreaded handling of Request-Response problems :) Runs also nicely on Tini..... An ObjectPool is to recycle instances at runtime. This would prevent the code from constantly creating new instances and garbage collecting unreferenced old ones. This is not the best practice for all cases, as the trade off on present up to date computers with an up-to date JVM is low compared to the additional cost on creating and garbage collecting. At least this is what "Effective Java" author Joshua Bloch believes. However, we are dealing with an embedded system, and probably the trade off balance is better for the pool implementation. This would clutter the code a little bit more, and needs care when Recycling (to assert that the object is like newly created), but maybe it is worth a try..... Best regards, Dieter =20 |
From: Proctor, K. <Kel...@al...> - 2001-11-05 05:40:47
|
> -----Original Message----- > From: Wimberger Dieter [SMTP:die...@td...] > Sent: Sunday, November 04, 2001 3:03 > To: jmo...@li... > Subject: [jModbus-devel] Proceeding > > Hi Kelvin, > > Sorry for submerging the last days, but things have been going up and > down a little bit. > Allthough it was pretty busy I have manged to come up with a Modbus > ASCII Implementation that fits with > my oo design. > However, I think you were right that it is much better to receive a > complete frame, so I am > now doing that and wrapping the frame into a ByteArrayInputStream for > reading with the Message classes. > [Proctor, Kelvin] This is becoming vitally important for the RTU transport, there is no way it could work without looking for whole frames. I was working on that over the weekend and I'm having real trouble coming up with system for doing this under the javax.comm API. Most implementations that are floating around on the net (under any language) are Master devices and simply write a frame, pause and then read until there is no more to read. This works fine for the master only cause but I would like something that conforms to the spec a little better and is more suitable for use in either a master or a slave. The implementations that really do stick to the spec (such as PLC's) have access to the UART in more primitive and powerful way usually. I'll find some way to solve this but it might take some more work yet. > I have also done a LRC, it would be good to have some results to test > against..it is much simpler then the version you created, and it gives > the same results but anyway, maybe there is some official way to test > this. > [Proctor, Kelvin] I'll be fascinated to see this, the version I came up with was pretty small already. With a function like this (and more importantly for the CRC for RTU) getting a fast implementation is the most important issue, even at he expense of 10 vs 5 lines of code. I have not had a serious think out run time of my algorithm yet, I just hacked up something that worked. > Another point I did not have the time to figure out are the > specifications for the serial communication. As each cycle is a > Transaction (Request by Master, Response by addressed Client) there must > be some mechanism that repeats frames if there is no answer from any > client (timeout??) or to notify the master that a frame is corrupt etc. > Any clue about this so far? > [Proctor, Kelvin] You are correct here. The spec is a little vague about how all of this should be handled. My original code does not handle any of this at all really, only working out if a packet was sent correctly or not and returning true or false. The method you have used in creating a Connection class is a good solution to this. You can set it up to know how many times to retry, set the timeouts etc.. and it can reference the transport. It adds another layer but I think it is justified. > If you are still interested, I can make the package accessible to you > again (when I am done with clean ups). > I was also thinking about how we are going to proceed, because I am not > exactly sure if you feel confident with > my whole design. > I also think that for the TINI it is probably too heavy weight, it runs, > but I would not dare to let it do so without some optimizations. > Specifically I am thinking of an ObjectPool (which is not always the > best thing to do, but in this case it could be). > [Proctor, Kelvin] This was always likely to be that hardest part of the design. My design was written with the TINI in mind and written to be able to act as a master or a slave. You code was written with the master only in mind and designed to be run from a PC or similar. These two setups have very different requirements. Until we work out where we want to go with this I'll keep plugging away with my transport code under my old architecture (as it's more basic and hence a little simpler to integrate into). I'll have another go at the serial stuff tonight and see where it gets me. I'm interested in what you would intend to use the ObjectPool for? I have usually seen this term used in the context of web servers where a set of threads is created and then reset after a connection assigned to them dies, as opposed to creating a new thread each time. If this is the case I'm note sure it would really help this all that much. In my experience of control type application this is not as much of a problem. In the case of a web server you will have a lot of very short sessions open and closed all the time, each dealing with only a single request. In the case of ModbusTCP this is unlikely as most application will open a single connect and keep it open send possibly millions of requests across a single connection. If I have your definition of an ObjectPool wrong let me know. Cheers, Kelvin > Let me know what you think, > Dieter > > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Wimberger D. <die...@td...> - 2001-11-03 16:03:36
|
Hi Kelvin, Sorry for submerging the last days, but things have been going up and down a little bit. Allthough it was pretty busy I have manged to come up with a Modbus ASCII Implementation that fits with my oo design. However, I think you were right that it is much better to receive a complete frame, so I am now doing that and wrapping the frame into a ByteArrayInputStream for reading with the Message classes. I have also done a LRC, it would be good to have some results to test against..it is much simpler then the version you created, and it gives the same results but anyway, maybe there is some official way to test this. Another point I did not have the time to figure out are the specifications for the serial communication. As each cycle is a Transaction (Request by Master, Response by addressed Client) there must be some mechanism that repeats frames if there is no answer from any client (timeout??) or to notify the master that a frame is corrupt etc.=20 Any clue about this so far? If you are still interested, I can make the package accessible to you again (when I am done with clean ups). I was also thinking about how we are going to proceed, because I am not exactly sure if you feel confident with=20 my whole design. I also think that for the TINI it is probably too heavy weight, it runs, but I would not dare to let it do so without some optimizations. Specifically I am thinking of an ObjectPool (which is not always the best thing to do, but in this case it could be). Let me know what you think, Dieter |
From: Kelvin P. <k.p...@st...> - 2001-10-29 11:14:13
|
Dieter, I have now finalized the ASCII transport. This is now fully operation and I have stress tested it for a few hours running a serial of different speeds etc... I have checked the code in to the CVS server if you want to grab a copy. The receive code is pretty long but I think the way I have written it make it suitably robust for the try of environment we are going to be putting it into. Cheers, Kelvin -----Original Message----- From: jmo...@li... [mailto:jmo...@li...]On Behalf Of Kelvin Proctor Sent: Sunday, 28 October 2001 11:51 AM To: jmo...@li... Subject: RE: [jModbus-devel] ASCII transport update Dieter, Another update. I found that a few of my problems in testing is that the serial ports on my Linux box were not working. Thus I have but a proper null modem cable using a serial breakout box I had lying about. I have not committed my code again, I'll do that later tonight after cleaning it up again. I found a problem in that if you disable the receive timeout (block until you get data) that the pushback input stream will have problems when you try and read a block that consists of pushed back data and (possibly) new data. It will simply block forever. The lesson I have learnt out of all of this is that the reading system must use the receive timeout and be prepared for read events to return 0 bytes and continue then continue normal operation. This is different to the behavior you would usually set for a Socket where you will simply block until you get more data. I have to go out for the day but I'll be back this evening and I'll have a major cleanup of the code and I'll post it again. Cheers, Kelvin -----Original Message----- From: jmo...@li... [mailto:jmo...@li...]On Behalf Of Kelvin Proctor Sent: Sunday, 28 October 2001 1:31 AM To: jmo...@li... Subject: [jModbus-devel] ASCII transport update Dieter, I have completely rewritten the ModbusASCIITransport (old framework). It now uses pushback input streams to scan for the start and end of frame delimiters. I have committed it into the project CVS repository. It is a relatively large piece of code (about 600 lines) as I have attempted to make it as robust as possible. It make no assumptions unless absolutely required. It requires that the ':' character be within the first 527 characters and the end characters be within 527 characters of that. It will simply return false from the receiveFrame command if the above conditions fail. I have not had time to really acid test it but I have had it running with a simple Master/Slave echo style program between a Win NT box and a TINI. (Linux and serial ports did not want to work today, due to cabling problems I think.) It sent about 10 messages that were send, received, then sent and received again correctly before something dies so it is pretty close to working. I have also made sure that no byte-banning happens. As you will see from the code all stream operations are block transfers. This is good as a frame can be up to 527 characters in length. The LRC code is also working. Anyway it is now 2:30 in the morning (exaggerated due to daylight saving coming in 1/2 an hours ago in Sydney) and I'm going to get some sleep but I will have more of a play with it tomorrow and see if I can harden it some more. Cheers, Kelvin _______________________________________________ jModbus-devel mailing list jMo...@li... https://lists.sourceforge.net/lists/listinfo/jmodbus-devel _______________________________________________ jModbus-devel mailing list jMo...@li... https://lists.sourceforge.net/lists/listinfo/jmodbus-devel |
From: Kelvin P. <k.p...@st...> - 2001-10-28 00:47:52
|
Dieter, Another update. I found that a few of my problems in testing is that the serial ports on my Linux box were not working. Thus I have but a proper null modem cable using a serial breakout box I had lying about. I have not committed my code again, I'll do that later tonight after cleaning it up again. I found a problem in that if you disable the receive timeout (block until you get data) that the pushback input stream will have problems when you try and read a block that consists of pushed back data and (possibly) new data. It will simply block forever. The lesson I have learnt out of all of this is that the reading system must use the receive timeout and be prepared for read events to return 0 bytes and continue then continue normal operation. This is different to the behavior you would usually set for a Socket where you will simply block until you get more data. I have to go out for the day but I'll be back this evening and I'll have a major cleanup of the code and I'll post it again. Cheers, Kelvin -----Original Message----- From: jmo...@li... [mailto:jmo...@li...]On Behalf Of Kelvin Proctor Sent: Sunday, 28 October 2001 1:31 AM To: jmo...@li... Subject: [jModbus-devel] ASCII transport update Dieter, I have completely rewritten the ModbusASCIITransport (old framework). It now uses pushback input streams to scan for the start and end of frame delimiters. I have committed it into the project CVS repository. It is a relatively large piece of code (about 600 lines) as I have attempted to make it as robust as possible. It make no assumptions unless absolutely required. It requires that the ':' character be within the first 527 characters and the end characters be within 527 characters of that. It will simply return false from the receiveFrame command if the above conditions fail. I have not had time to really acid test it but I have had it running with a simple Master/Slave echo style program between a Win NT box and a TINI. (Linux and serial ports did not want to work today, due to cabling problems I think.) It sent about 10 messages that were send, received, then sent and received again correctly before something dies so it is pretty close to working. I have also made sure that no byte-banning happens. As you will see from the code all stream operations are block transfers. This is good as a frame can be up to 527 characters in length. The LRC code is also working. Anyway it is now 2:30 in the morning (exaggerated due to daylight saving coming in 1/2 an hours ago in Sydney) and I'm going to get some sleep but I will have more of a play with it tomorrow and see if I can harden it some more. Cheers, Kelvin _______________________________________________ jModbus-devel mailing list jMo...@li... https://lists.sourceforge.net/lists/listinfo/jmodbus-devel |
From: Kelvin P. <k.p...@st...> - 2001-10-27 15:27:43
|
Dieter, I have completely rewritten the ModbusASCIITransport (old framework). It now uses pushback input streams to scan for the start and end of frame delimiters. I have committed it into the project CVS repository. It is a relatively large piece of code (about 600 lines) as I have attempted to make it as robust as possible. It make no assumptions unless absolutely required. It requires that the ':' character be within the first 527 characters and the end characters be within 527 characters of that. It will simply return false from the receiveFrame command if the above conditions fail. I have not had time to really acid test it but I have had it running with a simple Master/Slave echo style program between a Win NT box and a TINI. (Linux and serial ports did not want to work today, due to cabling problems I think.) It sent about 10 messages that were send, received, then sent and received again correctly before something dies so it is pretty close to working. I have also made sure that no byte-banning happens. As you will see from the code all stream operations are block transfers. This is good as a frame can be up to 527 characters in length. The LRC code is also working. Anyway it is now 2:30 in the morning (exaggerated due to daylight saving coming in 1/2 an hours ago in Sydney) and I'm going to get some sleep but I will have more of a play with it tomorrow and see if I can harden it some more. Cheers, Kelvin |
From: Proctor, K. <Kel...@al...> - 2001-10-26 02:38:54
|
Dieter, I'm sorry I don't fully understand what you mean by 'pack up "all-in-one".' For creating a TCP<->serial Modbus gateway I think the sort of architecture where the transport objects deal in full frames would be best. This then allows a relatively simple class to be created for this. If we assume for the example (and it would be likely) that the master is on the TCP end then we have a class that just continually reads a frame from the TCP end, sends it out the serial end, reads a frame back in the serial end (with a timeout) and then sends that back along the TCP end and repeats. With the 'whole frames' architecture I'm in favour of this would be a very simple application to write really. (It's one of the reasons I like that architecture, but I still like being able to use streams up high as you did.) Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Friday, October 26, 2001 1:06 > To: jmo...@li... > Subject: [jModbus-devel] A question > > Kelvin, > > I have got an important question. I took a more in depth look into serial > communication matters, and I wonder if it makes sense to pack up > "all-in-one". > > A bridge between serial cabling and ethernet is one specific case where it > is necessary, but the question is if it is not possible to come up with > another construct that solves the same problem. Specifically if it isn't > much better to decouple such a construct due to cycling etc. and have the > serial and the ethernet side running in seperate processes. > > I just want to propose this question, because we had a lot of discussions > on issues that would have been more clear with only one specific flavor in > mind. > Also we are at the right decision point, as we just started looking more > in depth into serial communication. > As a matter of fact there might be not enough share in behaviour and > handling to keep a medium path that considers and satisfies design, > resource and behaviour issues. > > What do you think? > > Regards, > Dieter > > PS: I do not want to express that it is impossible, I just like cross > thinking and taking steps back and considering if what is done is really a > good thing to do. > > > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Proctor, K. <Kel...@al...> - 2001-10-26 02:27:22
|
Dieter, I have to disagree with a few points you have raised below. I have also remembered another problem that we would face with the RTU transport mode. Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Thursday, October 25, 2001 20:41 > To: jmo...@li... > Subject: [jModbus-devel] Issues discussion continued > > Hi Kelvin, > > First of all thanks regarding the exam, that worked out nicely. I do not > have much > left so it is not such an issue :) > > Now to our issues.... > > Regarding the : and CRLF characters (let's call those tokens FRAME_START > and FRAME_END), > it is very easy to pass them on. In Java a byte is -128 to +127 this is > the main reason > for the byte reading methods to return int (which is actually -2147483648 > to 2147483647). > According to my calculation I would say we have enough encoding space.... > ;) > [Proctor, Kelvin] I believe you have interpreted the way the java API is written incorrectly. I believe the reason the read() method returns an int and not a byte is for efficiency reasons. The JVM spec states that the minimum memory allocation is 4 bytes. Thus a byte is really stored as 4 bytes in the JVM. If you want to do any sort of arithmetic the byte must be converted to an int, the arithmetic takes place and is then converted back to a byte. All this is done within the JVM so we don't see it but it does make the process less efficient. This is why on a platform like the TINI is it recommended to use ints everywhere to save on conversion cycles. I am assuming that you would simply put a null implementation in the block read functions for the ASCIIInputStream (as they use byte arrays and the above method would not be an option). This raises the point that if we are not going to implement these function in a meaningful manner then should we really be extending FilterInputStream. The method you have suggested would force *all* the values to be bye-banged through the I/O stream. I may have made my definition of this unclear the other day. Looping through an array with a for loop etc... is fine, it's when you read information from streams 1 byte at a time that this becomes a problem. The method you have proposed would force us to always do this. For some good information on why byte-banging of streams is *really* bad I recommend having a look at the TINI book by Don Loomis (http://www.ibutton.com/TINI/tinispec.pdf) in section 11.2.1 on page 227. This shows an example where byte-banging can be so bad that TINI will only do about 100 bytes per second and the same program on a PIII Win2K machine only gets 1000 bytes per second. All of section 11.2 on efficient I/O is worth a read. I know I must sound like I'm harping on this point a bit but I would really like the library to still run on a TINI at acceptable speed if possible. I found in my own testing that even printing about 15 System.out.println() statements per packet in debug mode was enough that the TINI could not handle the rate at which Citect wanted to send requests. (Although Citect has a relatively fast sample rate by default). > The LRC Value could be easily extracted at the transport layer, and > checked too, > whether byte banging or not. I also do think that the byte banging is not > such an > issue in our case, it would be interesting to see whether the performance > and use > of resources differ by any means. > > Also note that the message does not perform any kind of computations > despite extracting > the values. It would throw an Exception if something is malformed and this > exception would > end in the transport. > In fact the message instance is nothing else then a Data Model for the > message, > and whether you discard that one or the byte[] is also more a > philosophical discussion :) > The checks would be still performed by the transport.... > [Proctor, Kelvin] I have also remembered a very important point about the RTU mode that is probably significant at this point. In RTU mode the frame separator is a mark of at least 3.5 character times. This is quite a difficult thing to capture properly under the javax.comm API. David MacMahon and I had a discussion on the TINI list some months back about a way to do this but it will rely heavily on using the timeout and receive thresholds and a few other good tricks. This means that (at least on one layer) that the whole frame must be read as a contiguous block The serial of messages that relate to this discussion are below (in order hopefully) http://lists.dalsemi.com/maillists/tini/2001-August/016297.html http://lists.dalsemi.com/maillists/tini/2001-August/016298.html http://lists.dalsemi.com/maillists/tini/2001-August/016303.html http://lists.dalsemi.com/maillists/tini/2001-August/016301.html http://lists.dalsemi.com/maillists/tini/2001-August/016309.html I still think I would probably be happier with a system that looked something like public class ModbusConnection { private ModbusTransport transport private ModbusMessage send_msg; private ModbusMessage receive_msg; private ByteArrayInputStream in; private ByteArrayOutputStream out; public ModbusConnection(ModbusTransport transport) { this.transport = transport; send_msg = new ModbusMessage(); receive_buff = new byte[Modbus.MAX_MESSAGE_SIZE]; receive_msg = new ModbusMessage(receive_buff, 0); in = new ByteArrayInputStream(receive_buff); out = new ByteArrayOutputStream(Modbus.MAX_MESSAGE_SIZE); } public InputStream getInputStream() { return in; } public OutputStream getOutputStream() { return out; } public int getTransactionID() { return receive_msg.getTransactionID(); } public void setTransactionID(int ID) { send_msg.setTransactionID(ID); } // Send the message I have just written down the output stream and // reset ready for the next message public boolen sendMessage() { boolen success; byte[] buffer = out.toByteArray(); send_msg.setBuffer(buffer, buffer.length) success = transport.sendFrame(send_msg); out.reset(); return success; } // Move onto the next receive message public boolean nextMessage() { boolen success; success = transport.receiveFrame(receive_msg); is.reset(); return success; } } public interface ModbusTransport { // Send a frame and report if it worked OK public boolean sendFrame(ModbusMessage msg); // Receive a frame and report if it worked OK public boolean receiveFrame(ModbusMessage msg); } public class ModbusMessage { private byte[] buff; private int length; priavte int transactionID ModbusMessage(byte[] buff, int length) { this.buff = buff; this.length = length; transactionID = 0; } ModbusMessage() { buff = new byte[Modbus.MAX_MESSAGE_SIZE]; int length = 0; transactionID = 0; } public byte[] getBuffer() { return buff; } public void setBuffer(byte[] buff, int length) { this.buff = buff; this.length = length; } // standard get/set for length // standard get/set for transactionID } Much of the code above would be called different names as not to collide with the class you have already created and in some places (such as the ModbusConnection class) it could be integrated into the classes you have created. The system I have proposed above gives you higher level code access to and input stream and an output steam to play with (within the confines of a single frame) so all the function code you have written will work (almost) directly. The above code allows all the transport classes to perform all I/O in terms of block transfer function wherever possible. As the transport can also see the whole frame it can do the checksum checking. The TCP transport would only need to perform 2 read operations per frame. (one to read the fixed header and a second to read the body). The ASCII transport could use a PushbackInputStream to try and read the maximum message size and than scan along till it found the delimeters and push back however many bytes it overread. (This is the type of purpose this class was designed for.) The RTU transport can set the timeout and receive thresholds to appropriate levels and a single read should read a whole frame in one hit. (This idea that David and I came up with is yet to be proven but I'll try it soon.). This is also extra important for sending RTU frames as the whole message *must* be written in a single block read operation so that there won't be any gaps between characters, as that would cause a end of frame mark. > I also agree with you that the way you call things make a change. I > introduced this concept > [Transaction] because I understood from the context of the specs for > ModbusTCP that there > are always sequences of request-response which are tightly coupled. As I > am also doing work with > databases and other data stores, I borrowed the vocabulary from there, as > I thought it > would be a common nomer :) > However, probably it is too much master(client)/ModbusTCP centric....I > don't know. > Would you suggest an alternative name? > [Proctor, Kelvin] I can appreciate that. The best way for a project to get stuffed up is if the requirements change half way. All the little, basic assumptions you made that influence your design suddenly become wrong. > I guess this sheds another light on the proposal you made too. > I will try to make up the Stream to show how it is meant, and probably I > manage to > prepare an interaction diagram to show what exactly happens when we are > reading a > message :) > This could maybe show the knots in our two approaches and indicate a way > to open those. > > Regards, > Dieter > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Dieter W. <wi...@oe...> - 2001-10-25 15:06:39
|
Kelvin, I have got an important question. I took a more in depth look into serial communication matters, and I wonder if it makes sense to pack up "all-in-one". A bridge between serial cabling and ethernet is one specific case where it is necessary, but the question is if it is not possible to come up with another construct that solves the same problem. Specifically if it isn't much better to decouple such a construct due to cycling etc. and have the serial and the ethernet side running in seperate processes. I just want to propose this question, because we had a lot of discussions on issues that would have been more clear with only one specific flavor in mind. Also we are at the right decision point, as we just started looking more in depth into serial communication. As a matter of fact there might be not enough share in behaviour and handling to keep a medium path that considers and satisfies design, resource and behaviour issues. What do you think? Regards, Dieter PS: I do not want to express that it is impossible, I just like cross thinking and taking steps back and considering if what is done is really a good thing to do. |
From: Dieter W. <wi...@oe...> - 2001-10-25 10:41:41
|
Hi Kelvin, First of all thanks regarding the exam, that worked out nicely. I do not have much left so it is not such an issue :) Now to our issues.... Regarding the : and CRLF characters (let's call those tokens FRAME_START and FRAME_END), it is very easy to pass them on. In Java a byte is -128 to +127 this is the main reason for the byte reading methods to return int (which is actually -2147483648 to 2147483647). According to my calculation I would say we have enough encoding space.... ;) The LRC Value could be easily extracted at the transport layer, and checked too, whether byte banging or not. I also do think that the byte banging is not such an issue in our case, it would be interesting to see whether the performance and use of resources differ by any means. Also note that the message does not perform any kind of computations despite extracting the values. It would throw an Exception if something is malformed and this exception would end in the transport. In fact the message instance is nothing else then a Data Model for the message, and whether you discard that one or the byte[] is also more a philosophical discussion :) The checks would be still performed by the transport.... I also agree with you that the way you call things make a change. I introduced this concept [Transaction] because I understood from the context of the specs for ModbusTCP that there are always sequences of request-response which are tightly coupled. As I am also doing work with databases and other data stores, I borrowed the vocabulary from there, as I thought it would be a common nomer :) However, probably it is too much master(client)/ModbusTCP centric....I don't know. Would you suggest an alternative name? I guess this sheds another light on the proposal you made too. I will try to make up the Stream to show how it is meant, and probably I manage to prepare an interaction diagram to show what exactly happens when we are reading a message :) This could maybe show the knots in our two approaches and indicate a way to open those. Regards, Dieter |
From: Proctor, K. <Kel...@al...> - 2001-10-25 00:05:38
|
Dieter, I think I have solved the problem I put forward below. I'm proposing a revised design for the ModbusASCIIInputStream class. First a new exception class will need to be defined, the EndOfFrameException. The class will still extend the FilterInputStream class. Internally the class would wrap the InputStream into a PushbackInputStream, allowing it to peek ahead as required. The class would look something like the following. public class ModbusASCIIInputStream extends FilterInputStream { private PuchbackInputStream m_Input; private int m_BytesLeftInFrame; private int m_LrcSum; private byte[] m_Buffer; public ModbusASCIIInputStream(InputStream in) { m_Input = new PushbackInputStream(in, Modbus.MAX_MESSAGE_SIZE * 2); m_Buffer = new byte[Modbus.MAX_MESSAGE_SIZE]; } public int read() { - Check if there is another byte (not delimeters or LRC) available - If available return next byte and update LrcSum. - else throw EndOfFrame Exception - update m_BytesLeftInFrame accordingly } public int read(byte[] b, int off, int len) { - Check if there is at least another byte (not delimeters or LRC) available. - If available - int byteToReturn = min(len,m_BytesLeftInFrame) - Copy read byteToReturn bytes into m_Buffer using m_Input.read(m_Buffer, 0, byteToReturn) - Scan over m_Buffer to update m_LrcSum - Copy bytes into b using System.arraycopy(m_Buffer, 0, b, off, byteToReturn) - return byteToReturn - NOTE: Above avoids looped use of m_Input.read() (which is byte banging input method and should be avoided if at all possible) instead using the block read function and the System.arraycopy - Else (no more bytes available) - throw EndOfFrameException - update m_BytesLeftInFrame accordingly } public int read(byte[] b, int off, int len) { return read(b, 0. b.length); } public void nextFrame() { - read past the frame delimeters - peek ahead to look for end of frame (using read then unread for a large block of data) - reset the m_BytesLeftInFrame variable } public int bytesLeftInFrame() { return m_BytesLeftInFrame; } public boolean checkLRC() { - If this is called when BytesLeftInFrame==0 then the LRC value is checked and result returned - If this is called at any other point then false is returned (This is so if you think there should only been 10 bytes in the frame and there are really 20 bytes then this will return false causing you to abort the transaction) } } I'm not 100% happy with the way the LRC check is performed above but I do really like the way that we avoid byte banging the input stream using read() all the time. It also extends FilterInputStream in a sensible way by making all the read functions work properly. What do you think of the above proposal and can you suggest any better mechanism for checking the LRC? It would be nice of you could check the LRC at the start somehow (before you start processing the message) as opposed to at the end when you have wasted all this runtime processing a bogus message. This becomes more important for write commands as you need to know if the frame is OK before you do anything. With a read you can simply abort the message at the last moment. Hope you exams went (is going) well. Cheers, Kelvin > -----Original Message----- > From: Proctor, Kelvin [SMTP:Kel...@al...] > Sent: Wednesday, October 24, 2001 11:10 > To: 'jModbus Devel' > Subject: RE: Re: [jModbus-devel] Codebase Merge initial comments > > Dieter, > > Good luck with your exam. I hope this is not taking too much of your time > away from such things. > > Comments below. > > Cheers, > > Kelvin > > > -----Original Message----- > > From: Dieter Wimberger [SMTP:wi...@oe...] > > Sent: Wednesday, October 24, 2001 5:07 > > To: jmo...@li... > > Subject: RE: Re: [jModbus-devel] Codebase Merge initial comments > > > > Hi Kelvin, > > > > Well I have also to get back to some real work, as I am up to do an exam > > tomorrow :) > > > > However, here some explanations on the questions you had: > > > > > > 1. Why not reading frames from the ASCIIInputStream? > > > > Well this is easily answered, as this is the only way to make use of the > > structure as it is in my package. The message implementations can keep > > reading what is in their responsibility themselves, as the stream can be > > > passed on without problems. > > > > The Transport class has the responsibility of knowing frames, and > handling > > frames as such. This means you could simply pass on the : character and > > the > > CRLF character (anything outside 0-9 A-F) should do the job. > > The transport should read from the stream, check for the start character > > and the address > > (if it is addressed, and we need to think about where this address comes > > from :) etc.... > > > [Proctor, Kelvin] > I'm still note sure how you intend that this be done. Perhaps a > little diagram below will illustrate the difficult I am having. It is how > you 'pass on' the : and CR LF characters that I don't understand. > > <FixedWidthFont> > > Serial Port Stream (consider it to be 7 bit ASCII) > --------------------------------------------------- > | : | A | 2 | 3 | F | 9 | 4 | CR | LF | : | A | E | > --------------------------------------------------- > > Translates to byte stream > --------------------------------------------------- > | ? | 0xA2 | 0x3F | 0x94 | ? | ? | 0xAE | > --------------------------------------------------- > > </FixedWidthFont> > > I am unsure what byte values would go in the place of the ? > characters in the bottom stream. > > > 2. Why producing the LRC byte for byte? > > > > Well this is not much of an issue, if you check out the sources of the > I/O > > streams of the > > Java API, you will realize that at the end of the day all your reads end > > up in > > native public int read() somewhen. > > Despite that your code will loop over the byte array too, so performance > > of the > > one byte at a time is probably even better then looping. > > I am still not exactly sure however if the LRC is performed on each raw > > byte (i.e. still encoded) > > or on the decoded ones. I will check this out when I find time again, > i.e. > > after my exam. > > > [Proctor, Kelvin] > I'm also unsure when you would propose checking the LRC if the frame > is not extracted as a whole at the transport layer. > > There are a number of checks that need to be made that rely on > knowing the length of the modbus message. > 1. The LRC check can't occur until you find the end of the frame to > do the check. > 2. If a message states that it has 10 bytes to follow and there are > infact 20 bytes following in the message then an exception should be > generated as this is a malformed (even if not fatal) request. > > I can see a way that streams all the way could work for the output > streams but I can't picture it for the input streams. I still see a need > to > at some point have the whole message sitting in a byte array (hidden in a > class probably) so that a number of checks can be performed on it, > including > determining it length and the LRC. > > > 3. Why using a FilterInputStream? > > > > The use of FilterInputStream is for model reasons as it does exactly > what > > is stated also in the API, > > it transforms the raw data exposing a standard interface. > > All reads in Java are blocking, and I do not exactly understand what you > > mean with "byte banging", > > probably you can explain this term to me. > > I guess I have to code this out to see what it does and whether it works > > out :) > > > [Proctor, Kelvin] > Byte banging is where you do things one byte at a time. This is > often see with read and write operations. Block operations are usually of > the order of 100 time more efficient then byte-by-byte operations. We are > going to have to do that at one point at least (2 ASCII chars to 1 byte) > but > se should be going out of our way to minimise it if possible. > > > 4. Why the Modbus interface? > > > > This interface is solemnly serving the purpose of holding globally > > accessible constants. > > I have realized that it does not make any difference if you use a class > or > > an interface > > with constants, despite that the class needs extra care to prevent > > instantiation (i.e. > > a private constructor). I am not even sure, but I think the compiler > makes > > the same out > > of it (got to check the bytecode specs once to know). > > > > The use is Modbus.CONSTANT_NAME in any case from anywhere in the rest of > > the code as it > > is completely public. > > > [Proctor, Kelvin] > This was really a non-issue, I just wanted to know if there was some > reasoning and importance I had missed. > > > 6. Why the ModbusTransaction interface? > > > > This is one of the contracts I have been talking about. > > I think it is reasonable to go like this, as for example a Transaction > for > > ModbusASCII transported > > messages might have to be implemented differently. > > The rest of the code using transactions can be coded against the > > interface, and would not realize any > > difference :) > > > [Proctor, Kelvin] > I see now. I had perceived the wrong meaning of the word > transaction. I had though this referred to a transaction up at function > code level, this interface now make quite a lot of sense. > > One thing I have learnt over the last year is the importance of what > names things are called. A slightly different name for the same object > can > give people a very different impression of what the object does > > > 7. Why the ModbusMessage interface? > > > > This is probably the only place where it is not so necessary to make > such > > a construct. > > However, if you want to optimize or make a different implementation of > > ModbusMessage then the one given by ModbusMessageImpl) you could go > ahead > > without the need to change certain other parts of your code (e.g the > > transports for example). All this depends on how good your model and > your > > abstraction/specialization was :) > > > > > > 8. What is a Singleton? > > > > Well this is a Pattern that serves the purpose of having only one > instance > > at runtime. > > Basically there are different approaches to this in Java, however, the > way > > I implemented it, > > is stemming from a very good book on object oriented programming/design > > patterns. > > This "bible" is > > Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. 1995. > > Design Patterns. Addison-Wesley. Reading,Mass. > > > > There are entries in the code snippets for Java, with some changes, even > > done by people that are a bit strange, just overwriting parts and not > even > > documenting what they exactly did ;) > > > [Proctor, Kelvin] > This is as I though, I had just never hear the term, before. Thanks > for the information. > > > Regards, > > Dieter > > > > _______________________________________________ > > jModbus-devel mailing list > > jMo...@li... > > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel > > Alcoa World Alumina Australia is a trading name of Alcoa of Australia > Limited, ACN 004 879 298 > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Proctor, K. <Kel...@al...> - 2001-10-24 01:14:39
|
Dieter, Good luck with your exam. I hope this is not taking too much of your time away from such things. Comments below. Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Wednesday, October 24, 2001 5:07 > To: jmo...@li... > Subject: RE: Re: [jModbus-devel] Codebase Merge initial comments > > Hi Kelvin, > > Well I have also to get back to some real work, as I am up to do an exam > tomorrow :) > > However, here some explanations on the questions you had: > > > 1. Why not reading frames from the ASCIIInputStream? > > Well this is easily answered, as this is the only way to make use of the > structure as it is in my package. The message implementations can keep > reading what is in their responsibility themselves, as the stream can be > passed on without problems. > > The Transport class has the responsibility of knowing frames, and handling > frames as such. This means you could simply pass on the : character and > the > CRLF character (anything outside 0-9 A-F) should do the job. > The transport should read from the stream, check for the start character > and the address > (if it is addressed, and we need to think about where this address comes > from :) etc.... > [Proctor, Kelvin] I'm still note sure how you intend that this be done. Perhaps a little diagram below will illustrate the difficult I am having. It is how you 'pass on' the : and CR LF characters that I don't understand. <FixedWidthFont> Serial Port Stream (consider it to be 7 bit ASCII) --------------------------------------------------- | : | A | 2 | 3 | F | 9 | 4 | CR | LF | : | A | E | --------------------------------------------------- Translates to byte stream --------------------------------------------------- | ? | 0xA2 | 0x3F | 0x94 | ? | ? | 0xAE | --------------------------------------------------- </FixedWidthFont> I am unsure what byte values would go in the place of the ? characters in the bottom stream. > 2. Why producing the LRC byte for byte? > > Well this is not much of an issue, if you check out the sources of the I/O > streams of the > Java API, you will realize that at the end of the day all your reads end > up in > native public int read() somewhen. > Despite that your code will loop over the byte array too, so performance > of the > one byte at a time is probably even better then looping. > I am still not exactly sure however if the LRC is performed on each raw > byte (i.e. still encoded) > or on the decoded ones. I will check this out when I find time again, i.e. > after my exam. > [Proctor, Kelvin] I'm also unsure when you would propose checking the LRC if the frame is not extracted as a whole at the transport layer. There are a number of checks that need to be made that rely on knowing the length of the modbus message. 1. The LRC check can't occur until you find the end of the frame to do the check. 2. If a message states that it has 10 bytes to follow and there are infact 20 bytes following in the message then an exception should be generated as this is a malformed (even if not fatal) request. I can see a way that streams all the way could work for the output streams but I can't picture it for the input streams. I still see a need to at some point have the whole message sitting in a byte array (hidden in a class probably) so that a number of checks can be performed on it, including determining it length and the LRC. > 3. Why using a FilterInputStream? > > The use of FilterInputStream is for model reasons as it does exactly what > is stated also in the API, > it transforms the raw data exposing a standard interface. > All reads in Java are blocking, and I do not exactly understand what you > mean with "byte banging", > probably you can explain this term to me. > I guess I have to code this out to see what it does and whether it works > out :) > [Proctor, Kelvin] Byte banging is where you do things one byte at a time. This is often see with read and write operations. Block operations are usually of the order of 100 time more efficient then byte-by-byte operations. We are going to have to do that at one point at least (2 ASCII chars to 1 byte) but se should be going out of our way to minimise it if possible. > 4. Why the Modbus interface? > > This interface is solemnly serving the purpose of holding globally > accessible constants. > I have realized that it does not make any difference if you use a class or > an interface > with constants, despite that the class needs extra care to prevent > instantiation (i.e. > a private constructor). I am not even sure, but I think the compiler makes > the same out > of it (got to check the bytecode specs once to know). > > The use is Modbus.CONSTANT_NAME in any case from anywhere in the rest of > the code as it > is completely public. > [Proctor, Kelvin] This was really a non-issue, I just wanted to know if there was some reasoning and importance I had missed. > 6. Why the ModbusTransaction interface? > > This is one of the contracts I have been talking about. > I think it is reasonable to go like this, as for example a Transaction for > ModbusASCII transported > messages might have to be implemented differently. > The rest of the code using transactions can be coded against the > interface, and would not realize any > difference :) > [Proctor, Kelvin] I see now. I had perceived the wrong meaning of the word transaction. I had though this referred to a transaction up at function code level, this interface now make quite a lot of sense. One thing I have learnt over the last year is the importance of what names things are called. A slightly different name for the same object can give people a very different impression of what the object does > 7. Why the ModbusMessage interface? > > This is probably the only place where it is not so necessary to make such > a construct. > However, if you want to optimize or make a different implementation of > ModbusMessage then the one given by ModbusMessageImpl) you could go ahead > without the need to change certain other parts of your code (e.g the > transports for example). All this depends on how good your model and your > abstraction/specialization was :) > > > 8. What is a Singleton? > > Well this is a Pattern that serves the purpose of having only one instance > at runtime. > Basically there are different approaches to this in Java, however, the way > I implemented it, > is stemming from a very good book on object oriented programming/design > patterns. > This "bible" is > Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. 1995. > Design Patterns. Addison-Wesley. Reading,Mass. > > There are entries in the code snippets for Java, with some changes, even > done by people that are a bit strange, just overwriting parts and not even > documenting what they exactly did ;) > [Proctor, Kelvin] This is as I though, I had just never hear the term, before. Thanks for the information. > Regards, > Dieter > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Dieter W. <wi...@oe...> - 2001-10-23 19:07:20
|
Hi Kelvin, Well I have also to get back to some real work, as I am up to do an exam tomorrow :) However, here some explanations on the questions you had: 1. Why not reading frames from the ASCIIInputStream? Well this is easily answered, as this is the only way to make use of the structure as it is in my package. The message implementations can keep reading what is in their responsibility themselves, as the stream can be passed on without problems. The Transport class has the responsibility of knowing frames, and handling frames as such. This means you could simply pass on the : character and the CRLF character (anything outside 0-9 A-F) should do the job. The transport should read from the stream, check for the start character and the address (if it is addressed, and we need to think about where this address comes from :) etc.... 2. Why producing the LRC byte for byte? Well this is not much of an issue, if you check out the sources of the I/O streams of the Java API, you will realize that at the end of the day all your reads end up in native public int read() somewhen. Despite that your code will loop over the byte array too, so performance of the one byte at a time is probably even better then looping. I am still not exactly sure however if the LRC is performed on each raw byte (i.e. still encoded) or on the decoded ones. I will check this out when I find time again, i.e. after my exam. 3. Why using a FilterInputStream? The use of FilterInputStream is for model reasons as it does exactly what is stated also in the API, it transforms the raw data exposing a standard interface. All reads in Java are blocking, and I do not exactly understand what you mean with "byte banging", probably you can explain this term to me. I guess I have to code this out to see what it does and whether it works out :) 4. Why the Modbus interface? This interface is solemnly serving the purpose of holding globally accessible constants. I have realized that it does not make any difference if you use a class or an interface with constants, despite that the class needs extra care to prevent instantiation (i.e. a private constructor). I am not even sure, but I think the compiler makes the same out of it (got to check the bytecode specs once to know). The use is Modbus.CONSTANT_NAME in any case from anywhere in the rest of the code as it is completely public. 6. Why the ModbusTransaction interface? This is one of the contracts I have been talking about. I think it is reasonable to go like this, as for example a Transaction for ModbusASCII transported messages might have to be implemented differently. The rest of the code using transactions can be coded against the interface, and would not realize any difference :) 7. Why the ModbusMessage interface? This is probably the only place where it is not so necessary to make such a construct. However, if you want to optimize or make a different implementation of ModbusMessage then the one given by ModbusMessageImpl) you could go ahead without the need to change certain other parts of your code (e.g the transports for example). All this depends on how good your model and your abstraction/specialization was :) 8. What is a Singleton? Well this is a Pattern that serves the purpose of having only one instance at runtime. Basically there are different approaches to this in Java, however, the way I implemented it, is stemming from a very good book on object oriented programming/design patterns. This "bible" is Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. 1995. Design Patterns. Addison-Wesley. Reading,Mass. There are entries in the code snippets for Java, with some changes, even done by people that are a bit strange, just overwriting parts and not even documenting what they exactly did ;) Regards, Dieter |
From: Proctor, K. <Kel...@al...> - 2001-10-23 04:45:12
|
Dieter, Based on you comments below regarding the use of filter streams I think I can now see a nice way to handle this, along the lines of what you had proposed. I would propose a slightly different looking ASCIIInputStream class. See what you think. public class ASCIIInputStream extends FilterInputStream { public ASCIIInputStream(InputStream in) { //constructor..... } public void readFrame(byte[] buff) { // This function will write a whole frame (including the LRC) into // the byte array, having converted from ASCII into binary. // i.e. it will strip the leading : and the trailing CR LF as well as // do the binary conversion } } The LRC check and creation could exist in the transport class, which would be responsible for rejecting frames. I'm not sure I see any point in being able to read the frame a single byte at a time before the LRC is calculated and checked. If there is a good reason to be able to do this can you point it out to me. This also raises the point that if reading a single byte is not a useful thing to do then why would you make it extend FilterInputStream if some of it's methods can not apply to this class. ([general OO question] Is this a valid criteria to impose when considering extending a class, I'm not sure?) Part of my reasoning is this: Below you have proposed that the start and end frame characters be passed up from the ASCII Stream to the Transport, where deframing and checksum checks could occur. I'm wondering how this would be done. If we are returning a byte (that as part of the message may have any value) how do we signal that this is the end or start of the frame character? It could be possible by setting the int returned to a different negative value (not -1 which indicates failure) such as -2 for start of frame and -3 for end of frame. This presents the problem of what to do for the block read functions (which should be used wherever possible to avoid byte banging which is inefficient, but we will have to do some of that anyway for the conversion so it doesn't really matter). Other than the above difficulty I like the proposal you have put forward. From below: The fix you have proposed for the TCP transport is good. With no possible way of regaining sequence if it is lost it is important to make sure we preform all checks with the TCP transport, the other at least have delimiters. The package structure is quite nice. It is at first a bit baffling with the net and io packages. Once I considered this was only written with the TCP implementation in mind it made much more sense. The example with the interfaces would be the Modbus interface. No classes implement this interface, thus I'm wondering if it would be an interface or simply a class with public static final fields? This is a very minor thing but I'm wondering if there was any special reasoning behind it that I can't figure out. Another example would be the ModbusTransaction interface. Under what type of use would you see a class other than ModbusTransactionImpl implementing this interface. This is not to argue that it should not be setup this way but I'm curious how this sort of thing would be used and what the application would be. Likewise for ModbusMessage and ModbusMessageImpl. With the ModbusCoupler class it makes reference to a Singleton pattern. I'm wondering what this is as I have never come across the term. I probably know it by a different (crazy Australian) name so I though I should just check it's meaning. Anyway I had better get back to doing some real work (which in this unfortunate case is writing a GUI to a database in VB, not very nice....) Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Monday, October 22, 2001 21:36 > To: jmo...@li... > Subject: Re: Re: [jModbus-devel] Codebase Merge initial comments > > Kelvin, > > I completely agree with you that it is not easy to share code or work with > code from other people. I also think that I have bombed you a bit, because > I delivered a complete package with completely different approaches to > everything. > I am long enough into Open Source (I am contributing and leading some > projects) that I know this not easy, but it bears a huge potential for > learning from each other. > The only thing that is important when opening the source is that you have > detached emotionally from your creation. In any other case, you will take > things discussed personally, and this will block any learning process. > > Regarding the model, well, usually the best way to see what a model does > is to check out the UML Class diagrams. They visualize what is often very > hard to understand from the code. > I will try to walk through the packages to explain the motivation for the > interface: > > io package: > There is the ModbusTransaction and the ModbusTransport. Both are supposed > to be used to code against, representing rather a contract then anything > else. The common method in those cases do not necessarily share more then > the Interface, so it is natural to proceed like this. > > msg package: > The ModbusMessage is probably not necessary, but it could allow to replace > the implementation without problems, if the rest of the code is written > properly against the contract. > People always think things can be further optimized :) > > The abstract classes are to get a differentiated model with clearly > defined entities and responsibilities. > > net package: > No interface, however, I am thinking of introducing either a superclass or > an interface called ModbusConnection, which both the slave and the master > connection should be implementing or subclassing. > This will allow handling troubles on the low level side. > > procimg package: > There are a lot of interfaces ok :) Well the reason is again to define > contracts to code against. > Without knowing the actual specifics of the implementation, the other > parts of the code will be able to read/write values. I think you have > already realized the benefit of this, at least I have understood that from > the comment you added in the other mail. > > > util package: > No interfaces. > > > Now, to summarize, I would say the major driver for the use of Interfaces > is to > 1. define contracts > 2. hide implementation specifics, respectively expose just what should be > exposed > > Multiple inheritance is not really an issue, and I have seen enough misuse > of that in C++ to be able to understand the "no multiple inheritance" move > of the Java language creators. No tears for those classes that inherit > complete sets of parents only to gather one or two methods..... > > > Probably you can specify exactly were you see the problem with the > inheritance, because I am not exactly sure which part you are adressing. > Don't worry about the critism, I will try to learn from the discussions, > and not take it personally :) > > > >The TCP issue [Kelvin] > > This is not necessarily true. The spec states that messages may be > >pipelined by some clients and this could happen in the same packet quite > >conceivably, or (more unlikely) the packets could be fragmented. It does > >not matter to us however as we should only look at it in terms of the TCP > >stream. The spec says a multi threaded client should read in just the 6 > >byte header and examine that. Two checks are then to be performed, 1. > the > >protocol identifier check and 2. the check that the message length field > is > >not greater than 255. If either of these fail the socket is to be > closed. > > Ok, I have read the specification, and I think this can be solved very > easily and at the > right place: > ModbusTCPTransport Class: > > public ModbusRequest readRequest() > throws ModbusIOException { > try { > int transactionID = m_Input.readShort(); > int protocolID = m_Input.readShort(); > int dataLength = m_Input.readShort(); > if(protocolID!=0 || dataLength>256) { > throw new ModbusIOException(); > } > [...] > > > }//readRequest > > We can either work with this Exception, or take a look if we need another > one, to make sure we can differentiate the problems and close unilaterally > when something is seriously wrong. Another option is to include a Flag, > anything that differentiates, if such a differentiation to lead behaviour > is necessary. > > Regarding the timeouts, well this could be achieved with keeping a > reference to the Socket (i.e. m_Socket) and using > m_Socket.setSoTimeout(0); > Also not a big issue :) > > The remaining code actually does what the Specs request, however, the > threading issues are handled by the JVM, rather then by us. > > Would you agree that this will properly do the job? > > > > [Proctor, Kelvin] > > Sorry, my mistake in not clearly explaining my self here and not > >understanding you code properly. What I had intended to imply is that > the > >ModbusMessage must keep an internal buffer that contains the message and > >create streams from than (both input and output) that any of the 'message > >processing' (read higher level) code desires. We can't have a stream > that > >leads down to one of the TCP socket's streams being used at a higher > level > >as this would not work with the ASCII transport, as a translation of the > >stream from ASCII encoded data to binary is required. > > Hmm probably I did not express myself very clear either. Yes you can have > an absolutely standard construct that handles this problem. Java I/O > proposes to "wrap" Streams into other streams for aggregating certain > functionality. > Here a piece from the Java API, java.io.FilterInputStream: > "A FilterInputStream contains some other input stream, which it uses as > its basic source of data, possibly transforming the data along the way or > providing additional functionality" > > The catchword is transforming here. > For ASCII and RTU this is exactly what you need, as the interface to the > next level is cleary reading > binary data, and not the encoded one. > Imagine you have > public class ASCIIInputStream extends FilterInputStream { > > private InputStream m_Input; > > public ASCIIInputStream(InputStream in) { > m_Input=in; > }//constructor > > public int read() { > > 1. read first character and update LRC > 2. read second character and update LRC > 3. transform the two into a byte > 4. return byte > > }//read > > private void updateLRC(int char) { > //mechanism to update LRC sum > }//updateLRC > > public int getLRC() { > //return actual LRC Checksum > }//getLRC > > public void resetLRC() { > //if necessary.. > }//resetLRC > > }//class ASCIIInputStream > > > The ModbusASCIITransport would simply use this one, and the correct > mechanisms > necessary to implement the specs ;) > Definately the above is a rough sketch, as I do not know whether each > character is > used for the LRC, or just the bytes, and there must be a mechanism to pass > through > the Frame Start colon and the CRLF in one turn, but that is if at all some > > if-elseif-else construct. > > I hope now it is clearer _why_ anything above this would never be > confronted with this low > level details. > The responsibilities will be clearly assigned: > 1. The ModbusASCIIInputStream is responsible for transformation of the > encoding. > it also calculates/updates the LRC on the fly. > 2. The ModbusASCIITransport is responsible for handling the framing, > including > start, end recoginition, and LRC checking (by retrieving the checksum > from > the underlying stream. > 3. The ModbusMessage implementation never sees encoded data or anything > related to the framing. > It is only responsible to read the data it knows and needs. If it does > not work out, the Exception > will anyway be passed through the ModbusTransport, and that is again > the right instance with the > responsibility to handle this. > > For the RTU this will be more or less the same, schema ..... > > Don't get me wrong, but I think the complete construct is quite > beautifully working hand in hand :) > > > I hope that I could shed some more light now, and explain more clearly how > this "working hand in hand" actually happens. > If not, do not hesistate to ask, and also go ahead and put things into > question, because this will definately be the way that leads us to an > excellent and well thought out design respectively implementation. > > > Thanks and best regards, > Dieter > > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Kelvin P. <k.p...@st...> - 2001-10-22 12:46:37
|
Dieter, I have not had time to fully code or test the ASCII transport tonight but I have the receiveFrame code written and it will give you an indication about how I have intended to solve the problem. The decode functions to go from char[] to byte[] array can probably be made more efficient but you will get the idea. By using a StreamTokeniser setup in the correct fashion it make the code relatively neat. How efficient this is and if it will work with the streams properly I'm unsure but we will find out. I have committed the code to the CVS repository (as in my sandbox was the easiest place to undertake development) for you to have a look at. Cheers, Kelvin -----Original Message----- From: jmo...@li... [mailto:jmo...@li...]On Behalf Of Proctor, Kelvin Sent: Monday, 22 October 2001 4:11 PM To: 'jModbus Devel' Subject: RE: [jModbus-devel] Codebase Merge initial comments Dieter, As I've slowly discovered over the last year when you first read someone else's code you initial reaction is almost always to see a different way you would have done things and usually dislike the code you are looking at in some way. I've found this can with equal likelihood be caused by 1. the code actually being bad or 2. you not understanding the code properly and the problem the code solves. In a few areas you have a very large number of interfaces. I like the idea of exposing the internals of the system in certain places to allow for greater flexibility. In a few places I'm wondering if you have used a lot of interfaces to get around multiple inheritance types issues in places or if you expect all of the said interfaces to possibly be implemented by external classes by a user in some way. Please don't take this as a criticism, I'm just curious as my formal OO training has been very limited, most of it has been self taught. I'm just comparing the number of interfaces vs. real classes in this API vs. the main java API as an example. Are there places where simple inheritance could be used more cleanly? Anyway I'm about to go home and I'll see how quickly I can get the ASCII transport to you. Other than that see the comments below. Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Sunday, October 21, 2001 10:45 > To: jmo...@li... > Subject: Re: [jModbus-devel] Codebase Merge initial comments > > Hi Kelvin, > > Good to hear from you. I add some comments below, as I'd like to oppose to > some of your findings. > > > >--- IO Package --- > > >The Modbus TCP Transport is not as fully robust as it might possibly be. > >The only thing you > >can really assume about a packet is that you can read 6 bytes to give the > >complete header. > >If that fails you close the socket. You are not able to assume that you > >will receive a unit > >ID or a function code, which I do not believe should be part of the > >transport. The transport > >should have the responsibility for framing and deframing a packet and > should > >not be concerned > >with it's contents in any way. I will modify this to behave like my > >original package which > >has all these protections and checks. > > Hmm ok, however, it does not make any difference. Basically you can assume > that if you cannot read one character you did not get any package ;) > Remember that the whole Modbus message is coming in _one_ TCP package. [Proctor, Kelvin] This is not necessarily true. The spec states that messages may be pipelined by some clients and this could happen in the same packet quite conceivably, or (more unlikely) the packets could be fragmented. It does not matter to us however as we should only look at it in terms of the TCP stream. The spec says a multi threaded client should read in just the 6 byte header and examine that. Two checks are then to be performed, 1. the protocol identifier check and 2. the check that the message length field is not greater than 255. If either of these fail the socket is to be closed. > According to the specs the Unit ID and function code have a special > position I know, but I rather account it on the header then to the package > data. > The Transport does not do anything on the messages actually, because all > of it is done within the ModbusMessageImpl and the specialized > ModbusRequest or ModbusResponse. > I did drop a check on the first read in the ModbusMessageImpl, I just did > not hook it up, because I believe it should be bubbled to the connection > through an event mechanism (this would be the right place to handle the > problem, either by closing and reporting to the user, or by re-executing > the request). > [Proctor, Kelvin] The distinction I would draw here is that the unit ID and the function code and part of the modbus message, which I define to be only that part which is common to all transport mechanisms. I have included the transaction ID into this as an exception and have decided that the ASCII and RTU transports simply default this to zero. > >I'm also of the opinion that the interaction between the transport > classes > >and the message > >classes should be done in terms of byte arrays. (We should also user the > >System.arrayCopy > >function where required as it is implemented locally in a fast manner). > > Another hmm. You can simply get the message as bytes and read them out, > this isn't much of a problem. However, note that per design you will get a > newly allocated byte array from the ByteArray stream. > It is a matter of resources..... > On a object oriented design basis I'd say that it is completely ok to pass > the message object. > [Proctor, Kelvin] Sorry, my mistake in not clearly explaining my self here and not understanding you code properly. What I had intended to imply is that the ModbusMessage must keep an internal buffer that contains the message and create streams from than (both input and output) that any of the 'message processing' (read higher level) code desires. We can't have a stream that leads down to one of the TCP socket's streams being used at a higher level as this would not work with the ASCII transport, as a translation of the stream from ASCII encoded data to binary is required. I had through about writing a classes to extend one of the IO stream classes but I can't think of a satisfactory way of mapping the start and end delimiters through that get round the face that they are 'in-band' coding, as the modbus message can contain any of the 0-255 byte values. There is also the issue that the transport needs to calculate and check/add the LRC, which is not part of the 'modbus message' as I have defined it. I have been a little delayed but I should be able to get the ASCII transport sent to you tonight. It will be for my old architecture but it should demonstrate the point. > >Where the rest > >of the application desires streams based communications this should be > done > >through the use > >ByteArray streams. This would be done as it means that *only* the frame > >data needs to be > >transferred to the messaging classes, leaving all the other rubbish to do > >with the differences > >between the transport in the transport objects. (Things like frame > >delimnating breaks in the > >RTU modes and CR LF and : breaks in the ASCII would stuff things up and > the > >whole situation > >would not work for ASCII as the data is not binary encoded.) I'll have a > go > > Now I understand your point better. Well, the problem is just that the > whole design as it is becomes obsolete under this viewpoint :( > Well the design as I came up with is in a very object oriented manner, > taking care of resources and with reasonably assigned responsibilities. > > The real handling of the different transport flavors can be simply done in > the Transports. Look, this is what I meant with RTU/ASCII Input and Output > Streams. > The specialized Transport implementation can use such filtering streams to > translate binary data to the encoding that is necessary for the specific > flavor, no specialized message class would _ever_ get involved into this. > Maybe the situation with data transport is a bit different here though. > Guess that I/O exception handling has to be re-thought very well. The > assumption that all comes in one "package" is not valid, like for TCP. > [Proctor, Kelvin] As above. I'll send the code for the ASCII module to you soon and this should act as a good point for this discussion to continue from. > >a modifying these > >classes and we'll see what you think. > > I'd hope you see my point.... > [Proctor, Kelvin] Yes, unfortunately the problem is not quite as simple as either of us would have liked, but I think I can see the solution. > >--- Process Image Package --- > > >I also like the way you have made all the registers etc.. interfaces as > this > >can provide a > >means by which an event/listener interface as I has proposed can be > avoided > >completely. If > >you want to trigger on certain types of changes to a register values then > >you implement the > >register yourself so that so write the set command and get put whatever > >trigger code in there > >that you desire. > > Exactly this is the idea. In fact I think that it will be necessary to > taylor implementations to the specific needs. Concurrency issues can be > handled without affecting the downstream. I had some discussions with my > advisor, and I am sure I will try to implement some more sophisticated > items to showcase copy-on-write or Read-Write priority handling. > > Regards, > Dieter > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 _______________________________________________ jModbus-devel mailing list jMo...@li... https://lists.sourceforge.net/lists/listinfo/jmodbus-devel |
From: Dieter W. <wi...@oe...> - 2001-10-22 11:37:25
|
Kelvin, I completely agree with you that it is not easy to share code or work with code from other people. I also think that I have bombed you a bit, because I delivered a complete package with completely different approaches to everything. I am long enough into Open Source (I am contributing and leading some projects) that I know this not easy, but it bears a huge potential for learning from each other. The only thing that is important when opening the source is that you have detached emotionally from your creation. In any other case, you will take things discussed personally, and this will block any learning process. Regarding the model, well, usually the best way to see what a model does is to check out the UML Class diagrams. They visualize what is often very hard to understand from the code. I will try to walk through the packages to explain the motivation for the interface: io package: There is the ModbusTransaction and the ModbusTransport. Both are supposed to be used to code against, representing rather a contract then anything else. The common method in those cases do not necessarily share more then the Interface, so it is natural to proceed like this. msg package: The ModbusMessage is probably not necessary, but it could allow to replace the implementation without problems, if the rest of the code is written properly against the contract. People always think things can be further optimized :) The abstract classes are to get a differentiated model with clearly defined entities and responsibilities. net package: No interface, however, I am thinking of introducing either a superclass or an interface called ModbusConnection, which both the slave and the master connection should be implementing or subclassing. This will allow handling troubles on the low level side. procimg package: There are a lot of interfaces ok :) Well the reason is again to define contracts to code against. Without knowing the actual specifics of the implementation, the other parts of the code will be able to read/write values. I think you have already realized the benefit of this, at least I have understood that from the comment you added in the other mail. util package: No interfaces. Now, to summarize, I would say the major driver for the use of Interfaces is to 1. define contracts 2. hide implementation specifics, respectively expose just what should be exposed Multiple inheritance is not really an issue, and I have seen enough misuse of that in C++ to be able to understand the "no multiple inheritance" move of the Java language creators. No tears for those classes that inherit complete sets of parents only to gather one or two methods..... Probably you can specify exactly were you see the problem with the inheritance, because I am not exactly sure which part you are adressing. Don't worry about the critism, I will try to learn from the discussions, and not take it personally :) >The TCP issue [Kelvin] > This is not necessarily true. The spec states that messages may be >pipelined by some clients and this could happen in the same packet quite >conceivably, or (more unlikely) the packets could be fragmented. It does >not matter to us however as we should only look at it in terms of the TCP >stream. The spec says a multi threaded client should read in just the 6 >byte header and examine that. Two checks are then to be performed, 1. the >protocol identifier check and 2. the check that the message length field is >not greater than 255. If either of these fail the socket is to be closed. Ok, I have read the specification, and I think this can be solved very easily and at the right place: ModbusTCPTransport Class: public ModbusRequest readRequest() throws ModbusIOException { try { int transactionID = m_Input.readShort(); int protocolID = m_Input.readShort(); int dataLength = m_Input.readShort(); if(protocolID!=0 || dataLength>256) { throw new ModbusIOException(); } [...] }//readRequest We can either work with this Exception, or take a look if we need another one, to make sure we can differentiate the problems and close unilaterally when something is seriously wrong. Another option is to include a Flag, anything that differentiates, if such a differentiation to lead behaviour is necessary. Regarding the timeouts, well this could be achieved with keeping a reference to the Socket (i.e. m_Socket) and using m_Socket.setSoTimeout(0); Also not a big issue :) The remaining code actually does what the Specs request, however, the threading issues are handled by the JVM, rather then by us. Would you agree that this will properly do the job? > [Proctor, Kelvin] > Sorry, my mistake in not clearly explaining my self here and not >understanding you code properly. What I had intended to imply is that the >ModbusMessage must keep an internal buffer that contains the message and >create streams from than (both input and output) that any of the 'message >processing' (read higher level) code desires. We can't have a stream that >leads down to one of the TCP socket's streams being used at a higher level >as this would not work with the ASCII transport, as a translation of the >stream from ASCII encoded data to binary is required. Hmm probably I did not express myself very clear either. Yes you can have an absolutely standard construct that handles this problem. Java I/O proposes to "wrap" Streams into other streams for aggregating certain functionality. Here a piece from the Java API, java.io.FilterInputStream: "A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality" The catchword is transforming here. For ASCII and RTU this is exactly what you need, as the interface to the next level is cleary reading binary data, and not the encoded one. Imagine you have public class ASCIIInputStream extends FilterInputStream { private InputStream m_Input; public ASCIIInputStream(InputStream in) { m_Input=in; }//constructor public int read() { 1. read first character and update LRC 2. read second character and update LRC 3. transform the two into a byte 4. return byte }//read private void updateLRC(int char) { //mechanism to update LRC sum }//updateLRC public int getLRC() { //return actual LRC Checksum }//getLRC public void resetLRC() { //if necessary.. }//resetLRC }//class ASCIIInputStream The ModbusASCIITransport would simply use this one, and the correct mechanisms necessary to implement the specs ;) Definately the above is a rough sketch, as I do not know whether each character is used for the LRC, or just the bytes, and there must be a mechanism to pass through the Frame Start colon and the CRLF in one turn, but that is if at all some if-elseif-else construct. I hope now it is clearer _why_ anything above this would never be confronted with this low level details. The responsibilities will be clearly assigned: 1. The ModbusASCIIInputStream is responsible for transformation of the encoding. it also calculates/updates the LRC on the fly. 2. The ModbusASCIITransport is responsible for handling the framing, including start, end recoginition, and LRC checking (by retrieving the checksum from the underlying stream. 3. The ModbusMessage implementation never sees encoded data or anything related to the framing. It is only responsible to read the data it knows and needs. If it does not work out, the Exception will anyway be passed through the ModbusTransport, and that is again the right instance with the responsibility to handle this. For the RTU this will be more or less the same, schema ..... Don't get me wrong, but I think the complete construct is quite beautifully working hand in hand :) I hope that I could shed some more light now, and explain more clearly how this "working hand in hand" actually happens. If not, do not hesistate to ask, and also go ahead and put things into question, because this will definately be the way that leads us to an excellent and well thought out design respectively implementation. Thanks and best regards, Dieter |
From: Proctor, K. <Kel...@al...> - 2001-10-22 06:15:09
|
Dieter, As I've slowly discovered over the last year when you first read someone else's code you initial reaction is almost always to see a different way you would have done things and usually dislike the code you are looking at in some way. I've found this can with equal likelihood be caused by 1. the code actually being bad or 2. you not understanding the code properly and the problem the code solves. In a few areas you have a very large number of interfaces. I like the idea of exposing the internals of the system in certain places to allow for greater flexibility. In a few places I'm wondering if you have used a lot of interfaces to get around multiple inheritance types issues in places or if you expect all of the said interfaces to possibly be implemented by external classes by a user in some way. Please don't take this as a criticism, I'm just curious as my formal OO training has been very limited, most of it has been self taught. I'm just comparing the number of interfaces vs. real classes in this API vs. the main java API as an example. Are there places where simple inheritance could be used more cleanly? Anyway I'm about to go home and I'll see how quickly I can get the ASCII transport to you. Other than that see the comments below. Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Sunday, October 21, 2001 10:45 > To: jmo...@li... > Subject: Re: [jModbus-devel] Codebase Merge initial comments > > Hi Kelvin, > > Good to hear from you. I add some comments below, as I'd like to oppose to > some of your findings. > > > >--- IO Package --- > > >The Modbus TCP Transport is not as fully robust as it might possibly be. > >The only thing you > >can really assume about a packet is that you can read 6 bytes to give the > >complete header. > >If that fails you close the socket. You are not able to assume that you > >will receive a unit > >ID or a function code, which I do not believe should be part of the > >transport. The transport > >should have the responsibility for framing and deframing a packet and > should > >not be concerned > >with it's contents in any way. I will modify this to behave like my > >original package which > >has all these protections and checks. > > Hmm ok, however, it does not make any difference. Basically you can assume > that if you cannot read one character you did not get any package ;) > Remember that the whole Modbus message is coming in _one_ TCP package. [Proctor, Kelvin] This is not necessarily true. The spec states that messages may be pipelined by some clients and this could happen in the same packet quite conceivably, or (more unlikely) the packets could be fragmented. It does not matter to us however as we should only look at it in terms of the TCP stream. The spec says a multi threaded client should read in just the 6 byte header and examine that. Two checks are then to be performed, 1. the protocol identifier check and 2. the check that the message length field is not greater than 255. If either of these fail the socket is to be closed. > According to the specs the Unit ID and function code have a special > position I know, but I rather account it on the header then to the package > data. > The Transport does not do anything on the messages actually, because all > of it is done within the ModbusMessageImpl and the specialized > ModbusRequest or ModbusResponse. > I did drop a check on the first read in the ModbusMessageImpl, I just did > not hook it up, because I believe it should be bubbled to the connection > through an event mechanism (this would be the right place to handle the > problem, either by closing and reporting to the user, or by re-executing > the request). > [Proctor, Kelvin] The distinction I would draw here is that the unit ID and the function code and part of the modbus message, which I define to be only that part which is common to all transport mechanisms. I have included the transaction ID into this as an exception and have decided that the ASCII and RTU transports simply default this to zero. > >I'm also of the opinion that the interaction between the transport > classes > >and the message > >classes should be done in terms of byte arrays. (We should also user the > >System.arrayCopy > >function where required as it is implemented locally in a fast manner). > > Another hmm. You can simply get the message as bytes and read them out, > this isn't much of a problem. However, note that per design you will get a > newly allocated byte array from the ByteArray stream. > It is a matter of resources..... > On a object oriented design basis I'd say that it is completely ok to pass > the message object. > [Proctor, Kelvin] Sorry, my mistake in not clearly explaining my self here and not understanding you code properly. What I had intended to imply is that the ModbusMessage must keep an internal buffer that contains the message and create streams from than (both input and output) that any of the 'message processing' (read higher level) code desires. We can't have a stream that leads down to one of the TCP socket's streams being used at a higher level as this would not work with the ASCII transport, as a translation of the stream from ASCII encoded data to binary is required. I had through about writing a classes to extend one of the IO stream classes but I can't think of a satisfactory way of mapping the start and end delimiters through that get round the face that they are 'in-band' coding, as the modbus message can contain any of the 0-255 byte values. There is also the issue that the transport needs to calculate and check/add the LRC, which is not part of the 'modbus message' as I have defined it. I have been a little delayed but I should be able to get the ASCII transport sent to you tonight. It will be for my old architecture but it should demonstrate the point. > >Where the rest > >of the application desires streams based communications this should be > done > >through the use > >ByteArray streams. This would be done as it means that *only* the frame > >data needs to be > >transferred to the messaging classes, leaving all the other rubbish to do > >with the differences > >between the transport in the transport objects. (Things like frame > >delimnating breaks in the > >RTU modes and CR LF and : breaks in the ASCII would stuff things up and > the > >whole situation > >would not work for ASCII as the data is not binary encoded.) I'll have a > go > > Now I understand your point better. Well, the problem is just that the > whole design as it is becomes obsolete under this viewpoint :( > Well the design as I came up with is in a very object oriented manner, > taking care of resources and with reasonably assigned responsibilities. > > The real handling of the different transport flavors can be simply done in > the Transports. Look, this is what I meant with RTU/ASCII Input and Output > Streams. > The specialized Transport implementation can use such filtering streams to > translate binary data to the encoding that is necessary for the specific > flavor, no specialized message class would _ever_ get involved into this. > Maybe the situation with data transport is a bit different here though. > Guess that I/O exception handling has to be re-thought very well. The > assumption that all comes in one "package" is not valid, like for TCP. > [Proctor, Kelvin] As above. I'll send the code for the ASCII module to you soon and this should act as a good point for this discussion to continue from. > >a modifying these > >classes and we'll see what you think. > > I'd hope you see my point.... > [Proctor, Kelvin] Yes, unfortunately the problem is not quite as simple as either of us would have liked, but I think I can see the solution. > >--- Process Image Package --- > > >I also like the way you have made all the registers etc.. interfaces as > this > >can provide a > >means by which an event/listener interface as I has proposed can be > avoided > >completely. If > >you want to trigger on certain types of changes to a register values then > >you implement the > >register yourself so that so write the set command and get put whatever > >trigger code in there > >that you desire. > > Exactly this is the idea. In fact I think that it will be necessary to > taylor implementations to the specific needs. Concurrency issues can be > handled without affecting the downstream. I had some discussions with my > advisor, and I am sure I will try to implement some more sophisticated > items to showcase copy-on-write or Read-Write priority handling. > > Regards, > Dieter > > > _______________________________________________ > jModbus-devel mailing list > jMo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |
From: Kelvin P. <k.p...@st...> - 2001-10-21 11:18:25
|
Dieter, I may have changed my mind somewhat over some of these things. I have almost finished the basics of the ASCII transport to show you which may change the way things are viewed slightly as it presents different challenges to that from the TCP transport. I'll explain in more detail when I get to work in the morning and have a bit more time and more complete code. Cheers, Kelvin -----Original Message----- From: jmo...@li... [mailto:jmo...@li...]On Behalf Of Dieter Wimberger Sent: Sunday, 21 October 2001 10:45 AM To: jmo...@li... Subject: Re: [jModbus-devel] Codebase Merge initial comments Hi Kelvin, Good to hear from you. I add some comments below, as I'd like to oppose to some of your findings. >--- IO Package --- >The Modbus TCP Transport is not as fully robust as it might possibly be. >The only thing you >can really assume about a packet is that you can read 6 bytes to give the >complete header. >If that fails you close the socket. You are not able to assume that you >will receive a unit >ID or a function code, which I do not believe should be part of the >transport. The transport >should have the responsibility for framing and deframing a packet and should >not be concerned >with it's contents in any way. I will modify this to behave like my >original package which >has all these protections and checks. Hmm ok, however, it does not make any difference. Basically you can assume that if you cannot read one character you did not get any package ;) Remember that the whole Modbus message is coming in _one_ TCP package. According to the specs the Unit ID and function code have a special position I know, but I rather account it on the header then to the package data. The Transport does not do anything on the messages actually, because all of it is done within the ModbusMessageImpl and the specialized ModbusRequest or ModbusResponse. I did drop a check on the first read in the ModbusMessageImpl, I just did not hook it up, because I believe it should be bubbled to the connection through an event mechanism (this would be the right place to handle the problem, either by closing and reporting to the user, or by re-executing the request). >I'm also of the opinion that the interaction between the transport classes >and the message >classes should be done in terms of byte arrays. (We should also user the >System.arrayCopy >function where required as it is implemented locally in a fast manner). Another hmm. You can simply get the message as bytes and read them out, this isn't much of a problem. However, note that per design you will get a newly allocated byte array from the ByteArray stream. It is a matter of resources..... On a object oriented design basis I'd say that it is completely ok to pass the message object. >Where the rest >of the application desires streams based communications this should be done >through the use >ByteArray streams. This would be done as it means that *only* the frame >data needs to be >transferred to the messaging classes, leaving all the other rubbish to do >with the differences >between the transport in the transport objects. (Things like frame >delimnating breaks in the >RTU modes and CR LF and : breaks in the ASCII would stuff things up and the >whole situation >would not work for ASCII as the data is not binary encoded.) I'll have a go Now I understand your point better. Well, the problem is just that the whole design as it is becomes obsolete under this viewpoint :( Well the design as I came up with is in a very object oriented manner, taking care of resources and with reasonably assigned responsibilities. The real handling of the different transport flavors can be simply done in the Transports. Look, this is what I meant with RTU/ASCII Input and Output Streams. The specialized Transport implementation can use such filtering streams to translate binary data to the encoding that is necessary for the specific flavor, no specialized message class would _ever_ get involved into this. Maybe the situation with data transport is a bit different here though. Guess that I/O exception handling has to be re-thought very well. The assumption that all comes in one "package" is not valid, like for TCP. >a modifying these >classes and we'll see what you think. I'd hope you see my point.... >--- Process Image Package --- >I also like the way you have made all the registers etc.. interfaces as this >can provide a >means by which an event/listener interface as I has proposed can be avoided >completely. If >you want to trigger on certain types of changes to a register values then >you implement the >register yourself so that so write the set command and get put whatever >trigger code in there >that you desire. Exactly this is the idea. In fact I think that it will be necessary to taylor implementations to the specific needs. Concurrency issues can be handled without affecting the downstream. I had some discussions with my advisor, and I am sure I will try to implement some more sophisticated items to showcase copy-on-write or Read-Write priority handling. Regards, Dieter _______________________________________________ jModbus-devel mailing list jMo...@li... https://lists.sourceforge.net/lists/listinfo/jmodbus-devel |
From: Dieter W. <wi...@oe...> - 2001-10-21 00:45:07
|
Hi Kelvin, Good to hear from you. I add some comments below, as I'd like to oppose to some of your findings. >--- IO Package --- >The Modbus TCP Transport is not as fully robust as it might possibly be. >The only thing you >can really assume about a packet is that you can read 6 bytes to give the >complete header. >If that fails you close the socket. You are not able to assume that you >will receive a unit >ID or a function code, which I do not believe should be part of the >transport. The transport >should have the responsibility for framing and deframing a packet and should >not be concerned >with it's contents in any way. I will modify this to behave like my >original package which >has all these protections and checks. Hmm ok, however, it does not make any difference. Basically you can assume that if you cannot read one character you did not get any package ;) Remember that the whole Modbus message is coming in _one_ TCP package. According to the specs the Unit ID and function code have a special position I know, but I rather account it on the header then to the package data. The Transport does not do anything on the messages actually, because all of it is done within the ModbusMessageImpl and the specialized ModbusRequest or ModbusResponse. I did drop a check on the first read in the ModbusMessageImpl, I just did not hook it up, because I believe it should be bubbled to the connection through an event mechanism (this would be the right place to handle the problem, either by closing and reporting to the user, or by re-executing the request). >I'm also of the opinion that the interaction between the transport classes >and the message >classes should be done in terms of byte arrays. (We should also user the >System.arrayCopy >function where required as it is implemented locally in a fast manner). Another hmm. You can simply get the message as bytes and read them out, this isn't much of a problem. However, note that per design you will get a newly allocated byte array from the ByteArray stream. It is a matter of resources..... On a object oriented design basis I'd say that it is completely ok to pass the message object. >Where the rest >of the application desires streams based communications this should be done >through the use >ByteArray streams. This would be done as it means that *only* the frame >data needs to be >transferred to the messaging classes, leaving all the other rubbish to do >with the differences >between the transport in the transport objects. (Things like frame >delimnating breaks in the >RTU modes and CR LF and : breaks in the ASCII would stuff things up and the >whole situation >would not work for ASCII as the data is not binary encoded.) I'll have a go Now I understand your point better. Well, the problem is just that the whole design as it is becomes obsolete under this viewpoint :( Well the design as I came up with is in a very object oriented manner, taking care of resources and with reasonably assigned responsibilities. The real handling of the different transport flavors can be simply done in the Transports. Look, this is what I meant with RTU/ASCII Input and Output Streams. The specialized Transport implementation can use such filtering streams to translate binary data to the encoding that is necessary for the specific flavor, no specialized message class would _ever_ get involved into this. Maybe the situation with data transport is a bit different here though. Guess that I/O exception handling has to be re-thought very well. The assumption that all comes in one "package" is not valid, like for TCP. >a modifying these >classes and we'll see what you think. I'd hope you see my point.... >--- Process Image Package --- >I also like the way you have made all the registers etc.. interfaces as this >can provide a >means by which an event/listener interface as I has proposed can be avoided >completely. If >you want to trigger on certain types of changes to a register values then >you implement the >register yourself so that so write the set command and get put whatever >trigger code in there >that you desire. Exactly this is the idea. In fact I think that it will be necessary to taylor implementations to the specific needs. Concurrency issues can be handled without affecting the downstream. I had some discussions with my advisor, and I am sure I will try to implement some more sophisticated items to showcase copy-on-write or Read-Write priority handling. Regards, Dieter |
From: Kelvin P. <k.p...@st...> - 2001-10-20 23:49:43
|
Dieter, I'm still working through things but here are some of the initial comments about how some of the code may need to be modified. Overall however I really like the look of things. Cheers, Kelvin --- IO Package --- The Modbus TCP Transport is not as fully robust as it might possibly be. The only thing you can really assume about a packet is that you can read 6 bytes to give the complete header. If that fails you close the socket. You are not able to assume that you will receive a unit ID or a function code, which I do not believe should be part of the transport. The transport should have the responsibility for framing and deframing a packet and should not be concerned with it's contents in any way. I will modify this to behave like my original package which has all these protections and checks. I'm also of the opinion that the interaction between the transport classes and the message classes should be done in terms of byte arrays. (We should also user the System.arrayCopy function where required as it is implemented locally in a fast manner). Where the rest of the application desires streams based communications this should be done through the use ByteArray streams. This would be done as it means that *only* the frame data needs to be transferred to the messaging classes, leaving all the other rubbish to do with the differences between the transport in the transport objects. (Things like frame delimnating breaks in the RTU modes and CR LF and : breaks in the ASCII would stuff things up and the whole situation would not work for ASCII as the data is not binary encoded.) I'll have a go a modifying these classes and we'll see what you think. --- Process Image Package --- I also like the way you have made all the registers etc.. interfaces as this can provide a means by which an event/listener interface as I has proposed can be avoided completely. If you want to trigger on certain types of changes to a register values then you implement the register yourself so that so write the set command and get put whatever trigger code in there that you desire. |
From: Proctor, K. <Kel...@al...> - 2001-10-18 23:53:36
|
Dieter, That stability sounds great. I have also seen fantastic stability from by original, non-hardened implementation that sits on the TINI's I have here at work. The TINI's now have up times of 84 days and the slave processes have been running for all of that time. Every few days I startup Citect to connect to both of them and just see it is still working. I'm not sure how many requests this would have handled but it would be many hundreds of thousands. It's a nice thing about the Modbus protocol in that the way the protocol is written there are enough checks in there that you always really know what is happening, thus giving you a fighting chance of creating a solid, fault tolerant implementation. If you would either be able to send me a tarball of the code you are working on, or a link to it before the weekend that would be great. I'll probably spend most of tonight working through your code and making sure I know how it works before I start to merge the two together over the weekend. Cheers, Kelvin > -----Original Message----- > From: Dieter Wimberger [SMTP:wi...@oe...] > Sent: Thursday, October 18, 2001 21:03 > To: jmo...@li... > Subject: [Jmodbus-devel] List and comments > > Hi Kelvin, > > I have subscribed to the list, and I will send my mails to the list from > now on. > > It is good that we have a similar picture of the "process image" term, and > I fully agree that the threading mechanics should be hidden behind > interface(s). > I even think that for specific cases it will be necessary to specially > implement this to suit the actual requirements. > > Regarding to the sources I would like to mention that I did not update the > package that I dropped on my web site. I have driven things further, and I > will put up the new version as soon as I am done with some basic testing > and my clean up (I want to ensure I remove unecessary comments, and add > documentation were I left it out). > I'll notify you when I am done, and the new package can be picked up :) > > During the last half day and night I was running a slave burn-in test, two > simulatenous Requesters running a million requests each in the fastest > sequence possible. It is still running, but that it is still running > already prooves the stability of the implementation :) > > Regards, > Dieter > > > > _______________________________________________ > Jmodbus-devel mailing list > Jmo...@li... > https://lists.sourceforge.net/lists/listinfo/jmodbus-devel Alcoa World Alumina Australia is a trading name of Alcoa of Australia Limited, ACN 004 879 298 |