Random Musings of a Coffee Technologist

Jun 02

How to make Puni juice.
The newspaper in Atelier Meruru is great.

How to make Puni juice.

The newspaper in Atelier Meruru is great.

Adding Modbus Support to Typica - Day 9

There has been progress and things are just about ready to go out for testing. If adding hardware support for one or two devices was the only thing that I were doing that would have been done by now, but since I didn’t want to have to rip out the code for other changes that I wanted to make it’s taking a little longer. There isn’t really anything interesting to write about. It’s pretty straightforward implementation of a design. Just requires that I take the time to write it and that everybody else leaves me alone so I can maintain my focus. That last part can be challenging when you’re writing code in a coffee shop. Every so often I’ll read about some startup that has coders working out of coffee shops (hopefully they get up frequently for another drink or a snack from the bakery case instead of milking a small coffee for eight hours while taking up a table and leeching free WiFi) but a busy coffee shop is really a terrible environment for programming. Too many distractions. It won’t be long before I have something ready for others to test and it shouldn’t be long after that for a proper version 1.4 release. I’m not going to get 2.0 out by the time I had planned to (probably) so I’d like to get as much in the way of features that people were really waiting for into that release as I can.

In unrelated news it seems that my visa for entering Brazil is still valid. I’ll be going back next month traveling through some parts of the country that I haven’t been to previously. The food was really good the last time I was there and it looks like I’ll also be making a return trip to the roasting firm that has the hot pink roaster/afterburner/espresso machine and a bunch of barista competition trophies. The month after I’ll be back in the Pacific Northwest for the Roasters Guild retreat. I’ll probably have photos to share from both of those trips later.

Jun 01

Selecting from an enum

Yesterday I was working on the issue of bringing device configuration into Typica. In the case of devices that use a serial port, it’s not uncommon to need the ability to configure certain details of how communications on the port are handled. For example, you need to specify the baud rate. When doing this there are a finite number of valid values and these exist in an enum. If that enum is specified in a Q_ENUMS macro in a class declaration it’s possible to make a QComboBox that has the valid entries without writing code to add each by hand.

BaudSelector::BaudSelector(QWidget *parent) : QComboBox(parent)
{
    QMetaObject meta = BaudSelector::staticMetaObject;
    QMetaEnum type = meta.enumerator(meta.indexOfEnumerator("BaudRateType"));
    for(int i = 0; i < type.keyCount(); i++)
    {
        addItem(QString("%1").arg(type.value(i)));
    }
}

If you’d rather have as entries the name rather than the value of the enum but still have access to the value for later lookup, it’s just a matter of changing the call to addItem() to:

addItem(QString(type.key(i)), QVariant(type.value(i)));

May 31

Menacing rabbit will beat you with a carrot.

Menacing rabbit will beat you with a carrot.

Adding Modbus Support to Typica - Day 7

Device configuration in Typica 1.3 was pretty simple… for a programmer. In the script fragment for the logging window you would just instantiate the device, use its methods to configure the measurement channels, and hook those channels up to the various widgets that need the data. One of the changes planned for Typica 2.0 was getting rid that configuration system which. It was amazingly flexible and made it possible to implement new features or try out different ways of doing things much faster, but most people using the software don’t want to muck around with that (this is a completely reasonable position to take). Scriptability isn’t something that’s going away. My intent on the 2.0 branch is to make scripts less visible (no prompt every time the program is started) and more modular. It should be possible to write a file that adds a new feature and share that in such a way that people using the program can just install the new feature to live alongside their current configuration. I still don’t really expect people to do that, but it makes my life easier. Part of that transition requires moving device configuration out of script fragments and into the program proper with configuration widgets that can be adjusted from within the program and this has been partially back-ported to what will be the 1.4 release.

One of the interesting consequences of the current design is a more explicit separation of the devices measurements are coming from and the coffee roaster the devices are used with. Here’s how it works in the case of Modbus:

