Version 1.20 – release date: August 1st, 2017

We are pleased to announce the release of CPAL version 1.20. The programmer is now given access to the internal job list to have maximum flexibility in defining process activations. The release provides several helper functions in source code (as part of the CPAL standard library under pkg folder) to ease the use of triggered processes. This release also introduces new possibilities to work with strings.

Note: this is a maintenance release distributed only as command-line binaries for Windows, Mac and Linux platforms. Users of the CPAL-editor should update the path to the binaries manually in “Edition – Parameters” menu of the editor.

What is new

  • ADDED: more flexibility to implement complex process activation patterns (e.g., bursty) by accessing in reading and writing next_activations, the queue of the scheduled activations of a process. In the example below, the helper function require_activation(p) returns true when an activation of p has been scheduled for execution earlier or at the current point in time:

    
    const time64: period = 50ms;
    
    processdef My_Process()
    {
      state Main {
        IO.println("Current activation released at %t", self.current_activation);
        if (self.current_activation mod period == 0ms) {
          IO.println("Creating two new activations");
          /* Schedule another activation 5ms after the period,
    	  the process is thus released at times 0ms, 5ms, 50ms, 55ms, 100ms, 105ms, etc. 
          */
          self.next_activations.push(int64.as(period));
          self.next_activations.push(int64.as(period+5ms));
        }
        loop over self.next_activations with it {
            IO.println("An activation scheduled in %t", time64.as(it.current));
        }
      }
    }
    /* task1 is a triggered process that is self-programming its activations */ 
    process My_Process: task1[][require_activation(task1)]();
    
    init() {
      task1.next_activations.push(int64.as(0));
      task1.next_activations.push(int64.as(5ms));
    }
    
  • ADDED: Helper functions to trigger the execution of processes at specific points in time expressed in relative or absolute time: wakeup_at(), wakeup_also_at(), wakeup_in() and wakeup_also_in():

    
    const time64: period = 50ms;
    
    processdef My_Process()
    {
      state Main {
        IO.println("Current activation released at %t", self.current_activation);
        loop over self.next_activations with it {
            IO.println("An activation scheduled in %t", time64.as(it.current));
        }
      }
    }
    
    process My_Process: task1[][require_activation(task1)]();
    
    init() {
      
      /* Schedule a process activation at time 150ms*/ 
      wakeup_at(task1, 150ms);
      /* This call is without effect since an activation is already planed at 150 ms*/ 
      wakeup_at(task1, 150ms);
      /* Schedule another activation, at time 300ms */
      wakeup_at(task1, 300ms);
      /* A second activation is released at time 300ms */ 
      wakeup_also_at(task1, 300ms);
      /* Scheduling a process activation in relative time */
      wakeup_in(task1, 400ms);
      /* This call is ignored as an activation is already planed at t=400ms */
      wakeup_in(task1, 400ms);
      /* This call will add another instance at t=400ms */ 
      wakeup_also_in(task1, 400ms); 
    }
    
  • ADDED: support for strings as arguments through collections (#368)

    
    foo(in channel<uint8>: ch, out uint8: r)
    {
      r = uint8.as(ch.count());
    }
    
    init()
    {
     var queue<uint8>: a_string[5] = "abcd";
      assert(4 == foo(a_string));
      assert(4 == foo("abcd"));
    }
    
  • ADDED: equivalent of C-language sprintf() function

    
    init()
    {
      var uint8: sfloat[10];
      const float32: f1 = 1.0/3.0;
      var uint8: stime[50];
      const time64: t1 = 123456789101112ps; /* 0d0h2mn3s456ms789us101ns112ps */
      float_to_string: {
        uint8.print(sfloat,"%f", f1);
        IO.println(sfloat);
      }
      time_to_string: {
        uint8.print(stime,"%t", t1);
        IO.println(stime);
      }
    }
    

What has been fixed or changed

  • Parse error indicated at wrong line occasionally (#361)
  • Extends constness detection to (curried) function (#366)

    
    foo(in uint8: b, out uint8: r)
    {
      r = 3;
    }
    
    bar(in uint8: arg, out uint8: r)
    {
      r = arg + 1;
    }
    
    const uint8: g_var = bar(foo(4));
    
    init()
    {
      assert(g_var == 4);
    }
    
  • A timing annotation which is specific to a process instance (i.e., of the form @cpal:time:instance-name) must be unique (#371)
  • Fix infinite loop when running step command without any process defined
  • Use of process state enum before actual state definition made possible

    
    processdef B_Proc()
    {
      var uint32: x = 5;
      common{
        if (self.process_state == Process_State.State1) {
          IO.println("in common - State1 to be executed");
        }
      }
      state State1 {
      }
      on (true) to State2;
      state State2 {
      }
      on (true) to State1;
       finally{
        if (self.process_state == Process_State.State1) {
          IO.println("in finally - State1 executed");
        }
       }
    }
    
    process B_Proc : p[100ms]();
    

Test coverage metrics (figures for embedded Linux platform)

  • Test code coverage for runtime engine: 86.6% (lines of code), 82.2% (functions) and 74.9% (branches)
  • Tests: parser=3993, interpreter=889, cpal2x=1034, multi-interpreter=15