Merge remote-tracking branch 'upstream/master' into reset-overlap
This commit is contained in:
commit
c7d6b7f6cd
|
@ -36,7 +36,15 @@ jobs:
|
|||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub build-firmware Action"
|
||||
git status
|
||||
git commit -am "Auto-generated configs and docs" 2>&1 | grep -E '(nothing to commit|changed)'
|
||||
OUT=$(git commit -am "Auto-generated configs and docs" 2>&1) || echo "commit failed, finding out why"
|
||||
if echo "$OUT" | grep 'nothing to commit'; then
|
||||
echo "::set-env name=NOCOMMIT::true"
|
||||
exit 0
|
||||
elif echo "$OUT" | grep 'changed'; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We need to know what branch this is in order to push to the correct branch
|
||||
- name: Extract branch name
|
||||
|
@ -45,6 +53,7 @@ jobs:
|
|||
id: extract_branch
|
||||
|
||||
- name: Push configs
|
||||
if: ${{env.NOCOMMIT != 'true'"}}
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* @file logicdata.cpp
|
||||
*
|
||||
* Based on LogicdataStreamFile.java by andreika
|
||||
*
|
||||
* Created on: Jul 19, 2020
|
||||
* @author Andrey Belomutskiy, (c) 2012-2020
|
||||
*/
|
||||
|
@ -8,11 +10,474 @@
|
|||
#include "logicdata.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdint>
|
||||
#include <string.h>
|
||||
|
||||
void writeFile() {
|
||||
#define frequency 1000000
|
||||
#define frequencyDiv 10
|
||||
#define magic 0x7f
|
||||
|
||||
FILE *ptr = fopen("test.logicdata", "wb");
|
||||
#define BLOCK 0x15
|
||||
#define CHANNEL_BLOCK 0x16
|
||||
#define SUB 0x54
|
||||
|
||||
#define title "Data save2"
|
||||
|
||||
#define FLAG_NOTEMPTY 2
|
||||
#define FLAG_NOTEMPTY_LONG 3
|
||||
#define FLAG_EMPTY 5
|
||||
|
||||
#define LOGIC4 0x40FD
|
||||
#define LOGIC8 0x673B
|
||||
|
||||
#define SIGN_FLAG 0x80000000L
|
||||
|
||||
#define numChannels 6
|
||||
#define reservedDurationInSamples 10
|
||||
|
||||
#define MAX_STRING_SIZE 40
|
||||
|
||||
static char channelNames[][MAX_STRING_SIZE] = { "Primary", "Secondary", "Trg",
|
||||
"Sync", "Coil", "Injector", "Channel 6", "Channel 7" };
|
||||
|
||||
static int CHANNEL_FLAGS[] = { 0x13458b, 0x0000ff, 0x00a0f9, 0x00ffff, 0x00ff00,
|
||||
0xff0000, 0xf020a0, };
|
||||
|
||||
static FILE *ptr;
|
||||
|
||||
static int realDurationInSamples;
|
||||
static int scaledDurationInSamples;
|
||||
|
||||
static void writeByte(uint8_t value) {
|
||||
fwrite(&value, 1, sizeof(value), ptr);
|
||||
}
|
||||
|
||||
static void writeAs(int64_t value, int numBytes) {
|
||||
if (value == 0) {
|
||||
writeByte(0);
|
||||
} else {
|
||||
writeByte(numBytes);
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
writeByte((uint8_t)((value >> (i * 8)) & 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeString(const char *value) {
|
||||
int len = strlen(value);
|
||||
writeByte(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
writeByte(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// This is the main secret of this format! :)
|
||||
static void write(int64_t value) {
|
||||
if (value < 0 || value > 0xFFFFFFFFL) {
|
||||
writeAs(value, 8);
|
||||
} else if (value == 0) {
|
||||
writeByte(0);
|
||||
} else if (value <= 0xff) {
|
||||
writeAs(value, 1);
|
||||
} else if (value <= 0xffff) {
|
||||
writeAs(value, 2);
|
||||
} else if (value <= 0xffffff) {
|
||||
writeAs(value, 3);
|
||||
} else {
|
||||
writeAs(value, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: some C++ magic would allow us to drop 'count' parameter
|
||||
// todo: Look at efi::size in util
|
||||
static void write(int values[], int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
write(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void write(int value, int num) {
|
||||
for (int i = 0; i < num; i++)
|
||||
write(value);
|
||||
}
|
||||
|
||||
static void writeId(int i1, int i2) {
|
||||
write((numChannels == 4) ? LOGIC4 : LOGIC8);
|
||||
write(i1);
|
||||
write(i2);
|
||||
}
|
||||
|
||||
static void writeHeader() {
|
||||
writeByte(magic);
|
||||
write(strlen(title));
|
||||
writeString(title);
|
||||
|
||||
write(BLOCK);
|
||||
write(SUB);
|
||||
write(frequency);
|
||||
write(0);
|
||||
write(reservedDurationInSamples);
|
||||
write(frequency / frequencyDiv);
|
||||
write(0, 2);
|
||||
write(numChannels);
|
||||
|
||||
write(BLOCK);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
for (int i = 0; i < numChannels; i++) {
|
||||
writeId(i, 1);
|
||||
}
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
|
||||
writeId(0, 0);
|
||||
write(0);
|
||||
write(0);
|
||||
|
||||
}
|
||||
|
||||
static void writeChannelHeader(int ch) {
|
||||
write(0xff);
|
||||
write(ch);
|
||||
writeString(channelNames[ch]);
|
||||
write(0, 2);
|
||||
write(1.0);
|
||||
write(0);
|
||||
write(0.0);
|
||||
write(1); // or 2
|
||||
write(0.0); // or 1.0
|
||||
|
||||
// this part sounds like the 'next' pointer?
|
||||
if (ch == numChannels - 1) {
|
||||
write(0);
|
||||
} else {
|
||||
writeId(1 + ch, 1);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
write((CHANNEL_FLAGS[ch] >> (i * 8)) & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeEdges(int64_t *chDeltas, bool useLongDeltas, int numEdges) {
|
||||
for (int i = 0; i < numEdges; i++) {
|
||||
uint64_t d = chDeltas[i];
|
||||
|
||||
// set 16-bit 'sign' flag
|
||||
if (!useLongDeltas && (d & SIGN_FLAG) == SIGN_FLAG)
|
||||
d = (d & 0x7fff) | (SIGN_FLAG >> 16);
|
||||
writeByte((uint8_t)(d & 0xff));
|
||||
writeByte((uint8_t)((d >> 8) & 0xff));
|
||||
if (useLongDeltas) {
|
||||
writeByte((uint8_t)((d >> 16) & 0xff));
|
||||
writeByte((uint8_t)((d >> 24) & 0xff));
|
||||
}
|
||||
}
|
||||
writeByte(0x00);
|
||||
}
|
||||
|
||||
static void writeRaw(int value, int num) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
writeByte(value);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeChannelData(int ch, int64_t *chDeltas, int chLastState,
|
||||
int lastRecord, bool useLongDeltas, int numEdges) {
|
||||
if (numEdges == 0)
|
||||
lastRecord = 0;
|
||||
write(CHANNEL_BLOCK);
|
||||
// channel#0 is somehow special...
|
||||
if (ch == 0) {
|
||||
write(SUB);
|
||||
write(BLOCK);
|
||||
}
|
||||
|
||||
write(ch + 1);
|
||||
write(0);
|
||||
write(realDurationInSamples);
|
||||
write(1);
|
||||
write(lastRecord);
|
||||
|
||||
int numSamplesLeft = realDurationInSamples - lastRecord;
|
||||
write(numSamplesLeft);
|
||||
|
||||
write(chLastState);
|
||||
|
||||
int chFlag =
|
||||
(numEdges == 0) ?
|
||||
FLAG_EMPTY :
|
||||
(useLongDeltas ? FLAG_NOTEMPTY_LONG : FLAG_NOTEMPTY);
|
||||
write(chFlag);
|
||||
|
||||
if (ch == 0) {
|
||||
write(0);
|
||||
write(BLOCK);
|
||||
write(0, 11);
|
||||
if (useLongDeltas) {
|
||||
write(BLOCK);
|
||||
write(0, 6);
|
||||
}
|
||||
write(BLOCK);
|
||||
} else {
|
||||
write(0, 10);
|
||||
if (useLongDeltas) {
|
||||
write(0, 5);
|
||||
}
|
||||
}
|
||||
|
||||
write(numEdges);
|
||||
write(0);
|
||||
write(numEdges);
|
||||
write(0);
|
||||
write(numEdges);
|
||||
|
||||
writeEdges(chDeltas, useLongDeltas, numEdges);
|
||||
|
||||
if (ch == 0) {
|
||||
write(BLOCK);
|
||||
write(0, 6);
|
||||
if (!useLongDeltas) {
|
||||
write(BLOCK);
|
||||
write(0, 6);
|
||||
}
|
||||
write(BLOCK);
|
||||
} else {
|
||||
write(0, 4);
|
||||
if (!useLongDeltas) {
|
||||
write(0, 5);
|
||||
}
|
||||
}
|
||||
|
||||
if (numEdges == 0) {
|
||||
write(0, 5);
|
||||
return;
|
||||
}
|
||||
|
||||
write(1);
|
||||
write(0);
|
||||
write(1);
|
||||
write(0);
|
||||
write(1);
|
||||
write(0, 16);
|
||||
|
||||
writeRaw(0xFF, 8);
|
||||
writeRaw(chFlag, 1);
|
||||
writeRaw(0x00, 7);
|
||||
}
|
||||
|
||||
static void writeChannelDataHeader() {
|
||||
write(BLOCK);
|
||||
write(scaledDurationInSamples);
|
||||
write(0, 5);
|
||||
write(numChannels);
|
||||
write(0, 3);
|
||||
writeId(0, 1);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
write(0, 3);
|
||||
|
||||
for (int i = 0; i < numChannels; i++) {
|
||||
writeChannelHeader(i);
|
||||
}
|
||||
|
||||
write(BLOCK);
|
||||
int SUB_ARRAY[] = { SUB, SUB, 0, SUB, 0, SUB };
|
||||
write(SUB_ARRAY, 6);
|
||||
write(0, 6);
|
||||
|
||||
write(BLOCK);
|
||||
write(0, 2);
|
||||
write(realDurationInSamples);
|
||||
write(0);
|
||||
write(SUB);
|
||||
write(reservedDurationInSamples);
|
||||
write(frequency / frequencyDiv);
|
||||
write(0, 2);
|
||||
write(SUB);
|
||||
write(0, 2);
|
||||
write(1);
|
||||
write(0, 3);
|
||||
writeId(0, 0);
|
||||
|
||||
write(BLOCK);
|
||||
int SAM_ARRAY[] = { realDurationInSamples, realDurationInSamples,
|
||||
realDurationInSamples };
|
||||
write(SAM_ARRAY, 3);
|
||||
write(0);
|
||||
write(SUB);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
write(SUB, 4);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
write(frequency);
|
||||
write(0, 3);
|
||||
write(1);
|
||||
write(0, 3);
|
||||
writeId(0, 0);
|
||||
int ARR_6[] = { 0, 1, 1, 0, 1, 0x13 };
|
||||
write(ARR_6, 6);
|
||||
write(SUB);
|
||||
|
||||
write(BLOCK);
|
||||
write(0);
|
||||
write(realDurationInSamples);
|
||||
write(0, 2);
|
||||
write(numChannels);
|
||||
int ARR_3[] = { 1, 0, 1 };
|
||||
write(ARR_3, 3);
|
||||
}
|
||||
|
||||
static void writeTimingMarker() {
|
||||
write(BLOCK);
|
||||
write(numChannels + 2);
|
||||
write(0, 4);
|
||||
writeString("Timing Marker Pair");
|
||||
writeString("A1");
|
||||
writeString("A2");
|
||||
write(0, 2);
|
||||
write(SUB);
|
||||
write(0, 9);
|
||||
}
|
||||
|
||||
static void writeChannelDataFooter() {
|
||||
write(0, 3);
|
||||
write(1);
|
||||
write(1);
|
||||
write(0);
|
||||
write(numChannels);
|
||||
}
|
||||
|
||||
static int getChannelState(int ch, CompositeEvent *event) {
|
||||
switch (ch) {
|
||||
case 0:
|
||||
return event->primaryTrigger;
|
||||
case 1:
|
||||
return event->secondaryTrigger;
|
||||
case 2:
|
||||
return event->trg;
|
||||
case 3:
|
||||
return event->sync;
|
||||
case 4:
|
||||
return event->coil;
|
||||
case 5:
|
||||
return event->injector;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void writeEvents(CompositeEvent *events, int count) {
|
||||
// we need at least 2 records
|
||||
if (count < 2)
|
||||
return;
|
||||
int firstRecordTs = events[1].timestamp;
|
||||
int lastRecordTs = events[count - 1].timestamp;
|
||||
// we don't know the total duration, so we create a margin after the last record which equals to the duration of the first event
|
||||
realDurationInSamples = lastRecordTs + firstRecordTs;
|
||||
scaledDurationInSamples = realDurationInSamples / 4;
|
||||
|
||||
writeChannelDataHeader();
|
||||
|
||||
int64_t *chDeltas = (int64_t*) malloc(sizeof(int64_t) * count);
|
||||
int deltaCount = 0;
|
||||
|
||||
bool useLongDeltas = false;
|
||||
for (int ch = 0; ch < numChannels; ch++) {
|
||||
int chPrevState = -1;
|
||||
int prevTs = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
CompositeEvent *event = &events[i];
|
||||
|
||||
int chState = getChannelState(ch, event);
|
||||
int ts = event->timestamp;
|
||||
|
||||
if (chPrevState == -1) {
|
||||
chPrevState = chState;
|
||||
}
|
||||
if (chState != chPrevState) {
|
||||
long delta = ts - prevTs;
|
||||
if (delta > 0x7fff) {
|
||||
useLongDeltas = true;
|
||||
}
|
||||
// encode state
|
||||
if (chState == 0)
|
||||
delta |= SIGN_FLAG;
|
||||
|
||||
chDeltas[deltaCount++] = delta;
|
||||
|
||||
prevTs = ts;
|
||||
chPrevState = chState;
|
||||
}
|
||||
writeChannelData(ch, chDeltas, chPrevState, prevTs, useLongDeltas,
|
||||
deltaCount);
|
||||
}
|
||||
}
|
||||
|
||||
free(chDeltas);
|
||||
|
||||
writeChannelDataFooter();
|
||||
}
|
||||
|
||||
static void writeFooter() {
|
||||
write(BLOCK);
|
||||
for (int i = 0; i < numChannels; i++) {
|
||||
writeId(i, 1);
|
||||
}
|
||||
write(1);
|
||||
writeId(numChannels, 0x15);
|
||||
for (int i = 0; i < numChannels; i++) {
|
||||
writeId(i, 1);
|
||||
}
|
||||
write(1);
|
||||
write(0);
|
||||
write(frequency);
|
||||
write(0, 16);
|
||||
write(0x01);
|
||||
write(0x23); // ???
|
||||
write(SUB);
|
||||
|
||||
write(BLOCK);
|
||||
write(numChannels + 1);
|
||||
write(0);
|
||||
write(0xFFFFFFFFFFFFFFFFL);
|
||||
write(0xFFFFFFFFL);
|
||||
write(1);
|
||||
write(0, 3);
|
||||
|
||||
write(BLOCK);
|
||||
write(0);
|
||||
|
||||
write(BLOCK);
|
||||
write(0);
|
||||
write(1.0);
|
||||
write(SUB);
|
||||
write(0, 6);
|
||||
write(1);
|
||||
write(0, 4);
|
||||
|
||||
write(1);
|
||||
write(0x29); // ???
|
||||
write(SUB);
|
||||
|
||||
writeTimingMarker();
|
||||
}
|
||||
|
||||
void writeFile(CompositeEvent *events, int count) {
|
||||
|
||||
ptr = fopen("test.logicdata", "wb");
|
||||
|
||||
writeHeader();
|
||||
writeEvents(events, count);
|
||||
writeFooter();
|
||||
|
||||
fclose(ptr);
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* @file logicdata.h
|
||||
*
|
||||
* Created on: Jul 19, 2020
|
||||
* @author Andrey Belomutskiy, (c) 2012-2020
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct CompositeEvent {
|
||||
int timestamp;
|
||||
bool primaryTrigger;
|
||||
bool secondaryTrigger;
|
||||
bool trg;
|
||||
bool sync;
|
||||
bool coil;
|
||||
bool injector;
|
||||
};
|
||||
|
||||
void writeFile(CompositeEvent *events, int count);
|
|
@ -2,10 +2,27 @@
|
|||
#include <cstdio>
|
||||
#include "logicdata.h"
|
||||
|
||||
static CompositeEvent events[100];
|
||||
|
||||
|
||||
void setEvent(CompositeEvent *events, int index,
|
||||
int timestamp, bool primaryTrigger, bool secondaryTrigger, bool trg, bool sync, bool coil, bool injector) {
|
||||
events[index].timestamp = timestamp;
|
||||
events[index].primaryTrigger = primaryTrigger;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
printf(".logicdata Sandbox 20200719\n");
|
||||
|
||||
writeFile();
|
||||
|
||||
int index = 0;
|
||||
setEvent(events, index++, 10, false, false, false, false, false, false);
|
||||
setEvent(events, index++, 20, true, false, true, false, false, false);
|
||||
setEvent(events, index++, 30, false, false, false, false, false, false);
|
||||
setEvent(events, index++, 1000030, false, false, false, false, true, false);
|
||||
setEvent(events, index++, 2000030, false, false, true, false, false, true);
|
||||
|
||||
writeFile(events, index);
|
||||
|
||||
printf("Done!\n");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue