Hi, I was documenting the whole process and I noticed I forgot something, the EIPFieldHandler. This will be used to encode the values of the read request right? I will have a look at this tomorrow, then I can send you also the document I am working on if you want. Etienne
Le mar. 17 mars 2020 à 14:41, Robinet, Etienne <43...@etu.he2b.be> a écrit : > Hi again, > I've just send it. > > Etienne > > Le mar. 17 mars 2020 à 14:01, Julian Feinauer < > j.feina...@pragmaticminds.de> a écrit : > >> Hi, >> >> it is, yes (first paragraph) and the mail is correct. >> A scan suffices : ) >> >> Julian >> >> Am 17.03.20, 14:00 schrieb "Christofer Dutz" <christofer.d...@c-ware.de >> >: >> >> Hi Etienne, >> >> I think it's secret...@apache.org ... >> should be mentioned in the document. >> >> Chris >> >> >> Am 17.03.20, 13:51 schrieb "Robinet, Etienne" <43...@etu.he2b.be>: >> >> Hi Julian, >> where should I send it once signed? >> >> Etienne >> >> Le mar. 17 mars 2020 à 13:34, Julian Feinauer < >> j.feina...@pragmaticminds.de> >> a écrit : >> >> > Hi, >> > >> > awesome work Etienne. >> > Just a quick note from me... did you already sign a ICLA with >> the Apache >> > Foundation? If not you should do that now, otherwise we can not >> accept this >> > big (and awesome!!) contribution. >> > >> > You can find more information here: >> https://www.apache.org/licenses/ >> > Direkt Link tot he ICLA: https://apache.org/licenses/icla.pdf >> > >> > Best >> > Julian >> > >> > Am 17.03.20, 13:30 schrieb "Etienne Robinet" <43...@etu.he2b.be >> >: >> > >> > Hi Chris, >> > I will do the PR. inside the fork there are also the >> changes I did to >> > the Camel component a couple of weeks ago (passing a List of >> queries and >> > returning a List of values). >> > >> > Etienne >> > On 2020/03/17 10:25:01, Christofer Dutz < >> christofer.d...@c-ware.de> >> > wrote: >> > > Hi Etienne, >> > > >> > > I would suggest you create a Pull Request for your >> changes so we can >> > pull them in. >> > > We can then work on finalizing this together. >> > > >> > > Chris >> > > >> > > >> > > >> > > Am 17.03.20, 11:22 schrieb "Etienne Robinet" < >> 43...@etu.he2b.be>: >> > > >> > > Hi Chris, >> > > the problem was the <parameter> tag was a parameter >> from COTP >> > and not propper to XML. Just removed it and it found the right >> parameters. >> > I pushed the test for Parser/Serializer for Read&Write >> Response/Request. >> > The only little issue I have is with the parsing from the Java >> Object to an >> > XML string (to compare). It seems like it still has some >> difficulties to >> > correctly parse a byte[]; for the rest everything should be OK. >> > > What needs to be done more on the driver? >> > > Etienne >> > > On 2020/03/17 08:00:49, Christofer Dutz < >> > christofer.d...@c-ware.de> wrote: >> > > > Hi Etienne, >> > > > >> > > > sorry for the late response ... couldn't read the >> image on my >> > phone, but on the computer it's fine. >> > > > >> > > > In your case the root element needs to be >> EipConnectionRequest >> > and not EipRequest. >> > > > >> > > > I have to admit I too haven't completely grasped >> all the >> > details of how Jackson parses and serializes stuff. >> > > > But usually I paste an empty xml representation (in >> your case >> > an empty EipPacket element) and put in the bytes. >> > > > Then I run the test and obviously it fails >> complaining about >> > what it parsed and that it looks different. >> > > > I manually examine if the xml is correct and >> replace the empty >> > element with the printed out verson. >> > > > >> > > > Chris >> > > > >> > > > >> > > > >> > > > Am 16.03.20, 17:20 schrieb "Etienne Robinet" < >> > 43...@etu.he2b.be>: >> > > > >> > > > Hi again, >> > > > I started also to test serializer and parser. >> Here is the >> > problem I am facing: https://i.imgur.com/stmEqlm.png >> > > > On the left you see the testcase, on the right >> the code in >> > the ProtocolLogic. I don't know what I a m doing wrong, but >> from the log it >> > seems it does only look for the parameters I am giving? >> > > > >> > > > Etienne >> > > > On 2020/03/16 15:38:33, Etienne Robinet < >> 43...@etu.he2b.be> >> > wrote: >> > > > > Hi Chris, >> > > > > I did a similar test for reading a tag. As I >> never did >> > such tests before, I don't know if the method is correct, but >> the results >> > are similar to the ones I get running the same test for the s7. >> I also >> > pushed this to my fork. Tomorrow I will try to do some tests on >> the PLC to >> > see if I can perform fetching a lot of data (like I did on the >> s7) and if >> > the writing works. >> > > > > >> > > > > Etienne >> > > > > >> > > > > On 2020/03/16 13:47:53, Christofer Dutz < >> > christofer.d...@c-ware.de> wrote: >> > > > > > Hi Etienne, >> > > > > > >> > > > > > You probably pulled in a SNAPSHOT from our >> maven repo >> > ... if this is newer than yours, Maven usually pulls new >> versions the first >> > time you build on every day. ... yes this can be annoying ;-) >> > > > > > >> > > > > > Chris >> > > > > > >> > > > > > Am 16.03.20, 14:41 schrieb "Etienne >> Robinet" < >> > 43...@etu.he2b.be>: >> > > > > > >> > > > > > Hi, >> > > > > > Ok I see, seems to be resolved once >> rebuilt. But >> > how does it come that it generates the getLengthInBits() before >> I updated >> > it? >> > > > > > >> > > > > > Etienne >> > > > > > On 2020/03/16 13:10:24, Christofer Dutz >> < >> > christofer.d...@c-ware.de> wrote: >> > > > > > > Hi Etienne, >> > > > > > > >> > > > > > > it's there ... have a look: >> > > > > > > >> > >> https://github.com/apache/plc4x/blob/develop/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java >> > > > > > > >> > > > > > > The problem is that you checked out >> your fork. >> > That doesn't update automatically if someone pushes anything to >> our repo. >> > > > > > > You manually have to do that. >> > > > > > > >> > > > > > > Please check "Keeping your fork up to >> date" on >> > https://plc4x.apache.org/developers/contributing.html >> > > > > > > >> > > > > > > Hope that helps. >> > > > > > > >> > > > > > > Chris >> > > > > > > >> > > > > > > >> > > > > > > >> > > > > > > Am 16.03.20, 13:50 schrieb "Etienne >> Robinet" < >> > 43...@etu.he2b.be>: >> > > > > > > >> > > > > > > Hi Chris, >> > > > > > > >> > > > > > > buy how do I stop it from >> generating the >> > error? He calls the getLengthInBits on an implmentation of >> Message so that >> > is where the error happens (also the @Override). I checked the >> Message >> > interface and there is no such metho, also checked the >> pojo-template and >> > couldn't find the method. I did not had that before when >> generating sources >> > (I think since I ran some tests on the PLC). >> > > > > > > Etienne >> > > > > > > On 2020/03/16 12:46:48, >> Christofer Dutz < >> > christofer.d...@c-ware.de> wrote: >> > > > > > > > Hi Etienne, >> > > > > > > > >> > > > > > > > well the getLengthInBytes is >> still there >> > ... it just calls the getLengthInBits and divides that by 8. >> > > > > > > > The reason was that with the >> Firmata >> > driver we first had a protocol where the getLengthInBytes >> returned 0 >> > because one datatype didn't have a full multiple of 8 as >> content. This made >> > getLengthInBytes return 0 instead of 1. >> > > > > > > > >> > > > > > > > In general nothing should have >> changed as >> > the getLengthInBytes still exists. It's just that there is an >> additional >> > getLengthInBits. >> > > > > > > > >> > > > > > > > Chris >> > > > > > > > >> > > > > > > > >> > > > > > > > >> > > > > > > > >> > > > > > > > Am 16.03.20, 13:19 schrieb >> "Etienne >> > Robinet" <43...@etu.he2b.be>: >> > > > > > > > >> > > > > > > > Hi Chris, >> > > > > > > > >> > > > > > > > Thanks for the advice I >> will try to >> > find a way for that. >> > > > > > > > I tried executing some >> tests but I >> > realisedI got an error on runtime. After looking at the >> generated source, >> > this is what I have: >> > > > > > > > >> https://i.imgur.com/LflQvpw.png >> > > > > > > > Why does the >> getLengthInBytes method >> > got swapped by getLengthInBits? The error comes that he is >> looking for the >> > gteLengthInBits() on a Message, and the @Override is also wrong. >> > > > > > > > >> > > > > > > > Etienne >> > > > > > > > On 2020/03/16 11:46:53, >> Christofer >> > Dutz <christofer.d...@c-ware.de> wrote: >> > > > > > > > > Hi Etienne, >> > > > > > > > > >> > > > > > > > > well there must be some >> way to >> > distinguish the two ... perhaps using more than one field to >> discriminate >> > the types? >> > > > > > > > > >> > > > > > > > > Chris >> > > > > > > > > >> > > > > > > > > >> > > > > > > > > >> > > > > > > > > Am 16.03.20, 12:01 >> schrieb "Etienne >> > Robinet" <43...@etu.he2b.be>: >> > > > > > > > > >> > > > > > > > > Hi Chris, >> > > > > > > > > I will have a look to >> build the >> > tests for the parser/serializer. >> > > > > > > > > >> > > > > > > > > I have another >> question. In Cip >> > when data is too large and wont fit into a signle packet (>500 >> bytes), we >> > use fragmentedRequest. The problem I'm facing is: >> ReadFragmentedService and >> > UnconnectedRequest have the same service number 0x52. >> > > > > > > > > From the structure, >> the >> > UnconnectedRequest contains the fragmentedServiceRequest; but >> the responses >> > are at the same 'level' as the UnconnectedRequest. So I don't >> know for now >> > how to implement this and if we even need it (but I still find >> a good >> > option); >> > > > > > > > > >> > > > > > > > > Etienne >> > > > > > > > > On 2020/03/16 >> 10:35:34, >> > Christofer Dutz <christofer.d...@c-ware.de> wrote: >> > > > > > > > > > Hi Etienne, >> > > > > > > > > > >> > > > > > > > > > I would also >> suggest you have >> > a look at the unit-test framework I built for testing the >> parsers, >> > serializers and the model. >> > > > > > > > > > >> > > > > > > > > > >> > >> plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/S7DriverTestsuite.java >> > > > > > > > > > >> > >> plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml >> > > > > > > > > > >> > > > > > > > > > I'm currently still >> working on >> > an integration test-suite that will test the protocol component >> using >> > pre-defined messages: >> > > > > > > > > > >> > > > > > > > > > >> > >> plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/S7ParserSerializerTestsuite.java >> > > > > > > > > > >> > >> plc4j/drivers/s7/src/test/resources/testsuite/S7ParserSerializerTestsuite.xml >> > > > > > > > > > >> > > > > > > > > > But I wouldn't call >> that >> > production ready yet as I was distracted by other work and have >> to check >> > where I dropped the ball last time. >> > > > > > > > > > >> > > > > > > > > > Chris >> > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > > Am 16.03.20, 11:28 >> schrieb >> > "Etienne Robinet" <43...@etu.he2b.be>: >> > > > > > > > > > >> > > > > > > > > > Hi Chris, >> > > > > > > > > > this did also >> the trick >> > and looks far more clean, thanks for the help on that! >> > > > > > > > > > >> > > > > > > > > > I am now >> working on the >> > writing, might have a look on connected messages afterwards. >> The fact is >> > that now I'm doing home office so it will be a bit trickier to >> test, but I >> > might get a solution in the following days. >> > > > > > > > > > Stay safe, >> > > > > > > > > > >> > > > > > > > > > Etienne >> > > > > > > > > > On 2020/03/13 >> 17:09:06, >> > Christofer Dutz <christofer.d...@c-ware.de> wrote: >> > > > > > > > > > > Hi Etienne, >> > > > > > > > > > > >> > > > > > > > > > > I just took >> the version >> > before your last commit and applied the pattern how you pass >> along the >> > arguments. >> > > > > > > > > > > Please have a >> look ... I >> > haven't compiled the spec, but it should work. As you can see, >> if you want >> > to use the >> > > > > > > > > > > arguments >> inside a >> > sub-type, you have to re-declare the variable (identical name >> and type) in >> > the sub-type. >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > // >> > > > > > > > > > > // Licensed >> to the >> > Apache Software Foundation (ASF) under one >> > > > > > > > > > > // or more >> contributor >> > license agreements. See the NOTICE file >> > > > > > > > > > > // >> distributed with >> > this work for additional information >> > > > > > > > > > > // regarding >> copyright >> > ownership. The ASF licenses this file >> > > > > > > > > > > // to you >> under the >> > Apache License, Version 2.0 (the >> > > > > > > > > > > // >> "License"); you may >> > not use this file except in compliance >> > > > > > > > > > > // with the >> License. >> > You may obtain a copy of the License at >> > > > > > > > > > > // >> > > > > > > > > > > // >> > http://www.apache.org/licenses/LICENSE-2.0 >> > > > > > > > > > > // >> > > > > > > > > > > // Unless >> required by >> > applicable law or agreed to in writing, >> > > > > > > > > > > // software >> distributed >> > under the License is distributed on an >> > > > > > > > > > > // "AS IS" >> BASIS, >> > WITHOUT WARRANTIES OR CONDITIONS OF ANY >> > > > > > > > > > > // KIND, >> either express >> > or implied. See the License for the >> > > > > > > > > > > // specific >> language >> > governing permissions and limitations >> > > > > > > > > > > // under the >> License. >> > > > > > > > > > > // >> > > > > > > > > > > >> > > > > > > > > > > >> > >> ////////////////////////////////////////////////////////////////// >> > > > > > > > > > > >> ///EthernetIP Header of >> > size 24 >> > > > > > > > > > > >> > >> ///////////////////////////////////////////////////////////////// >> > > > > > > > > > > >> > > > > > > > > > > >> [discriminatedType >> > 'EipPacket' >> > > > > > > > > > > >> [discriminator uint >> > 16 'command'] >> > > > > > > > > > > >> [implicit uint >> > 16 'len' 'lengthInBytes - 24'] >> > > > > > > > > > > [simple >> uint >> > 32 'sessionHandle'] >> > > > > > > > > > > [simple >> uint >> > 32 'status'] >> > > > > > > > > > > [array >> uint >> > 8 'senderContext' count '8'] >> > > > > > > > > > > [simple >> uint >> > 32 'options'] >> > > > > > > > > > > >> [typeSwitch 'command' >> > > > > > > > > > > >> ['0x0065' >> > EipConnectionRequest >> > > > > > > > > > > >> [const >> > uint 16 'protocolVersion' '0x01'] >> > > > > > > > > > > >> [const >> > uint 16 'flags' '0x00'] >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0x0066' >> > EipDisconnectRequest >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0x006F' >> > CipRRData [uint 16 'len'] >> > > > > > > > > > > >> > [reserved uint 32 '0x00000000'] >> > > > > > > > > > > >> > [reserved uint 16 '0x0000'] >> > > > > > > > > > > >> [simple >> > CipExchange 'exchange' ['len-6']] >> > > > > > > > > > > ] >> > > > > > > > > > > ] >> > > > > > > > > > > ] >> > > > > > > > > > > [type >> 'CipExchange' >> > [uint 16 'exchangeLen'] >> > > > > > > > > > > [const >> > uint 16 'itemCount' '0x0002'] //2 >> items >> > > > > > > > > > > [const >> > uint 32 'nullPtr' '0x0'] >> > //NullPointerAddress >> > > > > > > > > > > [const >> > uint 16 'UnconnectedData' '0x00B2'] >> //Connection Manager >> > > > > > > > > > > [implicit >> > uint 16 'size' 'lengthInBytes - 8 - >> 2'] >> > //remove fields above and routing >> > > > > > > > > > > [simple >> > CipService 'service' ['exchangeLen - 10'] ] >> > > > > > > > > > > ] >> > > > > > > > > > > >> > > > > > > > > > > >> [discriminatedType >> > 'CipService' [uint 16 'serviceLen'] >> > > > > > > > > > > >> [discriminator >> > uint 8 'service'] >> > > > > > > > > > > >> [typeSwitch 'service' >> > > > > > > > > > > >> ['0x4C' >> > CipReadRequest >> > > > > > > > > > > >> [simple >> > int 8 'RequestPathSize'] >> > > > > > > > > > > >> [array >> > int 8 'tag' length '(RequestPathSize*2)'] >> > > > > > > > > > > >> [simple >> > uint 16 'elementNb'] >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0xCC' >> > CipReadResponse [uint 16 'serviceLen'] >> > > > > > > > > > > >> [reserved >> > uint 8 '0x00'] >> > > > > > > > > > > >> [simple >> > uint 8 'status'] >> > > > > > > > > > > >> [simple >> > uint 8 'extStatus'] >> > > > > > > > > > > >> [enum >> > CIPDataTypeCode 'dataType'] >> > > > > > > > > > > >> [array >> > int 8 'data' length 'serviceLen-6'] >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0x0A' >> > MultipleServiceRequest [uint 16 'serviceLen'] >> > > > > > > > > > > >> [const >> > int 8 'RequestPathSize' '0x02'] >> > > > > > > > > > > >> [const >> > uint 32 'RequestPath' '0x01240220'] //Logical >> Segment: >> > Class(0x20) 0x02, Instance(0x24) 01 (Message Router) >> > > > > > > > > > > >> [simple >> > Services 'data' ['serviceLen - 6 ']] >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0x8A' >> > MultipleServiceResponse [uint 16 'serviceLen'] >> > > > > > > > > > > >> > [reserved uint 8 '0x0'] >> > > > > > > > > > > >> [simple >> > uint 8 'status'] >> > > > > > > > > > > >> [simple >> > uint 8 'extStatus'] >> > > > > > > > > > > >> [simple >> > Services 'data' ['serviceLen - 4']] >> > > > > > > > > > > ] >> > > > > > > > > > > >> ['0x0052' >> > CipUnconnectedRequest >> > > > > > > > > > > >> > [reserved uint 8 '0x02'] >> > > > > > > > > > > >> > [reserved uint 8 '0x20'] // >> setRequestPathLogicalClassSegment >> > > > > > > > > > > >> > [reserved uint 8 '0x06'] // set request class path >> > > > > > > > > > > >> > [reserved uint 8 '0x24'] // >> setRequestPathLogicalInstanceSegment >> > > > > > > > > > > >> > [reserved uint 8 '0x01'] // setRequestPathInstance >> > > > > > > > > > > >> > [reserved uint 16 '0x9D05'] //Timeout 5s >> > > > > > > > > > > >> > [implicit uint 16 'messageSize' 'lengthInBytes - 10 - >> 4'] >> > //substract above and routing >> > > > > > > > > > > >> [simple >> > CipService 'service'] >> > > > > > > > > > > >> [const >> > uint 16 'route' '0x0001'] >> > > > > > > > > > > >> [simple >> > int 8 'backPlane'] >> > > > > > > > > > > >> [simple >> > int 8 'slot'] >> > > > > > > > > > > ] >> > > > > > > > > > > ] >> > > > > > > > > > > ] >> > > > > > > > > > > >> > > > > > > > > > > [type >> 'Services' >> > [uint 16 'servicesLen'] >> > > > > > > > > > > [simple >> uint 16 >> > 'serviceNb'] >> > > > > > > > > > > [array >> uint >> > 16 'offsets' count 'serviceNb'] >> > > > > > > > > > > [array >> CipService >> > 'services' count 'serviceNb' ['servicesLen/serviceNb'] ] >> > > > > > > > > > > ] >> > > > > > > > > > > >> > > > > > > > > > > [enum uint >> 16 >> > 'CIPDataTypeCode' [uint 8 'size'] >> > > > > > > > > > > >> ['0X00C1' BOOL >> > ['1']] >> > > > > > > > > > > >> ['0X00CA' REAL >> > ['4']] >> > > > > > > > > > > >> ['0X00C4' DINT >> > ['4']] >> > > > > > > > > > > >> ['0X00C3' INT >> > ['2']] >> > > > > > > > > > > >> ['0X00C2' SINT >> > ['1']] >> > > > > > > > > > > ['0X02A0' >> > STRUCTURED ['88']] >> > > > > > > > > > > >> ['0X02A0' STRING >> > ['88']] >> > > > > > > > > > > ['0X02A0' >> > STRING36 ['40']] >> > > > > > > > > > > ['-1' >> UNKNOWN >> > ['-1']] >> > > > > > > > > > > ] >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > Hope that >> helps, >> > > > > > > > > > > Chris >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > Am 13.03.20, >> 17:09 >> > schrieb "Etienne Robinet" <43...@etu.he2b.be>: >> > > > > > > > > > > >> > > > > > > > > > > Hi all, >> > > > > > > > > > > sorry for >> > double-posting, but I found the fix. For me the code does not >> look that >> > 'sexy' now but it works. I do not know if I can make it better >> but for now >> > I will stick to this :) I pushed it to the 'eip' branch of my >> fork. >> > > > > > > > > > > Have a >> nice weekend, >> > > > > > > > > > > >> > > > > > > > > > > Etienne >> > > > > > > > > > > On >> 2020/03/13 >> > 14:48:35, Etienne Robinet <43...@etu.he2b.be> wrote: >> > > > > > > > > > > > Hi, >> > > > > > > > > > > > Thanks >> for the >> > advice. I am trying to pass the length down the subclasses, but >> I'm stuck. >> > This does not work as it seems: >> > > > > > > > > > > > >> > https://i.imgur.com/77bbdBN.png CipRRData does not know what >> 'len' is nor >> > its value as it seems. >> > > > > > > > > > > > >> > > > > > > > > > > > I >> wanted to >> > inspire mysefl from the CotpPayload, but unfortunately, the >> first byte of >> > the whole packet is a discriminator (command). >> > > > > > > > > > > > >> > > > > > > > > > > > Etienne >> > > > > > > > > > > > On >> 2020/03/13 >> > 13:52:16, Christofer Dutz <christofer.d...@c-ware.de> wrote: >> > > > > > > > > > > > > Hi >> Etienne, >> > > > > > > > > > > > > >> > > > > > > > > > > > > I >> think you can >> > solve your problem in two ways. >> > > > > > > > > > > > > In >> all you need >> > to pass down the length of the packet in total from the root >> type (which >> > knows the length). >> > > > > > > > > > > > > 1) >> You keep on >> > just reading bytes and parse in the protocol logic class (Like >> in the S7 >> > driver or KNX) >> > > > > > > > > > > > > 2) >> You directly >> > parse PlcValues (using "dataIo" types) >> > > > > > > > > > > > > >> > > > > > > > > > > > > I >> would prefer >> > option 2 but 1 is simpler. The reason I'm doing 1) in S7 and >> KNX is that I >> > need to know the type from the request to decode in the S7 case >> and in the >> > KNX case I need to know the type from an external source in >> order to decode >> > it. >> > > > > > > > > > > > > >> > > > > > > > > > > > > >> > > > > > > > > > > > > Chris >> > > > > > > > > > > > > >> > > > > > > > > > > > > Am >> 13.03.20, >> > 14:45 schrieb "Etienne Robinet" <43...@etu.he2b.be>: >> > > > > > > > > > > > > >> > > > > > > > > > > > > >> Yes this is >> > exactly what I need. If I get the remaining bytes, I can know >> the element >> > numbers as I have their type! >> > > > > > > > > > > > > >> > > > > > > > > > > > > >> Etienne >> > > > > > > > > > > > > >> > > > > > > > > > > > > On >> > 2020/03/13 13:40:09, Julian Feinauer < >> j.feina...@pragmaticminds.de> >> > wrote: >> > > > > > > > > > > > > > >> Hey, >> > > > > > > > > > > > > > >> > > > > > > > > > > > > > >> there ist >> > he possibility to get the remaining size oft he bytes of the >> message. Does >> > that help? >> > > > > > > > > > > > > > >> Otherwise >> > I misread your question. >> > > > > > > > > > > > > > >> > > > > > > > > > > > > > >> Julian >> > > > > > > > > > > > > > >> > > > > > > > > > > > > > >> Am >> > 13.03.20, 14:37 schrieb "Etienne Robinet" <43...@etu.he2b.be>: >> > > > > > > > > > > > > > >> > > > > > > > > > > > > >> > Hi >> > Julian, >> > > > > > > > > > > > > >> > so how >> > should I declare this field in the mspec if I can not get its >> size? >> > > > > > > > > > > > > >> > Thank >> > you, >> > > > > > > > > > > > > > >> > > > > > > > > > > > > >> > Etienne >> > > > > > > > > > > > > > >> > > > > > > > > > > > > >> > On >> > 2020/03/13 13:35:52, Julian Feinauer < >> j.feina...@pragmaticminds.de> >> > wrote: >> > > > > > > > > > > > > >> > > Hi >> > Etienne, >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > first, Congratulations on your Progress! >> > > > > > > > > > > > > >> > > To >> > you question: >> > > > > > > > > > > > > >> > > This >> > is a common issue with many protocols. >> > > > > > > > > > > > > >> > > We >> > solve that in the protocol layer by keeping the request until >> we get the >> > response (see for Example how we did it for S7). >> > > > > > > > > > > > > >> > > So >> > you cannot solve that in mpsec at compile time but have to >> decode the >> > byte[] you get with the Information from the Request. >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > Hope >> > that helps! >> > > > > > > > > > > > > >> > > >> > Julian >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > Am >> > 13.03.20, 14:02 schrieb "Etienne Robinet" <43...@etu.he2b.be>: >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > Hi Chris, >> > > > > > > > > > > > > >> > > >> > I have yet another question. When sending a request for >> multiple elements >> > (let's say 10 elements of an array), you get a response from >> the PLC with >> > all the data at the end of the packet. The problem is, in the >> request there >> > is the number of elements we want, but not in the response. So >> so the >> > protocol knows how many elements there are in the response >> packet, but not >> > the packet itself. This is quite a problem as for the parse, we >> need to >> > know the length of the 'data' array containing the response >> data (for now >> > it was only depending on the type, but I would need >> type*elements). >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > I tested a bit by modifying the generated IO, and 1 way to do >> it is to get >> > the remaining bytes and divide this by the datatype size. I >> just wanted to >> > ask if someone would know how to declare this in the mspec, as >> I don't want >> > to touch at the template. I also thought about having an >> attribute on the >> > response, but I don't know how to put an attribute that won't >> get >> > parsed/serialized. Hope I am clear enough, but this is a code >> sample that >> > worked (modifying generated sources): >> > > > > > > > > > > > > >> > > >> > https://i.imgur.com/Xm6DxEZ.png (notice the error but this >> code works if >> > I write it myself) >> > > > > > > > > > > > > >> > > >> > And here is how I put it in the mspec: >> https://i.imgur.com/Ye1Kl9q.png >> > (you can see the number of element is not present) >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > Any help is welcome of course! :) >> > > > > > > > > > > > > >> > > >> > Etienne >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > On 2020/03/12 21:34:12, Christofer Dutz < >> christofer.d...@c-ware.de> >> > wrote: >> > > > > > > > > > > > > >> > > >> > > Hi Etienne, >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > that's amazing news :-) ... congratulations :-) >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Also had a look at your mspec and I think you have done a >> great job with >> > that. I wasn't quite sure about the relation between CipRRData >> and >> > CipExchange, but your solution looks rock-solid. >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > And now reading that you even managed to get something >> working, that >> > makes me very happy. >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Tomorrow I'll be a little consumed with signing the contract >> with the >> > KNX foundation but I'll try to have a look at your fork. >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Thanks for your great work :) >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Chris >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Am 12.03.20, 17:50 schrieb "Etienne Robinet" < >> 43...@etu.he2b.be>: >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Hi all, >> > > > > > > > > > > > > >> > > >> > > again a productive day, I pushed to my branch and the >> driver support >> > reading, multiple reading and the camel component works (in >> karaf) and >> > takes a List of strings. Tested it on a different PLC and it >> also worked! >> > Next I'm going to implement the array readings and then maybe >> writing >> > (tests needs to be done too). >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > Etienne >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > On 2020/03/12 07:18:32, Etienne Robinet < >> 43...@etu.he2b.be> wrote: >> > > > > > > > > > > > > >> > > >> > > > Hi Chris, >> > > > > > > > > > > > > >> > > >> > > > yes that's what I thought so I managed to work around >> like this: >> > > > > > > > > > > > > >> > > >> > > > >> > > > > > > > > > > > > >> > > >> > > > >> > >> https://github.com/etiennerobinet/plc4x/blob/eip/protocols/eip/src/main/resources/protocols/eip/eip.mspec >> > > > > > > > > > > > > >> > > >> > > > >> > > > > > > > > > > > > >> > > >> > > > And this works for reading! I managed to make a quick >> test and >> > read via the tag name. Now my question is: can I create >> sub-types that are >> > also discriminated with sub-subtypes? That would allow to >> create the >> > ReadRequest only, as the fields before are mainly >> constant/implicit. >> > > > > > > > > > > > > >> > > >> > > > Etienne >> > > > > > > > > > > > > >> > > >> > > > >> > > > > > > > > > > > > >> > > >> > > > On 2020/03/11 20:24:14, Christofer Dutz < >> > christofer.d...@c-ware.de> wrote: >> > > > > > > > > > > > > >> > > >> > > > > Hi Etienne, >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > you are defining the type CipRRData twice ... once >> as one of the >> > sub-types of EipPacket and once as a dedicated discriminated >> type. >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > Chris >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > PS: I have no idea why I didn't finish writing this >> email and I >> > just noticed when closing everything down ... sorry for the >> late reply. >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > Am 11.03.20, 09:30 schrieb "Etienne Robinet" < >> 43...@etu.he2b.be >> > >: >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > Hi all, >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > I have a quick question. I've been working on >> the CIP >> > encapsulation but hitting a problem with the mspec design. Here >> is the >> > error I am facing: https://i.imgur.com/iCfh59n.png >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > The problem here is that this CipRRData should >> also be of >> > type EipPacket. When the command of an EipPacket is '0x66' this >> means >> > SendRRData (for Read/Write and Request/Response so I have to >> discriminate >> > it on the sub level). The problem is that after generation, >> CipRRData >> > implements Message but does not extend EipPacket. How should I >> do it? Here >> > is the mspec: >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > [discriminatedType 'EipPacket' >> > > > > > > > > > > > > >> > > >> > > > > [discriminator uint 16 'command'] >> > > > > > > > > > > > > >> > > >> > > > > [implicit uint 16 'len' 'lengthInBytes >> - 24'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 32 'sessionHandle'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 32 'status'] >> > > > > > > > > > > > > >> > > >> > > > > [array uint 8 'senderContext' count >> '8'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 32 'options'] >> > > > > > > > > > > > > >> > > >> > > > > [typeSwitch 'command' >> > > > > > > > > > > > > >> > > >> > > > > ['0x0065' EipConnectionRequest >> > > > > > > > > > > > > >> > > >> > > > > [const uint 16 >> 'protocolVersion' >> > '0x01'] >> > > > > > > > > > > > > >> > > >> > > > > [const uint 16 'flags' >> > '0x00'] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ['0x0066' EipDisconnectRequest >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ['0x006F' CipRRData >> > > > > > > > > > > > > >> > > >> > > > > [const uint 32 >> 'EipInterface' >> > '0x00000000'] >> > > > > > > > > > > > > >> > > >> > > > > [const uint 8 'timeout' >> '0x0000'] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > [discriminatedType 'CipRRData' >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 8 'itemNb'] >> > > > > > > > > > > > > >> > > >> > > > > [array CipItem 'items' >> length 'itemNb'] >> > > > > > > > > > > > > >> > > >> > > > > [discriminator uint 8 >> 'CipService'] >> > > > > > > > > > > > > >> > > >> > > > > [typeSwitch 'CipService' >> > > > > > > > > > > > > >> > > >> > > > > ['0x52' CipUnconnectedRequest >> > > > > > > > > > > > > >> > > >> > > > > [simple CommandData 'data'] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ['0xCC' CipReadResponse >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 >> '0x0000'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 8 >> 'status'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 8 >> 'extStatus'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 8 >> 'dataType'] >> > > > > > > > > > > > > >> > > >> > > > > [array uint 8 >> 'data' length >> > 'dataType'] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > [type 'CipItem' >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 16 'typeID'] >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 16 'size'] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > [discriminatedType 'CommandData' >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x02'] >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x20'] // >> > setRequestPathLogicalClassSegment >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x06'] // >> set request >> > class path >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x24'] // >> > setRequestPathLogicalInstanceSegment >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x01'] // >> > setRequestPathInstance >> > > > > > > > > > > > > >> > > >> > > > > [discriminator uint 8 'CipService'] >> > > > > > > > > > > > > >> > > >> > > > > [typeSwitch 'CipService' >> > > > > > > > > > > > > >> > > >> > > > > ['0x4C' CipReadRequest >> > > > > > > > > > > > > >> > > >> > > > > [simple uint 8 >> 'RequestPathSize'] >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 8 '0x91'] >> > > > > > > > > > > > > >> > > >> > > > > [array uint 8 'tag' >> length >> > '(RequestPathSize*2) - 1'] >> > > > > > > > > > > > > >> > > >> > > > > [reserved uint 16 '0x0001'] >> //itemCount >> > set to 1 for now >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > [enum int 16 'CIPDataTypeCode' [uint 8 >> 'size'] >> > > > > > > > > > > > > >> > > >> > > > > ['0X00C1' BOOL ['1']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X00CA' REAL ['4']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X00C4' DINT ['4']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X00C3' INT ['2']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X00C2' SINT ['1']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X02A0' STRUCTURED ['88']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X02A0' STRING ['88']] >> > > > > > > > > > > > > >> > > >> > > > > ['0X02A0' STRING36 ['40']] >> > > > > > > > > > > > > >> > > >> > > > > ['-1' UNKNOWN ['-1']] >> > > > > > > > > > > > > >> > > >> > > > > ] >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > Thanks for any help! >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > Etienne >> > > > > > > > > > > > > >> > > >> > > > > On 2020/03/10 15:18:47, Etienne Robinet < >> 43...@etu.he2b.be> >> > wrote: >> > > > > > > > > > > > > >> > > >> > > > > > Hi all, >> > > > > > > > > > > > > >> > > >> > > > > > I've managed to implement the EIP Session >> > Register/Unregister (used for connected message which is best >> for high >> > frequency fetching). I will push it to my branch and create a >> document >> > explaining my steps. >> > > > > > > > > > > > > >> > > >> > > > > > Next I want to do was to to the CIP >> encapsulation part for >> > accessing tag by their name. The thing is, CIP is (from what I >> heard) >> > proper to Allen Bradley. Should I leave it in the EIP driver or >> modify and >> > adapt the current AB driver later on? For now I will continue >> on eip. >> > > > > > > > > > > > > >> > > >> > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > Etienne >> > > > > > > > > > > > > >> > > >> > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > On 2020/03/10 14:41:42, Cesar Garcia < >> > cesar.gar...@ceos.com.ve> wrote: >> > > > > > > > > > > > > >> > > >> > > > > > > Hi, >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > You can document the process step by step, >> you will >> > surely find observation >> > > > > > > > > > > > > >> > > >> > > > > > > points. >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > I am working with the handwritten S7 driver, >> but in the >> > future I would >> > > > > > > > > > > > > >> > > >> > > > > > > support the team in migrate to mspec, so the >> experience >> > you will gain with >> > > > > > > > > > > > > >> > > >> > > > > > > the Etheret / IP is very important. >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > Best regards, >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > El mar., 10 mar. 2020 a las 9:17, Christofer >> Dutz (< >> > > > > > > > > > > > > >> > > >> > > > > > > christofer.d...@c-ware.de>) escribió: >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > Hi Etienne, >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > I would strongly suggest you install the >> Antlr plugn >> > for the IDE you use. >> > > > > > > > > > > > > >> > > >> > > > > > > > The problem is that ANTLR seems to gobble >> up a lot of >> > errors and tries to >> > > > > > > > > > > > > >> > > >> > > > > > > > be smart in a lot of cases. >> > > > > > > > > > > > > >> > > >> > > > > > > > Whenever I have problems like this I use >> the ANTLR >> > visual parser to parse >> > > > > > > > > > > > > >> > > >> > > > > > > > a block of mspec (one type at a time) and >> try to >> > narrow down the cause. >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > Chris >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > Am 10.03.20, 13:31 schrieb "Etienne >> Robinet" < >> > 43...@etu.he2b.be>: >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > Hi all, >> > > > > > > > > > > > > >> > > >> > > > > > > > I've been struggling with implementing >> the EIP >> > driver. I started >> > > > > > > > > > > > > >> > > >> > > > > > > > writing the mspec after creating both a >> module for the >> > protocol and the one >> > > > > > > > > > > > > >> > > >> > > > > > > > from the driver. I copied and adapted the >> pom(s) from >> > the AB-ETH but only >> > > > > > > > > > > > > >> > > >> > > > > > > > the enum is generated. >> > > > > > > > > > > > > >> > > >> > > > > > > > Here is a link to the forked branch: >> > > > > > > > > > > > > >> > > >> > > > > > > > >> https://github.com/etiennerobinet/plc4x/tree/eip >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > I've been studying the EIP/CIP >> protocol and now I >> > am confident what >> > > > > > > > > > > > > >> > > >> > > > > > > > the packages should contain but I can not >> figure out >> > how to generate this >> > > > > > > > > > > > > >> > > >> > > > > > > > with the templates. Am I missing something? >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > Etienne >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > -- >> > > > > > > > > > > > > >> > > >> > > > > > > *CEOS Automatización, C.A.* >> > > > > > > > > > > > > >> > > >> > > > > > > *GALPON SERVICIO INDUSTRIALES Y NAVALES FA, >> C.A.,* >> > > > > > > > > > > > > >> > > >> > > > > > > *PISO 1, OFICINA 2, AV. RAUL LEONI, SECTOR >> GUAMACHITO,* >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > *FRENTE A LA ASOCIACION DE >> GANADEROS,BARCELONA,EDO. >> > ANZOATEGUI* >> > > > > > > > > > > > > >> > > >> > > > > > > *Ing. César García* >> > > > > > > > > > > > > >> > > >> > > > > > > *Cel: 0416-681.03.99* >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > *Cel: 0414-760.98.95* >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > *Hotline Técnica SIEMENS: 0800 1005080* >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > > *Email: support.aan.automat...@siemens.com >> > > > > > > > > > > > > >> > > >> > > > > > > <support.aan.automat...@siemens.com>* >> > > > > > > > > > > > > >> > > >> > > > > > > >> > > > > > > > > > > > > >> > > >> > > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > > >> > > > > > > > > > > > > >> > > >> > > > >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > >> > > >> > > > > > > > > > > > > > >> > > > > > > > > > > > > > >> > > > > > > > > > > > > > >> > > > > > > > > > > > > >> > > > > > > > > > > > > >> > > > > > > > > > > > > >> > > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > > >> > > > > > > > > >> > > > > > > > > >> > > > > > > > > >> > > > > > > > >> > > > > > > > >> > > > > > > > >> > > > > > > >> > > > > > > >> > > > > > > >> > > > > > >> > > > > > >> > > > > > >> > > > > >> > > > >> > > > >> > > > >> > > >> > > >> > > >> > >> > >> > >> >> >> >> >>