Initial commit

This commit is contained in:
Sasa Karanovic
2024-04-10 21:49:35 -04:00
commit 85cc5219e9
70 changed files with 71036 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
github: [SasaKaranovic]
custom: [https://shop.sasakaranovic.com]
+91
View File
@@ -0,0 +1,91 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
### PlatformIO ###
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.pio
# Various Altium files
*.PrjPCBStructure
*.SchDocPreview
*.PcbDocPreview
__Previews
*.PrjPcbStructure
*.Dat
*.REP
*.TLT
*.LOG
*.log
*.htm
*.$$$
#useless dirs
Project\ Outputs
Project\ Logs
Project Outputs for*
#History
History
#Exports, but not manual ones
exports/*
!exports/manual
#Python stuff
scripts/__pycache__/
*.bak
*.dwl
*.dwl2
+26
View File
@@ -0,0 +1,26 @@
# How to build firmware
For our firmware development, we are going to use Arduino. Mainly because it's user friendly, easy to use and
most hobbyists are familiar with it or have already used it. While we could build the same or even more efficient
firmware using bare-metal C and ESP-IDF, we are going to stick with Arduino and hope that this allows the project to be
more friendly and easier to use/modify by wider DIY/hacker community.
## How can I build/compile firmware?
### 1. Install PlatformIO
Installing PlatformIO CLI is pretty straight-forward and also well documented for Windows, Linux and MacOS.
You will need to follow few steps and get PlatformIO CLI installed, detailed tutorial can be found at https://platformio.org/install/cli
Make sure to install [PlatformIO Core](https://docs.platformio.org/en/latest//core/installation.html#installation-methods 'https://docs.platformio.org/en/latest//core/installation.html#installation-methods') and allso that it is available trough [shell](https://docs.platformio.org/en/latest//core/installation.html#piocore-install-shell-commands 'PlatformIO Core - Install Shell Commands¶').
### 2. Build firmware
Open shell/command-prompt and navigate to 'Firmware/platformio' folder.
1. Compile and upload the firmware with `pio run --target upload --upload-port <COM-PORT>`. Make sure to replace `<COM-PORT>` with your ESP32's COM port (ie COM1 or /dev/ttyACM0)
2. Upload the file system (Web page) with `pio run --target uploadfs --upload-port <COM-PORT>`, again replace `<COM-PORT>` with your ESP32's COM port.
3. Restart/power-cycle your board
Every time you make a firmware change, you need to run step #1.
Every time you make a change to the web page (anything inside `data` folder) you only need to run step #2.
[<- Go back to repository root](../README.md)
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
/*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands";font-weight:400}
+1
View File
@@ -0,0 +1 @@
body{padding-top:120px}pre{background:#f7f7f9}iframe{overflow:hidden;border:none}@media (min-width: 768px){body>.navbar-transparent{box-shadow:none}body>.navbar-transparent .navbar-nav>.open>a{box-shadow:none}}#home,#help{font-size:.9rem}#home .navbar,#help .navbar{background:#349aed;background:linear-gradient(145deg, #349aed 50%, #34d8ed 100%);transition:box-shadow 200ms ease-in}#home .navbar-transparent,#help .navbar-transparent{background:none !important;box-shadow:none}#home .navbar-brand .nav-link,#help .navbar-brand .nav-link{display:inline-block;margin-right:-30px}#home .nav-link,#help .nav-link{text-transform:uppercase;font-weight:500;color:#fff}#home{padding-top:0}#home .btn{padding:.6rem .55rem .5rem;box-shadow:none;font-size:.7rem;font-weight:500}.bs-docs-section{margin-top:4em}.bs-docs-section .page-header h1{padding:2rem 0;font-size:3rem}.dropdown-menu.show[aria-labelledby="themes"]{display:-ms-flexbox;display:flex;width:420px;-ms-flex-wrap:wrap;flex-wrap:wrap}.dropdown-menu.show[aria-labelledby="themes"] .dropdown-item{width:33.333%}.dropdown-menu.show[aria-labelledby="themes"] .dropdown-item:first-child{width:100%}.bs-component{position:relative}.bs-component+.bs-component{margin-top:1rem}.bs-component .card{margin-bottom:1rem}.bs-component .modal{position:relative;top:auto;right:auto;left:auto;bottom:auto;z-index:1;display:block}.bs-component .modal-dialog{width:90%}.bs-component .popover{position:relative;display:inline-block;width:220px;margin:20px}.source-button{display:none;position:absolute;top:0;right:0;z-index:100;font-weight:700}.source-button:hover{cursor:pointer}.bs-component:hover .source-button{display:block}#source-modal pre{max-height:calc(100vh - 11rem);background-color:rgba(0,0,0,0.7);color:rgba(255,255,255,0.7)}.nav-tabs{margin-bottom:15px}.progress{margin-bottom:10px}#footer{margin:5em 0}#footer li{float:left;margin-right:1.5em;margin-bottom:1.5em}#footer p{clear:left;margin-bottom:0}.splash{padding:12em 0 6em;background:#349aed;background:linear-gradient(145deg, #349aed 50%, #34d8ed 100%);color:#fff;text-align:center}.splash .logo{width:160px}.splash h1{font-size:3em;color:#fff}.splash #social{margin:2em 0 3em}.splash .alert{margin:2em 0;border:none}.splash .sponsor a{color:#fff}.section-tout{padding:6em 0 1em;border-bottom:1px solid rgba(0,0,0,0.05);background-color:#eaf1f1;text-align:center}.section-tout .icon{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;width:80px;height:80px;margin:0 auto 1rem;background:#349aed;background:linear-gradient(145deg, #3b9cea 50%, #3db8eb 100%);border-radius:50%;font-size:2rem;color:rgba(0,0,0,0.5)}.section-tout p{margin-bottom:5em}.section-preview{padding:4em 0}.section-preview .preview{margin-bottom:4em;background-color:#eaf1f1}.section-preview .preview .image{position:relative}.section-preview .preview .image::before{box-shadow:inset 0 0 0 1px rgba(0,0,0,0.1);position:absolute;top:0;left:0;width:100%;height:100%;content:"";pointer-events:none}.section-preview .preview .options{padding:2em;border:1px solid rgba(0,0,0,0.05);border-top:none;text-align:center}.section-preview .preview .options p{margin-bottom:2em}.section-preview .dropdown-menu{text-align:left}.section-preview .lead{margin-bottom:2em}.sponsor #carbonads{max-width:240px;margin:0 auto}.sponsor .carbon-text{display:block;margin-top:1em;font-size:12px}.sponsor .carbon-poweredby{float:right;margin-top:1em;font-size:10px}@media (max-width: 767px){.splash{padding-top:8em}.splash .logo{width:100px}.splash h1{font-size:2em}#banner{margin-bottom:2em;text-align:center}}
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
/*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+85
View File
@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WInFiDEL v%FW_VERSION% - Sasa Karanovic</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/custom.min.css">
<link href="css/fontawesome.min.css" rel="stylesheet">
<link href="css/brands.min.css" rel="stylesheet">
<link href="css/solid.min.css" rel="stylesheet">
<link rel="shortcut icon" type="image/jpg" href="favicon.png"/>
</head>
<body>
<div class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<div class="container">
<a href="index.html" class="navbar-brand">WInFiDEL</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="settings.html">Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://sasakaranovic.com/projects/diy-camera-slider/" target="_blank">Project Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/SasaKaranovic/DIY-Camera-Slider" target="_blank">Source Code</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="p-5 text-center bg-body-tertiary">
<h1 class="text-body-emphasis"><span id="reading-last">...</span>mm</h1>
<p class="col-lg-8 mx-auto fs-5 text-muted">
Min: <span id="reading-min">...</span>mm -
Average: <span id="reading-avg">...</span>mm -
Max: <span id="reading-max">...</span>mm
</p>
<p class="col-lg-8 mx-auto fs-5 text-muted">
Based on <span id="reading-count">...</span> measurements.
</p>
<p class="col-lg-8 mx-auto fs-5 text-muted mb-4">
<a href="#" onclick="javascript:reset_stats();">Reset min/max/avg</a>
</p>
<canvas id="myChart" width="600" height="200"></canvas>
</div>
</div>
<div class="container">
<footer class="w-100 py-2 flex-shrink-3 mt-3 dark-bg">
<div class="row gy-4 gx-5">
<div class="col-lg-6 col-md-6">
<p class="small text-muted">
WInFiDEL v%FW_VERSION% made by <a href="https://SasaKaranovic.com/" target="_blank">Saša Karanović</a><br>
WInFiDEL is based on the original InFiDel sensor made by <a href="https://www.youtube.com/watch?v=RYgdLPe_T0c" target="_blank">Thomas Sanladerer</a>.<br>
Released as open-source and open-hardware for you to hack and enjoy! :)<br>
</p>
</div>
<div class="col-lg-6 col-md-6">
<a class="m-2" href="https://sasakaranovic.com/" target="_blank"><i class="fas fa-home"></i> Blog</a>
<a class="m-2" href="https://youtube.com/c/sasakaranovic" target="_blank"><i class="fab fa-youtube"></i> YouTube</a>
<a class="m-2" href="https://twitter.com/_sasakaranovic_" target="_blank"><i class="fab fa-twitter"></i> Twitter</a>
<a class="m-2" href="https://github.com/sasakaranovic" target="_blank"><i class="fab fa-github"></i> GitHub</a>
<a href="https://github.com/sponsors/SasaKaranovic" target="_blank" title="Sponsor on GitHub"><i class="fab fa-github"></i> Sponsor on GitHub</a>
</div>
</div>
</footer>
</div>
<script src="js/jquery-3.6.0.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src='js/chart.js'></script>
<script src="js/winfidel_index.js"></script>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+118
View File
@@ -0,0 +1,118 @@
var updateIntervalID;
$(document).ready(function(){
refresh_reading();
get_calibration();
start_periodic_update();
$('[data-toggle="tooltip"]').tooltip()
$("#btn-calibrate").on( "click", function() {
const cal_adc = $('#input-adc-last').val();
const cal_mm = $('#input-cal-diameter').val();
if(!isNaN(parseFloat(cal_mm)))
{
$('#btn-calibrate').text('Please wait...');
create_calibration_point(cal_adc, cal_mm);
}
else
{
$("#invalid-value").show();
}
});
$("#adc-label").on("dblclick", function() {
let manual = $("#input-adc-last").prop('disabled');
if (manual == true)
{
alert("Enabling manual calibration!");
$("#input-adc-last").prop('disabled', false);
$("#input-adc-last").tooltip('disable');
stop_periodic_update();
$('#input-adc-last').val('');
$('#input-adc-last').focus();
}
else
{
$("#input-adc-last").prop('disabled', true);
$("#input-adc-last").tooltip('enable');
start_periodic_update();
}
});
});
function get_calibration()
{
$.getJSON( '/api/calibration/read', function( data ) {
const total_points = data['data'].length;
$('#calibration-points-count').text(total_points);
$("#calibration-points > tbody").html("");
for (let i = 0; i < total_points; i++) {
if(i==0 || i== total_points-1)
{
$('table#calibration-points').append('<tr class="d-flex"><td class="col-5">'+ data['data'][i][0] +'</td><td class="col-5">'+ data['data'][i][1] +' mm</td><td class="col-2"></td></tr>');
}
else
{
$('table#calibration-points').append('<tr class="d-flex"><td class="col-5">'+ data['data'][i][0] +'</td><td class="col-5">'+ data['data'][i][1] +' mm</td><td class="col-2"><a href="javascript:remove_calibration_point('+ data['data'][i][1] +');">Remove</a></td></tr>');
}
}
});
}
function create_calibration_point(adc, mm)
{
$.get( '/api/calibration/create?adc='+ adc +'&mm='+ mm, function( data ) {
if (data['status'] == 'ok')
{
location.reload();
}
});
}
function remove_calibration_point(diameter)
{
$.get( '/api/calibration/remove?mm='+ diameter, function( data ) {
console.log(data);
if (data['status'] == 'ok')
{
location.reload();
}
});
}
function refresh_reading()
{
$.getJSON( '/api/diameter/read', function( data ) {
$('#input-adc-last').val(data['data']['adc']);
});
}
function reset_stats()
{
$.get( '/api/diameter/reset');
}
function start_periodic_update()
{
updateIntervalID = window.setInterval(function(){
refresh_reading();
}, 1000);
}
function stop_periodic_update()
{
clearInterval(updateIntervalID);
}
+85
View File
@@ -0,0 +1,85 @@
let measurements_chart;
$(function() {
// Take new reading
// refresh_reading();
var intervalId = window.setInterval(function(){
refresh_reading();
}, 1000);
const ctx = document.getElementById('myChart');
measurements_chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
data: []
}]
},
options: {
scales: {
y: {
beginAtZero: false,
suggestedMin: 1.35,
suggestedMax: 2.25,
ticks: {
// forces step size to be 50 units
stepSize: 0.05
}
},
x: {
beginAtZero: false,
reverse: true
}
},
plugins: {
legend: {
display: false,
}
}
}
});
});
function chart_add_point(newData) {
measurements_chart.data.datasets.forEach((dataset) => {
// dataset.data.push(newData);
dataset.data.unshift(newData);
});
// measurements_chart.update();
measurements_chart.update('none');
}
function refresh_reading()
{
$.getJSON( '/api/diameter/read', function( data ) {
$('#reading-last').text(data['data']['diameter']);
$('#reading-min').text(data['data']['min']);
$('#reading-avg').text(data['data']['avg']);
$('#reading-max').text(data['data']['max']);
$('#reading-count').text(data['data']['count']);
chart_add_point({x: get_timestamp(), y: data['data']['diameter']});
});
}
function reset_stats()
{
$.get( '/api/diameter/reset');
}
function get_timestamp()
{
let date = new Date();
return twoDigitPad(date.getHours()) +':'+ twoDigitPad(date.getMinutes()) +':'+ twoDigitPad(date.getSeconds());
}
function twoDigitPad(num) {
return num < 10 ? "0" + num : num;
}
+241
View File
@@ -0,0 +1,241 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WInFiDEL v%FW_VERSION% - Sasa Karanovic</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/custom.min.css">
<link href="css/fontawesome.min.css" rel="stylesheet">
<link href="css/brands.min.css" rel="stylesheet">
<link href="css/solid.min.css" rel="stylesheet">
<link rel="shortcut icon" type="image/jpg" href="favicon.png"/>
</head>
<body>
<div class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<div class="container">
<a href="index.html" class="navbar-brand">WInFiDEL</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="settings.html">Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://sasakaranovic.com/projects/diy-camera-slider/" target="_blank">Project Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/SasaKaranovic/DIY-Camera-Slider" target="_blank">Source Code</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="p-5 text-center bg-body-tertiary">
<h1 class="text-body-emphasis">Using <span id="calibration-points-count"></span> calibration points</h1>
<div class="col-lg-6 mx-auto mt-4 mb-5">
<table id="calibration-points" class="table table-sm table-striped text-left">
<thead>
<tr class="d-flex">
<th class="col-5">ADC</th>
<th class="col-5">Diameter</th>
<th class="col-2">Remove</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="">
<p class="col-lg-8 mx-auto fs-5 text-muted mb-4">
We use above calibration points to estimate filament diameter using <a href="https://en.wikipedia.org/wiki/Linear_interpolation" target="_blank" class="text-muted">linear interpolation</a>.<br>
First and last point are boundary items and can not be removed.<br>
The firmware has been compiled to allow up to %MAX_CALIBRATION_POINTS% calibration points.</p>
</div>
</div>
</div>
<div class="container">
<div class="p-5 text-center bg-body-tertiary">
<h1 class="text-body-emphasis">Create calibration point</h1>
<div class="text-left">
<p class="col-lg-6 mx-auto fs-5 text-muted mt-4">
Calibration procedure (using drill bit)
</p>
<p class="col-lg-6 mx-auto fs-5 text-muted mb-1">
1. Measure drill bit using calipers and note the diameter size in mm
</p>
<p class="col-lg-6 mx-auto fs-5 text-muted mb-1">
2. Insert the drill bit into WInFiDEL sensor and note the ADC value
</p>
<p class="col-lg-6 mx-auto fs-5 text-muted mb-1">
3. In the input box below enter the measured diameter from step #1
</p>
<p class="col-lg-6 mx-auto fs-5 text-muted mb-1">
4. Click on `Calibrate` button and wait for page to reload.
</p>
<p class="col-lg-6 mx-auto fs-5 text-muted mb-1">
5. Verify that the list of calibration points has been updated.
</p>
</div>
<div>
<p class="col-lg-6 mx-auto fs-5 mt-4">
Current ADC value of
</p>
<div class="input-group mb-3 mt-3 col-lg-2 mx-auto">
<input type="text" class="form-control" disabled placeholder="" aria-label="" aria-describedby="basic-addon2" id="input-adc-last" data-toggle="tooltip" data-placement="top" title="This value is updated automatically.">
<span class="input-group-text" id="adc-label">ADC</span>
</div>
<p class="col-lg-6 mx-auto fs-5 mt-4">
should be calibrated as
</p>
<div class="input-group mb-3 mt-3 col-lg-2 mx-auto">
<input type="text" class="form-control" placeholder="" aria-label="" aria-describedby="basic-addon2" id="input-cal-diameter">
<span class="input-group-text" id="basic-addon3">mm</span>
</div>
<div id="invalid-value" class="invalid-feedback">Invalid diameter value!</div>
<div class="input-group mb-3 mt-3 col-lg-2 mx-auto">
<button type="button" class="btn btn-primary" id="btn-calibrate">Calibrate</button>
</div>
</div>
<div class="">
<p class="col-lg-7 mx-auto fs-5 text-muted mt-4">
Note: Update existing calibration point by specifying same `mm` diameter.<br>
Note: If new point has same ADC or mm value as the existing one. Existing point will be updated.
</p>
</div>
</div>
</div>
<div class="container">
<div class="p-5 text-center bg-body-tertiary">
<h1 class="text-body-emphasis">Firmware information</h1>
<table class="table table-sm table-striped text-left">
<thead>
<tr class="d-flex">
<th class="col-4 text-break">Parameter</th>
<th class="col-2">Value</th>
<th class="col-6">Note</th>
</tr>
</thead>
<tbody>
<tr class="d-flex">
<td class="col-4 text-break">MAX_CALIBRATION_POINTS</td>
<td class="col-2 text-break">%MAX_CALIBRATION_POINTS%</td>
<td class="col-6">Maximum number of calibration points supported by firmware.</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">CALIBRATION_POINT_SAMPLE_COUNT</td>
<td class="col-2 text-break">%CALIBRATION_POINT_SAMPLE_COUNT%</td>
<td class="col-6">Number of ADC samples taken when creating a calibration point</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">CALIBRATION_POINT_ACCURACY_POINT</td>
<td class="col-2 text-break">%CALIBRATION_POINT_ACCURACY_POINT%</td>
<td class="col-6">When creating calibration point. All ADC samples must be within `%CALIBRATION_POINT_ACCURACY_POINT%` points of each other. Otherwise we will fail to create a calibration point due to ADC noise.</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_MIN</td>
<td class="col-2 text-break">%ADC_MIN%</td>
<td class="col-6">Minimum value ADC can provide</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_MIN_EQUALS_MM</td>
<td class="col-2 text-break">%ADC_MIN_EQUALS_MM%</td>
<td class="col-6">Minimum ADC value is treated as `%ADC_MIN_EQUALS_MM%`mm</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_MAX</td>
<td class="col-2 text-break">%ADC_MAX%</td>
<td class="col-6">Maximum value ADC can provide</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_MAX_EQUALS_MM</td>
<td class="col-2 text-break">%ADC_MAX_EQUALS_MM%</td>
<td class="col-6">Maximum ADC value is treated as `%ADC_MAX_EQUALS_MM%`mm</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">BUILD_TIME</td>
<td class="col-2 text-break">%BUILD_TIME%</td>
<td class="col-6">Time when firmware was compiled</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">BUILD_DATE</td>
<td class="col-2 text-break">%BUILD_DATE%</td>
<td class="col-6">Date when firmware was compiled</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_ALGO</td>
<td class="col-2 text-break">%ADC_ALGO%</td>
<td class="col-6">Which alghoritm is used to calculate final ADC value</td>
</tr>
<tr class="d-flex">
<td class="col-4 text-break">ADC_CHIP</td>
<td class="col-2 text-break">%ADC_CHIP%</td>
<td class="col-6">Which ADC chip is populated on the board</td>
</tr>
</tbody>
</table>
<div class="">
<p class="col-lg-8 mx-auto fs-5 text-muted mb-4">
Values in this table are provided for development/debugging purposes (and just for fun).<br>
You should not have to worry about them during devices normal operation.
</p>
</div>
</div>
</div>
<div class="container">
<footer class="w-100 py-2 flex-shrink-3 mt-5 dark-bg">
<div class="row gy-4 gx-5">
<div class="col-lg-6 col-md-6">
<p class="small text-muted">
WInFiDEL v%FW_VERSION% made by <a href="https://SasaKaranovic.com/" target="_blank">Saša Karanović</a><br>
WInFiDEL is based on the original InFiDel sensor made by <a href="https://www.youtube.com/watch?v=RYgdLPe_T0c" target="_blank">Thomas Sanladerer</a>.<br>
There are two types of people in the world: those who can extrapolate from incomplete data sets.<br>
Released as open-source and open-hardware for you to hack and enjoy! :)<br>
</p>
</div>
<div class="col-lg-6 col-md-6">
<a class="m-2" href="https://sasakaranovic.com/" target="_blank"><i class="fas fa-home"></i> Blog</a>
<a class="m-2" href="https://youtube.com/c/sasakaranovic" target="_blank"><i class="fab fa-youtube"></i> YouTube</a>
<a class="m-2" href="https://twitter.com/_sasakaranovic_" target="_blank"><i class="fab fa-twitter"></i> Twitter</a>
<a class="m-2" href="https://github.com/sasakaranovic" target="_blank"><i class="fab fa-github"></i> GitHub</a>
<a href="https://github.com/sponsors/SasaKaranovic" target="_blank" title="Sponsor on GitHub"><i class="fab fa-github"></i> Sponsor on GitHub</a>
</div>
</div>
</footer>
</div>
<script src="js/jquery-3.6.0.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/winfidel_calibration.js"></script>
</body>
</html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = esp32dev
[env:esp32_ota]
extends = env:esp32dev
upload_protocol = espota
[env:esp32dev]
board_build.f_cpu = 160000000L
board_build.f_flash = 80000000L
board_build.flash_mode = qio
board_build.filesystem = littlefs
board_build.partitions = default.csv
framework = arduino
platform = https://github.com/platformio/platform-espressif32.git
board = esp32-c3-devkitm-1
upload_protocol = esptool
Monitor_speed = 115200
build_flags =
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
lib_deps=
LittleFS
FS
WiFi
EEPROM
Wire
https://github.com/SasaKaranovic/ESPAsyncWebServer.git
https://github.com/me-no-dev/AsyncTCP.git
ESPmDNS @ 2.0.0
Arduino_JSON
https://github.com/tzapu/WiFiManager.git
;arduino-libraries/Arduino_JSON @ 0.1.0
+149
View File
@@ -0,0 +1,149 @@
#include <Wire.h>
uint32_t adc_samples[ADC_MAX_SAMPLES] = {0};
uint8_t rxBuff[2] = {0};
uint8_t rxPos = 0;
uint32_t nADCTimeoutTick = 0;
void adc_init(void)
{
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
}
// Helper function to indicate (in the UI) which
// algo is used for calculating final ADC value
String adc_get_algo(void)
{
#ifdef ADC_FINAL_ADC_VALUE_USING_MEAN
return String("MEAN");
#else
return String("AVERAGE");
#endif
}
String adc_get_chip(void)
{
#ifdef ADC_CHIP_IS_MCP3221
return String("MCP3221");
#else
return String("MCP3021");
#endif
}
// This function will take `N` samples and store them into an array
// After that we should use one of the available functions to calculate value
// ie. calculate average, mean, trimmed_mean etc.
uint32_t adc_sample_data(uint8_t nSamples)
{
if(nSamples > ADC_MAX_SAMPLES)
{
Serial.print("Limiting number of samples to ");
Serial.println(ADC_MAX_SAMPLES);
nSamples = ADC_MAX_SAMPLES;
}
else if (nSamples <= 0)
{
Serial.println("Requested invalid number of samples. Aborting.");
return 0;
}
uint32_t accumulator = 0;
uint32_t sample = 0;
rxPos = 0;
while(rxPos++ < nSamples)
{
// Request two bytes
Wire.requestFrom(ADC_I2C_ADDRESS, 2);
// // Wait for data to become available
nADCTimeoutTick = millis() + 100;
while((!Wire.available()) && (millis()<=nADCTimeoutTick));
// Read two bytes
rxBuff[0] = Wire.read();
rxBuff[1] = Wire.read();
// Accumulate value
#ifdef ADC_CHIP_IS_MCP3221
// Using MCP3221
sample = ( (rxBuff[0] << 8 | (rxBuff[1])));
#else
// Using MCP3021
sample = ( (rxBuff[0] << 6 | (rxBuff[1]) >> 2));
#endif
adc_samples[rxPos] = sample;
accumulator += sample;
}
// Divide value with number of samples
return (accumulator/nSamples);
}
int qsort_compare( const void* a, const void* b)
{
uint32_t int_a = * ( (uint32_t*) a );
uint32_t int_b = * ( (uint32_t*) b );
// an easy expression for comparing
return (int_a > int_b) - (int_a < int_b);
}
uint32_t adc_get_mean(void)
{
// We want to have 3 or more samples
if (rxPos <= 2)
{
Serial.println("Insufficient number of samples. Returing the first value");
return adc_samples[0];
}
// Sort samples
qsort(adc_samples, rxPos, sizeof(uint32_t), qsort_compare);
// Get the "middle" element
// (we will round up/down on even number of samples, but we can live with that for now)
return adc_samples[rxPos/2];
}
void i2c_scan_bus(void)
{
uint8_t error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
+277
View File
@@ -0,0 +1,277 @@
/*
We will use a struct to hold all of our calibration points.
Using known calibration points, we can interpolate what is the
measured value for any ADC value as long as we have two calibration
so that one is lower and the other is higher than the current reading.
Our calibration points look like: ADC_VALUE -> CALIBRATED_MM_VALUE
* We will keep all of our calibration vales sorted by ASC value of ADC_VALUE
For example, let's assume we have below calibration points
620 -> 2.0mm
850 -> 1.5mm
915 -> 1.0mm
In order to calculate what is the `mm` equivalent for ADC_VALUE value of `750`
1) Find calibration point that is higher than current ADC_VALUE and use it as HIGH_POINT
1.1) Make sure there that there is a lower (we use boundary items to guarantee this) and use it as LOW_POINT
2) Calculate the slope between two points (LOW_POINT and HIGH_POINT)
3) Calculate the Y(mm) value using LOW_POINT and the calculated slope
*/
#include "config_winfidel.h"
static calibration_t cal = {0};
char calibration_json[CALIBRATION_JSON_STR_MAX_LEN] = {0};
void calibration_init(void)
{
bool res;
res = calibration_read_from_eeprom();
if (res == false)
{
calibration_reset();
}
}
bool calibration_read_from_eeprom(void)
{
EEPROM.readBytes(0, (void *)&cal, sizeof(calibration_t));
if (cal.valid == EEPROM_MAGIC_KEY)
{
Serial.println("Calibration loaded from EEPROM");
return true;
}
Serial.println("Calibration in EEPROM is invalid");
return false;
}
void calibration_save_to_eeprom(void)
{
EEPROM.writeBytes(0, (void *)&cal, sizeof(calibration_t));
EEPROM.commit();
}
void calibration_reset(void)
{
for(uint8_t i=0; i<MAX_CALIBRATION_POINTS; i++)
{
cal.points[i] = CAL_POINT_EMPTY;
}
cal.points[0] = CAL_POINT_FIRST;
cal.points[1] = CAL_POINT_LAST;
cal.numPoints = 2;
cal.valid = EEPROM_MAGIC_KEY;
sort_calibration_points();
calibration_save_to_eeprom();
Serial.println("Default calibration loaded");
}
// Create new calibration point using provided `mm` value
// and sampled ADC value
winfidel_status_t create_calibration_point(float mm)
{
// Check if we already have maximum number of point
if(cal.numPoints >= MAX_CALIBRATION_POINTS)
{
return WINFIDEL_NO_SPACE;
}
uint32_t adc_samples[CALIBRATION_POINT_SAMPLE_COUNT] = {0};
uint32_t adc_min = ADC_MAX;
uint32_t adc_max = ADC_MIN;
uint32_t adc_average = 0;
// Sample the ADC value CALIBRATION_POINT_SAMPLE_COUNT times
for(uint8_t i=0; i<CALIBRATION_POINT_SAMPLE_COUNT; i++)
{
// Sample ADC
adc_samples[i] = adc_sample_data(1);
// Update minimum
if(adc_samples[i] < adc_min)
{
adc_min = adc_samples[i];
}
// Update maximum
if(adc_samples[i] > adc_max)
{
adc_max = adc_samples[i];
}
}
// Check our max-min is less than CALIBRATION_POINT_ACCURACY_POINT
if( (adc_max-adc_min) > CALIBRATION_POINT_ACCURACY_POINT)
{
Serial.print("ADC accuracy was too low: ");
Serial.print((adc_max-adc_min));
Serial.print(" points between min and max!");
return WINFIDEL_LOW_ACCURACY;
}
// Average out ADC
for(uint8_t i=0; i<CALIBRATION_POINT_SAMPLE_COUNT; i++)
{
adc_average += adc_samples[i];
}
adc_average = adc_average/CALIBRATION_POINT_SAMPLE_COUNT;
manually_create_calibration_point(adc_average, mm);
return WINFIDEL_OK;
}
// Create calibration point wih given ADC value and MM diameter
winfidel_status_t manually_create_calibration_point(uint32_t adc_average, float mm)
{
bool existing_point = false;
// Check if we already have maximum number of point
if(cal.numPoints >= MAX_CALIBRATION_POINTS)
{
return WINFIDEL_NO_SPACE;
}
// Check if we are creating new point or updating existing `mm` point with new ADC value
for(uint8_t i=0; i<MAX_CALIBRATION_POINTS; i++)
{
if(cal.points[i].mm == mm || cal.points[i].adc == adc_average)
{
existing_point = true;
cal.points[i].adc = adc_average;
cal.points[i].mm = mm;
break;
}
}
// We didn't find existing calibration point with same `mm` value
if (existing_point == false)
{
// Create new point
cal.points[cal.numPoints++] = { .adc = adc_average, .mm = mm };
}
sort_calibration_points();
calibration_save_to_eeprom();
return WINFIDEL_OK;
}
// Remove calibration point by using given mm value
// We will find the position of this calibration point
// and then use `remove_calibration_point_pos` to remove it
winfidel_status_t remove_calibration_point_mm(float mm)
{
for(uint8_t i=0; i<MAX_CALIBRATION_POINTS; i++)
{
if(cal.points[i].mm == mm)
{
return remove_calibration_point_pos(i);
}
}
return WINFIDEL_MISSING;
}
// Remove calibration point at index N
// We need to POP the N-th calibration point and shift all
// calibration values up
winfidel_status_t remove_calibration_point_pos(uint8_t pos)
{
// We don't allow removing first and last (cal.numPoints) calibration points
if(pos == 0 || pos == cal.numPoints-1)
{
return WINFIDEL_FORBIDDEN;
}
// Shift up all calibration points starting from pos
for(uint8_t i=pos; i<MAX_CALIBRATION_POINTS-1; i++)
{
cal.points[i] = cal.points[i+1];
}
// Decrement number of calibration points
cal.numPoints--;
calibration_save_to_eeprom();
return WINFIDEL_OK;
}
// This function should only be called inside `sort_calibration_points`
static void swap_calibration_points(uint8_t i, uint8_t j)
{
cal_point_t temp = cal.points[i];
cal.points[i] = cal.points[j];
cal.points[j] = temp;
}
// Sort all calibration points in ASC order using ADC value
void sort_calibration_points(void)
{
uint8_t i, j;
for (i = 0; i < cal.numPoints - 1; i++)
{
// Last i elements are already
// in place
for (j = 0; j < cal.numPoints - i - 1; j++)
{
if (cal.points[j].adc > cal.points[j + 1].adc)
{
swap_calibration_points(j, j + 1);
}
}
}
}
// Format JSON string that contains all calibration points
char *get_calibration_json(void)
{
int32_t pos = 0;
int32_t len = 0;
// Start of JSON
len = snprintf(calibration_json, CALIBRATION_JSON_STR_MAX_LEN-pos, "{\"status\":\"ok\",\"data\":[");
pos += len;
// Append each calibration point
#if 1
for (uint8_t i=0; i<cal.numPoints; i++) // Send ONLY currently used calibration points
#else
for (uint8_t i=0; i<MAX_CALIBRATION_POINTS; i++) // Send ALL (used and unused) calibration points
#endif
{
len = snprintf(&calibration_json[pos], CALIBRATION_JSON_STR_MAX_LEN-pos, "[%d, \"%.3f\"],",
cal.points[i].adc, cal.points[i].mm);
pos += len;
}
// End of JSON
snprintf(&calibration_json[pos-1], CALIBRATION_JSON_STR_MAX_LEN-pos, "]}");
return calibration_json;
}
// Convert given ADC value to mm using available calibration points
float adc_to_mm(uint32_t adc)
{
for (uint8_t i=0; i<cal.numPoints; i++)
{
if(cal.points[i].adc > adc)
{
float slope = ((float)cal.points[i].mm - cal.points[i-1].mm) / ((float)cal.points[i].adc - cal.points[i-1].adc);
float indiff = ((float)adc - cal.points[i-1].adc);
float outdiff = slope * indiff;
float out = outdiff + cal.points[i-1].mm;
return (out);
}
}
// We should never reach this section
Serial.println("Failed to find calibration point. Returning 0.0mm");
return 0.0f;
}
+71
View File
@@ -0,0 +1,71 @@
#ifndef __WINFIDEL_CFG__
#define __WINFIDEL_CFG__
#define MDNS_NAME "winfidel"
#define WIFI_HOSTNAME "WInFiDEL by SK"
#define CALIBRATION_POINT_SAMPLE_COUNT 32 // Number of ADC samples to take for new calibration point
#define CALIBRATION_POINT_ACCURACY_POINT 50 // We expect all CALIBRATION_POINT_SAMPLE_COUNT samples to be
// within CALIBRATION_POINT_ACCURACY_POINT of each other
// in order to have successful calibration point creation
#define CALIBRATION_BOUNDARY_ITEMS 2 // We need lower and upper boundary item for safety
#define MAX_CALIBRATION_POINTS (10 + CALIBRATION_BOUNDARY_ITEMS)
#define ADC_MIN 0 // Minimum value we can get from our ADC (should be always 0)
#define ADC_MIN_EQUALS_MM 5.0f // ADC_MIN should be considered this diameter (in mm)
#define ADC_MAX 4095 // Maximum value we can get from our ADC (should be 2^n-bits)
#define ADC_MAX_EQUALS_MM 0.0f // ADC_MAX should be considered this diameter (in mm)
#define CAL_POINT_EMPTY { .adc = ADC_MIN, .mm = ADC_MIN_EQUALS_MM }
#define CAL_POINT_FIRST { .adc = ADC_MIN, .mm = ADC_MIN_EQUALS_MM }
#define CAL_POINT_LAST { .adc = ADC_MAX, .mm = ADC_MAX_EQUALS_MM }
#define ADC_MAX_SAMPLES 64 // Maximum number of ADC samples we can take in one measurement cycle
#define ADC_SAMPLES_PER_MEASUREMENT_CYCLE 16 // How many samples to take for each measurement cycle
#define ADC_FINAL_ADC_VALUE_USING_MEAN // Use mean instead of average ADC value
#define ADC_CHIP_IS_MCP3221 // Specify which ADC chip we are using
// #define ADC_CHIP_MCP3021 // Specify which ADC chip we are using
#define ADC_I2C_ADDRESS 0x4D // 7-bit I2C address of our ADC IC
#define I2C_SCL_PIN 0 // SCL pin number
#define I2C_SDA_PIN 1 // SDA pin number
// String buffers
#define SENSOR_STR_MAX_LEN 256
#define CALIBRATION_JSON_STR_MAX_LEN 512
#define EEPROM_MAGIC_KEY 0x53 // Predefined value used to verify EEPROM has been initialized
// Enum holding calibration results
typedef enum winfidel_status
{
WINFIDEL_OK,
WINFIDEL_FAIL,
WINFIDEL_FORBIDDEN,
WINFIDEL_INVALID_ARGUMENT,
WINFIDEL_MISSING,
WINFIDEL_NO_SPACE,
WINFIDEL_LOW_ACCURACY
} winfidel_status_t;
// Calibration point struct -> holds ADC value and equivalent mm diameter
typedef struct cal_point
{
uint32_t adc;
float mm;
} cal_point_t;
// Calibration struct -> holds all calibration points and total number of valid calibration points
typedef struct calibration
{
cal_point_t points[MAX_CALIBRATION_POINTS];
uint32_t numPoints;
uint8_t valid;
} calibration_t;
#endif
+140
View File
@@ -0,0 +1,140 @@
/* SPDX-License-Identifier: MIT
* Copyright(c) 2022 Lincoln Lavoie <lincoln.lavoie@gmail.com>
*/
#include <Preferences.h>
#ifndef __PersistSettings__
#define __PersistSettings__
template <class T>
class PersistSettings{
private:
bool mValid;
unsigned int mConfigVersion;
uint16_t CRC16(byte *data, size_t data_len);
public:
T Config;
PersistSettings(unsigned int ConfigVersion);
void Begin(void);
void Write(void);
void ResetToDefault(void);
bool Valid(void);
};
#endif
// PersistSettings Constructor
// Use the Config structure as the class template for the object.
// Provide a default version, preferable as a static member of the
// config object.
template <class T>
PersistSettings<T>::PersistSettings(unsigned int version){
mConfigVersion = version;
mValid= false;
}
// Initialize the settings object, read the config from the
// persistent storage, and validate data. If the config object
// can not be read, an error is detected, or the version mismatches,
// the Config object will be reset to the default values.
template <class T>
void PersistSettings<T>::Begin(void){
Preferences pref;
// Setup the preferences namespace, as read only
if( !pref.begin("PersistSettings", true) ){
log_e("Failed to open PersistSettings namespace, resetting and writing defaults.\r\n");
this->ResetToDefault();
return;
}
// Get the stored config version version, if it's not equal to then the version provided
// with the the detail, we assume the DefaultConfig has a newer revision of the
// Config object and we initialize to that value instead of stored values.
// A value of 0 indicates the key didn't exist, assume no settings exist.
unsigned int storedVersion = pref.getUInt("version", 0);
if( storedVersion == 0 || storedVersion != mConfigVersion ){
log_e("Version mismatch (saved: %d, current: %d), resetting to defaults.\r\n", storedVersion, mConfigVersion);
this->ResetToDefault();
return;
}
// Read the settings from the persistent storage.
size_t configLen = pref.getBytesLength("config");
byte memBytes[configLen];
if (sizeof(T)+2 != configLen ){
log_e("Length read failure (read: %d, expected: %d), resetting to defaults.\r\n", configLen, sizeof(T)+2);
this->ResetToDefault();
return;
}
pref.getBytes("config", memBytes, configLen);
// Check the CRC16
if( CRC16(memBytes, configLen) ){
log_e("CRC16 check failed, resetting to default\r\n");
this->ResetToDefault();
return;
}
// All checks passed, valid config, copy the data to the object.
memcpy(&Config, memBytes, sizeof(T));
// Close the preferences
pref.end();
// Indicate the config is valid
mValid = true;
}
// Indicates the Config data object is valid.
template <class T>
bool PersistSettings<T>::Valid(void){ return mValid; }
// Resets the Config object to the default value and provided during the
// construction of the PersistSettings object and writes those values to
// the persistent storage.
template <class T>
void PersistSettings<T>::ResetToDefault(void){
T newConfig;
Config = newConfig;
this->Write();
mValid = true;
}
// Write the current values of the Config object to persistent storage.
template <class T>
void PersistSettings<T>::Write(void){
Preferences pref;
// Setup the preferences namespace, as read only
pref.begin("PersistSettings", false);
// Save the version
pref.putUInt("version", mConfigVersion);
// Save the config, as a byte array, with 2-byte CRC on the end.
byte memBytes[sizeof(T)+2];
memcpy(memBytes, &Config, sizeof(T));
uint16_t crc = CRC16(memBytes, sizeof(T));
memBytes[sizeof(T)] = static_cast<byte>((crc&0xFF));
memBytes[sizeof(T)+1] = static_cast<byte>((crc>>8));
pref.putBytes("config", memBytes, sizeof(T)+2);
// Close the preferences
pref.end();
}
// Calculate the CRC16 over the provided data object (byte array) and
// return the value.
template <class T>
uint16_t PersistSettings<T>::CRC16(byte *data, size_t data_len){
uint16_t crc = 0xFFFF;
for(unsigned int i = 0; i < data_len; i++){
crc ^= data[i];
for(unsigned char k = 0; k<8; ++k){
if(crc & 1) crc = (crc >> 1) ^ 0x8005;
else crc>>=1;
}
}
return crc;
}
+129
View File
@@ -0,0 +1,129 @@
#include <ESPmDNS.h>
#include <EEPROM.h>
#include <WiFiManager.h>
#include <Arduino_JSON.h>
#include <ArduinoOTA.h>
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "LittleFS.h"
#include "include/PersistSettings.h"
#include "config_winfidel.h"
WiFiManager wifiManager;
AsyncWebServer server(80);
volatile int WiFi_status = WL_IDLE_STATUS;
const char mdnsName[] = MDNS_NAME;
const char wifiName[] = WIFI_HOSTNAME;
uint8_t dbgOTApercent = 100;
void setup()
{
// Configure Serial communication
Serial.begin(115200);
Serial.println("Wireless Inline Filament Estimator, Low-Cost - WInFiDEL");
WiFi.setHostname(wifiName);
// wifiManager.resetSettings(); // Wipe WiFi settings. Uncomment for WiFi manager testing
delay(500);
bool res;
res = wifiManager.autoConnect("SK-WInFiDEL-Setup", "letsrock");
if(!res) {
Serial.println("Failed to connect or hit timeout");
ESP.restart();
}
else {
//if you get here you have connected to the WiFi
Serial.println("Connected.");
}
// Initialize LittleFS
Serial.print("Starting LittleFS...");
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
Serial.println("done.");
Serial.print("WiFi IP: ");
Serial.println(WiFi.localIP());
if (!MDNS.begin(mdnsName))
{
Serial.println("Error starting mDNS");
}
else
{
Serial.println((String) "mDNS http://" + MDNS_NAME + ".local");
}
// Add service to MDNS-SD
MDNS.addService("http", "tcp", 80);
EEPROM.begin(sizeof(calibration_t));
calibration_init();
adc_init();
Serial.print("Starting WebServer...");
setupWebServer();
server.begin();
Serial.println("done.");
Serial.print("WiFi IP: ");
Serial.println(WiFi.localIP());
/**
* Enable OTA update
*/
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
uint8_t percent = (progress / (total / 100));
if (percent == dbgOTApercent)
{
return;
}
if ((percent%5) == 0)
{
Serial.printf("Progress: %u%%\r", percent);
dbgOTApercent = percent;
}
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Arduino OTA is on");
// Debug message to signal we are initialized and entering loop
Serial.println("Ready to go.");
i2c_scan_bus();
}
void loop()
{
Measurements_Tick();
ArduinoOTA.handle();
}
+110
View File
@@ -0,0 +1,110 @@
float gReadingMax = 0.0; // Holds maximum reading
float gReadingMin = 99999.9; // Holds minimum reading
float gReadingAvg = 0.0; // Holds average reading
float gReadingLast = 0.0; // Holds value of last reading
uint32_t nLastADC = 0; // Last sampled ADC value
uint32_t numMeasurements = 0; // Counts how many readings we had
uint32_t nNextMeasurementTick = 0; // When next measurement should occur
uint32_t adc_sample(void)
{
return random(512, 520);
}
uint32_t adc_sample_RNG(void)
{
return random(470, 780);
}
float get_last(void)
{
return gReadingLast;
}
float get_min(void)
{
return gReadingMin;
}
float get_max(void)
{
return gReadingMax;
}
float get_avg(void)
{
return gReadingAvg;
}
uint32_t get_adc(void)
{
return nLastADC;
}
uint32_t get_measurements_count(void)
{
return numMeasurements;
}
void reset_stats(void)
{
gReadingMax = 0.0;
gReadingMin = 99999.9;
gReadingAvg = 0.0;
numMeasurements = 0;
}
void Measurements_Tick(void)
{
if (millis() >= nNextMeasurementTick)
{
// Get latest measurement
// nLastADC = adc_sample_RNG();
// Take `ADC_SAMPLES_PER_MEASUREMENT_CYCLE` number of ADC samples
nLastADC = adc_sample_data(ADC_SAMPLES_PER_MEASUREMENT_CYCLE);
// Should we use mean or average (already calculated above)?
#ifdef ADC_FINAL_ADC_VALUE_USING_MEAN
// Use ADC mean
nLastADC = adc_get_mean();
#endif
if (nLastADC >= ADC_MAX)
{
Serial.print("Invalid ADC value of `");
Serial.print(nLastADC);
Serial.print("`. Clipping to `");
Serial.print(ADC_MAX);
Serial.println("`.");
nLastADC = ADC_MAX;
}
gReadingLast = adc_to_mm(nLastADC);
// Update average
if (numMeasurements > 1)
{
gReadingAvg = (gReadingAvg + gReadingLast) / 2;
}
else
{
gReadingAvg = gReadingLast;
}
// Update min
if (gReadingLast < gReadingMin)
{
gReadingMin = gReadingLast;
}
// Update max
if (gReadingLast > gReadingMax)
{
gReadingMax = gReadingLast;
}
// Update reading counter
numMeasurements++;
// Set next update timestamp
nNextMeasurementTick = millis() + 200;
}
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef __WINFIDEL_FW_VERSION_H__
#define __WINFIDEL_FW_VERSION_H__
#define VERSION_MAJOR 0
#define VERSION_MINOR 1
#define VERSION_PATCH 0
#endif
+230
View File
@@ -0,0 +1,230 @@
/*
Winfidel - Web
Description: This file contains all the functions we use for receiving and responding to HTTP requests
*/
#include "version.h"
char sensor_data[SENSOR_STR_MAX_LEN] = {0};
// Helper function that allows us to replace template variable in .html file
// with a value from our code.
String template_const_processor(const String& var)
{
if (var == "FW_VERSION") {
return String(String(VERSION_MAJOR) + "." + String(VERSION_MINOR) + "." + String(VERSION_PATCH));
}
else if (var == "CALIBRATION_POINT_SAMPLE_COUNT")
{
return String(CALIBRATION_POINT_SAMPLE_COUNT);
}
else if (var == "CALIBRATION_POINT_ACCURACY_POINT")
{
return String(CALIBRATION_POINT_ACCURACY_POINT);
}
else if (var == "MAX_CALIBRATION_POINTS")
{
return String(MAX_CALIBRATION_POINTS);
}
else if (var == "ADC_MIN")
{
return String(ADC_MIN);
}
else if (var == "ADC_MIN_EQUALS_MM")
{
return String(ADC_MIN_EQUALS_MM);
}
else if (var == "ADC_MAX")
{
return String(ADC_MAX);
}
else if (var == "ADC_MAX_EQUALS_MM")
{
return String(ADC_MAX_EQUALS_MM);
}
else if (var == "BUILD_DATE")
{
return String(__DATE__);
}
else if (var == "BUILD_TIME")
{
return String(__TIME__);
}
else if (var == "ADC_ALGO")
{
return adc_get_algo();
}
else if (var == "ADC_CHIP")
{
return adc_get_chip();
}
Serial.print("Unknown template variable: ");
Serial.println(var);
return String();
}
void setupWebServer(void)
{
server.onNotFound([](AsyncWebServerRequest *request) {
Serial.println("404:");
Serial.println(request->url());
request->send(404);
});
// send a file when /index is requested
server.on("/index.html", HTTP_ANY, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html", false, template_const_processor);
});
server.on("/settings.html", HTTP_ANY, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/settings.html", "text/html", false, template_const_processor);
});
server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) {
request->send(LittleFS, "/index.html", "text/html", false, template_const_processor);
});
server.serveStatic("/js/", LittleFS, "/js/");
server.serveStatic("/css/", LittleFS, "/css/");
server.serveStatic("/webfonts/", LittleFS, "/webfonts/");
server.serveStatic("/favicon.png", LittleFS, "/favicon.png");
server.serveStatic("/favicon.ico", LittleFS, "/favicon.ico");
server.on("/api/diameter/read", HTTP_GET, [] (AsyncWebServerRequest *request) {
format_sensor_data();
request->send(200, "application/json", sensor_data);
});
server.on("/api/diameter/reset", HTTP_GET, [] (AsyncWebServerRequest *request) {
reset_stats();
request->send(200, "application/json", "{\"status\":\"ok\"}");
});
server.on("/api/calibration/read", HTTP_GET, [] (AsyncWebServerRequest *request) {
request->send(200, "application/json", get_calibration_json());
});
server.on("/api/calibration/create", HTTP_GET, [] (AsyncWebServerRequest *request) {
if ( request->hasParam("mm") )
{
winfidel_status_t status;
bool adc_provided = false;
float cal_mm = request->getParam("mm")->value().toFloat();
uint32_t cal_adc = 0;
// Check if ADC count was provided
if (request->hasParam("adc"))
{
adc_provided = true;
cal_adc = request->getParam("adc")->value().toInt();
}
if (adc_provided == false)
{
status = create_calibration_point(cal_mm);
}
else
{
status = manually_create_calibration_point(cal_adc, cal_mm);
}
if (status == WINFIDEL_OK)
{
request->send(200, "application/json", "{\"status\":\"ok\"}");
}
else if (status == WINFIDEL_NO_SPACE)
{
request->send(500, "application/json", "{\"status\":\"fail\", \"message\": \"Maximum number of calibration points reached!\"}");
}
else if (status == WINFIDEL_LOW_ACCURACY)
{
request->send(500, "application/json", "{\"status\":\"fail\", \"message\": \"ADC failed to produce samples with sufficient accuracy!\"}");
}
}
else
{
request->send(400, "application/json", "{\"status\":\"fail\", \"message\": \"Missing argument `mm`!\"}");
}
});
server.on("/api/calibration/remove", HTTP_GET, [] (AsyncWebServerRequest *request) {
if ( request->hasParam("mm") )
{
winfidel_status_t status;
float rem_mm = request->getParam("mm")->value().toFloat();
status = remove_calibration_point_mm(rem_mm);
if (status == WINFIDEL_OK)
{
request->send(200, "application/json", "{\"status\":\"ok\"}");
}
else if (status == WINFIDEL_MISSING)
{
request->send(500, "application/json", "{\"status\":\"fail\", \"message\": \"Could not find calibration point!\"}");
}
else if (status == WINFIDEL_FORBIDDEN)
{
request->send(403, "application/json", "{\"status\":\"fail\", \"message\": \"Can not remove boundary points!\"}");
}
}
else
{
request->send(400, "application/json", "{\"status\":\"fail\", \"message\": \"Missing argument `mm`!\"}");
}
});
server.on("/api/calibration/reset", HTTP_GET, [] (AsyncWebServerRequest *request) {
if ( request->hasParam("confirm") )
{
calibration_reset();
request->send(200, "application/json", "{\"status\":\"ok\"}");
}
else
{
request->send(400, "application/json", "{\"status\":\"fail\", \"message\": \"Missing argument `confirm`!\"}");
}
});
server.on("/api/wifi/reset", HTTP_GET, [] (AsyncWebServerRequest *request) {
if ( request->hasParam("confirm") )
{
Serial.println("WiFi reset request recevied.");
request->send(200, "application/json", "{\"status\":\"ok\", \"message\": \"WiFi configuration has been reset. Please connect to WInFiDEL WiFi and re-configure the device.\"}");
wifiManager.resetSettings();
}
else
{
request->send(400, "application/json", "{\"status\":\"fail\", \"message\": \"Missing argument `confirm`!\"}");
}
});
server.on("/api/device/reboot", HTTP_GET, [] (AsyncWebServerRequest *request) {
if ( request->hasParam("confirm") )
{
Serial.println("Device reboot request recevied. Rebooting...");
ESP.restart();
}
else
{
request->send(400, "application/json", "{\"status\":\"fail\", \"message\": \"Missing argument `confirm`!\"}");
}
});
}
void format_sensor_data(void)
{
snprintf(sensor_data, SENSOR_STR_MAX_LEN, "{\"status\":\"ok\",\"data\":{\"diameter\":%.2f,\"min\":%.2f,\"max\":%.2f,\"avg\":%.2f,\"adc\":%d,\"count\":%d}}",
get_last(), get_min(), get_max(), get_avg(), get_adc(), get_measurements_count());
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,74 @@
M48
;Layer_Color=9474304
;FILE_FORMAT=4:4
METRIC,LZ
;TYPE=PLATED
T01F00S00C0.4000
T02F00S00C0.6000
T04F00S00C0.9000
;TYPE=NON_PLATED
T05F00S00C0.6500
T06F00S00C3.1000
%
T01
X00374Y00114
X00408Y00116
X00419Y00083
X00467
X00442Y00131
X00331375Y0011
X00263Y00147
X00244Y00137
X00245Y00162
X00228375
X00228875Y00188
X002455
X0021225
X00195625
X00179
Y00153
X00202771
X00202Y00132
X00192Y00125
X0016295Y0013195
X00144Y00109
X00121Y001199
X00098Y00112
X00101541Y00096
X00076
X001025Y000629
Y000471
X00132Y00058
Y00068
X00157Y00063
Y00074
X00168
X00179
Y00063
X00168
Y00052
X00157
X00179
X00199Y00035
X00241Y00037
X00264Y00035
X002294Y0006
X00174Y00009
X00141Y00035
T02
X001524Y00170099
X001651
X001778
T04
X003762Y00183
X004016
X00427
X004524
X004778
T05
X004141Y000628
X004719
T06
X00043Y00153
X00331Y00048
M30
@@ -0,0 +1,29 @@
M48
;Layer_Color=9474304
;FILE_FORMAT=4:4
METRIC,LZ
;TYPE=PLATED
T03F00S00C0.6000
;TYPE=NON_PLATED
%
G90
G05
T03
G00X003998Y00022
M15
G01Y0003
M16
G00X003998Y000623
M15
G01Y000733
M16
G00X004862Y000623
M15
G01Y000733
M16
G00X004862Y00022
M15
G01Y0003
M16
M17
M30
@@ -0,0 +1,20 @@
----------------------------------------------------------------------------------------------------------------------------------
NCDrill File Report For: ESP_Infidel_PCB.PcbDoc 2023-12-31 02:15:29
----------------------------------------------------------------------------------------------------------------------------------
Layer Pair : Top Layer to Bottom Layer
ASCII RoundHoles File : ESP_Infidel_PCB-RoundHoles.TXT
ASCII SlotHoles File : ESP_Infidel_PCB-SlotHoles.TXT
Tool Hole Size Hole Tolerance Hole Type Hole Count Plated Tool Travel
----------------------------------------------------------------------------------------------------------------------------------
T1 0.4mm (16mil) Round 44 PTH 125.24mm (4.93inch)
T2 0.6mm (24mil) Round 3 PTH 2.54mm (0.10inch)
T3 0.6mm (24mil) Slot 4 PTH 38.17mm (1.50inch)
T4 0.9mm (35mil) Round 5 PTH 10.16mm (0.40inch)
T5 0.65mm (26mil) Round 2 NPTH 5.78mm (0.23inch)
T6 3.1mm (122mil) Round 2 NPTH 30.65mm (1.21inch)
----------------------------------------------------------------------------------------------------------------------------------
Totals 60
Total Processing Time (hh:mm:ss) : 00:00:00
@@ -0,0 +1,22 @@
------------------------------------------------------------------------------------------
Gerber File Extension Report For: ESP_Infidel_PCB.GBR 2023-12-31 02:15:34
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
Layer Extension Layer Description
------------------------------------------------------------------------------------------
.GTO Top Overlay
.GTP Top Paste
.GTS Top Solder
.GTL Top Layer
.G1 Layer 1
.G2 Layer 2
.GBL Bottom Layer
.GBS Bottom Solder
.GBP Bottom Paste
.GBO Bottom Overlay
.GM2 Route Tool Path
.GD1 Drill Drawing
.GM Profile
------------------------------------------------------------------------------------------
@@ -0,0 +1,16 @@
G04*
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,24.0.1 (36)*
G04*
G04 Layer_Color=128*
%FSLAX44Y44*%
%MOMM*%
G71*
G04*
G04 #@! TF.SameCoordinates,F64AAE0E-53C9-4E3E-96B2-16B86AA6748B*
G04*
G04*
G04 #@! TF.FilePolarity,Positive*
G04*
G01*
G75*
M02*
@@ -0,0 +1,38 @@
G04*
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,24.0.1 (36)*
G04*
G04 Layer_Color=0*
%FSLAX44Y44*%
%MOMM*%
G71*
G04*
G04 #@! TF.SameCoordinates,F64AAE0E-53C9-4E3E-96B2-16B86AA6748B*
G04*
G04*
G04 #@! TF.FilePolarity,Positive*
G04*
G01*
G75*
%ADD73C,0.0254*%
D73*
X8602Y0D02*
G02*
X0Y8602I0J8602D01*
G01*
Y191397D01*
D02*
G02*
X8602Y200000I8602J0D01*
G01*
X491397D01*
D02*
G02*
X499999Y191397I0J-8602D01*
G01*
Y8602D01*
D02*
G02*
X491397Y0I-8602J0D01*
G01*
X8602D01*
M02*
@@ -0,0 +1,16 @@
G04*
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,24.0.1 (36)*
G04*
G04 Layer_Color=10066329*
%FSLAX44Y44*%
%MOMM*%
G71*
G04*
G04 #@! TF.SameCoordinates,F64AAE0E-53C9-4E3E-96B2-16B86AA6748B*
G04*
G04*
G04 #@! TF.FilePolarity,Positive*
G04*
G01*
G75*
M02*
@@ -0,0 +1,308 @@
G04*
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,24.0.1 (36)*
G04*
G04 Layer_Color=8421504*
%FSLAX44Y44*%
%MOMM*%
G71*
G04*
G04 #@! TF.SameCoordinates,F64AAE0E-53C9-4E3E-96B2-16B86AA6748B*
G04*
G04*
G04 #@! TF.FilePolarity,Positive*
G04*
G01*
G75*
%ADD18R,0.6000X1.1000*%
%ADD19R,0.7000X0.9000*%
%ADD20R,0.3500X0.3500*%
%ADD21R,1.3000X1.0000*%
%ADD22R,0.9000X0.7000*%
%ADD23R,0.6000X1.1000*%
%ADD24O,0.7500X0.2500*%
%ADD25O,0.2500X0.7500*%
%ADD26R,3.5000X3.8000*%
%ADD27R,1.6000X0.9000*%
%ADD28R,0.3500X0.3500*%
%ADD29R,0.7500X0.8500*%
%ADD30R,1.8000X0.4000*%
%ADD31R,0.3000X1.1500*%
%ADD32R,0.6000X1.1500*%
D18*
X254500Y176750D02*
D03*
X245000D02*
D03*
X235500D02*
D03*
Y148250D02*
D03*
X254500D02*
D03*
D19*
X202100Y176500D02*
D03*
X217900D02*
D03*
X202100Y161500D02*
D03*
X217900D02*
D03*
X285600Y132500D02*
D03*
X301400D02*
D03*
Y117500D02*
D03*
X285600D02*
D03*
X229400Y52500D02*
D03*
X213600D02*
D03*
X214100Y37000D02*
D03*
X229900D02*
D03*
X213600Y82500D02*
D03*
X229400D02*
D03*
X213600Y67500D02*
D03*
X229400D02*
D03*
X164900Y141000D02*
D03*
X149100D02*
D03*
D20*
X85358Y81313D02*
D03*
X91858D02*
D03*
D21*
X349000Y112300D02*
D03*
Y131700D02*
D03*
X467000Y112800D02*
D03*
Y132200D02*
D03*
D22*
X366500Y114600D02*
D03*
Y130400D02*
D03*
X381500Y114600D02*
D03*
Y130400D02*
D03*
X449500Y130400D02*
D03*
Y114600D02*
D03*
X434500Y130400D02*
D03*
Y114600D02*
D03*
X110000Y47100D02*
D03*
Y62900D02*
D03*
X80000Y47100D02*
D03*
Y62900D02*
D03*
X95000Y47100D02*
D03*
Y62900D02*
D03*
X303000Y170400D02*
D03*
Y154600D02*
D03*
X288000Y170400D02*
D03*
Y154600D02*
D03*
X272500Y154600D02*
D03*
Y170400D02*
D03*
X161000Y9600D02*
D03*
Y25400D02*
D03*
X130500Y9600D02*
D03*
Y25400D02*
D03*
X145500Y9600D02*
D03*
Y25400D02*
D03*
X131000Y173900D02*
D03*
Y158100D02*
D03*
X178000Y115100D02*
D03*
Y130900D02*
D03*
X113500Y119900D02*
D03*
Y104100D02*
D03*
X128500D02*
D03*
Y119900D02*
D03*
X381000Y40900D02*
D03*
Y25100D02*
D03*
Y63100D02*
D03*
Y78900D02*
D03*
D23*
X417602Y136500D02*
D03*
Y108500D02*
D03*
X408102D02*
D03*
X398602Y136500D02*
D03*
Y108500D02*
D03*
D24*
X143500Y80500D02*
D03*
Y75500D02*
D03*
Y70500D02*
D03*
Y65500D02*
D03*
Y60500D02*
D03*
Y55500D02*
D03*
Y50500D02*
D03*
Y45500D02*
D03*
X192500D02*
D03*
Y50500D02*
D03*
Y55500D02*
D03*
Y60500D02*
D03*
Y65500D02*
D03*
Y70500D02*
D03*
Y75500D02*
D03*
Y80500D02*
D03*
D25*
X150500Y38500D02*
D03*
X155500D02*
D03*
X160500D02*
D03*
X165500D02*
D03*
X170500D02*
D03*
X175500D02*
D03*
X180500D02*
D03*
X185500D02*
D03*
Y87500D02*
D03*
X180500D02*
D03*
X175500D02*
D03*
X170500D02*
D03*
X165500D02*
D03*
X160500D02*
D03*
X155500D02*
D03*
X150500D02*
D03*
D26*
X168000Y63000D02*
D03*
D27*
X263000Y10000D02*
D03*
Y51000D02*
D03*
Y64500D02*
D03*
Y105500D02*
D03*
D28*
X101541Y81301D02*
D03*
Y87801D02*
D03*
X76000Y81301D02*
D03*
Y87801D02*
D03*
D29*
X151750Y109250D02*
D03*
X162250D02*
D03*
X151750Y122750D02*
D03*
X162250D02*
D03*
D30*
X20500Y50000D02*
D03*
Y81000D02*
D03*
D31*
X425500Y73550D02*
D03*
X430500D02*
D03*
X435500D02*
D03*
X460500D02*
D03*
X455500D02*
D03*
X450500D02*
D03*
X440500D02*
D03*
X445500D02*
D03*
D32*
X467000D02*
D03*
X419000D02*
D03*
X475000D02*
D03*
X411000D02*
D03*
M02*
@@ -0,0 +1,3 @@
Layer Pairs Export File for PCB: C:\Users\Sasa\Desktop\git\_shop\ESP-Infidel\ESP_Infidel_PCB.PcbDoc
LayersSetName=Top_Bot_Thru_Holes|DrillFile=esp_infidel_pcb-roundholes.txt|DrillLayers=gtl,g1,g2,gbl
LayersSetName=Top_Bot_Slot_Holes|DrillFile=esp_infidel_pcb-slotholes.txt|DrillLayers=gtl,g1,g2,gbl
@@ -0,0 +1,64 @@
D10 ROUNDED 9.842 9.842 0.000 LINE 0.000
D11 ROUNDED 7.874 7.874 0.000 LINE 0.000
D12 ROUNDED 11.811 11.811 0.000 LINE 0.000
D13 ROUNDED 8.000 8.000 0.000 LINE 0.000
D14 ROUNDED 7.000 7.000 0.000 LINE 0.000
D15 ROUNDED 10.000 10.000 0.000 LINE 0.000
D16 ROUNDED 5.906 5.906 0.000 LINE 0.000
D17 ROUNDED 3.937 3.937 0.000 LINE 0.000
D18 RECTANGULAR 23.622 43.307 0.000 FLASH 0.000
D19 RECTANGULAR 27.559 35.433 0.000 FLASH 0.000
D20 RECTANGULAR 13.780 13.780 0.000 FLASH 90.000
D21 RECTANGULAR 39.370 51.181 0.000 FLASH 90.000
D22 RECTANGULAR 27.559 35.433 0.000 FLASH 90.000
D23 RECTANGULAR 43.307 23.622 0.000 FLASH 90.000
D24 ROUNDED 9.842 29.528 0.000 FLASH 90.000
D25 ROUNDED 9.842 29.528 0.000 FLASH 0.000
D26 RECTANGULAR 137.795 149.606 0.000 FLASH 0.000
D27 RECTANGULAR 35.433 62.992 0.000 FLASH 90.000
D28 RECTANGULAR 13.780 13.780 0.000 FLASH 0.000
D29 RECTANGULAR 33.465 29.528 0.000 FLASH 270.000
D30 RECTANGULAR 70.866 15.748 0.000 FLASH 180.000
D31 RECTANGULAR 11.811 45.276 0.000 FLASH 0.000
D32 RECTANGULAR 23.622 45.276 0.000 FLASH 0.000
D33 RECTANGULAR 31.622 51.307 0.000 FLASH 0.000
D34 RECTANGULAR 35.559 43.433 0.000 FLASH 0.000
D35 RECTANGULAR 21.779 21.779 0.000 FLASH 90.000
D36 RECTANGULAR 47.370 59.181 0.000 FLASH 90.000
D37 RECTANGULAR 35.559 43.433 0.000 FLASH 90.000
D38 RECTANGULAR 51.307 31.622 0.000 FLASH 90.000
D39 ROUNDED 17.843 37.528 0.000 FLASH 90.000
D40 ROUNDED 17.843 37.528 0.000 FLASH 0.000
D41 RECTANGULAR 145.795 157.606 0.000 FLASH 0.000
D42 RECTANGULAR 43.433 70.992 0.000 FLASH 90.000
D43 RECTANGULAR 21.779 21.779 0.000 FLASH 0.000
D44 RECTANGULAR 41.465 37.528 0.000 FLASH 270.000
D45 RECTANGULAR 78.866 23.748 0.000 FLASH 180.000
D46 RECTANGULAR 19.811 53.276 0.000 FLASH 0.000
D47 RECTANGULAR 31.622 53.276 0.000 FLASH 0.000
D48 RECTANGULAR 67.055 67.055 0.000 FLASH 180.000
D49 ROUNDED 67.055 67.055 0.000 FLASH 0.000
D50 ROUNDED 51.622 96.976 0.000 FLASH 0.000
D51 ROUNDED 8.000 8.000 0.000 FLASH 0.000
D52 ROUNDED 33.591 33.591 0.000 FLASH 0.000
D53 ROUNDED 90.677 49.339 0.000 FLASH 90.000
D54 ROUNDED 86.740 47.370 0.000 FLASH 90.000
D55 ROUNDED 35.559 35.559 0.000 FLASH 0.000
D56 ROUNDED 19.685 19.685 0.000 LINE 0.000
D57 ROUNDED 7.512 7.512 0.000 LINE 0.000
D58 RECTANGULAR 59.055 59.055 0.000 FLASH 180.000
D59 ROUNDED 59.055 59.055 0.000 FLASH 0.000
D60 ROUNDED 43.622 88.976 0.000 FLASH 0.000
D61 ROUNDED 25.591 25.591 0.000 FLASH 0.000
D62 ROUNDED 82.677 41.339 0.000 FLASH 90.000
D63 ROUNDED 78.740 39.370 0.000 FLASH 90.000
D64 ROUNDED 31.496 31.496 0.000 FLASH 0.000
D65 ROUNDED 27.559 27.559 0.000 FLASH 0.000
D66 ROUNDED 31.496 31.496 0.000 LINE 0.000
D67 ROUNDED 4.724 4.724 0.000 LINE 0.000
D68 ROUNDED 5.000 5.000 0.000 LINE 0.000
D69 ROUNDED 15.000 15.000 0.000 LINE 0.000
D70 ROUNDED 1.000 1.000 0.000 LINE 0.000
D71 ROUNDED 16.000 16.000 0.000 LINE 0.000
D72 ROUNDED 14.000 14.000 0.000 LINE 0.000
D73 ROUNDED 1.000 1.000 0.000 LINE 0.000
@@ -0,0 +1,56 @@
Altium Designer Pick and Place Locations
C:\Users\Sasa\Desktop\git\_shop\ESP-Infidel\Project Outputs for ESP_Infidel\Pick Place\Pick Place for ESP_Infidel_PCB.txt
========================================================================================================================
File Design Information:
Date: 31-12-23
Time: 02:15
Revision: Not in VersionControl
Variant: No variations
Units used: mil
Designator Comment Layer Footprint Center-X(mil) Center-Y(mil) Rotation Description
P2 "Header 5" TopLayer Header_5x1 1681.102mil 720.472mil 180 "Header, 5-Pin"
R12 Res TopLayer 0603 826.772mil 694.882mil 0 Resistor
C21 Cap TopLayer 0603_-_CAP 1072.835mil 639.764mil 90 Capacitor
C20 Cap TopLayer 0603_-_CAP 826.772mil 635.827mil 0 Capacitor
U4 MCP3021A5T-E/OT TopLayer SOT95P270X145-5N 964.567mil 639.764mil 270 "10 Bit Analog to Digital Converter 1 Input 1 SAR SOT-23-5"
U3 DRV5055A2QLPGM BottomLayer SS490A 650.000mil 669.680mil 0 "Hall Effect Sensor Single Axis Radial Lead"
U1 "IC REG LINEAR 3.3V 300MA SOT23-5" TopLayer SOT-23-5 1606.701mil 482.284mil 90 "600mA null 3.3V positive 6V SOT-25 Linear Voltage Regulators (LDO) ROHS"
R10 Res TopLayer 0603 1133.858mil 639.764mil 270 Resistor
R9 Res TopLayer 0603 1192.913mil 639.764mil 270 Resistor
C22 Cap TopLayer 0603_-_CAP 515.748mil 653.543mil 90 Capacitor
C6 Cap TopLayer 0805 1374.016mil 480.315mil 90 Capacitor
C5 Cap TopLayer 0603_-_CAP 1442.913mil 482.284mil 90 Capacitor
C4 Cap TopLayer 0603_-_CAP 1501.968mil 482.284mil 90 Capacitor
C2 Cap TopLayer 0603_-_CAP 1710.630mil 482.284mil 270 Capacitor
C3 Cap TopLayer 0603_-_CAP 1769.685mil 482.284mil 270 Capacitor
C1 Cap TopLayer 0805 1838.582mil 482.284mil 270 Capacitor
A1 ANT3216LL00R2400A TopLayer ANT3216LL00R2400A 80.709mil 257.874mil 270 "RF ANT 2.45GHZ CHIP SOLDER SMD"
X1 40MHz TopLayer XTAL-4LEAD-2016 618.110mil 456.693mil 270 "40MHz 9pF ±10ppm SMD2016-4P Crystals ROHS"
U2 ESP32-C3-FNH4 TopLayer QFN50P500X500X100_HS-33N 661.417mil 248.031mil 0 "Ultra-Low-Power SoC with RISC-V Single-Core CPU 2.4 GHz Wi-Fi (802.11 b/g/n) and Bluetooth® 5 (LE)"
SW2 Switch TopLayer Switch-XDTD-0304-215 1035.433mil 334.646mil 90 "50mA Surface Mount SPST 100MO 100,000 Times 12V 160gf@±50gf SMD Tactile Switches ROHS"
SW1 Switch TopLayer Switch-XDTD-0304-215 1035.433mil 120.079mil 270 "50mA Surface Mount SPST 100MO 100,000 Times 12V 160gf@±50gf SMD Tactile Switches ROHS"
R11 Res TopLayer 0201i_0603m 348.849mil 320.128mil 0 Resistor
R8 Res TopLayer 0603 513.779mil 68.898mil 90 Resistor
R7 Res TopLayer 0603 572.835mil 68.898mil 90 Resistor
R6 Res TopLayer 0603 874.016mil 145.669mil 0 Resistor
R3 Res TopLayer 0603 1155.512mil 521.653mil 180 Resistor
R2 Res TopLayer 0603 1500.000mil 129.921mil 270 Resistor
R1 Res TopLayer 0603 1500.000mil 279.528mil 90 Resistor
C19 Cap TopLayer 0603_-_CAP 700.787mil 484.252mil 270 Capacitor
C18 Cap TopLayer 0603_-_CAP 618.110mil 555.118mil 0 Capacitor
C17 Cap TopLayer 0603_-_CAP 446.851mil 440.945mil 270 Capacitor
C16 Cap TopLayer 0603_-_CAP 505.906mil 440.945mil 270 Capacitor
C15 Cap TopLayer 0603_-_CAP 314.961mil 216.536mil 90 Capacitor
C14 Cap TopLayer 0603_-_CAP 374.016mil 216.536mil 90 Capacitor
C13 Cap TopLayer 0603_-_CAP 433.071mil 216.536mil 90 Capacitor
C12 Cap TopLayer 0603_-_CAP 872.047mil 206.693mil 180 Capacitor
C11 Cap TopLayer 0603_-_CAP 633.858mil 68.898mil 90 Capacitor
C10 Cap TopLayer 0603_-_CAP 872.047mil 324.803mil 180 Capacitor
C9 Cap TopLayer 0603_-_CAP 872.047mil 265.748mil 180 Capacitor
C8 Cap TopLayer 0201i_0603m 399.769mil 332.879mil 270 Capacitor
C7 Cap TopLayer 0201i_0603m 299.213mil 332.879mil 270 Capacitor
R4 Res TopLayer 0603 1155.512mil 462.598mil 180 Resistor
P1 "USB-C Recepticle" TopLayer GCT_USB4105-GF-A 1744.094mil 195.964mil 0 "3A 1 Surface Mount 16P Female -25?~+85? Type-C SMD USB Connectors ROHS"
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
# WInFiDEL Sensor
**W**ireless
**In**line
**Fi**lament
**D**iameter
**E**stimator
**L**ow-cost
Sensor
## What is WInFiDEL?
WInFiDEL is an DIY open-source open-hardware Wireless 3D printing filament diameter sensor.
This design is heavily inspired by the design previously published by Made with Layers (Thomas Sanladerer) (video: https://www.youtube.com/watch?v=RYgdLPe_T0c)
:soon: (WIP) Soon I will publish a video that goes into more details on how this sensor works and how you can build one.
This repository will be updated with additional information as soon as that video goes live.
## Screenshots
![Home](assets/WInFiDEL_home.png)
![Calibration](assets/WInFiDEL_settings.png)
## Sasa Karanovic
<a href="https://sasakaranovic.com/" target="_blank" title="Sasa Karanovic Home Page"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_home.png" width="16"> Home Page</a> &nbsp;&middot;&nbsp;
<a href="https://youtube.com/c/sasakaranovic" target="_blank" title="Sasa Karanovic on YouTube"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_youtube.png" width="16"> YouTube</a> &nbsp;&middot;&nbsp;
<a href="https://github.com/sasakaranovic" target="_blank" title="Sasa Karanovic on GitHub"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_github.png" width="16"> GitHub</a> &nbsp;&middot;&nbsp;
<a href="https://twitter.com/_sasakaranovic_" target="_blank" title="Sasa Karanovic on Twitter"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_twitter.png" width="16"> Twitter</a> &nbsp;&middot;&nbsp;
<a href="https://instagram.com/_sasakaranovic_" target="_blank" title="Sasa Karanovic on Instagram"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_instagram.png" width="16"> Instagram</a> &nbsp;&middot;&nbsp;
<a href="https://github.com/sponsors/SasaKaranovic" target="_blank" title="Sponsor on GitHub"><img src="https://raw.githubusercontent.com/SasaKaranovic/common/master/assets/img_github.png" width="16"> Sponsor on GitHub</a>
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB