reciving data from Conductometer (RS232)


mukrainc

Recommended Posts

Dear sirs,

I have DaQ factory BASE, and have some problems in communicating with instrument: Conductometer.

I conected via serial rs-232 and define its parameters (follow the manual).

I can see in Monitor that my data is coming in the form:

Rx: 0.008\230S/cm 20.8\248C 19:27:57 STAB 1310

Rx: 0.008\230S/cm 20.8\248C 19:28:02 STAB 1310

Rx: 0.008\230S/cm 20.8\248C 19:28:06 STAB 1310

Rx: 0.008\230S/cm 20.8\248C 19:28:11 STAB 1310

where 0.008 is the value of conductivity (which i must have for PID regulation).

I assume that i can use Null protocol.

But,

When I add channel: device type is com(which I named) and I/O is A to D which is only present.

Why I can not see my data comming in channel, in tabel???? Nothing is happening!!

Please help me to solve this relativle simple task!

What am I doing wrong?

Link to comment
Share on other sites

Like many computer tasks, like speech recognition, things that are really easy to do for a human are a bit harder to tell a computer how to do. In this case its no where near as hard as speech recognition, but you do have to do more than simply expect the computer to pull out the number you want. This is in no way a standard protocol and so requires you to tell the computer how to parse the data. The problem here is that your data stream doesn't have an end of line delimiter, only mid-line delimiters. To get around this, we'll have to use the \248 as an end of line delimiter and assume that the date / STAB 1310 is a fixed length field. We'll need to create a sequence for this:

private string datain
device.com.purge() // clear anything accumulated
while(1)
   try
	  readuntil(248)
	  read(20) // read the "C 19:27:57 STAB 1310"
	  datain = readuntil(230)
	  mychannel.addvalue(strtodouble(datain))
   catch() 
	  ? strLastError
	  delay(0.1)
	  device.com.purge()	  
   endcatch
endwhile

We can't simply do readuntil(230) because we don't know where we start, so we readuntil 248, throwing away anything that is returned, then read the next 20 characters, throwing that at. Then we know we are at the number we want, so we readuntil 230 to get the value, convert it to a number and stick it in our mychannel channel. Note we don't put a delay() in the loop because the system will pause at the readuntil() waiting for new data. We do, however, put a delay() in the catch(), otherwise if you have a typo that causes an error in the first line, you will get an infinite loop.

With the next release, we will have a protocol for doing delimited inputs without having to do any scripting, but unfortunately your protocol is unique and that protocol probably won't work. But that's why we have the scripting power of DAQFactory. There are many common devices, but inevitably the one you want to use uses some weird proprietary protocol like this one.

Link to comment
Share on other sites

Thank you for your reply.

If I understand correctly:

I must add new sequence, named it (Cond) and write the code.

Do I still have to configure device (serial port), or just write the code in sequence.

However,

when I apply&compile the the green alert is shown:

C1000 Channel or fuction not found: Cond Line 5

At line 5 is readuntil(248)?

Link to comment
Share on other sites

Yes, you need to configure a device. In this case I assumed you called it com. However, I then was typing too fast and forgot to put the full specifiers in for readuntil. The correct code should be:

private string datain
device.com.purge() // clear anything accumulated
while(1)
   try
	  device.com.readuntil(248)
	  device.com.read(20) // read the "C 19:27:57 STAB 1310"
	  datain = device.com.readuntil(230)
	  mychannel.addvalue(strtodouble(datain))
   catch()
	  ? strLastError
	  delay(0.1)
	  device.com.purge()	  
   endcatch
endwhile

Link to comment
Share on other sites

Super, I did it and it works.

Now, I wont to extract another value from given data, which is temperature.

20.8 is temperature value in oC. How can i extract this value in, for instance, mychannel2?

Ofcourse, this have to be done simultenuilsly with conductivity (pulling two parameters fom conductometer)!

You have been very helpfull.

Thanks,

Best regards!

Link to comment
Share on other sites

OK. Well first let me repeat that who ever wrote this protocol obviously didn't know what they were doing as it is a particularly unreliable protocol to parse as there are few good delimiters and they are located in weird places. Anyhow...

private string datain
device.com.purge() // clear anything accumulated
device.com.readuntil(248) // locate us for the first round
while(1)
   try
	  device.com.read(20) // read the "C 19:27:57 STAB 1310"
	  datain = device.com.readuntil(230)
	  mychannel.addvalue(strtodouble(datain))
	  device.com.read(4) // read the S/cm
	  datain = device.com.readuntil(248)
	  mychannel2.addvalue(strtodouble(datain))
   catch()
	  ? strLastError
	  delay(0.1)
	  device.com.purge()	  
   endcatch
endwhile

The problem is that if the units change to something that doesn't take 4 characters, or the whole "C 19:27:57 STAB 1310" part changes length, the above code will break. They should have made the string look more like this:

0.008S/cm\230 20.8C\248 19:27:57\248 STAB 1310\248