You have 1 or more Modbus devices in your roaster. These are, possibly through some sort of adapter, connected to your computer and the whole device network shows up as a serial port (COM9 in my case). You want to add these devices to your configuration so in Typica, you go to Device Configuration (don’t look for this in current releases, it’s not there, and don’t trust this with future releases, I’ll make real documentation once there’s a release out), add Modbus RTU devices. First you’ll be able to specify which serial port that’s on. If the devices are connected when you bring this up it will auto-detect all of your serial ports. A lot of laptops don’t have old style serial ports these days and if you don’t have anything else connected, your adapter to these devices might be the only port there is and would already be selected. If you’re not connected but know what port the devices are on, you can just type that in. If you have no clue at all but somehow are able to do the rest, you can just select whatever and change the port settings when you do know what they are. You can also select the baud rate and other details that must be common across all devices on that port. If you carry that laptop around to several roasters and different devices show up on the same port depending on where you are, don’t worry. Typica isn’t going to complain about port conflicts because it’s smart enough (or rather too dumb to care or perhaps just trusting that the person using the software knows what they’re doing and that the software should just shut up and do as its told) to let you configure duplicate ports with different devices.

Now you have your port configured. You probably only have one device on the port (if you have more, just repeat this step until you’ve covered them all), so go ahead and add a device to the port. I’m starting with just a generic device that takes further configuration options but intend to add more options which are built on top of that but provide information that must be configured in the case of generic devices. For example, someone with a Fuji PXR series device will be able to select that, specify the station number for the device, and their device configuration will be finished. In the case of a generic device, however, you’ll need to further specify the relative addresses of data you intend to read or write to the device and how that data should be interpreted. I looked over documentation for several devices and there’s no standardization here even between different lines from the same manufacturer so until someone with the hardware shares working settings with me to incorporate into a release, you’ll have to RTFM for your device and type in a few numbers. Once you figure it out, I’d encourage you to send me teh codez so it will be easier for the next person who wants to use that device. I should probably consider building in a way for the program to produce an email with the relevant information (not in a hidey, sneaky sort of way, but like clicking a mailto: link which opens up your email client, pre-populates a new email, and you can review exactly what would be sent to me and would then need to manually hit that send button) but that’s not an immediate priority for me.

The code for this part is all done. You can add however many devices to the port and it will save the relevant details with QSettings (how that works depends on the platform: on Windows it goes into the registry).

Next, you need to be able to configure a roaster. When doing this, you’ll have access to all of the devices that you’ve configured. You select which ones you want to use and then for each channel that’s configured on those devices you can decide if you get a panel that shows the most recent measurement, if it goes to the table view, if it goes to the graph, that sort of thing. This is also where you can specify what you want in the way of annotation controls. Don’t need the ones I’ve previously put in the example configurations? You can get rid of them. Want ones that I don’t see the point of (lots of people have expressed interest in having first and second crack annotation buttons, for example)? Go ahead and put them in. It’ll be easy. This is the next thing that I need to work on back porting from the 2.0 branch. Then when you want to roast coffee you’ll need to select the roaster you intend to use and the program will look at how you’ve previously configured that roaster and set up the devices and logging view appropriately. While I don’t recommend it (there are safety and focus issues) you could also go back and indicate that you want to roast on another machine with a non-conflicting device set (2.0 gets the ability to split channels from the same device among multiple concurrently operating machines but I’m not going to put the extra effort in for that right now) and have two logging windows running at the same time, one for each roaster.

Developing an idea for a new and novel video series. Won&#8217;t have time to do it for a while, but I want it written down so I don&#8217;t forget. It involves coffee and sharks. Mostly coffee, the sharks would only feature in one episode.
I have the concepts down for 12 episodes so far. Would like to think up a few more before I start to work on it more seriously. I wonder if anybody would watch it.

Developing an idea for a new and novel video series. Won’t have time to do it for a while, but I want it written down so I don’t forget. It involves coffee and sharks. Mostly coffee, the sharks would only feature in one episode.

I have the concepts down for 12 episodes so far. Would like to think up a few more before I start to work on it more seriously. I wonder if anybody would watch it.

May 30

Adding Modbus Support to Typica - Day 6
Day 5 was also a no progress day because I was helping to put the shop back together so we&#8217;d be ready to reopen today. Here&#8217;s a picture of the equipment that I&#8217;m using to test what I&#8217;m doing. The transformer on the left plugs into the wall and gives me the 24VAC power needed for the controller. Thermocouple wire goes between the controller and the calibrator on the right. This lets me set whatever value I want for the process value. The device between the transformer and the controller is an RS485/RS232 to USB adapter. For cable runs as short as I&#8217;m using here RS485 works over just about any wire. In this case I just clipped the ends off an old CAT5 patch cable and used the green pair of wires. Suwako doesn&#8217;t have anything to do with all of that. She arrived today as a replacement for the cat key chain that recently fell apart.
Today I went over the documentation for the controller looking for addresses that it might be interesting to read or write from, tested that writes were doing the right thing and that reads were returning the values I expected. This also included some multi-value reads (for example, reading the current PV and SV at the same time or getting both the upper and lower SV limits) since it&#8217;s faster to read multiple values at once than to read values from close addresses separately. Everything worked as expected. This ends the step of testing that I understand how to interface with the hardware. I&#8217;ve also finished the design of the required code and made good progress on writing it. All the hard parts (not that any of this was particularly challenging) are done, now it&#8217;s really just a matter of getting the time to write the rest of the code.

Adding Modbus Support to Typica - Day 6

Day 5 was also a no progress day because I was helping to put the shop back together so we’d be ready to reopen today. Here’s a picture of the equipment that I’m using to test what I’m doing. The transformer on the left plugs into the wall and gives me the 24VAC power needed for the controller. Thermocouple wire goes between the controller and the calibrator on the right. This lets me set whatever value I want for the process value. The device between the transformer and the controller is an RS485/RS232 to USB adapter. For cable runs as short as I’m using here RS485 works over just about any wire. In this case I just clipped the ends off an old CAT5 patch cable and used the green pair of wires. Suwako doesn’t have anything to do with all of that. She arrived today as a replacement for the cat key chain that recently fell apart.

Today I went over the documentation for the controller looking for addresses that it might be interesting to read or write from, tested that writes were doing the right thing and that reads were returning the values I expected. This also included some multi-value reads (for example, reading the current PV and SV at the same time or getting both the upper and lower SV limits) since it’s faster to read multiple values at once than to read values from close addresses separately. Everything worked as expected. This ends the step of testing that I understand how to interface with the hardware. I’ve also finished the design of the required code and made good progress on writing it. All the hard parts (not that any of this was particularly challenging) are done, now it’s really just a matter of getting the time to write the rest of the code.

New connect() overload in Qt 5. -

I’ve just noticed that Qt 5 added another overload to the connect() method which is used to establish connections in Qt’s signals and slots mechanism. It lets you connect a signal to a lambda expression (introduced in C++11). It seems this style might be preferable in most cases one might currently be tempted to define a private slot method.

May 29

krammarkio:

The best part of my day today?Our soft serve ice cream machine randomly spurts out huge blasts of liquid ice cream when it first starts up. My boss, who today, got new pants and made a big deal out of them, squirted ice cream ALL OVER his pants. He then proceeded to, in a rage, produce vast amounts of ridiculously tall soft serve ice cream to quell his rage and empty the machine.
Here you go bud, free ridiculously tall ice cream~

That is one happy, and soon to be sticky, kid. It&#8217;s not every boss who&#8217;d be able to use pant rage to spread some joy.

krammarkio:

The best part of my day today?

Our soft serve ice cream machine randomly spurts out huge blasts of liquid ice cream when it first starts up. My boss, who today, got new pants and made a big deal out of them, squirted ice cream ALL OVER his pants. He then proceeded to, in a rage, produce vast amounts of ridiculously tall soft serve ice cream to quell his rage and empty the machine.

Here you go bud, free ridiculously tall ice cream~

That is one happy, and soon to be sticky, kid. It’s not every boss who’d be able to use pant rage to spread some joy.

May 28

Adding Modbus Support to Typica - Day 4

