mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-27 01:56:14 +01:00
First checkin
This commit is contained in:
parent
e95a1a11a5
commit
2ebf1a6f66
67
.travis.yml
67
.travis.yml
|
@ -1,67 +0,0 @@
|
||||||
# Continuous Integration (CI) is the practice, in software
|
|
||||||
# engineering, of merging all developer working copies with a shared mainline
|
|
||||||
# several times a day < https://docs.platformio.org/page/ci/index.html >
|
|
||||||
#
|
|
||||||
# Documentation:
|
|
||||||
#
|
|
||||||
# * Travis CI Embedded Builds with PlatformIO
|
|
||||||
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
|
||||||
#
|
|
||||||
# * PlatformIO integration with Travis CI
|
|
||||||
# < https://docs.platformio.org/page/ci/travis.html >
|
|
||||||
#
|
|
||||||
# * User Guide for `platformio ci` command
|
|
||||||
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Please choose one of the following templates (proposed below) and uncomment
|
|
||||||
# it (remove "# " before each line) or use own configuration according to the
|
|
||||||
# Travis CI documentation (see above).
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Template #1: General project. Test it using existing `platformio.ini`.
|
|
||||||
#
|
|
||||||
|
|
||||||
# language: python
|
|
||||||
# python:
|
|
||||||
# - "2.7"
|
|
||||||
#
|
|
||||||
# sudo: false
|
|
||||||
# cache:
|
|
||||||
# directories:
|
|
||||||
# - "~/.platformio"
|
|
||||||
#
|
|
||||||
# install:
|
|
||||||
# - pip install -U platformio
|
|
||||||
# - platformio update
|
|
||||||
#
|
|
||||||
# script:
|
|
||||||
# - platformio run
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Template #2: The project is intended to be used as a library with examples.
|
|
||||||
#
|
|
||||||
|
|
||||||
# language: python
|
|
||||||
# python:
|
|
||||||
# - "2.7"
|
|
||||||
#
|
|
||||||
# sudo: false
|
|
||||||
# cache:
|
|
||||||
# directories:
|
|
||||||
# - "~/.platformio"
|
|
||||||
#
|
|
||||||
# env:
|
|
||||||
# - PLATFORMIO_CI_SRC=path/to/test/file.c
|
|
||||||
# - PLATFORMIO_CI_SRC=examples/file.ino
|
|
||||||
# - PLATFORMIO_CI_SRC=path/to/test/directory
|
|
||||||
#
|
|
||||||
# install:
|
|
||||||
# - pip install -U platformio
|
|
||||||
# - platformio update
|
|
||||||
#
|
|
||||||
# script:
|
|
||||||
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
|
|
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
|
||||||
"platformio.platformio-ide"
|
|
||||||
]
|
|
||||||
}
|
|
67
CVReader.ino
Normal file
67
CVReader.ino
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "DCCWaveform.h"
|
||||||
|
#include "DIAG.h"
|
||||||
|
bool verifyCV(int cv, byte bValue);
|
||||||
|
int readCv(int cv);
|
||||||
|
const int cvnums[]={1,2,3,4,5,17,18,19,21,22,29};
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
DCCWaveform::begin();
|
||||||
|
Serial.println(F("CVReader"));
|
||||||
|
|
||||||
|
DIAG(F("\n===================================\n"));
|
||||||
|
|
||||||
|
for (byte x=0;x<sizeof(cvnums)/sizeof(cvnums[0]);x++) {
|
||||||
|
DIAG(F("\n\nCV VERIFICATION %d = %s\n"),cvnums[x],readCV(cvnums[x])>=0?"OK":"FAIL");
|
||||||
|
}
|
||||||
|
|
||||||
|
DIAG(F("\nProgram complete, press reset to retry"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
byte cv1(byte opcode, int cv) {
|
||||||
|
cv--;
|
||||||
|
return (highByte(cv) & (byte)0x03) | opcode;
|
||||||
|
}
|
||||||
|
byte cv2(int cv) {
|
||||||
|
cv--;
|
||||||
|
return lowByte(cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
//// The functions below are lifted from the DCCApi for easy testing and experimentation.
|
||||||
|
// Once reliable, tha DCCApi should be updated to match
|
||||||
|
bool verifyCV(int cv, byte value) {
|
||||||
|
|
||||||
|
delay(2); // allow for decoder to quiesce latest pulse
|
||||||
|
|
||||||
|
|
||||||
|
byte message[] = {
|
||||||
|
cv1(0x74,cv) , // set-up to re-verify entire byte
|
||||||
|
cv2(cv),
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), 5);
|
||||||
|
return DCCWaveform::progTrack.getAck();
|
||||||
|
}
|
||||||
|
|
||||||
|
int readCV(int cv)
|
||||||
|
{
|
||||||
|
|
||||||
|
byte message[]={ cv1(0x78,cv) , // any CV>1023 will become modulus(1024) due to bit-mask of 0x03
|
||||||
|
cv2(cv),
|
||||||
|
0}; // trailing zero will be updated in loop below
|
||||||
|
|
||||||
|
byte value = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i<8; i++) {
|
||||||
|
message[2] = 0xE8 + i;
|
||||||
|
DCCWaveform::progTrack.schedulePacket(message,sizeof(message), 4); // NMRA recommends 5 rerad packets
|
||||||
|
value+= (DCCWaveform::progTrack.getAck()<<i);
|
||||||
|
}
|
||||||
|
DIAG(F("\n*** READ CV %d = %d ******\n"),cv,value);
|
||||||
|
return verifyCV(cv,value)?value:-1;
|
||||||
|
}
|
235
DCCWaveform.cpp
Normal file
235
DCCWaveform.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <TimerThree.h>
|
||||||
|
#include "DCCWaveform.h"
|
||||||
|
#include "DIAG.h"
|
||||||
|
DCCWaveform DCCWaveform::mainTrack(MAIN_POWER_PIN,MAIN_SIGNAL_PIN,MAIN_SENSE_PIN,PREAMBLE_BITS_MAIN,true);
|
||||||
|
DCCWaveform DCCWaveform::progTrack(PROG_POWER_PIN,PROG_SIGNAL_PIN,PROG_SENSE_PIN,PREAMBLE_BITS_PROG,false);
|
||||||
|
|
||||||
|
void DCCWaveform::begin() {
|
||||||
|
|
||||||
|
Timer3.initialize(58);
|
||||||
|
Timer3.disablePwm(MAIN_SIGNAL_PIN);
|
||||||
|
Timer3.disablePwm(PROG_SIGNAL_PIN);
|
||||||
|
Timer3.attachInterrupt(interruptHandler);
|
||||||
|
mainTrack.beginTrack();
|
||||||
|
progTrack.beginTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCWaveform::loop() {
|
||||||
|
mainTrack.checkPowerOverload();
|
||||||
|
progTrack.checkPowerOverload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static //
|
||||||
|
void DCCWaveform::interruptHandler() {
|
||||||
|
// call the timer edge sensitive actions for progtrack and maintrack
|
||||||
|
bool mainCall2=mainTrack.interrupt1();
|
||||||
|
bool progCall2=progTrack.interrupt1();
|
||||||
|
|
||||||
|
// call (if necessary) the procs to get the current bits
|
||||||
|
// these must complete within 50microsecs of the interrupt
|
||||||
|
// but they are only called ONCE PER BIT TRANSMITTED
|
||||||
|
// after the rising edge of the signal
|
||||||
|
if (mainCall2) mainTrack.interrupt2();
|
||||||
|
if (progCall2) progTrack.interrupt2();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// An instance of this class handles the DCC transmissions for one track. (main or prog)
|
||||||
|
// Interrupts are marshalled via the statics.
|
||||||
|
// A track has a current transmit buffer, and a pending buffer.
|
||||||
|
// When the current buffer is exhausted, either the pending buffer (if there is one waiting) or an idle buffer.
|
||||||
|
|
||||||
|
|
||||||
|
// This bitmask has 9 entries as each byte is trasmitted as a zero + 8 bits.
|
||||||
|
const byte bitMask[]={0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
|
||||||
|
|
||||||
|
|
||||||
|
DCCWaveform::DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain) {
|
||||||
|
// establish appropriate pins
|
||||||
|
powerPin=Arduino_to_GPIO_pin(powerPinNo);
|
||||||
|
directionPin=Arduino_to_GPIO_pin(directionPinNo);
|
||||||
|
sensePin=sensePinNo;
|
||||||
|
isMainTrack=isMain;
|
||||||
|
packetPending=false;
|
||||||
|
memcpy(transmitPacket,idlePacket,sizeof(idlePacket));
|
||||||
|
state=0;
|
||||||
|
requiredPreambles=preambleBits;
|
||||||
|
bytes_sent=0;
|
||||||
|
bits_sent=0;
|
||||||
|
nextSampleDue=0;
|
||||||
|
}
|
||||||
|
void DCCWaveform::beginTrack() {
|
||||||
|
pinMode2f(powerPin,OUTPUT);
|
||||||
|
pinMode2f(directionPin,OUTPUT);
|
||||||
|
pinMode(sensePin,INPUT);
|
||||||
|
setPowerMode(POWERMODE::ON);
|
||||||
|
DIAG(F("\nTrack started sensePin=%d\n"),sensePin);
|
||||||
|
}
|
||||||
|
|
||||||
|
POWERMODE DCCWaveform::getPowerMode() {
|
||||||
|
return powerMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
||||||
|
powerMode=mode;
|
||||||
|
digitalWrite2f(powerPin, mode==POWERMODE::ON ? HIGH:LOW);
|
||||||
|
if (mode==POWERMODE::ON) schedulePacket(resetMessage,2,20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DCCWaveform::checkPowerOverload() {
|
||||||
|
if (millis()<nextSampleDue) return;
|
||||||
|
int current;
|
||||||
|
int delay;
|
||||||
|
|
||||||
|
switch (powerMode) {
|
||||||
|
case POWERMODE::OFF:
|
||||||
|
delay=POWER_SAMPLE_OFF_WAIT;
|
||||||
|
break;
|
||||||
|
case POWERMODE::ON:
|
||||||
|
// Check current
|
||||||
|
current=analogRead(sensePin);
|
||||||
|
if (current < POWER_SAMPLE_MAX) delay=POWER_SAMPLE_ON_WAIT;
|
||||||
|
else {
|
||||||
|
setPowerMode(POWERMODE::OVERLOAD);
|
||||||
|
DIAG(F("\n*** %s TRACK POWER OVERLOAD pin=%d current=%d max=%d ***\n"),isMainTrack?"MAIN":"PROG",sensePin,current,POWER_SAMPLE_MAX);
|
||||||
|
delay=POWER_SAMPLE_OVERLOAD_WAIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POWERMODE::OVERLOAD:
|
||||||
|
// Try setting it back on after the OVERLOAD_WAIT
|
||||||
|
setPowerMode(POWERMODE::ON);
|
||||||
|
delay=POWER_SAMPLE_ON_WAIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delay=999; // cant get here..meaningless statement to avoid compiler warning.
|
||||||
|
}
|
||||||
|
nextSampleDue=millis()+delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// process time-edge sensitive part of interrupt
|
||||||
|
// return true if second level required
|
||||||
|
bool DCCWaveform::interrupt1() {
|
||||||
|
// NOTE: this must consume transmission buffers even if the power is off
|
||||||
|
// otherwise can cause hangs in main loop waiting for the pendingBuffer.
|
||||||
|
switch (state) {
|
||||||
|
case 0: // start of bit transmission
|
||||||
|
digitalWrite2f(directionPin, HIGH);
|
||||||
|
state = 1;
|
||||||
|
return true; // must call interrupt2
|
||||||
|
|
||||||
|
case 1: // 58Ms after case 0
|
||||||
|
if (currentBit) {
|
||||||
|
digitalWrite2f(directionPin, LOW);
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
else state = 2;
|
||||||
|
break;
|
||||||
|
case 2: digitalWrite2f(directionPin, LOW);
|
||||||
|
state = 3;
|
||||||
|
break;
|
||||||
|
case 3: state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
void DCCWaveform::interrupt2() {
|
||||||
|
// set currentBit to be the next bit to be sent.
|
||||||
|
|
||||||
|
if (remainingPreambles > 0 ) {
|
||||||
|
currentBit=true;
|
||||||
|
remainingPreambles--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// beware OF 9-BIT MASK generating a zero to start each byte
|
||||||
|
currentBit=transmitPacket[bytes_sent] & bitMask[bits_sent];
|
||||||
|
bits_sent++;
|
||||||
|
|
||||||
|
// If this is the last bit of a byte, prepare for the next byte
|
||||||
|
|
||||||
|
if (bits_sent==9) { // zero followed by 8 bits of a byte
|
||||||
|
//end of Byte
|
||||||
|
bits_sent=0;
|
||||||
|
bytes_sent++;
|
||||||
|
// if this is the last byte, prepere for next packet
|
||||||
|
if (bytes_sent >= transmitLength) {
|
||||||
|
// end of transmission buffer... repeat or switch to next message
|
||||||
|
bytes_sent = 0;
|
||||||
|
remainingPreambles=requiredPreambles;
|
||||||
|
|
||||||
|
if (transmitRepeats > 0) {
|
||||||
|
transmitRepeats--;
|
||||||
|
}
|
||||||
|
else if (packetPending) {
|
||||||
|
// Copy pending packet to transmit packet
|
||||||
|
for (int b=0;b<pendingLength;b++) transmitPacket[b]= pendingPacket[b];
|
||||||
|
transmitLength=pendingLength;
|
||||||
|
transmitRepeats=pendingRepeats;
|
||||||
|
packetPending=false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Fortunately reset and idle packets are the same length
|
||||||
|
memcpy( transmitPacket,isMainTrack?idlePacket:resetPacket, sizeof(idlePacket));
|
||||||
|
transmitLength=sizeof(idlePacket);
|
||||||
|
transmitRepeats=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Wait until there is no packet pending, then make this pending
|
||||||
|
void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) {
|
||||||
|
if (byteCount>=MAX_PACKET_SIZE) return; // allow for chksum
|
||||||
|
while(packetPending) delay(1);
|
||||||
|
|
||||||
|
byte checksum=0;
|
||||||
|
for (int b=0;b<byteCount; b++) {
|
||||||
|
checksum^=buffer[b];
|
||||||
|
pendingPacket[b]=buffer[b];
|
||||||
|
}
|
||||||
|
pendingPacket[byteCount]=checksum;
|
||||||
|
pendingLength=byteCount+1;
|
||||||
|
pendingRepeats=repeats;
|
||||||
|
packetPending=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool DCCWaveform::getAck()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isMainTrack) return false; // cant do this on main track
|
||||||
|
|
||||||
|
while(packetPending) delay(1); // wait until transmitter has gont into reset packets
|
||||||
|
delay(20); // time for enough resets
|
||||||
|
unsigned long timeout=millis()+ACK_TIMEOUT;
|
||||||
|
int maxCurrent=0;
|
||||||
|
bool result=false;
|
||||||
|
int upsamples=0;
|
||||||
|
int downsamples=0;
|
||||||
|
while(result==false && timeout>millis()) {
|
||||||
|
upsamples++;
|
||||||
|
delay(1);
|
||||||
|
int current=analogRead(sensePin);
|
||||||
|
maxCurrent=max(maxCurrent,current);
|
||||||
|
result=current > ACK_MIN_PULSE;
|
||||||
|
}
|
||||||
|
if (result) while( true) {
|
||||||
|
downsamples++;
|
||||||
|
delay(1);
|
||||||
|
int current=analogRead(sensePin);
|
||||||
|
maxCurrent=max(maxCurrent,current);
|
||||||
|
if (current<= ACK_MAX_NOT_PULSE)break;
|
||||||
|
}
|
||||||
|
DIAG(F("\nack=%d max=%d, up=%d, down=%d "),result,maxCurrent, upsamples,downsamples);
|
||||||
|
return result;
|
||||||
|
}
|
89
DCCWaveform.h
Normal file
89
DCCWaveform.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include <DIO2.h>
|
||||||
|
// This hardware configuration would normally be setup in a .h file elsewhere
|
||||||
|
const byte MAIN_POWER_PIN=3;
|
||||||
|
const byte MAIN_SIGNAL_PIN=12;
|
||||||
|
const byte MAIN_SENSE_PIN=A0;
|
||||||
|
|
||||||
|
const byte PROG_POWER_PIN=11;
|
||||||
|
const byte PROG_SIGNAL_PIN=13;
|
||||||
|
const byte PROG_SENSE_PIN=A1;
|
||||||
|
|
||||||
|
const int POWER_SAMPLE_MAX=300;
|
||||||
|
const int POWER_SAMPLE_ON_WAIT=100;
|
||||||
|
const int POWER_SAMPLE_OFF_WAIT=1000;
|
||||||
|
const int POWER_SAMPLE_OVERLOAD_WAIT=4000;
|
||||||
|
|
||||||
|
|
||||||
|
// ACK current analogRead values (vary depending on motor shield and cpu voltage)
|
||||||
|
const int ACK_TIMEOUT = 5 ; // millis getAck is prepared to wait for a signal
|
||||||
|
const int ACK_MAX_NOT_PULSE = 10 ; // current below which this is NOT a pulse any more
|
||||||
|
const int ACK_MIN_PULSE = 50 ; // current above which a pulse is recognised
|
||||||
|
|
||||||
|
const int PREAMBLE_BITS_MAIN=16;
|
||||||
|
const int PREAMBLE_BITS_PROG=22;
|
||||||
|
|
||||||
|
const byte MAX_PACKET_SIZE=12;
|
||||||
|
// NOTE: static functions are used for the overall controller, then
|
||||||
|
// one instance is created for each track.
|
||||||
|
|
||||||
|
|
||||||
|
enum class POWERMODE { OFF, ON, OVERLOAD };
|
||||||
|
const byte idleMessage[]={0xFF,0x00};
|
||||||
|
const byte resetMessage[]={0x00,0x00};
|
||||||
|
const byte idlePacket[]={0xFF,0x00,0xFF};
|
||||||
|
const byte resetPacket[]={0x00,0x00,0x00};
|
||||||
|
|
||||||
|
class DCCWaveform {
|
||||||
|
public:
|
||||||
|
DCCWaveform(byte powerPinNo, byte directionPinNo, byte sensePinNo, byte preambleBits, bool isMain);
|
||||||
|
static void begin();
|
||||||
|
static void loop();
|
||||||
|
static DCCWaveform mainTrack;
|
||||||
|
static DCCWaveform progTrack;
|
||||||
|
|
||||||
|
void beginTrack();
|
||||||
|
void setPowerMode(POWERMODE);
|
||||||
|
POWERMODE getPowerMode();
|
||||||
|
void checkPowerOverload();
|
||||||
|
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
|
||||||
|
volatile bool packetPending;
|
||||||
|
bool startAckProcess();
|
||||||
|
bool getAck();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void interruptHandler();
|
||||||
|
bool interrupt1();
|
||||||
|
void interrupt2();
|
||||||
|
|
||||||
|
POWERMODE powerMode;
|
||||||
|
|
||||||
|
// Transmission controller
|
||||||
|
byte transmitPacket[MAX_PACKET_SIZE]; // packet being transmitted
|
||||||
|
byte transmitLength;
|
||||||
|
byte transmitRepeats; // remaining repeats of transmission
|
||||||
|
byte remainingPreambles;
|
||||||
|
byte requiredPreambles;
|
||||||
|
bool currentBit; // bit to be transmitted
|
||||||
|
|
||||||
|
byte bits_sent; // 0-8 (yes 9 bits) sent for current byte
|
||||||
|
byte bytes_sent; // number of bytes sent from transmitPacket
|
||||||
|
|
||||||
|
byte state; // wave generator state machine
|
||||||
|
|
||||||
|
byte pendingPacket[MAX_PACKET_SIZE];
|
||||||
|
byte pendingLength;
|
||||||
|
byte pendingRepeats;
|
||||||
|
|
||||||
|
// Hardware pins
|
||||||
|
GPIO_pin_t directionPin;
|
||||||
|
GPIO_pin_t powerPin;
|
||||||
|
|
||||||
|
// current sampling
|
||||||
|
bool isMainTrack;
|
||||||
|
byte sensePin;
|
||||||
|
unsigned long nextSampleDue;
|
||||||
|
int ackBaseCurrent;
|
||||||
|
|
||||||
|
};
|
27
DIAG.cpp
Normal file
27
DIAG.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <arduino.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
void Serialprint(const __FlashStringHelper* input...) {
|
||||||
|
// thanks to Jan Turoň https://arduino.stackexchange.com/questions/56517/formatting-strings-in-arduino-for-output
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, input);
|
||||||
|
char* flash=(char*)input;
|
||||||
|
for(int i=0; ; ++i) {
|
||||||
|
char c=pgm_read_byte_near(flash+i);
|
||||||
|
if (c=='\0') return;
|
||||||
|
if(c!='%') { Serial.print(c); continue; }
|
||||||
|
i++;
|
||||||
|
c=pgm_read_byte_near(flash+i);
|
||||||
|
switch(c) {
|
||||||
|
case '%': Serial.print('%'); break;
|
||||||
|
case 's': Serial.print(va_arg(args, char*)); break;
|
||||||
|
case 'd': Serial.print(va_arg(args, int), DEC); break;
|
||||||
|
case 'b': Serial.print(va_arg(args, int), BIN); break;
|
||||||
|
case 'o': Serial.print(va_arg(args, int), OCT); break;
|
||||||
|
case 'x': Serial.print(va_arg(args, int), HEX); break;
|
||||||
|
case 'f': Serial.print(va_arg(args, double), 2); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
5
DIAG.h
Normal file
5
DIAG.h
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
void Serialprint(const __FlashStringHelper* input...);
|
||||||
|
#ifndef DIAG_ENABLED
|
||||||
|
#define DIAG_ENABLED true
|
||||||
|
#endif
|
||||||
|
#define DIAG if (DIAG_ENABLED) Serialprint
|
|
@ -1,39 +0,0 @@
|
||||||
|
|
||||||
This directory is intended for project header files.
|
|
||||||
|
|
||||||
A header file is a file containing C declarations and macro definitions
|
|
||||||
to be shared between several project source files. You request the use of a
|
|
||||||
header file in your project source file (C, C++, etc) located in `src` folder
|
|
||||||
by including it, with the C preprocessing directive `#include'.
|
|
||||||
|
|
||||||
```src/main.c
|
|
||||||
|
|
||||||
#include "header.h"
|
|
||||||
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Including a header file produces the same results as copying the header file
|
|
||||||
into each source file that needs it. Such copying would be time-consuming
|
|
||||||
and error-prone. With a header file, the related declarations appear
|
|
||||||
in only one place. If they need to be changed, they can be changed in one
|
|
||||||
place, and programs that include the header file will automatically use the
|
|
||||||
new version when next recompiled. The header file eliminates the labor of
|
|
||||||
finding and changing all the copies as well as the risk that a failure to
|
|
||||||
find one copy will result in inconsistencies within a program.
|
|
||||||
|
|
||||||
In C, the usual convention is to give header files names that end with `.h'.
|
|
||||||
It is most portable to use only letters, digits, dashes, and underscores in
|
|
||||||
header file names, and at most one dot.
|
|
||||||
|
|
||||||
Read more about using header files in official GCC documentation:
|
|
||||||
|
|
||||||
* Include Syntax
|
|
||||||
* Include Operation
|
|
||||||
* Once-Only Headers
|
|
||||||
* Computed Includes
|
|
||||||
|
|
||||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
|
46
lib/README
46
lib/README
|
@ -1,46 +0,0 @@
|
||||||
|
|
||||||
This directory is intended for project specific (private) libraries.
|
|
||||||
PlatformIO will compile them to static libraries and link into executable file.
|
|
||||||
|
|
||||||
The source code of each library should be placed in a an own separate directory
|
|
||||||
("lib/your_library_name/[here are source files]").
|
|
||||||
|
|
||||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
|
||||||
|
|
||||||
|--lib
|
|
||||||
| |
|
|
||||||
| |--Bar
|
|
||||||
| | |--docs
|
|
||||||
| | |--examples
|
|
||||||
| | |--src
|
|
||||||
| | |- Bar.c
|
|
||||||
| | |- Bar.h
|
|
||||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
|
||||||
| |
|
|
||||||
| |--Foo
|
|
||||||
| | |- Foo.c
|
|
||||||
| | |- Foo.h
|
|
||||||
| |
|
|
||||||
| |- README --> THIS FILE
|
|
||||||
|
|
|
||||||
|- platformio.ini
|
|
||||||
|--src
|
|
||||||
|- main.c
|
|
||||||
|
|
||||||
and a contents of `src/main.c`:
|
|
||||||
```
|
|
||||||
#include <Foo.h>
|
|
||||||
#include <Bar.h>
|
|
||||||
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
PlatformIO Library Dependency Finder will find automatically dependent
|
|
||||||
libraries scanning project source files.
|
|
||||||
|
|
||||||
More information about PlatformIO Library Dependency Finder
|
|
||||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
|
|
@ -1,14 +0,0 @@
|
||||||
; PlatformIO Project Configuration File
|
|
||||||
;
|
|
||||||
; Build options: build flags, source filter
|
|
||||||
; Upload options: custom upload port, speed and extra flags
|
|
||||||
; Library options: dependencies, extra library storages
|
|
||||||
; Advanced options: extra scripting
|
|
||||||
;
|
|
||||||
; Please visit documentation for the other options and examples
|
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
|
||||||
|
|
||||||
[env:megaatmega1280]
|
|
||||||
platform = atmelavr
|
|
||||||
board = megaatmega1280
|
|
||||||
framework = arduino
|
|
10
src/main.cpp
10
src/main.cpp
|
@ -1,10 +0,0 @@
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
Serial.println(F("CVReader"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// put your main code here, to run repeatedly:
|
|
||||||
}
|
|
11
test/README
11
test/README
|
@ -1,11 +0,0 @@
|
||||||
|
|
||||||
This directory is intended for PIO Unit Testing and project tests.
|
|
||||||
|
|
||||||
Unit Testing is a software testing method by which individual units of
|
|
||||||
source code, sets of one or more MCU program modules together with associated
|
|
||||||
control data, usage procedures, and operating procedures, are tested to
|
|
||||||
determine whether they are fit for use. Unit testing finds problems early
|
|
||||||
in the development cycle.
|
|
||||||
|
|
||||||
More information about PIO Unit Testing:
|
|
||||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
|
Loading…
Reference in New Issue
Block a user