Procházet zdrojové kódy

Message builder: < > to incr/decr fields.

antirez před 3 roky
rodič
revize
de085c87c4
3 změnil soubory, kde provedl 104 přidání a 22 odebrání
  1. 1 0
      app.h
  2. 59 0
      fields.c
  3. 44 22
      view_build.c

+ 1 - 0
app.h

@@ -310,6 +310,7 @@ void fieldset_add_float(ProtoViewFieldSet *fs, const char *name, float val, uint
 const char *field_get_type_name(ProtoViewField *f);
 int field_to_string(char *buf, size_t len, ProtoViewField *f);
 bool field_set_from_string(ProtoViewField *f, char *buf, size_t len);
+bool field_incr_value(ProtoViewField *f, int incr);
 
 /* crc.c */
 uint8_t crc8(const uint8_t *data, size_t len, uint8_t init, uint8_t poly);

+ 59 - 0
fields.c

@@ -162,6 +162,65 @@ bool field_set_from_string(ProtoViewField *f, char *buf, size_t len) {
     return true;
 }
 
+/* Increment the specified field value of 'incr'. If the field type
+ * does not support increments false is returned, otherwise the
+ * action is performed. */
+bool field_incr_value(ProtoViewField *f, int incr) {
+    switch(f->type) {
+        case FieldTypeStr: return false;
+        case FieldTypeSignedInt: {
+            /* Wrap around depending on the number of bits (f->len)
+             * the integer was declared to have. */
+            int64_t max = (1ULL << (f->len-1))-1;
+            int64_t min = -max-1;
+            int64_t v = (int64_t)f->value + incr;
+            if (v > max) v = min+(v-max-1);
+            if (v < min) v = max+(v-min+1);
+            f->value = v;
+            break;
+        }
+        case FieldTypeBinary:
+        case FieldTypeHex:
+        case FieldTypeUnsignedInt: {
+            /* Wrap around like for the unsigned case, but here
+             * is simpler. */
+            uint64_t max = (1ULL << f->len)-1; // Broken for 64 bits.
+            uint64_t uv = (uint64_t)f->value + incr;
+            if (uv > max) uv = uv & max;
+            f->uvalue = uv;
+            break;
+        }
+        case FieldTypeFloat:
+            f->fvalue += incr;
+            break;
+        case FieldTypeBytes: {
+            // For bytes we only support single unit increments.
+            if (incr != -1 && incr != 1) return false;
+            for (int j = f->len-1; j >= 0; j--) {
+                uint8_t nibble = (j&1) ? (f->bytes[j/2] & 0x0F) :
+                                         ((f->bytes[j/2] & 0xF0) >> 4);
+
+                nibble += incr;
+                nibble &= 0x0F;
+
+                f->bytes[j/2] = (j&1) ? ((f->bytes[j/2] & 0xF0) | nibble) :
+                                        ((f->bytes[j/2] & 0x0F) | (nibble<<4));
+
+		/* Propagate the operation on overflow of this nibble. */
+		if ((incr == 1 && nibble == 0) ||
+		    (incr == -1 && nibble == 0xf))
+		{
+		    continue;
+		}
+		break; // Otherwise stop the loop here.
+            }
+            break;
+        }
+    }
+    return true;
+}
+
+
 /* Free a field set and its contained fields. */
 void fieldset_free(ProtoViewFieldSet *fs) {
     for (uint32_t j = 0; j < fs->numfields; j++)

+ 44 - 22
view_build.c

@@ -147,34 +147,56 @@ static void text_input_done_callback(void* context) {
     ui_dismiss_keyboard(app);
 }
 
+/* Handles the effects of < and > keys in field editing mode.
+ * Instead of force the user to enter the text input mode, delete
+ * the old value, enter the one, we allow to increment and
+ * decrement the current field in a much simpler way.
+ *
+ * The current filed is changed by 'incr' amount. */
+static bool increment_current_field(ProtoViewApp *app, int incr) {
+    BuildViewPrivData *privdata = app->view_privdata;
+    ProtoViewFieldSet *fs = privdata->fieldset;
+    ProtoViewField *f = fs->fields[privdata->cur_field];
+    return field_incr_value(f,incr);
+}
+
 /* Handle input for fields editing mode. */
 static void process_input_set_fields(ProtoViewApp *app, InputEvent input) {
     BuildViewPrivData *privdata = app->view_privdata;
     ProtoViewFieldSet *fs = privdata->fieldset;
-    if (input.type == InputTypeShort) {
-        if (input.key == InputKeyOk) {
-            /* Show the keyboard to let the user type the new
-             * value. */
-            if (privdata->user_value == NULL)
-                privdata->user_value = malloc(USER_VALUE_LEN);
-            field_to_string(privdata->user_value, USER_VALUE_LEN,
-                            fs->fields[privdata->cur_field]);
-            ui_show_keyboard(app, privdata->user_value, USER_VALUE_LEN,
-                             text_input_done_callback);
-        } else if (input.key == InputKeyDown) {
-            privdata->cur_field = (privdata->cur_field+1) % fs->numfields;
-        } else if (input.key == InputKeyUp) {
-            if (privdata->cur_field == 0)
-                privdata->cur_field = fs->numfields-1;
-            else
-                privdata->cur_field--;
-        }
-    }
 
-    if (input.type == InputTypeLong && input.key == InputKeyOk) {
-        /* Build the message a fresh raw buffer. */
-        RawSamplesBuffer *rs = raw_samples_alloc();
+    if (input.type == InputTypeShort && input.key == InputKeyOk) {
+        /* Show the keyboard to let the user type the new
+         * value. */
+        if (privdata->user_value == NULL)
+            privdata->user_value = malloc(USER_VALUE_LEN);
+        field_to_string(privdata->user_value, USER_VALUE_LEN,
+                        fs->fields[privdata->cur_field]);
+        ui_show_keyboard(app, privdata->user_value, USER_VALUE_LEN,
+                         text_input_done_callback);
+    } else if (input.type == InputTypeShort && input.key == InputKeyDown) {
+        privdata->cur_field = (privdata->cur_field+1) % fs->numfields;
+    } else if (input.type == InputTypeShort && input.key == InputKeyUp) {
+        if (privdata->cur_field == 0)
+            privdata->cur_field = fs->numfields-1;
+        else
+            privdata->cur_field--;
+    } else if (input.type == InputTypeShort && input.key == InputKeyRight) {
+        increment_current_field(app,1);
+    } else if (input.type == InputTypeShort && input.key == InputKeyLeft) {
+        increment_current_field(app,-1);
+    } else if (input.type == InputTypeRepeat && input.key == InputKeyRight) {
+        // The reason why we don't use a large increment directly
+        // is that certain field types only support +1 -1 increments.
+        int times = 10;
+        while(times--) increment_current_field(app,1);
+    } else if (input.type == InputTypeRepeat && input.key == InputKeyLeft) {
+        int times = 10;
+        while(times--) increment_current_field(app,-1);
+    } else if (input.type == InputTypeLong && input.key == InputKeyOk) {
+        // Build the message in a fresh raw buffer.
         if (privdata->decoder->build_message) {
+            RawSamplesBuffer *rs = raw_samples_alloc();
             privdata->decoder->build_message(rs,privdata->fieldset);
             app->signal_decoded = false; // So that the new signal will be
                                          // accepted as the current signal.