]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/demo/protocol.c
demo: Implement logic triggering.
[libsigrok.git] / src / hardware / demo / protocol.c
index 46808fd6cf5622b4cd2ad333906ab9159059ac3d..994c955dbeb1d263f0de83c16804a27d80c174ff 100644 (file)
@@ -245,6 +245,19 @@ SR_PRIV void demo_generate_analog_pattern(struct analog_gen *ag, uint64_t sample
        }
 }
 
+static uint64_t encode_number_to_gray(uint64_t nr)
+{
+       return nr ^ (nr >> 1);
+}
+
+static void set_logic_data(uint64_t bits, uint8_t *data, size_t len)
+{
+       while (len--) {
+               *data++ = bits & 0xff;
+               bits >>= 8;
+       }
+}
+
 static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
 {
        struct dev_context *devc;
@@ -253,6 +266,7 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
        uint8_t *sample;
        const uint8_t *image_col;
        size_t col_count, col_height;
+       uint64_t gray;
 
        devc = sdi->priv;
 
@@ -326,6 +340,15 @@ static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
                        devc->step %= col_count;
                }
                break;
+       case PATTERN_GRAYCODE:
+               for (i = 0; i < size; i += devc->logic_unitsize) {
+                       devc->step++;
+                       devc->step &= devc->all_logic_channels_mask;
+                       gray = encode_number_to_gray(devc->step);
+                       gray &= devc->all_logic_channels_mask;
+                       set_logic_data(gray, &devc->logic_data[i], devc->logic_unitsize);
+               }
+               break;
        default:
                sr_err("Unknown pattern: %d.", devc->logic_pattern);
                break;
@@ -433,6 +456,8 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
        void *value;
        uint64_t samples_todo, logic_done, analog_done, analog_sent, sending_now;
        int64_t elapsed_us, limit_us, todo_us;
+       int64_t trigger_offset;
+       int pre_trigger_samples;
 
        (void)fd;
        (void)revents;
@@ -470,12 +495,13 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
        if (samples_todo == 0)
                return G_SOURCE_CONTINUE;
 
-#if (SAMPLES_PER_FRAME > 0) /* Avoid "comparison < 0 always false" warning. */
-       /* Never send more samples than a frame can fit... */
-       samples_todo = MIN(samples_todo, SAMPLES_PER_FRAME);
-       /* ...or than we need to finish the current frame. */
-       samples_todo = MIN(samples_todo, SAMPLES_PER_FRAME - devc->sent_frame_samples);
-#endif
+       if (devc->limit_frames) {
+               /* Never send more samples than a frame can fit... */
+               samples_todo = MIN(samples_todo, SAMPLES_PER_FRAME);
+               /* ...or than we need to finish the current frame. */
+               samples_todo = MIN(samples_todo,
+                       SAMPLES_PER_FRAME - devc->sent_frame_samples);
+       }
 
        /* Calculate the actual time covered by this run back from the sample
         * count, rounded towards zero. This avoids getting stuck on a too-low
@@ -483,31 +509,45 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
         */
        todo_us = samples_todo * G_USEC_PER_SEC / devc->cur_samplerate;
 
-       logic_done  = devc->num_logic_channels  > 0 ? 0 : samples_todo;
+       logic_done = devc->num_logic_channels > 0 ? 0 : samples_todo;
        if (!devc->enabled_logic_channels)
                logic_done = samples_todo;
        analog_done = devc->num_analog_channels > 0 ? 0 : samples_todo;
        if (!devc->enabled_analog_channels)
                analog_done = samples_todo;
