mirror of
https://github.com/anklimov/lighthub
synced 2025-12-12 06:39:51 +03:00
Moving sketch and source files to lighthub folder according with comment @perl1234
This commit is contained in:
233
lighthub/dmx.cpp
Normal file
233
lighthub/dmx.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
#include "dmx.h"
|
||||
//#include <DmxSimple.h>
|
||||
//#include <DMXSerial.h>
|
||||
#include "options.h"
|
||||
#ifdef _dmxin
|
||||
#include <DMXSerial.h>
|
||||
#endif
|
||||
|
||||
uint8_t * DMXin = NULL;
|
||||
int D_State=0;
|
||||
|
||||
unsigned long D_checkT=0;
|
||||
|
||||
#ifdef _artnet
|
||||
#include <Artnet.h>
|
||||
Artnet *artnet = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
extern aJsonObject *items;
|
||||
extern aJsonObject *dmxArr;
|
||||
|
||||
|
||||
int itemCtrl2(char* name,int r,int g, int b, int w)
|
||||
{
|
||||
aJsonObject *itemArr= aJson.getObjectItem(items, name);
|
||||
|
||||
if (itemArr && (itemArr->type==aJson_Array))
|
||||
{
|
||||
|
||||
short itemtype = aJson.getArrayItem(itemArr,0)->valueint;
|
||||
short itemaddr = aJson.getArrayItem(itemArr,1)->valueint;
|
||||
switch (itemtype){
|
||||
#ifdef _dmxout
|
||||
case 0: //Dimmed light
|
||||
|
||||
DmxWrite(itemaddr, w);
|
||||
break;
|
||||
|
||||
|
||||
case 1: //Colour RGBW
|
||||
DmxWrite(itemaddr+3, w);
|
||||
|
||||
case 2: // RGB
|
||||
{
|
||||
|
||||
DmxWrite(itemaddr, r);
|
||||
DmxWrite(itemaddr+1, g);
|
||||
DmxWrite(itemaddr+2, b);
|
||||
|
||||
break; }
|
||||
#endif
|
||||
case 7: //Group
|
||||
aJsonObject *groupArr= aJson.getArrayItem(itemArr, 1);
|
||||
if (groupArr && (groupArr->type==aJson_Array))
|
||||
{ aJsonObject *i =groupArr->child;
|
||||
while (i)
|
||||
{ //Serial.println(i->valuestring);
|
||||
itemCtrl2(i->valuestring,r,g,b,w);
|
||||
i=i->next;}
|
||||
}
|
||||
} //itemtype
|
||||
// break;
|
||||
} //if have correct array
|
||||
}
|
||||
|
||||
|
||||
void DMXImmediateUpdate(short tch,short r, short g, short b, short w) {
|
||||
//Here only safe re-interable code for quick passthrow between DMX IN and DMX OUT
|
||||
if (dmxArr && (dmxArr->type==aJson_Array))
|
||||
|
||||
{
|
||||
char* itemname = aJson.getArrayItem(dmxArr,tch)->valuestring;
|
||||
itemCtrl2(itemname,r,g,b,w);
|
||||
}
|
||||
}
|
||||
|
||||
void DMXSemiImmediateUpdate(short tch,short trh, int val)
|
||||
{
|
||||
//Here any code for passthrow between DMX IN and DMX OUT in idle state
|
||||
}
|
||||
|
||||
void DMXput(void)
|
||||
{
|
||||
int t;
|
||||
for (short tch=0; tch<=3 ; tch++)
|
||||
{
|
||||
short base = tch*4;
|
||||
DMXImmediateUpdate(tch,DMXin[base],DMXin[base+1],DMXin[base+2],DMXin[base+3]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void DMXUpdate(void)
|
||||
{
|
||||
#if defined(_dmxin)
|
||||
int t;
|
||||
for (short tch=0; tch<=3 ; tch++)
|
||||
{
|
||||
short base = tch*4;
|
||||
bool updated = 0;
|
||||
|
||||
for (short trh=0; trh<4 ; trh++)
|
||||
if ((t=DMXSerial.read(base+trh+1)) != DMXin[base+trh])
|
||||
{
|
||||
D_State |= (1<<tch);
|
||||
updated=1;
|
||||
//Serial.print("Changed :"); Serial.print(DMXin[tch*4+trh]); Serial.print(" => "); Serial.print(t);Serial.println();
|
||||
DMXin[base+trh]=t;
|
||||
//DMXImmediateUpdate(tch,trh,t);
|
||||
//break;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
DMXImmediateUpdate(tch,DMXin[base],DMXin[base+1],DMXin[base+2],DMXin[base+3]);
|
||||
D_checkT=millis()+D_CHECKT;
|
||||
}
|
||||
}
|
||||
//Serial.print(D_State,BIN);Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DMXCheck(void)
|
||||
{
|
||||
// CHSV hsv;
|
||||
// CRGB rgb;
|
||||
#if defined(_dmxin)
|
||||
|
||||
short t,tch;
|
||||
//Here code for semi-immediate update
|
||||
for (t=1,tch=0; t<=8 ; t<<=1,tch++)
|
||||
if (D_State & t)
|
||||
{
|
||||
// Serial.print(D_State,BIN);Serial.print(":");
|
||||
D_State &= ~t;
|
||||
for (short trh=0; trh<4 ; trh++)
|
||||
DMXSemiImmediateUpdate(tch,trh,DMXin[tch*4+trh]);
|
||||
|
||||
}
|
||||
|
||||
if ((millis()<D_checkT) || (D_checkT==0)) return;
|
||||
D_checkT=0;
|
||||
|
||||
// Here code for network update
|
||||
//int ch = 0;
|
||||
DMXput();
|
||||
#ifdef _dmxout
|
||||
for (int i=1; i<17; i++) {Serial.print(DMXSerial.read(i));Serial.print(";");}
|
||||
#endif
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
|
||||
{
|
||||
#ifdef _dmxout
|
||||
for (int i = 0 ; i < length && i<MAX_CHANNELS ; i++)
|
||||
{
|
||||
DmxWrite(i+1,data[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DMXinSetup(int channels)
|
||||
{
|
||||
// //Use digital pin 3 for DMX output. Must be a PWM channel.
|
||||
// DmxSimple.usePin(pin);
|
||||
//DmxSimple.maxChannel(channels);
|
||||
|
||||
#if defined(_dmxin)
|
||||
DMXin = new uint8_t [channels];
|
||||
|
||||
DMXSerial.init(DMXReceiver,0,channels);
|
||||
if (DMXSerial.getBuffer()) {Serial.print(F("Init in ch:"));Serial.println(channels);} else Serial.println(F("DMXin Buffer alloc err"));
|
||||
//DMXSerial.maxChannel(channels);
|
||||
DMXSerial.attachOnUpdate(&DMXUpdate);
|
||||
#endif
|
||||
|
||||
#ifdef _artnet
|
||||
// this will be called for each packet received
|
||||
if (artnet) artnet->setArtDmxCallback(onDmxFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DMXoutSetup(int channels,int pin)
|
||||
{
|
||||
#ifdef _dmxout
|
||||
#if defined(__AVR__)
|
||||
DmxSimple.usePin(pin);
|
||||
DmxSimple.maxChannel(channels);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__ESP__)
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
dmxout.setTxMaxChannels(channels);
|
||||
dmxout.beginWrite();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void ArtnetSetup()
|
||||
{
|
||||
#ifdef _artnet
|
||||
if (!artnet) artnet = new Artnet;
|
||||
// this will be called for each packet received
|
||||
if (artnet) artnet->setArtDmxCallback(onDmxFrame);
|
||||
#endif
|
||||
}
|
||||
71
lighthub/dmx.h
Normal file
71
lighthub/dmx.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#define D_UPDATED1 1
|
||||
#define D_UPDATED2 2
|
||||
#define D_UPDATED3 4
|
||||
#define D_UPDATED4 8
|
||||
#define D_CHECKT 300
|
||||
|
||||
#define MAX_CHANNELS 60
|
||||
//define MAX_IN_CHANNELS 16
|
||||
|
||||
//#define DMX_OUT_PIN 3
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#if defined(_dmxout)
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <DmxSimple.h>
|
||||
#define DmxWrite DmxSimple.write
|
||||
#endif
|
||||
|
||||
#if defined(__ESP__)
|
||||
#include <ESP-Dmx.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
#include <DmxDue.h>
|
||||
#define DmxWrite dmxout.write
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _artnet
|
||||
#include <Artnet.h>
|
||||
extern Artnet *artnet;
|
||||
#endif
|
||||
|
||||
#ifdef _dmxin
|
||||
#include <DMXSerial.h>
|
||||
#endif
|
||||
|
||||
#include "aJSON.h"
|
||||
|
||||
extern aJsonObject *dmxArr;
|
||||
|
||||
|
||||
void DMXput(void);
|
||||
void DMXinSetup(int channels);
|
||||
void DMXoutSetup(int channels,int pin);
|
||||
void ArtnetSetup();
|
||||
void DMXCheck(void);
|
||||
int itemCtrl2(char* name,int r,int g, int b, int w);
|
||||
void ArtnetSetup();
|
||||
147
lighthub/inputs.cpp
Normal file
147
lighthub/inputs.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#include "inputs.h"
|
||||
#include "aJSON.h"
|
||||
#include "item.h"
|
||||
#include <PubSubClient2.h>
|
||||
|
||||
extern PubSubClient client;
|
||||
|
||||
Input::Input(char * name) //Constructor
|
||||
{
|
||||
if (name)
|
||||
inputObj= aJson.getObjectItem(inputs, name);
|
||||
else inputObj=NULL;
|
||||
|
||||
Parse();
|
||||
}
|
||||
|
||||
|
||||
Input::Input(int pin) //Constructor
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
Input::Input(aJsonObject * obj) //Constructor
|
||||
{
|
||||
inputObj= obj;
|
||||
Parse();
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean Input::isValid ()
|
||||
{
|
||||
return (pin && store);
|
||||
}
|
||||
|
||||
void Input::Parse()
|
||||
{
|
||||
store = NULL;
|
||||
inType = 0;
|
||||
pin = 0;
|
||||
|
||||
if (inputObj && (inputObj->type==aJson_Object))
|
||||
{
|
||||
aJsonObject * s;
|
||||
|
||||
s = aJson.getObjectItem(inputObj,"T");
|
||||
if (s) inType = s->valueint;
|
||||
|
||||
pin = atoi(inputObj->name);
|
||||
|
||||
|
||||
s = aJson.getObjectItem(inputObj,"S");
|
||||
if (!s) { Serial.print("In: ");Serial.print(pin);Serial.print("/");Serial.println(inType);
|
||||
aJson.addNumberToObject(inputObj,"S", 0);
|
||||
s = aJson.getObjectItem(inputObj,"S");
|
||||
}
|
||||
|
||||
if (s) store= (inStore *) &s->valueint;
|
||||
}
|
||||
}
|
||||
|
||||
int Input::Pool ()
|
||||
{
|
||||
boolean v;
|
||||
if (!isValid()) return -1;
|
||||
|
||||
|
||||
if (inType & IN_ACTIVE_HIGH)
|
||||
{ pinMode(pin, INPUT);
|
||||
v = (digitalRead(pin)==HIGH);
|
||||
}
|
||||
else
|
||||
{ pinMode(pin, INPUT_PULLUP);
|
||||
v = (digitalRead(pin)==LOW);
|
||||
}
|
||||
if (v!=store->cur) // value changed
|
||||
{
|
||||
if (store->bounce) store->bounce--;
|
||||
else //confirmed change
|
||||
{
|
||||
Changed(v);
|
||||
store->cur=v;
|
||||
}
|
||||
}
|
||||
else // no change
|
||||
store->bounce=3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Input::Changed (int val)
|
||||
{
|
||||
Serial.print(pin);Serial.print("=");Serial.println(val);
|
||||
aJsonObject * item = aJson.getObjectItem(inputObj,"item");
|
||||
aJsonObject * scmd = aJson.getObjectItem(inputObj,"scmd");
|
||||
aJsonObject * rcmd = aJson.getObjectItem(inputObj,"rcmd");
|
||||
aJsonObject * emit = aJson.getObjectItem(inputObj,"emit");
|
||||
|
||||
if (emit)
|
||||
{
|
||||
|
||||
if (val)
|
||||
{ //send set command
|
||||
if (!scmd) client.publish(emit->valuestring,"ON"); else if (strlen(scmd->valuestring)) client.publish(emit->valuestring,scmd->valuestring);
|
||||
}
|
||||
else
|
||||
{ //send reset command
|
||||
if (!rcmd) client.publish(emit->valuestring,"OFF"); else if (strlen(rcmd->valuestring)) client.publish(emit->valuestring,rcmd->valuestring);
|
||||
}
|
||||
}
|
||||
|
||||
if (item)
|
||||
{
|
||||
Item it(item->valuestring);
|
||||
if (it.isValid())
|
||||
{
|
||||
if (val)
|
||||
{ //send set command
|
||||
if (!scmd) it.Ctrl(CMD_ON,0,NULL,true); else if (strlen(scmd->valuestring)) it.Ctrl(txt2cmd(scmd->valuestring),0,NULL,true);
|
||||
}
|
||||
else
|
||||
{ //send reset command
|
||||
if (!rcmd) it.Ctrl(CMD_OFF,0,NULL,true); else if (strlen(rcmd->valuestring)) it.Ctrl(txt2cmd(rcmd->valuestring),0,NULL,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
lighthub/inputs.h
Normal file
97
lighthub/inputs.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#include "aJSON.h"
|
||||
|
||||
#define IN_ACTIVE_HIGH 128 // High level = PUSHED/ CLOSED/ ON othervise :Low Level
|
||||
#define IN_ANALOG 64 // Analog input
|
||||
#define IN_RE 32 // Rotary Encoder (for further use)
|
||||
|
||||
#define IN_PUSH_ON 0 // PUSH - ON, Release - OFF (ovverrided by pcmd/rcmd) - DEFAULT
|
||||
#define IN_PUSH_TOGGLE 1 // Every physicall push toggle logical switch on/off
|
||||
|
||||
|
||||
// in syntaxis
|
||||
// "pin": { "T":"N", "emit":"out_emit", item:"out_item", "scmd": "ON,OFF,TOGGLE,INCREASE,DECREASE", "rcmd": "ON,OFF,TOGGLE,INCREASE,DECREASE", "rcmd":"repeat_command" }
|
||||
|
||||
//
|
||||
//Switch/Restore all
|
||||
//"pin": { "T":"1", "emit":"/all", item:"local_all", "scmd": "OFF", "rcmd": "RESTORE"}
|
||||
|
||||
//
|
||||
//Normal (not button) Switch (toggled mode)
|
||||
//"pin": { "T":"1", "emit":"/light1", item:"light1", "scmd": "TOGGLE", "rcmd": "TOGGLE"}
|
||||
// or
|
||||
// "pin": { "T":"xx", "emit":"/light1", item:"light1"}
|
||||
|
||||
//Normal (not button) Switch
|
||||
//"pin": { "T":"0", "emit":"/light1", item:"light1", "scmd": "ON", "rcmd": "OFF"}
|
||||
// or
|
||||
// "pin": { "T":"0", "emit":"/light1", item:"light1"}
|
||||
//or
|
||||
// "pin": { "emit":"/light1", item:"light1"}
|
||||
|
||||
//1-Button dimmer
|
||||
//"pin": { "T":"1", "emit":"/light1", item:"light1", "scmd": "ON", srcmd:"INCREASE",rrcmd:"DECREASE", "rcmd": "OFF"}
|
||||
// or
|
||||
// "pin": { "T":"xx", "emit":"/light1", item:"light1"}
|
||||
|
||||
//2-Buttons dimmer
|
||||
//"pin1": { "T":"0", "emit":"/light1", item:"light1", "scmd": "ON", repcmd:"INCREASE"}
|
||||
//"pin2": { "T":"0", "emit":"/light1", item:"light1", "scmd": "OFF", repcmd:"INCREASE"}
|
||||
|
||||
extern aJsonObject *inputs;
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
long int aslong;
|
||||
struct
|
||||
{
|
||||
int8_t reserve;
|
||||
int8_t logicState;
|
||||
int8_t bounce;
|
||||
int8_t cur;
|
||||
};
|
||||
} inStore;
|
||||
|
||||
class Input
|
||||
{
|
||||
public:
|
||||
aJsonObject *inputObj;
|
||||
uint8_t inType;
|
||||
uint8_t pin;
|
||||
inStore * store;
|
||||
|
||||
Input(int pin);
|
||||
Input(aJsonObject * obj);
|
||||
Input(char * name);
|
||||
|
||||
boolean isValid ();
|
||||
void Changed (int val);
|
||||
|
||||
int Pool ();
|
||||
protected:
|
||||
void Parse();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
960
lighthub/item.cpp
Normal file
960
lighthub/item.cpp
Normal file
@@ -0,0 +1,960 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#include "item.h"
|
||||
#include "aJSON.h"
|
||||
|
||||
#ifdef _dmxout
|
||||
|
||||
/*
|
||||
#if defined(__AVR__)
|
||||
#include <DmxSimple.h>
|
||||
#endif
|
||||
|
||||
#if defined(__ESP__)
|
||||
#include <ESP-Dmx.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
#include <DmxDue.h>
|
||||
#endif
|
||||
*/
|
||||
#include "dmx.h"
|
||||
#include "FastLED.h"
|
||||
#endif
|
||||
|
||||
#include <ModbusMaster.h>
|
||||
#include <PubSubClient2.h>
|
||||
|
||||
#define dimPar SERIAL_8E1
|
||||
#define fmPar SERIAL_8N1
|
||||
|
||||
short modbusBusy=0;
|
||||
extern aJsonObject * modbusitem;
|
||||
|
||||
|
||||
int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value);
|
||||
extern PubSubClient client;
|
||||
//extern const char* outprefix;
|
||||
const char outprefix[] PROGMEM = "/myhome/s_out/";
|
||||
|
||||
static unsigned long lastctrl = 0;
|
||||
static aJsonObject * lastobj = NULL;
|
||||
|
||||
int txt2cmd (char * payload)
|
||||
{
|
||||
int cmd=-1;
|
||||
|
||||
// Check for command
|
||||
if (strcmp(payload,"ON")==0) cmd=CMD_ON;
|
||||
else if (strcmp(payload,"OFF")==0) cmd=CMD_OFF;
|
||||
else if (strcmp(payload,"REST")==0) cmd=CMD_RESTORE;
|
||||
else if (strcmp(payload,"TOGGLE")==0) cmd=CMD_TOGGLE;
|
||||
else if (strcmp(payload,"HALT")==0) cmd=CMD_HALT;
|
||||
else if (*payload=='-' || (*payload>='0' && *payload<='9')) cmd=0;
|
||||
else if (*payload=='{') cmd=-2;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
const short defval[4] = {0,0,0,0}; //Type,Arg,Val,Cmd
|
||||
|
||||
Item::Item(aJsonObject * obj)//Constructor
|
||||
{
|
||||
itemArr= obj;
|
||||
Parse();
|
||||
}
|
||||
|
||||
void Item::Parse()
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
// Todo - avoid static enlarge for every types
|
||||
for (int i=aJson.getArraySize(itemArr);i<4;i++) aJson.addItemToArray(itemArr,aJson.createItem(int(defval[i]))); //Enlarge item to 4 elements. VAL=int if no other definition in conf
|
||||
|
||||
|
||||
itemType = aJson.getArrayItem(itemArr,I_TYPE)->valueint;
|
||||
itemArg = aJson.getArrayItem(itemArr,I_ARG);
|
||||
itemVal = aJson.getArrayItem(itemArr,I_VAL);
|
||||
|
||||
|
||||
Serial.print(F(" Item:"));
|
||||
Serial.print(itemArr->name);Serial.print(F(" T:"));
|
||||
Serial.print(itemType);Serial.print(F(" ="));Serial.println(getArg());
|
||||
}
|
||||
}
|
||||
|
||||
Item::Item(char * name) //Constructor
|
||||
{
|
||||
if (name)
|
||||
itemArr= aJson.getObjectItem(items, name);
|
||||
else itemArr=NULL;
|
||||
|
||||
Parse();
|
||||
}
|
||||
|
||||
uint8_t Item::getCmd()
|
||||
{
|
||||
aJsonObject *t = aJson.getArrayItem(itemArr,I_CMD);
|
||||
if (t)
|
||||
return t->valueint;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
|
||||
void Item::setCmd(uint8_t cmd)
|
||||
{
|
||||
aJsonObject *t = aJson.getArrayItem(itemArr,I_CMD);
|
||||
if (t)
|
||||
t->valueint=cmd;
|
||||
}
|
||||
|
||||
int Item::getArg(short n) //Return arg int or first array element if Arg is array
|
||||
{ if (!itemArg) return -1;
|
||||
if (itemArg->type==aJson_Int) return itemArg->valueint;
|
||||
else if (itemArg->type==aJson_Array) return aJson.getArrayItem(itemArg,n)->valueint;
|
||||
else return -2;
|
||||
}
|
||||
/*
|
||||
int Item::getVal(short n) //Return Val from Value array
|
||||
{ if (!itemVal) return -1;
|
||||
else if (itemVal->type==aJson_Array)
|
||||
{
|
||||
aJsonObject *t = aJson.getArrayItem(itemVal,n);
|
||||
if (t) return t->valueint;
|
||||
else return -3;
|
||||
}
|
||||
else return -2;
|
||||
}
|
||||
*/
|
||||
|
||||
long int Item::getVal() //Return Val if val is int or first elem of Value array
|
||||
{ if (!itemVal) return -1;
|
||||
if (itemVal->type==aJson_Int) return itemVal->valueint;
|
||||
else if (itemVal->type==aJson_Array)
|
||||
{
|
||||
aJsonObject *t = aJson.getArrayItem(itemVal,0);
|
||||
if (t) return t->valueint;
|
||||
else return -3;
|
||||
}
|
||||
else return -2;
|
||||
}
|
||||
/*
|
||||
void Item::setVal(short n, int par) // Only store if VAL is array defined in config to avoid waste of RAM
|
||||
{
|
||||
if (!itemVal || itemVal->type!=aJson_Array) return;
|
||||
Serial.print(F(" Store p="));Serial.print(n);Serial.print(F(" Val="));Serial.println(par);
|
||||
for (int i=aJson.getArraySize(itemVal);i<=n;i++) aJson.addItemToArray(itemVal,aJson.createItem(int(0))); //Enlarge array of Values
|
||||
|
||||
aJsonObject *t = aJson.getArrayItem(itemVal,n);
|
||||
if (t) t->valueint=par;
|
||||
}
|
||||
*/
|
||||
|
||||
void Item::setVal(long int par) // Only store if VAL is int (autogenerated or config-defined)
|
||||
{
|
||||
if (!itemVal || itemVal->type!=aJson_Int) return;
|
||||
Serial.print(F(" Store "));Serial.print(F(" Val="));Serial.println(par);
|
||||
itemVal->valueint=par;
|
||||
}
|
||||
|
||||
|
||||
boolean Item::isValid ()
|
||||
{
|
||||
return (itemArr && (itemArr->type==aJson_Array));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void Item::copyPar (aJsonObject *itemV)
|
||||
{ int n=aJson.getArraySize(itemV);
|
||||
//for (int i=aJson.getArraySize(itemVal);i<n;i++) aJson.addItemToArray(itemVal,aJson.createItem(int(0))); //Enlarge array of Values
|
||||
for (int i=0;i<n;i++) setPar(i,aJson.getArrayItem(itemV,i)->valueint);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef ESP32
|
||||
void analogWrite(int pin, int val)
|
||||
{
|
||||
//TBD
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
boolean Item::getEnableCMD(int delta)
|
||||
{
|
||||
return ((millis()-lastctrl>(unsigned long) delta) );//|| (itemArr!=lastobj));
|
||||
}
|
||||
|
||||
int Item::Ctrl(short cmd, short n, int * Par, boolean send)
|
||||
{
|
||||
|
||||
Serial.print(F("Cmd="));Serial.println(cmd);
|
||||
//va_list vl;
|
||||
|
||||
int _Par[3]={0,0,0};
|
||||
if (Par==NULL) Par=_Par;
|
||||
|
||||
int iaddr=getArg();
|
||||
HSVstore st;
|
||||
//Store Parameter(s) into json VAL
|
||||
|
||||
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
int t;
|
||||
case CMD_TOGGLE:
|
||||
switch (t=getCmd())
|
||||
{
|
||||
case CMD_ON:
|
||||
case CMD_SET:
|
||||
cmd=CMD_OFF;
|
||||
break;
|
||||
case CMD_OFF:
|
||||
case CMD_HALT:
|
||||
case 0:
|
||||
case -1: //No stored command yet
|
||||
cmd=CMD_ON;
|
||||
break;
|
||||
}//switch old cmd
|
||||
//Serial.print("Tog/oldcmd:");Serial.print(t);Serial.print(F(" new "));Serial.println(cmd);
|
||||
break;
|
||||
|
||||
case CMD_RESTORE:
|
||||
if (itemType!=CH_GROUP) //individual threating of channels. Ignore restore command for groups
|
||||
switch (t=getCmd())
|
||||
{
|
||||
case CMD_HALT: //previous command was HALT ?
|
||||
Serial.print(F("Restored from:"));Serial.println(t);
|
||||
cmd=CMD_ON; //turning on
|
||||
break;
|
||||
default:
|
||||
return -3;
|
||||
}//switch old cmd
|
||||
} //switch cmd
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case 0: //no command
|
||||
|
||||
setCmd(CMD_SET);
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
|
||||
case CH_RGBW: //only if configured VAL array
|
||||
if (!Par[1]) itemType=CH_WHITE;
|
||||
case CH_GROUP: //Save for groups as well
|
||||
case CH_RGB:
|
||||
st.h=Par[0];
|
||||
st.s=Par[1];
|
||||
st.v=Par[2];
|
||||
setVal(st.aslong);
|
||||
break;
|
||||
|
||||
case CH_DIMMER: //Everywhere, in flat VAL
|
||||
case CH_MODBUS:
|
||||
case CH_THERMO:
|
||||
case CH_VC:
|
||||
case CH_VCTEMP:
|
||||
setVal(Par[0]);
|
||||
|
||||
}//itemtype
|
||||
|
||||
lastctrl=millis(); //last controlled object ond timestamp update
|
||||
lastobj =itemArr;
|
||||
|
||||
break;
|
||||
|
||||
case CMD_ON:
|
||||
if (getCmd()!=CMD_ON)
|
||||
|
||||
{
|
||||
short params=0;
|
||||
//retrive stored values
|
||||
st.aslong=getVal();
|
||||
if (st.aslong>0) //Stored smthng
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
//case CH_GROUP:
|
||||
case CH_RGBW:
|
||||
case CH_RGB:
|
||||
Par[0]=st.h;
|
||||
Par[1]=st.s;
|
||||
Par[2]=st.v;
|
||||
params=3;
|
||||
SendCmd(0,params,Par); // Send restored triplet
|
||||
break;
|
||||
|
||||
case CH_DIMMER: //Everywhere, in flat VAL
|
||||
case CH_MODBUS:
|
||||
case CH_VC:
|
||||
case CH_VCTEMP:
|
||||
Par[0]=st.aslong;
|
||||
params=1;
|
||||
SendCmd(0,params,Par); // Send restored parameter
|
||||
break;
|
||||
case CH_THERMO:
|
||||
Par[0]=st.aslong;
|
||||
params=0;
|
||||
SendCmd(CMD_ON); // Just ON (switch)
|
||||
break;
|
||||
default:
|
||||
SendCmd(cmd); // Just send ON
|
||||
}//itemtype
|
||||
else
|
||||
{// Default settings
|
||||
Serial.print(st.aslong);
|
||||
Serial.println(F(": No stored values - default"));
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
case CH_VCTEMP:
|
||||
Par[0]=20;
|
||||
break;
|
||||
default:
|
||||
Par[0]=100;
|
||||
Par[1]=0;
|
||||
Par[2]=100;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (short i=0;i<params ;i++)
|
||||
{
|
||||
Serial.print(F("Restored: "));Serial.print(i);Serial.print(F("="));Serial.println(Par[i]);
|
||||
}
|
||||
|
||||
|
||||
setCmd(cmd);
|
||||
}
|
||||
else
|
||||
{ //Double ON - apply special preset - clean white full power
|
||||
switch (itemType)
|
||||
{
|
||||
case CH_RGBW:
|
||||
Serial.println(F("Force White"));
|
||||
itemType=CH_WHITE;
|
||||
Par[1]=0; //Zero saturation
|
||||
Par[2]=100; //Full power
|
||||
|
||||
// Store
|
||||
st.h=Par[0];
|
||||
st.s=Par[1];
|
||||
st.v=Par[2];
|
||||
setVal(st.aslong);
|
||||
|
||||
//Send to OH
|
||||
SendCmd(0,3,Par);
|
||||
break;
|
||||
} //itemtype
|
||||
} //else
|
||||
|
||||
//Serial.print("Sa:");Serial.println(Par[1]);
|
||||
if ((itemType==CH_RGBW) && (Par[1]==0)) itemType=CH_WHITE;
|
||||
|
||||
|
||||
break; //CMD_ON
|
||||
|
||||
case CMD_OFF:
|
||||
if (getCmd()!=CMD_HALT) //if channels are halted - OFF to be ignored (restore issue)
|
||||
{
|
||||
Par[0]=0;Par[1]=0;Par[2]=0;
|
||||
setCmd(cmd);
|
||||
SendCmd(cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_HALT:
|
||||
|
||||
if (isActive()>0)
|
||||
{
|
||||
Par[0]=0;Par[1]=0;Par[2]=0;
|
||||
setCmd(cmd);
|
||||
SendCmd(CMD_OFF);
|
||||
Serial.println(F(" Halted"));
|
||||
}
|
||||
|
||||
|
||||
}//switch cmd
|
||||
|
||||
|
||||
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
|
||||
#ifdef _dmxout
|
||||
case CH_DIMMER: //Dimmed light
|
||||
|
||||
DmxWrite(iaddr, map(Par[0],0,100,0,255));
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case CH_RGBW: //Colour RGBW
|
||||
{
|
||||
int k;
|
||||
DmxWrite(iaddr+3, k=map((100-Par[1])*Par[2],0,10000,0,255));
|
||||
Serial.print(F("W:"));Serial.println(k);
|
||||
}
|
||||
|
||||
|
||||
case CH_RGB: // RGB
|
||||
|
||||
{
|
||||
|
||||
|
||||
CRGB rgb= CHSV(map(Par[0],0,365,0,255),map(Par[1],0,100,0,255),map(Par[2],0,100,0,255));
|
||||
|
||||
DmxWrite(iaddr, rgb.r);
|
||||
DmxWrite(iaddr+1, rgb.g);
|
||||
DmxWrite(iaddr+2, rgb.b);
|
||||
|
||||
|
||||
break; }
|
||||
|
||||
|
||||
case CH_WHITE:
|
||||
DmxWrite(iaddr, 0);
|
||||
DmxWrite(iaddr+1, 0);
|
||||
DmxWrite(iaddr+2, 0);
|
||||
DmxWrite(iaddr+3, map(Par[2],0,100,0,255));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef _modbus
|
||||
case CH_MODBUS:
|
||||
{
|
||||
|
||||
if ((itemArg->type == aJson_Array) && (aJson.getArraySize(itemArg)==3))
|
||||
{
|
||||
int _addr= aJson.getArrayItem(itemArg,0)->valueint;
|
||||
int _reg = aJson.getArrayItem(itemArg,1)->valueint;
|
||||
int _mask= aJson.getArrayItem(itemArg,2)->valueint;
|
||||
|
||||
modbusSet(_addr,_reg,_mask,map(Par[0],0,100,0,0x3f));
|
||||
}
|
||||
break;}
|
||||
#endif
|
||||
|
||||
case CH_GROUP://Group
|
||||
{
|
||||
//aJsonObject *groupArr= aJson.getArrayItem(itemArr, 1);
|
||||
if (itemArg->type==aJson_Array)
|
||||
{
|
||||
aJsonObject *i =itemArg->child;
|
||||
while (i)
|
||||
{
|
||||
Item it (i->valuestring);
|
||||
// it.copyPar(itemVal);
|
||||
it.Ctrl(cmd,n,Par,send); //// was true
|
||||
i=i->next;
|
||||
} //while
|
||||
} //if
|
||||
} //case
|
||||
break;
|
||||
case CH_RELAY:
|
||||
{int k;
|
||||
pinMode(iaddr,OUTPUT);
|
||||
digitalWrite(iaddr,k=((cmd==CMD_ON)?HIGH:LOW));
|
||||
Serial.print(F("Pin:"));Serial.print(iaddr);Serial.print(F("="));Serial.println(k);
|
||||
break;
|
||||
case CH_THERMO:
|
||||
///thermoSet(name,cmd,Par1); all cativities done - update temp & cmd
|
||||
break;
|
||||
}
|
||||
case CH_PWM:
|
||||
{int k;
|
||||
short inverse=0;
|
||||
if (iaddr<0) {iaddr=-iaddr;inverse=1;}
|
||||
pinMode(iaddr,OUTPUT);
|
||||
//timer 0 for pin 13 and 4
|
||||
//timer 1 for pin 12 and 11
|
||||
//timer 2 for pin 10 and 9
|
||||
//timer 3 for pin 5 and 3 and 2
|
||||
//timer 4 for pin 8 and 7 and 6
|
||||
//prescaler = 1 ---> PWM frequency is 31000 Hz
|
||||
//prescaler = 2 ---> PWM frequency is 4000 Hz
|
||||
//prescaler = 3 ---> PWM frequency is 490 Hz (default value)
|
||||
//prescaler = 4 ---> PWM frequency is 120 Hz
|
||||
//prescaler = 5 ---> PWM frequency is 30 Hz
|
||||
//prescaler = 6 ---> PWM frequency is <20 Hz
|
||||
int tval = 7; // this is 111 in binary and is used as an eraser
|
||||
#if defined(__AVR_ATmega2560__)
|
||||
TCCR4B &= ~tval; // this operation (AND plus NOT), set the three bits in TCCR2B to 0
|
||||
TCCR3B &= ~tval;
|
||||
tval=2;
|
||||
TCCR4B|=tval;
|
||||
TCCR3B|=tval;
|
||||
#endif
|
||||
if (inverse) k=map(Par[0],100,0,0,255);
|
||||
else k=map(Par[0],0,100,0,255);
|
||||
analogWrite(iaddr,k);
|
||||
Serial.print(F("Pin:"));Serial.print(iaddr);Serial.print(F("="));Serial.println(k);
|
||||
break;
|
||||
}
|
||||
#ifdef _modbus
|
||||
case CH_VC:
|
||||
|
||||
VacomSetFan(Par[0],cmd);
|
||||
break;
|
||||
|
||||
|
||||
case CH_VCTEMP:
|
||||
{
|
||||
Item it (itemArg->valuestring);
|
||||
if (it.isValid() && it.itemType==CH_VC)
|
||||
VacomSetHeat(it.getArg(),Par[0],cmd);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // switch itemtype
|
||||
// break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int Item::isActive()
|
||||
{
|
||||
HSVstore st;
|
||||
int val=0;
|
||||
|
||||
if (!isValid()) return -1;
|
||||
//Serial.print(itemArr->name);
|
||||
int cmd=getCmd();
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_ON:
|
||||
//Serial.println(" active");
|
||||
return 1;
|
||||
case CMD_OFF:
|
||||
case CMD_HALT:
|
||||
//Serial.println(" inactive");
|
||||
return 0;
|
||||
}
|
||||
|
||||
st.aslong=getVal();
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
//case CH_GROUP:
|
||||
case CH_RGBW:
|
||||
case CH_RGB:
|
||||
|
||||
val=st.v;
|
||||
break;
|
||||
|
||||
case CH_DIMMER: //Everywhere, in flat VAL
|
||||
case CH_MODBUS:
|
||||
case CH_THERMO:
|
||||
case CH_VC:
|
||||
case CH_VCTEMP:
|
||||
val=st.aslong;
|
||||
} //switch
|
||||
Serial.print(F(":="));Serial.println(val);
|
||||
if (val) return 1; else return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
short thermoSet(char * name, short cmd, short t)
|
||||
{
|
||||
|
||||
if (items)
|
||||
{
|
||||
aJsonObject *item= aJson.getObjectItem(items, name);
|
||||
if (item && (item->type==aJson_Array) && (aJson.getArrayItem(item, I_TYPE)->valueint==CH_THERMO))
|
||||
{
|
||||
|
||||
for (int i=aJson.getArraySize(item);i<4;i++) aJson.addItemToArray(item,aJson.createItem(int(0))); //Enlarge item to 4 elements
|
||||
if (!cmd) aJson.getArrayItem(item, I_VAL)->valueint=t;
|
||||
aJson.getArrayItem(item, I_CMD)->valueint=cmd;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PooledItem::Idle()
|
||||
{
|
||||
if (PoolingInterval)
|
||||
{
|
||||
Pool();
|
||||
next=millis()+PoolingInterval;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
addr 10d
|
||||
Снять аварию 42001 (2001=7d1) =>4
|
||||
|
||||
[22:20:33] Write task has completed successfully
|
||||
[22:20:33] <= Response: 0A 06 07 D0 00 04 89 FF
|
||||
[22:20:32] => Poll: 0A 06 07 D0 00 04 89 FF
|
||||
|
||||
100%
|
||||
2003-> 10000
|
||||
[22:24:05] Write task has completed successfully
|
||||
[22:24:05] <= Response: 0A 06 07 D2 27 10 33 C0
|
||||
[22:24:05] => Poll: 0A 06 07 D2 27 10 33 C0
|
||||
|
||||
ON
|
||||
2001->1
|
||||
[22:24:50] Write task has completed successfully
|
||||
[22:24:50] <= Response: 0A 06 07 D0 00 01 49 FC
|
||||
[22:24:50] => Poll: 0A 06 07 D0 00 01 49 FC
|
||||
|
||||
OFF
|
||||
2001->0
|
||||
[22:25:35] Write task has completed successfully
|
||||
[22:25:35] <= Response: 0A 06 07 D0 00 00 88 3C
|
||||
[22:25:34] => Poll: 0A 06 07 D0 00 00 88 3C
|
||||
|
||||
|
||||
POOL 2101x10
|
||||
[22:27:29] <= Response: 0A 03 14 00 23 00 00 27 10 13 88 0B 9C 00 32 00 F8 00 F2 06 FA 01 3F AD D0
|
||||
[22:27:29] => Poll: 0A 03 08 34 00 0A 87 18
|
||||
|
||||
*/
|
||||
|
||||
void mb_fail(short addr, short op, int val, int cmd)
|
||||
{
|
||||
Serial.println(F("Modbus op failed"));
|
||||
|
||||
}
|
||||
|
||||
extern ModbusMaster node;
|
||||
|
||||
int Item::VacomSetFan (int8_t val, int8_t cmd)
|
||||
{
|
||||
int addr=getArg();
|
||||
Serial.print(F("VC#"));Serial.print(addr);Serial.print(F("="));Serial.println(val);
|
||||
|
||||
|
||||
if (modbusBusy) {mb_fail(1,addr,val,cmd);return -1;}
|
||||
modbusBusy=1;
|
||||
|
||||
uint8_t j, result;
|
||||
uint16_t data[1];
|
||||
|
||||
modbusSerial.begin(9600,fmPar);
|
||||
node.begin(addr,modbusSerial);
|
||||
|
||||
if (val) {
|
||||
node.writeSingleRegister(2001-1,4+1);//delay(500);
|
||||
//node.writeSingleRegister(2001-1,1);
|
||||
}
|
||||
else node.writeSingleRegister(2001-1,0);
|
||||
delay (50);
|
||||
node.writeSingleRegister(2003-1,val*100);
|
||||
|
||||
modbusBusy=0;
|
||||
|
||||
}
|
||||
|
||||
#define a 0.1842
|
||||
#define b -36.68
|
||||
|
||||
int Item::VacomSetHeat(int addr,int8_t val, int8_t cmd)
|
||||
{
|
||||
|
||||
Serial.print(F("VC_heat#"));Serial.print(addr);Serial.print(F("="));Serial.print(val);Serial.print(F(" cmd="));Serial.println(cmd);
|
||||
if (modbusBusy) {mb_fail(2,addr,val,cmd);return -1;}
|
||||
modbusBusy=1;
|
||||
|
||||
modbusSerial.begin(9600,fmPar);
|
||||
node.begin(addr,modbusSerial);
|
||||
|
||||
uint16_t regval;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_OFF:
|
||||
case CMD_HALT:
|
||||
regval=0;
|
||||
break;
|
||||
|
||||
default:
|
||||
regval=round(((float)val-b)*10/a);
|
||||
}
|
||||
|
||||
Serial.println(regval);
|
||||
node.writeSingleRegister(2004-1,regval);
|
||||
modbusBusy=0;
|
||||
}
|
||||
|
||||
|
||||
int Item::SendCmd(short cmd,short n, int * Par)
|
||||
{
|
||||
|
||||
/// ToDo: relative patches, configuration
|
||||
|
||||
char addrstr[32];
|
||||
//char addrbuf[17];
|
||||
char valstr[16]="";
|
||||
|
||||
strcpy_P (addrstr,outprefix);
|
||||
strncat (addrstr,itemArr->name,sizeof(addrstr)); ////
|
||||
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_ON:
|
||||
strcpy(valstr,"ON");
|
||||
break;
|
||||
case CMD_OFF:
|
||||
case CMD_HALT:
|
||||
strcpy(valstr,"OFF");
|
||||
break;
|
||||
// TODO send Par
|
||||
case 0:
|
||||
case CMD_SET:
|
||||
if (Par)
|
||||
for (short i=0;i<n;i++)
|
||||
{
|
||||
char num [4];
|
||||
snprintf(num,sizeof(num),"%d",Par[i]);
|
||||
strncat(valstr,num,sizeof(valstr));
|
||||
if (i!=n-1)
|
||||
{
|
||||
strcpy(num,",");
|
||||
strncat(valstr,num,sizeof(valstr));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
Serial.print(addrstr);Serial.print(F("->"));Serial.println(valstr);
|
||||
client.publish(addrstr, valstr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value)
|
||||
{
|
||||
|
||||
if (modbusBusy) {mb_fail(3,addr,value,0);return -1;};
|
||||
modbusBusy=1;
|
||||
|
||||
modbusSerial.begin(9600,dimPar);
|
||||
node.begin(addr,modbusSerial);
|
||||
|
||||
|
||||
if (_mask)
|
||||
{value <<= 8; value |= (0xff);}
|
||||
else {value &= 0xff; value |= (0xff00);}
|
||||
|
||||
Serial.print(addr);Serial.print(F("=>"));Serial.print(_reg,HEX);Serial.print(F(":"));Serial.println(value,HEX);
|
||||
|
||||
node.writeSingleRegister(_reg,value);
|
||||
modbusBusy=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Item::checkFM()
|
||||
{
|
||||
if (modbusBusy) return -1;
|
||||
modbusBusy=1;
|
||||
|
||||
uint8_t j, result;
|
||||
int16_t data;
|
||||
|
||||
|
||||
aJsonObject *out =aJson.createObject();
|
||||
char * outch;
|
||||
char addrstr[32];
|
||||
|
||||
strcpy_P (addrstr,outprefix);
|
||||
strncat(addrstr,itemArr->name,sizeof(addrstr)-1);
|
||||
strncat(addrstr,"_stat",sizeof(addrstr)-1);
|
||||
|
||||
// aJson.addStringToObject(out,"type", "rect");
|
||||
|
||||
|
||||
modbusSerial.begin(9600,fmPar);
|
||||
node.begin(getArg(),modbusSerial);
|
||||
|
||||
|
||||
result = node.readHoldingRegisters(2101-1, 10);
|
||||
|
||||
// do something with data if read is successful
|
||||
if (result == node.ku8MBSuccess)
|
||||
{ Serial.print(F(" FM Val :"));
|
||||
for (j = 0; j < 10; j++)
|
||||
{
|
||||
data = node.getResponseBuffer(j);
|
||||
Serial.print(data,HEX);Serial.print(F("-"));
|
||||
|
||||
}
|
||||
|
||||
// aJson.addNumberToObject(out,"gsw", (int) node.getResponseBuffer(1));
|
||||
aJson.addNumberToObject(out,"V", (int) node.getResponseBuffer(2)/100.);
|
||||
// aJson.addNumberToObject(out,"f", (int) node.getResponseBuffer(3)/100.);
|
||||
aJson.addNumberToObject(out,"RPM", (int) node.getResponseBuffer(4));
|
||||
aJson.addNumberToObject(out,"I", (int) node.getResponseBuffer(5)/100.);
|
||||
aJson.addNumberToObject(out,"M", (int) node.getResponseBuffer(6)/10.);
|
||||
// aJson.addNumberToObject(out,"P", (int) node.getResponseBuffer(7)/10.);
|
||||
// aJson.addNumberToObject(out,"U", (int) node.getResponseBuffer(8)/10.);
|
||||
// aJson.addNumberToObject(out,"Ui", (int) node.getResponseBuffer(9));
|
||||
aJson.addNumberToObject(out,"sw", (int) node.getResponseBuffer(0));
|
||||
|
||||
Serial.println();
|
||||
} else {Serial.print(F("Modbus pooling error=")); Serial.println(result,HEX); }
|
||||
|
||||
if (node.getResponseBuffer(0) & 8) //Active fault
|
||||
{
|
||||
result = node.readHoldingRegisters(2111-1, 1);
|
||||
if (result == node.ku8MBSuccess) aJson.addNumberToObject(out,"flt", (int) node.getResponseBuffer(0));
|
||||
} else aJson.addNumberToObject(out,"flt", 0);
|
||||
|
||||
delay(50);
|
||||
result = node.readHoldingRegisters(20-1, 4);
|
||||
|
||||
// do something with data if read is successful
|
||||
if (result == node.ku8MBSuccess)
|
||||
{ Serial.print(F(" PI Val :"));
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
data = node.getResponseBuffer(j);
|
||||
Serial.print(data);Serial.print(F("-"));
|
||||
|
||||
}
|
||||
|
||||
int set = node.getResponseBuffer(0);
|
||||
if (set) aJson.addNumberToObject(out,"set", set*a+b);
|
||||
aJson.addNumberToObject(out,"t", (int) node.getResponseBuffer(1)*a+b);
|
||||
// aJson.addNumberToObject(out,"d", (int) node.getResponseBuffer(2)*a+b);
|
||||
int pwr= node.getResponseBuffer(3);
|
||||
if (pwr>0) aJson.addNumberToObject(out,"pwr", pwr/10.); else aJson.addNumberToObject(out,"pwr",0);
|
||||
|
||||
|
||||
Serial.println();
|
||||
} else {Serial.print(F("Modbus pooling error=")); Serial.println(result,HEX); }
|
||||
|
||||
|
||||
outch=aJson.print(out);
|
||||
client.publish(addrstr, outch);
|
||||
free (outch);
|
||||
aJson.deleteItem(out);
|
||||
|
||||
modbusBusy=0;
|
||||
}
|
||||
|
||||
|
||||
int Item::checkModbus()
|
||||
{
|
||||
if (modbusBusy) return -1;
|
||||
modbusBusy=1;
|
||||
|
||||
uint8_t result;
|
||||
|
||||
uint16_t addr = getArg(0);
|
||||
uint16_t reg = getArg(1);
|
||||
short mask = getArg(2);
|
||||
|
||||
int data;
|
||||
|
||||
//node.setSlave(addr);
|
||||
|
||||
modbusSerial.begin(9600,dimPar);
|
||||
node.begin(addr,modbusSerial);
|
||||
|
||||
|
||||
result = node.readHoldingRegisters(reg, 1);
|
||||
|
||||
if (result == node.ku8MBSuccess)
|
||||
{
|
||||
data=node.getResponseBuffer(0);
|
||||
Serial.print(F("Modbus Val: ")); Serial.println(data,HEX);
|
||||
checkModbus(data);
|
||||
}
|
||||
else {Serial.print(F("Modbus pooling error=")); Serial.println(result,HEX); }
|
||||
|
||||
modbusBusy=0;
|
||||
|
||||
// Looking 1 step ahead for modbus item, which uses same register
|
||||
Item nextItem(modbusitem->next);
|
||||
if (modbusitem && nextItem.isValid() && nextItem.itemType==CH_MODBUS && nextItem.getArg(0)==addr && nextItem.getArg(1)==reg)
|
||||
{
|
||||
nextItem.checkModbus(data);
|
||||
modbusitem=modbusitem->next;
|
||||
if (!modbusitem) modbusitem=items->child;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Item::checkModbus(int data)
|
||||
{
|
||||
short mask = getArg(2);
|
||||
int d=data;
|
||||
if (mask) d>>=8; d&=0xff;
|
||||
d=map(d,0,0x3f,0,100);
|
||||
int cmd=getCmd();
|
||||
//Serial.println(d);
|
||||
if (getVal()!=d || d && cmd==CMD_OFF || d && cmd==CMD_HALT) //volume changed or turned on manualy
|
||||
{
|
||||
if (d)
|
||||
|
||||
{ // Actually turned on
|
||||
if (cmd==CMD_OFF || cmd==CMD_HALT) SendCmd(CMD_ON); //update OH with ON if it was turned off before
|
||||
SendCmd(0,1,&d); //update OH with value
|
||||
setCmd(CMD_ON); //store command
|
||||
setVal(d); //store value
|
||||
}
|
||||
else {
|
||||
if (cmd!=CMD_HALT && cmd!=CMD_OFF)
|
||||
{
|
||||
setCmd(CMD_OFF); // store command (not value)
|
||||
SendCmd(CMD_OFF);// update OH
|
||||
}
|
||||
}
|
||||
} //if data changed
|
||||
}
|
||||
|
||||
int Item::Pool()
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case CH_MODBUS:
|
||||
checkModbus();
|
||||
break;
|
||||
case CH_VC:
|
||||
checkFM();
|
||||
}
|
||||
}
|
||||
|
||||
130
lighthub/item.h
Normal file
130
lighthub/item.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
#include "options.h"
|
||||
|
||||
#define CH_DIMMER 0 //DMX 1 ch
|
||||
#define CH_RGBW 1 //DMX 4 ch
|
||||
#define CH_RGB 2 //DMX 3 ch
|
||||
#define CH_PWM 3 //PWM output directly to PIN
|
||||
#define CH_MODBUS 4 //Modbus AC Dimmer
|
||||
#define CH_THERMO 5 //Simple ON/OFF thermostat
|
||||
#define CH_RELAY 6 //ON_OFF relay output
|
||||
#define CH_GROUP 7 //Group pseudochannel
|
||||
#define CH_VCTEMP 8 //Vacom PID regulator
|
||||
#define CH_VC 9 //Vacom modbus motor regulator
|
||||
#define CH_WHITE 127//
|
||||
|
||||
#define CMD_ON 1
|
||||
#define CMD_OFF 2
|
||||
#define CMD_HALT 5
|
||||
#define CMD_RESTORE 3
|
||||
#define CMD_TOGGLE 4
|
||||
#define CMD_CURTEMP 127
|
||||
#define CMD_SET 9
|
||||
|
||||
#define I_TYPE 0 //Type of item
|
||||
#define I_ARG 1 //Chanel-type depended argument or array of arguments (pin, address etc)
|
||||
#define I_VAL 2 //Latest preset (int or array of presets)
|
||||
#define I_CMD 3 //Latest CMD received
|
||||
#define I_EXT 4 //Chanell-depended extension - array
|
||||
|
||||
#include "aJSON.h"
|
||||
|
||||
extern aJsonObject *items;
|
||||
|
||||
int txt2cmd (char * payload);
|
||||
|
||||
typedef union
|
||||
{
|
||||
long int aslong;
|
||||
struct
|
||||
{
|
||||
int16_t h;
|
||||
int8_t s;
|
||||
int8_t v;
|
||||
};
|
||||
} HSVstore;
|
||||
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
aJsonObject *itemArr, *itemArg,*itemVal;
|
||||
uint8_t itemType;
|
||||
|
||||
|
||||
Item(char * name);
|
||||
Item(aJsonObject * obj);
|
||||
boolean isValid ();
|
||||
virtual int Ctrl(short cmd, short n=0, int * Par=NULL, boolean send=false);
|
||||
int getArg(short n=0);
|
||||
boolean getEnableCMD(int delta);
|
||||
//int getVal(short n); //From VAL array. Negative if no array
|
||||
long int getVal(); //From int val OR array
|
||||
uint8_t getCmd();
|
||||
void setCmd(uint8_t cmd);
|
||||
//void setVal(uint8_t n, int par);
|
||||
void setVal(long int par);
|
||||
//void copyPar (aJsonObject *itemV);
|
||||
inline int On (){Ctrl(CMD_ON);};
|
||||
inline int Off(){Ctrl(CMD_OFF);};
|
||||
inline int Toggle(){Ctrl(CMD_TOGGLE);};
|
||||
int Pool ();
|
||||
int SendCmd(short cmd,short n=0, int * Par=NULL);
|
||||
|
||||
protected:
|
||||
int VacomSetFan (int8_t val, int8_t cmd=0);
|
||||
int VacomSetHeat(int addr, int8_t val, int8_t cmd=0);
|
||||
int isActive();
|
||||
void Parse();
|
||||
int checkModbus();
|
||||
int checkModbus(int data);
|
||||
|
||||
int checkFM();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
||||
class PooledItem : public Item
|
||||
{
|
||||
public:
|
||||
virtual int Changed() = 0;
|
||||
virtual void Idle ();
|
||||
protected:
|
||||
int PoolingInterval;
|
||||
unsigned long next;
|
||||
virtual int Pool() =0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Vacon : public Item
|
||||
{
|
||||
public:
|
||||
int Pool ();
|
||||
virtual int Ctrl(short cmd, short n=0, int * Par=NULL);
|
||||
protected:
|
||||
};
|
||||
|
||||
*/
|
||||
1158
lighthub/lighthub.ino
Normal file
1158
lighthub/lighthub.ino
Normal file
File diff suppressed because it is too large
Load Diff
30
lighthub/options.h
Normal file
30
lighthub/options.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Configuration of drivers enabled
|
||||
#define _dmxin
|
||||
#define _dmxout
|
||||
#define _owire
|
||||
#define _modbus
|
||||
#define _artnet
|
||||
|
||||
|
||||
#if defined(__AVR__)
|
||||
//All options available
|
||||
#define modbusSerial Serial2
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
/// DMX not deployed yet
|
||||
#undef _dmxin
|
||||
#define modbusSerial Serial2
|
||||
#define dmxout DmxDue4
|
||||
#define dmxin DmxDue1
|
||||
#endif
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#undef _dmxin
|
||||
#undef _dmxout
|
||||
#define modbusSerial Serial
|
||||
#endif
|
||||
|
||||
#ifndef _dmxout
|
||||
#undef _artnet
|
||||
#endif
|
||||
457
lighthub/owSwitch.cpp
Normal file
457
lighthub/owSwitch.cpp
Normal file
@@ -0,0 +1,457 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. (anklimov@gmail.com) All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
|
||||
*/
|
||||
|
||||
#include "owSwitch.h"
|
||||
#include "owTerm.h"
|
||||
#include <Arduino.h>
|
||||
#include "utils.h"
|
||||
|
||||
int owRead2408(uint8_t* addr) {
|
||||
uint8_t buf[13];
|
||||
// PrintBytes(buf, 13, true);
|
||||
if (!net) return -1;
|
||||
net->reset();
|
||||
net->select(addr);
|
||||
|
||||
// uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily.
|
||||
buf[0] = 0xF0; // Read PIO Registers
|
||||
buf[1] = 0x88; // LSB address
|
||||
buf[2] = 0x00; // MSB address
|
||||
net->write_bytes(buf, 3,1);
|
||||
net->read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16
|
||||
net->reset();
|
||||
|
||||
if (!OneWire::check_crc16(buf, 11, &buf[11])) {
|
||||
Serial.print(F("CRC failure in DS2408 at "));
|
||||
PrintBytes(addr, 8, true);
|
||||
PrintBytes(buf+3,10);
|
||||
return -1;
|
||||
}
|
||||
return (buf[3]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
int read1W(int i)
|
||||
{
|
||||
|
||||
Serial.print("1W requested: ");
|
||||
Serial.println (i);
|
||||
|
||||
int t=-1;
|
||||
switch (term[i][0]){
|
||||
case 0x29: // DS2408
|
||||
t=owRead2408(term[i]);
|
||||
break;
|
||||
case 0x28: // Thermomerer
|
||||
t=sensors.getTempC(term[i]);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int ow2408out(DeviceAddress addr,uint8_t cur)
|
||||
{
|
||||
if (!net) return -1;
|
||||
uint8_t buf[5];
|
||||
net->reset();
|
||||
net->select(addr);
|
||||
buf[0] = 0x5A; // Write PIO Registers
|
||||
buf[1]=cur;
|
||||
buf[2] = ~buf[1];
|
||||
net->write_bytes(buf, 3);
|
||||
net->read_bytes(buf+3, 2);
|
||||
//net.reset();
|
||||
PrintBytes(buf, 5);
|
||||
Serial.print(F(" Out: "));Serial.print(buf[1],BIN);
|
||||
Serial.print(F(" In: "));Serial.println(buf[4],BIN);
|
||||
if (buf[3] != 0xAA) {
|
||||
Serial.print(F("Write failure in DS2408 at "));
|
||||
PrintBytes(addr, 8, true);
|
||||
return -2;
|
||||
}
|
||||
return buf[4];
|
||||
}
|
||||
int cntrl2408(uint8_t* addr, int subchan, int val) {
|
||||
if (!net) return -1;
|
||||
|
||||
uint8_t buf;
|
||||
int mask,devnum;
|
||||
|
||||
if ((devnum=owFind(addr))<0) return -1;
|
||||
buf=regs[devnum];
|
||||
Serial.print(F("Current: "));Serial.println(buf,BIN);
|
||||
mask=0;
|
||||
int r,f;
|
||||
switch (subchan) {
|
||||
case 0:
|
||||
if ((buf & SW_STAT0) != ((val)?SW_STAT0:0))
|
||||
{
|
||||
if (wstat[devnum] & (SW_PULSE0|SW_PULSE_P0))
|
||||
{
|
||||
wstat[devnum]|=SW_CHANGED_P0;
|
||||
Serial.println(F("Rollback 0"));
|
||||
}
|
||||
else {
|
||||
wstat[devnum]|=SW_PULSE0;
|
||||
regs[devnum] = (ow2408out(addr,(buf | SW_MASK) & ~SW_OUT0) & SW_INMASK) ^ SW_STAT0; ///?
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case 1:
|
||||
if ((buf & SW_STAT1) != ((val)?SW_STAT1:0))
|
||||
{
|
||||
if (wstat[devnum] & (SW_PULSE1|SW_PULSE_P1))
|
||||
{
|
||||
wstat[devnum]|=SW_CHANGED_P1;
|
||||
Serial.println(F("Rollback 1"));
|
||||
}
|
||||
else {
|
||||
wstat[devnum]|=SW_PULSE1;
|
||||
regs[devnum] =(ow2408out(addr,(buf | SW_MASK) & ~SW_OUT1) & SW_INMASK) ^ SW_STAT1; /// -?
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
/* Assume AUX 0&1 it is INPUTS - no write
|
||||
case 2:
|
||||
mask=SW_AUX0;
|
||||
break;
|
||||
case 3:
|
||||
mask=SW_AUX1; */
|
||||
}
|
||||
|
||||
/* Assume AUX 0&1 it is INPUTS - no write
|
||||
switch (val) {
|
||||
case 0: buf=(buf | SW_MASK | SW_OUT0 | SW_OUT1) | mask;
|
||||
break;
|
||||
default: buf= (buf | SW_MASK | SW_OUT0 | SW_OUT1) & ~mask;
|
||||
}
|
||||
|
||||
|
||||
regs[devnum] = ow2408out(addr,buf); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cntrl2890(uint8_t* addr, int val) {
|
||||
uint8_t buf[13];
|
||||
if (!net) return -1;
|
||||
// case 0x2C: //Dimmer
|
||||
Serial.print(F("Update dimmer "));PrintBytes(addr, 8, true);Serial.print(F(" = "));
|
||||
Serial.println(val);
|
||||
|
||||
net->reset();
|
||||
net->select(addr);
|
||||
|
||||
buf[0] = 0x55;
|
||||
buf[1] = 0x4c;
|
||||
net->write_bytes(buf, 2);
|
||||
net->read_bytes(buf+2, 1); // check if buf[2] == val = ok
|
||||
buf[3]=0x96;
|
||||
net->write_bytes(buf+3, 1);
|
||||
net->read_bytes(buf+4, 1); // 0 = updated ok
|
||||
PrintBytes(buf, 5, true);
|
||||
|
||||
net->select(addr);
|
||||
|
||||
|
||||
if (val==-1)
|
||||
{
|
||||
buf[0] = 0xF0;
|
||||
net->write_bytes(buf, 1);
|
||||
net->read_bytes(buf+1, 2); // check if buf[2] == val = ok
|
||||
net->reset();
|
||||
return buf[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = 0x0F;
|
||||
buf[1] = val;
|
||||
net->write_bytes(buf, 2);
|
||||
net->read_bytes(buf+2, 1); // check if buf[2] == val = ok
|
||||
buf[3]=0x96;
|
||||
net->write_bytes(buf+3, 1);
|
||||
net->read_bytes(buf+4, 1); // 0 = updated ok
|
||||
net->reset();
|
||||
PrintBytes(buf, 5, true);
|
||||
return buf[2];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define DS2413_FAMILY_ID 0x3A
|
||||
#define DS2413_ACCESS_READ 0xF5
|
||||
#define DS2413_ACCESS_WRITE 0x5A
|
||||
#define DS2413_ACK_SUCCESS 0xAA
|
||||
#define DS2413_ACK_ERROR 0xFF
|
||||
|
||||
#define DS2413_IN_PinA 1
|
||||
#define DS2413_IN_LatchA 2
|
||||
#define DS2413_IN_PinB 4
|
||||
#define DS2413_IN_LatchB 8
|
||||
|
||||
#define DS2413_OUT_PinA 1
|
||||
#define DS2413_OUT_PinB 2
|
||||
|
||||
|
||||
/*
|
||||
byte read(void)
|
||||
{
|
||||
bool ok = false;
|
||||
uint8_t results;
|
||||
|
||||
oneWire.reset();
|
||||
oneWire.select(address);
|
||||
oneWire.write(DS2413_ACCESS_READ);
|
||||
|
||||
results = oneWire.read(); / Get the register results /
|
||||
ok = (!results & 0x0F) == (results >> 4); / Compare nibbles /
|
||||
results &= 0x0F; / Clear inverted values /
|
||||
|
||||
oneWire.reset();
|
||||
|
||||
// return ok ? results : -1;
|
||||
return results;
|
||||
}
|
||||
|
||||
bool write(uint8_t state)
|
||||
{
|
||||
uint8_t ack = 0;
|
||||
|
||||
/ Top six bits must '1' /
|
||||
state |= 0xFC;
|
||||
|
||||
oneWire.reset();
|
||||
oneWire.select(address);
|
||||
oneWire.write(DS2413_ACCESS_WRITE);
|
||||
oneWire.write(state);
|
||||
oneWire.write(~state); / Invert data and resend /
|
||||
ack = oneWire.read(); / 0xAA=success, 0xFF=failure /
|
||||
if (ack == DS2413_ACK_SUCCESS)
|
||||
{
|
||||
oneWire.read(); / Read the status byte /
|
||||
}
|
||||
oneWire.reset();
|
||||
|
||||
return (ack == DS2413_ACK_SUCCESS ? true : false);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int cntrl2413(uint8_t* addr, int subchan, int val) {
|
||||
|
||||
|
||||
bool ok = false;
|
||||
uint8_t results;
|
||||
uint8_t cmd;
|
||||
uint8_t set=0;
|
||||
uint8_t count =10;
|
||||
if (!net) return -1;
|
||||
// case 0x85: //Switch
|
||||
Serial.print(F("Update switch "));PrintBytes(addr, 8, false); Serial.print(F("/"));Serial.print(subchan);Serial.print(F(" = "));Serial.println(val);
|
||||
while (count--)
|
||||
{
|
||||
net->reset();
|
||||
net->select(addr);
|
||||
net->setStrongPullup();
|
||||
|
||||
cmd = DS2413_ACCESS_READ;
|
||||
net->write(cmd);
|
||||
|
||||
results = net->read();
|
||||
Serial.print(F("Got: ")); Serial.println(results,BIN);
|
||||
//Serial.println((~results & 0x0F),BIN); Serial.println ((results >> 4),BIN);
|
||||
|
||||
ok = (~results & 0x0F) == (results >> 4); // Compare nibbles
|
||||
results &= 0x0F; // Clear inverted values
|
||||
|
||||
if (ok) {Serial.println(F("Read ok"));break;} else {Serial.println(F("read Error"));delay(1);}
|
||||
} //while
|
||||
|
||||
if (ok && (val>=0))
|
||||
{
|
||||
count=10;
|
||||
while (count--)
|
||||
{
|
||||
net->reset();
|
||||
net->select(addr);
|
||||
|
||||
if (results & DS2413_IN_LatchA) set|=DS2413_OUT_PinA;
|
||||
if (results & DS2413_IN_LatchB) set|=DS2413_OUT_PinB;
|
||||
|
||||
switch (subchan) {
|
||||
case 0:
|
||||
if (!val) set|=DS2413_OUT_PinA; else set &= ~DS2413_OUT_PinA;
|
||||
break;
|
||||
case 1:
|
||||
if (!val) set|=DS2413_OUT_PinB; else set &= ~DS2413_OUT_PinB;
|
||||
};
|
||||
set |= 0xFC;
|
||||
Serial.print(F("New: "));Serial.println(set,BIN);
|
||||
cmd = DS2413_ACCESS_WRITE;
|
||||
net->write(cmd);
|
||||
|
||||
net->write(set);
|
||||
net->write(~set);
|
||||
|
||||
uint8_t ack = net->read(); // 0xAA=success, 0xFF=failure
|
||||
|
||||
if (ack == DS2413_ACK_SUCCESS)
|
||||
{
|
||||
results=net->read();
|
||||
Serial.print(F("Updated ok: ")); Serial.println(results,BIN);
|
||||
ok = (~results & 0x0F) == (results >> 4); // Compare nibbles
|
||||
{
|
||||
if (ok)
|
||||
{Serial.println(F("Readback ok"));
|
||||
break;}
|
||||
else {Serial.println(F("readback Error"));delay(1);}
|
||||
}
|
||||
results &= 0x0F; // Clear inverted values
|
||||
}
|
||||
else Serial.println (F("Write failed"));;
|
||||
|
||||
} //while
|
||||
} //if
|
||||
return ok ? results : -1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int sensors_ext(void)
|
||||
{
|
||||
|
||||
int t;
|
||||
switch (term[si][0]){
|
||||
case 0x29: // DS2408
|
||||
//Serial.println(wstat[si],BIN);
|
||||
|
||||
if (wstat[si] & SW_PULSE0) {
|
||||
wstat[si]&=~SW_PULSE0;
|
||||
wstat[si]|=SW_PULSE_P0;
|
||||
Serial.println(F("Pulse0 in progress"));
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (wstat[si] & SW_PULSE0_R) {
|
||||
wstat[si]&=~SW_PULSE0_R;
|
||||
wstat[si]|=SW_PULSE_P0;
|
||||
regs[si] =(ow2408out(term[si],(regs[si] | SW_MASK) & ~SW_OUT0) & SW_INMASK) ^ SW_STAT0;
|
||||
Serial.println(F("Pulse0 in activated"));
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (wstat[si] & SW_PULSE1) {
|
||||
wstat[si]&=~SW_PULSE1;
|
||||
wstat[si]|=SW_PULSE_P1;
|
||||
Serial.println(F("Pulse1 in progress"));
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (wstat[si] & SW_PULSE1_R) {
|
||||
wstat[si]&=~SW_PULSE1_R;
|
||||
wstat[si]|=SW_PULSE_P1;
|
||||
regs[si] =(ow2408out(term[si],(regs[si] | SW_MASK) & ~SW_OUT1) & SW_INMASK) ^ SW_STAT1;
|
||||
Serial.println(F("Pulse0 in activated"));
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (wstat[si] & SW_PULSE_P0) {
|
||||
wstat[si]&=~SW_PULSE_P0;
|
||||
Serial.println(F("Pulse0 clearing"));
|
||||
ow2408out(term[si],regs[si] | SW_MASK | SW_OUT0);
|
||||
|
||||
if (wstat[si] & SW_CHANGED_P0) {
|
||||
wstat[si]&=~SW_CHANGED_P0;
|
||||
wstat[si]|=SW_PULSE0_R;
|
||||
return 500;
|
||||
}
|
||||
}
|
||||
|
||||
if (wstat[si] & SW_PULSE_P1) {
|
||||
wstat[si]&=~SW_PULSE_P1;
|
||||
Serial.println(F("Pulse1 clearing"));
|
||||
ow2408out(term[si],regs[si] | SW_MASK | SW_OUT1);
|
||||
|
||||
if (wstat[si] & SW_CHANGED_P1) {
|
||||
wstat[si]&=~SW_CHANGED_P1;
|
||||
wstat[si]|=SW_PULSE1_R;
|
||||
return 500;
|
||||
}
|
||||
}
|
||||
|
||||
if (wstat[si])
|
||||
{
|
||||
t=owRead2408(term[si]) & SW_INMASK;
|
||||
|
||||
|
||||
|
||||
if (t!=regs[si]) {
|
||||
|
||||
Serial.print(F("DS2408 data = "));
|
||||
Serial.println(t, BIN);
|
||||
|
||||
if (!(wstat[si] & SW_DOUBLECHECK))
|
||||
{
|
||||
wstat[si]|=SW_DOUBLECHECK; //suspected
|
||||
Serial.println(F("DOUBLECHECK"));
|
||||
return recheck_interval;
|
||||
}
|
||||
|
||||
|
||||
Serial.println(F("Really Changed"));
|
||||
if (owChanged) owChanged(si,term[si],t);
|
||||
regs[si]=t;
|
||||
|
||||
|
||||
}
|
||||
wstat[si]&=~SW_DOUBLECHECK;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x01:
|
||||
case 0x81:
|
||||
t=wstat[si];
|
||||
if (t!=regs[si])
|
||||
{ Serial.println(F("Changed"));
|
||||
if (owChanged) owChanged(si,term[si],t);
|
||||
regs[si]=t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
si++;
|
||||
return check_circle;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
32
lighthub/owSwitch.h
Normal file
32
lighthub/owSwitch.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
//define APU_OFF
|
||||
#include <DS2482_OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
|
||||
|
||||
|
||||
int owRead2408(uint8_t* addr);
|
||||
int ow2408out(DeviceAddress addr,uint8_t cur);
|
||||
//int read1W(int i);
|
||||
int cntrl2408(uint8_t* addr, int subchan, int val=-1);
|
||||
int cntrl2413(uint8_t* addr, int subchan, int val=-1);
|
||||
int cntrl2890(uint8_t* addr, int val);
|
||||
198
lighthub/owTerm.cpp
Normal file
198
lighthub/owTerm.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "owTerm.h"
|
||||
#include <Arduino.h>
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
OneWire *net = NULL;
|
||||
// Pass our oneWire reference to Dallas Temperature.
|
||||
//DallasTemperature sensors(&net);
|
||||
|
||||
DeviceAddress *term = NULL;
|
||||
//int *regs = NULL;
|
||||
uint16_t *wstat = NULL;
|
||||
DallasTemperature *sensors = NULL;
|
||||
|
||||
short si=0;
|
||||
int t_count = 0;
|
||||
unsigned long owTimer=0;
|
||||
|
||||
owChangedType owChanged;
|
||||
|
||||
int owUpdate()
|
||||
{
|
||||
unsigned long finish = millis() + 5000;
|
||||
short sr;
|
||||
|
||||
//net.setStrongPullup();
|
||||
Serial.println(F("Searching"));
|
||||
if (net) net->reset_search();
|
||||
for (short i=0;i<t_count;i++) wstat[i]&=~SW_FIND; //absent
|
||||
|
||||
while (net && net->wireSearch(term[t_count])>0 && (t_count<t_max) && finish > millis ())
|
||||
{ short ifind=-1;
|
||||
if (net->crc8(term[t_count], 7) == term[t_count][7])
|
||||
{
|
||||
for (short i=0;i<t_count;i++) if (!memcmp(term[i],term[t_count],8)) {ifind=i;wstat[i]|=SW_FIND;
|
||||
Serial.print(F(" Node:"));PrintBytes(term[t_count],8);Serial.println(F(" alive"));
|
||||
break;}; //alive
|
||||
if (ifind<0 && sensors)
|
||||
{
|
||||
wstat[t_count]=SW_FIND; //Newly detected
|
||||
Serial.print(F("dev#"));Serial.print(t_count);Serial.print(F(" Addr:"));PrintBytes(term[t_count],8);
|
||||
Serial.println();
|
||||
if (term[t_count][0]==0x28)
|
||||
{
|
||||
sensors->setResolution(term[t_count], TEMPERATURE_PRECISION);
|
||||
net->setStrongPullup();
|
||||
// sensors.requestTemperaturesByAddress(term[t_count]);
|
||||
}
|
||||
t_count++;}
|
||||
}//if
|
||||
} //while
|
||||
|
||||
Serial.print(F("1-wire count: "));
|
||||
Serial.println(t_count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int owSetup(owChangedType owCh) {
|
||||
//// todo - move memory allocation to here
|
||||
|
||||
#ifdef _2482
|
||||
net = new OneWire;
|
||||
#else
|
||||
net = new OneWire (ONE_WIRE_BUS);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Pass our oneWire reference to Dallas Temperature.
|
||||
sensors = new DallasTemperature (net);
|
||||
|
||||
term = new DeviceAddress[t_max];
|
||||
//regs = new int [t_max];
|
||||
wstat = new uint16_t [t_max];
|
||||
|
||||
|
||||
|
||||
#ifdef _2482
|
||||
Wire.begin();
|
||||
if (net->checkPresence())
|
||||
{
|
||||
Serial.println(F("DS2482-100 present"));
|
||||
net->deviceReset();
|
||||
#ifdef APU_OFF
|
||||
Serial.println(F("APU off"));
|
||||
#else
|
||||
net->setActivePullup();
|
||||
#endif
|
||||
|
||||
Serial.println(F("\tChecking for 1-Wire devices..."));
|
||||
if (net->wireReset())
|
||||
Serial.println(F("\tReset done"));
|
||||
|
||||
sensors->begin();
|
||||
owChanged=owCh;
|
||||
//owUpdate();
|
||||
//Serial.println(F("\t1-w Updated"));
|
||||
sensors->setWaitForConversion(false);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
// IC Default 9 bit. If you have troubles consider upping it 12. Ups the delay giving the IC more time to process the temperature measurement
|
||||
|
||||
|
||||
delay(500);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int sensors_loop(void)
|
||||
{
|
||||
if (!sensors) return -1;
|
||||
if (si>=t_count)
|
||||
{
|
||||
owUpdate(); //every check circle - scan for new devices
|
||||
si=0;
|
||||
return 8000;
|
||||
}
|
||||
|
||||
int t;
|
||||
switch (term[si][0]){
|
||||
|
||||
case 0x28: // Thermomerer
|
||||
t=sensors->getTempC(term[si]);//*10.0;
|
||||
//Serial.println("o");
|
||||
if (owChanged) owChanged(si,term[si],t);
|
||||
sensors->requestTemperaturesByAddress(term[si]);
|
||||
si++;
|
||||
return 2500;
|
||||
|
||||
// default
|
||||
// return sensors_ext();
|
||||
} //switch
|
||||
|
||||
|
||||
si++;
|
||||
return check_circle;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void owLoop()
|
||||
|
||||
{
|
||||
if (millis() >=owTimer) owTimer=millis()+sensors_loop();
|
||||
}
|
||||
|
||||
|
||||
int owFind(DeviceAddress addr)
|
||||
{
|
||||
for (short i=0;i<t_count;i++) if (!memcmp(term[i],addr,8)) return i;//find
|
||||
return -1;
|
||||
}
|
||||
|
||||
void owAdd (DeviceAddress addr)
|
||||
{
|
||||
wstat[t_count]=SW_FIND; //Newly detected
|
||||
memcpy (term[t_count],addr,8);
|
||||
//term[t_count]=addr;
|
||||
|
||||
Serial.print(F("dev#"));Serial.print(t_count);Serial.print(F(" Addr:"));PrintBytes(term[t_count],8);
|
||||
Serial.println();
|
||||
if (term[t_count][0]==0x28)
|
||||
{
|
||||
sensors->setResolution(term[t_count], TEMPERATURE_PRECISION);
|
||||
net->setStrongPullup();
|
||||
// sensors.requestTemperaturesByAddress(term[t_count]);
|
||||
}
|
||||
t_count++;
|
||||
}
|
||||
|
||||
|
||||
90
lighthub/owTerm.h
Normal file
90
lighthub/owTerm.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
//define APU_OFF
|
||||
|
||||
#define SW_AUX0 0x40
|
||||
#define SW_AUX1 0x80
|
||||
#define SW_STAT0 0x4
|
||||
#define SW_STAT1 0x8
|
||||
#define SW_OUT0 0x20
|
||||
#define SW_OUT1 0x10
|
||||
#define SW_MASK 0xF
|
||||
#define SW_INMASK 0xFC
|
||||
|
||||
#define recheck_interval 5
|
||||
#define check_circle 2000/t_count
|
||||
|
||||
#define SW_FIND 1
|
||||
#define SW_DOUBLECHECK 2 //Doublecheck required
|
||||
#define SW_PULSE0 4 //Pulse Reset started
|
||||
#define SW_PULSE1 8 //Pulse Reset stsrted
|
||||
#define SW_PULSE_P0 0x10 //Pulse reset in process
|
||||
#define SW_PULSE_P1 0x20 //Pulse reset in process
|
||||
#define SW_CHANGED_P0 0x40 //Changes while pulse in progress
|
||||
#define SW_CHANGED_P1 0x80 //Changes while pulse in progress
|
||||
#define SW_PULSE0_R 0x100 //Pulse Reset requested
|
||||
#define SW_PULSE1_R 0x200 //Pulse Reset requested
|
||||
|
||||
|
||||
#define recheck_interval 5
|
||||
#define check_circle 2000/t_count
|
||||
|
||||
|
||||
|
||||
#define t_max 20 //Maximum number of 1w devices
|
||||
#define TEMPERATURE_PRECISION 9
|
||||
|
||||
#include <DS2482_OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include "aJSON.h"
|
||||
|
||||
extern aJsonObject *owArr;
|
||||
|
||||
typedef void (*owChangedType) (int , DeviceAddress, int) ;
|
||||
|
||||
#define _2482 // HW driver
|
||||
|
||||
#ifdef _2482
|
||||
#include <Wire.h>
|
||||
#else
|
||||
#define ONE_WIRE_BUS A0
|
||||
#endif
|
||||
|
||||
extern OneWire *net;
|
||||
|
||||
extern DallasTemperature *sensors;
|
||||
extern DeviceAddress *term ;
|
||||
extern int *regs ;
|
||||
extern uint16_t *wstat;
|
||||
extern int t_count;
|
||||
extern short si;
|
||||
|
||||
extern owChangedType owChanged;
|
||||
|
||||
|
||||
|
||||
int owUpdate();
|
||||
int owSetup(owChangedType owCh);
|
||||
void owLoop();
|
||||
void owIdle(void) ;
|
||||
int owFind(DeviceAddress addr);
|
||||
void owAdd (DeviceAddress addr);
|
||||
|
||||
105
lighthub/utils.cpp
Normal file
105
lighthub/utils.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#if defined(__SAM3X8E__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
void PrintBytes(uint8_t* addr, uint8_t count, bool newline) {
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Serial.print(addr[i]>>4, HEX);
|
||||
Serial.print(addr[i]&0x0f, HEX);
|
||||
}
|
||||
if (newline)
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
const char HEXSTR[]="0123456789ABCDEF";
|
||||
|
||||
void SetBytes(uint8_t* addr, uint8_t count, char * out) {
|
||||
// Serial.println("SB:");
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
*(out++)=HEXSTR[(addr[i]>>4)];
|
||||
*(out++)=HEXSTR[(addr[i]&0x0f)];
|
||||
}
|
||||
*out=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
byte HEX2DEC(char i)
|
||||
{ byte v;
|
||||
if ('a' <= i && i <='f') { v=i-97+10; }
|
||||
else if ('A' <= i && i <='F') { v=i-65+10; }
|
||||
else if ('0' <= i && i <='9') { v=i-48; }
|
||||
return v;
|
||||
}
|
||||
|
||||
void SetAddr(char * out, uint8_t* addr) {
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
*addr=HEX2DEC(*out++)<<4;
|
||||
*addr++|=HEX2DEC(*out++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int getInt(char ** chan)
|
||||
{
|
||||
int ch = atoi(*chan);
|
||||
*chan=strchr(*chan,',');
|
||||
|
||||
if (*chan) *chan+=1;
|
||||
//Serial.print(F("Par:")); Serial.println(ch);
|
||||
return ch;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
int freeRam ()
|
||||
{return system_get_free_heap_size();}
|
||||
#endif
|
||||
|
||||
#if defined(__AVR__)
|
||||
int freeRam ()
|
||||
{
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
extern char _end;
|
||||
extern "C" char *sbrk(int i);
|
||||
|
||||
int freeRam()
|
||||
{
|
||||
char *ramstart = (char *) 0x20070000;
|
||||
char *ramend = (char *) 0x20088000;
|
||||
char *heapend = sbrk(0);
|
||||
register char * stack_ptr asm( "sp" );
|
||||
struct mallinfo mi = mallinfo();
|
||||
|
||||
return stack_ptr - heapend + mi.fordblks;
|
||||
}
|
||||
#endif
|
||||
27
lighthub/utils.h
Normal file
27
lighthub/utils.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* Copyright © 2017-2018 Andrey Klimov. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Homepage: http://lazyhome.ru
|
||||
GIT: https://github.com/anklimov/lighthub
|
||||
e-mail anklimov@gmail.com
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
void PrintBytes(uint8_t* addr, uint8_t count, bool newline=0);
|
||||
void SetBytes(uint8_t* addr, uint8_t count, char * out);
|
||||
void SetAddr(char * out, uint8_t* addr);
|
||||
uint8_t HEX2DEC(char i);
|
||||
int getInt(char ** chan);
|
||||
int freeRam ();
|
||||
Reference in New Issue
Block a user