I say this since I know a number of you are actually designing protocols. You want to put the delimiters after the units because most programming languages (include C and DAQFactory) will throw away the units when reading the number. So, strtodouble("0.008S/cm") will return 0.008, but strtodouble("S/cm 20.8") will return NaN or not a number because it starts with a character. Notice how I put a delimiter after each field, not in the middle of the field.

That said, its possible that this protocol is fixed field length, in which case we could have done things a bit different, but since you didn't provide documentation I have to assume that it was not.

Link to comment
Share on other sites

  • 3 years later...

I've been studying this thread a little, and it looks to have what I can use. So, a few questions, if you don't mind.

I made a device called Send_Witts, using the Null protocol. But I have been having alot of fun trying to parse the data into DF channels. I can send-write to the port just fine, but am having great difficulty parsing the wits data stream.

what does device.send_witts.purge() do exactly?

Is this important? To puge the device? Why?

device.com.read(20) // read the "C 19:27:57 STAB 1310"

In the manual, I understood that read(20) was read 20 bytes, but does the read(20) mean read 20

characters, where spaces are included into the 20? Are bytes and letters interchangeable? What about

13 , is that 4 characters? Or only 3?

datain = device.com.readuntil(230)

Do I understand, that the readuntil(230) takes everything after the read(20) untill, BUT NOT INCLUDING the 230? And defines the string datain?

mychannel.addvalue(strtodouble(datain))

Does this take the string datain, and covert it to a number(strtodouble function) and put that number into

mychannel?

Finally, a question about the parse function. Since wits echoes, whatever was sent to it, before it streams back data. Can I do this:

datain = device.send_witts.readuntil(X)

where X would equal to total # of characters and spaces in the RX: stream?

And then could I parse the wits like so?

mychannel.addvalue.parse(datain,4,1234,013) ?

Where mychannel needs to be the number in between the wits code 1234 and chr(13) in the RX stream?

or should it be:

mychannel.addvalue.parse(datain,4,013,1234)?

or neither?

So for example, I want to get 578.34 from a part of datain that looks like this:" 1234578.341310 "

and put it into mychannel.

In DF channels, do I select send_wits for device, and have A to D? for "mychannel?

I'm sure I'm still missing something, but does this sound like it could work? :blink:

Link to comment
Share on other sites

OK, lots of questions, lots of answers:

1) purge(): this function clears any queued up data on the comm port. Most communications expects some sort of frame, either a command and response (like Modbus), or simply streaming data (which I believe WITS is if I remember correctly). But even with streaming data, there is the beginning of a packet of data and an end. Purge() ensures that we are processing data in the serial port starting at this instant, and not data that might have come through previously that we just never got to. This is important, if for no other reason than if you unplug a serial device and plug it back in, you'll often get a few bytes of garbage (or 0's) that you don't want to process.

2) in standard ASCII, a character is a byte, so are interchangeable. There are multibyte character sets, such as Unicode, but I've never seen them used in serial communications. slash 013 (the real slash gets parsed by this forum, so I spelled it out), means ASCII code 13, or really just the byte with the value 13, so it is just one byte. It corresponds to a carriage return character.

3) readuntil(230) will start with whatever byte is in the queue (and read(20) will empty the queue of 20 bytes), and search for the byte with the value 230. If it can't find it, it will wait up to the timeout amount for that character to arrive. If it never arrives, you get a timeout exception. If it does, or was already in the queue, it will empty the queue up to that point (including the 230), and return everything up to, but not including the 230 character in a string. It doesn't "define" datain, but "assigns" the value to datain. Symantic details, I'm sorry... Also, remember a string is just a bunch of bytes stored in a single value. You can use the asca() function to break a string into an array of individual bytes, though for an ASCII protocol like WITS this is usually not desired.

4) mychannel.addvalue(strtodouble(datain)) does exactly what you described. strToDouble() will convert up to the first invalid character, so "123A45" gets converted to just 123. If the invalid character is the first character, "A1234", it will return NaN (Not a number)

5) No, parse doesn't work the way you think. For one thing, you can only parse on one character. You can't parse on the string "1234". To find the number right after 1234, you probably have to use the find() function, add 4 to the result (provided its not -1, meaning not found), then somehow figure out how many characters you need after that (6?). As I said in one of the previous posts in this thread, WITS isn't exactly the most well designed protocol, at least when it comes to writing easy parsing routines. They could have made some better choices and made it much simpler and more reliable to parse. In your example, I'm not sure if its always 6 characters, or you variable depending on the value. You may have to also search for 1310 and use the mid() function to extract the values between. Worse, what happens if 1310 doesn't follow 1234?

6) For channels, if send_wits is a device you created with NULL protocol, it won't have any I/O types. You can still create a channel that way, skip the I/O type, and just make sure the Timing is 0, then use AddValue() to stick data into the channel. Its no different than using a Test channel with Timing = 0 to do the same thing.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.