-
+       
        while (logic_done < samples_todo || analog_done < samples_todo) {
                /* Logic */
                if (logic_done < samples_todo) {
                        sending_now = MIN(samples_todo - logic_done,
                                        LOGIC_BUFSIZE / devc->logic_unitsize);
                        logic_generator(sdi, sending_now * devc->logic_unitsize);
-                       packet.type = SR_DF_LOGIC;
-                       packet.payload = &logic;
-                       logic.length = sending_now * devc->logic_unitsize;
-                       logic.unitsize = devc->logic_unitsize;
-                       logic.data = devc->logic_data;
-                       logic_fixup_feed(devc, &logic);
-                       sr_session_send(sdi, &packet);
-                       logic_done += sending_now;
+                       /* Trigger */
+                       if (!devc->trigger_fired) {
+                               trigger_offset = soft_trigger_logic_check(devc->stl,
+                                               devc->logic_data, sending_now * devc->logic_unitsize, 
+                                               &pre_trigger_samples);
+                               if (trigger_offset > -1)
+                                       devc->trigger_fired = TRUE;
+                                       logic_done = pre_trigger_samples;
+                       } else
+                               trigger_offset = 0;
+
+                       /* Remaining data */
+                       if (devc->trigger_fired && trigger_offset < (unsigned int)sending_now) {
+                               packet.type = SR_DF_LOGIC;
+                               packet.payload = &logic;
+                               logic.length = (sending_now - trigger_offset) * devc->logic_unitsize;
+                               logic.unitsize = devc->logic_unitsize;
+                               logic.data = devc->logic_data + trigger_offset * devc->logic_unitsize;
+                               logic_fixup_feed(devc, &logic);
+                               sr_session_send(sdi, &packet);
+                               logic_done += sending_now - trigger_offset;
+                       }
                }
 
                /* Analog, one channel at a time */
-               if (analog_done < samples_todo) {
+               if (devc->trigger_fired && analog_done < samples_todo) {
                        analog_sent = 0;
 
                        g_hash_table_iter_init(&iter, devc->ch_ag);
@@ -518,24 +558,28 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
                        }
                        analog_done += analog_sent;
                }
+
+               /* If trigger didn't happen continue to next iteration
+                * Allow the client to stop this process
+                */
+               if (!devc->trigger_fired)
+                       break;
        }
-       /* At this point, both logic_done and analog_done should be
-        * exactly equal to samples_todo, or else.
-        */
-       if (logic_done != samples_todo || analog_done != samples_todo) {
-               sr_err("BUG: Sample count mismatch.");
-               return G_SOURCE_REMOVE;
-       }
-       devc->sent_samples += samples_todo;
-       devc->sent_frame_samples += samples_todo;
+
+       uint64_t min = MIN(logic_done, analog_done);
+       devc->sent_samples += min;
+       devc->sent_frame_samples += min;
        devc->spent_us += todo_us;
 
-#if (SAMPLES_PER_FRAME > 0) /* Avoid "comparison >= 0 always true" warning. */
-       if (devc->sent_frame_samples >= SAMPLES_PER_FRAME) {
+       if (devc->limit_frames && devc->sent_frame_samples >= SAMPLES_PER_FRAME) {
                std_session_send_frame_end(sdi);
                devc->sent_frame_samples = 0;
+               devc->limit_frames--;
+               if (!devc->limit_frames) {
+                       sr_dbg("Requested number of frames reached.");
+                       sr_dev_acquisition_stop(sdi);
+               }
        }
-#endif
 
        if ((devc->limit_samples > 0 && devc->sent_samples >= devc->limit_samples)
                        || (limit_us > 0 && devc->spent_us >= limit_us)) {
@@ -554,11 +598,9 @@ SR_PRIV int demo_prepare_data(int fd, int revents, void *cb_data)
                }
                sr_dbg("Requested number of samples reached.");
                sr_dev_acquisition_stop(sdi);
-       } else {
-#if (SAMPLES_PER_FRAME > 0)
+       } else if (devc->limit_frames) {
                if (devc->sent_frame_samples == 0)
                        std_session_send_frame_begin(sdi);
-#endif
        }
 
        return G_SOURCE_CONTINUE;