How to write an App

OK, you decided that the Texmate Tiger can do what you need for your application and it looks like you will need to write an app, too. You got the Texmate Development System, the Macro Programming Tutorial, the Registers Supplement, the Code Sheet, the sample macros, the data sheets for your I/O modules, and maybe even some additional stuff (e.g. the Serial Communications Supplement or the Totalizing Supplement). If you print out all of that you end up with a big pile of paper.

But the question remains: How do I start - and how do I get it done quickly?

If you do have the time to work through the Tutorial this might not be that hard anymore - but unfortunately many of you don't. Instead you would rather find out whether your idea works without wasting too much time if it doesn't.

Well, we cannot make you an expert on writing apps in an instant but we will try to help you getting started - from a programmers point of view :-)


  1. Preliminary considerations

    Before you start you should clarify what you really want to do with the meter:
    • processing input data (e.g. linearization, higher maths calculations)
    • setting up a logic control system (e.g. setpoints/relays)
    • providing a 'simple' user interface
    • implementing a custom communication protocol

  2. Keeping track of things

    Start your macro with a few comment lines (REM or //) containing:
    • the (file) name of the macro
    • a short overview of the application
    • the date of your last changes
    • the changes you made since the last version of the macro

    Write a CUSTOMER_ID_MACRO containing a single WRITE command that states the application name and the app version number:

      CUSTOMER_ID_MACRO:
    WRITE " Tank Fill 1.2 "
    END

    Especially for longer macros it is also useful to redefine register names according to the actual application. At least the USER_MEMORY registers should get a proper name.

      REG &LEVEL = &CH3
    BIT |PUMP_1 = |SP1
    BIT |PUMP_2 = |SP2
    BIT |MED_LEVEL = |SP5 // only used for logic control, no relay attached
    BIT |HIGH_LEVEL = |SP6 // only used for logic control, no relay attached
    BIT |EMERGENCY = |CAPTURE_PIN
    REG &ALARM_VALUE = &USER_MEMORY_1
  3. Start from a known position

    Write a RESET_MACRO and initialize all variables there. Keep it up to date as you go on extending the macro.

      RESET_MACRO:
    #output = 0
    |pumps_activated = false
    END

    If your application relies on a certain meter setup use the MEM command to preset the according registers. USER_MEMORY registers should always be initialized with the MEM command.

      MEM &DISPLAY_FORMAT_CH1 = 0004 // 3 decimals
    MEM &DATA_SOURCE_SP5 = addr(&LEVEL)
    MEM &DATA_SOURCE_SP6 = addr(&LEVEL)
    MEM &DATA_SOURCE_ANALOG1 = addr(#output)
    MEM &ALARM_VALUE = 10000

    If you plan to run the meter in a different communication mode (Master, Modbus...) you should set it back to ASCII in the RESET_MACRO so you can get access to the meter again. You may do that only conditional, though:

      RESET_MACRO:
    IF |CAPTURE_PIN = on THEN
       &CODE3 = 0000
    ENDIF
    END
  4. Processing input data

    This is typically pretty easy so this may be the first thing to add to the MAIN_MACRO:

      MAIN_MACRO:
    #output = &LEVEL * 1.2 + (&LEVEL ^ 2) * 3.8
    END
  5. Logic control system

    Logic control is usually quite easy to translate into a programming language. So this should be simple, too, as long as you already figured out the logic :-)

      MAIN_MACRO:
    // for copying a bit/boolean value you can use the short form
    |PUMP_2 = |HIGH_LEVEL

    // but for additional settings you have to write it explicitly
    if |MED_LEVEL = on then
       |PUMP_1 = on
       |pumps_activated = true
    else
       |PUMP_1 = off
    endif

    // show a message when pumps are off again
    if |MED_LEVEL = off and |pumps_activated = true then
       |pumps_activated = false
      write " back to normal "
    endif
    END
  6. 'Simple' user interface

    Even though this is not that difficult the EDIT_MACRO usually takes up quite an amount of code if you want to do it properly. As the Tutorial and the sample macros should be sufficient to explain how it works I will only give a few additional hints :-)

    When you write your own user interface you typically want to hide the complexity from the user. So it is a good idea to hide those functions you don't need. If you allow access to the built-in menus you have to take the trigger events (UP/DOWN/PROG+UP/PROG+DOWN) into account as well as the fact that you are currently in these menus (&EDIT_STATE).

      MEM &VIEW_MODE_BLANKING = 0x0000 // turn off view mode completely
    MEM &SETPOINT_BLANKING = 0x0060 // edit only SP5/6 with PROG+DOWN
    MEM &CODE_BLANKING = 0x0000 // note: editing brightness cannot be turned off
    ...
    MAIN_MACRO:
    // standard operation, only UP is pressed
    if &STATE = 0 and &EDIT_STATE = 0 and |UP_BUTTON = on and \
    |PROG_BUTTON = off and |DOWN_BUTTON = off then
    ...
    endif
    END

    If you have a 7-segment display the letters 'M' and 'W' take up the space for two digits. Also some characters are relatively hard to read especially while scrolling text. So in general the interface should be rather simple to remain understandable. For a complex interface or elaborate text messages a 15-segment or a LCD display is recommended.

    To keep track of the different STATE values it is recommended to use CONST definitions that are more readable. Sometimes it is also convenient to use these as index for a text array with the corresponding messages.

      DIM Msg[] = [ "", "Setup", "Zero", "Full" ]
    CONST eNONE = 0
    CONST eENTER_SETUP = 1
    CONST eANALOG_ZERO = 2
    CONST eANALOG_FULL_SCALE = 3

    EDIT_MACRO:
    select &STATE
    ...
    case eANALOG_ZERO:
       |NON_VOLATILE_WRITE = on
       EXIT_EDIT &D2A_AOP1_ZERO

       EDIT &D2A_AOP1_FULL_SCALE
       &EDIT_MIN = &D2A_AOP1_ZERO + 1
       &EDIT_MAX = 99999
       &EDIT_DEF = 10000
       &STATE = eANALOG_FULL_SCALE
    ...
    endsel
    write Msg[&STATE]
    END

    If you change setup registers within the macro you have to set the |NON_VOLATILE_WRITE flag to ON before writing the register. Otherwise the change will not be stored in non-volatile memory, i.e. will be lost on power off.

  7. Communication protocols

    The Tiger 320 Series provides only a very basic way to implement a communication protocol with the PRINT command and the SERIAL_INPUT comparisons. This will be sufficient for directly manipulating other devices (like another Tiger) or sending data and is explained in the Tutorial.

    However, for more sophisticated protocols (e.g. for sending emails using an ethernet module, or parsing incoming data from another device) we added more features in the Tiger 380 series which allow for limited string operations. But, though getting easier, implementing a custom protocol still remains a tricky exercise which should not be attempted without a good understanding of how Tiger apps work.

App Documentation