Yesterday I wrote a tiny test program that would write a particular string of digits out over a serial port and display the result that comes back. What went out was 0x010403E80001B1BA which is Modbus for Station 1, read out input registers (command 0x04) starting from relative address 0x03E8 (PV in engineering units) 1 value (0x0001). The 0xB1BA is a check digit computed from everything in the message prior to that. If that were all I was interested in doing I could stick it in a loop and call it done, but that’s not going to work. First, consider that station number. The way Modbus works, you can wire up a whole bunch of devices on the same port. Any message I send out will be received by all of them and they’ll look at that first byte of the message to decide if the message is addressed to that device. This is something that’s configured in the device itself and I can’t count on the device I want to send the message to always being station 1. Changing the station number changes the check digit so we need to be able to calculate this.

This is calculated according to an algorithm given in the documentation. It’s a 16 bit cyclic redundancy check algorithm. While Qt already provides a function for calculating the CRC of a QByteArray, it uses the wrong algorithm for the purpose here so I wrote my own function for that, building on my previous test program so that I could type in any arbitrary Modbus message (sans check digits) and the program would calculate and append the check digits, send the completed message out over the wire, and display both what it sent (so I can verify the CRC) and the response. Here’s the code. Input is a QByteArray with everything other than the check digits, output is a 16 bit unsigned integer that should be appended to the message before it is sent.

quint16 modbusCrc(QByteArray data)
{
    quint16 retval = 0xFFFF;
    int i = 0;
    while(i < data.size())
    {
        retval ^= 0x00FF & (quint16)data.at(i);
        for(int j = 0; j < 8; j++)
        {
            if(retval & 1)
            {
                retval = (retval >> 1) ^ 0xA001;
            }
            else
            {
                retval >>= 1;
            }
        }
        i++;
    }
    return retval;
}

We might also want to check that the replies sent back from a device were received correctly. If we take the whole response and pass it into this same function, the return value will be 0 if the message was correctly received.

I’m using an event driven system for reading data from the serial port and at only 9600 baud it’s not uncommon that my software will attempt to read a message before the whole thing has been received. When we send a message, we can know what to expect in returned data. The length of the reply depends on what we asked for. While we can calculate the response length we expect, in the case of an error that might not be what we get. Better to find out from the response itself how long the message is. So what does a response look like? The first byte identifies the device sending the response. It’s the station number from the message we sent. The second byte is a function code. We expect this to be the same as what we sent, but if there’s an error we’ll get a different value here. If there’s an error, we now know how long the message is. It’s five bytes with the remaining three bytes being what kind of error was reported and the CRC. Some functions have fixed sized replies. The ones that don’t use the third byte to indicate how many bytes of data follow. Once you have that number you can add 5 (3 for the data we’ve already read and 2 for the CRC) and now you know how long the reply should be.

There are a few things that still need to be done to get this integrated into Typica.

1) Connection configuration is slightly different from previously supported devices. I’ll want to provide a configuration widget that allows specifying the port settings. When I get around to looking at the documentation for other devices I might find that I need to expand on that a bit, but for now I intend to keep the options minimal for the device I’m testing against.

2) Internally Typica handles all of its temperature measurements in degrees Fahrenheit. Requesting the PV returns an integer value in whatever the currently selected unit is, ignoring the decimal point (so 500, 50.0, and 5.00 would all be shown as 500). Before getting measurements, the program will need to ask the device which unit it’s displaying its values in and where the decimal point goes so that any conversions that are needed can be performed appropriately.

3) Once measurements start, I could just have a thread loop, sending the request for PV out, getting the response back, and packing the measurement up to send to the rest of the program, but there are a couple issues with that. While we’ll generally want to read the PV as often as possible, we might sometimes want to do something like output a new SV so there needs to be a way to slip something like that in between PV requests. The other complication that should be considered early is that we may want to request the PV from more than one device on the same port. The program needs to give each device a turn. Neither of these is a hard problem. There’s a well understood solution, but it’s important to be aware of these things rather than have to rip the code apart later.

4) From there I’ll want to do some testing to make sure that code that’s currently working for a few minutes at a time and not moving much data over the port continues to work after a few hours of moving lots of data over the port.