Commit eca36369 authored by Anders Wallin's avatar Anders Wallin

add Arduino MKR ZERO software

parent 094b88fc
#ifndef __HTTPD_H__
#define __HTTPD_H__
/*
Web Server
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
This functionality inspired by Mini-Circuits rf-switch, which respons to:
requests.get("http://%s/SP6T%s:STATE:%d" % (ip, switch, state))
*/
#include <SPI.h>
#include <Ethernet.h>
#include "rf_mux.h"
namespace HTTPD {
byte mac[] = {
// 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
0x90, 0xA2, 0xDA, 0x0E, 0xCE, 0x76
};
IPAddress ip(192, 168, 1, 18);
//IPAddress ip(192, 168, 3, 30);
//IPAddress ip(130, 188, 45, 253);
class httpd {
public:
httpd(RF_MUX::RF_MUX* m1, RF_MUX::RF_MUX* m2){
server = new EthernetServer(80); // (port 80 is default for HTTP):
_m1 = m1;
_m2 = m2;
}
~httpd(){
delete server;
}
void init() {
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip); // fixed IP
//Serial.println("DHCP...");
//int dhcp_result = Ethernet.begin(mac); // DHCP result
//Serial.print("DHCP success? ");
//Serial.println(dhcp_result);
server->begin();
Serial.print("MUX is at IP: ");
Serial.println(Ethernet.localIP());
_m1->init();
_m2->init();
}
void available() {
// 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;
while (client.connected()) {
if (client.available()) {
char c = client.read();
_httpRequest += c;
// 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) {
// send a standard http response header
_httpRequest.toUpperCase();
//Serial.print("_httpRequest: ");
//Serial.println( _httpRequest);
if (_httpRequest.indexOf("GET / ") >= 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
//client.println("Index page");
print_state(&client);
client.println("</html>");
}
else if (_httpRequest.indexOf("GET /SP8T") >= 0){
// parse command
parse_command();
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
print_state(&client);
client.println("</html>");
}
_httpRequest = "";
break; // request done- break out of while(connected)
}
if (c == '\n') { // you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') { // you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
//Serial.println("client disconnected");
}
}// available()
#define DELIMETERS " :/" // split the httpRequest with these delimeters
void parse_command() {
char *strings[10]; // SP8T:A:STATE:2 four tokens
char *ptr = NULL;
byte index = 0;
char buf[ _httpRequest.length() +1 ];
_httpRequest.toCharArray(buf, _httpRequest.length());
//Serial.println("strtok() %s", buf);
ptr = strtok(buf, DELIMETERS);
while(ptr != NULL) {
strings[index] = ptr;
index++;
ptr = strtok(NULL, DELIMETERS); // takes a list of delimiters
if (index>4) // stop parsing string when we found what we want
break;
}
/*
for(int n = 0; n < index; n++) {
Serial.print("Token ");
Serial.print(n);
Serial.print(" ");
Serial.println(strings[n]);
}*/
if ( strcmp(strings[0], "GET")==0 ) {
if (strcmp(strings[1], "SP8T")==0 ) {
RF_MUX::RF_MUX* mux;
uint8_t state;
if (strcmp(strings[2], "1") == 0) {
mux = _m1;
} else if ( strcmp(strings[2], "2") == 0) {
mux = _m2;
} else {
return;
}
if (strcmp(strings[3], "STATE") == 0) {
//Serial.println("command received");
//Serial.print("MUX ");
//Serial.print(mux->get_id());
uint8_t state = atoi( strings[4] );
//Serial.print(" STATE ");
//Serial.println(state);
mux->set(state);
}
}
}
}
void advance(int mux_id) {
// move one step forward
RF_MUX::RF_MUX* mux;
if (mux_id==0) {
mux = _m1;
} else if (mux_id==1) {
mux = _m2;
}
mux->advance();
delay(1000);
}
void print_state(EthernetClient* client) {
// www-browser sees this output.
client->print("SP8T:");
client->print( _m1->get_id() );
client->print(":STATE:");
client->print( _m1->get() );
client->println("<BR>");
client->print("SP8T:");
client->print( _m2->get_id() );
client->print(":STATE:");
client->print( _m2->get() );
client->println("<BR>");
} // print_state
private:
EthernetServer* server;
String _httpRequest;
RF_MUX::RF_MUX* _m1;
RF_MUX::RF_MUX* _m2;
}; // end class
} // end namespace
#endif
#ifndef __MCP23S17_H__
#define __MCP23S17_H__
namespace MCP23S17 {
#define SERIAL_DEBUG 0
//setup register values for this chip
// BANK=1 mode
/*
const int IODIRA = 0x00;
const int IPOLA = 0x01;
const int GPINTENA = 0x02;
const int DEFVALA = 0x03;
const int INTCONA = 0x04;
const int IOCON = 0x05;
const int GPPUA = 0x06;
const int INTFA = 0x07;
const int INTCAPA = 0x08;
const int GPIOA = 0x09;
const int OLATA = 0x0A;
const int IODIRB = 0x10;
const int IPOLB = 0x11;
const int GPINTENB = 0x12;
const int DEFVALB = 0x13;
const int INTCONB = 0x14;
const int IOCONB = 0x15;
const int GPPUB = 0x16;
const int INTFB = 0x17;
const int INTCAPB = 0x18;
const int GPIOB = 0x19;
const int OLATB = 0x1A;
*/
// IOCON.Bank = 0
const int IODIRA = 0x00;
const int IPOLA = 0x02;
const int GPINTENA = 0x04;
const int DEFVALA = 0x06;
const int INTCONA = 0x08;
const int IOCON = 0x0A;
const int GPPUA = 0x0C;
const int INTFA = 0x0E;
const int INTCAPA = 0x10;
const int GPIOA = 0x12;
const int OLATA = 0x14;
const int IODIRB = 0x01;
const int IPOLB = 0x03;
const int GPINTENB = 0x05;
const int DEFVALB = 0x07;
const int INTCONB = 0x09;
const int IOCONB = 0x0B;
const int GPPUB = 0x0D;
const int INTFB = 0x0F;
const int INTCAPB = 0x11;
const int GPIOB = 0x13;
const int OLATB = 0x15;
const uint8_t PINMODE_INPUT = 0xFF;
const uint8_t PINMODE_OUTPUT = 0x00;
const uint8_t OPCODE_ADDR = 0b01000000;
const uint8_t OPCODE_A0 = 0b00000010;
const uint8_t OPCODE_A1 = 0b00000100;
const uint8_t OPCODE_A2 = 0b00001000;
const uint8_t OPCODE_READ = 0b00000001;
// "B" relays
const uint8_t PINA[9] = {
0b00000000,
0b00000000, // OP 1
0b00000000, // OP 2
0b00000000, // OP 3
0b00000000, // OP 4
0b00000001, // OP 5
0b00000111, // OP 6
0b01001001, // OP 7
0b01110001, // OP 8
};
// "A" relays"
const uint8_t PINB[9] = {
0b00000000,
0b00000001, // OP 1
0b00000110, // OP 2
0b00011000, // OP 3
0b01101000, // OP 4
0b10000000, // OP 5
0b00000000, // OP 6
0b00000000, // OP 7
0b00000000, // OP 8
};
class MCP23S17 {
public:
MCP23S17( int8_t SDIO, int8_t CSB, int8_t SCLK) {
spi = new SPIBitBang(SDIO, CSB, SCLK);
//write_register(IOCON, 0b01110010);
//write_register(0x05 , 0b01110010); // if we were in bank=1 mode
}
~MCP23S17() {
delete spi;
}
void set_pin_mode(uint8_t mode) {
write_register(IODIRA, mode);
write_register(IODIRB, mode);
}
void set_gpio(uint8_t stateA, uint8_t stateB) {
write_register(GPIOA, stateA);
write_register(GPIOB, stateB);
//spi->write16(cmd);
}
void write_register(uint8_t reg, uint8_t data) {
uint8_t opcode = OPCODE_ADDR; // | OPCODE_A0 | OPCODE_A1;
if (SERIAL_DEBUG) {
Serial.print("opcode ");
Serial.print(opcode, HEX);
Serial.print(" reg ");
Serial.print(reg, HEX);
Serial.print(" data= ");
Serial.print(data, HEX);
Serial.print("\n");
}
spi->write_three(opcode, reg, data);
//spi->write24(cmd, data);
//spi->write16
//spi->write16(cmd);
}
private:
SPIBitBang* spi;
}; // end class
} // end namespace
#endif
/*
* Firmware for the "RF Multiplexer 8ch 1GHz" open hardware RF-multiplexer
* project hosted at: https://ohwr.org/project/rf-mux-8ch
*
*
* This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "spibitbang.h"
#include "rf_mux.h"
#include "httpd.h"
// IDC-carrier, version0 pins:
// CS A3
// SCK A0
// SI A1
// SO A2
// pin-definitions, for the MKR ZERO on the carrier board (2018.11 version)
#define SDIO_PIN A1 // old:3
#define SCLK_PIN A0 // old:4
#define CSB_MUX_A A3 // old 0
#define CSB_MUX_B A4 // old 1
#define LED1_PIN 0
#define LED2_PIN 1
#define BUT1_PIN 14
#define BUT2_PIN 13
// #define DUE // Arduino DUE, early prototype MUX
#define MKR // used for all new MUXes with MKR ZERO controller
#ifdef MKR
const int A_SPI_SDIO = SDIO_PIN; // SATA pin SI = 5, SO = 6
const int A_SPI_CSB = CSB_MUX_A; // SATA pin 2
const int A_SPI_SCLK = SCLK_PIN; // SATA pin 3
const int B_SPI_SDIO = SDIO_PIN; // SATA pin SI = 5, SO = 6
const int B_SPI_CSB = CSB_MUX_B; // SATA pin 2
const int B_SPI_SCLK = SCLK_PIN; // SATA pin 3
#endif
#ifdef DUE
const int A_SPI_SDIO = 32; // SATA pin SI = 5, SO = 6
const int A_SPI_CSB = 30; // SATA pin 2
const int A_SPI_SCLK = 31; // SATA pin 3
const int B_SPI_SDIO = 44; // SATA pin SI = 5, SO = 6
const int B_SPI_CSB = 42; // SATA pin 2
const int B_SPI_SCLK = 43; // SATA pin 3
#endif
// Two RF_MUX objects, for the left and right board
RF_MUX::RF_MUX* a_mux = new RF_MUX::RF_MUX('1', A_SPI_SDIO, A_SPI_CSB, A_SPI_SCLK);
RF_MUX::RF_MUX* b_mux = new RF_MUX::RF_MUX('2', B_SPI_SDIO, B_SPI_CSB, B_SPI_SCLK);
// mux carrier v1 pins
const int LED1 = LED1_PIN;
const int LED2 = LED2_PIN;
const int BUTTON1 = BUT1_PIN;
const int BUTTON2 = BUT2_PIN;
// button states
int b1;
int b2;
HTTPD::httpd* webserver = new HTTPD::httpd(a_mux, b_mux);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
Serial.print("initializing.\n");
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
delay(1000);
webserver->init();
delay(1000);
Serial.print("ready.\n");
}
void loop() {
webserver->available();
b1 = digitalRead(BUTTON1);
b2 = digitalRead(BUTTON2);
#ifdef MKR
if (b1== HIGH) {
webserver->advance(0); // pressing button advances state of MUX
} else if (b2==HIGH) {
webserver->advance(1);
}
#endif
}
#ifndef __RF_MUX_H__
#define __RF_MUX_H__
#include "mcp23s17.h"
namespace RF_MUX {
class RF_MUX {
public:
RF_MUX(char id, int8_t SDIO, int8_t CSB, int8_t SCLK) {
_io = new MCP23S17::MCP23S17(SDIO, CSB, SCLK);
_id = id;
_state = 0;
}
~RF_MUX() {
delete _io;
}
void init(){
_io->set_pin_mode(MCP23S17::PINMODE_OUTPUT);
_state=1; // to ensure we set zero below
this->set(0); // reset to state zero
}
void set(uint8_t ch) {
// don't accept invalid states
if (ch<0) {
return;
} else if (ch>8) {
return;
} else if (ch==_state) {
return; // nothing to do.
}
// valid state, do change:
_state = ch;
_io->set_gpio( MCP23S17::PINA[_state], MCP23S17::PINB[_state] );
Serial.print("MUX ");
Serial.print(_id);
Serial.print(" state ");
Serial.print(_state);
Serial.print("\n");
}
void advance() {
uint8_t newstate = this->get()+1;
if (newstate>8) {
newstate = 0;
}
this->set(newstate);
}
uint8_t get() {
return _state;
}
const char get_id() {
return _id;
}
private:
MCP23S17::MCP23S17* _io;
uint8_t _state;
char _id;
}; // end class
} // end namespace
#endif
#ifndef __SPIBITBANG_H__
#define __SPIBITBANG_H__
#include "Arduino.h"
class SPIBitBang {
/*
experimental bit-banged SPI
AW 2014
native SPI api is at http://arduino.cc/en/Reference/SPI
pinSDIO is a combined MOSI/MISO data pin
pinCSB is the chip select pin
pinSCLK is the serial clock pin
*/
public:
SPIBitBang( int8_t pinSDIO, int8_t pinCSB, int8_t pinSCLK) : SDIO (pinSDIO), CSB(pinCSB), SCLK (pinSCLK) {
pinMode(SDIO, OUTPUT);
pinMode(CSB, OUTPUT);
digitalWrite( CSB, HIGH); // deactivate
pinMode(SCLK, OUTPUT);
digitalWrite( SCLK, LOW);
};
// write one byte
void write8(int8_t data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, data);
digitalWrite( CSB, HIGH);
};
// write threee byte1
// ONLY THIS FUNCTION USED FOR RF-MUX
void write_three(int8_t d1, uint8_t d2, uint8_t d3) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
//delay(10);
shiftOut( SDIO, SCLK, MSBFIRST, d1);
//delay(10);
shiftOut( SDIO, SCLK, MSBFIRST, d2);
//delay(10);
shiftOut( SDIO, SCLK, MSBFIRST, d3);
//delay(10);
digitalWrite( CSB, HIGH);
};
// write two bytes
void write16(int data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (data >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data); // low byte
digitalWrite( CSB, HIGH);
};
// write three bytes:
// two-byte instruction
// one-byte data
void write24(int instruction, int8_t data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, data);
digitalWrite( CSB, HIGH);
};
// write four bytes
void write32(int data1, int data2) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (data1 >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data1); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, (data2 >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, data2); // low byte
digitalWrite( CSB, HIGH);
};
/*
int read16() {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
int8_t lsb = shiftIn( SDIO, SCLK, MSBFIRST);
pinMode(SDIO, OUTPUT);
digitalWrite( CSB, HIGH);
return word(msb,lsb);
};*/
// write two bytes
// then read one byte
// the two-byte write is called "instruction", because it tells the AD9912 what to do
void write16read16(int instruction, int &data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
int8_t lsb = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
data = word(msb,lsb);
};
void write16read8(int instruction, int &data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
int8_t msb = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
data = msb;
};
// used for reading the 6-byte FTW of the AD9912 DDS
// writes results to *data, supplied by the user, which must have space for the 6 bytes.
void write16read48(int instruction, int8_t* data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
pinMode(SDIO, INPUT);
data[5] = shiftIn( SDIO, SCLK, MSBFIRST);
data[4] = shiftIn( SDIO, SCLK, MSBFIRST);
data[3] = shiftIn( SDIO, SCLK, MSBFIRST);
data[2] = shiftIn( SDIO, SCLK, MSBFIRST);
data[1] = shiftIn( SDIO, SCLK, MSBFIRST);
data[0] = shiftIn( SDIO, SCLK, MSBFIRST);
digitalWrite( CSB, HIGH);
pinMode(SDIO, OUTPUT);
};
// this is used for setting the FTW (frequency tuning word) on the AD9912 DDS
// the FTW is 48 bits, or 6 bytes. We assume the *data pointer contains these bytes
// there is no error checking, so bad things will happen if *data is not the right type
void write16write48(int instruction, int8_t* data) {
digitalWrite( SCLK, LOW); // ensure clock pin LOW when we start
digitalWrite( CSB, LOW);
shiftOut( SDIO, SCLK, MSBFIRST, (instruction >> 8)); // high byte
shiftOut( SDIO, SCLK, MSBFIRST, instruction); // low byte
shiftOut( SDIO, SCLK, MSBFIRST, data[5] );
shiftOut( SDIO, SCLK, MSBFIRST, data[4] );
shiftOut( SDIO, SCLK, MSBFIRST, data[3] );
shiftOut( SDIO, SCLK, MSBFIRST, data[2] );
shiftOut( SDIO, SCLK, MSBFIRST, data[1] );
shiftOut( SDIO, SCLK, MSBFIRST, data[0] );
digitalWrite( CSB, HIGH);
};
private:
int8_t SDIO; // serial data in/out pin. OUTPUT or INPUT
int8_t CSB; // chip-select pink. OUTPUT
int8_t SCLK; // serial clock pin. OUTPUT
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment