initial commit

Signed-off-by: Jyri Genral <jyri.eerola@jrd.fi>
This commit is contained in:
Jyri Genral 2020-09-06 12:20:23 +02:00
commit a9e1501e48
12 changed files with 6006 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
fe/node_modules
fe/dist
fe/dist.*

192
WebServer/WebServer.ino Normal file
View file

@ -0,0 +1,192 @@
// FukkenRF Web Server
// inspired by a Web Server example from year 2009 by David A. Mellis.
#include <SPI.h>
#include <Ethernet.h>
#include <Arduino.h>
#include <HardwareSerial.h>
HardwareSerial Serial;
// Set your desired MAC and IP addresses, you might want to change these below
byte mac[] = { 0xCA, 0xFE, 0x01, 0x02, 0x03, 0x04 };
IPAddress ip(10, 10, 10, 10);
// Set port
EthernetServer server(80);
// REMEMBER TO CHECK THE RIGHT CHIP SELECT PIN!
//
#define HFENABLE 3
#define LOVHF1 54
#define LOVHF2 2
#define HF1 5
#define HF2 6
#define HF3 7
#define HF4 8
#define HF5 9
#define HF6 11
#define VHF1 12
#define VHF2 13
#define VHF3 14
#define VHF4 15
#define VHF5 16
#define VHF6 17
void setup() {
pinMode(LOVHF1, OUTPUT);
pinMode(LOVHF2, OUTPUT);
pinMode(HF1, OUTPUT);
pinMode(HF2, OUTPUT);
pinMode(HF3, OUTPUT);
pinMode(HF4, OUTPUT);
pinMode(HF5, OUTPUT);
pinMode(HF6, OUTPUT);
pinMode(VHF1, OUTPUT);
pinMode(VHF2, OUTPUT);
pinMode(VHF3, OUTPUT);
pinMode(VHF4, OUTPUT);
pinMode(VHF5, OUTPUT);
pinMode(VHF6, OUTPUT);
// REMEMBER TO CHECK THE RIGHT CHIP SELECT PIN!
Ethernet.init(ETHERNET_CS_PIN);
Serial.begin(9600);
while (!Serial) {} // wait for it
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet shield's presense
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet: not found");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet: link down");
}
// start the server
server.begin();
Serial.print("listening at ");
Serial.println(Ethernet.localIP());
}
unsigned int newPin = 0;
unsigned int currentPin = 0;
void setPin() {
if (newPin != currentPin) {
digitalWrite(HFENABLE, LOW);
digitalWrite(LOVHF1, LOW);
digitalWrite(LOVHF2, LOW);
digitalWrite(HF1, LOW);
digitalWrite(HF2, LOW);
digitalWrite(HF3, LOW);
digitalWrite(HF4, LOW);
digitalWrite(HF5, LOW);
digitalWrite(HF6, LOW);
digitalWrite(VHF1, LOW);
digitalWrite(VHF2, LOW);
digitalWrite(VHF3, LOW);
digitalWrite(VHF4, LOW);
digitalWrite(VHF5, LOW);
digitalWrite(VHF6, LOW);
delay(100);
if ((HF1==newPin) ||
(HF2==newPin) ||
(HF3==newPin) ||
(HF4==newPin) ||
(HF5==newPin) ||
(HF6==newPin)) {
digitalWrite(HFENABLE, HIGH);
}
digitalWrite(newPin, HIGH);
}
currentPin = newPin;
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
boolean firstLine = true;
unsigned int firstCharN = 0;
char firstLineBuf[5] = "";
char postCompare[5] = "POST";
boolean wasPostReq = false;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
if (wasPostReq) {
//pin = client.read() - 65;
newPin = c - 65;
}
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Access-Control-Allow-Origin: *");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
if (wasPostReq) {
client.println("Got POST!!");
newPin = client.read() - 65;
client.print("New pin: ");
client.println(newPin);
} else {
client.println("Didn't get POST :(");
}
client.println("</html>");
setPin();
break;
}
if (c == '\n') {
firstLine = false;
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
if (firstLine && firstCharN < sizeof(firstLineBuf)) {
firstLineBuf[firstCharN] = c;
if (0 == memcmp(firstLineBuf, postCompare, sizeof(postCompare))) {
wasPostReq = true;
}
firstCharN++;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}

23
fe/LICENSE Normal file
View file

@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2015 Michel Weststrate
Forked from: https://github.com/bvanreeven/react-typescript
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

13
fe/README.md Normal file
View file

@ -0,0 +1,13 @@
_Fork of https://github.com/mobxjs/mobx-react-typescript-boilerplate.git_
# React-TypeScript
Minimal boilerplate for a single-page app using MobX, React and TypeScript with TSX.
Initial run:
* Install Node.js
* `yarn install`
* `yarn start`
For simplicity sake Webpack Hot Module Reloading is disabled. If you want to use HMR, see the [Reactive2015 demo](https://github.com/mobxjs/mobx-reactive2015-demo) to see a valid setup.

10
fe/index.html Normal file
View file

@ -0,0 +1,10 @@
<html>
<head>
<title>FukkenRF</title>
<link rel="stylesheet" href="/static/main.css">
</head>
<body>
<div id="root"></div>
<script src="/static/bundle.js"></script>
</body>
</html>

42
fe/package.json Normal file
View file

@ -0,0 +1,42 @@
{
"name": "mobx-react-typescript-boilerplate",
"version": "1.0.0",
"description": "Boilerplate for MobX + React project with Typescript, ES6 compilation and hot code reloading",
"scripts": {
"start": "node server.js"
},
"keywords": [
"react",
"reactjs",
"boilerplate",
"mobx",
"starter-kit"
],
"author": "Michel Weststrate <mweststrate@gmail.com> (http://github.com/mweststrate)",
"license": "MIT",
"homepage": "http://mobxjs.github.com/mobx",
"devDependencies": {
"@types/react-dom": "^16.9.6",
"@types/react-router-dom": "^5.1.4",
"@types/webpack": "^4.41.10",
"css-loader": "^3.5.2",
"extract-css-chunks-webpack-plugin": "^4.7.4",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"ts-loader": "6.2.2",
"typescript": "^3.8.3",
"webpack": "^4.42.1",
"webpack-bundle-analyzer": "^3.6.1",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
},
"dependencies": {
"antd": "^4.1.2",
"mobx": "^5.15.4",
"mobx-react": "^6.2.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "5.1.2"
}
}

15
fe/server.js Normal file
View file

@ -0,0 +1,15 @@
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: false,
historyApiFallback: true
}).listen(3000, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});

16
fe/src/CRE.tsx Normal file
View file

@ -0,0 +1,16 @@
// Re-exporting components
import "antd/es/radio/style";
export { default as Radio, RadioChangeEvent } from "antd/es/radio";
// import "antd/es/row/style";
// export { default as Row } from "antd/es/row";
// import "antd/es/col/style";
// export { default as Col } from "antd/es/col";
import "antd/es/divider/style";
export { default as Divider } from "antd/es/divider";
import "antd/es/message/style";
export { default as message } from "antd/es/message";

116
fe/src/index.tsx Normal file
View file

@ -0,0 +1,116 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {observable, configure, action} from 'mobx';
import {observer} from 'mobx-react';
import { Radio, RadioChangeEvent, Divider, message } from "./CRE";
configure({enforceActions: 'always'});
enum HF {
LOVHF1 = 54,
LOVHF2 = 2,
HF1 = 5,
HF2 = 6,
HF3 = 7,
HF4 = 8,
HF5 = 9,
HF6 = 11
}
enum VHF {
VHF1 = 12,
VHF2 = 13,
VHF3 = 14,
VHF4 = 15,
VHF5 = 16,
VHF6 = 17
}
// const HFENABLEPIN = 5;
class AppState {
@observable hfSelection: HF;
@observable vhfSelection: VHF;
constructor() {
}
@action.bound
setHF(selection: HF) {
this.hfSelection = selection;
}
@action.bound
setVHF(selection: VHF) {
this.vhfSelection = selection;
}
}
@observer
class TimerView extends React.Component<{appState: AppState}, {}> {
render() {
return (
<div>
<Divider>LoVHF / HF selection</Divider>
<Radio.Group buttonStyle="solid" onChange={this.changeHF}>
<Radio.Button value={HF.LOVHF1}>LoVHF1</Radio.Button>
<Radio.Button value={HF.LOVHF2}>LoVHF2</Radio.Button>
<Radio.Button value={HF.HF1}>HF1</Radio.Button>
<Radio.Button value={HF.HF2}>HF2</Radio.Button>
<Radio.Button value={HF.HF3}>HF3</Radio.Button>
<Radio.Button value={HF.HF4}>HF4</Radio.Button>
<Radio.Button value={HF.HF5}>HF5</Radio.Button>
<Radio.Button value={HF.HF6}>HF6</Radio.Button>
</Radio.Group>
<Divider>VHF selection</Divider>
<Radio.Group buttonStyle="solid" onChange={this.changeVHF}>
<Radio.Button value={VHF.VHF1}>VHF1</Radio.Button>
<Radio.Button value={VHF.VHF2}>VHF2</Radio.Button>
<Radio.Button value={VHF.VHF3}>VHF3</Radio.Button>
<Radio.Button value={VHF.VHF4}>VHF4</Radio.Button>
<Radio.Button value={VHF.VHF5}>VHF5</Radio.Button>
<Radio.Button value={VHF.VHF6}>VHF6</Radio.Button>
</Radio.Group>
<br></br>
<br></br>
<br></br>
HF: {this.props.appState.hfSelection}
<br></br>
VHF: {this.props.appState.vhfSelection}
</div>
);
}
@action.bound
async changeHF(e: RadioChangeEvent) {
this.props.appState.setHF(e.target.value);
const res = await fetch(`http://192.168.9.4/`, {
method: "POST",
headers: {},
body: String.fromCharCode(Number(e.target.value) + 65)
});
if (res.ok) {
message.success("HF change sent!");
}
}
@action.bound
async changeVHF(e: RadioChangeEvent) {
this.props.appState.setVHF(e.target.value);
const res = await fetch(`http://192.168.9.4/`, {
method: "POST",
headers: {},
body: String.fromCharCode(Number(e.target.value) + 65)
});
if (res.ok) {
message.success("VHF change sent!");
}
}
};
const appState = new AppState();
ReactDOM.render(<TimerView appState={appState} />, document.getElementById('root'));

14
fe/tsconfig.json Normal file
View file

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es5",
"removeComments": true,
"experimentalDecorators": true,
"jsx": "react",
"outDir": "dist",
"lib": ["dom", "es2015"]
},
"exclude": [
"node_modules",
"static"
]
}

59
fe/webpack.config.js Normal file
View file

@ -0,0 +1,59 @@
var path = require('path');
var webpack = require('webpack');
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
// devtool: 'eval',
// mode: 'development',
mode: 'production',
entry: [
// 'webpack-dev-server/client?http://localhost:3000',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: { mobx: __dirname + "/node_modules/mobx/lib/mobx.es6.js" }
},
plugins: [
new ExtractCssChunks({
filename: '[name].css',
chunkFilename: '[id].css',
})
],
module: {
rules: [{
test: /\.tsx?$/,
loader: "ts-loader",
include: path.join(__dirname, 'src')
},
{
test: /\.less$/,
use: [
{
loader: ExtractCssChunks.loader
},
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
},
},
],
},
{
test: /\.css$/i,
use: [ExtractCssChunks.loader, 'css-loader'],
},
]
}
};

5503
fe/yarn.lock Normal file

File diff suppressed because it is too large Load diff